]>
git.saurik.com Git - wxWidgets.git/blob - utils/Install/packace/unace.c
1 /* ------------------------------------------------------------------------ */
3 /* Main file of public UNACE. */
5 /* ------------------------------------------------------------------------ */
8 //--------------- include general files ------------------------------------//
9 #include <ctype.h> // tolower()
10 #include <fcntl.h> // open()
11 #include <stdio.h> // printf() sprintf() remove()
12 #include <stdlib.h> // malloc()
13 #include <string.h> // str*()
14 #include <sys/types.h>
15 #include <sys/stat.h> // S_I* AMIGA: fstat()
19 #if (!defined(__EMX__) && !defined(__OS2__) && !defined(WINNT) && !defined(WIN32)) || defined(__CYGWIN__)
20 #include <sys/errno.h>
24 //--------------- include unace specific header files ----------------------//
40 //--------------- BEGIN OF UNACE ROUTINES ----------------------------------//
42 int pipeit(char *format
, ...) {
43 /* Do nothing ... perhaps pipe this somewhere in the future */
47 void init_unace(void) // initializes unace
49 buf_rd
=malloc(size_rdb
* sizeof(ULONG
)); // Allocate buffers: increase
50 buf
=malloc(size_buf
); // sizes when possible to speed
51 buf_wr
=malloc(size_wrb
); // up the program
52 readbuf
=malloc(size_headrdb
);
60 make_crctable(); // initialize CRC table
61 dcpr_init(); // initialize decompression
63 set_handler(); // ctrl+break etc.
68 if (buf_rd
) free(buf_rd
);
70 if (buf_wr
) free(buf_wr
);
71 if (readbuf
) free(readbuf
);
72 if (dcpr_text
) free(dcpr_text
);
75 INT
read_header(INT print_err
) // reads any header from archive
83 lseek(archan
, skipsize
, SEEK_CUR
); // skip ADDSIZE block
85 if (read(archan
, &head
, 4)<4)
86 return (0); // read CRC and header size
88 #ifdef HI_LO_BYTE_ORDER
89 WORDswap(&head
.HEAD_CRC
);
90 WORDswap(&head
.HEAD_SIZE
);
92 // read size_headrdb bytes into
93 head_size
= head
.HEAD_SIZE
; // header structure
94 rd
= (head_size
> size_headrdb
) ? size_headrdb
: head_size
;
95 if (read(archan
, readbuf
, rd
) < rd
)
98 crc
= getcrc(CRC_MASK
, readbuf
, rd
);
100 while (head_size
) // skip rest of header
102 rd
= (head_size
> size_buf
) ? size_buf
: head_size
;
103 if (read(archan
, buf
, rd
) < rd
)
106 crc
= getcrc(crc
, (UCHAR
*)buf
, rd
);
109 head
.HEAD_TYPE
=*tp
++; // generic buffer to head conversion
110 head
.HEAD_FLAGS
=BUFP2WORD(tp
);
112 if (head
.HEAD_FLAGS
& ACE_ADDSIZE
)
113 skipsize
= head
.ADDSIZE
= BUF2LONG(tp
); // get ADDSIZE
118 if (!(crc_ok
= head
.HEAD_CRC
== (crc
& 0xffff)) && print_err
)
119 pipeit("\nError: archive is broken\n");
121 switch (head
.HEAD_TYPE
) // specific buffer to head conversion
124 memcpy(mhead
.ACESIGN
, tp
, acesign_len
); tp
+=acesign_len
;
129 mhead
.TIME_CR
=BUFP2LONG(tp
);
130 mhead
.RES1
=BUFP2WORD(tp
);
131 mhead
.RES2
=BUFP2WORD(tp
);
132 mhead
.RES
=BUFP2LONG(tp
);
134 memcpy(mhead
.AV
, tp
, rd
-(USHORT
)(tp
-readbuf
));
137 fhead
.PSIZE
=BUFP2LONG(tp
);
138 fhead
.SIZE
=BUFP2LONG(tp
);
139 fhead
.FTIME
=BUFP2LONG(tp
);
140 fhead
.ATTR
=BUFP2LONG(tp
);
141 fhead
.CRC32
=BUFP2LONG(tp
);
142 fhead
.TECH
.TYPE
=*tp
++;
143 fhead
.TECH
.QUAL
=*tp
++;
144 fhead
.TECH
.PARM
=BUFP2WORD(tp
);
145 fhead
.RESERVED
=BUFP2WORD(tp
);
146 fhead
.FNAME_SIZE
=BUFP2WORD(tp
);
147 memcpy(fhead
.FNAME
, tp
, rd
-(USHORT
)(tp
-readbuf
));
149 // default: (REC_BLK and future things):
150 // do nothing 'cause isn't needed for extraction
155 // maximum SFX module size
156 #define max_sfx_size 65536 // (needed by read_arc_head)
158 INT
read_arc_head(void) // searches for the archive header and reads it
170 memset(buf
, 0, size_buf
);
172 #if !defined(__EMX__) && !defined(__OS2__)
173 while (ftell(farchan
)<st
.st_size
&& fpos
< max_sfx_size
)
175 while (tell(archan
)<st
.st_size
&& fpos
< max_sfx_size
)
179 fpos
+= read(archan
, &buf
[buf_pos
], size_buf
- buf_pos
);
181 for (i
= 0; i
< size_buf
; i
++) // look for the acesign
183 if (!memcmp(acesign
, &buf
[i
], acesign_len
))
185 // seek to the probable begin
187 arc_head_pos
= old_fpos
+ i
- buf_pos
- bytes_before_acesign
;
188 lseek(archan
, arc_head_pos
, SEEK_SET
);
189 if (read_header(0)) // try to read archive header
191 flags
= mhead
.HEAD_FLAGS
;
192 adat
.sol
= (flags
& ACE_SOLID
) > 0;
193 adat
.vol
= (flags
& ACE_MULT_VOL
) > 0;
194 adat
.vol_num
= mhead
.VOL_NUM
;
195 adat
.time_cr
= mhead
.TIME_CR
;
200 // was no archive header,
202 lseek(archan
, fpos
, SEEK_SET
);
203 memcpy(buf
, &buf
[size_buf
- 512], 512);
204 buf_pos
= 512; // keep 512 old bytes
209 INT
open_archive(INT print_err
) // opens archive (or volume)
214 #if defined(__OS2_) || defined(__EMX__) || defined(WIN32)
215 archan
= open(aname
, O_RDONLY
| O_BINARY
); // open file
217 archan
= open(aname
, O_RDONLY
); // open file
219 #if !defined(__EMX__) && !defined(__OS2__)
220 farchan
= fdopen(archan
, "rb");
224 pipeit("\nError opening file %s", aname
);
227 if (!read_arc_head()) // read archive header
230 pipeit("\nInvalid archive file: %s\n", aname
);
231 #if !defined(__EMX__) && !defined(__OS2__)
238 pipeit("\nProcessing archive: %s\n\n", aname
);
239 if (head
.HEAD_FLAGS
& ACE_AV
)
241 pipeit("Authenticity Verification:"); // print the AV
242 sprintf(av_str
, "\ncreated on %d.%d.%d by ",
243 ts_day(adat
.time_cr
), ts_month(adat
.time_cr
), ts_year(adat
.time_cr
));
245 strncpy(av_str
, (char *)mhead
.AV
, mhead
.AV_SIZE
);
246 av_str
[mhead
.AV_SIZE
] = 0;
247 pipeit("%s\n\n", av_str
);
249 comment_out("Main comment:"); // print main comment
253 void get_next_volname(void) // get file name of next volume
258 if ((cp
= (CHAR
*) strrchr(aname
, '.')) == NULL
|| !*(cp
+ 1))
263 num
= (*(cp
+ 1) - '0') * 10 + *(cp
+ 2) - '0';
266 if (in(*cp
, '0', '9'))
267 num
+= (*cp
- '0') * 100;
274 *cp
= num
/ 100 + '0';
275 *(cp
+ 1) = (num
/ 10) % 10 + '0';
276 *(cp
+ 2) = num
% 10 + '0';
279 INT
proc_vol(void) // opens volume
284 if (!fileexists(aname
) || !f_allvol_pr
)
288 sprintf(s
, "Ready to process %s?", aname
);
289 #if !defined(__MINGW32__)
294 i
= wrask(s
); // ask whether ready or not
295 f_allvol_pr
= (i
== 1); // "Always" --> process all volumes
302 while (!fileexists(aname
));
305 if (!open_archive(1)) // open volume
307 pipeit("\nError while opening archive. File not found or archive broken.\n");
315 INT
proc_next_vol(void) // opens next volume to process
317 #if !defined(__EMX__) && !defined(__OS2__)
320 close(archan
); // close handle
321 get_next_volname(); // get file name of next volume
323 if (!proc_vol()) // try to open volume, read archive header
325 if (!read_header(1)) // read 2nd header
333 INT
read_adds_blk(CHAR
* buffer
, INT len
) // reads part of ADD_SIZE block
340 char *cbuffer
=buffer
;
342 if (head
.HEAD_TYPE
== FILE_BLK
&& (head
.HEAD_FLAGS
& ACE_PASSW
))
343 len
= crypt_len(len
);
345 while (!f_err
&& len
&& skipsize
)
347 i
= (skipsize
> len
) ? len
: skipsize
;
350 /* How do I check error condition when comping -mno-cygwin? */
351 #if !defined(__MINGW32__)
354 rd
+= read(archan
, buffer
, i
);
355 #if !defined(__MINGW32__)
358 pipeit("\nRead error\n");
366 if (!skipsize
) // if block is continued on next volume
367 if (head
.HEAD_FLAGS
& ACE_SP_AFTER
&& !proc_next_vol())
371 if (head
.HEAD_TYPE
== FILE_BLK
&& (head
.HEAD_FLAGS
& ACE_PASSW
))
372 decrypt(cbuffer
, rd
);
375 return (rd
> l
? l
: rd
);
378 void crc_print(void) // checks CRC, prints message
380 INT crc_not_ok
= rd_crc
!= fhead
.CRC32
; /* check CRC of file */
382 if (!f_err
) // print message
384 pipeit(crc_not_ok
? " CRC-check error" : " CRC OK");
389 void analyze_file(void) // analyzes one file (for solid archives)
391 pipeit("\n Analyzing");
393 while (!cancel() && (dcpr_adds_blk(buf_wr
, size_wrb
))) // decompress only
398 void extract_file(void) // extracts one file
402 pipeit("\n Extracting");
403 flush
; // decompress block
404 while (!cancel() && (rd
= dcpr_adds_blk(buf_wr
, size_wrb
)))
406 if (write(wrhan
, buf_wr
, rd
) != rd
) // write block
408 pipeit("\nWrite error\n");
415 /* extracts or tests all files of the archive
417 void extract_files(int nopath
, int test
)
421 while (!cancel() && read_header(1))
423 if (head
.HEAD_TYPE
== FILE_BLK
)
425 comment_out("File comment:"); // show file comment
426 ace_fname(file
, &head
, nopath
); // get file name
427 pipeit("\n%s", file
);
429 dcpr_init_file(); // initialize decompression of file
433 (wrhan
= create_dest_file(file
, (INT
) fhead
.ATTR
))<0)
435 if (test
|| adat
.sol
)
436 analyze_file(); // analyze file
440 extract_file(); // extract it
441 #ifdef DOS // set file time
442 _dos_setftime(wrhan
, (USHORT
) (fhead
.FTIME
>> 16), (USHORT
) fhead
.FTIME
);
445 #ifdef DOS // set file attributes
446 _dos_setfileattr(file
, (UINT
) fhead
.ATTR
);
449 { // set file date and time
451 char Date
[9], Time
[9];
452 ULONG tstamp
=fhead
.FTIME
;
454 sprintf(Date
, "%02d-%02d-%02d", ts_year(tstamp
)-1900, ts_month(tstamp
), ts_day(tstamp
));
455 sprintf(Time
, "%02d:%02d:%02d", ts_hour(tstamp
), ts_min(tstamp
), ts_sec(tstamp
));
457 dt
.dat_Format
= FORMAT_INT
;
459 dt
.dat_StrDate
= Date
;
460 dt
.dat_StrTime
= Time
;
463 SetFileDate(file
, &dt
.dat_Stamp
);
474 unsigned percentage(ULONG p
, ULONG d
)
476 return (unsigned)( d
? (d
/2+p
*100)/d
: 100 );
479 void list_files(int verbose
)
486 pipeit("Date |Time |Packed |Size |Ratio|File\n");
488 while (!cancel() && read_header(1))
490 if (head
.HEAD_TYPE
== FILE_BLK
)
492 ULONG ti
=fhead
.FTIME
;
493 ace_fname(file
, &head
, verbose
? 0 : 1); // get file name
497 tpsize
= fhead
.PSIZE
;
500 while (head
.HEAD_FLAGS
& ACE_SP_AFTER
)
503 if (!proc_next_vol())
505 psize
+= fhead
.PSIZE
;
506 tpsize
+= fhead
.PSIZE
;
509 pipeit("%02u.%02u.%02u|%02u:%02u|%c%c%9lu|%9lu|%4u%%|%c%s\n",
510 ts_day (ti
), ts_month(ti
), ts_year(ti
)%100
,
511 ts_hour(ti
), ts_min (ti
),
512 fhead
.HEAD_FLAGS
& ACE_SP_BEF
? '<' : ' ',
513 fhead
.HEAD_FLAGS
& ACE_SP_AFTER
? '>' : ' ',
514 tpsize
, fhead
.SIZE
, percentage(tpsize
, fhead
.SIZE
),
515 fhead
.HEAD_FLAGS
& ACE_PASSW
? '*' : ' ',
522 pipeit("\n %9lu|%9lu|%4u%%| %u file%s",
525 percentage(psize
, size
),
527 (char*)(files
== 1 ? "" : "s")
535 "Usage: UNACE <command> <archive[.ace]>\n"
537 "Where <command> is one of:\n"
541 " t Test archive integrity\n"
542 " v List archive (verbose)\n"
543 " x Extract files with full path"
547 int include_unpack(char *bleah
) // processes the archive
551 strcpy(aname
, bleah
);
553 init_unace(); // initialize unace
555 if (!(s
= (CHAR
*) strrchr(aname
, DIRSEP
)))
557 if (!strrchr(s
, '.'))
558 strcat(aname
, ".ACE");
560 if (open_archive(1)) // open archive to process
563 pipeit("\nFirst volume of archive required!\n");
567 #if !defined(__EMX__) && !defined(__OS2__)
573 pipeit("\nError occurred\n");
575 pipeit("Critical error on drive %c\n", f_criterr
);