2011-01-15 07:34:30 +08:00
|
|
|
package iconv
|
|
|
|
|
2012-04-11 06:30:42 +08:00
|
|
|
import (
|
2011-01-15 07:34:30 +08:00
|
|
|
"io"
|
2017-04-25 12:37:24 +08:00
|
|
|
"runtime"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
defaultReadBufferSize = 8 * 1024
|
|
|
|
minReadBufferSize = 16
|
2011-01-15 07:34:30 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
type Reader struct {
|
2012-04-11 06:30:42 +08:00
|
|
|
source io.Reader
|
|
|
|
converter *Converter
|
|
|
|
buffer []byte
|
2011-01-15 17:06:50 +08:00
|
|
|
readPos, writePos int
|
2017-04-25 12:37:24 +08:00
|
|
|
eof bool
|
2011-01-15 07:34:30 +08:00
|
|
|
}
|
|
|
|
|
2017-04-25 12:37:24 +08:00
|
|
|
func NewReader(source io.Reader, fromEncoding, toEncoding string) (*Reader, error) {
|
|
|
|
return NewReaderSized(source, fromEncoding, toEncoding, defaultReadBufferSize)
|
|
|
|
}
|
2011-01-15 07:34:30 +08:00
|
|
|
|
2017-04-25 12:37:24 +08:00
|
|
|
func NewReaderFromConverter(source io.Reader, converter *Converter) *Reader {
|
|
|
|
return NewReaderFromConverterSized(source, converter, defaultReadBufferSize)
|
2011-01-15 07:34:30 +08:00
|
|
|
}
|
|
|
|
|
2017-04-25 12:37:24 +08:00
|
|
|
func NewReaderSized(source io.Reader, fromEncoding, toEncoding string, size int) (*Reader, error) {
|
|
|
|
converter, err := NewConverter(fromEncoding, toEncoding)
|
2011-01-15 07:34:30 +08:00
|
|
|
|
2017-04-25 12:37:24 +08:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2011-01-15 07:34:30 +08:00
|
|
|
|
2017-04-25 12:37:24 +08:00
|
|
|
// add a finalizer for the converter we created
|
|
|
|
runtime.SetFinalizer(converter, finalizeConverter)
|
2011-01-15 07:34:30 +08:00
|
|
|
|
2017-04-25 12:37:24 +08:00
|
|
|
return NewReaderFromConverterSized(source, converter, size), nil
|
2011-01-15 07:34:30 +08:00
|
|
|
}
|
|
|
|
|
2017-04-25 12:37:24 +08:00
|
|
|
func NewReaderFromConverterSized(source io.Reader, converter *Converter, size int) *Reader {
|
|
|
|
if size < minReadBufferSize {
|
|
|
|
size = minReadBufferSize
|
2011-01-15 07:34:30 +08:00
|
|
|
}
|
|
|
|
|
2017-04-25 12:37:24 +08:00
|
|
|
return &Reader{
|
|
|
|
source: source,
|
|
|
|
converter: converter,
|
|
|
|
buffer: make([]byte, size),
|
2011-01-15 07:34:30 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-25 12:37:24 +08:00
|
|
|
func (r *Reader) Read(p []byte) (int, error) {
|
|
|
|
if len(p) == 0 {
|
|
|
|
return 0, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
var bytesRead, bytesWritten int
|
|
|
|
var err error
|
|
|
|
|
|
|
|
// setup for a single read into buffer if possible
|
|
|
|
if !r.eof {
|
|
|
|
if r.readPos > 0 {
|
|
|
|
// slide data to front of buffer
|
|
|
|
r.readPos, r.writePos = 0, copy(r.buffer, r.buffer[r.readPos:r.writePos])
|
2011-01-15 17:06:50 +08:00
|
|
|
}
|
2011-01-15 07:34:30 +08:00
|
|
|
|
2017-04-25 12:37:24 +08:00
|
|
|
if r.writePos < len(r.buffer) {
|
|
|
|
// do the single read
|
|
|
|
bytesRead, err = r.source.Read(r.buffer[r.writePos:])
|
2011-01-15 07:34:30 +08:00
|
|
|
|
2017-04-25 12:37:24 +08:00
|
|
|
if bytesRead < 0 {
|
|
|
|
panic("iconv: source reader returned negative count from Read")
|
|
|
|
}
|
2011-01-15 07:34:30 +08:00
|
|
|
|
2017-04-25 12:37:24 +08:00
|
|
|
r.writePos += bytesRead
|
|
|
|
r.eof = err == io.EOF
|
|
|
|
}
|
|
|
|
}
|
2011-01-15 07:34:30 +08:00
|
|
|
|
2017-04-25 12:37:24 +08:00
|
|
|
if r.readPos < r.writePos || r.eof {
|
|
|
|
// convert any buffered data we have, or do a final reset (for shift based conversions)
|
|
|
|
bytesRead, bytesWritten, err = r.converter.Convert(r.buffer[r.readPos:r.writePos], p)
|
|
|
|
r.readPos += bytesRead
|
2011-01-15 07:34:30 +08:00
|
|
|
|
2017-04-25 12:37:24 +08:00
|
|
|
// if we experienced an iconv error and didn't make progress, report it.
|
|
|
|
// if we did make progress, it may be informational only (i.e. reporting
|
|
|
|
// an EILSEQ even when using //ignore to skip them)
|
|
|
|
if err != nil && bytesWritten == 0 {
|
|
|
|
return bytesWritten, err
|
2011-01-15 17:06:50 +08:00
|
|
|
}
|
2017-04-25 12:37:24 +08:00
|
|
|
|
|
|
|
// signal an EOF only if we didn't write anything - accomodates premature
|
|
|
|
// errror checking in user code
|
|
|
|
if bytesWritten == 0 && r.eof {
|
|
|
|
return 0, io.EOF
|
|
|
|
}
|
|
|
|
|
|
|
|
return bytesWritten, nil
|
2011-01-15 07:34:30 +08:00
|
|
|
}
|
|
|
|
|
2017-04-25 12:37:24 +08:00
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *Reader) Reset(source io.Reader) {
|
|
|
|
r.converter.Reset()
|
|
|
|
|
|
|
|
*r = Reader{
|
|
|
|
source: source,
|
|
|
|
converter: r.converter,
|
|
|
|
buffer: r.buffer,
|
|
|
|
}
|
2011-01-15 07:34:30 +08:00
|
|
|
}
|