ASCII85の基本
連日猛暑の上、新型コロナウイルス感染症の影響もあって身動きがとりにくくなっていて大変なのはわたしだけではないとは思います。皆様はmRNAキャリアの投入はお墨でございましょうか。わたしは週明けに1回目を投入予定でございます。家人たちは既に1回目を2週間前に接種済みでそろそろ抗体値が上昇するころかと思います。当所においてもデルタ株の罹患者が確認されており、注意が必要な状況です。とまあ、こんな事書き始めるときりがありませんが、本日お届けするのはPDFの中身のあのストリームを紐解く時に必要な情報です。PDFの内部構造はいくつかのデータストリームに分割されて並べられているのですが、ここで利用されているのがFlateストリームとAscii85ストリームです。今回はAscii85の方をお届けいたします。
基本構造
基本構造はBase64に類似するものです。異なるのは85進数として扱う事と、4文字のタプルから5文字分を生成するために容量が1.333倍になるBase64に対してAscii85では1.25倍となるところです。
今回はデコードできれば良いのでデコードのアルゴリズムを紹介しますが、エンコードは逆の手順でOKです。
Ascii]85にエンコードされたデータは5文字単位の塊に分け、これらをタプルと呼びます。各タプルは基数85で記述された数値として処理し、結果を8bit毎に区切って連結します。エンコードされた文字列が5の倍数でない場合、末尾にパディングキャラクターとして「u」を必要数付加します。
では、タプルの処理について例を用いて詳しく説明します。
5文字で構成されたタプルが以下の場合
9jqo^
各文字の文字コードを取得し、
0x39 0x6a 0x71 0x6f 0x5e
それぞれの数値から33(0x21)を引きます。
0x18 0x49 0x50 0x4e 0x3d
85が基数ですから上位の数値に85をかけつつ後続を加えていきます。
((((0x18 * 85) + 0x49) * 85 + 0x50) * 85 + 0x4e) * 85 + 0x3d
= 0x4d616e20
得られた結果を頭からバイト単位で区切ってデコード結果となります。
この手順をエンコードされた文字列分繰り返し、uでパディングした分は末尾から除外すると全体のデコード結果が得られます。
上記の例では
4d 61 6e 20
のAsciiコードの文字列をエンコードしたものだったので復号結果は
Man
となります。これはウィキペディアのAscii85についての記事のエンコード例の冒頭部分です。
で、諸々を勘案した上で書いた関数が以下です(^-^;
function efdecoder(st)
{
var tmp = [];
var ar = st.split("");
var n = 5 - ar.length % 5;
var t = 0;
result = "";
for (var i=0;i<n;i++) ar.push('u');
while (ar.length>0)
{
for (i=0;i<5;i++) t = t*85 + (ar.shift().charCodeAt(0) - 33);
for (i=0;i<4;i++)
{
tmp.unshift(String.fromCharCode(t&255));
t >>= 8;
}
if (ar.length==0) for (i=0;i<n;i++) tmp.pop();
result += tmp.join("");
tmp = [];
}
return result;
}
最後に、Asscii85の特徴としては85進数を利用するためにBase64よりデータ効率が良くなる事と、85個のキャラクタにはシングル・ダブルのクォーテーションマークやバックスラッシュが含まれていてJavaScriptではめちゃくちゃ扱いにくい点ですw
おまけ、ドレンホースからゴキブリ入るの塞ぐのに便利なやつ…