]>
git.saurik.com Git - wxWidgets.git/blob - utils/Install/sfxace/unace.c
1 /* ------------------------------------------------------------------------ */
3 /* Main file of public UNACE. */
5 /* ------------------------------------------------------------------------ */
8 #define INCL_WIN /* Window Manager Functions */
13 //--------------- include general files ------------------------------------//
14 #include <ctype.h> // tolower()
15 #include <fcntl.h> // open()
16 #include <stdio.h> // printf() sprintf() remove()
17 #include <stdlib.h> // malloc()
18 #include <string.h> // str*()
19 #include <sys/types.h>
20 #include <sys/stat.h> // S_I* AMIGA: fstat()
21 #if (!defined(__EMX__) && !defined(__OS2__) && !defined(WINNT) && !defined(WIN32)) || defined(__CYGWIN__)
22 #include <sys/errno.h>
25 #if !defined(__EMX__) && !defined(__OS2__) && !defined(WIN32) && !defined(WINNT)
26 #define stricmp strcasecmp
31 extern int installstate
;
33 off_t
acelseek(off_t offset
, int whence
);
34 int aceread(void *buf
, size_t count
);
35 int aceopen(const char *path
, int flags
);
39 char *replacestr(char *str1
, char *str2
, char *str3
);
41 //--------------- include unace specific header files ----------------------//
59 //--------------- BEGIN OF UNACE ROUTINES ----------------------------------//
61 int pipeit(char *format
, ...)
63 /* Do nothing ... perhaps pipe this somewhere in the future */
67 void init_unace(void) // initializes unace
69 buf_rd
=malloc(size_rdb
* sizeof(ULONG
)); // Allocate buffers: increase
70 buf
=malloc(size_buf
); // sizes when possible to speed
71 buf_wr
=malloc(size_wrb
); // up the program
72 readbuf
=malloc(size_headrdb
);
80 make_crctable(); // initialize CRC table
81 dcpr_init(); // initialize decompression
83 set_handler(); // ctrl+break etc.
88 if (buf_rd
) free(buf_rd
);
90 if (buf_wr
) free(buf_wr
);
91 if (readbuf
) free(readbuf
);
92 if (dcpr_text
) free(dcpr_text
);
95 INT
read_header(INT print_err
) // reads any header from archive
103 acelseek(skipsize
, SEEK_CUR
); // skip ADDSIZE block
105 if (aceread(&head
, 4)<4)
106 return (0); // read CRC and header size
108 #ifdef HI_LO_BYTE_ORDER
109 WORDswap(&head
.HEAD_CRC
);
110 WORDswap(&head
.HEAD_SIZE
);
112 // read size_headrdb bytes into
113 head_size
= head
.HEAD_SIZE
; // header structure
114 rd
= (head_size
> size_headrdb
) ? size_headrdb
: head_size
;
115 if (aceread(readbuf
, rd
) < rd
)
118 crc
= getcrc(CRC_MASK
, readbuf
, rd
);
120 while (head_size
) // skip rest of header
122 rd
= (head_size
> size_buf
) ? size_buf
: head_size
;
123 if (aceread(buf
, rd
) < rd
)
126 crc
= getcrc(crc
, (UCHAR
*)buf
, rd
);
129 head
.HEAD_TYPE
=*tp
++; // generic buffer to head conversion
130 head
.HEAD_FLAGS
=BUFP2WORD(tp
);
132 if (head
.HEAD_FLAGS
& ACE_ADDSIZE
)
133 skipsize
= head
.ADDSIZE
= BUF2LONG(tp
); // get ADDSIZE
138 if (!(crc_ok
= head
.HEAD_CRC
== (crc
& 0xffff)) && print_err
)
139 pipeit("\nError: archive is broken\n");
141 switch (head
.HEAD_TYPE
) // specific buffer to head conversion
144 memcpy(mhead
.ACESIGN
, tp
, acesign_len
); tp
+=acesign_len
;
149 mhead
.TIME_CR
=BUFP2LONG(tp
);
150 mhead
.RES1
=BUFP2WORD(tp
);
151 mhead
.RES2
=BUFP2WORD(tp
);
152 mhead
.RES
=BUFP2LONG(tp
);
154 memcpy(mhead
.AV
, tp
, rd
-(USHORT
)(tp
-readbuf
));
157 fhead
.PSIZE
=BUFP2LONG(tp
);
158 fhead
.SIZE
=BUFP2LONG(tp
);
159 fhead
.FTIME
=BUFP2LONG(tp
);
160 fhead
.ATTR
=BUFP2LONG(tp
);
161 fhead
.CRC32
=BUFP2LONG(tp
);
162 fhead
.TECH
.TYPE
=*tp
++;
163 fhead
.TECH
.QUAL
=*tp
++;
164 fhead
.TECH
.PARM
=BUFP2WORD(tp
);
165 fhead
.RESERVED
=BUFP2WORD(tp
);
166 fhead
.FNAME_SIZE
=BUFP2WORD(tp
);
167 memcpy(fhead
.FNAME
, tp
, rd
-(USHORT
)(tp
-readbuf
));
169 // default: (REC_BLK and future things):
170 // do nothing 'cause isn't needed for extraction
175 // maximum SFX module size
176 #define max_sfx_size 65536 // (needed by read_arc_head)
178 INT
read_arc_head(void) // searches for the archive header and reads it
190 memset(buf
, 0, size_buf
);
192 while (acetell(archan
)<acesize() && fpos
< max_sfx_size
)
195 fpos
+= aceread(&buf
[buf_pos
], size_buf
- buf_pos
);
197 for (i
= 0; i
< size_buf
; i
++) // look for the acesign
199 if (!memcmp(acesign
, &buf
[i
], acesign_len
))
201 // seek to the probable begin
203 arc_head_pos
= old_fpos
+ i
- buf_pos
- bytes_before_acesign
;
204 acelseek(arc_head_pos
, SEEK_SET
);
205 if (read_header(0)) // try to read archive header
207 flags
= mhead
.HEAD_FLAGS
;
208 adat
.sol
= (flags
& ACE_SOLID
) > 0;
209 adat
.vol
= (flags
& ACE_MULT_VOL
) > 0;
210 adat
.vol_num
= mhead
.VOL_NUM
;
211 adat
.time_cr
= mhead
.TIME_CR
;
216 // was no archive header,
218 acelseek(fpos
, SEEK_SET
);
219 memcpy(buf
, &buf
[size_buf
- 512], 512);
220 buf_pos
= 512; // keep 512 old bytes
225 INT
open_archive(INT print_err
) // opens archive (or volume)
229 #if defined(__OS2_) || defined(__EMX__) || defined(WIN32)
230 archan
= aceopen(aname
, O_RDONLY
| O_BINARY
); // open file
232 archan
= aceopen(aname
, O_RDONLY
); // open file
234 #if !defined(__EMX__) && !defined(__OS2__)
235 farchan
= fdopen(archan
, "rb");
240 error("\nError opening file %s", aname
);
243 if (!read_arc_head()) // read archive header
245 error("Invalid embedded archive file.");
246 #if !defined(__EMX__) && !defined(__OS2__)
253 pipeit("\nProcessing archive: %s\n\n", aname
);
254 if (head
.HEAD_FLAGS
& ACE_AV
)
256 pipeit("Authenticity Verification:"); // print the AV
257 sprintf(av_str
, "\ncreated on %d.%d.%d by ",
258 ts_day(adat
.time_cr
), ts_month(adat
.time_cr
), ts_year(adat
.time_cr
));
260 strncpy(av_str
, (CHAR
*)mhead
.AV
, mhead
.AV_SIZE
);
261 av_str
[mhead
.AV_SIZE
] = 0;
262 pipeit("%s\n\n", av_str
);
264 comment_out("Main comment:"); // print main comment
268 void get_next_volname(void) // get file name of next volume
273 if ((cp
= (CHAR
*) strrchr(aname
, '.')) == NULL
|| !*(cp
+ 1))
278 num
= (*(cp
+ 1) - '0') * 10 + *(cp
+ 2) - '0';
281 if (in(*cp
, '0', '9'))
282 num
+= (*cp
- '0') * 100;
289 *cp
= num
/ 100 + '0';
290 *(cp
+ 1) = (num
/ 10) % 10 + '0';
291 *(cp
+ 2) = num
% 10 + '0';
294 INT
proc_vol(void) // opens volume
299 if (!fileexists(aname
) || !f_allvol_pr
)
303 sprintf(s
, "Ready to process %s?", aname
);
304 #if defined(__MINGW32__)
309 i
= confirm(s
); // ask whether ready or not
310 f_allvol_pr
= (i
== 1); // "Always" --> process all volumes
317 while (!fileexists(aname
));
320 if (!open_archive(1)) // open volume
322 pipeit("\nError while opening archive. File not found or archive broken.\n");
330 INT
proc_next_vol(void) // opens next volume to process
332 #if !defined(__EMX__) && !defined(__OS2__)
335 aceclose(archan
); // close handle
336 get_next_volname(); // get file name of next volume
338 if (!proc_vol()) // try to open volume, read archive header
340 if (!read_header(1)) // read 2nd header
348 INT
read_adds_blk(CHAR
* buffer
, INT len
) // reads part of ADD_SIZE block
355 char *cbuffer
=buffer
;
357 if (head
.HEAD_TYPE
== FILE_BLK
&& (head
.HEAD_FLAGS
& ACE_PASSW
))
358 len
= crypt_len(len
);
360 while (!f_err
&& len
&& skipsize
)
362 i
= (skipsize
> len
) ? len
: skipsize
;
365 /* How do I test failure when compiling -mno-cygwin? */
366 #if !defined(__MINGW32__)
369 rd
+= aceread(buffer
, i
);
370 #if !defined(__MINGW32__)
373 error("\nRead error\n");
381 if (!skipsize
) // if block is continued on next volume
382 if (head
.HEAD_FLAGS
& ACE_SP_AFTER
&& !proc_next_vol())
386 if (head
.HEAD_TYPE
== FILE_BLK
&& (head
.HEAD_FLAGS
& ACE_PASSW
))
387 decrypt(cbuffer
, rd
);
390 return (rd
> l
? l
: rd
);
393 void crc_print(void) // checks CRC, prints message
395 INT crc_not_ok
= rd_crc
!= fhead
.CRC32
; /* check CRC of file */
397 if(crc_not_ok
&& installstate
!= ABORTED
)
398 error("CRC error reading archive!");
401 void analyze_file(void) // analyzes one file (for solid archives)
403 pipeit("\n Analyzing");
405 while (!cancel() && (dcpr_adds_blk(buf_wr
, size_wrb
))) // decompress only
410 void extract_file(void) // extracts one file
414 pipeit("\n Extracting");
415 flush
; // decompress block
416 while (!cancel() && (rd
= dcpr_adds_blk(buf_wr
, size_wrb
)))
418 if (write(wrhan
, buf_wr
, rd
) != rd
) // write block
420 error("\nWrite error\n");
428 /* extracts or tests all files of the archive
430 void extract_files(int nopath
, int test
, char *getfilename
)
434 extern unsigned current_file
;
435 extern char installdir2
[];
437 while (!cancel() && read_header(1))
439 if (head
.HEAD_TYPE
== FILE_BLK
)
441 if(installstate
== ABORTED
)
444 if(installstate
== INSTALLING
)
447 comment_out("File comment:"); // show file comment
448 ace_fname(file
, &head
, nopath
); // get file name
450 /* We allow expansion of "userdir" to the selected directory by the user */
451 tmpfile
= replacestr(file
, "USERDIR", installdir2
);
452 strcpy(file
, tmpfile
);
455 if(!getfilename
|| (getfilename
&& stricmp(getfilename
, file
) == 0))
457 pipeit("\n%s", file
);
459 dcpr_init_file(); // initialize decompression of file
463 (wrhan
= create_dest_file(file
, (INT
) fhead
.ATTR
))<0)
465 if (test
|| adat
.sol
)
466 analyze_file(); // analyze file
470 extract_file(); // extract it
471 #ifdef DOS // set file time
472 _dos_setftime(wrhan
, (USHORT
) (fhead
.FTIME
>> 16), (USHORT
) fhead
.FTIME
);
475 #if defined(__OS2__) || defined(__EMX__)
477 FILESTATUS3 fileinfo
;
479 DosQueryPathInfo(file
, FIL_STANDARD
, &fileinfo
, sizeof(FILESTATUS3
));
480 *((USHORT
*)&fileinfo
.fdateCreation
) = (USHORT
)(fhead
.FTIME
>> 16);
481 *((USHORT
*)&fileinfo
.ftimeCreation
) = (USHORT
)fhead
.FTIME
;
482 *((USHORT
*)&fileinfo
.fdateLastAccess
) = (USHORT
)(fhead
.FTIME
>> 16);
483 *((USHORT
*)&fileinfo
.ftimeLastAccess
) = (USHORT
)fhead
.FTIME
;
484 *((USHORT
*)&fileinfo
.fdateLastWrite
) = (USHORT
)(fhead
.FTIME
>> 16);
485 *((USHORT
*)&fileinfo
.ftimeLastWrite
) = (USHORT
)fhead
.FTIME
;
486 DosSetPathInfo(file
, FIL_STANDARD
, (PVOID
)&fileinfo
, sizeof(FILESTATUS3
), 0);
489 #ifdef DOS // set file attributes
490 _dos_setfileattr(file
, (UINT
) fhead
.ATTR
);
493 { // set file date and time
495 char Date
[9], Time
[9];
496 ULONG tstamp
=fhead
.FTIME
;
498 sprintf(Date
, "%02d-%02d-%02d", ts_year(tstamp
)-1900, ts_month(tstamp
), ts_day(tstamp
));
499 sprintf(Time
, "%02d:%02d:%02d", ts_hour(tstamp
), ts_min(tstamp
), ts_sec(tstamp
));
501 dt
.dat_Format
= FORMAT_INT
;
503 dt
.dat_StrDate
= Date
;
504 dt
.dat_StrTime
= Time
;
507 SetFileDate(file
, &dt
.dat_Stamp
);
519 unsigned percentage(ULONG p
, ULONG d
)
521 return (unsigned)( d
? (d
/2+p
*100)/d
: 100 );
524 int installer_unpack(CHAR
* filename
, int operation
) // processes the archive
526 init_unace(); // initialize unace
527 strcpy(aname
, "installer"); // get archive name
532 if (open_archive(1)) // open archive to process
535 pipeit("\nFirst volume of archive required!\n");
539 extract_files(0, 0, filename
);
541 #if !defined(__EMX__) && !defined(__OS2__)
547 pipeit("\nError occurred\n");
549 pipeit("Critical error on drive %c\n", f_criterr
);