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 
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() %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 
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 %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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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