/* ------------------------------------------------------------------------ */ /* */ /* Main file of public UNACE. */ /* */ /* You need to COMPILE and LINK this file ONLY! */ /* */ /* ------------------------------------------------------------------------ */ //--------------- include system dependend things --------------------------// #include "os.h" //--------------- include general files ------------------------------------// #include // delay() _dos_*() #include // open() #include // printf() sprintf() remove() #include // malloc() #include // str*() #include // signal() //--------------- include unace variables and conversion definitions -------// #include "unace.h" #include "variabls.c" #include "portable.h" #include "prototyp.h" //--------------- include other unace routines -----------------------------// #include "uac_crc.c" #include "uac_dcpr.c" #include "uac_comm.c" #include "uac_crt.c" #include "uac_sys.c" //--------------- BEGIN OF UNACE ROUTINES ----------------------------------// void init_unace(void) // initializes unace { printf(version); buf_rd=malloc(size_rdb * sizeof(ULONG)); // Allocate buffers: increase buf =malloc(size_buf); // sizes when possible to speed buf_wr=malloc(size_wrb); // up the program if (buf_rd==NULL || buf==NULL || buf_wr==NULL) f_err = ERR_MEM; make_crctable(); // initialize CRC table dcpr_init(); // initialize decompression set_handler(); // ctrl+break etc. } void done_unace(void) { if (buf_rd ) free(buf_rd ); if (buf ) free(buf ); if (buf_wr ) free(buf_wr ); if (dcpr_text) free(dcpr_text); } INT read_header(INT print_err) // reads any header from archive { USHORT rd, head_size, crc_ok; LONG crc; UCHAR *tp=readbuf; lseek(archan, skipsize, SEEK_CUR); // skip ADDSIZE block if (read(archan, &head, 4)<4) return (0); // read CRC and header size #ifdef HI_LO_BYTE_ORDER WORDswap(&head.HEAD_CRC); WORDswap(&head.HEAD_SIZE); #endif // read size_headrdb bytes into head_size = head.HEAD_SIZE; // header structure rd = (head_size > size_headrdb) ? size_headrdb : head_size; if (read(archan, readbuf, rd) < rd) return (0); head_size -= rd; crc = getcrc(CRC_MASK, readbuf, rd); while (head_size) // skip rest of header { rd = (head_size > size_buf) ? size_buf : head_size; if (read(archan, buf, rd) < rd) return (0); head_size -= rd; crc = getcrc(crc, buf, rd); } head.HEAD_TYPE =*tp++; // generic buffer to head conversion head.HEAD_FLAGS=BUFP2WORD(tp); if (head.HEAD_FLAGS & ACE_ADDSIZE) skipsize = head.ADDSIZE = BUF2LONG(tp); // get ADDSIZE else skipsize = 0; // check header CRC if (!(crc_ok = head.HEAD_CRC == (crc & 0xffff)) && print_err) printf("\nError: archive is broken\n"); else switch (head.HEAD_TYPE) // specific buffer to head conversion { case MAIN_BLK: memcpy(mhead.ACESIGN, tp, acesign_len); tp+=acesign_len; mhead.VER_MOD=*tp++; mhead.VER_CR =*tp++; mhead.HOST_CR=*tp++; mhead.VOL_NUM=*tp++; mhead.TIME_CR=BUFP2LONG(tp); mhead.RES1 =BUFP2WORD(tp); mhead.RES2 =BUFP2WORD(tp); mhead.RES =BUFP2LONG(tp); mhead.AV_SIZE=*tp++; memcpy(mhead.AV, tp, rd-(USHORT)(tp-readbuf)); break; case FILE_BLK: fhead.PSIZE =BUFP2LONG(tp); fhead.SIZE =BUFP2LONG(tp); fhead.FTIME =BUFP2LONG(tp); fhead.ATTR =BUFP2LONG(tp); fhead.CRC32 =BUFP2LONG(tp); fhead.TECH.TYPE =*tp++; fhead.TECH.QUAL =*tp++; fhead.TECH.PARM =BUFP2WORD(tp); fhead.RESERVED =BUFP2WORD(tp); fhead.FNAME_SIZE=BUFP2WORD(tp); memcpy(fhead.FNAME, tp, rd-(USHORT)(tp-readbuf)); break; // default: (REC_BLK and future things): // do nothing 'cause isn't needed for extraction } return (crc_ok); } // maximum SFX module size #define max_sfx_size 65536 // (needed by read_arc_head) INT read_arc_head() // searches for the archive header and reads it { INT i, flags, buf_pos = 0; LONG arc_head_pos, old_fpos, fpos = 0; struct stat st; fstat(archan, &st); memset(buf, 0, size_buf); while (tell(archan) 0; adat.vol = (flags & ACE_MULT_VOL) > 0; adat.vol_num = mhead.VOL_NUM; adat.time_cr = mhead.TIME_CR; return (1); } } } // was no archive header, // continue search lseek(archan, fpos, SEEK_SET); memcpy(buf, &buf[size_buf - 512], 512); buf_pos = 512; // keep 512 old bytes } return (0); } INT open_archive(INT print_err) // opens archive (or volume) { CHAR av_str[80]; archan = open(aname, O_RDONLY | O_BINARY); // open file if (archan == -1) { printf("\nError opening file %s", aname); return (0); } if (!read_arc_head()) // read archive header { if (print_err) printf("\nInvalid archive file: %s\n", aname); close(archan); return (0); } printf("\n\n Processing archive %s\n", aname); if (head.HEAD_FLAGS & ACE_AV) { printf("\nAuthenticity Verification:"); // print the AV sprintf(av_str, "\ncreated on %d.%d.%d by ", ts_day(adat.time_cr), ts_month(adat.time_cr), ts_year(adat.time_cr)); printf(av_str); strncpy(av_str, mhead.AV, mhead.AV_SIZE); av_str[mhead.AV_SIZE] = 0; printf("%s\n", av_str); } comment_out("Main comment:"); // print main comment return (1); } void get_next_volname(void) // get file name of next volume { CHAR *cp; INT num; if ((cp = (CHAR *) strrchr(aname, '.')) == NULL || !*(cp + 1)) num = -1; else { cp++; num = (*(cp + 1) - '0') * 10 + *(cp + 2) - '0'; if (!in(num, 0, 99)) num = -1; if (in(*cp, '0', '9')) num += (*cp - '0') * 100; } num++; if (num < 100) *cp = 'C'; else *cp = num / 100 + '0'; *(cp + 1) = (num / 10) % 10 + '0'; *(cp + 2) = num % 10 + '0'; } INT proc_vol(void) // opens volume { INT i; CHAR s[80]; if (!fileexists(aname) || !f_allvol_pr) { do { sprintf(s, "Ready to process %s?", aname); beep(); i = wrask(s); // ask whether ready or not f_allvol_pr = (i == 1); // "Always" --> process all volumes if (i >= 2) { f_err = ERR_FOUND; return (0); } } while (!fileexists(aname)); } if (!open_archive(1)) // open volume { printf("\nError while opening archive. File not found or archive broken.\n"); f_err = ERR_OPEN; return (0); } return (1); } INT proc_next_vol(void) // opens next volume to process { close(archan); // close handle get_next_volname(); // get file name of next volume if (!proc_vol()) return (0); // try to open volume, read archive header return (read_header(1)); // read 2nd header } INT read_adds_blk(CHAR * buffer, INT len) // reads part of ADD_SIZE block { INT rd = 0, l = len; LONG i; while (!f_err && len && skipsize) { i = (skipsize > len) ? len : skipsize; skipsize -= i; errno = 0; rd += read(archan, buffer, i); if (errno) { printf("\nRead error\n"); f_err = ERR_READ; } buffer += i; len -= i; if (!skipsize) // if block is continued on next volume if (head.HEAD_FLAGS & ACE_SP_AFTER) proc_next_vol(); else break; } return (rd > l ? l : rd); } void crc_print(void) // checks CRC, prints message { INT crc_not_ok = rd_crc != fhead.CRC32; /* check CRC of file */ if (!f_err) // print message { printf(crc_not_ok ? " CRC-check error" : " CRC OK"); flush; } } void analyze_file(void) // analyzes one file (for solid archives) { printf("\n Analyzing"); flush; while (!cancel() && (dcpr_adds_blk(buf_wr, size_wrb))) // decompress only { } crc_print(); } void extract_file(void) // extracts one file { INT rd; printf("\n Extracting"); flush; // decompress block while (!cancel() && (rd = dcpr_adds_blk(buf_wr, size_wrb))) { if (write(wrhan, buf_wr, rd) != rd) // write block { printf("\nWrite error\n"); f_err = ERR_WRITE; } } crc_print(); } void extract_files(void) // extracts all files of the archive { CHAR file[PATH_MAX]; while (!cancel() && read_header(1)) { if (head.HEAD_TYPE == FILE_BLK) { comment_out("File comment:"); // show file comment ace_fname(file, &head); // get file name printf("\n%s", file); dcpr_init_file(); // initialize decompression of file if (!f_err) { wrhan = create_dest_file(file, (INT) fhead.ATTR); // create file if (wrhan != -1) { extract_file(); // extract it #if DOS // set file time _dos_setftime(wrhan, (USHORT) (fhead.FTIME >> 16), (USHORT) fhead.FTIME); #endif close(wrhan); #if DOS // set file attributes _dos_setfileattr(file, (UINT) fhead.ATTR); #endif #if AMIGA { // set file date and time struct DateTime dt; char Date[9], Time[9]; ULONG tstamp=fhead.FTIME; sprintf(Date, "%02d-%02d-%02d", ts_year(tstamp)-1900, ts_month(tstamp), ts_day(tstamp)); sprintf(Time, "%02d:%02d:%02d", ts_hour(tstamp), ts_min(tstamp), ts_sec(tstamp)); dt.dat_Format = FORMAT_INT; dt.dat_Flags = 0; dt.dat_StrDate= Date; dt.dat_StrTime= Time; if (StrToDate(&dt)) SetFileDate(file, &dt.dat_Stamp); } #endif if (f_err) remove(file); } else if (adat.sol) analyze_file(); // analyze file if needed } } } } int main(INT argc, CHAR * argv[]) // processes the archive { CHAR *s; if (argc>=2) { init_unace(); // initialize unace strcpy(aname, argv[1]); // get archive name if (!(s = (CHAR *) strrchr(aname, DIRSEP))) s = aname; if (!strrchr(s, '.')) strcat(aname, ".ACE"); } if (argc<2 || !open_archive(1)) { // open archive to process printf("\n\nUsage: UNACE \n"); f_err = ERR_CLINE; } else { if (adat.vol_num) printf("\nFirst volume of archive required!\n"); else extract_files(); // extract files close(archan); if (f_err) { printf("\nError occurred during extraction\n"); if (f_criterr) printf("Critical error on drive %c\n", f_criterr); } } done_unace(); printf("\n"); return (f_err); }