#include #include #include #include #include #define READ(dst, size) memcpy(dst, buffer, size); buffer += size struct rgb { uint8_t r, g, b; }; struct image_descriptor_t { uint16_t left, top, width, height; uint8_t fields; }; struct dictionary_entry_t { unsigned char byte; int prev, len; }; void uncompress( int code_length, const uint8_t *input, int input_length, uint8_t *out ) { dictionary_entry_t *dictionary; int dictionary_ind; const int clear_code = 1 << ( code_length ); const int stop_code = clear_code + 1; const int reset_code_length = code_length; dictionary = ( dictionary_entry_t * ) malloc( sizeof( dictionary_entry_t ) * ( 1 << ( code_length + 1 ) ) ); for ( dictionary_ind = 0; dictionary_ind < ( 1 << code_length ); dictionary_ind++ ) { dictionary[ dictionary_ind ].byte = dictionary_ind; dictionary[ dictionary_ind ].prev = -1; dictionary[ dictionary_ind ].len = 1; } dictionary_ind+=2; int prev = -1; uint32_t mask = 0x01; while ( input_length ) { int code = 0x0; for (int i=0; i<(code_length + 1); i++) { const int bit = ( *input & mask ) ? 1 : 0; mask <<= 1; if ( mask == 0x100 ) { mask = 0x01; input++; input_length--; } code = code | ( bit << i ); } if ( code == clear_code ) { code_length = reset_code_length; dictionary = ( dictionary_entry_t * ) realloc( dictionary, sizeof( dictionary_entry_t ) * ( 1 << ( code_length + 1 ) ) ); for ( dictionary_ind = 0; dictionary_ind < ( 1 << code_length ); dictionary_ind++ ) { dictionary[ dictionary_ind ].byte = dictionary_ind; dictionary[ dictionary_ind ].prev = -1; dictionary[ dictionary_ind ].len = 1; } dictionary_ind+=2; prev = -1; continue; } else if ( code == stop_code ) break; if ( (prev > -1) && (code_length < 12) ) { if (code > dictionary_ind) { fprintf( stderr, "code = %.02x, but dictionary_ind = %.02x\n", code, dictionary_ind ); exit( 0 ); } int ptr = (code == dictionary_ind) ? prev : code; while ( dictionary[ ptr ].prev != -1 ) ptr = dictionary[ ptr ].prev; dictionary[ dictionary_ind ].byte = dictionary[ ptr ].byte; dictionary[ dictionary_ind ].prev = prev; dictionary[ dictionary_ind ].len = dictionary[ prev ].len + 1; dictionary_ind++; if ( (dictionary_ind == (1 << (code_length + 1))) && (code_length < 11) ) { code_length++; dictionary = ( dictionary_entry_t * ) realloc( dictionary, sizeof( dictionary_entry_t ) * ( 1 << ( code_length + 1 ) ) ); } } prev = code; const int match_len = dictionary[ code ].len; while ( code != -1 ) { out[ dictionary[ code ].len - 1 ] = dictionary[ code ].byte; if ( dictionary[ code ].prev == code ) { fprintf( stderr, "Internal error; self-reference." ); exit( 0 ); } code = dictionary[ code ].prev; } out += match_len; } } static int read_sub_blocks( uint8_t* buffer, uint8_t **data ) { int data_length = 0; *data = NULL; int index = 0; while (1) { uint8_t block_size = *(buffer++); if ( block_size == 0 ) break; data_length += block_size; *data = (uint8_t*)realloc( *data, data_length ); READ(*data + index, block_size); index += block_size; } return data_length; } uint8_t* process_image_descriptor( uint8_t* buffer, rgb *gct, int gct_size, int resolution_bits ) { image_descriptor_t image_descriptor; READ(&image_descriptor, 9); uint8_t lzw_code_size; READ(&lzw_code_size, 1); uint8_t *compressed_data = NULL; const int compressed_data_length = read_sub_blocks( buffer, &compressed_data ); const int uncompressed_data_length = image_descriptor.width * image_descriptor.height; uint8_t *uncompressed_data = (uint8_t*)malloc( uncompressed_data_length ); uncompress( lzw_code_size, compressed_data, compressed_data_length, uncompressed_data ); if ( compressed_data ) free( compressed_data ); return uncompressed_data; } uint32_t* LoadPalette(uint8_t *buffer, uint16_t *size = NULL ) { buffer += 10; const uint8_t fields = *buffer; uint32_t *global_color_table = (uint32_t *)calloc(1, 1024);; if (size) *size = 0; if (fields & 0x80) { int global_color_table_size = 1 << (((fields & 0x07) + 1)); if (size) *size = global_color_table_size; for (int i=0; i> 4 ) + 1; if ( fields & 0x80 ) { global_color_table_size = 1 << ( ( ( fields & 0x07 ) + 1 ) ); global_color_table = (rgb*)malloc( 3 * global_color_table_size ); READ(global_color_table, 3 * global_color_table_size); } uint8_t block_type = 0x0; while ( block_type != 0x3B ) { READ(&block_type, 1); uint8_t size; switch ( block_type ) { case 0x2C: return process_image_descriptor(buffer, global_color_table, global_color_table_size, color_resolution_bits); case 0x21: buffer++; //size = *(buffer++); buffer += size; do { size = *(buffer++); buffer += size; } while (size != 0); break; case 0x3B: break; default: fprintf( stderr, "Bailing on unrecognized block type %.02x\n", block_type ); return NULL; } } return NULL; } /*unsigned char* LoadGif(unsigned char *buffer, unsigned short* w, unsigned short* h) { return process_gif_stream(buffer, w, h); }*/