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
align(unsigned long value,unsigned long align)60 static unsigned long align ( unsigned long value, unsigned long align ) {
61 return ( ( value + align - 1 ) & ~( align - 1 ) );
62 }
63
read_file(const char * filename,void ** buf,size_t * len)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
read_input_file(const char * filename,struct input_file * input)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
read_zinfo_file(const char * filename,struct zinfo_file * zinfo)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
alloc_output_file(size_t max_len,struct output_file * output)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
process_zinfo_copy(struct input_file * input,struct output_file * output,union zinfo_record * zinfo)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
process_zinfo_pack(struct input_file * input,struct output_file * output,union zinfo_record * zinfo)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
process_zinfo_add(struct input_file * input,struct output_file * output,struct zinfo_add * add,size_t datasize)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
process_zinfo_addb(struct input_file * input,struct output_file * output,union zinfo_record * zinfo)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
process_zinfo_addw(struct input_file * input,struct output_file * output,union zinfo_record * zinfo)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
process_zinfo_addl(struct input_file * input,struct output_file * output,union zinfo_record * zinfo)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
process_zinfo(struct input_file * input,struct output_file * output,union zinfo_record * zinfo)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
write_output_file(struct output_file * output)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
main(int argc,char ** argv)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 }
384