libiconvをemscriptenでjs化し、node.jsで使った
背景
WindowsでCビルド環境が入っていない環境下でnode.jsでSMTPを受けるサーバーを書いていた。
世界で活躍するエンジニアと違い、自分は日本語を含むメールしか扱わないため、iso-2022-jpでエンコードされている文字コードをUTF-8にしてコンソールに表示する必要があった。
node.js向けのiconvパッケージがいくつか見るかるも、パフォーマンス重視しているようで、libiconvのCでのバインドだった。この為、使えなかった。
sjisをutf-8に変換するjsピュア実装はあるも、JISをUTF-8にする実装は見つけることが出来なかった。
Emscriptenでやってみるか!
別環境でlibiconvをemscriptenでビルド
テスト用のSMPTサーバーを動かす環境はビルドツールの類がないので、cloud9のIDEのターミナル越しに某所のOSXマシンにsshして作業を進めた。
emconfigure時に--enable-staticを付けるだけで行けた。ちなみに、静的ライブラリにしておかないと、後の作業でつくるラッパーをemccでリンク出来ない。
emconfigure ./configure --enable-static emmake make
うまくいけば、./lib/.lib/libiconv.aが作られる。
参考Link
jsから呼びやすい関数にしておく
nodeでrequire('libiconv.a')なんてできれば便利なのだが、それは出来ないようで、ラッパーを作る必要がある。
今回はテストで使う一時的なものなので、mallocしてメモリーリーク問題(jsで使うから関係ないかもw)を避けるべく、4096バイトの上限を設けて処理することにした。
use with Gist Search
ちょっとしたポイント
OSXでは/usr/includeにiconv.hがあるので、
#include <iconv.h>
ではなく、
#include "iconv.h"
としてローカルのヘッダを参照するようなコードにしておき、以下の作業を進める。
以下のコマンドで、libiconv.aを含めたjsファイルを生成する。
emcc -s EXPORTED_FUNCTIONS="['_jis2utf8']" -Qunused-arguments -Wno-logical-op-parentheses -I./include -o jis2utf8lib.js jis2utf8lib.c ./lib/.libs/libiconv.a
使うには
Cの関数をnode.jsで呼ぶには
libiconvはあっけないほどemscriptenでjs化出来たのだが、このjsファイルをnode.jsでrequireして利用することが、分からなかったので、以下の力技的な方法を使った
var fs = require('fs'); eval(fs.readFileSync('./jis2utf8lib.js'));
jsでchar*を渡すには
呼び出し先で参照のみの文字列を渡す場合
Module.cwrapで'string'を指定すれば、文字列を渡すこが出来る。
呼び出し先に編集して貰うchar*を渡すには
Module.cwrapで'number'を指定し、Module._mallocで必要な領域を確保して渡せば、js化したC言語の関数内で処理した結果を受け取ることが可能。
var jis2utf8 = Module.cwrap('jis2utf8', 'number', ['string','number']); var ptr = Module._malloc(length); jis2utf8(jisBuf.toString('ascii'), ptr); var view = Module.HEAPU8.subarray(ptr, ptr+length); var str = Uint8ToString(view); function Uint8ToString(u8a){ var buf=new Buffer(u8a.length); for(var i = 0; i < u8a.length&&u8a[i]!=0; i++) { buf.writeUInt8(u8a[i],i); } var nBuf = new Buffer(i); buf.copy(nBuf,0,0,i); return nBuf.toString('utf8'); }
まとめ
この記事書き終わろうとしている頃、sjisをutf-8に変換するjsピュア実装のリンクを貼ろうとググったらjconvがあっさり見つかった。
Link
関連記事
- slコマンドのWebGL版を作ろうとしたら
- Emscriptenでファイルを読み込む
- emscriptenでOpenGL
- 公式のOpenCVでWASM版OpenCV.jsがビルドできたのでnode.jsで動かそうとした件