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