1#include <stdio.h>
2#include <sys/stat.h>
3
4#define ENCODE
5#define VERBOSE
6#include "nrv2b.c"
7FILE *infile, *outfile;
8
9#define DEBUG 0
10
11struct input_file {
12	void *buf;
13	size_t len;
14};
15
16struct output_file {
17	void *buf;
18	size_t len;
19	size_t max_len;
20};
21
22struct zinfo_common {
23	char type[4];
24	char pad[12];
25};
26
27struct zinfo_copy {
28	char type[4];
29	uint32_t offset;
30	uint32_t len;
31	uint32_t align;
32};
33
34struct zinfo_pack {
35	char type[4];
36	uint32_t offset;
37	uint32_t len;
38	uint32_t align;
39};
40
41struct zinfo_add {
42	char type[4];
43	uint32_t offset;
44	uint32_t divisor;
45	uint32_t pad;
46};
47
48union zinfo_record {
49	struct zinfo_common common;
50	struct zinfo_copy copy;
51	struct zinfo_pack pack;
52	struct zinfo_add add;
53};
54
55struct zinfo_file {
56	union zinfo_record *zinfo;
57	unsigned int num_entries;
58};
59
60static unsigned long align ( unsigned long value, unsigned long align ) {
61	return ( ( value + align - 1 ) & ~( align - 1 ) );
62}
63
64static 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
104static int read_input_file ( const char *filename,
105			     struct input_file *input ) {
106	return read_file ( filename, &input->buf, &input->len );
107}
108
109static 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
128static 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
141static 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
171static 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
212static 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
292static 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
298static 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
304static 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
310struct zinfo_processor {
311	char *type;
312	int ( * process ) ( struct input_file *input,
313			    struct output_file *output,
314			    union zinfo_record *zinfo );
315};
316
317static 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
325static 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
345static 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
354int 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