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"
int ftime;
int file_crc;
char os_id;
+ int level;
};
struct lha_method methods[] = {
opts.nocompress = 0;
opts.outdir = NULL;
opts.quiet = 0;
+ opts.header_level = 2;
/* default is the -lh5- method */
opts.method = &methods[5];
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);
}
}
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");
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;
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 */
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)
{
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)
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 */
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;
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)
enum {
LHA_OPT_HELP = 128,
+ LHA_OPT_VERSION,
};
static struct option long_options[] = {
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 == '=')
case LHA_OPT_HELP:
print_usage();
break;
+ case LHA_OPT_VERSION:
+ print_version();
+ break;
default:
break;
}