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