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