iconv-go/writer.go

86 lines
1.8 KiB
Go

package iconv
import (
"io"
"os"
)
type Writer struct {
destination io.Writer
converter *Converter
buffer []byte
readPos, writePos int
err os.Error
}
func NewWriter(destination io.Writer, fromEncoding string, toEncoding string) (*Writer, os.Error) {
// create a converter
converter, err := NewConverter(fromEncoding, toEncoding)
if err == nil {
return NewWriterFromConverter(destination, converter), err
}
// return the error
return nil, err
}
func NewWriterFromConverter(destination io.Writer, converter *Converter) (writer *Writer) {
writer = new(Writer)
// copy elements
writer.destination = destination
writer.converter = converter
// create 8K buffers
writer.buffer = make([]byte, 8 * 1024)
return writer
}
func (this *Writer) emptyBuffer() {
// write new data out of buffer
bytesWritten, err := this.destination.Write(this.buffer[this.readPos:this.writePos])
// update read position
this.readPos += bytesWritten
// slide existing data to beginning
if this.readPos > 0 {
// copy current bytes - is this guaranteed safe?
copy(this.buffer, this.buffer[this.readPos:this.writePos])
// adjust positions
this.writePos -= this.readPos
this.readPos = 0
}
// track any reader error / EOF
if err != nil {
this.err = err
}
}
// implement the io.Writer interface
func (this *Writer) Write(p []byte) (n int, err os.Error) {
// write data into our internal buffer
bytesRead, bytesWritten, err := this.converter.Convert(p, this.buffer[this.writePos:])
// update bytes written for return
n += bytesRead
this.writePos += bytesWritten
// checks for when we have a full buffer
for this.writePos > 0 {
// if we have an error, just return it
if this.err != nil {
return
}
// else empty the buffer
this.emptyBuffer()
}
return n, err
}