OSDN Git Service

support level 2 header (limited)
authorKoji Arai <jca02266@gmail.com>
Mon, 24 Mar 2008 16:21:05 +0000 (01:21 +0900)
committerKoji Arai <jca02266@gmail.com>
Mon, 24 Mar 2008 16:21:05 +0000 (01:21 +0900)
ar.c
ar.h
encode.txt
io.c
randtest/.gitignore [new file with mode: 0644]

diff --git a/ar.c b/ar.c
index 745472d..155ecef 100644 (file)
--- a/ar.c
+++ b/ar.c
@@ -2,6 +2,8 @@
        ar.c -- main file
 ***********************************************************/
 
+static char *version = "0.01";
+
 static char *usage =
     "ar -- compression archiver -- written by Haruhiko Okumura\n"
     "  PC-VAN:SCIENCE        CompuServe:74050,1022\n"
@@ -57,6 +59,7 @@ struct lzh_header {
     int ftime;
     int file_crc;
     char os_id;
+    int level;
 };
 
 struct lha_method methods[] = {
@@ -96,6 +99,7 @@ init_opts()
     opts.nocompress = 0;
     opts.outdir = NULL;
     opts.quiet = 0;
+    opts.header_level = 2;
 
     /* default is the -lh5- method */
     opts.method   = &methods[5];
@@ -106,13 +110,19 @@ init_opts()
 int unpackable;                 /* global, set in io.c */
 ulong compsize, origsize;       /* global */
 
-static uchar headersize;
 static char *temp_name;
 
 static void
 print_usage()
 {
-    puts("usage: ...");
+    printf("%s", usage);
+    exit(0);
+}
+
+static void
+print_version()
+{
+    printf("version %s\n", version);
     exit(0);
 }
 
@@ -223,18 +233,19 @@ put_char(char *buf, char *p, size_t size)
 }
 
 static int
-read_header(FILE *fp, struct lzh_header *h)
+read_header_lv1(FILE *fp, char *buf, struct lzh_header *h)
 {
     int headersize;
     int headersum;
-    char buf[4096];
     int ext_headersize;
 
-    headersize = (uchar) fgetc(fp);
-    if (headersize == 0)
-        return 0;               /* end of archive */
-    headersum = (uchar) fgetc(fp);
-    fread_crc(buf, headersize, fp);     /* CRC not used */
+    headersize = get_byte(&buf[0]);
+    headersum = get_byte(&buf[1]);
+
+    fread_crc(buf + 21, headersize - (21 - 2), fp);     /* CRC not used */
+
+    buf += 2;
+
     if (calc_headersum(buf, headersize) != headersum)
         error("Header sum error");
 
@@ -243,7 +254,7 @@ read_header(FILE *fp, struct lzh_header *h)
     h->origsize = get_dword(&buf[9]);
     h->ftime    = get_dword(&buf[13]);
     /* attrib   = get_byte(&buf[17]); */
-    /* level    = get_byte(&buf[18]); */         /* level */
+    h->level    = get_byte(&buf[18]); /* header level */
     h->namelen = get_byte(&buf[19]);
     get_char(&buf[20], h->filename, h->namelen);
     h->filename[h->namelen] = 0;
@@ -267,12 +278,110 @@ read_header(FILE *fp, struct lzh_header *h)
     return 1;                   /* success */
 }
 
+static int
+read_header_lv2(FILE *fp, char *buf, struct lzh_header *h)
+{
+    int headersize;
+    int headersum;
+    int ext_headersize;
+    char extbuf[1024];
+    uchar ext_type;
+    int remainder;
+
+    headersize = get_word(&buf[0]);
+
+    fread_crc(buf + 21, 26 - 21, fp);     /* CRC not used */
+
+    get_char(&buf[2], h->method, 5);
+    h->compsize = get_dword(&buf[7]);
+    h->origsize = get_dword(&buf[11]);
+    h->ftime    = get_dword(&buf[15]);
+    /* attrib   = get_byte(&buf[19]); */
+    h->level    = get_byte(&buf[20]); /* header level */
+    h->file_crc = get_word(&buf[21]);
+    h->os_id    = get_byte(&buf[23]);
+
+    ext_headersize = get_word(&buf[24]);
+
+    remainder = headersize - 26;
+
+    while (ext_headersize != 0) {
+        char *p = extbuf;
+
+        remainder -= ext_headersize;
+
+        fread_crc(p, ext_headersize, fp);
+        ext_type = get_byte(p++);
+        switch (ext_type) {
+        case 0:
+            /* header crc */
+            break;
+        case 1:
+            /* filename header */
+            h->namelen = ext_headersize - 3;
+            get_char(p, h->filename, h->namelen);
+            h->filename[h->namelen] = 0;
+            break;
+        case 2:
+            /* dirname header */
+            break;
+        }
+        ext_headersize = get_word(&extbuf[ext_headersize - 2]);
+    }
+
+    while (remainder > 0) {
+        fgetc(fp); /* skip padding */
+        remainder--;
+    }
+
+    return 1;                   /* success */
+}
+
+static int
+read_header(FILE *fp, struct lzh_header *h)
+{
+    int headersize;
+    int headersum;
+    char buf[4096];
+    int ext_headersize;
+    int ret;
+
+    ret = fgetc(fp);
+    buf[0] = (uchar)ret;
+    if (buf[0] == 0 || ret == EOF)
+        return 0;               /* end of archive */
+    fread_crc(buf + 1, 21 - 1, fp);
+    switch (buf[20]) {
+    case 0:
+        break;
+    case 1:
+        return read_header_lv1(fp, buf, h);
+        break;
+    case 2:
+        return read_header_lv2(fp, buf, h);
+        break;
+    default:
+        error("unknown level (%d)\n", buf[20]);
+        break;
+    }
+
+    return 1;                   /* success */
+}
+
 
 void
-write_header(FILE *fp, int headersize, struct lzh_header *h)
+write_header_lv0(FILE *fp, struct lzh_header *h)
+{
+}
+
+void
+write_header_lv1(FILE *fp, struct lzh_header *h)
 {
     char buf[4096], *p = buf;
     int sum;
+    int headersize;
+
+    headersize = 25 + h->namelen;
 
     put_byte(&buf[0], headersize);
     put_byte(&buf[1], 0); /* dummy */
@@ -294,6 +403,93 @@ write_header(FILE *fp, int headersize, struct lzh_header *h)
     fwrite_crc(buf, headersize+2, fp);
 }
 
+void
+write_header_lv2(FILE *fp, struct lzh_header *h)
+{
+    char buf[4096], *p = buf, *crcptr;
+    int sum;
+    int headersize, next_headersize;
+    extern ushort crctable[];
+
+    put_word(&buf[0], 0);       /* dummy */
+    put_char(&buf[2], h->method, 5);
+    put_dword(&buf[7], h->compsize);    /* packed size */
+    put_dword(&buf[11], h->origsize);   /* original size */
+    put_dword(&buf[15], h->ftime);      /* time_t */
+    put_byte(&buf[19], 0x20);           /* DOS attribute (0x20 fixed) */
+    put_byte(&buf[20], 2);              /* level */
+    put_word(&buf[21], h->file_crc);
+    put_byte(&buf[23], 'M');
+
+    headersize = 24;
+
+    /* ext-header */
+    p = buf + headersize;
+    next_headersize = 3 + 2;
+    put_word(p, next_headersize); /* next header size */
+    put_byte(p+2, 0);             /* 0x00: header crc */
+    crcptr = p+3;
+    put_word(p+3, 0);             /* crc (dummy) */
+    headersize += next_headersize;
+
+    p = buf + headersize;
+    next_headersize = 3 + h->namelen;
+    put_word(p, next_headersize);      /* next header size */
+    put_byte(p+2, 1);                  /* 0x01: filename header */
+    put_char(p+3, h->filename, h->namelen); /* filename */
+    headersize += next_headersize;
+
+#if 0
+    p = buf + headersize;
+    next_headersize = 3 + h->namelen;
+    put_word(p, next_headersize); /* next header size */
+    put_byte(p+2, 2);             /* 0x02: dirname header */
+    put_char(p+3, x, len);        /* dirname */
+    headersize += next_headersize;
+#endif
+
+    p = buf + headersize;
+    next_headersize = 0;
+    put_word(p, next_headersize); /* next header size */
+    headersize += next_headersize;
+    headersize += 2;
+
+    /* padding */
+    if (headersize % 256 == 0) {
+        put_byte(&buf[headersize], 0);
+        headersize++;
+    }
+
+    put_word(&buf[0], headersize);
+
+    crc = INIT_CRC;
+    for (p = buf; p - buf < headersize; p++)
+        UPDATE_CRC(*p);
+
+    put_word(crcptr, crc);
+
+    fwrite_crc(buf, headersize, fp);
+}
+
+void
+write_header(FILE *fp, struct lzh_header *h)
+{
+    switch (h->level) {
+    case 0:
+        write_header_lv0(fp, h);
+        break;
+    case 1:
+        write_header_lv1(fp, h);
+        break;
+    case 2:
+        write_header_lv2(fp, h);
+        break;
+    default:
+        error("unknown level (%d)", h->level);
+        break;
+    }
+}
+
 static void
 skip(FILE *fp, struct lzh_header *h)
 {
@@ -306,7 +502,7 @@ copy(FILE *arcfile, FILE *outfile, struct lzh_header *h)
     uint n;
     uchar buffer[MAXDICSIZ];
 
-    write_header(outfile, headersize, h);
+    write_header(outfile, h);
     while (h->compsize != 0) {
         n = (uint) ((h->compsize > sizeof(buffer)) ? sizeof(buffer) : h->compsize);
         if (fread((char *) buffer, 1, n, arcfile) != n)
@@ -339,6 +535,8 @@ add(int replace_flag, char *filename)
     uint r;
     struct lzh_header h;
 
+    h.level = opts.header_level;
+
     if ((infile = fopen(filename, "rb")) == NULL) {
         fprintf(stderr, "Can't open %s\n", filename);
         return 0;               /* failure */
@@ -356,11 +554,10 @@ add(int replace_flag, char *filename)
     strcpy(h.filename, filename);
     h.namelen = strlen(filename);
 
-    headersize = 25 + h.namelen;
     memcpy(h.method, opts.method->id, sizeof(h.method));  /* compress */
 
     headerpos = ftell(outfile);
-    write_header(outfile, headersize, &h);
+    write_header(outfile, &h);
     arcpos = ftell(outfile);
 
     origsize = compsize = 0;
@@ -386,7 +583,7 @@ add(int replace_flag, char *filename)
     h.origsize = origsize;
 
     fseek(outfile, headerpos, SEEK_SET);
-    write_header(outfile, headersize, &h);
+    write_header(outfile, &h);
     fseek(outfile, 0L, SEEK_END);
     r = ratio(compsize, origsize);
     if (opts.quiet < 2)
@@ -538,6 +735,7 @@ parse_args(int argc, char **argv)
 
         enum {
             LHA_OPT_HELP = 128,
+            LHA_OPT_VERSION,
         };
 
         static struct option long_options[] = {
@@ -551,35 +749,44 @@ parse_args(int argc, char **argv)
                non-NULL: getopt_long() return 0, and *flag set val.
             */
             {"help", no_argument, NULL, LHA_OPT_HELP},
+            {"version", no_argument, NULL, LHA_OPT_VERSION},
             {0, 0, 0, 0}
         };
 
-        c = getopt_long(argc, argv, "o[567]q[012]w:z",
+        c = getopt_long(argc, argv, "h[012]o[567]q[012]w:z",
                         long_options, &option_index);
 
-        if (c == -1) break;
+        if (c == -1) break;     /* end of parsing options */
 
         switch (c) {
-        case 0:                 /* set vallue by long option */
+        case 0:
+            /* set value by long option */
+            break;
+        case 'h':
+            /* header level */
+            opts.header_level = 2;     /* -h is equivalent to -h2 */
+            if (optarg)
+                opts.header_level = *optarg - '0';
             break;
-        case 'o':               /* compress method */
+        case 'o':
+            /* compress method */
             {
-                int idx;
+                int idx = 1;    /* -o means -lh1- method */
 
                 if (optarg)
                     idx = *optarg - '0'; /* -lh[567]- method */
-                else
-                    idx = 1;    /* -lh1- method */
 
                 opts.method   = &methods[idx];
             }
             break;
-        case 'q':               /* quiet mode */
-            opts.quiet = 2;     /* level 2 */
+        case 'q':
+            /* quiet mode */
+            opts.quiet = 2;     /* -q is equivalent to -q2 */
             if (optarg)
                 opts.quiet = *optarg - '0';
             break;
-        case 'w':               /* extract directory */
+        case 'w':
+            /* extract directory */
             if (!optarg)
                 error("extract directory does not specified for `-w'");
             if (*optarg == '=')
@@ -593,6 +800,9 @@ parse_args(int argc, char **argv)
         case LHA_OPT_HELP:
             print_usage();
             break;
+        case LHA_OPT_VERSION:
+            print_version();
+            break;
         default:
             break;
         }
diff --git a/ar.h b/ar.h
index 7acf44a..87d4cb5 100644 (file)
--- a/ar.h
+++ b/ar.h
@@ -20,6 +20,7 @@ struct lha_opts {
     int nocompress;
     char *outdir;
     int quiet;
+    int header_level;
 
     /* compress parameter */
     struct lha_method *method;
@@ -33,6 +34,9 @@ extern ulong origsize, compsize;
 /* io.c */
 
 #define INIT_CRC  0             /* CCITT: 0xFFFF */
+#define UPDATE_CRC(c) \
+       crc = crctable[(crc ^ (c)) & 0xFF] ^ (crc >> CHAR_BIT)
+
 extern FILE *arcfile, *infile, *outfile;
 extern uint crc;
 extern ushort bitbuf;
index 9f334bc..7a686a3 100644 (file)
@@ -1045,7 +1045,7 @@ DICBIT は、とりあえず13(-lh5)であるからビット列であらわす
                                                |-----------|
                                                 (DICBIT-9)
 
-と12ビット目から4ビット目までを使用した値の範囲となる。
+と11ビット目から4ビット目までを使用した値の範囲となる。
 ここでは、node 型(実体はunsigned short)の範囲を想定している。
 なお、short が16bitであることも前提となっているように思う。
 
@@ -1203,9 +1203,10 @@ c<<4       | 0| 0| 0| 0| y| y| y| y| y| y| y| y| 0| 0| 0| 0|
                    x  y  y  y  y  y  y  y  y  y  y  y  y  y
 
 
-p, c の2文字(2*8bit)の情報を、12bitに写像しており、p の上位4bitとcの下位4bit
-を使っている。これを行う理由ははっきりとはまだわからないが、
-HASH()が指す node は、引数の組み合わせにより同じ値を持つ場合があることがわかる。
+p, c の2文字(2*8bit)の情報を、12bitに写像(桁上がりも考慮)しており、p の
+上位4bitとcの下位4bit を使っている。これを行う理由ははっきりとはまだわ
+からないが、HASH()が指す node は、引数の組み合わせにより同じ値を持つ場
+合があることがわかる。
 
 c<<4 はc<<(DICBIT-9)であるが、DICBITが大きくなるとbitをずらす範囲が広がる。
 c<<(DICBIT-9) は、2<<DICBIT つまり13bit目を上書きしない程度に2文字目の情報を
diff --git a/io.c b/io.c
index f3acdb3..602999f 100644 (file)
--- a/io.c
+++ b/io.c
@@ -7,14 +7,12 @@
 
 #define CRCPOLY  0xA001         /* ANSI CRC-16 */
                          /* CCITT: 0x8408 */
-#define UPDATE_CRC(c) \
-       crc = crctable[(crc ^ (c)) & 0xFF] ^ (crc >> CHAR_BIT)
 
 FILE *arcfile, *infile, *outfile;
 uint crc;
 ushort bitbuf;
 
-static ushort crctable[UCHAR_MAX + 1];
+ushort crctable[UCHAR_MAX + 1];
 static uint subbitbuf;
 static int bitcount;
 
diff --git a/randtest/.gitignore b/randtest/.gitignore
new file mode 100644 (file)
index 0000000..27eb93a
--- /dev/null
@@ -0,0 +1 @@
+*.lzh