OSDN Git Service

support PMA file decoding
authorKoji Arai <jca02266@gmail.com>
Wed, 20 Aug 2008 15:54:10 +0000 (00:54 +0900)
committerKoji Arai <jca02266@gmail.com>
Wed, 20 Aug 2008 15:55:37 +0000 (00:55 +0900)
12 files changed:
src/Makefile.am
src/extract.c
src/lha_macro.h
src/lharc.c
src/lhext.c
src/pm2.c [new file with mode: 0644]
src/pm2hist.c [new file with mode: 0644]
src/pm2hist.h [new file with mode: 0644]
src/pm2tree.c [new file with mode: 0644]
src/pm2tree.h [new file with mode: 0644]
src/prototypes.h
src/slide.c

index cabdf12..aec7ef8 100644 (file)
@@ -3,7 +3,8 @@ bin_PROGRAMS = lha
 lha_SOURCES = append.c bitio.c crcio.c dhuf.c extract.c header.c huf.c \
        indicator.c larc.c lha.h lha_macro.h prototypes.h lhadd.c lharc.c \
        lhext.c lhlist.c maketbl.c maketree.c patmatch.c shuf.c slide.c \
-       util.c getopt_long.c getopt_long.h
+       util.c getopt_long.c getopt_long.h \
+       pm2.c pm2hist.c pm2hist.h pm2tree.c pm2tree.h
 lha_LDADD = @LIBOBJS@
 EXTRA_DIST = lhdir.h fnmatch.h
 AM_CPPFLAGS=$(DEF_KCODE) $(SUPPORT_LZHUFF_METHOD)
index 328226c..32cbb4f 100644 (file)
@@ -62,13 +62,19 @@ decode_lzhuf(infp, outfp, original_size, packed_size, name, method, read_sizep)
     case LARC4_METHOD_NUM:      /* -lz4- */
         interface.dicbit = LARC4_DICBIT;
         break;
+    case PMARC0_METHOD_NUM:     /* -pm0- */
+        interface.dicbit = PMARC0_DICBIT;
+        break;
+    case PMARC2_METHOD_NUM:     /* -pm2- */
+        interface.dicbit = PMARC2_DICBIT;
+        break;
     default:
         warning("unknown method %d", method);
         interface.dicbit = LZHUFF5_DICBIT; /* for backward compatibility */
         break;
     }
 
-    if (interface.dicbit == 0) { /* LZHUFF0_DICBIT or LARC4_DICBIT */
+    if (interface.dicbit == 0) { /* LZHUFF0_DICBIT or LARC4_DICBIT or PMARC0_DICBIT*/
         start_indicator(name,
                         original_size,
                         verify_mode ? "Testing " : "Melting ",
index 9bee7ff..9710209 100644 (file)
@@ -73,6 +73,8 @@
 #define LARC5_METHOD            "-lz5-"
 #define LARC4_METHOD            "-lz4-"
 #define LZHDIRS_METHOD          "-lhd-"
+#define PMARC0_METHOD           "-pm0-"
+#define PMARC2_METHOD           "-pm2-"
 
 #define METHOD_TYPE_STORAGE     5
 
@@ -89,6 +91,8 @@
 #define LARC5_METHOD_NUM        9
 #define LARC4_METHOD_NUM        10
 #define LZHDIRS_METHOD_NUM      11
+#define PMARC0_METHOD_NUM       12
+#define PMARC2_METHOD_NUM       13
 /* Added N.Watazaki ..^ */
 
 #define LZHUFF0_DICBIT           0      /* no compress */
 #define LARC_DICBIT             11      /* 2^11 =  2KB sliding dictionary */
 #define LARC5_DICBIT            12      /* 2^12 =  4KB sliding dictionary */
 #define LARC4_DICBIT             0      /* no compress */
+#define PMARC0_DICBIT            0      /* no compress */
+#define PMARC2_DICBIT           13      /* 2^13 =  8KB sliding dictionary */
 
 #ifdef SUPPORT_LH7
 #define MAX_DICBIT          LZHUFF7_DICBIT      /* lh7 use 16bits */
index 23b0755..dc90c66 100644 (file)
@@ -157,6 +157,7 @@ LHx(arc) for OSK   V 2.01  Modified     1990  Momozou\n\
 LHa      for UNIX  V 1.00  Copyright(C) 1992  Masaru Oki\n\
 LHa      for UNIX  V 1.14  Modified     1995  Nobutaka Watazaki\n\
 LHa      for UNIX  V 1.14i Modified     2000  Tsugio Okamoto\n\
+LHA-PMA  for UNIX  V 2     PMA added    2000  Maarten ter Huurne\n\
                    Autoconfiscated 2001-2008  Koji Arai\n\
 ");
 
index c4a275c..2122cfc 100644 (file)
@@ -22,6 +22,7 @@ static char    *methods[] =
     LZHUFF4_METHOD, LZHUFF5_METHOD, LZHUFF6_METHOD, LZHUFF7_METHOD,
     LARC_METHOD, LARC5_METHOD, LARC4_METHOD,
     LZHDIRS_METHOD,
+    PMARC0_METHOD, PMARC2_METHOD,
     NULL
 };
 
@@ -262,7 +263,7 @@ extract_one(afp, hdr)
     /* 1999.4.30 t.okamoto */
     for (method = 0;; method++) {
         if (methods[method] == NULL) {
-            error("Unknown method \"%.*s\"; \"%s\" will be skiped ...",
+            error("Unknown method \"%.*s\"; \"%s\" will be skipped ...",
                   5, hdr->method, name);
             return read_size;
         }
diff --git a/src/pm2.c b/src/pm2.c
new file mode 100644 (file)
index 0000000..c41869b
--- /dev/null
+++ b/src/pm2.c
@@ -0,0 +1,118 @@
+/***********************************************************
+       pm2.c -- extract pmext2 coding
+***********************************************************/
+#include <stdio.h>
+#include "lha.h"
+#include "pm2hist.h"
+#include "pm2tree.h"
+
+static unsigned long nextcount;
+static unsigned short lastupdate;
+
+/* repeated from slide.c */
+static unsigned short dicsiz1;
+#define offset (0x100 - 2)
+
+void decode_start_pm2(void)
+{
+    dicsiz1 = (1 << dicbit) - 1;
+    init_getbits();
+    hist_init();
+    nextcount = 0;
+    lastupdate = 0;
+    getbits(1); /* discard bit */
+}
+
+
+static unsigned char gettree1;
+
+static int historyBits[8] = {   3,   3,   4,   5,   5,   5,   6,   6 };
+static int historyBase[8] = {   0,   8,  16,  32,  64,  96, 128, 192 };
+static int repeatBits[6]  = {   3,   3,   5,   6,   7,   0 };
+static int repeatBase[6]  = {  17,  25,  33,  65, 129, 256 };
+
+unsigned short decode_c_pm2(void)
+{
+    /* various admin: */
+    while (lastupdate != loc)
+    {
+        hist_update(dtext[lastupdate]);
+        lastupdate = (lastupdate + 1) & dicsiz1;
+    }
+    while (decode_count >= nextcount)
+    /* Actually it will never loop, because count doesn't grow that fast.
+       However, this is the way LHA does it.
+       Probably other encoding methods can have repeats larger than 256 bytes.
+       Note: LHA puts this code in decode_p...
+    */
+    {
+        if (nextcount == 0x0000)
+        {
+            maketree1();
+            maketree2(5);
+            nextcount = 0x0400;
+        }
+        else if (nextcount == 0x0400)
+        {
+            maketree2(6);
+            nextcount = 0x0800;
+        }
+        else if (nextcount == 0x0800)
+        {
+            maketree2(7);
+            nextcount = 0x1000;
+        }
+        else if (nextcount == 0x1000)
+        {
+            if (getbits(1) != 0) maketree1();
+            maketree2(8);
+            nextcount = 0x2000;
+        }
+        else
+        { /* 0x2000, 0x3000, 0x4000, ... */
+            if (getbits(1) != 0)
+            {
+                maketree1();
+                maketree2(8);
+            }
+            nextcount += 0x1000;
+        }
+    }
+    gettree1 = tree_get(&tree1); /* value preserved for decode_p */
+               
+    /* direct value (ret <= UCHAR_MAX) */
+    if (gettree1 < 8) return hist_lookup(
+        historyBase[gettree1] + getbits(historyBits[gettree1]) );
+    /* repeats: (ret > UCHAR_MAX) */
+    if (gettree1 < 23) return offset + 2 + (gettree1 - 8);
+    return offset + repeatBase[gettree1 - 23]
+        + getbits(repeatBits[gettree1 - 23]);
+}
+
+unsigned short decode_p_pm2(void)
+{
+    /* gettree1 value preserved from decode_c */
+    int nbits, delta, gettree2;
+    if (gettree1 == 8)
+    { /* 2-byte repeat with offset 0..63 */
+        nbits = 6; delta = 0;
+    }
+    else if (gettree1 < 28)
+    { /* n-byte repeat with offset 0..8191 */
+        gettree2 = tree_get(&tree2);
+        if (gettree2 == 0)
+        {
+                   nbits = 6; delta = 0;
+               }
+               else
+               { /* 1..7 */
+                   nbits = 5 + gettree2; delta = 1 << nbits;
+               }
+    }
+    else
+    { /* 256 bytes repeat with offset 0 */
+           nbits = 0; delta = 0;
+    }
+    return delta + getbits(nbits);
+                       
+}
diff --git a/src/pm2hist.c b/src/pm2hist.c
new file mode 100644 (file)
index 0000000..d6e143f
--- /dev/null
@@ -0,0 +1,65 @@
+/***********************************************************
+       pm2hist.c -- history for pmext2 decoding
+***********************************************************/
+
+/* Circular double-linked list. */
+
+static unsigned char prev[0x100];
+static unsigned char next[0x100];
+static unsigned char lastbyte;
+
+void hist_init()
+{
+    int i;
+    for (i = 0; i < 0x100; i++)
+    {
+        prev[(0xFF + i) & 0xFF] = i;
+       next[(0x01 + i) & 0xFF] = i;
+    }
+    prev[0x7F] = 0x00; next[0x00] = 0x7F;
+    prev[0xDF] = 0x80; next[0x80] = 0xDF;
+    prev[0x9F] = 0xE0; next[0xE0] = 0x9F;
+    prev[0x1F] = 0xA0; next[0xA0] = 0x1F;
+    prev[0xFF] = 0x20; next[0x20] = 0xFF;
+    lastbyte = 0x20;
+}
+
+unsigned char hist_lookup(int n)
+{
+    int i;
+    unsigned char *direction = prev;
+    if (n >= 0x80)
+    {
+        /* Speedup: If you have to process more than half the ring,
+                    it's faster to walk the other way around.
+        */
+        direction = next;
+        n = 0x100 - n;
+    }
+    for (i = lastbyte; n != 0; n--) i = direction[i];
+    return i;
+}              
+       
+void hist_update(unsigned char data)
+{
+    unsigned char oldNext, oldPrev, newNext;
+    if (data == lastbyte) return;
+       
+    /* detach from old position */
+    oldNext = next[data];
+    oldPrev = prev[data];
+    prev[oldNext] = oldPrev;
+    next[oldPrev] = oldNext;
+       
+    /* attach to new next */
+    newNext = next[lastbyte];
+    prev[newNext] = data;
+    next[data] = newNext;
+       
+    /* attach to new prev */
+    prev[data] = lastbyte;
+    next[lastbyte] = data;
+       
+    lastbyte = data;
+}
+
diff --git a/src/pm2hist.h b/src/pm2hist.h
new file mode 100644 (file)
index 0000000..879435f
--- /dev/null
@@ -0,0 +1,9 @@
+/***********************************************************
+       pm2hist.h -- history for pmext2 decoding
+***********************************************************/
+
+/* Circular double-linked list. */
+
+void hist_init();
+unsigned char hist_lookup(int n);
+void hist_update(unsigned char data);
diff --git a/src/pm2tree.c b/src/pm2tree.c
new file mode 100644 (file)
index 0000000..92b5b22
--- /dev/null
@@ -0,0 +1,160 @@
+/***********************************************************
+       pm2tree.c -- tree for pmext2 decoding
+***********************************************************/
+
+#ifdef __STDC__
+#include <stdlib.h>
+#endif
+#include "pm2tree.h"
+#include "lha.h"
+
+static unsigned char tree1left[32];
+static unsigned char tree1right[32];
+struct tree tree1 = { 0, tree1left, tree1right };
+static unsigned char table1[32];
+
+static unsigned char tree2left[8];
+static unsigned char tree2right[8];
+struct tree tree2 = { 0, tree2left, tree2right };
+static unsigned char table2[8];
+
+static unsigned char tree1bound;
+static unsigned char mindepth;
+
+void maketree1()
+{
+    int i, nbits, x;
+    tree1bound = getbits(5);
+    mindepth = getbits(3);
+    if (mindepth == 0)
+    {
+        tree_setsingle(&tree1, tree1bound - 1);
+    }
+    else
+    {
+        for (i = 0; i<32; i++) table1[i] = 0;
+               nbits = getbits(3);
+               for (i = 0; i < tree1bound; i++) {
+            x = getbits(nbits);
+            table1[i] = ( x == 0 ? 0 : x - 1 + mindepth );
+        }
+               tree_rebuild(&tree1, tree1bound, mindepth, table1);
+    }
+}
+
+void maketree2(int par_b) /* in use: 5 <= par_b <= 8 */
+{
+    int i, count, index;
+    if (tree1bound < 10) return;
+    if (tree1bound == 29 && mindepth == 0) return;
+       
+    for (i = 0; i < 8; i++) table2[i] = 0;
+    for (i = 0; i < par_b; i++) table2[i] = getbits(3);
+    index = 0;
+    count = 0;
+    for (i = 0; i < 8; i++)
+    {
+               if (table2[i] != 0)
+               {
+                   index = i;
+                   count++;
+        }
+    }
+       
+    if (count == 1)
+    {
+        tree_setsingle(&tree2, index);
+    }
+    else if (count > 1)
+    {
+               mindepth = 1;
+               tree_rebuild(&tree2, 8, mindepth, table2);
+    }
+    // Note: count == 0 is possible!
+    //       Excluding that possibility was a bug in version 1.
+
+}
+
+int tree_get(struct tree *t)
+{
+    int i;
+    i = t->root;
+    while (i < 0x80)
+    {
+        i = ( getbits(1) == 0 ? t->leftarr[i] : t->rightarr[i] );
+    }
+    return i & 0x7F;
+}
+
+void tree_setsingle(struct tree *t, unsigned char value)
+{
+    t->root = 128 | value;
+}
+
+void tree_rebuild(t, bound, mindepth, table)
+struct tree *t;
+unsigned char bound;
+unsigned char mindepth;
+unsigned char *table;
+{
+    unsigned char *parentarr, d;
+    int i, curr, empty, n;
+    parentarr = (unsigned char *)malloc(bound * sizeof(unsigned char));
+    t->root = 0;
+    for (i = 0; i < bound; i++)
+    {
+        t->leftarr[i]   = 0;
+        t->rightarr[i]  = 0;
+        parentarr[i] = 0;
+    }
+       
+    for (i = 0; i < mindepth - 1; i++)
+    {
+               t->leftarr[i] = i + 1;
+               parentarr[i+1] = i;
+    }
+
+    curr = mindepth - 1;
+    empty = mindepth;
+    for (d = mindepth; TRUE; d++)
+    {
+        for (i = 0; i < bound; i++)
+        {
+            if (table[i] == d)
+            {
+                       if (t->leftarr[curr] == 0) t->leftarr[curr] = i | 128;
+                else
+                {
+                    t->rightarr[curr] = i | 128;
+                    n = 0;
+                    while (t->rightarr[curr] != 0)
+                    {
+                       if (curr == 0) /* root? -> done */
+                       {
+                           free(parentarr);
+                           return;
+                       }
+                       curr = parentarr[curr];
+                               n++;
+                    }
+                    t->rightarr[curr] = empty;
+                    for (;;)
+                    {
+                               parentarr[empty] = curr;
+                               curr = empty;
+                               empty++;
+                               
+                               n--; if (n == 0) break;
+                               t->leftarr[curr] = empty;
+                    }
+                }
+            }
+        }
+               if (t->leftarr[curr] == 0) t->leftarr[curr] = empty; else t->rightarr[curr] = empty;
+               
+        parentarr[empty] = curr;
+        curr = empty;
+        empty++;
+    }
+}
+
diff --git a/src/pm2tree.h b/src/pm2tree.h
new file mode 100644 (file)
index 0000000..3618ec4
--- /dev/null
@@ -0,0 +1,14 @@
+/***********************************************************
+       pm2tree.h -- tree for pmext2 decoding
+***********************************************************/
+
+struct tree { unsigned char root, *leftarr, *rightarr; };
+
+extern struct tree tree1, tree2;
+
+void maketree1();
+void maketree2(int par_b);
+int tree_get(struct tree *t);
+void tree_setsingle(struct tree *t, unsigned char value);
+void tree_rebuild(struct tree *t, unsigned char bound,
+    unsigned char mindepth, unsigned char *table);
index 8297f7b..82bb83d 100644 (file)
@@ -64,6 +64,10 @@ void decode_start_lzs P_((void));
 unsigned short decode_c_lz5 P_((void));
 unsigned short decode_p_lz5 P_((void));
 void decode_start_lz5 P_((void));
+/* pm2.c */
+unsigned short decode_c_pm2 P_((void));
+unsigned short decode_p_pm2 P_((void));
+void decode_start_pm2 P_((void));
 /* lhadd.c */
 FILE *append_it P_((char *name, FILE *oafp, FILE *nafp));
 FILE *build_temporary_file P_((void));
index 6cf0379..4b94130 100644 (file)
@@ -74,7 +74,15 @@ static struct decode_option decode_define[] = {
     /* lzs */
     {decode_c_lzs, decode_p_lzs, decode_start_lzs},
     /* lz5 */
-    {decode_c_lz5, decode_p_lz5, decode_start_lz5}
+    {decode_c_lz5, decode_p_lz5, decode_start_lz5},
+    /* lz4 */
+    {NULL        , NULL        , NULL            },
+    /* lhd */
+    {NULL        , NULL        , NULL            },
+    /* pm0 */
+    {NULL        , NULL        , NULL            },
+    /* pm2 */
+    {decode_c_pm2, decode_p_pm2, decode_start_pm2}
 };
 
 static struct encode_option encode_set;
@@ -421,7 +429,7 @@ decode(interface)
     decode_set.decode_start();
     dicsiz1 = dicsiz - 1;
     adjust = 256 - THRESHOLD;
-    if (interface->method == LARC_METHOD_NUM)
+    if ((interface->method == LARC_METHOD_NUM) || (interface->method == PMARC2_METHOD_NUM))
         adjust = 256 - 2;
 
     decode_count = 0;