#include "macunpack.h" #ifdef DIA #define DIA_INTERNAL #include "dia.h" #include #include #include "globals.h" #include "../util/curtime.h" #include "../util/masks.h" #include "../util/transname.h" #include "../fileio/machdr.h" #include "../fileio/wrfile.h" #include "../fileio/kind.h" #include "../util/util.h" static unsigned char *dia_archive; static int dia_archive_size; static int dia_max_archive_size; static int dia_finfo; static int dia_method; static unsigned char *dia_archive_ptr; static unsigned char *dia_header_ptr; static unsigned char *dia_header_last; static int dia_forklength; static int dia_cforklength; static unsigned char dia_bitbuf[BCHUNKSIZE]; static int dia_LZtab[BCHUNKSIZE]; static unsigned char *dia_bit_base; static int dia_imask; static void dia_folder(unsigned char *name); static void dia_file(int indicator, unsigned char *name); static void dia_getlength(int nblocks); static void dia_skipfork(int nblocks); static void dia_getfork(int nblocks); static void dia_getblock(unsigned char **archive_ptr, unsigned char **block_ptr); static int dia_decode(unsigned char *ibuff, unsigned char *obuff, int in_length); static int dia_prevbit(void); void dia (unsigned char *bin_hdr) { int i, folder, nlength; unsigned char hdr; unsigned char *header; dir_skip = 0; for(i = 0; i < INFOBYTES; i++) { info[i] = 0; } if(in_data_size > dia_max_archive_size) { if(dia_archive == NULL) { dia_archive = (unsigned char *)malloc((unsigned)in_data_size); } else { dia_archive = (unsigned char *)realloc((char *)dia_archive, (unsigned)in_data_size); } if(dia_archive == 0) { (void)fprintf(stderr, "Insufficient memory.\n"); exit(1); } dia_max_archive_size = in_data_size; } dia_archive_size = in_data_size; if(fread((char *)dia_archive, 1, in_data_size, infp) != in_data_size) { (void)fprintf(stderr, "Can't read archive.\n"); #ifdef SCAN do_error("macunpack: Can't read archive"); #endif /* SCAN */ exit(1); } nlength = bin_hdr[I_NAMEOFF] & BYTEMASK; if(!strncmp((char *)bin_hdr + I_NAMEOFF + nlength - 1, " \272", 2)) { nlength -= 2; } info[I_NAMEOFF] = nlength; for(i = 1; i <= nlength; i++) { info[I_NAMEOFF + i] = bin_hdr[I_NAMEOFF + i]; } hdr = *dia_archive; folder = hdr & IS_FOLDER; dia_finfo = hdr & F_INFO; if(hdr & VOLUME) { (void)fprintf(stderr, "Multi-segment archives not implemented.\n"); #ifdef SCAN do_error("macunpack: Multi-segment archive"); #endif /* SCAN */ exit(1); } if(hdr & CRYPTED) { (void)fprintf(stderr, "Encrypted archives not implemented.\n"); #ifdef SCAN do_idf("", PROTECTED); #endif /* SCAN */ exit(1); } i = (hdr & N_BLOCKS) + 1; header = (unsigned char *)malloc((unsigned)(i * CHUNKSIZE)); dia_archive_ptr = dia_archive + 1; dia_header_last = header; dia_method = 0; while(i-- > 0) { dia_getblock(&dia_archive_ptr, &dia_header_last); } dia_header_ptr = header; if(folder) { dia_folder((unsigned char *)NULL); } else { dia_file(*dia_header_ptr++, (unsigned char *)NULL); } free((char *)header); } static void dia_folder (unsigned char *name) { unsigned char lname[32]; int i, length, doit = 0; unsigned char indicator, *old_ptr; if(name != NULL) { for(i = 0; i < INFOBYTES; i++) { info[i] = 0; } length = *name++ & REMAINS; info[I_NAMEOFF] = length; for(i = 1; i <= length; i++) { info[I_NAMEOFF + i] = *name++; } } else { length = info[I_NAMEOFF]; } if(dia_finfo) { dia_header_ptr += 20; } if(!dir_skip) { doit = 1; if(list) { transname(info + I_NAMEOFF + 1, (char *)lname, length); do_indent(indent); (void)fprintf(stderr, "folder=\"%s\"", lname); if(query) { doit = do_query(); } else { (void)fputc('\n', stderr); } if(doit) { indent++; } else { dir_skip = 1; } } if(doit && !info_only) { do_mkdir((char *)lname, info); } } else { dir_skip++; } while(dia_header_ptr < dia_header_last) { indicator = *dia_header_ptr; if(indicator & LEAVE_FOLDER) { *dia_header_ptr = indicator & ~LEAVE_FOLDER; break; } else if(indicator & ONLY_FOLDER) { if(indicator == ONLY_FOLDER) { dia_header_ptr++; } else { *dia_header_ptr -= 1; } break; } else if(indicator & FOLDER) { old_ptr = dia_header_ptr; dia_header_ptr += (indicator & REMAINS) + 1; dia_folder(old_ptr); } else { dia_header_ptr++; old_ptr = dia_header_ptr; dia_header_ptr += (*old_ptr & REMAINS) + 1; dia_file(indicator, old_ptr); } } if(!dir_skip) { if(doit) { indent--; if(!info_only) { enddir(); } do_indent(indent); (void)fprintf(stderr, "leaving folder \"%s\"\n", lname); } } else { dir_skip--; } } static void dia_file (int indicator, unsigned char *name) { unsigned char lname[32]; int i, length, doit; int n_data, n_rsrc; unsigned char *old_archive_ptr; char ftype[5], fauth[5]; int dataLength, rsrcLength; int cdataLength, crsrcLength; int dataMethod, rsrcMethod; uint32_t curtime; if(name != NULL) { for(i = 0; i < INFOBYTES; i++) { info[i] = 0; } length = *name++ & REMAINS; info[I_NAMEOFF] = length; for(i = 1; i <= length; i++) { info[I_NAMEOFF + i] = *name++; } } else { length = info[I_NAMEOFF]; } for(i = 0; i < 4; i++) { info[I_TYPEOFF + i] = *dia_header_ptr++; } for(i = 0; i < 4; i++) { info[I_AUTHOFF + i] = *dia_header_ptr++; } if(indicator & DATE_PRESENT) { for(i = 0; i < 4; i++) { info[I_CTIMOFF + i] = *dia_header_ptr++; } for(i = 0; i < 4; i++) { info[I_MTIMOFF + i] = *dia_header_ptr++; } } else { curtime = (uint32_t)time((time_t *)0) + TIMEDIFF; put4(info + I_CTIMOFF, curtime); put4(info + I_MTIMOFF, curtime); } if(dia_finfo) { for(i = 0; i < 6; i++) { info[I_FLAGOFF + i] = *dia_header_ptr++; } } n_data = 0; if(indicator & HAS_DATA) { if(indicator & SHORT_DATA) { n_data = 1; } else { n_data = *dia_header_ptr++ + 1; } } n_rsrc = 0; if(indicator & HAS_RSRC) { if(indicator & SHORT_RSRC) { n_rsrc = 1; } else { n_rsrc = *dia_header_ptr++ + 1; } } if(!dir_skip) { old_archive_ptr = dia_archive_ptr; dia_getlength(n_data); dataLength = dia_forklength; cdataLength = dia_cforklength; dataMethod = dia_method; dia_getlength(n_rsrc); rsrcLength = dia_forklength; crsrcLength = dia_cforklength; rsrcMethod = dia_method; dia_archive_ptr = old_archive_ptr; put4(info + I_DLENOFF, (uint32_t)dataLength); put4(info + I_RLENOFF, (uint32_t)rsrcLength); if(list) { transname(info + I_NAMEOFF + 1, (char *)lname, length); do_indent(indent); transname(info + I_TYPEOFF, ftype, 4); transname(info + I_AUTHOFF, fauth, 4); (void)fprintf(stderr, "name=\"%s\", type=%4.4s, author=%4.4s, data=%d, rsrc=%d", lname, ftype, fauth, (int32_t)dataLength, (int32_t)rsrcLength); if(info_only) { doit = 0; } else { doit = 1; } if(query) { doit = do_query(); } else { (void)fputc('\n', stderr); } } else { doit = 1; } } else { dia_skipfork(n_data); dia_skipfork(n_rsrc); return; } if(doit) { define_name((char *)lname); start_info(info, (uint32_t)rsrcLength, (uint32_t)dataLength); } if(verbose) { (void)fprintf(stderr, "\tData: "); if(dataLength == 0) { (void)fprintf(stderr, "empty"); } else if(dataMethod == NOCOMP) { (void)fprintf(stderr, "No compression"); } else { if(dataMethod != COMP) { (void)fprintf(stderr, "Partial "); } (void)fprintf(stderr, "LZFK compressed (%4.1f%%)", 100.0 * cdataLength / dataLength); } } if(doit) { start_data(); dia_getfork(n_data); } else { dia_skipfork(n_data); } if(verbose) { (void)fprintf(stderr, ", Rsrc: "); if(rsrcLength == 0) { (void)fprintf(stderr, "empty"); } else if(rsrcMethod == NOCOMP) { (void)fprintf(stderr, "No compression"); } else { if(rsrcMethod != COMP) { (void)fprintf(stderr, "Partial "); } (void)fprintf(stderr, "LZFK compressed (%4.1f%%)", 100.0 * crsrcLength / rsrcLength); } } if(doit) { start_rsrc(); dia_getfork(n_rsrc); } else { dia_skipfork(n_rsrc); } if(verbose) { (void)fprintf(stderr, ".\n"); } if(doit) { end_file(); } } static void dia_getlength (int nblocks) { int length; unsigned char *arch_ptr, *block_ptr; unsigned char block[CHUNKSIZE]; dia_method = 0; dia_forklength = 0; dia_cforklength = 0; while(nblocks > 1) { nblocks--; length = get2((char *)dia_archive_ptr); if(length >= 0x8000) { length = 0x10000 - length; dia_method |= NOCOMP; } else { dia_method |= COMP; } dia_forklength += CHUNKSIZE; dia_cforklength += length + 2; dia_archive_ptr += length + 2; } if(nblocks == 1) { arch_ptr = dia_archive_ptr; block_ptr = block; dia_getblock(&arch_ptr, &block_ptr); dia_forklength += block_ptr - block; dia_cforklength += arch_ptr - dia_archive_ptr; dia_archive_ptr = arch_ptr; } } static void dia_skipfork (int nblocks) { int length; while(nblocks-- > 0) { length = get2((char *)dia_archive_ptr); if(length >= 0x8000) { length = 0x10000 - length; } dia_archive_ptr += length + 2; } } static void dia_getfork (int nblocks) { while(nblocks-- > 0) { dia_getblock(&dia_archive_ptr, (unsigned char **)&out_ptr); } } static void dia_getblock (unsigned char **archive_ptr, unsigned char **block_ptr) { int length, i; unsigned char *arch_ptr, *bl_ptr; arch_ptr = *archive_ptr; bl_ptr = *block_ptr; length = get2((char *)arch_ptr); arch_ptr += 2; if(length >= 0x8000) { length = 0x10000 - length; for(i = 0; i < length; i++) { *bl_ptr++ = *arch_ptr++; } *block_ptr += length; dia_method |= NOCOMP; } else { *block_ptr += dia_decode(arch_ptr, bl_ptr, length); dia_method |= COMP; } *archive_ptr += length + 2; } static int dia_decode (unsigned char *ibuff, unsigned char *obuff, int in_length) { int nbits, set_zero, i, j; unsigned char *bitbuf_ptr; int count[4]; int *LZtab_ptr; unsigned char *out_ptr, *buf_ptr, *in_ptr; int omask; int LZcount; int *length_ptr, *nchars_ptr; int *offsn_ptr, length, nchars, offset; int *offs_ptr[4]; int nwords; in_ptr = ibuff + in_length; nbits = *--in_ptr; nbits |= (*--in_ptr << 8); if(nbits == WORDMASK) { nbits = *--in_ptr; nbits |= (*--in_ptr << 8); nbits = nbits + WORDMASK; } bitbuf_ptr = dia_bitbuf + BCHUNKSIZE; *--bitbuf_ptr = *--in_ptr; set_zero = 0; dia_bit_base = bitbuf_ptr; dia_imask = 1 << (7 - (nbits & 7)); if(dia_prevbit()) { set_zero = 1; } for(i = 0; i < nbits; i++) { if(set_zero) { *--bitbuf_ptr = 0; } else { *--bitbuf_ptr = *--in_ptr; } if(dia_prevbit()) { set_zero = !set_zero; } } /* Now we have the bits in longitudal order; reorder them */ nwords = ((dia_bit_base - bitbuf_ptr) >> 1); for(i = 0; i < nwords; i++) { dia_LZtab[i] = 0; } omask = 1; for(i = 0; i < 16; i++) { j = nwords; LZtab_ptr = dia_LZtab + nwords; while(j-- > 0) { LZtab_ptr--; if(dia_prevbit()) { *LZtab_ptr |= omask; } } omask <<= 1; } LZcount = nwords / 3; /* At this point we have in LZtab LZcount triples. Each triple consists of the following parts: nchars: the number of characters to take from input length: the number of characters - 1 to copy from output offset: the offset in the output buffer The ordering is as follows: 1. lengths 2. nchars 3. offsets for length 0 4. offsets for length 1 5. offsets for length 2 6. offsets for length 3 7. offsets for other lengths */ /* Now first count the occurences of lengths 0 to 3 */ count[0] = 0; count[1] = 0; count[2] = 0; count[3] = 0; for(i = 0; i < LZcount; i++) { if((j = dia_LZtab[i]) < 4) { count[j]++; } } length_ptr = dia_LZtab; nchars_ptr = dia_LZtab + LZcount; offs_ptr[0] = nchars_ptr + LZcount; offs_ptr[1] = offs_ptr[0] + count[0]; offs_ptr[2] = offs_ptr[1] + count[1]; offs_ptr[3] = offs_ptr[2] + count[2]; offsn_ptr = offs_ptr[3] + count[3]; out_ptr = obuff; for(i = 0; i < LZcount; i++) { length = *length_ptr++; nchars = *nchars_ptr++; if(length < 4) { offset = *offs_ptr[length]++; } else { offset = *offsn_ptr++; } while(nchars-- > 0) { *out_ptr++ = *ibuff++; } buf_ptr = out_ptr - length - offset - 1; while(length-- >= 0) { *out_ptr++ = *buf_ptr++; } } i = in_ptr - ibuff; while(i-- > 0) { *out_ptr++ = *ibuff++; } return out_ptr - obuff; } static int dia_prevbit (void) { int c; if(dia_imask == 0x100) { dia_bit_base--; dia_imask = 1; } c = *dia_bit_base & dia_imask; dia_imask <<= 1; return c; } #else /* DIA */ int dia; /* keep lint and some compilers happy */ #endif /* DIA */