今回圧縮形式のX Fileの読み込みコードを制作するにあたり、MSZip圧縮データの
伸長を自作してみました。MSZip圧縮は、RFC1951(Deflate format)のアプリケーション
になっているので、元の資料にあたればすんなり作れるとたかをくくっていたのですが、
やってみると案外ハマるポイントが多かったのです。ただ、結果として出来上がったので、
ハマった部分をメモしておこうと、この記事を作成しました。
特にハマったのは、ビットの順序、英語で読んでも日本語訳を読んでも全くわからない。
判った後原文を読むと、『ああ確かに書いてあったね』なのですが、始めて読んだときは意味が判らない
書き方がされているのも事実。そのあたり少し力を入れて解説してみます。
| Byte 0 | Byte 1 | Byte 2 | |||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
これは中身の順番と必ずしも一致しないので要注意。
これはあくまで読み出し順序。
読み取ったデータをどのように解釈するかによって
ビットの並び順が違うので要注意。
ハフマン符号以外のデータは、保存する際、
元のデータをLSB->MSBの順で読み取って、
上の表の順序で保存されます。
ハフマン符号は、上位ビットから順に読みだす
(ハフマン木の上から見ていく)ようにしないと
ビット長が判らないため、MSB->LSB の順で保存されます。
ここで要注意なのが、固定ハフマン木を使ったデコード(後述)。
距離を示すデータは、全ての値が5ビットとなる設定だが、
それらはハフマン符号とは言えないような値なのに、
ビットの並びはハフマン符号扱いになっているのでハマる。
ブロックは3種類あって、最初の3ビットで識別される。
まず一つ目のビットは最終ブロックか否かを表す。 (最終ブロックを伸長するまで伸長後のデータサイズは 判らない)
まずはじめの1ビットは、0なら次のブロックあり、1なら そのブロックでデータ終了の意味。
続く2ビットは、ブロックの種類。これを、
LSB->MSBの順序で読み出す。
MSB->LSB
?????101
は最終ブロックで、ブロック種別が、10 だと
みなす。
このブロック種別は、
| Code | Extra Bits | Length(s) | Code | Extra Bits | Length(s) | Code | Extra Bits | Length(s) |
|---|---|---|---|---|---|---|---|---|
| 257 | 0 | 3 | 267 | 1 | 15,16 | 277 | 4 | 67-82 |
| 258 | 0 | 4 | 268 | 1 | 17,18 | 278 | 4 | 83-98 |
| 259 | 0 | 5 | 269 | 2 | 19-22 | 279 | 4 | 99-114 |
| 260 | 0 | 6 | 270 | 2 | 23-26 | 280 | 4 | 115-130 |
| 261 | 0 | 7 | 271 | 2 | 27-30 | 281 | 5 | 131-162 |
| 262 | 0 | 8 | 272 | 2 | 31-34 | 282 | 5 | 163-194 |
| 263 | 0 | 9 | 273 | 3 | 35-42 | 283 | 5 | 195-226 |
| 264 | 0 | 10 | 274 | 3 | 43-50 | 284 | 5 | 227-257 |
| 265 | 1 | 11,12 | 275 | 3 | 51-58 | 285 | 0 | 258 |
| 266 | 1 | 13,14 | 276 | 3 | 59-66 |
| Code | Extra Bits | Dist | Code | Extra Bits | Dist | Code | Extra Bits | Dist |
|---|---|---|---|---|---|---|---|---|
| 0 | 0 | 1 | 10 | 4 | 33-48 | 20 | 9 | 1025-1536 |
| 1 | 0 | 2 | 11 | 4 | 49-64 | 21 | 9 | 1537-2048 |
| 2 | 0 | 3 | 12 | 5 | 65-96 | 22 | 10 | 2049-3072 |
| 3 | 0 | 4 | 13 | 5 | 97-128 | 23 | 10 | 3073-4096 |
| 4 | 1 | 5,6 | 14 | 6 | 129-192 | 24 | 11 | 4097-6144 |
| 5 | 1 | 7,8 | 15 | 6 | 193-256 | 25 | 11 | 6145-8192 |
| 6 | 2 | 9-12 | 16 | 7 | 257-384 | 26 | 12 | 8193-12288 |
| 7 | 2 | 13-16 | 17 | 7 | 385-512 | 27 | 12 | 12289-16384 |
| 8 | 3 | 17-24 | 18 | 8 | 513-768 | 28 | 13 | 16385-24576 |
| 9 | 3 | 25-32 | 19 | 8 | 769-1024 | 29 | 13 | 24577-32768 |
距離と長さを算出できたら、これからデータを書き込もうとする アドレスから、距離分だけ戻った位置から、長さ分のデータをコピー して次に進みます。
| 出力データ | 長さ | ハフマン符号 | 読みだされる符号 |
|---|---|---|---|
| 0 | 8 | 0x030 | 00001100 |
| 1 | 8 | 0x031 | 10001100 |
| 2 | 8 | 0x032 | 01001100 |
| 3 | 8 | 0x033 | 11001100 |
| 4 | 8 | 0x034 | 00101100 |
| 5 | 8 | 0x035 | 10101100 |
| 6 | 8 | 0x036 | 01101100 |
| 7 | 8 | 0x037 | 11101100 |
| 8 | 8 | 0x038 | 00011100 |
| 9 | 8 | 0x039 | 10011100 |
| 10 | 8 | 0x03a | 01011100 |
| 11 | 8 | 0x03b | 11011100 |
| 12 | 8 | 0x03c | 00111100 |
| 13 | 8 | 0x03d | 10111100 |
| 14 | 8 | 0x03e | 01111100 |
| 15 | 8 | 0x03f | 11111100 |
| 16 | 8 | 0x040 | 00000010 |
| 17 | 8 | 0x041 | 10000010 |
| 18 | 8 | 0x042 | 01000010 |
| 19 | 8 | 0x043 | 11000010 |
| 20 | 8 | 0x044 | 00100010 |
| 21 | 8 | 0x045 | 10100010 |
| 22 | 8 | 0x046 | 01100010 |
| 23 | 8 | 0x047 | 11100010 |
| 24 | 8 | 0x048 | 00010010 |
| 25 | 8 | 0x049 | 10010010 |
| 26 | 8 | 0x04a | 01010010 |
| 27 | 8 | 0x04b | 11010010 |
| 28 | 8 | 0x04c | 00110010 |
| 29 | 8 | 0x04d | 10110010 |
| 30 | 8 | 0x04e | 01110010 |
| 31 | 8 | 0x04f | 11110010 |
| 32 | 8 | 0x050 | 00001010 |
| 33 | 8 | 0x051 | 10001010 |
| 34 | 8 | 0x052 | 01001010 |
| 35 | 8 | 0x053 | 11001010 |
| 36 | 8 | 0x054 | 00101010 |
| 37 | 8 | 0x055 | 10101010 |
| 38 | 8 | 0x056 | 01101010 |
| 39 | 8 | 0x057 | 11101010 |
| 40 | 8 | 0x058 | 00011010 |
| 41 | 8 | 0x059 | 10011010 |
| 42 | 8 | 0x05a | 01011010 |
| 43 | 8 | 0x05b | 11011010 |
| 44 | 8 | 0x05c | 00111010 |
| 45 | 8 | 0x05d | 10111010 |
| 46 | 8 | 0x05e | 01111010 |
| 47 | 8 | 0x05f | 11111010 |
| 48 | 8 | 0x060 | 00000110 |
| 49 | 8 | 0x061 | 10000110 |
| 50 | 8 | 0x062 | 01000110 |
| 51 | 8 | 0x063 | 11000110 |
| 52 | 8 | 0x064 | 00100110 |
| 53 | 8 | 0x065 | 10100110 |
| 54 | 8 | 0x066 | 01100110 |
| 55 | 8 | 0x067 | 11100110 |
| 56 | 8 | 0x068 | 00010110 |
| 57 | 8 | 0x069 | 10010110 |
| 58 | 8 | 0x06a | 01010110 |
| 59 | 8 | 0x06b | 11010110 |
| 60 | 8 | 0x06c | 00110110 |
| 61 | 8 | 0x06d | 10110110 |
| 62 | 8 | 0x06e | 01110110 |
| 63 | 8 | 0x06f | 11110110 |
| 64 | 8 | 0x070 | 00001110 |
| 65 | 8 | 0x071 | 10001110 |
| 66 | 8 | 0x072 | 01001110 |
| 67 | 8 | 0x073 | 11001110 |
| 68 | 8 | 0x074 | 00101110 |
| 69 | 8 | 0x075 | 10101110 |
| 70 | 8 | 0x076 | 01101110 |
| 71 | 8 | 0x077 | 11101110 |
| 72 | 8 | 0x078 | 00011110 |
| 73 | 8 | 0x079 | 10011110 |
| 74 | 8 | 0x07a | 01011110 |
| 75 | 8 | 0x07b | 11011110 |
| 76 | 8 | 0x07c | 00111110 |
| 77 | 8 | 0x07d | 10111110 |
| 78 | 8 | 0x07e | 01111110 |
| 79 | 8 | 0x07f | 11111110 |
| 80 | 8 | 0x080 | 00000001 |
| 81 | 8 | 0x081 | 10000001 |
| 82 | 8 | 0x082 | 01000001 |
| 83 | 8 | 0x083 | 11000001 |
| 84 | 8 | 0x084 | 00100001 |
| 85 | 8 | 0x085 | 10100001 |
| 86 | 8 | 0x086 | 01100001 |
| 87 | 8 | 0x087 | 11100001 |
| 88 | 8 | 0x088 | 00010001 |
| 89 | 8 | 0x089 | 10010001 |
| 90 | 8 | 0x08a | 01010001 |
| 91 | 8 | 0x08b | 11010001 |
| 92 | 8 | 0x08c | 00110001 |
| 93 | 8 | 0x08d | 10110001 |
| 94 | 8 | 0x08e | 01110001 |
| 95 | 8 | 0x08f | 11110001 |
| 96 | 8 | 0x090 | 00001001 |
| 97 | 8 | 0x091 | 10001001 |
| 98 | 8 | 0x092 | 01001001 |
| 99 | 8 | 0x093 | 11001001 |
| 100 | 8 | 0x094 | 00101001 |
| 101 | 8 | 0x095 | 10101001 |
| 102 | 8 | 0x096 | 01101001 |
| 103 | 8 | 0x097 | 11101001 |
| 104 | 8 | 0x098 | 00011001 |
| 105 | 8 | 0x099 | 10011001 |
| 106 | 8 | 0x09a | 01011001 |
| 107 | 8 | 0x09b | 11011001 |
| 108 | 8 | 0x09c | 00111001 |
| 109 | 8 | 0x09d | 10111001 |
| 110 | 8 | 0x09e | 01111001 |
| 111 | 8 | 0x09f | 11111001 |
| 112 | 8 | 0x0a0 | 00000101 |
| 113 | 8 | 0x0a1 | 10000101 |
| 114 | 8 | 0x0a2 | 01000101 |
| 115 | 8 | 0x0a3 | 11000101 |
| 116 | 8 | 0x0a4 | 00100101 |
| 117 | 8 | 0x0a5 | 10100101 |
| 118 | 8 | 0x0a6 | 01100101 |
| 119 | 8 | 0x0a7 | 11100101 |
| 120 | 8 | 0x0a8 | 00010101 |
| 121 | 8 | 0x0a9 | 10010101 |
| 122 | 8 | 0x0aa | 01010101 |
| 123 | 8 | 0x0ab | 11010101 |
| 124 | 8 | 0x0ac | 00110101 |
| 125 | 8 | 0x0ad | 10110101 |
| 126 | 8 | 0x0ae | 01110101 |
| 127 | 8 | 0x0af | 11110101 |
| 128 | 8 | 0x0b0 | 00001101 |
| 129 | 8 | 0x0b1 | 10001101 |
| 130 | 8 | 0x0b2 | 01001101 |
| 131 | 8 | 0x0b3 | 11001101 |
| 132 | 8 | 0x0b4 | 00101101 |
| 133 | 8 | 0x0b5 | 10101101 |
| 134 | 8 | 0x0b6 | 01101101 |
| 135 | 8 | 0x0b7 | 11101101 |
| 136 | 8 | 0x0b8 | 00011101 |
| 137 | 8 | 0x0b9 | 10011101 |
| 138 | 8 | 0x0ba | 01011101 |
| 139 | 8 | 0x0bb | 11011101 |
| 140 | 8 | 0x0bc | 00111101 |
| 141 | 8 | 0x0bd | 10111101 |
| 142 | 8 | 0x0be | 01111101 |
| 143 | 8 | 0x0bf | 11111101 |
| 144 | 9 | 0x190 | 000010011 |
| 145 | 9 | 0x191 | 100010011 |
| 146 | 9 | 0x192 | 010010011 |
| 147 | 9 | 0x193 | 110010011 |
| 148 | 9 | 0x194 | 001010011 |
| 149 | 9 | 0x195 | 101010011 |
| 150 | 9 | 0x196 | 011010011 |
| 151 | 9 | 0x197 | 111010011 |
| 152 | 9 | 0x198 | 000110011 |
| 153 | 9 | 0x199 | 100110011 |
| 154 | 9 | 0x19a | 010110011 |
| 155 | 9 | 0x19b | 110110011 |
| 156 | 9 | 0x19c | 001110011 |
| 157 | 9 | 0x19d | 101110011 |
| 158 | 9 | 0x19e | 011110011 |
| 159 | 9 | 0x19f | 111110011 |
| 160 | 9 | 0x1a0 | 000001011 |
| 161 | 9 | 0x1a1 | 100001011 |
| 162 | 9 | 0x1a2 | 010001011 |
| 163 | 9 | 0x1a3 | 110001011 |
| 164 | 9 | 0x1a4 | 001001011 |
| 165 | 9 | 0x1a5 | 101001011 |
| 166 | 9 | 0x1a6 | 011001011 |
| 167 | 9 | 0x1a7 | 111001011 |
| 168 | 9 | 0x1a8 | 000101011 |
| 169 | 9 | 0x1a9 | 100101011 |
| 170 | 9 | 0x1aa | 010101011 |
| 171 | 9 | 0x1ab | 110101011 |
| 172 | 9 | 0x1ac | 001101011 |
| 173 | 9 | 0x1ad | 101101011 |
| 174 | 9 | 0x1ae | 011101011 |
| 175 | 9 | 0x1af | 111101011 |
| 176 | 9 | 0x1b0 | 000011011 |
| 177 | 9 | 0x1b1 | 100011011 |
| 178 | 9 | 0x1b2 | 010011011 |
| 179 | 9 | 0x1b3 | 110011011 |
| 180 | 9 | 0x1b4 | 001011011 |
| 181 | 9 | 0x1b5 | 101011011 |
| 182 | 9 | 0x1b6 | 011011011 |
| 183 | 9 | 0x1b7 | 111011011 |
| 184 | 9 | 0x1b8 | 000111011 |
| 185 | 9 | 0x1b9 | 100111011 |
| 186 | 9 | 0x1ba | 010111011 |
| 187 | 9 | 0x1bb | 110111011 |
| 188 | 9 | 0x1bc | 001111011 |
| 189 | 9 | 0x1bd | 101111011 |
| 190 | 9 | 0x1be | 011111011 |
| 191 | 9 | 0x1bf | 111111011 |
| 192 | 9 | 0x1c0 | 000000111 |
| 193 | 9 | 0x1c1 | 100000111 |
| 194 | 9 | 0x1c2 | 010000111 |
| 195 | 9 | 0x1c3 | 110000111 |
| 196 | 9 | 0x1c4 | 001000111 |
| 197 | 9 | 0x1c5 | 101000111 |
| 198 | 9 | 0x1c6 | 011000111 |
| 199 | 9 | 0x1c7 | 111000111 |
| 200 | 9 | 0x1c8 | 000100111 |
| 201 | 9 | 0x1c9 | 100100111 |
| 202 | 9 | 0x1ca | 010100111 |
| 203 | 9 | 0x1cb | 110100111 |
| 204 | 9 | 0x1cc | 001100111 |
| 205 | 9 | 0x1cd | 101100111 |
| 206 | 9 | 0x1ce | 011100111 |
| 207 | 9 | 0x1cf | 111100111 |
| 208 | 9 | 0x1d0 | 000010111 |
| 209 | 9 | 0x1d1 | 100010111 |
| 210 | 9 | 0x1d2 | 010010111 |
| 211 | 9 | 0x1d3 | 110010111 |
| 212 | 9 | 0x1d4 | 001010111 |
| 213 | 9 | 0x1d5 | 101010111 |
| 214 | 9 | 0x1d6 | 011010111 |
| 215 | 9 | 0x1d7 | 111010111 |
| 216 | 9 | 0x1d8 | 000110111 |
| 217 | 9 | 0x1d9 | 100110111 |
| 218 | 9 | 0x1da | 010110111 |
| 219 | 9 | 0x1db | 110110111 |
| 220 | 9 | 0x1dc | 001110111 |
| 221 | 9 | 0x1dd | 101110111 |
| 222 | 9 | 0x1de | 011110111 |
| 223 | 9 | 0x1df | 111110111 |
| 224 | 9 | 0x1e0 | 000001111 |
| 225 | 9 | 0x1e1 | 100001111 |
| 226 | 9 | 0x1e2 | 010001111 |
| 227 | 9 | 0x1e3 | 110001111 |
| 228 | 9 | 0x1e4 | 001001111 |
| 229 | 9 | 0x1e5 | 101001111 |
| 230 | 9 | 0x1e6 | 011001111 |
| 231 | 9 | 0x1e7 | 111001111 |
| 232 | 9 | 0x1e8 | 000101111 |
| 233 | 9 | 0x1e9 | 100101111 |
| 234 | 9 | 0x1ea | 010101111 |
| 235 | 9 | 0x1eb | 110101111 |
| 236 | 9 | 0x1ec | 001101111 |
| 237 | 9 | 0x1ed | 101101111 |
| 238 | 9 | 0x1ee | 011101111 |
| 239 | 9 | 0x1ef | 111101111 |
| 240 | 9 | 0x1f0 | 000011111 |
| 241 | 9 | 0x1f1 | 100011111 |
| 242 | 9 | 0x1f2 | 010011111 |
| 243 | 9 | 0x1f3 | 110011111 |
| 244 | 9 | 0x1f4 | 001011111 |
| 245 | 9 | 0x1f5 | 101011111 |
| 246 | 9 | 0x1f6 | 011011111 |
| 247 | 9 | 0x1f7 | 111011111 |
| 248 | 9 | 0x1f8 | 000111111 |
| 249 | 9 | 0x1f9 | 100111111 |
| 250 | 9 | 0x1fa | 010111111 |
| 251 | 9 | 0x1fb | 110111111 |
| 252 | 9 | 0x1fc | 001111111 |
| 253 | 9 | 0x1fd | 101111111 |
| 254 | 9 | 0x1fe | 011111111 |
| 255 | 9 | 0x1ff | 111111111 |
| 256 | 7 | 0x000 | 0000000 |
| 257 | 7 | 0x001 | 1000000 |
| 258 | 7 | 0x002 | 0100000 |
| 259 | 7 | 0x003 | 1100000 |
| 260 | 7 | 0x004 | 0010000 |
| 261 | 7 | 0x005 | 1010000 |
| 262 | 7 | 0x006 | 0110000 |
| 263 | 7 | 0x007 | 1110000 |
| 264 | 7 | 0x008 | 0001000 |
| 265 | 7 | 0x009 | 1001000 |
| 266 | 7 | 0x00a | 0101000 |
| 267 | 7 | 0x00b | 1101000 |
| 268 | 7 | 0x00c | 0011000 |
| 269 | 7 | 0x00d | 1011000 |
| 270 | 7 | 0x00e | 0111000 |
| 271 | 7 | 0x00f | 1111000 |
| 272 | 7 | 0x010 | 0000100 |
| 273 | 7 | 0x011 | 1000100 |
| 274 | 7 | 0x012 | 0100100 |
| 275 | 7 | 0x013 | 1100100 |
| 276 | 7 | 0x014 | 0010100 |
| 277 | 7 | 0x015 | 1010100 |
| 278 | 7 | 0x016 | 0110100 |
| 279 | 7 | 0x017 | 1110100 |
| 280 | 8 | 0x0c0 | 00000011 |
| 281 | 8 | 0x0c1 | 10000011 |
| 282 | 8 | 0x0c2 | 01000011 |
| 283 | 8 | 0x0c3 | 11000011 |
| 284 | 8 | 0x0c4 | 00100011 |
| 285 | 8 | 0x0c5 | 10100011 |
| 286 | 8 | 0x0c6 | 01100011 |
| 287 | 8 | 0x0c7 | 11100011 |
前半に格納されているハフマン木を読み取り、
読みとったハフマン木を使って、続く圧縮されたデータを読み取ります。
| サイズ | 名称 | 内容 |
|---|---|---|
| 5 bits | HLIT | Literal/Lengthコードの個数 - 257 |
| 5 bits | HDIST | Distance コードの個数 - 1 |
| 4 bits | HLEN | コード長コードの個数 - 4 |
| 0-15 | 単純にビット長として解釈 |
| 16 | 一つ前のコードのビット長を3~6回繰り返す、繰り返し回数は、 次の2ビットを読みだして、3を足す事で求める |
| 17 | 0を、3~10回繰り返す。繰り返し回数は次の3ビットを読み出し、 3を足す事で求める。 |
| 18 | 0を、11~138回繰り返す。繰り返し回数は次の7ビットを読み出し、 11を足す事で求める。 |
続いて格納されるのは、HLIT+257個の、Literal / Length コードのビットです。// Given : codeLengthsOfTheCodeLengths int *bitLengths = new int[19]; int *nextCodes = new int[19]; HuffmanCode node[19]; // members: WORD length; WORD code; int maxBits = -1; memset((VOID*)bitLengths,0,sizeof(int)*19); memset((VOID*)nextCodes,0,sizeof(int)*19); memset((VOID*)node,0,sizeof(node)); for (int i = 0; i <= 18 ; ++i){ int len = codeLengthsOfTheCodeLength[i]; node[i].length = len; bitLengths[len]++; if (maxBits < len) maxBits = len; } int code = 0; bitLengths[0] = 0; for (int bits = 1; bits <= 18; bits++) { code = (code + bitLengths[bits-1]) << 1; nextCodes[bits] = code; } for (int n = 0; n <= 18 ; n++) { int len = node[n].length; if (len != 0) { node[n].code = binreverse(nextCodes[len],len); nextCodes[len]++; } }