-
Notifications
You must be signed in to change notification settings - Fork 1
/
iconv-mlton.sml
54 lines (46 loc) · 1.67 KB
/
iconv-mlton.sml
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
structure Iconv :
sig
exception Iconv of string
val iconv: string -> string -> string -> string
end
=
struct
exception Iconv of string
val () = MLton.Exn.addExnMessager (fn Iconv m => SOME ("Iconv \"" ^ m ^ "\"") | _ => NONE)
local
type long = C_Long.t
val iconv_open_ffi = _import "iconv_open" : string * string -> long;
val iconv_ffi = _import "iconv" : long * string ref * long ref * Word8Array.array ref * long ref -> long;
val iconv_close_ffi = _import "iconv_close" : long -> unit;
in
fun iconv from to s =
let
val cd = iconv_open_ffi (to ^ "\000", from ^ "\000")
in
if cd = ~1 then raise Iconv "open" else
let
val maxSymbolSize = 8
val srcsize = String.size s
val dstsize = srcsize * 2
(* val dstmem = Word8Array.unsafeAlloc dstsize *) (* MLton 20180207 *)
val dstmem = Unsafe.Word8Array.create dstsize (* MLton 20130715 and 20180207 *)
val src = ref s
val srcleft = ref (C_Long.fromInt srcsize)
val dst = ref dstmem
val dstleft = ref (C_Long.fromInt dstsize)
val r = iconv_ffi (cd, src, srcleft, dst, dstleft)
val _ = iconv_close_ffi cd
in
if r = ~1
then
(
if C_Long.toInt (!dstleft) < maxSymbolSize
then raise Iconv "convert: maybe small buffer"
else raise Iconv "convert"
)
else
Byte.bytesToString (Word8ArraySlice.vector (Word8ArraySlice.slice (dstmem, 0, SOME (dstsize - C_Long.toInt (!dstleft)))))
end
end
end
end