/* LHarc Dearchiver Main */ /* Opens an archive and tests each internal file to see if it matches */ /* a specified wildcard pattern. If it does, it dearchives 1 buffers */ /* worth on each call. It does this for every file in the archive. */ /* 0 <= x != buffer size -> end of file */ /* 0 <= x <= buffer size -> x = # of bytes read into buf */ /* x > buffer size -> # of bytes read into buffer = buf size */ /* 0 > x -> end of archive */ /* if no files match pattern, 0 is returned. Next call -1 is returned */ #include "lharc.h" int NotInterruptedCall = 1; int ForceReturn; extern long WinSiz, BCount, TotRd; char expanded_archive_name[FILENAME_LENGTH]; char *writting_filename; char *archive_name; extern char *WildLZH; extern long BufrCnt; long TotSiz; long cursize; long HWinSiz; char *BfrPtr; LzHeader hdr; long pos; FILE *afp=NULL; long FillBufWithLZH( reading_filename, buffer ) char *reading_filename; char *buffer; { BfrPtr = buffer; HWinSiz = WinSiz >> 1; archive_name = reading_filename; ForceReturn = 0; if( NotInterruptedCall ) { if( afp == NULL ) { /* open archive file */ if ((afp = open_old_archive ()) == NULL) fatal_error (archive_name); } if( get_header (afp, &hdr)) { pos = ftell( afp); BCount = HWinSiz; /* lh5 only */ TotRd = hdr.packed_size; /* lh5 only */ cursize = hdr.original_size; /* lh5 only */ TotSiz = 0; BufrCnt = 0; extract_one( afp, &hdr); } else { /* close archive file */ fclose( afp); afp = NULL; return(-1); } } else { extract_one (afp, &hdr); } if( ForceReturn ) { NotInterruptedCall = 0; } else { fseek( afp, pos + hdr.packed_size, SEEK_SET); if( TotSiz == WinSiz) TotSiz++; /* signify endof int file if nonobvious */ } return(TotSiz); } static message_1 (title, subject, name) char *title, *subject, *name; { fprintf (stderr, "LHarc: %s%s ", title, subject); fflush (stderr); if (errno == 0) fprintf (stderr, "%s\n", name); else perror (name); } void message (subject, name) char *subject, *name; { message_1 ("", subject, name); } void warning (subject, name) char *subject, *name; { message_1 ("Warning: ", subject, name); } void error (subject, msg) char *subject, *msg; { message_1 ("Error: ", subject, msg); } void fatal_error (msg) char *msg; { message_1 ("Fatal error:", "", msg); ErrP("terminating..."); } read_error () { fatal_error (archive_name); } /*----------------------------------------------------------------------*/ /* */ /*----------------------------------------------------------------------*/ static boolean expand_archive_name (dst, src) char *dst, *src; { register char *p, *dot; strcpy (dst, src); for (p = dst, dot = (char*)0; ; p ++, dot = (char*)0) { while (*p == '.') /* skip leading dots of base name */ p ++; for (; *p != '/'; p ++) { if (*p == '.') dot = p; else if (*p == '\0') goto _Done; } } _Done: if (dot) p = dot; strcpy (p, ARCHIVENAME_EXTENTION); /* ".lzh" */ return (strcmp (dst, src) != 0); } /*----------------------------------------------------------------------*/ /* */ /*----------------------------------------------------------------------*/ static int calc_sum (p, len) register char *p; register int len; { register int sum; for (sum = 0; len; len --) sum += *p++; return sum & 0xff; } static char *get_ptr; #define setup_get(PTR) (get_ptr = (PTR)) #define get_byte() (*get_ptr++ & 0xff) #define put_ptr get_ptr #define setup_put(PTR) (put_ptr = (PTR)) static unsigned short get_word () { int b0, b1; b0 = get_byte (); b1 = get_byte (); return (b1 << 8) + b0; } static long get_longword () { long b0, b1, b2, b3; b0 = get_byte (); b1 = get_byte (); b2 = get_byte (); b3 = get_byte (); return (b3 << 24) + (b2 << 16) + (b1 << 8) + b0; } static msdos_to_unix_filename (name, len) register char *name; register int len; { register int i; #ifdef MULTIBYTE_CHAR for (i = 0; i < len; i ++) { if (MULTIBYTE_FIRST_P (name[i]) && MULTIBYTE_SECOND_P (name[i+1])) i ++; else if (name[i] == '\\') name[i] = '/'; else if (isupper (name[i])) name[i] = tolower (name[i]); } #else for (i = 0; i < len; i ++) { if (name[i] == '\\') name[i] = '/'; else if (isupper (name[i])) name[i] = tolower (name[i]); } #endif } static generic_to_unix_filename (name, len) register char *name; register int len; { register int i; boolean lower_case_used = FALSE; #ifdef MULTIBYTE_CHAR for (i = 0; i < len; i ++) { if (MULTIBYTE_FIRST_P (name[i]) && MULTIBYTE_SECOND_P (name[i+1])) i ++; else if (islower (name[i])) { lower_case_used = TRUE; break; } } for (i = 0; i < len; i ++) { if (MULTIBYTE_FIRST_P (name[i]) && MULTIBYTE_SECOND_P (name[i+1])) i ++; else if (name[i] == '\\') name[i] = '/'; else if (!lower_case_used && isupper (name[i])) name[i] = tolower (name[i]); } #else for (i = 0; i < len; i ++) if (islower (name[i])) { lower_case_used = TRUE; break; } for (i = 0; i < len; i ++) { if (name[i] == '\\') name[i] = '/'; else if (!lower_case_used && isupper (name[i])) name[i] = tolower (name[i]); } #endif } static macos_to_unix_filename (name, len) register char *name; register int len; { register int i; for (i = 0; i < len; i ++) { if (name[i] == ':') name[i] = '/'; else if (name[i] == '/') name[i] = ':'; } } /*----------------------------------------------------------------------*/ /* */ /* Generic stamp format: */ /* */ /* 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 */ /* |<-------- year ------->|<- month ->|<-- day -->| */ /* */ /* 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 */ /* |<--- hour --->|<---- minute --->|<- second*2 ->| */ /* */ /*----------------------------------------------------------------------*/ static long gettz () { return(time((time_t *)NULL)); } static time_t generic_to_unix_stamp (t) long t; { int year, month, day, hour, min, sec; long longtime; static unsigned int dsboy[12] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}; unsigned int days; year = ((int)(t >> 16+9) & 0x7f) + 1980; month = (int)(t >> 16+5) & 0x0f; /* 1..12 means Jan..Dec */ day = (int)(t >> 16) & 0x1f; /* 1..31 means 1st,...31st */ hour = ((int)t >> 11) & 0x1f; min = ((int)t >> 5) & 0x3f; sec = ((int)t & 0x1f) * 2; /* Calculate days since 1970.01.01 */ days = (365 * (year - 1970) + /* days due to whole years */ (year - 1970 + 1) / 4 + /* days due to leap years */ dsboy[month-1] + /* days since beginning of this year */ day-1); /* days since beginning of month */ if ((year % 4 == 0) && (year % 400 != 0) && (month >= 3)) /* if this is a leap year and month */ days ++; /* is March or later, add a day */ /* Knowing the days, we can find seconds */ longtime = (((days * 24) + hour) * 60 + min) * 60 + sec; longtime += gettz (); /* adjust for timezone */ /* special case: if MSDOS format date and time were zero, then we set time to be zero here too. */ if (t == 0) longtime = 0; /* LONGTIME is now the time in seconds, since 1970/01/01 00:00:00. */ return (time_t)longtime; } /*----------------------------------------------------------------------*/ /* */ /*----------------------------------------------------------------------*/ boolean get_header (fp, hdr) FILE *fp; register LzHeader *hdr; { int header_size; int name_length; char data[LZHEADER_STRAGE]; int checksum; int i; bzero (hdr, sizeof (LzHeader)); if (((header_size = getc (fp)) == EOF) || (header_size == 0)) { return FALSE; /* finish */ } if (fread (data + I_HEADER_CHECKSUM, sizeof (char), header_size + 1, fp) < header_size + 1) { fatal_error ("Invalid header (LHarc file ?)"); return FALSE; /* finish */ } setup_get (data + I_HEADER_CHECKSUM); checksum = calc_sum (data + I_METHOD, header_size); if (get_byte () != checksum) warning ("Checksum error (LHarc file?)", ""); hdr->header_size = header_size; bcopy (data + I_METHOD, hdr->method, METHOD_TYPE_STRAGE); #ifdef OLD if ((bcmp (hdr->method, LZHUFF1_METHOD, METHOD_TYPE_STRAGE) != 0) && (bcmp (hdr->method, LZHUFF0_METHOD, METHOD_TYPE_STRAGE) != 0) && (bcmp (hdr->method, LARC5_METHOD, METHOD_TYPE_STRAGE) != 0) && (bcmp (hdr->method, LARC4_METHOD, METHOD_TYPE_STRAGE) != 0)) { warning ("Unknown method (LHarc file ?)", ""); return FALSE; /* invalid method */ } #endif setup_get (data + I_PACKED_SIZE); hdr->packed_size = get_longword (); hdr->original_size = get_longword (); hdr->last_modified_stamp = get_longword (); hdr->attribute = get_word (); name_length = get_byte (); for (i = 0; i < name_length; i ++) hdr->name[i] =(char)get_byte (); hdr->name[name_length] = '\0'; /* defaults for other type */ hdr->unix_mode = UNIX_FILE_REGULAR | UNIX_RW_RW_RW; hdr->unix_gid = 0; hdr->unix_uid = 0; if (header_size - name_length >= 24) { /* EXTEND FORMAT */ hdr->crc = get_word (); hdr->extend_type = get_byte (); hdr->minor_version = get_byte (); hdr->has_crc = TRUE; } else if (header_size - name_length == 22) { /* Generic with CRC */ hdr->crc = get_word (); hdr->extend_type = EXTEND_GENERIC; hdr->has_crc = TRUE; } else if (header_size - name_length == 20) { /* Generic no CRC */ hdr->extend_type = EXTEND_GENERIC; hdr->has_crc = FALSE; } else { warning ("Unknown header (LHarc file ?)", ""); return FALSE; } switch (hdr->extend_type) { case EXTEND_MSDOS: msdos_to_unix_filename (hdr->name, name_length); hdr->unix_last_modified_stamp = generic_to_unix_stamp (hdr->last_modified_stamp); break; case EXTEND_UNIX: hdr->unix_last_modified_stamp = (time_t)get_longword (); hdr->unix_mode = get_word (); hdr->unix_uid = get_word (); hdr->unix_gid = get_word (); break; case EXTEND_MACOS: macos_to_unix_filename (hdr->name, name_length); hdr->unix_last_modified_stamp = generic_to_unix_stamp (hdr->last_modified_stamp); break; default: generic_to_unix_filename (hdr->name, name_length); hdr->unix_last_modified_stamp = generic_to_unix_stamp (hdr->last_modified_stamp); } return TRUE; } /*----------------------------------------------------------------------*/ /* */ /*----------------------------------------------------------------------*/ static void modify_filename_extention (buffer, ext) char *buffer; char *ext; { register char *p, *dot; for (p = buffer, dot = (char*)0; *p; p ++) { if (*p == '.') dot = p; else if (*p == '/') dot = (char*)0; } if (dot) p = dot; strcpy (p, ext); } /*----------------------------------------------------------------------*/ /* */ /*----------------------------------------------------------------------*/ static boolean open_old_archive_1 (name, v_fp) char *name; FILE **v_fp; { FILE *fp; struct stat stbuf; if (stat (name, &stbuf) >= 0 && (fp = fopen (name, READ_BINARY)) != NULL) { *v_fp = fp; return TRUE; } *v_fp = NULL; return FALSE; } FILE * open_old_archive () { FILE *fp; if (!open_old_archive_1 (archive_name, &fp)) { if (expand_archive_name (expanded_archive_name, archive_name)) { archive_name = expanded_archive_name; if (open_old_archive_1 (archive_name, &fp)) errno = 0; } } return fp; }