iconv for WebAssembly
v1.19WebAssemblyiconv 1.19 for browsers, Node.js and edge runtimes, precompiled for wasm32, single-threaded and multi-threaded as @crossbind/port-iconv-wasm.
Install
crossbind itself arrives with your bundler plugin, or with a new project from npm create crossbind@beta; Bundlers has Vite, Webpack, Rspack and Rollup.
Usage
Each example runs here, in this tab, and prints what the site build checked.
Each example also has a JavaScript only tab: the same task with no C++ file, calling iconv's own headers from @crossbind/port-iconv directly. All 4 work that way.
Convert between UTF-8 and a legacy encoding
What most iconv code does: iconv_open, iconv in a loop and iconv_close, strict in both directions. A last call without input ends stateful encodings such as ISO-2022-JP, which is where the closing ESC ( B comes from.
iconv.h defines iconv_open, iconv and iconv_close as macros, so they are bound as libiconv_open, libiconv and libiconv_close, and JavaScript builds their char ** and size_t * arguments itself: a pointer slot from allocPointer for each buffer, a 4-byte allocBuffer for each counter. errno is not bound, so a failed call cannot say whether the output was full (E2BIG) or the input stopped (EILSEQ, EINVAL): the output buffer is sized so it never fills. A failed iconv_open returns (iconv_t)-1 as an ordinary handle; its address shows only when it is written to a pointer slot and read back as a number.
Transliterate or drop what the target cannot hold
Append //TRANSLIT to the target and iconv approximates a missing character; append //IGNORE and it drops it. The return value of iconv counts those characters. GNU libiconv transliterates the same way in every locale, so ASCII keeps accents as marks.
//TRANSLIT and //IGNORE work unchanged, and the return value of libiconv (the bound name of iconv) still counts the characters approximated or dropped. readBytes hands the result back one character per byte, which is already how ISO-8859-1 and ASCII read, so it prints without a decode step. The output buffer is sized up front instead of grown on E2BIG, because errno is not bound.
Decode a stream that cuts characters in two
Bytes from fetch, a WebSocket or a serial port arrive in pieces of any size, so a multibyte character can straddle two pieces. iconv stops with EINVAL at such a cut and the unfinished bytes wait for the next piece; E2BIG only means the output buffer is full.
The stream works the same way: libiconv stops at a piece that ends inside a character, and the bytes it leaves wait for the next piece. What JavaScript cannot see is why it stopped, because errno is not bound: a cut (EINVAL) and an invalid byte (EILSEQ) both return (size_t)-1 with bytes left, so an invalid byte would also wait and show up at the end as bytes left over, not as an error at its position.
List the encodings and check a name
iconvlist walks every encoding with its aliases and iconv_canonicalize names the canonical one, but only iconv_open proves a name works. GNU libiconv writes UTF-8 with its hyphen, and this build leaves out CP437 with the other DOS and EBCDIC code pages.
iconvlist (bound as libiconvlist) reports each encoding to a callback, and a JavaScript function can stand in for a C callback only on the page's thread, so this example runs with useWorker: false; the callback runs inside the call and reads the names without await. A failed iconv_open returns (iconv_t)-1 as an ordinary handle, so the check uses libiconv_open_into, which returns 0 or -1 and needs no close. _libiconv_version is a variable, not a function, and is not bound, so the first line has no version.
What is different on WebAssembly
- In a browser the module runs in a Worker by default (
useWorker), so every call returns a promise:awaitcalls and constructors alike. - The module has its own filesystem:
m.FSwrites files,m.getFileBytesreads them back andm.autoMountFilesmountsFileobjects from an<input type=file>./memfslives in memory;/opfspersists across reloads and needs the Worker. See Filesystem. - In Node.js,
m.FSis the real disk, so use real paths there. - Multi-threaded builds (
runtime: 'mt') need COOP and COEP headers in production. See Threading.
Other platforms
- iconv overview: the apps, every platform's setup and the packages.
- iconv for Android: React Native apps on Android.
- iconv for iOS: React Native apps on iOS.
- iconv for WASI: command-line programs under wasmtime.
Facts on this page come from the port manifests in the repository and from what npm served on beta when the site was built. See the Libraries guide for the full consumer flow.