iconv-go/reader.go
Donovan Jimenez 82db0fae9a Initial iconv go package, supports:
* string conversion
 * byte slice conversion
 * Reader conversion
2011-01-14 18:34:30 -05:00

102 lines
2.4 KiB
Go

package iconv
import (
"io"
"os"
)
type Reader struct {
source io.Reader
converter *Converter
rawBuffer []byte
rawReadPos, rawWritePos int
convertedBuffer []byte
convertedReadPos, convertedWritePos int
}
func NewReader(source io.Reader, fromEncoding string, toEncoding string) (*Reader, os.Error) {
// create a converter
converter, err := NewConverter(fromEncoding, toEncoding)
if err == nil {
return NewReaderFromConverter(source, converter), err
}
// return the error
return nil, err
}
func NewReaderFromConverter(source io.Reader, converter *Converter) (reader *Reader) {
reader = new(Reader)
// copy elements
reader.source = source
reader.converter = converter
// create 8K buffers
reader.rawBuffer = make([]byte, 8 * 1024)
reader.convertedBuffer = make([]byte, 8 * 1024)
return reader
}
func (this *Reader) fillRawBuffer() {
// slide existing data to beginning
if this.rawReadPos > 0 {
// copy current bytes
copy(this.rawBuffer, this.rawBuffer[this.rawReadPos:this.rawWritePos])
// adjust positions
this.rawWritePos -= this.rawReadPos
this.rawReadPos = 0
}
// read new data into buffer at write position
bytesRead, err := this.source.Read(this.rawBuffer[this.rawWritePos:])
// adjust write position
this.rawWritePos += bytesRead
// track source reader errors
if err != nil {
// not sure where to put this for now
}
}
func (this *Reader) fillConvertedBuffer() {
// slide existing data to beginning
if this.convertedReadPos > 0 {
// copy current bytes
copy(this.convertedBuffer, this.convertedBuffer[this.convertedReadPos:this.convertedWritePos])
// adjust positions
this.convertedWritePos -= this.convertedReadPos
this.convertedReadPos = 0
}
// use iconv to fill the converted buffer from the raw buffer
bytesRead, bytesWritten, err := this.converter.Convert(this.rawBuffer[this.rawReadPos:this.rawWritePos], this.convertedBuffer[this.convertedWritePos:])
// adjust read and write positions
this.rawReadPos += bytesRead
this.convertedWritePos += bytesWritten
// track iconv convert errors
if err != nil {
// not sure where to put this for now
}
}
// implement the io.Reader interface
func (this *Reader) Read(p []byte) (n int, err os.Error) {
this.fillRawBuffer()
this.fillConvertedBuffer()
if this.convertedWritePos - 1 > this.convertedReadPos {
// copy converted bytes into p
n = copy(p, this.convertedBuffer[this.convertedReadPos:this.convertedWritePos])
}
return
}