6 put_header(char *buf, int *i, int n, uint32_t x)
9 buf[(*i)++] = (uchar) (x & 0xFF);
15 put_header_tmp(char *buf, int i, int n, uint32_t x)
17 put_header(buf, &i, n, x);
21 put_string(char *buf, int *n, size_t size, char *p)
23 memcpy(buf + *n, p, size);
28 get_header(char *buf, int *i, int size)
34 for (n = size-1; n >= 0; n--) {
35 s = (s << 8) + (unsigned char)buf[*i + n]; /* little endian */
42 get_string(char *buf, int *i, size_t size, char *p)
44 memcpy(p, buf + *i, size);
49 calc_headersum(char *buf, int size)
55 for (i = 0; i < size; i++)
64 return *(unsigned char*)buf;
70 return get_byte(buf) | (get_byte(buf+1) << 8);
76 return get_byte(buf) |
77 (get_byte(buf+1) << 8) |
78 (get_byte(buf+2) << 16) |
79 (get_byte(buf+3) << 24);
83 get_char(char *buf, char *p, size_t size)
89 put_byte(char *buf, int c)
91 *buf = (unsigned char)(c & 0xff);
95 put_word(char *buf, uint16_t c)
98 put_byte(buf+1, c>>8);
102 put_dword(char *buf, uint32_t c)
105 put_byte(buf+1, c>>8);
106 put_byte(buf+2, c>>16);
107 put_byte(buf+3, c>>24);
111 put_char(char *buf, char *p, size_t size)
113 memcpy(buf, p, size);
118 ftime_to_time_t(uint32_t ftime)
121 /* ftime is time structure on MS-DOS
124 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
125 |-------------|-------|---------|---------|-----------|---------|
126 year(-1980) month day hour minute second/2
127 (1-127) (1-12) (1-31) (0-23) (0-59) (0-29)
130 memset(&tm, 0, sizeof(tm));
131 tm.tm_year = (ftime >> 25) + 1980 - 1900;
132 tm.tm_mon = ((ftime >> 21) & 0x0f) - 1;
133 tm.tm_mday = (ftime >> 16) & 0x1f;
134 tm.tm_hour = (ftime >> 11) & 0x1f;
135 tm.tm_min = (ftime >> 5) & 0x3f;
136 tm.tm_sec = (ftime & 0x1f) * 2;
142 time_t_to_ftime(time_t t)
145 /* ftime is time structure on MS-DOS
148 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
149 |-------------|-------|---------|---------|-----------|---------|
150 year(-1980) month day hour minute second/2
151 (1-127) (1-12) (1-31) (0-23) (0-59) (0-29)
155 localtime_r(&t, &tm);
160 return (uint32_t)(tm.tm_year + 1900 - 1980) << 25
161 | (uint32_t)(tm.tm_mon + 1) << 21
162 | (uint32_t)(tm.tm_mday) << 16
163 | (uint32_t)(tm.tm_hour) << 11
164 | (uint32_t)(tm.tm_min) << 5
165 | (uint32_t)(tm.tm_sec / 2);
172 * offset size field name
173 * ----------------------------------
174 * 0 1 header size [*1]
176 * ---------------------------------------
178 * 7 4 packed size [*2] |
179 * 11 4 original size |
182 * 19 1 attribute | [*1] header size (X+Y+22)
183 * 20 1 level (0x00 fixed) |
186 * X +22 2 file crc (CRC-16) |
187 * X +24 Y ext-header(old style) v
188 * -------------------------------------------------
190 * : | [*2] packed size
192 * -------------------------------------------------
194 * ext-header(old style)
208 * bit6 archive bit (need to backup)
212 read_header_lv0(FILE *fp, char *buf, struct lzh_header *h)
219 headersize = get_header(buf, &pos, 1);
220 headersum = get_header(buf, &pos, 1);
222 fread_crc(buf + 21, headersize - (21 - pos), fp, 0); /* CRC not used */
224 if (calc_headersum(buf+pos, headersize) != headersum)
225 error("Header sum error");
227 get_string(buf, &pos, 5, h->method);
228 h->compsize = get_header(buf, &pos, 4);
229 h->origsize = get_header(buf, &pos, 4);
230 h->mtime = ftime_to_time_t(get_header(buf, &pos, 4));
231 /* attrib = */ get_header(buf, &pos, 1);
232 h->level = get_header(buf, &pos, 1); /* header level */
233 h->namelen = get_header(buf, &pos, 1);
234 if (pos + h->namelen > headersize+2) {
235 warn("path name is too long");
236 h->namelen = headersize+2-pos;
238 get_string(buf, &pos, h->namelen, h->filename);
239 h->filename[h->namelen] = 0;
240 h->file_crc = get_header(buf, &pos, 2);
241 h->os_id = 0; /* generic */
243 ext_size = headersize - pos;
247 h->os_id = get_header(buf, &pos, 1);
251 get_header(buf, &pos, 1); /* minor version */
255 h->mtime = get_header(buf, &pos, 4);
259 get_header(buf, &pos, 2); /* mode */
263 get_header(buf, &pos, 2); /* uid */
267 get_header(buf, &pos, 2); /* gid */
272 return 1; /* success */
279 * offset size field name
280 * -----------------------------------
281 * 0 1 header size [*1]
283 * -------------------------------------
285 * 7 4 skip size [*2] |
286 * 11 4 original size |
289 * 19 1 attribute (0x20 fixed) | [*1] header size (X+Y+25)
290 * 20 1 level (0x01 fixed) |
293 * X+ 22 2 file crc (CRC-16) |
296 * X+Y+25 2 next-header size v
297 * -------------------------------------------------
298 * X+Y+27 Z ext-header ^
300 * ----------------------------------- | [*2] skip size
303 * -------------------------------------------------
307 read_header_lv1(FILE *fp, char *buf, struct lzh_header *h)
312 char dirname[1024] = "";
316 headersize = get_header(buf, &pos, 1);
317 headersum = get_header(buf, &pos, 1);
319 fread_crc(buf + 21, headersize - (21 - 2), fp, 0); /* CRC not used */
321 if (calc_headersum(&buf[pos], headersize) != headersum)
322 error("Header sum error");
324 get_string(buf, &pos, 5, h->method);
325 h->compsize = get_header(buf, &pos, 4);
326 h->origsize = get_header(buf, &pos, 4);
327 h->mtime = ftime_to_time_t(get_header(buf, &pos, 4));
328 get_header(buf, &pos, 1); /* attribute */
329 h->level = get_header(buf, &pos, 1); /* header level */
330 h->namelen = get_header(buf, &pos, 1);
331 get_string(buf, &pos, h->namelen, h->filename);
332 h->filename[h->namelen] = 0;
333 h->file_crc = get_header(buf, &pos, 2);
334 h->os_id = get_header(buf, &pos, 1);
336 ext_headersize = get_header(buf, &pos, 2);
338 while (ext_headersize != 0) {
343 h->compsize -= ext_headersize;
345 if (fread(extbuf, ext_headersize, 1, fp) != 1) {
346 error("can't read ext header");
349 ext_type = get_header(extbuf, &extpos, 1);
352 /* filename header */
353 h->namelen = ext_headersize - 3;
354 get_string(extbuf, &extpos, h->namelen, h->filename);
355 h->filename[h->namelen] = 0;
359 dirnamelen = ext_headersize - 3;
360 get_string(extbuf, &extpos, dirnamelen, dirname);
361 dirname[dirnamelen] = 0;
364 h->mtime = get_header(extbuf, &extpos, 4);
369 extpos = ext_headersize - 2;
370 ext_headersize = get_header(extbuf, &extpos, 2);
373 if (dirnamelen > 0 && dirname[dirnamelen-1] != '/') {
374 dirname[dirnamelen++] = '/';
377 strcat(dirname, h->filename);
378 h->namelen = strlen(dirname);
379 strcpy(h->filename, dirname);
381 return 1; /* success */
388 * offset size field name
389 * --------------------------------------------------
390 * 0 2 total header size [*1] ^
391 * ----------------------- |
393 * 7 4 packed size [*2] |
394 * 11 4 original size |
396 * 19 1 RESERVED (0x20 fixed) | [*1] total header size
397 * 20 1 level (0x02 fixed) | (X+26+(1))
398 * 21 2 file crc (CRC-16) |
400 * 24 2 next-header size |
401 * ----------------------------------- |
404 * ----------------------------------- |
405 * X +26 (1) padding v
406 * -------------------------------------------------
408 * : | [*2] packed size
410 * -------------------------------------------------
414 read_header_lv2(FILE *fp, char *buf, struct lzh_header *h)
419 char dirname[1024] = "";
423 headersize = get_header(buf, &pos, 2);
425 fread_crc(buf + 21, 26 - 21, fp, 0); /* CRC not used */
427 get_string(buf, &pos, 5, h->method);
428 h->compsize = get_header(buf, &pos, 4);
429 h->origsize = get_header(buf, &pos, 4);
430 h->mtime = get_header(buf, &pos, 4);
431 get_header(buf, &pos, 1); /* attrib */
432 h->level = get_header(buf, &pos, 1); /* header level */
433 h->file_crc = get_header(buf, &pos, 2);
434 h->os_id = get_header(buf, &pos, 1);
436 ext_headersize = get_header(buf, &pos, 2);
438 remainder = headersize - pos;
440 while (ext_headersize != 0) {
445 remainder -= ext_headersize;
447 if (fread(extbuf, ext_headersize, 1, fp) != 1) {
448 error("can't read ext header");
450 ext_type = get_header(extbuf, &extpos, 1);
456 /* filename header */
457 h->namelen = ext_headersize - 3;
458 get_string(extbuf, &extpos, h->namelen, h->filename);
459 h->filename[h->namelen] = 0;
463 dirnamelen = ext_headersize - 3;
464 get_string(extbuf, &extpos, dirnamelen, dirname);
465 dirname[dirnamelen] = 0;
470 extpos = ext_headersize - 2;
471 ext_headersize = get_header(extbuf, &extpos, 2);
474 if (dirnamelen > 0 && dirname[dirnamelen-1] != '/') {
475 dirname[dirnamelen++] = '/';
478 strcat(dirname, h->filename);
479 h->namelen = strlen(dirname);
480 strcpy(h->filename, dirname);
482 while (remainder > 0) {
483 fgetc(fp); /* skip padding */
487 return 1; /* success */
491 read_header(FILE *fp, struct lzh_header *h)
498 if (buf[0] == 0 || ret == EOF)
499 return 0; /* end of archive */
500 fread_crc(buf + 1, 21 - 1, fp, 0);
503 return read_header_lv0(fp, buf, h);
506 return read_header_lv1(fp, buf, h);
509 return read_header_lv2(fp, buf, h);
512 error("unknown level (%d)\n", buf[20]);
516 return 1; /* success */
521 write_header_lv0(FILE *fp, struct lzh_header *h)
530 headersize += 12; /* extended header size */
532 if (headersize + h->namelen > 255) {
533 warn("path name is too long");
534 h->namelen = 255 - headersize;
538 headersize += h->namelen;
541 put_header(buf, &pos, 1, headersize);
542 put_header(buf, &pos, 1, 0); /* dummy */
544 put_string(buf, &pos, 5, h->method);
545 put_header(buf, &pos, 4, h->compsize); /* packed size */
546 put_header(buf, &pos, 4, h->origsize); /* original size */
547 put_header(buf, &pos, 4, time_t_to_ftime(h->mtime)); /* ftime */
548 put_header(buf, &pos, 1, 0x20); /* attribute */
549 put_header(buf, &pos, 1, 0); /* level */
550 put_header(buf, &pos, 1, h->namelen); /* length of pathname */
551 put_string(buf, &pos, h->namelen, h->filename);
552 put_header(buf, &pos, 2, h->file_crc);
555 /* extended header for Unix */
556 put_header(buf, &pos, 1, 'U'); /* OS type */
557 put_header(buf, &pos, 1, '\0'); /* minor version */
558 put_header(buf, &pos, 4, h->mtime); /* time_t */
559 put_header(buf, &pos, 2, 0100000); /* mode */
560 put_header(buf, &pos, 2, 0); /* uid */
561 put_header(buf, &pos, 2, 0); /* gid */
564 sum = calc_headersum(buf+2, headersize);
565 put_header_tmp(buf, 1, 1, sum);
567 fwrite_crc(buf, headersize+2, fp, 0);
571 write_header_lv1(FILE *fp, struct lzh_header *h)
579 char *dirname, *fname;
582 fname = xbasename(h->filename);
583 dirname = h->filename;
584 dirnamelen = fname - dirname;
585 h->namelen = strlen(fname);
589 put_header(buf, &pos, 1, 0); /* dummy */
590 put_header(buf, &pos, 1, 0); /* dummy */
591 put_string(buf, &pos, 5, h->method);
592 put_header(buf, &pos, 4, h->compsize); /* packed size */
593 put_header(buf, &pos, 4, h->origsize); /* original size */
594 put_header(buf, &pos, 4, time_t_to_ftime(h->mtime)); /* ftime */
595 put_header(buf, &pos, 1, 0x20); /* attribute */
596 put_header(buf, &pos, 1, 1); /* level */
597 if (headersize + h->namelen > 255)
598 put_header(buf, &pos, 1, 0); /* length of pathname */
600 put_header(buf, &pos, 1, h->namelen); /* length of pathname */
601 put_string(buf, &pos, h->namelen, fname);
602 headersize += h->namelen;
604 put_header_tmp(buf, 0, 1, headersize); /* header size */
605 put_header(buf, &pos, 2, h->file_crc);
607 put_header(buf, &pos, 1, '\0');
609 put_header(buf, &pos, 1, 'U');
612 put_header(buf, &pos, 2, 7); /* next header size */
613 put_header(buf, &pos, 1, 0x54); /* time stamp */
614 put_header(buf, &pos, 4, h->mtime); /* time_t */
616 if (h->namelen > 0) {
617 put_header(buf, &pos, 2, 3 + h->namelen);
618 put_header(buf, &pos, 1, 1); /* 0x01: filename header */
619 put_string(buf, &pos, h->namelen, fname); /* filename */
622 if (dirnamelen > 0) {
623 put_header(buf, &pos, 2, 3 + dirnamelen);
624 put_header(buf, &pos, 1, 2); /* 0x02: dirname header */
625 put_string(buf, &pos, dirnamelen, dirname); /* dirname */
628 extsize = pos - extpos;
629 put_header(buf, &pos, 2, 0); /* next header size (end of header) */
631 put_header_tmp(buf, 7, 4, h->compsize+extsize); /* packed size */
633 sum = calc_headersum(buf+2, headersize);
634 put_header_tmp(buf, 1, 1, sum);
636 fwrite_crc(buf, headersize+2+extsize, fp, 0);
640 write_header_lv2(FILE *fp, struct lzh_header *h)
642 char buf[4096], *crcptr;
644 extern ushort crctable[];
645 char dirname[1024] = "", *fname;
649 put_header(buf, &pos, 2, 0); /* dummy */
650 put_string(buf, &pos, 5, h->method);
651 put_header(buf, &pos, 4, h->compsize); /* packed size */
652 put_header(buf, &pos, 4, h->origsize); /* original size */
653 put_header(buf, &pos, 4, h->mtime); /* time_t */
654 put_header(buf, &pos, 1, 0x20); /* DOS attribute (0x20 fixed) */
655 put_header(buf, &pos, 1, 2); /* level */
656 put_header(buf, &pos, 2, h->file_crc);
658 put_header(buf, &pos, 1, '\0');
660 put_header(buf, &pos, 1, 'U');
662 put_header(buf, &pos, 2, 5);
663 put_header(buf, &pos, 1, 0); /* 0x00: header crc */
665 put_header(buf, &pos, 2, 0); /* crc (dummy) */
667 fname = xbasename(h->filename);
670 put_header(buf, &pos, 2, 3 + len);
671 put_header(buf, &pos, 1, 1); /* 0x01: filename header */
672 put_string(buf, &pos, len, fname); /* filename */
677 ptr = strrchr(h->filename, '/');
679 dirnamelen = ptr - h->filename;
680 strncpy(dirname, h->filename, dirnamelen);
681 dirname[dirnamelen+ 1] = 0;
686 put_header(buf, &pos, 2, 3 + dirnamelen);
687 put_header(buf, &pos, 1, 2); /* 0x02: dirname header */
688 put_string(buf, &pos, dirnamelen, dirname); /* dirname */
691 put_header(buf, &pos, 2, 0); /* next header size (end of header) */
694 if (pos % 256 == 0) {
695 put_header(buf, &pos, 1, 0);
699 put_header_tmp(buf, 0, 2, headersize);
706 for (i = 0; i < headersize; i++)
707 UPDATE_CRC(crc, buf[i]);
708 put_header_tmp(crcptr, 0, 2, crc);
711 fwrite_crc(buf, headersize, fp, 0);
715 write_header(FILE *fp, struct lzh_header *h)
719 write_header_lv0(fp, h);
722 write_header_lv1(fp, h);
725 write_header_lv2(fp, h);
728 error("unknown level (%d)", h->level);