Base128

最近お遊びで JavaScript を書いていると気がついたら C++ を書いてるのはなぜか疑問に思っていたのですが、それは Node.js の拡張モジュールを作っていたからなのでした。

Base128

というわけで、しょうもないものができたので公開します。ついに npm デビュー★

Base64 とは

Base64 とは、オリジナルのバイナリを 64 文字の可視 ASCII 文字、つまり大文字小文字英字52文字と数字10文字とあと +/ (余白を埋めるのに = も) を使って表現する方式で、例えば、オリジナルの 3 オクテットのデータ (24bit) は 4/3 倍されて 4 オクテット (32bit) になります。

結果、バイナリデータがクリーンな ASCII 文字で表現できるので可搬性が増したりします。 実際、そうはいっても +/ があるので、URL に入ってるとダブルエスケープされたりして困ったことになったりとかはありがちなんですが…

しかしこの方式、ちょっと無駄があるんですね。

例えば、JSON (やJavaScript) はその文字形式として Unicode 文字の UTF-8 表現を採用しているので、UTF-8 で表現できないバイト列は格納できず、バイナリの表現型も定まってないので例えば画像などは Base64 して格納することが多いです。

この場合、これらのバイナリデータは 4/3 倍に増えるわけですが、UTF-8 の仕様上、U+0000 から U+007F に該当する UTF-8 表現、つまり、0x00 から 0x7F なのですが、これらはどのような組み合わせをしても不正な UTF-8 表現にはなりません。つまり、0x00 から 0x7F の 7bit は自由にバイナリを埋め込んでいいことになります。

例えば、42byte のデータは Base64 だと 56byte になるのに対して、 UTF-8 で自由に使える 7bit を幅を全部使うと 48byte で表現できます。

base128 モジュール

ということで、base128 モジュールです。 base128 モジュールは Unicode 文字の U+0000 から U+007F の128文字を使って任意のバイナリを正規の UTF-8 文字列に相互変換するものです。

例えば、0xFF 0x01 というバイト列は、U+007F U+0003 U+0000 の3文字になります。 Base64 のように 6bit の数値表現から可視 ASCII 文字への変換がないので単純な bit 演算だけで取り出せるのでエンコード・デコードは楽かなあという気がします。

使い道は、バイナリを JSON に埋め込んだり、あるいは UTF-8 前提のプロトコル、例えば古い WebSocket でバイナリを送りつけたりするときに便利かなとおもいます。

注意点としてはなんかこういう仕様がデファクトだったりどこかで決まっているわけではないので閉じたシステム以外では使わないほうがいいということくらいでしょうか。

Node.jsのモジュールを作る

初めての npm なうえに C++ なんでもう何年ぶりでしょうっていう感じで書いたのでいろいろアレなところがあると思いますが公開しました。モジュールは このへん にあります。

$ npm install base128
$ node
> var base128 = require('base128')
> base128.encode(new Buffer([0xFF, 0x01]))

とかして遊んでください。インストールには全然 JavaScript ピュアじゃないモジュールなのでコンパイラとか必要です。

今回 npm でモジュール作ってみた感想としては、なかなか整理されてるなと思った反面、package.json に何書いたらいいのかよくわからなくて require できないモジュールを作ってしまったりとかしました。しかし、こんなかんじでサクサク作れるなら悪くないかなと思った次第です。Node.js は C++ を書いて使うものだったんですね!

ソースは このへん です。 間違いとかアレゲな点、あったら是非 @niw まで教えて下さい。

それでは。これから iPhone 5 予約体制に入ります1!

  1. これが書かれた当時は iPhone 5 発売予約の2時間前でした。 ↩︎