1 /*
2   Copyright (c) 1990-2000 Info-ZIP.  All rights reserved.
3 
4   See the accompanying file LICENSE, version 2000-Apr-09 or later
5   (the contents of which are also included in unzip.h) for terms of use.
6   If, for some reason, all these files are missing, the Info-ZIP license
7   also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
8 */
9 /* MakeSFX: join UnZipSFX and a .zip archive into a single self-extracting   */
10 /* Amiga program.  On most systems simple concatenation does the job but for */
11 /* the Amiga a special tool is needed.  By Paul Kienitz, no rights reserved. */
12 /* This program is written portably, so if anyone really wants to they can   */
13 /* produce Amiga self-extracting programs on a non-Amiga.  We are careful    */
14 /* not to mix Motorola-format longwords read from files with native long     */
15 /* integers.  Not necessarily limited to use with only the Zip format --     */
16 /* just combine any archive with any self-extractor program that is capable  */
17 /* of reading a HUNK_DEBUG section at the end as an archive.                 */
18 
19 #include <stat.h>
20 #include <string.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #ifdef __SASC
24 #  include <proto/dos.h>
25 #  ifdef DEBUG
26 #    include <sprof.h>
27 #  endif
28 #endif /* __SASC */
29 #ifdef AZTEC_C
30 #  include <dos/dos.h>
31 #  include <clib/dos_protos.h>
32 #endif /* AZTEC_C */
33 
34 typedef unsigned long ulg;
35 typedef unsigned char uch;
36 typedef unsigned short bool;
37 #define false 0
38 #define true  1
39 
40 /* the following are extracted from Commodore include file dos/doshunks.h: */
41 #define HUNK_NAME       1000L
42 #define HUNK_CODE       1001L
43 #define HUNK_DATA       1002L
44 #define HUNK_BSS        1003L
45 #define HUNK_RELOC32    1004L
46 #define HUNK_SYMBOL     1008L
47 #define HUNK_DEBUG      1009L
48 #define HUNK_END        1010L
49 #define HUNK_HEADER     1011L
50 #define HUNK_OVERLAY    1013L
51 #define HUNK_BREAK      1014L
52 
53 /* Convert a big-endian (Motorola) sequence of four bytes to a longword: */
54 #define CHARS2LONG(b)   (((ulg)(b)[0] << 24) | ((ulg)(b)[1] << 16) | \
55                          ((ulg)(b)[2] << 8) | ((ulg)(b)[3]))
56 /* b must be (uch *) in each of these.  Now the reverse: */
57 #define LONG2CHARS(b,l) ((b)[0] = (uch)((l) >> 24), (b)[1] = (uch)((l) >> 16),\
58                          (b)[2] = (uch)((l) >> 8), (b)[3] = (uch)(l))
59 
60 #define COPYBUFFER      16384
61 
62 ulg totalwritten = 0;
63 
64 
CopyData(FILE * out,FILE * inn,ulg archivesize,char * outname,char * inname)65 bool CopyData(FILE *out, FILE *inn, ulg archivesize,
66               char *outname, char *inname)
67 {
68     static uch buf[COPYBUFFER];
69     ulg written;
70     size_t chunk;
71 
72     if (archivesize) {
73         LONG2CHARS(buf, HUNK_DEBUG);
74         written = (archivesize + 3) / 4;
75         LONG2CHARS(buf + 4, written);
76         if (fwrite(buf, 1, 8, out) < 8) {
77             printf("Error writing in-between data to %s\n", outname);
78             return false;
79         }
80         totalwritten += 8;
81     }
82     written = 0;
83     do {
84         chunk = fread(buf, 1, COPYBUFFER, inn);
85         if (ferror(inn)) {
86             printf("Error reading data from %s\n", inname);
87             return false;
88         }
89         if (!archivesize && !written) {   /* true only for first block read */
90             if (CHARS2LONG(buf) != HUNK_HEADER) {
91                 printf("%s is not an Amiga executable.\n", inname);
92                 return false;
93             }
94         }
95         if (fwrite(buf, 1, chunk, out) < chunk) {
96             printf("Error writing %s to %s\n", archivesize ? "archive data" :
97                                                "self-extractor code", outname);
98             return false;
99         }
100         written += chunk;
101         totalwritten += chunk;
102     } while (!feof(inn));
103     if (archivesize) {
104         if (written != archivesize) {
105             printf("Wrong number of bytes copied from archive %s\n", outname);
106             return false;
107         }
108         LONG2CHARS(buf, 0);
109         chunk = 3 - (written + 3) % 4;
110         LONG2CHARS(buf + chunk, HUNK_END);
111         chunk += 4;
112         if (fwrite(buf, 1, chunk, out) < chunk) {
113             printf("Error writing end-marker data to %s\n", outname);
114             return false;
115         }
116         totalwritten += chunk;
117     }
118     return true;
119 }
120 
121 
main(int argc,char ** argv)122 void main(int argc, char **argv)
123 {
124     FILE *out, *arch, *tool;
125     char *toolname = argv[3];
126     struct stat ss;
127     int ret;
128     ulg archivesize;
129 
130     if (argc < 3 || argc > 4) {
131         printf("Usage: %s <result-file> <zip-archive> [<self-extractor-"
132                "program>]\nThe third arg defaults to \"UnZipSFX\" in the"
133                " current dir or C:.\n", argv[0]);
134         exit(20);
135     }
136     if (!(arch = fopen(argv[2], "rb"))) {
137         printf("Could not find archive file %s\n", argv[2]);
138         exit(10);
139     }
140     if (stat(argv[2], &ss) || !(archivesize = ss.st_size)) {
141         fclose(arch);
142         printf("Could not check size of archive %s, or file is empty.\n",
143                argv[2]);
144         exit(10);
145     }
146     if (argc < 4)
147         toolname = "UnZipSFX";
148     if (!(tool = fopen(toolname, "rb"))) {
149         BPTR lk = Lock("C:", ACCESS_READ);
150         BPTR ocd = lk ? CurrentDir(lk) : 0;
151         if (!(tool = fopen(toolname, "rb"))) {
152             fclose(arch);
153             printf("Could not find self-extractor program %s\n", toolname);
154             if (lk)
155                 UnLock(CurrentDir(ocd));
156             exit(10);
157         }
158         if (lk)
159             UnLock(CurrentDir(ocd));
160     }
161     if (!(out = fopen(argv[1], "wb"))) {
162         fclose(arch);
163         fclose(tool);
164         printf("Could not create output file %s\n", argv[1]);
165         exit(10);
166     }
167     ret = CopyData(out, tool, 0, argv[1], toolname)
168           && CopyData(out, arch, archivesize, argv[1], argv[2]) ? 0 : 10;
169     fclose(out);
170     fclose(arch);
171     fclose(tool);
172     if (ret) {
173         printf("Deleting %s\n", argv[1]);
174         remove(argv[1]);
175     } else
176         printf("%s successfully written, size %lu bytes.\n",
177                 argv[1], totalwritten);
178     exit(ret);
179 }
180 
181 
182 #if (defined(AZTEC_C) && defined(MCH_AMIGA))
_wb_parse(void)183 void _wb_parse(void) { }        /* avoid unneeded infrastructure */
184 #endif
185