2010-08-27

JavaScriptからバイナリファイルを読む

JavaScriptからバイナリファイルが読めると知った( Handling binary data - XMLHttpRequestの利用 - MDC )ので、色々試しているところです。

flash(flex)のURLLoaderByteArrayに似せたクラスがあればflashとの相互移植がやりやすくなりそうだなと思い、作ってみたり。

いくつか直面した問題を列挙。

  • Google Chromeでローカル・同一ディレクトリ下のファイルにアクセスできない。

    どうもセキュリティ上の都合のようです。コマンドラインオプション –allow-file-access-from-files で回避できました。(参考: Maginot-line: Error: NETWORK_ERR: XMLHttpRequest Exception 101)

  • IE8のXMLHttpRequestでローカル・同一ディレクトリ下のファイルにアクセスできない。

    ActiveXObject("Msxml2.XMLHTTP")ならアクセスできました。

  • IEでバイナリが取得できない。

    Msxml2.XMLHTTPにはoverrideMimeTypeは無く、responseTextでは正しくバイナリが取得できません。0のところで列が切れてしまうみたいです。responseBodyを使うと取得できるのですが、これはJavaScriptからはアクセスできず、VBScriptを経由してアクセスするものらしいです。(参考: JavaScriptによるLZHの解凍サンプル)

    私は以下のようなコードでresponseBodyの中身をJavaScript文字列へ変換しました。かなり遅いです。

    execScript("Function vbBinaryToText(bin)n"+
    	   "  Dim in"+
    	   "  Dim sn"+
    	   "  s=""n"+
    	   "  For i=1 to LenB(bin)n"+
    	   "    s = s & ChrW(AscB(MidB(bin, i, 1)))n"+
    	   "  Nextn"+
    	   "  vbBinaryToText = sn"+
    	   "End Functionn"+
    	   "n", "VBScript");
    str = vbBinaryToText(xhr.responseBody);
    
  • 文字列の文字エンコーディング変換が難しい。

    ByteArray.readMultiByte()のようなことをするのは難しそうです。Escape Codec Library: ecl.jsでやっているようなことをすれば実装できるのだとは思いますが、とりあえずUTF-8さえデコードできれば十分なので、readUTFBytes相当だけ実装しました。手元にあったC++の変換コードを移植。JavaScriptの内部エンコーディングはUTF-16っぽいのでサロゲートペアは分割。

  • 浮動小数点数バイナリの読み書きが難しい。

    NaN(JavaScriptにqNaNとsNaNの区別ってあるの?)、±無限大、±0、非正規数、正規化数をそれぞれ自分で分解・組みたてするしかないんでしょうね。powを使うのかな。