Subversion Repositories ipe_artfile_utils

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 daniel-mar 1
/**
2
 * LZW Decoder for Imagination Pilots Entertainment 16-bit games (IPE16)
3
 * - Blown Away - The Interactive Game by Imagination Pilots (BA)
4
 * - Panic in the Park - The Interactive Game by Imagination Pilots (PiP)
5
 * - Where's Waldo? At the Circus (Waldo1)
6
 * ART file packer and unpacker by Daniel Marschall, ViaThinkSoft (C) 2014-2018
7
 * Revision: 2018-02-15
8
 *
9
 * The code is based on "Cross platform GIF source code" (c) L. Patrick
10
 * http://www.cs.usyd.edu.au/~graphapp/package/src/libgif/gif.c
11
 * It was simplified and modified to encode IPE16-LZW instead of GIF-LZW.
12
 * The game uses exactly the compressed stream as defined in the GIF standard,
13
 * but the compressed stream is not divided into chunks.
14
 **/
15
 
16
#include "ipe16_lzw_decoder.h"
17
#include "utils.h"
18
 
19
#include <stdlib.h>
20
#include <stdio.h>
21
#include <stdbool.h>
22
 
23
Ipe16LZWDecoder* new_ipe16lzw_decoder(void) {
24
        return (Ipe16LZWDecoder*)app_zero_alloc(sizeof(Ipe16LZWDecoder));
25
}
26
 
27
void del_ipe16lzw_decoder(Ipe16LZWDecoder* decoder) {
28
        free(decoder);
29
}
30
 
31
void ipe16lzw_init_decoder(Ipe16LZWDecoder* decoder) {
32
        decoder->running_code = FIRST_CODE;
33
        decoder->running_bits = LZ_MIN_BITS;
34
        decoder->max_code_plus_one = 1 << decoder->running_bits;
35
        decoder->shift_state  = 0;
36
        decoder->shift_data   = 0;
37
 
38
        int i;
39
        for (i = 0; i <= LZ_MAX_CODE; i++) {
40
                decoder->prefix[i] = NO_SUCH_CODE;
41
        }
42
}
43
 
44
int ipe16lzw_read_code(FILE* inFile, Ipe16LZWDecoder* decoder) {
45
        int code;
46
        unsigned char next_byte;
47
        static int code_masks[] = {
48
                0x0000, 0x0001, 0x0003, 0x0007,
49
                0x000f, 0x001f, 0x003f, 0x007f,
50
                0x00ff, 0x01ff, 0x03ff, 0x07ff,
51
                0x0fff
52
        };
53
 
54
        while (decoder->shift_state < decoder->running_bits) {
55
                next_byte = read_byte(inFile);
56
                decoder->shift_data |=
57
                  ((unsigned long) next_byte) << decoder->shift_state;
58
                decoder->shift_state += 8;
59
        }
60
 
61
        code = decoder->shift_data & code_masks[decoder->running_bits];
62
 
63
        decoder->shift_data >>= decoder->running_bits;
64
        decoder->shift_state -= decoder->running_bits;
65
 
66
        if (++decoder->running_code > decoder->max_code_plus_one
67
                && decoder->running_bits < LZ_MAX_BITS) {
68
                decoder->max_code_plus_one <<= 1;
69
                decoder->running_bits++;
70
        }
71
 
72
        return code;
73
}
74
 
75
static int ipe16lzw_trace_prefix(unsigned int* prefix, int code, int clear_code) {
76
        int i = 0;
77
 
78
        while (code > clear_code && i++ <= LZ_MAX_CODE) {
79
                code = prefix[code];
80
        }
81
        return code;
82
}
83
 
84
// We don't do unsigned, because we want to have <0 as error result
85
/*unsigned*/ int ipe16lzw_decode(FILE* inFile, Ipe16LZWDecoder* decoder, unsigned char* output, int outputLength) {
86
        int i = 0, j;
87
        int current_code;
88
        int current_prefix;
89
        int stack_ptr = 0;
90
        int prev_code = NO_SUCH_CODE;
91
        unsigned char* stack;
92
        unsigned int* prefix;
93
        unsigned int* suffix;
94
        unsigned int bytes_written = 0;
95
 
96
        ipe16lzw_init_decoder(decoder);
97
 
98
        prefix          = decoder->prefix;
99
        suffix          = decoder->suffix;
100
        stack           = decoder->stack;
101
 
102
        /* Pop the stack */
103
        while (stack_ptr != 0 && i < outputLength) {
104
                output[i++] = stack[--stack_ptr];
105
                //if (i > bytes_written) bytes_written = i;
106
                ++bytes_written;
107
        }
108
 
109
        while (i < outputLength) {
110
                current_code = ipe16lzw_read_code(inFile, decoder);
111
 
112
                if (current_code == END_CODE) {
113
                        if (i != outputLength - 1) //  || decoder->pixel_count != 0
114
                                return -1; /* unexpected eof */
115
                        i++;
116
                } else if (current_code == CLEAR_CODE) {
117
                        for (j = 0; j <= LZ_MAX_CODE; j++) {
118
                                prefix[j] = NO_SUCH_CODE;
119
                        }
120
                        decoder->running_code = FIRST_CODE;
121
                        decoder->running_bits = LZ_MIN_BITS;
122
                        decoder->max_code_plus_one = 1 << decoder->running_bits;
123
                        prev_code = NO_SUCH_CODE;
124
                } else {
125
                        if (current_code < CLEAR_CODE) {
126
                                output[i++] = current_code;
127
                                //if (i > bytes_written) bytes_written = i;
128
                                ++bytes_written;
129
                        } else {
130
                                if ((current_code < 0) || (current_code > LZ_MAX_CODE))
131
                                        return -2; /* image defect */
132
                                if (prefix[current_code] == NO_SUCH_CODE) {
133
                                        if (current_code == decoder->running_code - 2) {
134
                                                current_prefix = prev_code;
135
                                                suffix[decoder->running_code - 2]
136
                                                        = stack[stack_ptr++]
137
                                                        = ipe16lzw_trace_prefix(prefix, prev_code, CLEAR_CODE);
138
                                        } else {
139
                                                return -3; /* image defect */
140
                                        }
141
                                } else {
142
                                        current_prefix = current_code;
143
                                }
144
                                j = 0;
145
                                while (j++ <= LZ_MAX_CODE && current_prefix > CLEAR_CODE && current_prefix <= LZ_MAX_CODE) {
146
                                        stack[stack_ptr++] = suffix[current_prefix];
147
                                        current_prefix = prefix[current_prefix];
148
                                }
149
                                if (j >= LZ_MAX_CODE || current_prefix > LZ_MAX_CODE)
150
                                        return -4; /* image defect */
151
 
152
                                stack[stack_ptr++] = current_prefix;
153
 
154
                                while (stack_ptr != 0 && i < outputLength) {
155
                                        output[i++] = stack[--stack_ptr];
156
                                        //if (i > bytes_written) bytes_written = i;
157
                                        ++bytes_written;
158
                                }
159
                        }
160
                        if (prev_code != NO_SUCH_CODE) {
161
                                if ((decoder->running_code < 2) ||
162
                                   (decoder->running_code > LZ_MAX_CODE+2))
163
                                        return -5; /* image defect */
164
                                prefix[decoder->running_code - 2] = prev_code;
165
 
166
                                if (current_code == decoder->running_code - 2) {
167
                                        suffix[decoder->running_code - 2]
168
                                                = ipe16lzw_trace_prefix(prefix, prev_code, CLEAR_CODE);
169
                                } else {
170
                                        suffix[decoder->running_code - 2]
171
                                                = ipe16lzw_trace_prefix(prefix, current_code, CLEAR_CODE);
172
                                }
173
                        }
174
                        prev_code = current_code;
175
                }
176
        }
177
 
178
        return bytes_written;
179
}