javascriptでバイナリを扱うために

html5の時代になってjsでバイナリデータを扱うことが増えてきている.
そんななかで覚えておくべきことをいくつかメモしておく.
C言語におけるintやshortなどの型ついて知っておくと楽になる.
具体的なことはあまり書いてないので実際にそういったプログラムを作るには,
出てきた単語をぐぐって欲しい.

# そもそもバイナリデータをどうやって扱う?
jsでは主に`Uint8Array`という配列を使って扱うことが多いだろう.
この`Uint8Array`というのは数値しか記録できず,値が0から255までの初期化時に長さが決まる配列である.
`Uint8Array`というのはつまり,負の数なし(Unsigned)の整数(int)で,要素一つあたり1バイト(8bit = 1byte)の配列(Array)ということである.
C言語における`unsigned char[]`に相当する.
この配列は連想配列ではなく純粋な配列であることに注意する.
バイナリデータとjsを結びつけるためにはFileAPIやXMLHttpRequestを用いる.

# Uint8ArrayとArrayBuffer
バイナリデータの扱い方について調べるとよく出てくるものに`ArrayBuffer`というものがある.
`ArrayBuffer`は実際にメモリ上に確保されているバッファを示すものである.
しかし,直接値を読んだり書き込んだりすることができないためそのまま使用することはほとんどない.
基本的には`Uint8Array`の引数に渡して`Uint8Array`のインスタンスを作るなどに使われる.
`Uint8Array`は直接読み書き可能なので扱いやすい.
`ArrayBuffer`からデータを読み出すだけでいいというのなら`DataView`というものを使うことで簡単に読み出すことができる.
ただし`DataView`を使用する場合はエンディアンに注意する.

追記:
`DataView`について詳しく調べてみるとどうやら書き込みもできてエンディアンの指定もできるようだ.
`DataView`が使えるなら積極的に使った方が良さそうだ.
ただし`DataView`には文字を読み込む機能がないので,文字の読み込みは文字コードに注意しながら自分で書く必要がある.
またごくまれにだがビット単位でバイナリを扱わなければならないこともある.
そういう場合は`DataView`が使えないので,そんな場合の例を下の方に追記しておく.

# TypedArray
C言語の`unsigned short[]`や`float[]`にあたる`Uint16Array`や`Float32Array`などの配列も用意されている.
これらの配列を`TypedArray`と呼び,全て共通して型付きで純粋な配列である.
バイナリデータから`short`や`float`で値を取り出したいときに使用する.
自分でエンディアンを指定することができずCPUネイティブで処理される(多くの場合はリトルエンディアン).
また,アライメントの問題なども出てくるため少し使いづらい.

# stringは2バイト
jsの`string`は基本的に1文字に付き2バイトであるため`Uint8Array`に格納するときは注意が必要である.
文字コードにも注意する.

# Uint8Arrayから値を読み出す
`DataView`を使わないととたんにめんどくさくなる.
使える場合はどんどん使えばよいがそうでない場合はどうすればいいのか.
`Uint8Array`からビッグエンディアンの`short`(負数あり2バイト)のデータを読み出すサンプルを示す.

```js:readBigendianShort.js
var uint8array = new Uint8Array(arrayBuffer);  //arrayBufferにはデータが入っているとする
var value = (uint8array[0] << 8) + uint8array[1];
if(value & 0x8000){
    value = -((value - 1) ^ 0xffff);    //2の補数計算
}
alert(value);    //valueに変換された値
```

ビックエンディアンや2の補数については調べればたくさん出てくるので割愛する.

追記:バイナリをビット単位で扱わないといけない例
swfファイルのヘッダにはFrameSizeというフィールドがある.
このフィールドのデータを得るためにはビット単位でバイナリを読み込んでいく必要がある.
(参考URL)[SWFバイナリ編集のススメ第一回](http://labs.gree.jp/blog/2010/08/631/ "SWFバイナリ編集のススメ第一回")

このFrameSizeを読み込むコードの例を以下に示す.

```js:readRect.js
function readRect(arraybuffer){
    var uint8array = new Uint8Array(arraybuffer);
    var NBits = uint8array[0] >> 3;
    var frameSize = {NBits:NBits};
    var filedNames = ['Xmin', 'Xmax', 'Ymin', 'Ymax'];
    var bitOffset = 2;    //最上位bitのオフセットを7とする
    var byteOffset = 0;
    for(var i = 0;i < 4;i++){
        var temp = 0;
        for(var j = 0;j < NBits;j++){
            temp <<= 1;
            var mask = 1 << bitOffset;
            temp += (uint8array[byteOffset] & mask) >> bitOffset;
            bitOffset--;
            if(bitOffset < 0){
                byteOffset++;
                bitOffset = 7;
            }
        }
        frameSize[filedNames[i]] = temp;
    }
    return frameSize;
}
```

この``readRect``関数を``readRect([0x70, 0x00, 0x09, 0x60, 0x00, 0x00, 0x96,  0x00])``のような感じで呼び出してやるとFrameSizeがかえってくる.
``Uint8Array``は普通の``Array``を引数に渡しても大丈夫なのでこれも扱いやすいポイントのひとつである.
上記の例では``{NBits: 14, Xmin: 0, Xmax: 4800, Ymin: 0, Ymax: 4800}``のようなオブジェクトがかえってくる.


# 最後に
バイナリをいじくるプログラムはjsでは書きやすいとは言えないと思います.
ただ,一度書けば基本的にWindowsでもMacでもiPhoneでも動くし,ブラウザ上で動くのですごく楽しい.

クライアントサイドjsのみでzipを作成したり,音楽ファイルをエンコードしたりするライブラリが既に出てきていて,昔では考えられないような状態になってきました.
このビックウェーブに乗り遅れないよう楽しいバイナリライフを送りましょう!