Merge 0efdb40d57
into 8960e66bd3
This commit is contained in:
commit
ee044a164c
26
reader.go
26
reader.go
@ -5,6 +5,8 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const bufferSize = 8 * 1024
|
||||||
|
|
||||||
type Reader struct {
|
type Reader struct {
|
||||||
source io.Reader
|
source io.Reader
|
||||||
converter *Converter
|
converter *Converter
|
||||||
@ -33,12 +35,12 @@ func NewReaderFromConverter(source io.Reader, converter *Converter) (reader *Rea
|
|||||||
reader.converter = converter
|
reader.converter = converter
|
||||||
|
|
||||||
// create 8K buffers
|
// create 8K buffers
|
||||||
reader.buffer = make([]byte, 8*1024)
|
reader.buffer = make([]byte, bufferSize)
|
||||||
|
|
||||||
return reader
|
return reader
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *Reader) fillBuffer() {
|
func (this *Reader) fillBuffer() int {
|
||||||
// slide existing data to beginning
|
// slide existing data to beginning
|
||||||
if this.readPos > 0 {
|
if this.readPos > 0 {
|
||||||
// copy current bytes - is this guaranteed safe?
|
// copy current bytes - is this guaranteed safe?
|
||||||
@ -59,6 +61,7 @@ func (this *Reader) fillBuffer() {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
this.err = err
|
this.err = err
|
||||||
}
|
}
|
||||||
|
return bytesRead
|
||||||
}
|
}
|
||||||
|
|
||||||
// implement the io.Reader interface
|
// implement the io.Reader interface
|
||||||
@ -85,6 +88,18 @@ func (this *Reader) Read(p []byte) (n int, err error) {
|
|||||||
|
|
||||||
// if we experienced an iconv error, check it
|
// if we experienced an iconv error, check it
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
// EINVAL:
|
||||||
|
// An incomplete multibyte sequence is encountered in the input,
|
||||||
|
// and the input byte sequence terminates after it.
|
||||||
|
if err == syscall.EINVAL {
|
||||||
|
// If we can read new data, then this should NOT be
|
||||||
|
// considered as an error.
|
||||||
|
newData := this.fillBuffer()
|
||||||
|
if newData > 0 {
|
||||||
|
return n, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// E2BIG errors can be ignored (we'll get them often) as long
|
// E2BIG errors can be ignored (we'll get them often) as long
|
||||||
// as at least 1 byte was written. If we experienced an E2BIG
|
// as at least 1 byte was written. If we experienced an E2BIG
|
||||||
// and no bytes were written then the buffer is too small for
|
// and no bytes were written then the buffer is too small for
|
||||||
@ -92,6 +107,13 @@ func (this *Reader) Read(p []byte) (n int, err error) {
|
|||||||
if err != syscall.E2BIG || bytesWritten == 0 {
|
if err != syscall.E2BIG || bytesWritten == 0 {
|
||||||
// track anything else
|
// track anything else
|
||||||
this.err = err
|
this.err = err
|
||||||
|
} else {
|
||||||
|
// Should not return this.err
|
||||||
|
// If we got EOF from source in last fillBuffer() call, and
|
||||||
|
// there is still more data to process in buffer, in this
|
||||||
|
// case, if we return this.err(=EOF), then data in buffer
|
||||||
|
// will be lost.
|
||||||
|
return n, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
38
reader_test.go
Normal file
38
reader_test.go
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
package iconv
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"io/ioutil"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GbkToUtf8(src []byte) ([]byte, error) {
|
||||||
|
reader, err := NewReader(bytes.NewReader(src), "gbk", "utf-8")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return ioutil.ReadAll(reader)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Utf8ToGbk(src []byte) ([]byte, error) {
|
||||||
|
reader, err := NewReader(bytes.NewReader(src), "utf-8", "gbk")
|
||||||
|
reader.buffer = make([]byte, 16)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return ioutil.ReadAll(reader)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReaderWithDataLargerThanBuffer(t *testing.T) {
|
||||||
|
chars := []byte("梅")
|
||||||
|
for len(chars) < bufferSize*2 {
|
||||||
|
t.Logf("input size: %d", len(chars))
|
||||||
|
chars = append(chars, chars...)
|
||||||
|
_, err := Utf8ToGbk(chars)
|
||||||
|
if err != nil {
|
||||||
|
t.Fail()
|
||||||
|
t.Logf("failed with %d bytes data", len(chars))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user