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