[build] Fix signed/unsigned division in util/zbin.c
[people/pcmattman/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 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() %d 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 %d 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 %d\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 %d 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", offset, ( offset + len ),
161                           output->len, ( output->len + len ) );
162         }
163
164         memcpy ( ( output->buf + output->len ),
165                  ( input->buf + offset ), len );
166         output->len += len;
167         return 0;
168 }
169
170 static int process_zinfo_pack ( struct input_file *input,
171                                 struct output_file *output,
172                                 union zinfo_record *zinfo ) {
173         struct zinfo_pack *pack = &zinfo->pack;
174         size_t offset = pack->offset;
175         size_t len = pack->len;
176         unsigned long packed_len;
177
178         if ( ( offset + len ) > input->len ) {
179                 fprintf ( stderr, "Input buffer overrun on pack\n" );
180                 return -1;
181         }
182
183         output->len = align ( output->len, pack->align );
184         if ( output->len > output->max_len ) {
185                 fprintf ( stderr, "Output buffer overrun on pack\n" );
186                 return -1;
187         }
188
189         if ( ucl_nrv2b_99_compress ( ( input->buf + offset ), len,
190                                      ( output->buf + output->len ),
191                                      &packed_len, 0 ) != UCL_E_OK ) {
192                 fprintf ( stderr, "Compression failure\n" );
193                 return -1;
194         }
195
196         if ( DEBUG ) {
197                 fprintf ( stderr, "PACK [%#zx,%#zx) to [%#zx,%#zx)\n", offset, ( offset + len ),
198                           output->len, ( output->len + packed_len ) );
199         }
200
201         output->len += packed_len;
202         if ( output->len > output->max_len ) {
203                 fprintf ( stderr, "Output buffer overrun on pack\n" );
204                 return -1;
205         }
206
207         return 0;
208 }
209
210 static int process_zinfo_subtract ( struct input_file *input,
211                                     struct output_file *output,
212                                     struct zinfo_subtract *subtract,
213                                     size_t datasize ) {
214         size_t offset = subtract->offset;
215         void *target;
216         signed long raw_delta;
217         signed long delta;
218         unsigned long old;
219         unsigned long new;
220
221         if ( ( offset + datasize ) > output->len ) {
222                 fprintf ( stderr, "Subtract at %#zx outside output buffer\n",
223                           offset );
224                 return -1;
225         }
226
227         target = ( output->buf + offset );
228         raw_delta = ( align ( output->len, subtract->divisor ) -
229                       align ( input->len, subtract->divisor ) );
230         delta = ( raw_delta / ( ( signed long ) subtract->divisor ) );
231
232         switch ( datasize ) {
233         case 1: {
234                 uint8_t *byte = target;
235                 old = *byte;
236                 *byte += delta;
237                 new = *byte;
238                 break; }
239         case 2: {
240                 uint16_t *word = target;
241                 old = *word;
242                 *word += delta;
243                 new = *word;
244                 break; }
245         case 4: {
246                 uint32_t *dword = target;
247                 old = *dword;
248                 *dword += delta;
249                 new = *dword;
250                 break; }
251         default:
252                 fprintf ( stderr, "Unsupported subtract datasize %d\n",
253                           datasize );
254                 return -1;
255         }
256
257         if ( DEBUG ) {
258                 fprintf ( stderr, "SUBx [%#zx,%#zx) (%#lx+(%#lx/%#x)-(%#lx/%#x)) = %#lx\n",
259                           offset, ( offset + datasize ), old, output->len, subtract->divisor,
260                           input->len, subtract->divisor, new );
261         }
262
263         return 0;
264 }
265
266 static int process_zinfo_subb ( struct input_file *input,
267                                 struct output_file *output,
268                                 union zinfo_record *zinfo ) {
269         return process_zinfo_subtract ( input, output, &zinfo->subtract, 1 );
270 }
271
272 static int process_zinfo_subw ( struct input_file *input,
273                                 struct output_file *output,
274                                 union zinfo_record *zinfo ) {
275         return process_zinfo_subtract ( input, output, &zinfo->subtract, 2 );
276 }
277
278 static int process_zinfo_subl ( struct input_file *input,
279                                 struct output_file *output,
280                                 union zinfo_record *zinfo ) {
281         return process_zinfo_subtract ( input, output, &zinfo->subtract, 4 );
282 }
283
284 struct zinfo_processor {
285         char *type;
286         int ( * process ) ( struct input_file *input,
287                             struct output_file *output,
288                             union zinfo_record *zinfo );
289 };
290
291 static struct zinfo_processor zinfo_processors[] = {
292         { "COPY", process_zinfo_copy },
293         { "PACK", process_zinfo_pack },
294         { "SUBB", process_zinfo_subb },
295         { "SUBW", process_zinfo_subw },
296         { "SUBL", process_zinfo_subl },
297 };
298
299 static int process_zinfo ( struct input_file *input,
300                            struct output_file *output,
301                            union zinfo_record *zinfo ) {
302         struct zinfo_common *common = &zinfo->common;
303         struct zinfo_processor *processor;
304         char type[ sizeof ( common->type ) + 1 ] = "";
305         unsigned int i;
306
307         strncat ( type, common->type, sizeof ( type ) - 1 );
308         for ( i = 0 ; i < ( sizeof ( zinfo_processors ) /
309                             sizeof ( zinfo_processors[0] ) ) ; i++ ) {
310                 processor = &zinfo_processors[i];
311                 if ( strcmp ( processor->type, type ) == 0 )
312                         return processor->process ( input, output, zinfo );
313         }
314
315         fprintf ( stderr, "Unknown zinfo record type \"%s\"\n", &type[0] );
316         return -1;
317 }
318
319 static int write_output_file ( struct output_file *output ) {
320         if ( fwrite ( output->buf, 1, output->len, stdout ) != output->len ) {
321                 fprintf ( stderr, "Could not write %d bytes of output: %s\n",
322                           output->len, strerror ( errno ) );
323                 return -1;
324         }
325         return 0;
326 }
327
328 int main ( int argc, char **argv ) {
329         struct input_file input;
330         struct output_file output;
331         struct zinfo_file zinfo;
332         unsigned int i;
333
334         if ( argc != 3 ) {
335                 fprintf ( stderr, "Syntax: %s file.bin file.zinfo "
336                           "> file.zbin\n", argv[0] );
337                 exit ( 1 );
338         }
339
340         if ( read_input_file ( argv[1], &input ) < 0 )
341                 exit ( 1 );
342         if ( read_zinfo_file ( argv[2], &zinfo ) < 0 )
343                 exit ( 1 );
344         if ( alloc_output_file ( ( input.len * 4 ), &output ) < 0 )
345                 exit ( 1 );
346
347         for ( i = 0 ; i < zinfo.num_entries ; i++ ) {
348                 if ( process_zinfo ( &input, &output,
349                                      &zinfo.zinfo[i] ) < 0 )
350                         exit ( 1 );
351         }
352
353         if ( write_output_file ( &output ) < 0 )
354                 exit ( 1 );
355
356         return 0;
357 }