func (w *WriteCloser) Write(p []byte) (int, error) { plen := len(p) src := (*C.char)(unsafe.Pointer(&p[0])) srcLimit := (*C.char)(unsafe.Pointer(&p[plen])) uErr := C.UErrorCode(C.U_ZERO_ERROR) oMaxLen, err := ucnvMaxLen(plen, w.from, w.to) if err != nil { return 0, err } // reallocate write buffer if oMaxLen > cap(w.obuf) { w.obuf = make([]byte, oMaxLen*2) } dst := (*C.char)(unsafe.Pointer(&w.obuf[0])) dstLimit := (*C.char)(unsafe.Pointer(&w.obuf[oMaxLen])) dstStart := uintptr(unsafe.Pointer(dst)) // fill write buffer by C.ucnv_convertEx _, err = C.ucnv_convertEx(w.to, w.from, &dst, dstLimit, &src, srcLimit, nil, nil, nil, nil, C.UBool(1), C.UBool(1), &uErr) if err != nil { return 0, err } if err = uErrorToGoError(uErr); err != nil { return 0, err } w.olen = int(uintptr(unsafe.Pointer(dst)) - dstStart) n, err := w.w.Write(w.obuf[:w.olen]) if err != nil { return n, err } return n, nil }
func (r *ReadCloser) Read(p []byte) (int, error) { plen := len(p) if plen == 0 { return 0, nil } n := 0 olen := r.oend - r.ostart // flush write buffer if exist if olen > 0 { if olen > plen { copy(p, r.obuf[r.ostart:plen]) r.ostart += plen return plen, nil } copy(p, r.obuf[r.ostart:r.oend]) r.ostart = 0 r.oend = 0 if olen == plen { return plen, nil } n = olen } // reallocate read buffer or set Len if plen != len(r.ibuf) { if plen > cap(r.ibuf) { r.ibuf = make([]byte, plen, plen*2) } else { r.ibuf = r.ibuf[:plen] } } // fill read buffer ilen, err := r.r.Read(r.ibuf) r.ilen = ilen if err != nil { return n, err } if ilen == 0 { return n, io.EOF } src := (*C.char)(unsafe.Pointer(&r.ibuf[0])) srcLimit := (*C.char)(unsafe.Pointer(&r.ibuf[ilen])) uErr := C.UErrorCode(C.U_ZERO_ERROR) oMaxLen, err := ucnvMaxLen(ilen, r.from, r.to) if err != nil { return n, err } // reallocate write buffer if oMaxLen > cap(r.obuf) { r.obuf = make([]byte, oMaxLen*2) } dst := (*C.char)(unsafe.Pointer(&r.obuf[0])) dstLimit := (*C.char)(unsafe.Pointer(&r.obuf[oMaxLen])) dstStart := uintptr(unsafe.Pointer(dst)) // fill write buffer by C.ucnv_convertEx _, err = C.ucnv_convertEx(r.to, r.from, &dst, dstLimit, &src, srcLimit, nil, nil, nil, nil, C.UBool(1), C.UBool(1), &uErr) if err != nil { return n, err } if err = uErrorToGoError(uErr); err != nil { return n, err } r.ilen = 0 olen = int(uintptr(unsafe.Pointer(dst)) - dstStart) // flush write buffer if olen > plen-n { copy(p[n:], r.obuf[:plen-n]) r.ostart = plen - n r.oend = olen return plen, nil } copy(p[n:], r.obuf[:olen]) return olen + n, nil }