XPCOMでUTF-8文字列から入力ストリームを作る
- 最近、XULの勉強をしている。
- Gaucheの豊富なポート操作に慣れているおかげで、XPCOMのストリームの理解がそれほど苦にならない。
- GaucheはポートにバイナリIOとキャラクタIOを混ぜて使えたり、
ファイルを重複して開いてもポートへの操作を共有してくれたりと、微に入り細を穿っている。
- JavascriptはSchemeに設計のヒントを得ているというし、やはりSchemeを勉強しておいてよかった。
- "プログラミングに必要な知恵はすべてGaucheユーザリファレンスで学んだ"
さて、XPCOMで、Gaucheのopen-input-string、つまりUTF-8文字列から入力ストリームを作ってみよう。2通りの方法を得た。
const Cc = Components.classes; const Ci = Components.interfaces; function openInputString(aString) { var converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"] .createInstance(Ci.nsIScriptableUnicodeConverter); converter.charset = "UTF-8"; var s = converter.convertToInputStream(aString); var stream = Cc["@mozilla.org/intl/converter-input-stream;1"] .createInstance(Ci.nsIConverterInputStream); stream.init(s, "UTF-8", 1024, Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER); return stream; }
- 2. nsIStorageStreamという入出力ストリームに、UTF-8のPascal文字列(先頭4byteに、文字列の長さが書いてある)をnsIBinaryOutputStreamで出力してから入力ストリームをとって、それをnsIConverterInputStreamでUTF-8入力ストリームにする。
function openInputString2(aString) { var storage = Cc["@mozilla.org/storagestream;1"] .createInstance(Ci.nsIStorageStream); // I have no idea what to pick for the first parameter (segments) storage.init(4, 0xffffffff, null); var out = storage.getOutputStream(0); var binout = Cc["@mozilla.org/binaryoutputstream;1"] .createInstance(Ci.nsIBinaryOutputStream); binout.setOutputStream(out); binout.writeUtf8Z(aString); binout.close(); var trunc = 4; var s = storage.newInputStream(trunc); var stream = Cc["@mozilla.org/intl/converter-input-stream;1"] .createInstance(Ci.nsIConverterInputStream); stream.init(s, "UTF-8", 1024, Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER); return stream; }
使用例。コンソールに"あいうえお"と出る。
var stream = openInputString("あいうえお"); var str = {}; var numChars = stream.readString(1024, str); if (numChars != 0 /* EOF */) Application.console.log(str.value);
ついでに、方法2でwriteUtf8Zが書き込んだPascal文字列の先頭4byteを見るコード
function pascal(aString) { var storage = Cc["@mozilla.org/storagestream;1"] .createInstance(Ci.nsIStorageStream); // I have no idea what to pick for the first parameter (segments) storage.init(4, 0xffffffff, null); var out = storage.getOutputStream(0); var binout = Cc["@mozilla.org/binaryoutputstream;1"] .createInstance(Ci.nsIBinaryOutputStream); binout.setOutputStream(out); binout.writeUtf8Z(aString); binout.close(); var s = storage.newInputStream(0); var binin = Cc["@mozilla.org/binaryinputstream;1"] .createInstance(Ci.nsIBinaryInputStream); binin.setInputStream(s); var bytes = binin.readByteArray(4); Application.console.log(bytes); }
"あいうえお"だとUTF-8で15byteなのでコンソールに[0,0,0,15]と出る。
参考文献
- Reading textual data - MDC
- (方法1)Sending a POST with binary and utf-8 encoded strings in Mozilla
- (方法2)
- Re: nsIStringInputStream and UTF-8 by Darin Fisher
- jsonview.jsの235-253行(コメントに「なぜか先頭4byteに謎のゴミが入ってる」と書いてあってちょっと面白い。Pascal文字列だよ。)
- XPCOM