Subversion Repositories ipe_artfile_utils

Compare Revisions

No changes between revisions

Regard whitespace Rev 1 → Rev 2

/trunk/ipe16_lzw_decoder.c
0,0 → 1,179
/**
* LZW Decoder for Imagination Pilots Entertainment 16-bit games (IPE16)
* - Blown Away - The Interactive Game by Imagination Pilots (BA)
* - Panic in the Park - The Interactive Game by Imagination Pilots (PiP)
* - Where's Waldo? At the Circus (Waldo1)
* ART file packer and unpacker by Daniel Marschall, ViaThinkSoft (C) 2014-2018
* Revision: 2018-02-15
*
* The code is based on "Cross platform GIF source code" (c) L. Patrick
* http://www.cs.usyd.edu.au/~graphapp/package/src/libgif/gif.c
* It was simplified and modified to encode IPE16-LZW instead of GIF-LZW.
* The game uses exactly the compressed stream as defined in the GIF standard,
* but the compressed stream is not divided into chunks.
**/
 
#include "ipe16_lzw_decoder.h"
#include "utils.h"
 
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
 
Ipe16LZWDecoder* new_ipe16lzw_decoder(void) {
return (Ipe16LZWDecoder*)app_zero_alloc(sizeof(Ipe16LZWDecoder));
}
 
void del_ipe16lzw_decoder(Ipe16LZWDecoder* decoder) {
free(decoder);
}
 
void ipe16lzw_init_decoder(Ipe16LZWDecoder* decoder) {
decoder->running_code = FIRST_CODE;
decoder->running_bits = LZ_MIN_BITS;
decoder->max_code_plus_one = 1 << decoder->running_bits;
decoder->shift_state = 0;
decoder->shift_data = 0;
 
int i;
for (i = 0; i <= LZ_MAX_CODE; i++) {
decoder->prefix[i] = NO_SUCH_CODE;
}
}
 
int ipe16lzw_read_code(FILE* inFile, Ipe16LZWDecoder* decoder) {
int code;
unsigned char next_byte;
static int code_masks[] = {
0x0000, 0x0001, 0x0003, 0x0007,
0x000f, 0x001f, 0x003f, 0x007f,
0x00ff, 0x01ff, 0x03ff, 0x07ff,
0x0fff
};
 
while (decoder->shift_state < decoder->running_bits) {
next_byte = read_byte(inFile);
decoder->shift_data |=
((unsigned long) next_byte) << decoder->shift_state;
decoder->shift_state += 8;
}
 
code = decoder->shift_data & code_masks[decoder->running_bits];
 
decoder->shift_data >>= decoder->running_bits;
decoder->shift_state -= decoder->running_bits;
 
if (++decoder->running_code > decoder->max_code_plus_one
&& decoder->running_bits < LZ_MAX_BITS) {
decoder->max_code_plus_one <<= 1;
decoder->running_bits++;
}
 
return code;
}
 
static int ipe16lzw_trace_prefix(unsigned int* prefix, int code, int clear_code) {
int i = 0;
 
while (code > clear_code && i++ <= LZ_MAX_CODE) {
code = prefix[code];
}
return code;
}
 
// We don't do unsigned, because we want to have <0 as error result
/*unsigned*/ int ipe16lzw_decode(FILE* inFile, Ipe16LZWDecoder* decoder, unsigned char* output, int outputLength) {
int i = 0, j;
int current_code;
int current_prefix;
int stack_ptr = 0;
int prev_code = NO_SUCH_CODE;
unsigned char* stack;
unsigned int* prefix;
unsigned int* suffix;
unsigned int bytes_written = 0;
 
ipe16lzw_init_decoder(decoder);
 
prefix = decoder->prefix;
suffix = decoder->suffix;
stack = decoder->stack;
 
/* Pop the stack */
while (stack_ptr != 0 && i < outputLength) {
output[i++] = stack[--stack_ptr];
//if (i > bytes_written) bytes_written = i;
++bytes_written;
}
 
while (i < outputLength) {
current_code = ipe16lzw_read_code(inFile, decoder);
 
if (current_code == END_CODE) {
if (i != outputLength - 1) // || decoder->pixel_count != 0
return -1; /* unexpected eof */
i++;
} else if (current_code == CLEAR_CODE) {
for (j = 0; j <= LZ_MAX_CODE; j++) {
prefix[j] = NO_SUCH_CODE;
}
decoder->running_code = FIRST_CODE;
decoder->running_bits = LZ_MIN_BITS;
decoder->max_code_plus_one = 1 << decoder->running_bits;
prev_code = NO_SUCH_CODE;
} else {
if (current_code < CLEAR_CODE) {
output[i++] = current_code;
//if (i > bytes_written) bytes_written = i;
++bytes_written;
} else {
if ((current_code < 0) || (current_code > LZ_MAX_CODE))
return -2; /* image defect */
if (prefix[current_code] == NO_SUCH_CODE) {
if (current_code == decoder->running_code - 2) {
current_prefix = prev_code;
suffix[decoder->running_code - 2]
= stack[stack_ptr++]
= ipe16lzw_trace_prefix(prefix, prev_code, CLEAR_CODE);
} else {
return -3; /* image defect */
}
} else {
current_prefix = current_code;
}
j = 0;
while (j++ <= LZ_MAX_CODE && current_prefix > CLEAR_CODE && current_prefix <= LZ_MAX_CODE) {
stack[stack_ptr++] = suffix[current_prefix];
current_prefix = prefix[current_prefix];
}
if (j >= LZ_MAX_CODE || current_prefix > LZ_MAX_CODE)
return -4; /* image defect */
 
stack[stack_ptr++] = current_prefix;
 
while (stack_ptr != 0 && i < outputLength) {
output[i++] = stack[--stack_ptr];
//if (i > bytes_written) bytes_written = i;
++bytes_written;
}
}
if (prev_code != NO_SUCH_CODE) {
if ((decoder->running_code < 2) ||
(decoder->running_code > LZ_MAX_CODE+2))
return -5; /* image defect */
prefix[decoder->running_code - 2] = prev_code;
 
if (current_code == decoder->running_code - 2) {
suffix[decoder->running_code - 2]
= ipe16lzw_trace_prefix(prefix, prev_code, CLEAR_CODE);
} else {
suffix[decoder->running_code - 2]
= ipe16lzw_trace_prefix(prefix, current_code, CLEAR_CODE);
}
}
prev_code = current_code;
}
}
 
return bytes_written;
}
Property changes:
Added: svn:mime-type
+text/x-csrc
\ No newline at end of property