[Lha-users] The Hacking of LHa for UNIX (2nd draft)

Back to archive index

Koji Arai JCA02****@nifty*****
2003年 2月 12日 (水) 00:01:43 JST


新井です。

圧縮に関してはこれで終り。

Index: Hackinf_of_LHa
===================================================================
RCS file: /cvsroot/lha/lha/Hackinf_of_LHa,v
retrieving revision 1.12
retrieving revision 1.13
diff -u -u -r1.12 -r1.13
--- Hackinf_of_LHa	8 Feb 2003 20:09:25 -0000	1.12
+++ Hackinf_of_LHa	11 Feb 2003 14:59:29 -0000	1.13
@@ -1,4 +1,4 @@
-$Id: Hackinf_of_LHa,v 1.12 2003/02/08 20:09:25 arai Exp $
+$Id: Hackinf_of_LHa,v 1.13 2003/02/11 14:59:29 arai Exp $
 
                The Hacking of LHa for UNIX (2nd draft)
              -------------------------------------------
@@ -3796,13 +3796,13 @@
 
 ----------------------------------------------------------------------------
 
-output_mask        128   64    32                16    8     4     2     1
-            +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
-buf         |  32 | c1  | c2  | len |    off    |  c3 |  c4 |  c5 |  c6 |  c7 |
-            +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
-            cpos                                                             /
-                                                                            /
-                                                                   output_pos
+output_mask    128   64    32                16    8     4     2     1
+        +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
+buf     |  32 | c1  | c2  | len |    off    |  c3 |  c4 |  c5 |  c6 |  c7 |
+        +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
+        cpos                                                             /
+                                                                        /
+                                                               output_pos
 
 ----------------------------------------------------------------------------
 
@@ -3961,10 +3961,10 @@
 値 root だ)。このとき以下のような出力になる。(TBIT{5}, CBIT{9} である)
 
 ----------------------------------------------------------------------------
-      5bit
-   5bit   9bit 9bit
-   |--|--|----|----|
-   +--+--+----+----+
+      TBIT    CBIT
+   TBIT   CBIT
+   |--|--|----|----|               TBIT: 5
+   +--+--+----+----+               CBIT: 9
    | 0| 0|   0|root|
    +--+--+----+----+
 
@@ -4230,9 +4230,228 @@
      0        20以上    t_freq[2]++
    0以外                t_freq[c_len[i]+2]++;
 
-これがどういう理屈であるかはよくわからないが、とにかく頻度計算を
-行う場合に t_freq[0], t_freq[1], t_freq[2] を特別扱いしている。
+これがどういう理屈であるかはよくわからないが、とにかく頻度計算を行う場
+合に t_freq[0], t_freq[1], t_freq[2] を特別扱いしている。そして、頻度
+計算の対象が c_len[] であることから (B) の処理は、c_len[] に関して 
+Huffman 符号化を行う処理のようだ。
+
+そうして、make_tree() で、t_freq[] に関して Huffman 符号表を作成し、
+write_pt_len() で、この符号表(文字の Huffman 符号のビット長 c_len の 
+Huffman 符号のビット長) pt_len[] を出力する。
+
+static void
+write_pt_len(n, nbit, i_special)
+    short           n;
+    short           nbit;
+    short           i_special;
+{
+    short           i, k;
+
+    while (n > 0 && pt_len[n - 1] == 0)
+        n--;
+    putbits(nbit, n);
+    i = 0;
+    while (i < n) {
+        k = pt_len[i++];
+        if (k <= 6)
+            putbits(3, k);
+        else
+            putbits(k - 3, USHRT_MAX << 1);
+        if (i == i_special) {
+            while (i < 6 && pt_len[i] == 0)
+                i++;
+            putbits(2, i - 3);
+        }
+    }
+}
+
+最初に pt_len[] の要素数を TBIT{5} 出力し、続けて符号 bit 長 pt_len[] 
+の要素を出力している。pt_len[] を出力するときは、その値が 6 より大きい
+かどうかで形式を変えて出力している。6 以下であればそのまま 3 bit で出
+力し、7 bit 以上であれば、bit 数で表現するらしい。例えば pt_len[i] ==
+7 なら、1110 となる。最初の 3 bit は必ず 1 になり、最初の形式と区別が
+つくようになっている。
+
+さらに、i_special 番目の pt_len[i] を出力後は、i_special ... 6 の範囲
+で pt_len[i] == 0 が続くことを 2 bit で、表現している。i_special は
+write_pt_len() の 3 番目の引数で、今回の場合は 3 だ。例えば 
+pt_len[3..5] がすべて 0 なら pt_len[3] を出力後、i - 3 (= 3) を 2 bit 
+出力する。つまり、11 が出力される。このようなことをしている意味はこれ
+またよくわからない。ちょっと複雑なので図示してみた。
+
+----------------------------------------------------------------------------
+< pt_len[] の出力フォーマット >
+
+             0       TBIT{5}
+             +-------+-----------+-----------+--   --+-----------+
+             |   n   | pt_len[0] | pt_len[1] | ...    pt_len[n-1]|
+             +-------+-----------+-----------+--   --+-----------+
+
+pt_len[i] <= 6 の場合
+
+              0     3bit
+              +-----+
+    pt_len[i] | | | |
+              +-----+
+
+pt_len[i] >= 7 の場合
+
+              0             pt_len[i] - 3
+              +----------------+
+    pt_len[i] |1 1 1 1 ... 1 0 |
+              +----------------+
+
+pt_len[i_special] の直後は 2 bit の情報が付加される。この値を x とする
+と、pt_len[i_special .. x + 3] の範囲で 0 が続くことを意味する。
+
+----------------------------------------------------------------------------
+
+最後に、write_c_len() で、符号表 c_len[] と pt_code[] を出力する。
+
+static void
+write_c_len(/*void*/)
+{
+    short           i, k, n, count;
+
+    n = NC;
+    while (n > 0 && c_len[n - 1] == 0)
+        n--;
+    putbits(CBIT, n);
+    i = 0;
+    while (i < n) {
+        k = c_len[i++];
+        if (k == 0) {
+            count = 1;
+            while (i < n && c_len[i] == 0) {
+                i++;
+                count++;
+            }
+            if (count <= 2) {
+                for (k = 0; k < count; k++)
+                    putcode(pt_len[0], pt_code[0]);
+            }
+            else if (count <= 18) {
+                putcode(pt_len[1], pt_code[1]);
+                putbits(4, count - 3);
+            }
+            else if (count == 19) {
+                putcode(pt_len[0], pt_code[0]);
+                putcode(pt_len[1], pt_code[1]);
+                putbits(4, 15);
+            }
+            else {
+                putcode(pt_len[2], pt_code[2]);
+                putbits(CBIT, count - 20);
+            }
+        }
+        else
+            putcode(pt_len[k + 2], pt_code[k + 2]);
+    }
+}
+
+前に、頻度を数えたときと同様の条件で出力形式が変わっている。処理内容は
+簡単なので、以下の図を示すだけにする(理屈はよくわからない)。
+
+----------------------------------------------------------------------------
+< c_len[] の出力フォーマット >
+
+             0       CBIT{9}
+             +-------+-----------+-----------+--   --+-----------+
+             |   n   |  c_len[0] |  c_len[1] | ...     c_len[n-1]|
+             +-------+-----------+-----------+--   --+-----------+
+
+c_len[i] == 0 の場合
+
+ 0 が続く数を count とすると、
+
+ count == 0..2 の場合
+
+                pt_len[0]  
+              <----------> 
+             +------------+
+             | pt_code[0] |
+             +------------+
+
+ count == 3..18 の場合
+
+               pt_len[1]    4 bit
+              <----------> <------>
+             +------------+-------+
+             | pt_code[1] |count-3|
+             +------------+-------+
+
+ count == 19 の場合
+
+                pt_len[0]   pt_len[1]    4 bit
+              <----------> <----------> <------>
+             +------------+------------+-------+
+             | pt_code[0] | pt_code[1] |count-3|
+             +------------+------------+-------+
+
+  count >= 20 の場合
+
+                pt_len[2]    CBIT{9}
+              <----------> <------>
+             +------------+--------+
+             | pt_code[2] |count-20|
+             +------------+--------+
+
+c_len[i] != 0 の場合
+
+              pt_len[c_len[i]+2]
+             +-------------------+
+             |pt_code[c_len[i]+2]|
+             +-------------------+
+
+----------------------------------------------------------------------------
+
+こうして、文字の Huffman 符号表は、pt_len[] と pt_code[](pt_code[] は
+つまり c_len[] の Huffman 符号)を出力することで表現される。c_code[] が
+出力されてない思うかもしれないが、おそらく、decode 処理が c_len[] の値
+から計算して求めているのではないかと思われる。これは decode 処理の解読
+で明らかになるだろう。
+
+この後、send_block() は、<off> の Huffman 符号表を出力するのだが、これ
+は、先の pt_len[] の出力フォーマットと同じなので詳細ははしょろう。
+
+まとめると LHA における圧縮ファイルの構造は以下の連続であると言えるよ
+うだ。
+
+----------------------------------------------------------------------------
+LHA ファイルの構造(1 ブロック分)
+
+    +-----------+
+    | blocksize |
+    +-----------+
+       16bit
+
+    +-----+--------------------+
+    | len |      pt_len        | c_lenのハフマン符号表
+    +-----+--------------------+
+      5bit        ?? bit
+      TBIT
+
+    +-------+------------------+
+    |  len  |     c_len        | 文字と長さのハフマン符号表
+    +-------+------------------+
+      9bit        ?? bit
+      CBIT
+
+    +---------+--------------------+
+    |   len   |   pt_len           | 位置のハフマン符号表
+    +---------+--------------------+
+     pbit         ?? bit
+                               (pbit=14bit(lh4,5) or 16bit(lh6) or 17bit(lh7))
+
+    +---------------------+
+    |  圧縮文             |
+    +---------------------+
+
+----------------------------------------------------------------------------
 
+ここまでの解読では細部をかなりはしょったが、decode 処理を見ればわかる
+こともあるであろうことを期待している。以降、decode 処理の内容を処理の
+流れを追うことで確認しよう。
 
 # Local Variables:
 # mode : indented-text



Lha-users メーリングリストの案内
Back to archive index