Subversion Repositories ipe_artfile_utils

Compare Revisions

No changes between revisions

Regard whitespace Rev 1 → Rev 2

/trunk/ipe32_lzw_decoder.c
0,0 → 1,159
/**
* LZW Decoder for Imagination Pilots Entertainment 32-bit games (IPE32)
* - Where's Waldo? Exploring Geography
* - Eraser Turnabout by Imagination Pilots
* - Virtual K'Nex by Imagination Pilots
* ART file packer and unpacker by Daniel Marschall, ViaThinkSoft (C) 2018
* Revision: 2018-02-15
*
* Based on : Basic LZW Data Compression program published in DDJ October 1989 issue.
* by Mark R. Nelson
* http://collaboration.cmc.ec.gc.ca/science/rpn/biblio/ddj/Website/articles/DDJ/1989/8910/8910b/8910b.htm
* Updated by: Shawn M. Regan, January 1990
* http://mirror.bagelwood.com/textfiles/computers/regan.lst
* Updated by: Daniel Marschall, 11 February 2018
* https://misc.daniel-marschall.de/code/c/lzw.c
* Changed for IPE32: - Simplified
* - Thread safe
* - MAX_BITS = 13
**/
 
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
 
#include "utils.h"
#include "ipe32_lzw_decoder.h"
 
#define INIT_BITS 9
#define MAX_BITS 13 /* Do not exceed 14 with this program */
 
#if MAX_BITS == 14 /* Set the table size. Must be a prime */
#define TABLE_SIZE 18041 /* number somewhat larger than 2^MAX_BITS.*/
#elif MAX_BITS == 13
#define TABLE_SIZE 9029
#else
#define TABLE_SIZE 5021
#endif
 
#define CLEAR_TABLE 256 /* Code to flush the string table */
#define TERMINATOR 257 /* To mark EOF Condition, instead of MAX_VALUE */
#define FIRST_CODE 258 /* First available code for code_value table */
 
#define MAXVAL(n) (( 1 <<( n )) -1) /* max_value formula macro */
 
unsigned char* decode_string(Ipe32LZWDecoder *decoder, unsigned char *buffer, unsigned int code) {
int i=0;
 
while (code > 255) {
*buffer++ = decoder->append_character[code];
code = decoder->prefix_code[code];
if (i++ >= 4000) {
// printf("Error during code expansion\n");
return NULL;
}
}
*buffer=code;
return(buffer);
}
 
unsigned input_code(Ipe32LZWDecoder *decoder, unsigned char* lzwInputBuffer, int* inputBufferPos) {
unsigned int return_value;
 
while (decoder->input_bit_count <= 24) {
decoder->input_bit_buffer |= lzwInputBuffer[(*inputBufferPos)] << (24 - decoder->input_bit_count);
(*inputBufferPos)++;
decoder->input_bit_count += 8;
}
return_value=decoder->input_bit_buffer >> (32-decoder->num_bits);
decoder->input_bit_buffer <<= decoder->num_bits;
decoder->input_bit_count -= decoder->num_bits;
return(return_value);
}
 
void reset_input_buffer(Ipe32LZWDecoder *decoder) {
decoder->input_bit_count = 0;
decoder->input_bit_buffer = 0;
}
 
void ipe32lzw_reset_decoder(Ipe32LZWDecoder *decoder) {
decoder->num_bits = INIT_BITS;
decoder->max_code = MAXVAL(decoder->num_bits); /* Initialize max_value & max_code */
 
// Make sure the input buffer is correctly flushed
reset_input_buffer(decoder);
}
 
void ipe32lzw_init_decoder(Ipe32LZWDecoder *decoder) {
decoder->prefix_code = malloc(TABLE_SIZE*sizeof(unsigned int));
decoder->append_character = malloc(TABLE_SIZE*sizeof(unsigned char));
ipe32lzw_reset_decoder(decoder);
}
 
// Returns: Bytes written or -1 when an error occurs
int ipe32lzw_decode(Ipe32LZWDecoder *decoder, unsigned char* outputBuffer, const size_t outpufBufferSize, unsigned char* lzwInputBuffer, const size_t maxReadBytes) {
unsigned int next_code=FIRST_CODE;
unsigned int new_code;
unsigned int old_code;
int character;
int clear_flag=1; /* Need to clear the code value array */
unsigned char *string;
 
int inputBufferPos = 0;
int outputBufferPos = 0;
#define OUTPUT(code) { if (outputBufferPos == outpufBufferSize) return -1; outputBuffer[outputBufferPos++] = code; }
 
ipe32lzw_reset_decoder(decoder);
 
while (1) {
if (inputBufferPos == maxReadBytes) return -1;
if ((new_code=input_code(decoder, lzwInputBuffer, &inputBufferPos)) == TERMINATOR) break;
 
if (clear_flag) { /* Initialize or Re-Initialize */
clear_flag=0;
old_code=new_code; /* The next three lines have been moved */
character=old_code; /* from the original */
OUTPUT(old_code);
continue;
}
if (new_code == CLEAR_TABLE) { /* Clear string table */
clear_flag=1;
decoder->num_bits=INIT_BITS;
next_code=FIRST_CODE;
decoder->max_code = MAXVAL(decoder->num_bits);
continue;
}
if (new_code >= next_code) { /* Check for string+char+string */
*decoder->decode_stack=character;
string = decode_string(decoder, decoder->decode_stack+1,old_code);
} else {
string = decode_string(decoder, decoder->decode_stack,new_code);
}
if (string == NULL) return -1;
 
character = *string; /* Output decoded string in reverse */
while (string >= decoder->decode_stack) {
OUTPUT(*string--);
}
 
if (next_code <= decoder->max_code) { /* Add to string table if not full */
decoder->prefix_code[next_code]=old_code;
decoder->append_character[next_code++]=character;
if (next_code == decoder->max_code && decoder->num_bits < MAX_BITS) {
decoder->max_code = MAXVAL(++decoder->num_bits);
}
}
old_code=new_code;
}
 
return outputBufferPos;
}
 
void ipe32lzw_free_decoder(Ipe32LZWDecoder *decoder) {
free(decoder->prefix_code);
free(decoder->append_character);
}
 
Ipe32LZWDecoder* new_ipe32lzw_decoder(void) {
return (Ipe32LZWDecoder*)app_zero_alloc(sizeof(Ipe32LZWDecoder));
}
Property changes:
Added: svn:mime-type
+text/x-csrc
\ No newline at end of property