| 1 | module iconv |
| 2 | |
| 3 | // Module iconv provides functions convert between vstring(UTF8) to/from different encodings. |
| 4 | |
| 5 | #flag openbsd -I/usr/local/include |
| 6 | |
| 7 | #include <iconv.h> |
| 8 | |
| 9 | #flag darwin -liconv |
| 10 | #flag freebsd -L/usr/local/lib -liconv |
| 11 | #flag openbsd -L/usr/local/lib -liconv |
| 12 | #flag termux -L/data/data/com.termux/files/usr/lib -liconv |
| 13 | |
| 14 | fn C.iconv_open(tocode charptr, fromcode charptr) voidptr |
| 15 | fn C.iconv_close(cd voidptr) i32 |
| 16 | fn C.iconv(cd voidptr, inbuf &charptr, inbytesleft &usize, outbuf &charptr, outbytesleft &usize) usize |
| 17 | |
| 18 | // conv convert `fromcode` encoding string to `tocode` encoding string |
| 19 | @[direct_array_access] |
| 20 | fn conv(tocode string, fromcode string, src &u8, src_len int) ![]u8 { |
| 21 | if src_len < 0 { |
| 22 | return error('src length error') |
| 23 | } |
| 24 | |
| 25 | mut src_encoding := fromcode.to_upper() |
| 26 | mut dst_encoding := tocode.to_upper() |
| 27 | |
| 28 | // As macos-12 has no UTF16LE/UTF16BE/UTF32LE/UTF32BE, change them to UTF-16LE/UTF-16BE/UTF-32LE/UTF-32BE |
| 29 | match src_encoding { |
| 30 | 'UTF16LE' { src_encoding = 'UTF-16LE' } |
| 31 | 'UTF16BE' { src_encoding = 'UTF-16BE' } |
| 32 | 'UTF32LE' { src_encoding = 'UTF-32LE' } |
| 33 | 'UTF32BE' { src_encoding = 'UTF-32BE' } |
| 34 | else {} |
| 35 | } |
| 36 | |
| 37 | match dst_encoding { |
| 38 | 'UTF16LE' { dst_encoding = 'UTF-16LE' } |
| 39 | 'UTF16BE' { dst_encoding = 'UTF-16BE' } |
| 40 | 'UTF32LE' { dst_encoding = 'UTF-32LE' } |
| 41 | 'UTF32BE' { dst_encoding = 'UTF-32BE' } |
| 42 | else {} |
| 43 | } |
| 44 | |
| 45 | mut cd := C.iconv_open(charptr(dst_encoding.str), charptr(src_encoding.str)) |
| 46 | if isize(cd) == -1 { |
| 47 | return error('platform can\'t convert from ${src_encoding} to ${dst_encoding}') |
| 48 | } |
| 49 | defer { C.iconv_close(cd) } |
| 50 | |
| 51 | mut dst := []u8{len: (src_len + 1) * 4} // this should be enough to hold the dst encoding string |
| 52 | |
| 53 | mut src_ptr := charptr(src) |
| 54 | mut dst_ptr := charptr(dst.data) |
| 55 | mut src_left := usize(src_len) |
| 56 | mut dst_left := usize(dst.len) |
| 57 | res := C.iconv(cd, &src_ptr, &src_left, &dst_ptr, &dst_left) |
| 58 | if res == usize(-1) { |
| 59 | return error('convert encoding string fail, iconv return ${res}') |
| 60 | } |
| 61 | |
| 62 | // resize dst buf to real length |
| 63 | dst.trim(dst.len - int(dst_left)) |
| 64 | return dst |
| 65 | } |
| 66 | |