github.com/isyscore/isc-gobase@v1.5.3-0.20231218061332-cbc7451899e9/iconv/iconv_writer.go (about) 1 package iconv 2 3 import "io" 4 5 type Writer struct { 6 destination io.Writer 7 converter *Converter 8 buffer []byte 9 readPos, writePos int 10 err error 11 } 12 13 func NewWriter(destination io.Writer, fromEncoding string, toEncoding string) (*Writer, error) { 14 // create a converter 15 converter, err := NewConverter(fromEncoding, toEncoding) 16 if err == nil { 17 return NewWriterFromConverter(destination, converter), err 18 } 19 // return the error 20 return nil, err 21 } 22 23 func NewWriterFromConverter(destination io.Writer, converter *Converter) (writer *Writer) { 24 writer = new(Writer) 25 // copy elements 26 writer.destination = destination 27 writer.converter = converter 28 // create 8K buffers 29 writer.buffer = make([]byte, 8*1024) 30 return writer 31 } 32 33 func (c *Writer) emptyBuffer() { 34 // write new data out of buffer 35 bytesWritten, err := c.destination.Write(c.buffer[c.readPos:c.writePos]) 36 // update read position 37 c.readPos += bytesWritten 38 // slide existing data to beginning 39 if c.readPos > 0 { 40 // copy current bytes - is this guaranteed safe? 41 copy(c.buffer, c.buffer[c.readPos:c.writePos]) 42 // adjust positions 43 c.writePos -= c.readPos 44 c.readPos = 0 45 } 46 // track any reader error / EOF 47 if err != nil { 48 c.err = err 49 } 50 } 51 52 // implement the io.Writer interface 53 func (c *Writer) Write(p []byte) (n int, err error) { 54 // write data into our internal buffer 55 bytesRead, bytesWritten, err := c.converter.Convert(p, c.buffer[c.writePos:]) 56 // update bytes written for return 57 n += bytesRead 58 c.writePos += bytesWritten 59 // checks for when we have a full buffer 60 for c.writePos > 0 { 61 // if we have an error, just return it 62 if c.err != nil { 63 return 64 } 65 // else empty the buffer 66 c.emptyBuffer() 67 } 68 return n, err 69 }