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 | } |