[util] Avoid calling fclose(NULL) in zbin.c
[people/dverkamp/gpxe.git] / src / util / zbin.c
1 #include <stdio.h>
2 #include <sys/stat.h>
3
4 #define ENCODE
5 #define VERBOSE
6 #include "nrv2b.c"
7 FILE *infile, *outfile;
8
9 struct input_file {
10         void *buf;
11         size_t len;
12 };
13
14 struct output_file {
15         void *buf;
16         size_t len;
17         size_t max_len;
18 };
19
20 struct zinfo_common {
21         char type[4];
22         char pad[12];
23 };
24
25 struct zinfo_copy {
26         char type[4];
27         uint32_t offset;
28         uint32_t len;
29         uint32_t align;
30 };
31
32 struct zinfo_pack {
33         char type[4];
34         uint32_t offset;
35         uint32_t len;
36         uint32_t align;
37 };
38
39 struct zinfo_subtract {
40         char type[4];
41         uint32_t offset;
42         uint32_t divisor;
43         uint32_t pad;
44 };
45
46 union zinfo_record {
47         struct zinfo_common common;
48         struct zinfo_copy copy;
49         struct zinfo_pack pack;
50         struct zinfo_subtract subtract;
51 };
52
53 struct zinfo_file {
54         union zinfo_record *zinfo;
55         unsigned int num_entries;
56 };
57
58 static int read_file ( const char *filename, void **buf, size_t *len ) {
59         FILE *file;
60         struct stat stat;
61
62         file = fopen ( filename, "r" );
63         if ( ! file ) {
64                 fprintf ( stderr, "Could not open %s: %s\n", filename,
65                           strerror ( errno ) );
66                 goto err;
67         }
68
69         if ( fstat ( fileno ( file ), &stat ) < 0 ) {
70                 fprintf ( stderr, "Could not stat %s: %s\n", filename,
71                           strerror ( errno ) );
72                 goto err;
73         }
74
75         *len = stat.st_size;
76         *buf = malloc ( *len );
77         if ( ! *buf ) {
78                 fprintf ( stderr, "Could not malloc() %d bytes for %s: %s\n",
79                           *len, filename, strerror ( errno ) );
80                 goto err;
81         }
82
83         if ( fread ( *buf, 1, *len, file ) != *len ) {
84                 fprintf ( stderr, "Could not read %d bytes from %s: %s\n",
85                           *len, filename, strerror ( errno ) );
86                 goto err;
87         }
88
89         fclose ( file );
90         return 0;
91
92  err:
93         if ( file )
94                 fclose ( file );
95         return -1;
96 }
97
98 static int read_input_file ( const char *filename,
99                              struct input_file *input ) {
100         return read_file ( filename, &input->buf, &input->len );
101 }
102
103 static int read_zinfo_file ( const char *filename,
104                              struct zinfo_file *zinfo ) {
105         void *buf;
106         size_t len;
107
108         if ( read_file ( filename, &buf, &len ) < 0 )
109                 return -1;
110
111         if ( ( len % sizeof ( *(zinfo->zinfo) ) ) != 0 ) {
112                 fprintf ( stderr, ".zinfo file %s has invalid length %d\n",
113                           filename, len );
114                 return -1;
115         }
116
117         zinfo->zinfo = buf;
118         zinfo->num_entries = ( len / sizeof ( *(zinfo->zinfo) ) );
119         return 0;
120 }
121
122 static int alloc_output_file ( size_t max_len, struct output_file *output ) {
123         output->len = 0;
124         output->max_len = ( max_len );
125         output->buf = malloc ( max_len );
126         if ( ! output->buf ) {
127                 fprintf ( stderr, "Could not allocate %d bytes for output\n",
128                           max_len );
129                 return -1;
130         }
131         memset ( output->buf, 0xff, sizeof ( output->buf ) );
132         return 0;
133 }
134
135 static int process_zinfo_copy ( struct input_file *input,
136                                 struct output_file *output,
137                                 union zinfo_record *zinfo ) {
138         struct zinfo_copy *copy = &zinfo->copy;
139         size_t offset = copy->offset;
140         size_t len = copy->len;
141         unsigned int align = copy->align;
142
143         if ( ( offset + len ) > input->len ) {
144                 fprintf ( stderr, "Input buffer overrun on copy\n" );
145                 return -1;
146         }
147
148         output->len = ( ( output->len + align - 1 ) & ~( align - 1 ) );
149         if ( ( output->len + len ) > output->max_len ) {
150                 fprintf ( stderr, "Output buffer overrun on copy\n" );
151                 return -1;
152         }
153
154         memcpy ( ( output->buf + output->len ),
155                  ( input->buf + offset ), len );
156         output->len += len;
157         return 0;
158 }
159
160 static int process_zinfo_pack ( struct input_file *input,
161                                 struct output_file *output,
162                                 union zinfo_record *zinfo ) {
163         struct zinfo_pack *pack = &zinfo->pack;
164         size_t offset = pack->offset;
165         size_t len = pack->len;
166         unsigned int align = pack->align;
167         unsigned long packed_len;
168
169         if ( ( offset + len ) > input->len ) {
170                 fprintf ( stderr, "Input buffer overrun on pack\n" );
171                 return -1;
172         }
173
174         output->len = ( ( output->len + align - 1 ) & ~( align - 1 ) );
175         if ( output->len > output->max_len ) {
176                 fprintf ( stderr, "Output buffer overrun on pack\n" );
177                 return -1;
178         }
179
180         if ( ucl_nrv2b_99_compress ( ( input->buf + offset ), len,
181                                      ( output->buf + output->len ),
182                                      &packed_len, 0 ) != UCL_E_OK ) {
183                 fprintf ( stderr, "Compression failure\n" );
184                 return -1;
185         }
186
187         output->len += packed_len;
188         if ( output->len > output->max_len ) {
189                 fprintf ( stderr, "Output buffer overrun on pack\n" );
190                 return -1;
191         }
192
193         return 0;
194 }
195
196 static int process_zinfo_subtract ( struct input_file *input,
197                                     struct output_file *output,
198                                     struct zinfo_subtract *subtract,
199                                     size_t datasize ) {
200         size_t offset = subtract->offset;
201         void *target;
202         long delta;
203
204         if ( ( offset + datasize ) > output->len ) {
205                 fprintf ( stderr, "Subtract at %#zx outside output buffer\n",
206                           offset );
207                 return -1;
208         }
209
210         target = ( output->buf + offset );
211         delta = ( ( output->len / subtract->divisor ) -
212                   ( input->len / subtract->divisor ) );
213
214         switch ( datasize ) {
215         case 1: {
216                 uint8_t *byte = target;
217                 *byte += delta;
218                 break; }
219         case 2: {
220                 uint16_t *word = target;
221                 *word += delta;
222                 break; }
223         case 4: {
224                 uint32_t *dword = target;
225                 *dword += delta;
226                 break; }
227         default:
228                 fprintf ( stderr, "Unsupported subtract datasize %d\n",
229                           datasize );
230                 return -1;
231         }
232         return 0;
233 }
234
235 static int process_zinfo_subb ( struct input_file *input,
236                                 struct output_file *output,
237                                 union zinfo_record *zinfo ) {
238         return process_zinfo_subtract ( input, output, &zinfo->subtract, 1 );
239 }
240
241 static int process_zinfo_subw ( struct input_file *input,
242                                 struct output_file *output,
243                                 union zinfo_record *zinfo ) {
244         return process_zinfo_subtract ( input, output, &zinfo->subtract, 2 );
245 }
246
247 static int process_zinfo_subl ( struct input_file *input,
248                                 struct output_file *output,
249                                 union zinfo_record *zinfo ) {
250         return process_zinfo_subtract ( input, output, &zinfo->subtract, 4 );
251 }
252
253 struct zinfo_processor {
254         char *type;
255         int ( * process ) ( struct input_file *input,
256                             struct output_file *output,
257                             union zinfo_record *zinfo );
258 };
259
260 static struct zinfo_processor zinfo_processors[] = {
261         { "COPY", process_zinfo_copy },
262         { "PACK", process_zinfo_pack },
263         { "SUBB", process_zinfo_subb },
264         { "SUBW", process_zinfo_subw },
265         { "SUBL", process_zinfo_subl },
266 };
267
268 static int process_zinfo ( struct input_file *input,
269                            struct output_file *output,
270                            union zinfo_record *zinfo ) {
271         struct zinfo_common *common = &zinfo->common;
272         struct zinfo_processor *processor;
273         char type[ sizeof ( common->type ) + 1 ] = "";
274         unsigned int i;
275
276         strncat ( type, common->type, sizeof ( type ) - 1 );
277         for ( i = 0 ; i < ( sizeof ( zinfo_processors ) /
278                             sizeof ( zinfo_processors[0] ) ) ; i++ ) {
279                 processor = &zinfo_processors[i];
280                 if ( strcmp ( processor->type, type ) == 0 )
281                         return processor->process ( input, output, zinfo );
282         }
283
284         fprintf ( stderr, "Unknown zinfo record type \"%s\"\n", &type[0] );
285         return -1;
286 }
287
288 static int write_output_file ( struct output_file *output ) {
289         if ( fwrite ( output->buf, 1, output->len, stdout ) != output->len ) {
290                 fprintf ( stderr, "Could not write %d bytes of output: %s\n",
291                           output->len, strerror ( errno ) );
292                 return -1;
293         }
294         return 0;
295 }
296
297 int main ( int argc, char **argv ) {
298         struct input_file input;
299         struct output_file output;
300         struct zinfo_file zinfo;
301         unsigned int i;
302
303         if ( argc != 3 ) {
304                 fprintf ( stderr, "Syntax: %s file.bin file.zinfo "
305                           "> file.zbin\n", argv[0] );
306                 exit ( 1 );
307         }
308
309         if ( read_input_file ( argv[1], &input ) < 0 )
310                 exit ( 1 );
311         if ( read_zinfo_file ( argv[2], &zinfo ) < 0 )
312                 exit ( 1 );
313         if ( alloc_output_file ( ( input.len * 4 ), &output ) < 0 )
314                 exit ( 1 );
315
316         for ( i = 0 ; i < zinfo.num_entries ; i++ ) {
317                 if ( process_zinfo ( &input, &output,
318                                      &zinfo.zinfo[i] ) < 0 )
319                         exit ( 1 );
320         }
321
322         if ( write_output_file ( &output ) < 0 )
323                 exit ( 1 );
324
325         return 0;
326 }