[contrib] Allow Network Protocol header to display in rom-o-matic
[gpxe.git] / src / util / zbin.c
blobf0df5ea0d7e2bbd2674f471e3633efde98d00ec3
1 #include <stdio.h>
2 #include <sys/stat.h>
4 #define ENCODE
5 #define VERBOSE
6 #include "nrv2b.c"
7 FILE *infile, *outfile;
9 #define DEBUG 0
11 struct input_file {
12 void *buf;
13 size_t len;
16 struct output_file {
17 void *buf;
18 size_t len;
19 size_t hdr_len;
20 size_t max_len;
23 struct zinfo_common {
24 char type[4];
25 char pad[12];
28 struct zinfo_copy {
29 char type[4];
30 uint32_t offset;
31 uint32_t len;
32 uint32_t align;
35 struct zinfo_pack {
36 char type[4];
37 uint32_t offset;
38 uint32_t len;
39 uint32_t align;
42 struct zinfo_payload {
43 char type[4];
44 uint32_t pad1;
45 uint32_t pad2;
46 uint32_t align;
49 struct zinfo_add {
50 char type[4];
51 uint32_t offset;
52 uint32_t divisor;
53 uint32_t pad;
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;
64 struct zinfo_file {
65 union zinfo_record *zinfo;
66 unsigned int num_entries;
69 static unsigned long align ( unsigned long value, unsigned long align ) {
70 return ( ( value + align - 1 ) & ~( align - 1 ) );
73 static int read_file ( const char *filename, void **buf, size_t *len ) {
74 FILE *file;
75 struct stat stat;
77 file = fopen ( filename, "r" );
78 if ( ! file ) {
79 fprintf ( stderr, "Could not open %s: %s\n", filename,
80 strerror ( errno ) );
81 goto err;
84 if ( fstat ( fileno ( file ), &stat ) < 0 ) {
85 fprintf ( stderr, "Could not stat %s: %s\n", filename,
86 strerror ( errno ) );
87 goto err;
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;
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;
104 fclose ( file );
105 return 0;
107 err:
108 if ( file )
109 fclose ( file );
110 return -1;
113 static int read_input_file ( const char *filename,
114 struct input_file *input ) {
115 return read_file ( filename, &input->buf, &input->len );
118 static int read_zinfo_file ( const char *filename,
119 struct zinfo_file *zinfo ) {
120 void *buf;
121 size_t len;
123 if ( read_file ( filename, &buf, &len ) < 0 )
124 return -1;
126 if ( ( len % sizeof ( *(zinfo->zinfo) ) ) != 0 ) {
127 fprintf ( stderr, ".zinfo file %s has invalid length %zd\n",
128 filename, len );
129 return -1;
132 zinfo->zinfo = buf;
133 zinfo->num_entries = ( len / sizeof ( *(zinfo->zinfo) ) );
134 return 0;
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;
146 memset ( output->buf, 0xff, sizeof ( output->buf ) );
147 return 0;
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;
157 if ( ( offset + len ) > input->len ) {
158 fprintf ( stderr, "Input buffer overrun on copy\n" );
159 return -1;
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;
168 if ( DEBUG ) {
169 fprintf ( stderr, "COPY [%#zx,%#zx) to [%#zx,%#zx)\n",
170 offset, ( offset + len ), output->len,
171 ( output->len + len ) );
174 memcpy ( ( output->buf + output->len ),
175 ( input->buf + offset ), len );
176 output->len += len;
177 return 0;
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;
188 if ( ( offset + len ) > input->len ) {
189 fprintf ( stderr, "Input buffer overrun on pack\n" );
190 return -1;
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;
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;
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 ) );
212 output->len += packed_len;
213 if ( output->len > output->max_len ) {
214 fprintf ( stderr, "Output buffer overrun on pack\n" );
215 return -1;
218 return 0;
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;
226 output->len = align ( output->len, payload->align );
227 output->hdr_len = output->len;
229 if ( DEBUG ) {
230 fprintf ( stderr, "PAYL at %#zx\n", output->hdr_len );
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;
246 if ( ( offset + datasize ) > output->len ) {
247 fprintf ( stderr, "Add at %#zx outside output buffer\n",
248 offset );
249 return -1;
252 target = ( output->buf + offset );
253 size = ( align ( len, add->divisor ) / add->divisor );
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;
271 val = size + addend;
273 /* The result of 1UL << ( 8 * sizeof(unsigned long) ) is undefined */
274 mask = ( ( datasize < sizeof ( mask ) ) ?
275 ( ( 1UL << ( 8 * datasize ) ) - 1 ) : ~0UL );
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;
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;
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;
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 );
312 return 0;
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 );
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 );
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 );
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 );
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 );
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 );
357 struct zinfo_processor {
358 char *type;
359 int ( * process ) ( struct input_file *input,
360 struct output_file *output,
361 union zinfo_record *zinfo );
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 },
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;
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 );
392 fprintf ( stderr, "Unknown zinfo record type \"%s\"\n", &type[0] );
393 return -1;
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;
402 return 0;
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;
411 if ( argc != 3 ) {
412 fprintf ( stderr, "Syntax: %s file.bin file.zinfo "
413 "> file.zbin\n", argv[0] );
414 exit ( 1 );
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 );
424 for ( i = 0 ; i < zinfo.num_entries ; i++ ) {
425 if ( process_zinfo ( &input, &output,
426 &zinfo.zinfo[i] ) < 0 )
427 exit ( 1 );
430 if ( write_output_file ( &output ) < 0 )
431 exit ( 1 );
433 return 0;