OSDN Git Service

* src/header.c (wintime_to_unix_stamp): no use 64bit constant to
[lha/lha.git] / src / slide.c
index ad7770f..0e8fab4 100644 (file)
@@ -1,10 +1,10 @@
 /* ------------------------------------------------------------------------ */
-/* LHa for UNIX                                                                                                                        */
-/*                             slice.c -- sliding dictionary with percolating update           */
-/*                                                                                                                                                     */
-/*             Modified                        Nobutaka Watazaki                                                       */
-/*                                                                                                                                                     */
-/*     Ver. 1.14d      Exchanging a search algorithm  1997.01.11    T.Okamoto      */
+/* LHa for UNIX                                                             */
+/*              slide.c -- sliding dictionary with percolating update       */
+/*                                                                          */
+/*      Modified                Nobutaka Watazaki                           */
+/*                                                                          */
+/*  Ver. 1.14d  Exchanging a search algorithm  1997.01.11    T.Okamoto      */
 /* ------------------------------------------------------------------------ */
 
 #if 0
 
 #include "lha.h"
 
-
 #ifdef DEBUG
 FILE *fout = NULL;
 static int noslide = 1;
 #endif
 
-/* ------------------------------------------------------------------------ */
-
-static unsigned long encoded_origsize;
-
-/* ------------------------------------------------------------------------ */
-
-static unsigned int *hash;
-static unsigned int *prev;
-
-/* static unsigned char  *text; */
-unsigned char *too_flag;
-
+/* variables for hash */
+struct hash {
+    unsigned int pos;
+    int too_flag;               /* if 1, matching candidate is too many */
+} *hash;
+static unsigned int *prev;      /* previous posiion associated with hash */
+
+/* hash function: it represents 3 letters from `pos' on `text' */
+#define INIT_HASH(pos) \
+        ((( (text[(pos)] << 5) \
+           ^ text[(pos) + 1]  ) << 5) \
+           ^ text[(pos) + 2]         ) & (unsigned)(HSHSIZ - 1);
+#define NEXT_HASH(hash,pos) \
+        (((hash) << 5) \
+           ^ text[(pos) + 2]         ) & (unsigned)(HSHSIZ - 1);
 
 static struct encode_option encode_define[2] = {
 #if defined(__STDC__) || defined(AIX)
-       /* lh1 */
-       {(void (*) ()) output_dyn,
-               (void (*) ()) encode_start_fix,
-       (void (*) ()) encode_end_dyn},
-       /* lh4, 5,6 */
-       {(void (*) ()) output_st1,
-               (void (*) ()) encode_start_st1,
-       (void (*) ()) encode_end_st1}
+    /* lh1 */
+    {(void (*) ()) output_dyn,
+     (void (*) ()) encode_start_fix,
+     (void (*) ()) encode_end_dyn},
+    /* lh4, 5, 6, 7 */
+    {(void (*) ()) output_st1,
+     (void (*) ()) encode_start_st1,
+     (void (*) ()) encode_end_st1}
 #else
-       /* lh1 */
-       {(int (*) ()) output_dyn,
-               (int (*) ()) encode_start_fix,
-       (int (*) ()) encode_end_dyn},
-       /* lh4, 5,6 */
-       {(int (*) ()) output_st1,
-               (int (*) ()) encode_start_st1,
-       (int (*) ()) encode_end_st1}
+    /* lh1 */
+    {(int (*) ()) output_dyn,
+     (int (*) ()) encode_start_fix,
+     (int (*) ()) encode_end_dyn},
+    /* lh4, 5, 6, 7 */
+    {(int (*) ()) output_st1,
+     (int (*) ()) encode_start_st1,
+     (int (*) ()) encode_end_st1}
 #endif
 };
 
 static struct decode_option decode_define[] = {
-       /* lh1 */
-       {decode_c_dyn, decode_p_st0, decode_start_fix},
-       /* lh2 */
-       {decode_c_dyn, decode_p_dyn, decode_start_dyn},
-       /* lh3 */
-       {decode_c_st0, decode_p_st0, decode_start_st0},
-       /* lh4 */
-       {decode_c_st1, decode_p_st1, decode_start_st1},
-       /* lh5 */
-       {decode_c_st1, decode_p_st1, decode_start_st1},
-       /* lh6 */
-       {decode_c_st1, decode_p_st1, decode_start_st1},
-       /* lh7 */
-       {decode_c_st1, decode_p_st1, decode_start_st1},
-       /* lzs */
-       {decode_c_lzs, decode_p_lzs, decode_start_lzs},
-       /* lz5 */
-       {decode_c_lz5, decode_p_lz5, decode_start_lz5}
+    /* lh1 */
+    {decode_c_dyn, decode_p_st0, decode_start_fix},
+    /* lh2 */
+    {decode_c_dyn, decode_p_dyn, decode_start_dyn},
+    /* lh3 */
+    {decode_c_st0, decode_p_st0, decode_start_st0},
+    /* lh4 */
+    {decode_c_st1, decode_p_st1, decode_start_st1},
+    /* lh5 */
+    {decode_c_st1, decode_p_st1, decode_start_st1},
+    /* lh6 */
+    {decode_c_st1, decode_p_st1, decode_start_st1},
+    /* lh7 */
+    {decode_c_st1, decode_p_st1, decode_start_st1},
+    /* lzs */
+    {decode_c_lzs, decode_p_lzs, decode_start_lzs},
+    /* lz5 */
+    {decode_c_lz5, decode_p_lz5, decode_start_lz5}
 };
 
 static struct encode_option encode_set;
 static struct decode_option decode_set;
 
-#if 0
-static node     pos, matchpos, avail, *position, *parent, *prev;
-static int      remainder, matchlen;
-static unsigned char *level, *childcount;
-static unsigned long dicsiz;  /* t.okamoto */
-static unsigned short max_hash_val;
-static unsigned short hash1, hash2;
-#endif
-
-#ifdef SUPPORT_LH7
-#define DICSIZ (1L << 16)
-#define TXTSIZ (DICSIZ * 2L + MAXMATCH)
-#else
-#define DICSIZ (((unsigned long)1) << 15)
-#define TXTSIZ (DICSIZ * 2 + MAXMATCH)
-#endif
-
+#define TXTSIZ (MAX_DICSIZ * 2L + MAXMATCH)
 #define HSHSIZ (((unsigned long)1) <<15)
 #define NIL 0
-#define LIMIT 0x100    /* chain Ä¹¤Î limit */
+#define LIMIT 0x100             /* limit of hash chain */
 
 static unsigned int txtsiz;
-
 static unsigned long dicsiz;
-
-static unsigned int hval;
-static int matchlen;
-static unsigned int matchpos;
-static unsigned int pos;
 static unsigned int remainder;
 
+struct matchdata {
+    int len;
+    unsigned int off;
+};
 
-/* ------------------------------------------------------------------------ */
 int
 encode_alloc(method)
-       int             method;
+    int method;
 {
-       if (method == LZHUFF1_METHOD_NUM) {     /* Changed N.Watazaki */
-               encode_set = encode_define[0];
-               maxmatch = 60;
-               dicbit = 12;   /* 12 Changed N.Watazaki */
-       } else { /* method LH4(12),LH5(13),LH6(15) */
-               encode_set = encode_define[1];
-               maxmatch = MAXMATCH;
-               if (method == LZHUFF7_METHOD_NUM)
-                       dicbit = LZHUFF7_DICBIT;        /* 16 bits */
-               else if (method == LZHUFF6_METHOD_NUM)
-                       dicbit = LZHUFF6_DICBIT;        /* 15 bits */
-               else /* LH5  LH4 is not used */
-                       dicbit = LZHUFF5_DICBIT;        /* 13 bits */
-       }
-
-       dicsiz = (((unsigned long)1) << dicbit);
-       txtsiz = dicsiz*2+maxmatch;
-
-       if (hash) return method;
-
-       alloc_buf();
-
-       hash = (unsigned int*)xmalloc(HSHSIZ * sizeof(unsigned int));
-       prev = (unsigned int*)xmalloc(DICSIZ * sizeof(unsigned int));
-       text = (unsigned char*)xmalloc(TXTSIZ);
-       too_flag = (unsigned char*)xmalloc(HSHSIZ);
-
-       return method;
+    switch (method) {
+    case LZHUFF1_METHOD_NUM:
+        encode_set = encode_define[0];
+        maxmatch = 60;
+        dicbit = LZHUFF1_DICBIT;    /* 12 bits  Changed N.Watazaki */
+        break;
+    case LZHUFF5_METHOD_NUM:
+        encode_set = encode_define[1];
+        maxmatch = MAXMATCH;
+        dicbit = LZHUFF5_DICBIT;    /* 13 bits */
+        break;
+    case LZHUFF6_METHOD_NUM:
+        encode_set = encode_define[1];
+        maxmatch = MAXMATCH;
+        dicbit = LZHUFF6_DICBIT;    /* 15 bits */
+        break;
+    case LZHUFF7_METHOD_NUM:
+        encode_set = encode_define[1];
+        maxmatch = MAXMATCH;
+        dicbit = LZHUFF7_DICBIT;    /* 16 bits */
+        break;
+    default:
+        error("unknown method %d", method);
+        exit(1);
+    }
+
+    dicsiz = (((unsigned long)1) << dicbit);
+    txtsiz = dicsiz*2+maxmatch;
+
+    if (hash) return method;
+
+    alloc_buf();
+
+    hash = (struct hash*)xmalloc(HSHSIZ * sizeof(struct hash));
+    prev = (unsigned int*)xmalloc(MAX_DICSIZ * sizeof(unsigned int));
+    text = (unsigned char*)xmalloc(TXTSIZ);
+
+    return method;
 }
 
-/* ------------------------------------------------------------------------ */
-/* ¥Ý¥¤¥ó¥¿¤Î½é´ü²½ */
-
-static void init_slide()
+static void
+init_slide()
 {
-       unsigned int i;
-
-       for (i = 0; i < HSHSIZ; i++) {
-               hash[i] = NIL;
-               too_flag[i] = 0;
-       }
-       /*
-       for (i = 0; i < DICSIZ; i++) {
-           prev[i] = NIL;
-       }
-       */
-}
+    unsigned int i;
 
-/* ¼­½ñ¤ò DICSIZ Ê¬ Á°¤Ë¤º¤é¤¹ */
+    for (i = 0; i < HSHSIZ; i++) {
+        hash[i].pos = NIL;
+        hash[i].too_flag = 0;
+    }
+}
 
-static unsigned int
-update(crc)
-    unsigned int crc;
+/* update dictionary */
+static void
+update_dict(pos, crc)
+    unsigned int *pos;
+    unsigned int *crc;
 {
-       unsigned int i, j;
-       long n;
+    unsigned int i, j;
+    long n;
 
-#if 0
-       memmove(&text[0], &text[dicsiz], (unsigned)(txtsiz - dicsiz));
-#else
-       {
-               int m;
-               i = 0; j = dicsiz; m = txtsiz-dicsiz;
-               while (m-- > 0) {
-                       text[i++] = text[j++];
-               }
-       }
-#endif
-       n = fread_crc(&crc, &text[(unsigned)(txtsiz - dicsiz)], 
-                                  (unsigned)dicsiz, infile);
-
-       remainder += n;
-       encoded_origsize += n;
-
-       pos -= dicsiz;
-       for (i = 0; i < HSHSIZ; i++) {
-               j = hash[i];
-               hash[i] = (j > dicsiz) ? j - dicsiz : NIL;
-               too_flag[i] = 0;
-       }
-       for (i = 0; i < dicsiz; i++) {
-               j = prev[i];
-               prev[i] = (j > dicsiz) ? j - dicsiz : NIL;
-       }
+    memmove(&text[0], &text[dicsiz], txtsiz - dicsiz);
 
-    return crc;
-}
+    n = fread_crc(crc, &text[txtsiz - dicsiz], dicsiz, infile);
 
+    remainder += n;
 
-/* ¸½ºß¤Îʸ»úÎó¤ò¥Á¥§¡¼¥ó¤ËÄɲ乤ë */
+    *pos -= dicsiz;
+    for (i = 0; i < HSHSIZ; i++) {
+        j = hash[i].pos;
+        hash[i].pos = (j > dicsiz) ? j - dicsiz : NIL;
+        hash[i].too_flag = 0;
+    }
+    for (i = 0; i < dicsiz; i++) {
+        j = prev[i];
+        prev[i] = (j > dicsiz) ? j - dicsiz : NIL;
+    }
+}
 
-static void insert()
+/* associate position with token */
+static void
+insert_hash(token, pos)
+    unsigned int token;
+    unsigned int pos;
 {
-       prev[pos & (dicsiz - 1)] = hash[hval];
-       hash[hval] = pos;
+    prev[pos & (dicsiz - 1)] = hash[token].pos; /* chain the previous pos. */
+    hash[token].pos = pos;
 }
 
-
-/* ¸½ºß¤Îʸ»úÎó¤ÈºÇĹ°ìÃפ¹¤ëʸ»úÎó¤ò¸¡º÷¤·¡¢¥Á¥§¡¼¥ó¤ËÄɲ乤ë */
-
-static void match_insert()
+static void
+search_dict_1(token, pos, off, max, m)
+    unsigned int token;
+    unsigned int pos;
+    unsigned int off;
+    unsigned int max;           /* max. length of matching string */
+    struct matchdata *m;
 {
-       unsigned int scan_pos, scan_end, len;
-       unsigned char *a, *b;
-       unsigned int chain, off, h, max;
-
-       max = maxmatch; /* MAXMATCH; */
-       if (matchlen < THRESHOLD - 1) matchlen = THRESHOLD - 1;
-       matchpos = pos;
-
-       off = 0;
-       for (h = hval; too_flag[h] && off < maxmatch - THRESHOLD; ) {
-               h = ((h << 5) ^ text[pos + (++off) + 2]) & (unsigned)(HSHSIZ - 1);
-       }
-       if (off == maxmatch - THRESHOLD) off = 0;
-       for (;;) {
-               chain = 0;
-               scan_pos = hash[h];
-               scan_end = (pos > dicsiz) ? pos + off - dicsiz : off;
-               while (scan_pos > scan_end) {
-                       chain++;
-
-                       if (text[scan_pos + matchlen - off] == text[pos + matchlen]) {
-                               {
-                                       a = text + scan_pos - off;  b = text + pos;
-                                       for (len = 0; len < max && *a++ == *b++; len++);
-                               }
-
-                               if (len > matchlen) {
-                                       matchpos = scan_pos - off;
-                                       if ((matchlen = len) == max) {
-                                               break;
-                                       }
+    unsigned int chain = 0;
+    unsigned int scan_pos = hash[token].pos;
+    int scan_beg = scan_pos - off;
+    int scan_end = pos - dicsiz;
+    unsigned int len;
+
+    while (scan_beg > scan_end) {
+        chain++;
+
+        if (text[scan_beg + m->len] == text[pos + m->len]) {
+            {
+                /* collate token */
+                unsigned char *a = &text[scan_beg];
+                unsigned char *b = &text[pos];
+
+                for (len = 0; len < max && *a++ == *b++; len++);
+            }
+
+            if (len > m->len) {
+                m->off = pos - scan_beg;
+                m->len = len;
+                if (m->len == max)
+                    break;
+
 #ifdef DEBUG
-                                       if (noslide) {
-                                         if (matchpos < dicsiz) {
-                                               printf("matchpos=%u scan_pos=%u dicsiz=%u\n"
-                                                          ,matchpos, scan_pos, dicsiz);
-                                         }
-                                       }
+                if (noslide) {
+                    if (pos - m->off < dicsiz) {
+                        printf("matchpos=%u scan_pos=%u dicsiz=%u\n",
+                               pos - m->off, scan_pos, dicsiz);
+                    }
+                }
 #endif
-                               }
-                       }
-                       scan_pos = prev[scan_pos & (dicsiz - 1)];
-               }
-
-               if (chain >= LIMIT)
-                       too_flag[h] = 1;
-
-               if (matchlen > off + 2 || off == 0)
-                       break;
-               max = off + 2;
-               off = 0;
-               h = hval;
-       }
-       prev[pos & (dicsiz - 1)] = hash[hval];
-       hash[hval] = pos;
+            }
+        }
+        scan_pos = prev[scan_pos & (dicsiz - 1)];
+        scan_beg = scan_pos - off;
+    }
+
+    if (chain >= LIMIT)
+        hash[token].too_flag = 1;
 }
 
+/* search the longest token matching to current token */
+static void
+search_dict(token, pos, min, m)
+    unsigned int token;         /* search token */
+    unsigned int pos;           /* position of token */
+    int min;                    /* min. length of matching string */
+    struct matchdata *m;
+{
+    unsigned int off, tok, max;
 
-/* ¥Ý¥¤¥ó¥¿¤ò¿Ê¤á¡¢¼­½ñ¤ò¹¹¿·¤·¡¢¥Ï¥Ã¥·¥åÃͤò¹¹¿·¤¹¤ë */
+    if (min < THRESHOLD - 1) min = THRESHOLD - 1;
 
-static unsigned int
-get_next(crc)
-    unsigned int crc;
+    max = maxmatch;
+    m->off = 0;
+    m->len = min;
+
+    off = 0;
+    for (tok = token; hash[tok].too_flag && off < maxmatch - THRESHOLD; ) {
+        /* If matching position is too many, The search key is
+           changed into following token from `off' (for speed). */
+        ++off;
+        tok = NEXT_HASH(tok, pos+off);
+    }
+    if (off == maxmatch - THRESHOLD) {
+        off = 0;
+        tok = token;
+    }
+
+    search_dict_1(tok, pos, off, max, m);
+
+    if (off > 0 && m->len < off + 3)
+        /* re-search */
+        search_dict_1(token, pos, 0, off+2, m);
+
+    if (m->len > remainder) m->len = remainder;
+}
+
+/* slide dictionary */
+static void
+next_token(token, pos, crc)
+    unsigned int *token;
+    unsigned int *pos;
+    unsigned int *crc;
 {
-       remainder--;
-       if (++pos >= txtsiz - maxmatch) {
-               crc = update(crc);
+    remainder--;
+    if (++*pos >= txtsiz - maxmatch) {
+        update_dict(pos, crc);
 #ifdef DEBUG
-               noslide = 0;
+        noslide = 0;
 #endif
-       }
-       hval = ((hval << 5) ^ text[pos + 2]) & (unsigned)(HSHSIZ - 1);
-
-    return crc;
+    }
+    *token = NEXT_HASH(*token, *pos);
 }
 
 unsigned int
 encode(interface)
     struct interfacing *interface;
 {
-       int lastmatchlen;
-       unsigned int lastmatchoffset;
-    unsigned int crc;
+    unsigned int token, pos, crc;
+    size_t count;
+    struct matchdata match, last;
 
 #ifdef DEBUG
-       unsigned int addr;
-
-       addr = 0;
-
-       fout = fopen("en", "wt");
-       if (fout == NULL) exit(1);
+    if (!fout)
+        fout = xfopen("en", "wt");
+    fprintf(fout, "[filename: %s]\n", reading_filename);
 #endif
-       infile = interface->infile;
-       outfile = interface->outfile;
-       origsize = interface->original;
-       compsize = count = 0L;
-       unpackable = 0;
+    infile = interface->infile;
+    outfile = interface->outfile;
+    origsize = interface->original;
+    compsize = count = 0L;
+    unpackable = 0;
 
     INITIALIZE_CRC(crc);
 
-       /* encode_alloc(); */ /* allocate_memory(); */
-       init_slide();  
+    init_slide();
 
-       encode_set.encode_start();
-       memset(&text[0], ' ', (long)TXTSIZ);
+    encode_set.encode_start();
+    memset(text, 0, TXTSIZ);
 
-       remainder = fread_crc(&crc, &text[dicsiz], txtsiz-dicsiz, infile);
-       encoded_origsize = remainder;
-       matchlen = THRESHOLD - 1;
+    remainder = fread_crc(&crc, &text[dicsiz], txtsiz-dicsiz, infile);
 
-       pos = dicsiz;
+    match.len = THRESHOLD - 1;
+    match.off = 0;
+    if (match.len > remainder) match.len = remainder;
 
-       if (matchlen > remainder) matchlen = remainder;
-       hval = ((((text[dicsiz] << 5) ^ text[dicsiz + 1]) << 5) 
-               ^ text[dicsiz + 2]) & (unsigned)(HSHSIZ - 1);
+    pos = dicsiz;
+    token = INIT_HASH(pos);
+    insert_hash(token, pos);     /* associate token and pos */
 
-       insert();
-       while (remainder > 0 && ! unpackable) {
-               lastmatchlen = matchlen;  lastmatchoffset = pos - matchpos - 1;
-               --matchlen;
-               crc = get_next(crc);  match_insert();
-               if (matchlen > remainder) matchlen = remainder;
-               if (matchlen > lastmatchlen || lastmatchlen < THRESHOLD) {
-                       encode_set.output(text[pos - 1], 0);
+    while (remainder > 0 && ! unpackable) {
+        last = match;
+
+        next_token(&token, &pos, &crc);
+        search_dict(token, pos, last.len-1, &match);
+        insert_hash(token, pos);
+
+        if (match.len > last.len || last.len < THRESHOLD) {
+            /* output a letter */
+            encode_set.output(text[pos - 1], 0);
 #ifdef DEBUG
-                       fprintf(fout, "%u C %02X\n", addr, text[pos-1]);
-                       addr++;
+            fprintf(fout, "%u C %02X\n", count, text[pos-1]);
 #endif
-                       count++;
-               } else {
-                       encode_set.output(lastmatchlen + (UCHAR_MAX + 1 - THRESHOLD),
-                          (lastmatchoffset) & (dicsiz-1) );
-                       --lastmatchlen;
+            count++;
+        } else {
+            /* output length and offset */
+            encode_set.output(last.len + (256 - THRESHOLD),
+                              (last.off-1) & (dicsiz-1) );
 
 #ifdef DEBUG
-                       fprintf(fout, "%u M %u %u ", addr,
-                                       lastmatchoffset & (dicsiz-1), lastmatchlen+1);
-                       addr += lastmatchlen +1 ;
-
-                       {
-                int t,cc;
-                for (t=0; t<lastmatchlen+1; t++) {
-                    cc = text[pos - lastmatchoffset - 2 + t];
-                    fprintf(fout, "%02X ", cc);
-                }
+            {
+                int i;
+                unsigned char *ptr;
+                unsigned int offset = (last.off & (dicsiz-1));
+
+                fprintf(fout, "%u M <%u %u> ",
+                        count, last.len, count - offset);
+
+                ptr = &text[pos-1 - offset];
+                for (i=0; i < last.len; i++)
+                    fprintf(fout, "%02X ", ptr[i]);
                 fprintf(fout, "\n");
-                       }
+            }
 #endif
-                       while (--lastmatchlen > 0) {
-                               crc = get_next(crc);  insert();
-                               count++;
-                       }
-                       crc = get_next(crc);
-                       matchlen = THRESHOLD - 1;
-                       match_insert();
-                       if (matchlen > remainder) matchlen = remainder;
-               }
-       }
-       encode_set.encode_end();
-
-       interface->packed = compsize;
-       interface->original = encoded_origsize;
+            count += last.len;
+
+            --last.len;
+            while (--last.len > 0) {
+                next_token(&token, &pos, &crc);
+                insert_hash(token, pos);
+            }
+            next_token(&token, &pos, &crc);
+            search_dict(token, pos, THRESHOLD - 1, &match);
+            insert_hash(token, pos);
+        }
+    }
+    encode_set.encode_end();
+
+    interface->packed = compsize;
+    interface->original = count;
 
     return crc;
 }
 
-/* ------------------------------------------------------------------------ */
 unsigned int
 decode(interface)
-       struct interfacing *interface;
+    struct interfacing *interface;
 {
-       unsigned int i, j, k, c;
-       unsigned int dicsiz1, offset;
-       unsigned char *dtext;
-       unsigned int crc;
+    unsigned int i, c;
+    unsigned int dicsiz1, adjust;
+    unsigned char *dtext;
+    unsigned int crc;
 
 #ifdef DEBUG
-       fout = fopen("de", "wt");
-       if (fout == NULL) exit(1);
+    if (!fout)
+        fout = xfopen("de", "wt");
+    fprintf(fout, "[filename: %s]\n", writing_filename);
 #endif
 
-       infile = interface->infile;
-       outfile = interface->outfile;
-       dicbit = interface->dicbit;
-       origsize = interface->original;
-       compsize = interface->packed;
-       decode_set = decode_define[interface->method - 1];
-
-       INITIALIZE_CRC(crc);
-       prev_char = -1;
-       dicsiz = 1L << dicbit;
-       dtext = (unsigned char *)xmalloc(dicsiz);
-       for (i=0; i<dicsiz; i++) dtext[i] = 0x20;
-       decode_set.decode_start();
-       dicsiz1 = dicsiz - 1;
-       offset = (interface->method == LARC_METHOD_NUM) ? 0x100 - 2 : 0x100 - 3;
-       count = 0;
-       loc = 0;
-       while (count < origsize) {
-               c = decode_set.decode_c();
-               if (c <= UCHAR_MAX) {
+    infile = interface->infile;
+    outfile = interface->outfile;
+    dicbit = interface->dicbit;
+    origsize = interface->original;
+    compsize = interface->packed;
+    decode_set = decode_define[interface->method - 1];
+
+    INITIALIZE_CRC(crc);
+    dicsiz = 1L << dicbit;
+    dtext = (unsigned char *)xmalloc(dicsiz);
+    memset(dtext, 0, dicsiz);
+    decode_set.decode_start();
+    dicsiz1 = dicsiz - 1;
+    adjust = 256 - THRESHOLD;
+    if (interface->method == LARC_METHOD_NUM)
+        adjust = 256 - 2;
+
+    decode_count = 0;
+    loc = 0;
+    while (decode_count < origsize) {
+        c = decode_set.decode_c();
+        if (c < 256) {
 #ifdef DEBUG
-                 fprintf(fout, "%u C %02X\n", count, c);
+          fprintf(fout, "%u C %02X\n", decode_count, c);
 #endif
-                       dtext[loc++] = c;
-                       if (loc == dicsiz) {
-                               fwrite_crc(&crc, dtext, dicsiz, outfile);
-                               loc = 0;
-                       }
-                       count++;
-               }
-               else {
-                       j = c - offset;
-                       i = (loc - decode_set.decode_p() - 1) & dicsiz1;
+            dtext[loc++] = c;
+            if (loc == dicsiz) {
+                fwrite_crc(&crc, dtext, dicsiz, outfile);
+                loc = 0;
+            }
+            decode_count++;
+        }
+        else {
+            struct matchdata match;
+            unsigned int matchpos;
+
+            match.len = c - adjust;
+            match.off = decode_set.decode_p() + 1;
+            matchpos = (loc - match.off) & dicsiz1;
 #ifdef DEBUG
-                       fprintf(fout, "%u M %u %u ", count, (loc-1-i) & dicsiz1, j);
+            fprintf(fout, "%u M <%u %u> ",
+                    decode_count, match.len, decode_count-match.off);
 #endif
-                       count += j;
-                       for (k = 0; k < j; k++) {
-                               c = dtext[(i + k) & dicsiz1];
-
+            decode_count += match.len;
+            for (i = 0; i < match.len; i++) {
+                c = dtext[(matchpos + i) & dicsiz1];
 #ifdef DEBUG
-                               fprintf(fout, "%02X ", c & 0xff);
+                fprintf(fout, "%02X ", c & 0xff);
 #endif
-                               dtext[loc++] = c;
-                               if (loc == dicsiz) {
-                                       fwrite_crc(&crc, dtext, dicsiz, outfile);
-                                       loc = 0;
-                               }
-                       }
+                dtext[loc++] = c;
+                if (loc == dicsiz) {
+                    fwrite_crc(&crc, dtext, dicsiz, outfile);
+                    loc = 0;
+                }
+            }
 #ifdef DEBUG
-                       fprintf(fout, "\n");
+            fprintf(fout, "\n");
 #endif
-               }
-       }
-       if (loc != 0) {
-               fwrite_crc(&crc, dtext, loc, outfile);
-       }
+        }
+    }
+    if (loc != 0) {
+        fwrite_crc(&crc, dtext, loc, outfile);
+    }
+
+    free(dtext);
+
+    /* usually read size is interface->packed */
+    interface->read_size = interface->packed - compsize;
 
-       free(dtext);
     return crc;
 }
-
-/* Local Variables: */
-/* mode:c */
-/* tab-width:4 */
-/* End: */
-/* vi: set tabstop=4: */