[prefix] Add .text16.early section
[people/meteger/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 #define DEBUG 0
10
11 struct input_file {
12         void *buf;
13         size_t len;
14 };
15
16 struct output_file {
17         void *buf;
18         size_t len;
19         size_t hdr_len;
20         size_t max_len;
21 };
22
23 struct zinfo_common {
24         char type[4];
25         char pad[12];
26 };
27
28 struct zinfo_copy {
29         char type[4];
30         uint32_t offset;
31         uint32_t len;
32         uint32_t align;
33 };
34
35 struct zinfo_pack {
36         char type[4];
37         uint32_t offset;
38         uint32_t len;
39         uint32_t align;
40 };
41
42 struct zinfo_payload {
43         char type[4];
44         uint32_t pad1;
45         uint32_t pad2;
46         uint32_t align;
47 };
48
49 struct zinfo_add {
50         char type[4];
51         uint32_t offset;
52         uint32_t divisor;
53         uint32_t pad;
54 };
55
56 union zinfo_record {
57         struct zinfo_common common;
58         struct zinfo_copy copy;
59         struct zinfo_pack pack;
60         struct zinfo_payload payload;
61         struct zinfo_add add;
62 };
63
64 struct zinfo_file {
65         union zinfo_record *zinfo;
66         unsigned int num_entries;
67 };
68
69 static unsigned long align ( unsigned long value, unsigned long align ) {
70         return ( ( value + align - 1 ) & ~( align - 1 ) );
71 }
72
73 static int read_file ( const char *filename, void **buf, size_t *len ) {
74         FILE *file;
75         struct stat stat;
76
77         file = fopen ( filename, "r" );
78         if ( ! file ) {
79                 fprintf ( stderr, "Could not open %s: %s\n", filename,
80                           strerror ( errno ) );
81                 goto err;
82         }
83
84         if ( fstat ( fileno ( file ), &stat ) < 0 ) {
85                 fprintf ( stderr, "Could not stat %s: %s\n", filename,
86                           strerror ( errno ) );
87                 goto err;
88         }
89
90         *len = stat.st_size;
91         *buf = malloc ( *len );
92         if ( ! *buf ) {
93                 fprintf ( stderr, "Could not malloc() %zd bytes for %s: %s\n",
94                           *len, filename, strerror ( errno ) );
95                 goto err;
96         }
97
98         if ( fread ( *buf, 1, *len, file ) != *len ) {
99                 fprintf ( stderr, "Could not read %zd bytes from %s: %s\n",
100                           *len, filename, strerror ( errno ) );
101                 goto err;
102         }
103
104         fclose ( file );
105         return 0;
106
107  err:
108         if ( file )
109                 fclose ( file );
110         return -1;
111 }
112
113 static int read_input_file ( const char *filename,
114                              struct input_file *input ) {
115         return read_file ( filename, &input->buf, &input->len );
116 }
117
118 static int read_zinfo_file ( const char *filename,
119                              struct zinfo_file *zinfo ) {
120         void *buf;
121         size_t len;
122
123         if ( read_file ( filename, &buf, &len ) < 0 )
124                 return -1;
125
126         if ( ( len % sizeof ( *(zinfo->zinfo) ) ) != 0 ) {
127                 fprintf ( stderr, ".zinfo file %s has invalid length %zd\n",
128                           filename, len );
129                 return -1;
130         }
131
132         zinfo->zinfo = buf;
133         zinfo->num_entries = ( len / sizeof ( *(zinfo->zinfo) ) );
134         return 0;
135 }
136
137 static int alloc_output_file ( size_t max_len, struct output_file *output ) {
138         output->len = 0;
139         output->max_len = ( max_len );
140         output->buf = malloc ( max_len );
141         if ( ! output->buf ) {
142                 fprintf ( stderr, "Could not allocate %zd bytes for output\n",
143                           max_len );
144                 return -1;
145         }
146         memset ( output->buf, 0xff, sizeof ( output->buf ) );
147         return 0;
148 }
149
150 static int process_zinfo_copy ( struct input_file *input,
151                                 struct output_file *output,
152                                 union zinfo_record *zinfo ) {
153         struct zinfo_copy *copy = &zinfo->copy;
154         size_t offset = copy->offset;
155         size_t len = copy->len;
156
157         if ( ( offset + len ) > input->len ) {
158                 fprintf ( stderr, "Input buffer overrun on copy\n" );
159                 return -1;
160         }
161
162         output->len = align ( output->len, copy->align );
163         if ( ( output->len + len ) > output->max_len ) {
164                 fprintf ( stderr, "Output buffer overrun on copy\n" );
165                 return -1;
166         }
167
168         if ( DEBUG ) {
169                 fprintf ( stderr, "COPY [%#zx,%#zx) to [%#zx,%#zx)\n",
170                           offset, ( offset + len ), output->len,
171                           ( output->len + len ) );
172         }
173
174         memcpy ( ( output->buf + output->len ),
175                  ( input->buf + offset ), len );
176         output->len += len;
177         return 0;
178 }
179
180 static int process_zinfo_pack ( struct input_file *input,
181                                 struct output_file *output,
182                                 union zinfo_record *zinfo ) {
183         struct zinfo_pack *pack = &zinfo->pack;
184         size_t offset = pack->offset;
185         size_t len = pack->len;
186         unsigned long packed_len;
187
188         if ( ( offset + len ) > input->len ) {
189                 fprintf ( stderr, "Input buffer overrun on pack\n" );
190                 return -1;
191         }
192
193         output->len = align ( output->len, pack->align );
194         if ( output->len > output->max_len ) {
195                 fprintf ( stderr, "Output buffer overrun on pack\n" );
196                 return -1;
197         }
198
199         if ( ucl_nrv2b_99_compress ( ( input->buf + offset ), len,
200                                      ( output->buf + output->len ),
201                                      &packed_len, 0 ) != UCL_E_OK ) {
202                 fprintf ( stderr, "Compression failure\n" );
203                 return -1;
204         }
205
206         if ( DEBUG ) {
207                 fprintf ( stderr, "PACK [%#zx,%#zx) to [%#zx,%#zx)\n",
208                           offset, ( offset + len ), output->len,
209                           ( size_t )( output->len + packed_len ) );
210         }
211
212         output->len += packed_len;
213         if ( output->len > output->max_len ) {
214                 fprintf ( stderr, "Output buffer overrun on pack\n" );
215                 return -1;
216         }
217
218         return 0;
219 }
220
221 static int process_zinfo_payl ( struct input_file *input,
222                                 struct output_file *output,
223                                 union zinfo_record *zinfo ) {
224         struct zinfo_payload *payload = &zinfo->payload;
225
226         output->len = align ( output->len, payload->align );
227         output->hdr_len = output->len;
228
229         if ( DEBUG ) {
230                 fprintf ( stderr, "PAYL at %#zx\n", output->hdr_len );
231         }
232 }
233
234 static int process_zinfo_add ( struct input_file *input,
235                                struct output_file *output,
236                                size_t len,
237                                struct zinfo_add *add,
238                                size_t datasize ) {
239         size_t offset = add->offset;
240         void *target;
241         signed long addend;
242         unsigned long size;
243         signed long val;
244         unsigned long mask;
245
246         if ( ( offset + datasize ) > output->len ) {
247                 fprintf ( stderr, "Add at %#zx outside output buffer\n",
248                           offset );
249                 return -1;
250         }
251
252         target = ( output->buf + offset );
253         size = ( align ( len, add->divisor ) / add->divisor );
254
255         switch ( datasize ) {
256         case 1:
257                 addend = *( ( int8_t * ) target );
258                 break;
259         case 2:
260                 addend = *( ( int16_t * ) target );
261                 break;
262         case 4:
263                 addend = *( ( int32_t * ) target );
264                 break;
265         default:
266                 fprintf ( stderr, "Unsupported add datasize %zd\n",
267                           datasize );
268                 return -1;
269         }
270
271         val = size + addend;
272
273         /* The result of 1UL << ( 8 * sizeof(unsigned long) ) is undefined */
274         mask = ( ( datasize < sizeof ( mask ) ) ?
275                  ( ( 1UL << ( 8 * datasize ) ) - 1 ) : ~0UL );
276
277         if ( val < 0 ) {
278                 fprintf ( stderr, "Add %s%#x+%#lx at %#zx %sflows field\n",
279                           ( ( addend < 0 ) ? "-" : "" ), abs ( addend ), size,
280                           offset, ( ( addend < 0 ) ? "under" : "over" ) );
281                 return -1;
282         }
283
284         if ( val & ~mask ) {
285                 fprintf ( stderr, "Add %s%#x+%#lx at %#zx overflows %zd-byte "
286                           "field (%d bytes too big)\n",
287                           ( ( addend < 0 ) ? "-" : "" ), abs ( addend ), size,
288                           offset, datasize,
289                           ( int )( ( val - mask - 1 ) * add->divisor ) );
290                 return -1;
291         }
292
293         switch ( datasize ) {
294         case 1:
295                 *( ( uint8_t * ) target ) = val;
296                 break;
297         case 2:
298                 *( ( uint16_t * ) target ) = val;
299                 break;
300         case 4:
301                 *( ( uint32_t * ) target ) = val;
302                 break;
303         }
304
305         if ( DEBUG ) {
306                 fprintf ( stderr, "ADDx [%#zx,%#zx) (%s%#x+(%#zx/%#x)) = "
307                           "%#lx\n", offset, ( offset + datasize ),
308                           ( ( addend < 0 ) ? "-" : "" ), abs ( addend ),
309                           len, add->divisor, val );
310         }
311
312         return 0;
313 }
314
315 static int process_zinfo_addb ( struct input_file *input,
316                                 struct output_file *output,
317                                 union zinfo_record *zinfo ) {
318         return process_zinfo_add ( input, output, output->len,
319                                    &zinfo->add, 1 );
320 }
321
322 static int process_zinfo_addw ( struct input_file *input,
323                                 struct output_file *output,
324                                 union zinfo_record *zinfo ) {
325         return process_zinfo_add ( input, output, output->len,
326                                    &zinfo->add, 2 );
327 }
328
329 static int process_zinfo_addl ( struct input_file *input,
330                                 struct output_file *output,
331                                 union zinfo_record *zinfo ) {
332         return process_zinfo_add ( input, output, output->len,
333                                    &zinfo->add, 4 );
334 }
335
336 static int process_zinfo_adhb ( struct input_file *input,
337                                 struct output_file *output,
338                                 union zinfo_record *zinfo ) {
339         return process_zinfo_add ( input, output, output->hdr_len,
340                                    &zinfo->add, 1 );
341 }
342
343 static int process_zinfo_adhw ( struct input_file *input,
344                                 struct output_file *output,
345                                 union zinfo_record *zinfo ) {
346         return process_zinfo_add ( input, output, output->hdr_len,
347                                    &zinfo->add, 2 );
348 }
349
350 static int process_zinfo_adhl ( struct input_file *input,
351                                 struct output_file *output,
352                                 union zinfo_record *zinfo ) {
353         return process_zinfo_add ( input, output, output->hdr_len,
354                                    &zinfo->add, 4 );
355 }
356
357 struct zinfo_processor {
358         char *type;
359         int ( * process ) ( struct input_file *input,
360                             struct output_file *output,
361                             union zinfo_record *zinfo );
362 };
363
364 static struct zinfo_processor zinfo_processors[] = {
365         { "COPY", process_zinfo_copy },
366         { "PACK", process_zinfo_pack },
367         { "PAYL", process_zinfo_payl },
368         { "ADDB", process_zinfo_addb },
369         { "ADDW", process_zinfo_addw },
370         { "ADDL", process_zinfo_addl },
371         { "ADHB", process_zinfo_adhb },
372         { "ADHW", process_zinfo_adhw },
373         { "ADHL", process_zinfo_adhl },
374 };
375
376 static int process_zinfo ( struct input_file *input,
377                            struct output_file *output,
378                            union zinfo_record *zinfo ) {
379         struct zinfo_common *common = &zinfo->common;
380         struct zinfo_processor *processor;
381         char type[ sizeof ( common->type ) + 1 ] = "";
382         unsigned int i;
383
384         strncat ( type, common->type, sizeof ( type ) - 1 );
385         for ( i = 0 ; i < ( sizeof ( zinfo_processors ) /
386                             sizeof ( zinfo_processors[0] ) ) ; i++ ) {
387                 processor = &zinfo_processors[i];
388                 if ( strcmp ( processor->type, type ) == 0 )
389                         return processor->process ( input, output, zinfo );
390         }
391
392         fprintf ( stderr, "Unknown zinfo record type \"%s\"\n", &type[0] );
393         return -1;
394 }
395
396 static int write_output_file ( struct output_file *output ) {
397         if ( fwrite ( output->buf, 1, output->len, stdout ) != output->len ) {
398                 fprintf ( stderr, "Could not write %zd bytes of output: %s\n",
399                           output->len, strerror ( errno ) );
400                 return -1;
401         }
402         return 0;
403 }
404
405 int main ( int argc, char **argv ) {
406         struct input_file input;
407         struct output_file output;
408         struct zinfo_file zinfo;
409         unsigned int i;
410
411         if ( argc != 3 ) {
412                 fprintf ( stderr, "Syntax: %s file.bin file.zinfo "
413                           "> file.zbin\n", argv[0] );
414                 exit ( 1 );
415         }
416
417         if ( read_input_file ( argv[1], &input ) < 0 )
418                 exit ( 1 );
419         if ( read_zinfo_file ( argv[2], &zinfo ) < 0 )
420                 exit ( 1 );
421         if ( alloc_output_file ( ( input.len * 4 ), &output ) < 0 )
422                 exit ( 1 );
423
424         for ( i = 0 ; i < zinfo.num_entries ; i++ ) {
425                 if ( process_zinfo ( &input, &output,
426                                      &zinfo.zinfo[i] ) < 0 )
427                         exit ( 1 );
428         }
429
430         if ( write_output_file ( &output ) < 0 )
431                 exit ( 1 );
432
433         return 0;
434 }