OSDN Git Service

ar.c was splited into header.c
authorKoji Arai <jca02266@gmail.com>
Mon, 26 May 2008 13:50:42 +0000 (22:50 +0900)
committerKoji Arai <jca02266@gmail.com>
Mon, 26 May 2008 13:50:42 +0000 (22:50 +0900)
ar.c
header.c [new file with mode: 0644]
makefile
prototypes.h

diff --git a/ar.c b/ar.c
index 13d9931..fe7d56c 100644 (file)
--- a/ar.c
+++ b/ar.c
@@ -165,734 +165,6 @@ os_string(char id)
 }
 
 static void
-put_header(char *buf, int *i, int n, uint32_t x)
-{
-    while (--n >= 0) {
-        buf[(*i)++] = (uchar) (x & 0xFF);
-        x >>= 8;
-    }
-}
-
-static void
-put_header_tmp(char *buf, int i, int n, uint32_t x)
-{
-    put_header(buf, &i, n, x);
-}
-
-void
-put_string(char *buf, int *n, size_t size, char *p)
-{
-    memcpy(buf + *n, p, size);
-    *n += size;
-}
-
-static uint32_t
-get_header(char *buf, int *i, int size)
-{
-    uint32_t s;
-    int n;
-
-    s = 0;
-    for (n = size-1; n >= 0; n--) {
-        s = (s << 8) + (unsigned char)buf[*i + n];   /* little endian */
-    }
-    *i += size;
-    return s;
-}
-
-void
-get_string(char *buf, int *i, size_t size, char *p)
-{
-    memcpy(p, buf + *i, size);
-    *i += size;
-}
-
-static uint
-calc_headersum(char *buf, int size)
-{
-    int i;
-    uint s;
-
-    s = 0;
-    for (i = 0; i < size; i++)
-        s += buf[i];
-    return s & 0xFF;
-}
-
-#if 0
-int
-get_byte(char *buf)
-{
-    return *(unsigned char*)buf;
-}
-
-uint16_t
-get_word(char *buf)
-{
-    return get_byte(buf) | (get_byte(buf+1) << 8);
-}
-
-uint32_t
-get_dword(char *buf)
-{
-    return get_byte(buf) |
-        (get_byte(buf+1) << 8) |
-        (get_byte(buf+2) << 16) |
-        (get_byte(buf+3) << 24);
-}
-
-void
-get_char(char *buf, char *p, size_t size)
-{
-    memcpy(p, buf, size);
-}
-
-void
-put_byte(char *buf, int c)
-{
-    *buf = (unsigned char)(c & 0xff);
-}
-
-void
-put_word(char *buf, uint16_t c)
-{
-    put_byte(buf,   c);
-    put_byte(buf+1, c>>8);
-}
-
-void
-put_dword(char *buf, uint32_t c)
-{
-    put_byte(buf, c);
-    put_byte(buf+1, c>>8);
-    put_byte(buf+2, c>>16);
-    put_byte(buf+3, c>>24);
-}
-
-void
-put_char(char *buf, char *p, size_t size)
-{
-    memcpy(buf, p, size);
-}
-
-#endif
-time_t
-ftime_to_time_t(uint32_t ftime)
-{
-    struct tm tm;
-    /* ftime is time structure on MS-DOS
-
-    32              24              16               8
-     0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
-      |-------------|-------|---------|---------|-----------|---------|
-       year(-1980)   month   day       hour      minute      second/2
-       (1-127)       (1-12)  (1-31)    (0-23)    (0-59)      (0-29)
-    */
-
-    memset(&tm, 0, sizeof(tm));
-    tm.tm_year = (ftime >> 25) + 1980 - 1900;
-    tm.tm_mon  = ((ftime >> 21) & 0x0f) - 1;
-    tm.tm_mday = (ftime >> 16) & 0x1f;
-    tm.tm_hour = (ftime >> 11) & 0x1f;
-    tm.tm_min  = (ftime >>  5) & 0x3f;
-    tm.tm_sec  = (ftime & 0x1f) * 2;
-
-    return mktime(&tm);
-}
-
-uint32_t
-time_t_to_ftime(time_t t)
-{
-    struct tm tm;
-    /* ftime is time structure on MS-DOS
-
-    32              24              16               8
-     0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
-      |-------------|-------|---------|---------|-----------|---------|
-       year(-1980)   month   day       hour      minute      second/2
-       (1-127)       (1-12)  (1-31)    (0-23)    (0-59)      (0-29)
-    */
-
-#if HAVE_LOCALTIME_R
-    localtime_r(&t, &tm);
-#else
-    tm = *localtime(&t);
-#endif
-
-    return (uint32_t)(tm.tm_year + 1900 - 1980) << 25
-        | (uint32_t)(tm.tm_mon + 1) << 21
-        | (uint32_t)(tm.tm_mday)    << 16
-        | (uint32_t)(tm.tm_hour)    << 11
-        | (uint32_t)(tm.tm_min)     <<  5
-        | (uint32_t)(tm.tm_sec / 2);
-}
-
-
-/*
- * level 0 header
- *
- *
- * offset  size  field name
- * ----------------------------------
- *     0      1  header size    [*1]
- *     1      1  header sum
- *            ---------------------------------------
- *     2      5  method ID                         ^
- *     7      4  packed size    [*2]               |
- *    11      4  original size                     |
- *    15      2  time                              |
- *    17      2  date                              |
- *    19      1  attribute                         | [*1] header size (X+Y+22)
- *    20      1  level (0x00 fixed)                |
- *    21      1  name length                       |
- *    22      X  pathname                          |
- * X +22      2  file crc (CRC-16)                 |
- * X +24      Y  ext-header(old style)             v
- * -------------------------------------------------
- * X+Y+24        data                              ^
- *                 :                               | [*2] packed size
- *                 :                               v
- * -------------------------------------------------
- *
- * ext-header(old style)
- *     0      1  ext-type ('U')
- *     1      1  minor version
- *     2      4  UNIX time
- *     6      2  mode
- *     8      2  uid
- *    10      2  gid
- *
- * attribute (MS-DOS)
- *    bit1  read only
- *    bit2  hidden
- *    bit3  system
- *    bit4  volume label
- *    bit5  directory
- *    bit6  archive bit (need to backup)
- *
- */
-static int
-read_header_lv0(FILE *fp, char *buf, struct lzh_header *h)
-{
-    int headersize;
-    int headersum;
-    int pos = 0;
-    int ext_size;
-
-    headersize = get_header(buf, &pos, 1);
-    headersum = get_header(buf, &pos, 1);
-
-    fread_crc(buf + 21, headersize - (21 - pos), fp);     /* CRC not used */
-
-    if (calc_headersum(buf+pos, headersize) != headersum)
-        error("Header sum error");
-
-    get_string(buf, &pos, 5, h->method);
-    h->compsize = get_header(buf, &pos, 4);
-    h->origsize = get_header(buf, &pos, 4);
-    h->mtime    = ftime_to_time_t(get_header(buf, &pos, 4));
-    /* attrib   = */ get_header(buf, &pos, 1);
-    h->level    = get_header(buf, &pos, 1); /* header level */
-    h->namelen  = get_header(buf, &pos, 1);
-    if (pos + h->namelen > headersize+2) {
-        warn("path name is too long");
-        h->namelen = headersize+2-pos;
-    }
-    get_string(buf, &pos, h->namelen, h->filename);
-    h->filename[h->namelen] = 0;
-    h->file_crc = get_header(buf, &pos, 2);
-    h->os_id    = 0;            /* generic */
-
-    ext_size = headersize - pos;
-
-    if (ext_size > 0) {
-        if (ext_size > 1) {
-            h->os_id = get_header(buf, &pos, 1);
-            ext_size--;
-        }
-        if (ext_size > 1) {
-            get_header(buf, &pos, 1); /* minor version */
-            ext_size--;
-        }
-        if (ext_size > 4) {
-            h->mtime = get_header(buf, &pos, 4);
-            ext_size -= 4;
-        }
-        if (ext_size > 2) {
-            get_header(buf, &pos, 2);         /* mode */
-            ext_size -= 2;
-        }
-        if (ext_size > 2) {
-            get_header(buf, &pos, 2);         /* uid */
-            ext_size -= 2;
-        }
-        if (ext_size > 2) {
-            get_header(buf, &pos, 2);         /* gid */
-            ext_size -= 2;
-        }
-    }
-
-    return 1;                   /* success */
-}
-
-/*
- * level 1 header
- *
- *
- * offset   size  field name
- * -----------------------------------
- *     0       1  header size   [*1]
- *     1       1  header sum
- *             -------------------------------------
- *     2       5  method ID                        ^
- *     7       4  skip size     [*2]               |
- *    11       4  original size                    |
- *    15       2  time                             |
- *    17       2  date                             |
- *    19       1  attribute (0x20 fixed)           | [*1] header size (X+Y+25)
- *    20       1  level (0x01 fixed)               |
- *    21       1  name length                      |
- *    22       X  filename                         |
- * X+ 22       2  file crc (CRC-16)                |
- * X+ 24       1  OS ID                            |
- * X +25       Y  ???                              |
- * X+Y+25      2  next-header size                 v
- * -------------------------------------------------
- * X+Y+27      Z  ext-header                       ^
- *                 :                               |
- * -----------------------------------             | [*2] skip size
- * X+Y+Z+27       data                             |
- *                 :                               v
- * -------------------------------------------------
- *
- */
-static int
-read_header_lv1(FILE *fp, char *buf, struct lzh_header *h)
-{
-    int headersize;
-    int headersum;
-    int ext_headersize;
-    char dirname[1024] = "";
-    int dirnamelen = 0;
-    int pos = 0;
-
-    headersize = get_header(buf, &pos, 1);
-    headersum = get_header(buf, &pos, 1);
-
-    fread_crc(buf + 21, headersize - (21 - 2), fp);     /* CRC not used */
-
-    if (calc_headersum(&buf[pos], headersize) != headersum)
-        error("Header sum error");
-
-    get_string(buf, &pos, 5, h->method);
-    h->compsize = get_header(buf, &pos, 4);
-    h->origsize = get_header(buf, &pos, 4);
-    h->mtime    = ftime_to_time_t(get_header(buf, &pos, 4));
-    get_header(buf, &pos, 1);   /* attribute */
-    h->level = get_header(buf, &pos, 1); /* header level */
-    h->namelen = get_header(buf, &pos, 1);
-    get_string(buf, &pos, h->namelen, h->filename);
-    h->filename[h->namelen] = 0;
-    h->file_crc = get_header(buf, &pos, 2);
-    h->os_id = get_header(buf, &pos, 1);
-
-    ext_headersize = get_header(buf, &pos, 2);
-
-    while (ext_headersize != 0) {
-        char extbuf[4096];
-        uchar ext_type;
-        int extpos = 0;
-
-        h->compsize -= ext_headersize;
-
-        if (fread(extbuf, ext_headersize, 1, fp) != 1) {
-            error("can't read ext header");
-        }
-
-        ext_type = get_header(extbuf, &extpos, 1);
-        switch (ext_type) {
-        case 1:
-            /* filename header */
-            h->namelen = ext_headersize - 3;
-            get_string(extbuf, &extpos, h->namelen, h->filename);
-            h->filename[h->namelen] = 0;
-            break;
-        case 2:
-            /* dirname header */
-            dirnamelen = ext_headersize - 3;
-            get_string(extbuf, &extpos, dirnamelen, dirname);
-            dirname[dirnamelen] = 0;
-            break;
-        case 0x54:
-            h->mtime = get_header(extbuf, &extpos, 4);
-            break;
-        default:
-            break;
-        }
-        extpos = ext_headersize - 2;
-        ext_headersize = get_header(extbuf, &extpos, 2);
-    }
-
-    if (dirnamelen > 0 && dirname[dirnamelen-1] != '/') {
-        dirname[dirnamelen++] = '/';
-    }
-
-    strcat(dirname, h->filename);
-    h->namelen = strlen(dirname);
-    strcpy(h->filename, dirname);
-
-    return 1;                   /* success */
-}
-
-/*
- * level 2 header
- *
- *
- * offset   size  field name
- * --------------------------------------------------
- *     0       2  total header size [*1]           ^
- *             -----------------------             |
- *     2       5  method ID                        |
- *     7       4  packed size       [*2]           |
- *    11       4  original size                    |
- *    15       4  time                             |
- *    19       1  RESERVED (0x20 fixed)            | [*1] total header size
- *    20       1  level (0x02 fixed)               |      (X+26+(1))
- *    21       2  file crc (CRC-16)                |
- *    23       1  OS ID                            |
- *    24       2  next-header size                 |
- * -----------------------------------             |
- *    26       X  ext-header                       |
- *                 :                               |
- * -----------------------------------             |
- * X +26      (1) padding                          v
- * -------------------------------------------------
- * X +26+(1)      data                             ^
- *                 :                               | [*2] packed size
- *                 :                               v
- * -------------------------------------------------
- *
- */
-static int
-read_header_lv2(FILE *fp, char *buf, struct lzh_header *h)
-{
-    int headersize;
-    int ext_headersize;
-    int remainder;
-    char dirname[1024] = "";
-    int dirnamelen = 0;
-    int pos = 0;
-
-    headersize = get_header(buf, &pos, 2);
-
-    fread_crc(buf + 21, 26 - 21, fp);     /* CRC not used */
-
-    get_string(buf, &pos, 5, h->method);
-    h->compsize = get_header(buf, &pos, 4);
-    h->origsize = get_header(buf, &pos, 4);
-    h->mtime    = get_header(buf, &pos, 4);
-    get_header(buf, &pos, 1);         /* attrib */
-    h->level    = get_header(buf, &pos, 1); /* header level */
-    h->file_crc = get_header(buf, &pos, 2);
-    h->os_id    = get_header(buf, &pos, 1);
-
-    ext_headersize = get_header(buf, &pos, 2);
-
-    remainder = headersize - pos;
-
-    while (ext_headersize != 0) {
-        char extbuf[4096];
-        uchar ext_type;
-        int extpos = 0;
-
-        remainder -= ext_headersize;
-
-        if (fread(extbuf, ext_headersize, 1, fp) != 1) {
-            error("can't read ext header");
-        }
-        ext_type = get_header(extbuf, &extpos, 1);
-        switch (ext_type) {
-        case 0:
-            /* header crc */
-            break;
-        case 1:
-            /* filename header */
-            h->namelen = ext_headersize - 3;
-            get_string(extbuf, &extpos, h->namelen, h->filename);
-            h->filename[h->namelen] = 0;
-            break;
-        case 2:
-            /* dirname header */
-            dirnamelen = ext_headersize - 3;
-            get_string(extbuf, &extpos, dirnamelen, dirname);
-            dirname[dirnamelen] = 0;
-            break;
-        default:
-            break;
-        }
-        extpos = ext_headersize - 2;
-        ext_headersize = get_header(extbuf, &extpos, 2);
-    }
-
-    if (dirnamelen > 0 && dirname[dirnamelen-1] != '/') {
-        dirname[dirnamelen++] = '/';
-    }
-
-    strcat(dirname, h->filename);
-    h->namelen = strlen(dirname);
-    strcpy(h->filename, dirname);
-
-    while (remainder > 0) {
-        fgetc(fp); /* skip padding */
-        remainder--;
-    }
-
-    return 1;                   /* success */
-}
-
-static int
-read_header(FILE *fp, struct lzh_header *h)
-{
-    char buf[4096];
-    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:
-        return read_header_lv0(fp, buf, h);
-        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_lv0(FILE *fp, struct lzh_header *h)
-{
-    char buf[4096];
-    int sum;
-    int headersize;
-    int pos = 0;
-
-    headersize = 22;
-    if (!opts.generic)
-        headersize += 12;       /* extended header size */
-
-    if (headersize + h->namelen > 255) {
-        warn("path name is too long");
-        h->namelen = 255 - headersize;
-        headersize = 255;
-    }
-    else {
-        headersize += h->namelen;
-    }
-
-    put_header(buf, &pos, 1, headersize);
-    put_header(buf, &pos, 1, 0); /* dummy */
-
-    put_string(buf, &pos, 5, h->method);
-    put_header(buf, &pos, 4, h->compsize); /* packed size */
-    put_header(buf, &pos, 4, h->origsize); /* original size */
-    put_header(buf, &pos, 4, time_t_to_ftime(h->mtime)); /* ftime */
-    put_header(buf, &pos, 1, 0x20);     /* attribute */
-    put_header(buf, &pos, 1, 0);        /* level */
-    put_header(buf, &pos, 1, h->namelen); /* length of pathname */
-    put_string(buf, &pos, h->namelen, h->filename);
-    put_header(buf, &pos, 2, h->file_crc);
-
-    if (!opts.generic) {
-        /* extended header for Unix */
-        put_header(buf, &pos, 1, 'U');  /* OS type */
-        put_header(buf, &pos, 1, '\0'); /* minor version */
-        put_header(buf, &pos, 4, h->mtime); /* time_t */
-        put_header(buf, &pos, 2, 0100000);  /* mode */
-        put_header(buf, &pos, 2, 0);  /* uid */
-        put_header(buf, &pos, 2, 0);  /* gid */
-    }
-
-    sum = calc_headersum(buf+2, headersize);
-    put_header_tmp(buf, 1, 1, sum);
-
-    fwrite_crc(buf, headersize+2, fp);
-}
-
-void
-write_header_lv1(FILE *fp, struct lzh_header *h)
-{
-    char buf[4096];
-    int sum;
-    int headersize;
-    int extsize = 0;
-    int pos = 0;
-    int extpos;
-    char *dirname, *fname;
-    int dirnamelen;
-
-    fname  = xbasename(h->filename);
-    dirname   = h->filename;
-    dirnamelen = fname - dirname;
-    h->namelen = strlen(fname);
-
-    headersize = 25;
-
-    put_header(buf, &pos, 1, 0); /* dummy */
-    put_header(buf, &pos, 1, 0); /* dummy */
-    put_string(buf, &pos, 5, h->method);
-    put_header(buf, &pos, 4, h->compsize); /* packed size */
-    put_header(buf, &pos, 4, h->origsize); /* original size */
-    put_header(buf, &pos, 4, time_t_to_ftime(h->mtime)); /* ftime */
-    put_header(buf, &pos, 1, 0x20);     /* attribute */
-    put_header(buf, &pos, 1, 1);        /* level */
-    if (headersize + h->namelen > 255)
-        put_header(buf, &pos, 1, 0);            /* length of pathname */
-    else {
-        put_header(buf, &pos, 1, h->namelen);   /* length of pathname */
-        put_string(buf, &pos, h->namelen, fname);
-        headersize += h->namelen;
-    }
-    put_header_tmp(buf, 0, 1, headersize); /* header size */
-    put_header(buf, &pos, 2, h->file_crc);
-    if (opts.generic)
-        put_header(buf, &pos, 1, '\0');
-    else
-        put_header(buf, &pos, 1, 'U');
-
-    extpos = pos;
-    put_header(buf, &pos, 2, 7); /* next header size */
-    put_header(buf, &pos, 1, 0x54); /* time stamp */
-    put_header(buf, &pos, 4, h->mtime); /* time_t */
-
-    if (h->namelen > 0) {
-        put_header(buf, &pos, 2, 3 + h->namelen);
-        put_header(buf, &pos, 1, 1); /* 0x01: filename header */
-        put_string(buf, &pos, h->namelen, fname); /* filename */
-    }
-
-    if (dirnamelen > 0) {
-        put_header(buf, &pos, 2, 3 + dirnamelen);
-        put_header(buf, &pos, 1, 2); /* 0x02: dirname header */
-        put_string(buf, &pos, dirnamelen, dirname); /* dirname */
-    }
-
-    extsize = pos - extpos;
-    put_header(buf, &pos, 2, 0); /* next header size (end of header) */
-
-    put_header_tmp(buf, 7, 4, h->compsize+extsize);    /* packed size */
-
-    sum = calc_headersum(buf+2, headersize);
-    put_header_tmp(buf, 1, 1, sum);
-
-    fwrite_crc(buf, headersize+2+extsize, fp);
-}
-
-void
-write_header_lv2(FILE *fp, struct lzh_header *h)
-{
-    char buf[4096], *crcptr;
-    int headersize;
-    extern ushort crctable[];
-    char dirname[1024] = "", *fname;
-    int dirnamelen, len;
-    int pos = 0;
-
-    put_header(buf, &pos, 2, 0); /* dummy */
-    put_string(buf, &pos, 5, h->method);
-    put_header(buf, &pos, 4, h->compsize); /* packed size */
-    put_header(buf, &pos, 4, h->origsize); /* original size */
-    put_header(buf, &pos, 4, h->mtime);    /* time_t */
-    put_header(buf, &pos, 1, 0x20);        /* DOS attribute (0x20 fixed) */
-    put_header(buf, &pos, 1, 2);           /* level */
-    put_header(buf, &pos, 2, h->file_crc);
-    if (opts.generic)
-        put_header(buf, &pos, 1, '\0');
-    else
-        put_header(buf, &pos, 1, 'U');
-
-    put_header(buf, &pos, 2, 5);
-    put_header(buf, &pos, 1, 0); /* 0x00: header crc */
-    crcptr = &buf[pos];
-    put_header(buf, &pos, 2, 0); /* crc (dummy) */
-
-    fname = xbasename(h->filename);
-    len = strlen(fname);
-
-    put_header(buf, &pos, 2, 3 + len);
-    put_header(buf, &pos, 1, 1); /* 0x01: filename header */
-    put_string(buf, &pos, len, fname); /* filename */
-
-    {
-        char *ptr;
-
-        ptr = strrchr(h->filename, '/');
-        if (ptr) {
-            dirnamelen = ptr - h->filename;
-            strncpy(dirname, h->filename, dirnamelen);
-            dirname[dirnamelen+ 1] = 0;
-        }
-    }
-
-    if (*dirname) {
-        put_header(buf, &pos, 2, 3 + dirnamelen);
-        put_header(buf, &pos, 1, 2); /* 0x02: dirname header */
-        put_string(buf, &pos, dirnamelen, dirname); /* dirname */
-    }
-
-    put_header(buf, &pos, 2, 0); /* next header size (end of header) */
-
-    /* padding */
-    if (pos % 256 == 0) {
-        put_header(buf, &pos, 1, 0);
-    }
-    headersize = pos;
-
-    put_header_tmp(buf, 0, 2, headersize);
-
-    {
-        int i;
-
-        crc = INIT_CRC;
-        for (i = 0; i < headersize; i++)
-            UPDATE_CRC(buf[i]);
-        put_header_tmp(crcptr, 0, 2, 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)
 {
     int i;
diff --git a/header.c b/header.c
new file mode 100644 (file)
index 0000000..e6dc879
--- /dev/null
+++ b/header.c
@@ -0,0 +1,730 @@
+#include <string.h>
+#include <time.h>
+#include "ar.h"
+
+static void
+put_header(char *buf, int *i, int n, uint32_t x)
+{
+    while (--n >= 0) {
+        buf[(*i)++] = (uchar) (x & 0xFF);
+        x >>= 8;
+    }
+}
+
+static void
+put_header_tmp(char *buf, int i, int n, uint32_t x)
+{
+    put_header(buf, &i, n, x);
+}
+
+static void
+put_string(char *buf, int *n, size_t size, char *p)
+{
+    memcpy(buf + *n, p, size);
+    *n += size;
+}
+
+static uint32_t
+get_header(char *buf, int *i, int size)
+{
+    uint32_t s;
+    int n;
+
+    s = 0;
+    for (n = size-1; n >= 0; n--) {
+        s = (s << 8) + (unsigned char)buf[*i + n];   /* little endian */
+    }
+    *i += size;
+    return s;
+}
+
+static void
+get_string(char *buf, int *i, size_t size, char *p)
+{
+    memcpy(p, buf + *i, size);
+    *i += size;
+}
+
+static uint
+calc_headersum(char *buf, int size)
+{
+    int i;
+    uint s;
+
+    s = 0;
+    for (i = 0; i < size; i++)
+        s += buf[i];
+    return s & 0xFF;
+}
+
+#if 0
+static int
+get_byte(char *buf)
+{
+    return *(unsigned char*)buf;
+}
+
+static uint16_t
+get_word(char *buf)
+{
+    return get_byte(buf) | (get_byte(buf+1) << 8);
+}
+
+static uint32_t
+get_dword(char *buf)
+{
+    return get_byte(buf) |
+        (get_byte(buf+1) << 8) |
+        (get_byte(buf+2) << 16) |
+        (get_byte(buf+3) << 24);
+}
+
+static void
+get_char(char *buf, char *p, size_t size)
+{
+    memcpy(p, buf, size);
+}
+
+static void
+put_byte(char *buf, int c)
+{
+    *buf = (unsigned char)(c & 0xff);
+}
+
+static void
+put_word(char *buf, uint16_t c)
+{
+    put_byte(buf,   c);
+    put_byte(buf+1, c>>8);
+}
+
+static void
+put_dword(char *buf, uint32_t c)
+{
+    put_byte(buf, c);
+    put_byte(buf+1, c>>8);
+    put_byte(buf+2, c>>16);
+    put_byte(buf+3, c>>24);
+}
+
+static void
+put_char(char *buf, char *p, size_t size)
+{
+    memcpy(buf, p, size);
+}
+
+#endif
+static time_t
+ftime_to_time_t(uint32_t ftime)
+{
+    struct tm tm;
+    /* ftime is time structure on MS-DOS
+
+    32              24              16               8
+     0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
+      |-------------|-------|---------|---------|-----------|---------|
+       year(-1980)   month   day       hour      minute      second/2
+       (1-127)       (1-12)  (1-31)    (0-23)    (0-59)      (0-29)
+    */
+
+    memset(&tm, 0, sizeof(tm));
+    tm.tm_year = (ftime >> 25) + 1980 - 1900;
+    tm.tm_mon  = ((ftime >> 21) & 0x0f) - 1;
+    tm.tm_mday = (ftime >> 16) & 0x1f;
+    tm.tm_hour = (ftime >> 11) & 0x1f;
+    tm.tm_min  = (ftime >>  5) & 0x3f;
+    tm.tm_sec  = (ftime & 0x1f) * 2;
+
+    return mktime(&tm);
+}
+
+static uint32_t
+time_t_to_ftime(time_t t)
+{
+    struct tm tm;
+    /* ftime is time structure on MS-DOS
+
+    32              24              16               8
+     0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
+      |-------------|-------|---------|---------|-----------|---------|
+       year(-1980)   month   day       hour      minute      second/2
+       (1-127)       (1-12)  (1-31)    (0-23)    (0-59)      (0-29)
+    */
+
+#if HAVE_LOCALTIME_R
+    localtime_r(&t, &tm);
+#else
+    tm = *localtime(&t);
+#endif
+
+    return (uint32_t)(tm.tm_year + 1900 - 1980) << 25
+        | (uint32_t)(tm.tm_mon + 1) << 21
+        | (uint32_t)(tm.tm_mday)    << 16
+        | (uint32_t)(tm.tm_hour)    << 11
+        | (uint32_t)(tm.tm_min)     <<  5
+        | (uint32_t)(tm.tm_sec / 2);
+}
+
+/*
+ * level 0 header
+ *
+ *
+ * offset  size  field name
+ * ----------------------------------
+ *     0      1  header size    [*1]
+ *     1      1  header sum
+ *            ---------------------------------------
+ *     2      5  method ID                         ^
+ *     7      4  packed size    [*2]               |
+ *    11      4  original size                     |
+ *    15      2  time                              |
+ *    17      2  date                              |
+ *    19      1  attribute                         | [*1] header size (X+Y+22)
+ *    20      1  level (0x00 fixed)                |
+ *    21      1  name length                       |
+ *    22      X  pathname                          |
+ * X +22      2  file crc (CRC-16)                 |
+ * X +24      Y  ext-header(old style)             v
+ * -------------------------------------------------
+ * X+Y+24        data                              ^
+ *                 :                               | [*2] packed size
+ *                 :                               v
+ * -------------------------------------------------
+ *
+ * ext-header(old style)
+ *     0      1  ext-type ('U')
+ *     1      1  minor version
+ *     2      4  UNIX time
+ *     6      2  mode
+ *     8      2  uid
+ *    10      2  gid
+ *
+ * attribute (MS-DOS)
+ *    bit1  read only
+ *    bit2  hidden
+ *    bit3  system
+ *    bit4  volume label
+ *    bit5  directory
+ *    bit6  archive bit (need to backup)
+ *
+ */
+static int
+read_header_lv0(FILE *fp, char *buf, struct lzh_header *h)
+{
+    int headersize;
+    int headersum;
+    int pos = 0;
+    int ext_size;
+
+    headersize = get_header(buf, &pos, 1);
+    headersum = get_header(buf, &pos, 1);
+
+    fread_crc(buf + 21, headersize - (21 - pos), fp);     /* CRC not used */
+
+    if (calc_headersum(buf+pos, headersize) != headersum)
+        error("Header sum error");
+
+    get_string(buf, &pos, 5, h->method);
+    h->compsize = get_header(buf, &pos, 4);
+    h->origsize = get_header(buf, &pos, 4);
+    h->mtime    = ftime_to_time_t(get_header(buf, &pos, 4));
+    /* attrib   = */ get_header(buf, &pos, 1);
+    h->level    = get_header(buf, &pos, 1); /* header level */
+    h->namelen  = get_header(buf, &pos, 1);
+    if (pos + h->namelen > headersize+2) {
+        warn("path name is too long");
+        h->namelen = headersize+2-pos;
+    }
+    get_string(buf, &pos, h->namelen, h->filename);
+    h->filename[h->namelen] = 0;
+    h->file_crc = get_header(buf, &pos, 2);
+    h->os_id    = 0;            /* generic */
+
+    ext_size = headersize - pos;
+
+    if (ext_size > 0) {
+        if (ext_size > 1) {
+            h->os_id = get_header(buf, &pos, 1);
+            ext_size--;
+        }
+        if (ext_size > 1) {
+            get_header(buf, &pos, 1); /* minor version */
+            ext_size--;
+        }
+        if (ext_size > 4) {
+            h->mtime = get_header(buf, &pos, 4);
+            ext_size -= 4;
+        }
+        if (ext_size > 2) {
+            get_header(buf, &pos, 2);         /* mode */
+            ext_size -= 2;
+        }
+        if (ext_size > 2) {
+            get_header(buf, &pos, 2);         /* uid */
+            ext_size -= 2;
+        }
+        if (ext_size > 2) {
+            get_header(buf, &pos, 2);         /* gid */
+            ext_size -= 2;
+        }
+    }
+
+    return 1;                   /* success */
+}
+
+/*
+ * level 1 header
+ *
+ *
+ * offset   size  field name
+ * -----------------------------------
+ *     0       1  header size   [*1]
+ *     1       1  header sum
+ *             -------------------------------------
+ *     2       5  method ID                        ^
+ *     7       4  skip size     [*2]               |
+ *    11       4  original size                    |
+ *    15       2  time                             |
+ *    17       2  date                             |
+ *    19       1  attribute (0x20 fixed)           | [*1] header size (X+Y+25)
+ *    20       1  level (0x01 fixed)               |
+ *    21       1  name length                      |
+ *    22       X  filename                         |
+ * X+ 22       2  file crc (CRC-16)                |
+ * X+ 24       1  OS ID                            |
+ * X +25       Y  ???                              |
+ * X+Y+25      2  next-header size                 v
+ * -------------------------------------------------
+ * X+Y+27      Z  ext-header                       ^
+ *                 :                               |
+ * -----------------------------------             | [*2] skip size
+ * X+Y+Z+27       data                             |
+ *                 :                               v
+ * -------------------------------------------------
+ *
+ */
+static int
+read_header_lv1(FILE *fp, char *buf, struct lzh_header *h)
+{
+    int headersize;
+    int headersum;
+    int ext_headersize;
+    char dirname[1024] = "";
+    int dirnamelen = 0;
+    int pos = 0;
+
+    headersize = get_header(buf, &pos, 1);
+    headersum = get_header(buf, &pos, 1);
+
+    fread_crc(buf + 21, headersize - (21 - 2), fp);     /* CRC not used */
+
+    if (calc_headersum(&buf[pos], headersize) != headersum)
+        error("Header sum error");
+
+    get_string(buf, &pos, 5, h->method);
+    h->compsize = get_header(buf, &pos, 4);
+    h->origsize = get_header(buf, &pos, 4);
+    h->mtime    = ftime_to_time_t(get_header(buf, &pos, 4));
+    get_header(buf, &pos, 1);   /* attribute */
+    h->level = get_header(buf, &pos, 1); /* header level */
+    h->namelen = get_header(buf, &pos, 1);
+    get_string(buf, &pos, h->namelen, h->filename);
+    h->filename[h->namelen] = 0;
+    h->file_crc = get_header(buf, &pos, 2);
+    h->os_id = get_header(buf, &pos, 1);
+
+    ext_headersize = get_header(buf, &pos, 2);
+
+    while (ext_headersize != 0) {
+        char extbuf[4096];
+        uchar ext_type;
+        int extpos = 0;
+
+        h->compsize -= ext_headersize;
+
+        if (fread(extbuf, ext_headersize, 1, fp) != 1) {
+            error("can't read ext header");
+        }
+
+        ext_type = get_header(extbuf, &extpos, 1);
+        switch (ext_type) {
+        case 1:
+            /* filename header */
+            h->namelen = ext_headersize - 3;
+            get_string(extbuf, &extpos, h->namelen, h->filename);
+            h->filename[h->namelen] = 0;
+            break;
+        case 2:
+            /* dirname header */
+            dirnamelen = ext_headersize - 3;
+            get_string(extbuf, &extpos, dirnamelen, dirname);
+            dirname[dirnamelen] = 0;
+            break;
+        case 0x54:
+            h->mtime = get_header(extbuf, &extpos, 4);
+            break;
+        default:
+            break;
+        }
+        extpos = ext_headersize - 2;
+        ext_headersize = get_header(extbuf, &extpos, 2);
+    }
+
+    if (dirnamelen > 0 && dirname[dirnamelen-1] != '/') {
+        dirname[dirnamelen++] = '/';
+    }
+
+    strcat(dirname, h->filename);
+    h->namelen = strlen(dirname);
+    strcpy(h->filename, dirname);
+
+    return 1;                   /* success */
+}
+
+/*
+ * level 2 header
+ *
+ *
+ * offset   size  field name
+ * --------------------------------------------------
+ *     0       2  total header size [*1]           ^
+ *             -----------------------             |
+ *     2       5  method ID                        |
+ *     7       4  packed size       [*2]           |
+ *    11       4  original size                    |
+ *    15       4  time                             |
+ *    19       1  RESERVED (0x20 fixed)            | [*1] total header size
+ *    20       1  level (0x02 fixed)               |      (X+26+(1))
+ *    21       2  file crc (CRC-16)                |
+ *    23       1  OS ID                            |
+ *    24       2  next-header size                 |
+ * -----------------------------------             |
+ *    26       X  ext-header                       |
+ *                 :                               |
+ * -----------------------------------             |
+ * X +26      (1) padding                          v
+ * -------------------------------------------------
+ * X +26+(1)      data                             ^
+ *                 :                               | [*2] packed size
+ *                 :                               v
+ * -------------------------------------------------
+ *
+ */
+static int
+read_header_lv2(FILE *fp, char *buf, struct lzh_header *h)
+{
+    int headersize;
+    int ext_headersize;
+    int remainder;
+    char dirname[1024] = "";
+    int dirnamelen = 0;
+    int pos = 0;
+
+    headersize = get_header(buf, &pos, 2);
+
+    fread_crc(buf + 21, 26 - 21, fp);     /* CRC not used */
+
+    get_string(buf, &pos, 5, h->method);
+    h->compsize = get_header(buf, &pos, 4);
+    h->origsize = get_header(buf, &pos, 4);
+    h->mtime    = get_header(buf, &pos, 4);
+    get_header(buf, &pos, 1);         /* attrib */
+    h->level    = get_header(buf, &pos, 1); /* header level */
+    h->file_crc = get_header(buf, &pos, 2);
+    h->os_id    = get_header(buf, &pos, 1);
+
+    ext_headersize = get_header(buf, &pos, 2);
+
+    remainder = headersize - pos;
+
+    while (ext_headersize != 0) {
+        char extbuf[4096];
+        uchar ext_type;
+        int extpos = 0;
+
+        remainder -= ext_headersize;
+
+        if (fread(extbuf, ext_headersize, 1, fp) != 1) {
+            error("can't read ext header");
+        }
+        ext_type = get_header(extbuf, &extpos, 1);
+        switch (ext_type) {
+        case 0:
+            /* header crc */
+            break;
+        case 1:
+            /* filename header */
+            h->namelen = ext_headersize - 3;
+            get_string(extbuf, &extpos, h->namelen, h->filename);
+            h->filename[h->namelen] = 0;
+            break;
+        case 2:
+            /* dirname header */
+            dirnamelen = ext_headersize - 3;
+            get_string(extbuf, &extpos, dirnamelen, dirname);
+            dirname[dirnamelen] = 0;
+            break;
+        default:
+            break;
+        }
+        extpos = ext_headersize - 2;
+        ext_headersize = get_header(extbuf, &extpos, 2);
+    }
+
+    if (dirnamelen > 0 && dirname[dirnamelen-1] != '/') {
+        dirname[dirnamelen++] = '/';
+    }
+
+    strcat(dirname, h->filename);
+    h->namelen = strlen(dirname);
+    strcpy(h->filename, dirname);
+
+    while (remainder > 0) {
+        fgetc(fp); /* skip padding */
+        remainder--;
+    }
+
+    return 1;                   /* success */
+}
+
+int
+read_header(FILE *fp, struct lzh_header *h)
+{
+    char buf[4096];
+    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:
+        return read_header_lv0(fp, buf, h);
+        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 */
+}
+
+
+static void
+write_header_lv0(FILE *fp, struct lzh_header *h)
+{
+    char buf[4096];
+    int sum;
+    int headersize;
+    int pos = 0;
+
+    headersize = 22;
+    if (!opts.generic)
+        headersize += 12;       /* extended header size */
+
+    if (headersize + h->namelen > 255) {
+        warn("path name is too long");
+        h->namelen = 255 - headersize;
+        headersize = 255;
+    }
+    else {
+        headersize += h->namelen;
+    }
+
+    put_header(buf, &pos, 1, headersize);
+    put_header(buf, &pos, 1, 0); /* dummy */
+
+    put_string(buf, &pos, 5, h->method);
+    put_header(buf, &pos, 4, h->compsize); /* packed size */
+    put_header(buf, &pos, 4, h->origsize); /* original size */
+    put_header(buf, &pos, 4, time_t_to_ftime(h->mtime)); /* ftime */
+    put_header(buf, &pos, 1, 0x20);     /* attribute */
+    put_header(buf, &pos, 1, 0);        /* level */
+    put_header(buf, &pos, 1, h->namelen); /* length of pathname */
+    put_string(buf, &pos, h->namelen, h->filename);
+    put_header(buf, &pos, 2, h->file_crc);
+
+    if (!opts.generic) {
+        /* extended header for Unix */
+        put_header(buf, &pos, 1, 'U');  /* OS type */
+        put_header(buf, &pos, 1, '\0'); /* minor version */
+        put_header(buf, &pos, 4, h->mtime); /* time_t */
+        put_header(buf, &pos, 2, 0100000);  /* mode */
+        put_header(buf, &pos, 2, 0);  /* uid */
+        put_header(buf, &pos, 2, 0);  /* gid */
+    }
+
+    sum = calc_headersum(buf+2, headersize);
+    put_header_tmp(buf, 1, 1, sum);
+
+    fwrite_crc(buf, headersize+2, fp);
+}
+
+static void
+write_header_lv1(FILE *fp, struct lzh_header *h)
+{
+    char buf[4096];
+    int sum;
+    int headersize;
+    int extsize = 0;
+    int pos = 0;
+    int extpos;
+    char *dirname, *fname;
+    int dirnamelen;
+
+    fname  = xbasename(h->filename);
+    dirname   = h->filename;
+    dirnamelen = fname - dirname;
+    h->namelen = strlen(fname);
+
+    headersize = 25;
+
+    put_header(buf, &pos, 1, 0); /* dummy */
+    put_header(buf, &pos, 1, 0); /* dummy */
+    put_string(buf, &pos, 5, h->method);
+    put_header(buf, &pos, 4, h->compsize); /* packed size */
+    put_header(buf, &pos, 4, h->origsize); /* original size */
+    put_header(buf, &pos, 4, time_t_to_ftime(h->mtime)); /* ftime */
+    put_header(buf, &pos, 1, 0x20);     /* attribute */
+    put_header(buf, &pos, 1, 1);        /* level */
+    if (headersize + h->namelen > 255)
+        put_header(buf, &pos, 1, 0);            /* length of pathname */
+    else {
+        put_header(buf, &pos, 1, h->namelen);   /* length of pathname */
+        put_string(buf, &pos, h->namelen, fname);
+        headersize += h->namelen;
+    }
+    put_header_tmp(buf, 0, 1, headersize); /* header size */
+    put_header(buf, &pos, 2, h->file_crc);
+    if (opts.generic)
+        put_header(buf, &pos, 1, '\0');
+    else
+        put_header(buf, &pos, 1, 'U');
+
+    extpos = pos;
+    put_header(buf, &pos, 2, 7); /* next header size */
+    put_header(buf, &pos, 1, 0x54); /* time stamp */
+    put_header(buf, &pos, 4, h->mtime); /* time_t */
+
+    if (h->namelen > 0) {
+        put_header(buf, &pos, 2, 3 + h->namelen);
+        put_header(buf, &pos, 1, 1); /* 0x01: filename header */
+        put_string(buf, &pos, h->namelen, fname); /* filename */
+    }
+
+    if (dirnamelen > 0) {
+        put_header(buf, &pos, 2, 3 + dirnamelen);
+        put_header(buf, &pos, 1, 2); /* 0x02: dirname header */
+        put_string(buf, &pos, dirnamelen, dirname); /* dirname */
+    }
+
+    extsize = pos - extpos;
+    put_header(buf, &pos, 2, 0); /* next header size (end of header) */
+
+    put_header_tmp(buf, 7, 4, h->compsize+extsize);    /* packed size */
+
+    sum = calc_headersum(buf+2, headersize);
+    put_header_tmp(buf, 1, 1, sum);
+
+    fwrite_crc(buf, headersize+2+extsize, fp);
+}
+
+static void
+write_header_lv2(FILE *fp, struct lzh_header *h)
+{
+    char buf[4096], *crcptr;
+    int headersize;
+    extern ushort crctable[];
+    char dirname[1024] = "", *fname;
+    int dirnamelen, len;
+    int pos = 0;
+
+    put_header(buf, &pos, 2, 0); /* dummy */
+    put_string(buf, &pos, 5, h->method);
+    put_header(buf, &pos, 4, h->compsize); /* packed size */
+    put_header(buf, &pos, 4, h->origsize); /* original size */
+    put_header(buf, &pos, 4, h->mtime);    /* time_t */
+    put_header(buf, &pos, 1, 0x20);        /* DOS attribute (0x20 fixed) */
+    put_header(buf, &pos, 1, 2);           /* level */
+    put_header(buf, &pos, 2, h->file_crc);
+    if (opts.generic)
+        put_header(buf, &pos, 1, '\0');
+    else
+        put_header(buf, &pos, 1, 'U');
+
+    put_header(buf, &pos, 2, 5);
+    put_header(buf, &pos, 1, 0); /* 0x00: header crc */
+    crcptr = &buf[pos];
+    put_header(buf, &pos, 2, 0); /* crc (dummy) */
+
+    fname = xbasename(h->filename);
+    len = strlen(fname);
+
+    put_header(buf, &pos, 2, 3 + len);
+    put_header(buf, &pos, 1, 1); /* 0x01: filename header */
+    put_string(buf, &pos, len, fname); /* filename */
+
+    {
+        char *ptr;
+
+        ptr = strrchr(h->filename, '/');
+        if (ptr) {
+            dirnamelen = ptr - h->filename;
+            strncpy(dirname, h->filename, dirnamelen);
+            dirname[dirnamelen+ 1] = 0;
+        }
+    }
+
+    if (*dirname) {
+        put_header(buf, &pos, 2, 3 + dirnamelen);
+        put_header(buf, &pos, 1, 2); /* 0x02: dirname header */
+        put_string(buf, &pos, dirnamelen, dirname); /* dirname */
+    }
+
+    put_header(buf, &pos, 2, 0); /* next header size (end of header) */
+
+    /* padding */
+    if (pos % 256 == 0) {
+        put_header(buf, &pos, 1, 0);
+    }
+    headersize = pos;
+
+    put_header_tmp(buf, 0, 2, headersize);
+
+    {
+        int i;
+
+        crc = INIT_CRC;
+        for (i = 0; i < headersize; i++)
+            UPDATE_CRC(buf[i]);
+        put_header_tmp(crcptr, 0, 2, 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;
+    }
+}
index ef3df4b..7432efe 100644 (file)
--- a/makefile
+++ b/makefile
@@ -6,7 +6,7 @@ else
   EXEEXT=
 endif
 OBJS1 = ar.o io.o encode.o decode.o maketree.o maketbl.o huf.o \
-       strlib.o pathlib.o filelib.o
+       strlib.o pathlib.o filelib.o header.o
 OBJS2 = getopt_long.o
 
 OBJS = $(OBJS1) $(OBJS2)
index de8b823..c8d378b 100644 (file)
@@ -7,14 +7,6 @@
 
 /* ar.c */
 struct lha_method *which_method P_((char *id));
-void put_string P_((char *buf, int *n, size_t size, char *p));
-void get_string P_((char *buf, int *i, size_t size, char *p));
-time_t ftime_to_time_t P_((uint32_t ftime));
-uint32_t time_t_to_ftime P_((time_t t));
-void write_header_lv0 P_((FILE *fp, struct lzh_header *h));
-void write_header_lv1 P_((FILE *fp, struct lzh_header *h));
-void write_header_lv2 P_((FILE *fp, struct lzh_header *h));
-void write_header P_((FILE *fp, struct lzh_header *h));
 int get_line P_((char *s, int n));
 void parse_args P_((int argc, char **argv));
 FILE *open_tempfile P_((void));
@@ -67,3 +59,6 @@ int file_mtime P_((char *file, time_t *t));
 int copy_stream P_((FILE *rfp, FILE *wfp));
 int move_file_to_stream P_((char *file, FILE *wfp));
 int xrename P_((char *from, char *to));
+/* header.c */
+int read_header P_((FILE *fp, struct lzh_header *h));
+void write_header P_((FILE *fp, struct lzh_header *h));