File: makesfx.c

package info (click to toggle)
unzip 5.40-1
  • links: PTS
  • area: non-free
  • in suites: potato
  • size: 4,120 kB
  • ctags: 5,900
  • sloc: ansic: 40,977; cpp: 3,778; makefile: 1,384; asm: 1,228; sh: 133
file content (176 lines) | stat: -rw-r--r-- 5,673 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
/* MakeSFX: join UnZipSFX and a .zip archive into a single self-extracting   */
/* Amiga program.  On most systems simple concatenation does the job but for */
/* the Amiga a special tool is needed.  By Paul Kienitz, no rights reserved. */
/* This program is written portably, so if anyone really wants to they can   */
/* produce Amiga self-extracting programs on a non-Amiga.  We are careful    */
/* not to mix Motorola-format longwords read from files with native long     */
/* integers.  Not necessarily limited to use with only the Zip format --     */
/* just combine any archive with any self-extractor program that is capable  */
/* of reading a HUNK_DEBUG section at the end as an archive.                 */

#include <stat.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#ifdef __SASC
#  include <proto/dos.h>
#  ifdef DEBUG
#    include <sprof.h>
#  endif
#endif /* __SASC */
#ifdef AZTEC_C
#  include <dos/dos.h>
#  include <clib/dos_protos.h>
#endif /* AZTEC_C */

typedef unsigned long ulg;
typedef unsigned char uch;
typedef unsigned short bool;
#define false 0
#define true  1

/* the following are extracted from Commodore include file dos/doshunks.h: */
#define HUNK_NAME       1000L
#define HUNK_CODE       1001L
#define HUNK_DATA       1002L
#define HUNK_BSS        1003L
#define HUNK_RELOC32    1004L
#define HUNK_SYMBOL     1008L
#define HUNK_DEBUG      1009L
#define HUNK_END        1010L
#define HUNK_HEADER     1011L
#define HUNK_OVERLAY    1013L
#define HUNK_BREAK      1014L

/* Convert a big-endian (Motorola) sequence of four bytes to a longword: */
#define CHARS2LONG(b)   (((ulg)(b)[0] << 24) | ((ulg)(b)[1] << 16) | \
                         ((ulg)(b)[2] << 8) | ((ulg)(b)[3]))
/* b must be (uch *) in each of these.  Now the reverse: */
#define LONG2CHARS(b,l) ((b)[0] = (uch)((l) >> 24), (b)[1] = (uch)((l) >> 16),\
                         (b)[2] = (uch)((l) >> 8), (b)[3] = (uch)(l))

#define COPYBUFFER      16384

ulg totalwritten = 0;


bool CopyData(FILE *out, FILE *inn, ulg archivesize,
              char *outname, char *inname)
{
    static uch buf[COPYBUFFER];
    ulg written;
    size_t chunk;

    if (archivesize) {
        LONG2CHARS(buf, HUNK_DEBUG);
        written = (archivesize + 3) / 4;
        LONG2CHARS(buf + 4, written);
        if (fwrite(buf, 1, 8, out) < 8) {
            printf("Error writing in-between data to %s\n", outname);
            return false;
        }
        totalwritten += 8;
    }
    written = 0;
    do {
        chunk = fread(buf, 1, COPYBUFFER, inn);
        if (ferror(inn)) {
            printf("Error reading data from %s\n", inname);
            return false;
        }
        if (!archivesize && !written) {   /* true only for first block read */
            if (CHARS2LONG(buf) != HUNK_HEADER) {
                printf("%s is not an Amiga executable.\n", inname);
                return false;
            }
        }
        if (fwrite(buf, 1, chunk, out) < chunk) {
            printf("Error writing %s to %s\n", archivesize ? "archive data" :
                                               "self-extractor code", outname);
            return false;
        }
        written += chunk;
        totalwritten += chunk;
    } while (!feof(inn));
    if (archivesize) {
        if (written != archivesize) {
            printf("Wrong number of bytes copied from archive %s\n", outname);
            return false;
        }
        LONG2CHARS(buf, 0);
        chunk = 3 - (written + 3) % 4;
        LONG2CHARS(buf + chunk, HUNK_END);
        chunk += 4;
        if (fwrite(buf, 1, chunk, out) < chunk) {
            printf("Error writing end-marker data to %s\n", outname);
            return false;
        }
        totalwritten += chunk;
    }
    return true;
}


void main(int argc, char **argv)
{
    FILE *out, *arch, *tool;
    char *toolname = argv[3];
    struct stat ss;
    int ret;
    ulg archivesize;

    if (argc < 3 || argc > 4) {
        printf("Usage: %s <result-file> <zip-archive> [<self-extractor-"
               "program>]\nThe third arg defaults to \"UnZipSFX\" in the"
               " current dir or C:.\n", argv[0]);
        exit(20);
    }
    if (!(arch = fopen(argv[2], "rb"))) {
        printf("Could not find archive file %s\n", argv[2]);
        exit(10);
    }
    if (stat(argv[2], &ss) || !(archivesize = ss.st_size)) {
        fclose(arch);
        printf("Could not check size of archive %s, or file is empty.\n",
               argv[2]);
        exit(10);
    }
    if (argc < 4)
        toolname = "UnZipSFX";
    if (!(tool = fopen(toolname, "rb"))) {
        BPTR lk = Lock("C:", ACCESS_READ);
        BPTR ocd = lk ? CurrentDir(lk) : 0;
        if (!(tool = fopen(toolname, "rb"))) {
            fclose(arch);
            printf("Could not find self-extractor program %s\n", toolname);
            if (lk)
                UnLock(CurrentDir(ocd));
            exit(10);
        }
        if (lk)
            UnLock(CurrentDir(ocd));
    }
    if (!(out = fopen(argv[1], "wb"))) {
        fclose(arch);
        fclose(tool);
        printf("Could not create output file %s\n", argv[1]);
        exit(10);
    }
    ret = CopyData(out, tool, 0, argv[1], toolname)
          && CopyData(out, arch, archivesize, argv[1], argv[2]) ? 0 : 10;
    fclose(out);
    fclose(arch);
    fclose(tool);
    if (ret) {
        printf("Deleting %s\n", argv[1]);
        remove(argv[1]);
    } else
        printf("%s successfully written, size %lu bytes.\n",
                argv[1], totalwritten);
    exit(ret);
}


#if (defined(AZTEC_C) && defined(MCH_AMIGA))
void _wb_parse(void) { }        /* avoid unneeded infrastructure */
#endif