TOP MAP UP

PS2 LZSS

PS2で使用されている圧縮方法はいくつかあるのだが、現在確認した普遍的な圧縮方法はzlibで解凍できる物(ただし断っておくがzlibで解凍できる物=zlibで圧縮してある物 or 実際にPS2でzlibが動いている、というわけではないので注意)と、以下に解説する圧縮方法である。
もちろん他にも色々な圧縮方法はあるが(解析した中ではステルヴィアとか)いずれも汎用的というよりは、そのソフトの為に(特定向けの為に)作った圧縮方法であるし、圧縮率もはっきり言って高くないし、データ構造から容易に復元可能なのでここでは解説は割愛する
今回ここで取り上げるのは(正式名称はわからないが呼称がないと不便なので)PS2 LZSSと呼ぶ圧縮方法である。

これまでの流れ

PS2 LZSSを初めて認識したのはPS2イニシャルDでICPというフォーマットの中身がどうも圧縮データのようだなと判断した時が最初である。その時は他のいわゆるTIM2フォーマットを解析する方に重点を置いていたので、圧縮データは後で実機のバイナリを解析して解凍しようと考えていた(その時は保留)
次に出会ったのがPS2いちご100%だが、実はこの圧縮がイニDと同じ圧縮方式であるという認識は無かった(むしろいちご100%の為に作られたオリジナルの圧縮かと思っていた)実際の解析作業はこのようにして行った
次がPS2ロボット作ろうぜ!だが、いちご100%ではごく一部のデータでしか出なかった解凍失敗がメインの画像でも沢山出た。この時は「何故失敗するのか?」までを問い詰める時間が無かったので、そのままリリースも保留していた
最後にPS2ひぐらしのなく頃に 祭でも同じように解凍失敗が出た。この時はひぐらしは自分ではとても好きなので、バリバリに気合が入っていたので、解凍失敗を追いかけ、問題点を発見する事ができ、完全なデコードを行う事が可能になった。(ちなみにひぐらしは厳密にはここで言うPS2 LZSSとはちょっと実装方式が違う)
ちなみにソフトによって失敗が出たり出なかったりしているが、これはエンコーダ側がより高圧縮率を達成できるように改良された為と思われる。

データ構造

圧縮データのストリームは規定があるが、それに付随するデータ(具体的には圧縮データ長さ、解凍データ長さ等)をどう配置するかは規定が無いので、ソフト毎、フォーマット毎に配置や格納場所が異なるので自力で探す必要がある。まぁしかしながら見つけるのはそう大した問題ではないと思う

次に圧縮データストリームだが、最初に1byteの圧縮フラグが出てくる。このフラグは右〜左のビット順で、1なら1byteの無圧縮データ、0なら2byteの圧縮データ、と以降8組のデータのフラグになっている。以降、圧縮データストリームが終わるまで、圧縮フラグ>8組のデータ>圧縮フラグ>8組のデータ・・・・と続く

圧縮データは左から3ニブルが位置情報(以降これを便宜上「D」と表現する)、最後の1ニブルが長さ情報(以降これを便宜上「L」とする)となっている。ちなみに基本的な事であるが、4bitひとかたまりを1ニブルという(4bit=1nibble=1hexdigit,2nibble=1byte,4nibble=2byte)

Lは表現可能な範囲は0-15(0x0-0xf)だが、実際には3を足した3-18を表現している(これはそもそも圧縮データその物が2byte表現なので、3byte以上圧縮出来ないと圧縮の意味が無いからであろう)

この圧縮フォーマットは辞書式圧縮であり(いちご100%の記録ではrun lengthも併用と書いているが実際は違った)、Dによる参照先がまだ未展開の場合は、参照先可能な部分を繰り返し展開していく、という動作によって解凍される。

Dは表現可能な範囲は0x000-0xfffだが、これでは普通に使用するデータの範囲としては圧倒的に狭すぎる。その為、実際には処理中の展開先アドレスの下位3ニブルを表現している。この表現方法の為、ラップアラウンド処理、(アドレス演算の)繰り上がり処理等が煩雑になる

実際の解凍コードはこれ