This repository has been archived by the owner on Apr 29, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
iconv.go
68 lines (54 loc) · 1.5 KB
/
iconv.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
package iconv
import (
"bytes"
"os"
)
// #include <iconv.h>
// #include <stdlib.h>
// #include <errno.h>
import "C"
import (
"unsafe"
)
type Iconv struct {
p C.iconv_t
}
func Open(to, from string) *Iconv {
cto := C.CString(to); defer C.free(unsafe.Pointer(cto))
cfrom := C.CString(from); defer C.free(unsafe.Pointer(cfrom))
cc, e := C.iconv_open(cto, cfrom)
if int(uintptr(cc)) == -1 { panic(e) }
return &Iconv{cc}
}
func (c *Iconv) Close() {
r, e := C.iconv_close(c.p)
if r == -1 { panic(e) }
}
// FIXME loop forever if inLen not decreasing
// FIXME if error reset state ?
func (c *Iconv) Conv(s string) string {
if len(s) == 0 { return "" }
inBytes := []byte(s)
bufferLen := len(inBytes)
if bufferLen < 64 { bufferLen = 64 } // XXX one character never exceeds this ?
buffer := make([]byte, bufferLen)
outBuffer := bytes.NewBuffer(nil)
inBytesPtr := &inBytes[0]
inLen := C.size_t(len(inBytes))
for inLen > 0 {
bufferPtr := &buffer[0]
bufferLen := C.size_t(len(buffer))
r, e := C.iconv(c.p,
(**C.char)(unsafe.Pointer(&inBytesPtr)), &inLen,
(**C.char)(unsafe.Pointer(&bufferPtr)), &bufferLen)
if int(r) == -1 && e != os.Errno(int(C.E2BIG)) { panic(e) }
outBuffer.Write(buffer[:len(buffer) - int(bufferLen)])
}
// XXX if input is incomplete we need to reset iconv state (if it has)
// or call a version that returns shift sequence ?
r, e := C.iconv(c.p,
(**C.char)(nil), (*C.size_t)(nil),
(**C.char)(nil), (*C.size_t)(nil))
if int(r) == -1 { panic(e) }
return outBuffer.String()
}