1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 
24 #include "common/endian.h"
25 #include "common/textconsole.h"
26 #include "common/util.h"
27 #include "scumm/bomp.h"
28 #include "scumm/smush/codec37.h"
29 
30 namespace Scumm {
31 
Codec37Decoder(int width,int height)32 Codec37Decoder::Codec37Decoder(int width, int height) {
33 	_width = width;
34 	_height = height;
35 	_frameSize = _width * _height;
36 	_deltaSize = _frameSize * 3 + 0x13600;
37 	_deltaBuf = (byte *)calloc(_deltaSize, sizeof(byte));
38 	if (_deltaBuf == 0)
39 		error("unable to allocate decoder buffer");
40 	_deltaBufs[0] = _deltaBuf + 0x4D80;
41 	_deltaBufs[1] = _deltaBuf + 0xE880 + _frameSize;
42 	_offsetTable = new int16[255];
43 	if (_offsetTable == 0)
44 		error("unable to allocate decoder offset table");
45 	_curtable = 0;
46 	_prevSeqNb = 0;
47 	_tableLastPitch = -1;
48 	_tableLastIndex = -1;
49 }
50 
~Codec37Decoder()51 Codec37Decoder::~Codec37Decoder() {
52 	if (_offsetTable) {
53 		delete[] _offsetTable;
54 		_offsetTable = 0;
55 		_tableLastPitch = -1;
56 		_tableLastIndex = -1;
57 	}
58 	if (_deltaBuf) {
59 		free(_deltaBuf);
60 		_deltaSize = 0;
61 		_deltaBuf = 0;
62 		_deltaBufs[0] = 0;
63 		_deltaBufs[1] = 0;
64 	}
65 }
66 
maketable(int pitch,int index)67 void Codec37Decoder::maketable(int pitch, int index) {
68 	static const int8 maketable_bytes[] = {
69     0,   0,   1,   0,   2,   0,   3,   0,   5,   0,
70     8,   0,  13,   0,  21,   0,  -1,   0,  -2,   0,
71    -3,   0,  -5,   0,  -8,   0, -13,   0, -17,   0,
72   -21,   0,   0,   1,   1,   1,   2,   1,   3,   1,
73     5,   1,   8,   1,  13,   1,  21,   1,  -1,   1,
74    -2,   1,  -3,   1,  -5,   1,  -8,   1, -13,   1,
75   -17,   1, -21,   1,   0,   2,   1,   2,   2,   2,
76     3,   2,   5,   2,   8,   2,  13,   2,  21,   2,
77    -1,   2,  -2,   2,  -3,   2,  -5,   2,  -8,   2,
78   -13,   2, -17,   2, -21,   2,   0,   3,   1,   3,
79     2,   3,   3,   3,   5,   3,   8,   3,  13,   3,
80    21,   3,  -1,   3,  -2,   3,  -3,   3,  -5,   3,
81    -8,   3, -13,   3, -17,   3, -21,   3,   0,   5,
82     1,   5,   2,   5,   3,   5,   5,   5,   8,   5,
83    13,   5,  21,   5,  -1,   5,  -2,   5,  -3,   5,
84    -5,   5,  -8,   5, -13,   5, -17,   5, -21,   5,
85     0,   8,   1,   8,   2,   8,   3,   8,   5,   8,
86     8,   8,  13,   8,  21,   8,  -1,   8,  -2,   8,
87    -3,   8,  -5,   8,  -8,   8, -13,   8, -17,   8,
88   -21,   8,   0,  13,   1,  13,   2,  13,   3,  13,
89     5,  13,   8,  13,  13,  13,  21,  13,  -1,  13,
90    -2,  13,  -3,  13,  -5,  13,  -8,  13, -13,  13,
91   -17,  13, -21,  13,   0,  21,   1,  21,   2,  21,
92     3,  21,   5,  21,   8,  21,  13,  21,  21,  21,
93    -1,  21,  -2,  21,  -3,  21,  -5,  21,  -8,  21,
94   -13,  21, -17,  21, -21,  21,   0,  -1,   1,  -1,
95     2,  -1,   3,  -1,   5,  -1,   8,  -1,  13,  -1,
96    21,  -1,  -1,  -1,  -2,  -1,  -3,  -1,  -5,  -1,
97    -8,  -1, -13,  -1, -17,  -1, -21,  -1,   0,  -2,
98     1,  -2,   2,  -2,   3,  -2,   5,  -2,   8,  -2,
99    13,  -2,  21,  -2,  -1,  -2,  -2,  -2,  -3,  -2,
100    -5,  -2,  -8,  -2, -13,  -2, -17,  -2, -21,  -2,
101     0,  -3,   1,  -3,   2,  -3,   3,  -3,   5,  -3,
102     8,  -3,  13,  -3,  21,  -3,  -1,  -3,  -2,  -3,
103    -3,  -3,  -5,  -3,  -8,  -3, -13,  -3, -17,  -3,
104   -21,  -3,   0,  -5,   1,  -5,   2,  -5,   3,  -5,
105     5,  -5,   8,  -5,  13,  -5,  21,  -5,  -1,  -5,
106    -2,  -5,  -3,  -5,  -5,  -5,  -8,  -5, -13,  -5,
107   -17,  -5, -21,  -5,   0,  -8,   1,  -8,   2,  -8,
108     3,  -8,   5,  -8,   8,  -8,  13,  -8,  21,  -8,
109    -1,  -8,  -2,  -8,  -3,  -8,  -5,  -8,  -8,  -8,
110   -13,  -8, -17,  -8, -21,  -8,   0, -13,   1, -13,
111     2, -13,   3, -13,   5, -13,   8, -13,  13, -13,
112    21, -13,  -1, -13,  -2, -13,  -3, -13,  -5, -13,
113    -8, -13, -13, -13, -17, -13, -21, -13,   0, -17,
114     1, -17,   2, -17,   3, -17,   5, -17,   8, -17,
115    13, -17,  21, -17,  -1, -17,  -2, -17,  -3, -17,
116    -5, -17,  -8, -17, -13, -17, -17, -17, -21, -17,
117     0, -21,   1, -21,   2, -21,   3, -21,   5, -21,
118     8, -21,  13, -21,  21, -21,  -1, -21,  -2, -21,
119    -3, -21,  -5, -21,  -8, -21, -13, -21, -17, -21,
120     0,   0,  -8, -29,   8, -29, -18, -25,  17, -25,
121     0, -23,  -6, -22,   6, -22, -13, -19,  12, -19,
122     0, -18,  25, -18, -25, -17,  -5, -17,   5, -17,
123   -10, -15,  10, -15,   0, -14,  -4, -13,   4, -13,
124    19, -13, -19, -12,  -8, -11,  -2, -11,   0, -11,
125     2, -11,   8, -11, -15, -10,  -4, -10,   4, -10,
126    15, -10,  -6,  -9,  -1,  -9,   1,  -9,   6,  -9,
127   -29,  -8, -11,  -8,  -8,  -8,  -3,  -8,   3,  -8,
128     8,  -8,  11,  -8,  29,  -8,  -5,  -7,  -2,  -7,
129     0,  -7,   2,  -7,   5,  -7, -22,  -6,  -9,  -6,
130    -6,  -6,  -3,  -6,  -1,  -6,   1,  -6,   3,  -6,
131     6,  -6,   9,  -6,  22,  -6, -17,  -5,  -7,  -5,
132    -4,  -5,  -2,  -5,   0,  -5,   2,  -5,   4,  -5,
133     7,  -5,  17,  -5, -13,  -4, -10,  -4,  -5,  -4,
134    -3,  -4,  -1,  -4,   0,  -4,   1,  -4,   3,  -4,
135     5,  -4,  10,  -4,  13,  -4,  -8,  -3,  -6,  -3,
136    -4,  -3,  -3,  -3,  -2,  -3,  -1,  -3,   0,  -3,
137     1,  -3,   2,  -3,   4,  -3,   6,  -3,   8,  -3,
138   -11,  -2,  -7,  -2,  -5,  -2,  -3,  -2,  -2,  -2,
139    -1,  -2,   0,  -2,   1,  -2,   2,  -2,   3,  -2,
140     5,  -2,   7,  -2,  11,  -2,  -9,  -1,  -6,  -1,
141    -4,  -1,  -3,  -1,  -2,  -1,  -1,  -1,   0,  -1,
142     1,  -1,   2,  -1,   3,  -1,   4,  -1,   6,  -1,
143     9,  -1, -31,   0, -23,   0, -18,   0, -14,   0,
144   -11,   0,  -7,   0,  -5,   0,  -4,   0,  -3,   0,
145    -2,   0,  -1,   0,   0, -31,   1,   0,   2,   0,
146     3,   0,   4,   0,   5,   0,   7,   0,  11,   0,
147    14,   0,  18,   0,  23,   0,  31,   0,  -9,   1,
148    -6,   1,  -4,   1,  -3,   1,  -2,   1,  -1,   1,
149     0,   1,   1,   1,   2,   1,   3,   1,   4,   1,
150     6,   1,   9,   1, -11,   2,  -7,   2,  -5,   2,
151    -3,   2,  -2,   2,  -1,   2,   0,   2,   1,   2,
152     2,   2,   3,   2,   5,   2,   7,   2,  11,   2,
153    -8,   3,  -6,   3,  -4,   3,  -2,   3,  -1,   3,
154     0,   3,   1,   3,   2,   3,   3,   3,   4,   3,
155     6,   3,   8,   3, -13,   4, -10,   4,  -5,   4,
156    -3,   4,  -1,   4,   0,   4,   1,   4,   3,   4,
157     5,   4,  10,   4,  13,   4, -17,   5,  -7,   5,
158    -4,   5,  -2,   5,   0,   5,   2,   5,   4,   5,
159     7,   5,  17,   5, -22,   6,  -9,   6,  -6,   6,
160    -3,   6,  -1,   6,   1,   6,   3,   6,   6,   6,
161     9,   6,  22,   6,  -5,   7,  -2,   7,   0,   7,
162     2,   7,   5,   7, -29,   8, -11,   8,  -8,   8,
163    -3,   8,   3,   8,   8,   8,  11,   8,  29,   8,
164    -6,   9,  -1,   9,   1,   9,   6,   9, -15,  10,
165    -4,  10,   4,  10,  15,  10,  -8,  11,  -2,  11,
166     0,  11,   2,  11,   8,  11,  19,  12, -19,  13,
167    -4,  13,   4,  13,   0,  14, -10,  15,  10,  15,
168    -5,  17,   5,  17,  25,  17, -25,  18,   0,  18,
169   -12,  19,  13,  19,  -6,  22,   6,  22,   0,  23,
170   -17,  25,  18,  25,  -8,  29,   8,  29,   0,  31,
171     0,   0,  -6, -22,   6, -22, -13, -19,  12, -19,
172     0, -18,  -5, -17,   5, -17, -10, -15,  10, -15,
173     0, -14,  -4, -13,   4, -13,  19, -13, -19, -12,
174    -8, -11,  -2, -11,   0, -11,   2, -11,   8, -11,
175   -15, -10,  -4, -10,   4, -10,  15, -10,  -6,  -9,
176    -1,  -9,   1,  -9,   6,  -9, -11,  -8,  -8,  -8,
177    -3,  -8,   0,  -8,   3,  -8,   8,  -8,  11,  -8,
178    -5,  -7,  -2,  -7,   0,  -7,   2,  -7,   5,  -7,
179   -22,  -6,  -9,  -6,  -6,  -6,  -3,  -6,  -1,  -6,
180     1,  -6,   3,  -6,   6,  -6,   9,  -6,  22,  -6,
181   -17,  -5,  -7,  -5,  -4,  -5,  -2,  -5,  -1,  -5,
182     0,  -5,   1,  -5,   2,  -5,   4,  -5,   7,  -5,
183    17,  -5, -13,  -4, -10,  -4,  -5,  -4,  -3,  -4,
184    -2,  -4,  -1,  -4,   0,  -4,   1,  -4,   2,  -4,
185     3,  -4,   5,  -4,  10,  -4,  13,  -4,  -8,  -3,
186    -6,  -3,  -4,  -3,  -3,  -3,  -2,  -3,  -1,  -3,
187     0,  -3,   1,  -3,   2,  -3,   3,  -3,   4,  -3,
188     6,  -3,   8,  -3, -11,  -2,  -7,  -2,  -5,  -2,
189    -4,  -2,  -3,  -2,  -2,  -2,  -1,  -2,   0,  -2,
190     1,  -2,   2,  -2,   3,  -2,   4,  -2,   5,  -2,
191     7,  -2,  11,  -2,  -9,  -1,  -6,  -1,  -5,  -1,
192    -4,  -1,  -3,  -1,  -2,  -1,  -1,  -1,   0,  -1,
193     1,  -1,   2,  -1,   3,  -1,   4,  -1,   5,  -1,
194     6,  -1,   9,  -1, -23,   0, -18,   0, -14,   0,
195   -11,   0,  -7,   0,  -5,   0,  -4,   0,  -3,   0,
196    -2,   0,  -1,   0,   0, -23,   1,   0,   2,   0,
197     3,   0,   4,   0,   5,   0,   7,   0,  11,   0,
198    14,   0,  18,   0,  23,   0,  -9,   1,  -6,   1,
199    -5,   1,  -4,   1,  -3,   1,  -2,   1,  -1,   1,
200     0,   1,   1,   1,   2,   1,   3,   1,   4,   1,
201     5,   1,   6,   1,   9,   1, -11,   2,  -7,   2,
202    -5,   2,  -4,   2,  -3,   2,  -2,   2,  -1,   2,
203     0,   2,   1,   2,   2,   2,   3,   2,   4,   2,
204     5,   2,   7,   2,  11,   2,  -8,   3,  -6,   3,
205    -4,   3,  -3,   3,  -2,   3,  -1,   3,   0,   3,
206     1,   3,   2,   3,   3,   3,   4,   3,   6,   3,
207     8,   3, -13,   4, -10,   4,  -5,   4,  -3,   4,
208    -2,   4,  -1,   4,   0,   4,   1,   4,   2,   4,
209     3,   4,   5,   4,  10,   4,  13,   4, -17,   5,
210    -7,   5,  -4,   5,  -2,   5,  -1,   5,   0,   5,
211     1,   5,   2,   5,   4,   5,   7,   5,  17,   5,
212   -22,   6,  -9,   6,  -6,   6,  -3,   6,  -1,   6,
213     1,   6,   3,   6,   6,   6,   9,   6,  22,   6,
214    -5,   7,  -2,   7,   0,   7,   2,   7,   5,   7,
215   -11,   8,  -8,   8,  -3,   8,   0,   8,   3,   8,
216     8,   8,  11,   8,  -6,   9,  -1,   9,   1,   9,
217     6,   9, -15,  10,  -4,  10,   4,  10,  15,  10,
218    -8,  11,  -2,  11,   0,  11,   2,  11,   8,  11,
219    19,  12, -19,  13,  -4,  13,   4,  13,   0,  14,
220   -10,  15,  10,  15,  -5,  17,   5,  17,   0,  18,
221   -12,  19,  13,  19,  -6,  22,   6,  22,   0,  23,
222 	};
223 
224 	if (_tableLastPitch == pitch && _tableLastIndex == index)
225 		return;
226 
227 	_tableLastPitch = pitch;
228 	_tableLastIndex = index;
229 	index *= 255;
230 	assert(index + 254 < (int32)(sizeof(maketable_bytes) / 2));
231 
232 	for (int32 i = 0; i < 255; i++) {
233 		int32 j = (i + index) * 2;
234 		_offsetTable[i] = maketable_bytes[j + 1] * pitch + maketable_bytes[j];
235 	}
236 }
237 
238 #if defined(SCUMM_NEED_ALIGNMENT)
239 
240 #define DECLARE_LITERAL_TEMP(v)			\
241 	byte v
242 
243 #define READ_LITERAL_PIXEL(src, v)		\
244 	v = *src++
245 
246 #define WRITE_4X1_LINE(dst, v)			\
247 	do {					\
248 		int j;				\
249 		for (j=0; j<4; j++)		\
250 			(dst)[j] = v;		\
251 	} while (0)
252 
253 #define COPY_4X1_LINE(dst, src)			\
254 	do {					\
255 		int j;				\
256 		for (j=0; j<4; j++)		\
257 			(dst)[j] = (src)[j];	\
258 	} while (0)
259 
260 #else /* SCUMM_NEED_ALIGNMENT */
261 
262 #define DECLARE_LITERAL_TEMP(v)			\
263 	uint32 v
264 
265 #define READ_LITERAL_PIXEL(src, v)			\
266 	do {						\
267 		v = *src++;				\
268 		v += (v << 8) + (v << 16) + (v << 24);	\
269 	} while (0)
270 
271 #define WRITE_4X1_LINE(dst, v)			\
272 	*(uint32 *)(dst) = v
273 
274 #define COPY_4X1_LINE(dst, src)			\
275 	*(uint32 *)(dst) = *(const uint32 *)(src)
276 
277 #endif /* SCUMM_NEED_ALIGNMENT */
278 
279 /* Fill a 4x4 pixel block with a literal pixel value */
280 
281 #define LITERAL_4X4(src, dst, pitch)				\
282 	do {							\
283 		int x;						\
284 		DECLARE_LITERAL_TEMP(t);			\
285 		READ_LITERAL_PIXEL(src, t);			\
286 		for (x=0; x<4; x++) {				\
287 			WRITE_4X1_LINE(dst + pitch * x, t);	\
288 		}						\
289 		dst += 4;					\
290 	} while (0)
291 
292 /* Fill four 4x1 pixel blocks with literal pixel values */
293 
294 #define LITERAL_4X1(src, dst, pitch)				\
295 	do {							\
296 		int x;						\
297 		DECLARE_LITERAL_TEMP(t);			\
298 		for (x=0; x<4; x++) {				\
299 			READ_LITERAL_PIXEL(src, t);		\
300 			WRITE_4X1_LINE(dst + pitch * x, t);	\
301 		}						\
302 		dst += 4;					\
303 	} while (0)
304 
305 /* Fill sixteen 1x1 pixel blocks with literal pixel values */
306 
307 #define LITERAL_1X1(src, dst, pitch)				\
308 	do {							\
309 		int x;						\
310 		for (x=0; x<4; x++) {				\
311 			COPY_4X1_LINE(dst + pitch * x, src);	\
312 			src += 4;				\
313 		}						\
314 		dst += 4;					\
315 	} while (0)
316 
317 /* Copy a 4x4 pixel block from a different place in the framebuffer */
318 
319 #define COPY_4X4(dst2, dst, pitch)					  \
320 	do {								  \
321 		int x;							  \
322 		for (x=0; x<4; x++) {					  \
323 			COPY_4X1_LINE(dst + pitch * x, dst2 + pitch * x); \
324 		}							  \
325 		dst += 4;						  \
326 	} while (0)
327 
proc1(byte * dst,const byte * src,int32 next_offs,int bw,int bh,int pitch,int16 * offset_table)328 void Codec37Decoder::proc1(byte *dst, const byte *src, int32 next_offs, int bw, int bh, int pitch, int16 *offset_table) {
329 	uint8 code;
330 	bool filling, skipCode;
331 	int32 len;
332 	int i, p;
333 	uint32 pitches[16];
334 
335 	i = bw;
336 	for (p = 0; p < 16; ++p) {
337 		pitches[p] = (p >> 2) * pitch + (p & 0x3);
338 	}
339 	code = 0;
340 	filling = false;
341 	len = -1;
342 	while (1) {
343 		if (len < 0) {
344 			filling = (*src & 1) == 1;
345 			len = *src++ >> 1;
346 			skipCode = false;
347 		} else {
348 			skipCode = true;
349 		}
350 		if (!filling || !skipCode) {
351 			code = *src++;
352 			if (code == 0xFF) {
353 				--len;
354 				for (p = 0; p < 0x10; ++p) {
355 					if (len < 0) {
356 						filling = (*src & 1) == 1;
357 						len = *src++ >> 1;
358 						if (filling) {
359 							code = *src++;
360 						}
361 					}
362 					if (filling) {
363 						*(dst + pitches[p]) = code;
364 					} else {
365 						*(dst + pitches[p]) = *src++;
366 					}
367 					--len;
368 				}
369 				dst += 4;
370 				--i;
371 				if (i == 0) {
372 					dst += pitch * 3;
373 					--bh;
374 					if (bh == 0) return;
375 					i = bw;
376 				}
377 				continue;
378 			}
379 		}
380 		byte *dst2 = dst + offset_table[code] + next_offs;
381 		COPY_4X4(dst2, dst, pitch);
382 		--i;
383 		if (i == 0) {
384 			dst += pitch * 3;
385 			--bh;
386 			if (bh == 0) return;
387 			i = bw;
388 		}
389 		--len;
390 	}
391 }
392 
proc3WithFDFE(byte * dst,const byte * src,int32 next_offs,int bw,int bh,int pitch,int16 * offset_table)393 void Codec37Decoder::proc3WithFDFE(byte *dst, const byte *src, int32 next_offs, int bw, int bh, int pitch, int16 *offset_table) {
394 	do {
395 		int32 i = bw;
396 		do {
397 			int32 code = *src++;
398 			if (code == 0xFD) {
399 				LITERAL_4X4(src, dst, pitch);
400 			} else if (code == 0xFE) {
401 				LITERAL_4X1(src, dst, pitch);
402 			} else if (code == 0xFF) {
403 				LITERAL_1X1(src, dst, pitch);
404 			} else {
405 				byte *dst2 = dst + _offsetTable[code] + next_offs;
406 				COPY_4X4(dst2, dst, pitch);
407 			}
408 		} while (--i);
409 		dst += pitch * 3;
410 	} while (--bh);
411 }
412 
proc3WithoutFDFE(byte * dst,const byte * src,int32 next_offs,int bw,int bh,int pitch,int16 * offset_table)413 void Codec37Decoder::proc3WithoutFDFE(byte *dst, const byte *src, int32 next_offs, int bw, int bh, int pitch, int16 *offset_table) {
414 	do {
415 		int32 i = bw;
416 		do {
417 			int32 code = *src++;
418 			if (code == 0xFF) {
419 				LITERAL_1X1(src, dst, pitch);
420 			} else {
421 				byte *dst2 = dst + _offsetTable[code] + next_offs;
422 				COPY_4X4(dst2, dst, pitch);
423 			}
424 		} while (--i);
425 		dst += pitch * 3;
426 	} while (--bh);
427 }
428 
proc4WithFDFE(byte * dst,const byte * src,int32 next_offs,int bw,int bh,int pitch,int16 * offset_table)429 void Codec37Decoder::proc4WithFDFE(byte *dst, const byte *src, int32 next_offs, int bw, int bh, int pitch, int16 *offset_table) {
430 	do {
431 		int32 i = bw;
432 		do {
433 			int32 code = *src++;
434 			if (code == 0xFD) {
435 				LITERAL_4X4(src, dst, pitch);
436 			} else if (code == 0xFE) {
437 				LITERAL_4X1(src, dst, pitch);
438 			} else if (code == 0xFF) {
439 				LITERAL_1X1(src, dst, pitch);
440 			} else if (code == 0x00) {
441 				int32 length = *src++ + 1;
442 				for (int32 l = 0; l < length; l++) {
443 					byte *dst2 = dst + next_offs;
444 					COPY_4X4(dst2, dst, pitch);
445 					i--;
446 					if (i == 0) {
447 						dst += pitch * 3;
448 						bh--;
449 						i = bw;
450 					}
451 				}
452 				if (bh == 0) {
453 					return;
454 				}
455 				i++;
456 			} else {
457 				byte *dst2 = dst + _offsetTable[code] + next_offs;
458 				COPY_4X4(dst2, dst, pitch);
459 			}
460 		} while (--i);
461 		dst += pitch * 3;
462 	} while (--bh);
463 }
464 
proc4WithoutFDFE(byte * dst,const byte * src,int32 next_offs,int bw,int bh,int pitch,int16 * offset_table)465 void Codec37Decoder::proc4WithoutFDFE(byte *dst, const byte *src, int32 next_offs, int bw, int bh, int pitch, int16 *offset_table) {
466 	do {
467 		int32 i = bw;
468 		do {
469 			int32 code = *src++;
470 			if (code == 0xFF) {
471 				LITERAL_1X1(src, dst, pitch);
472 			} else if (code == 0x00) {
473 				int32 length = *src++ + 1;
474 				for (int32 l = 0; l < length; l++) {
475 					byte *dst2 = dst + next_offs;
476 					COPY_4X4(dst2, dst, pitch);
477 					i--;
478 					if (i == 0) {
479 						dst += pitch * 3;
480 						bh--;
481 						i = bw;
482 					}
483 				}
484 				if (bh == 0) {
485 					return;
486 				}
487 				i++;
488 			} else {
489 				byte *dst2 = dst + _offsetTable[code] + next_offs;
490 				COPY_4X4(dst2, dst, pitch);
491 			}
492 		} while (--i);
493 		dst += pitch * 3;
494 	} while (--bh);
495 }
496 
decode(byte * dst,const byte * src)497 void Codec37Decoder::decode(byte *dst, const byte *src) {
498 	int32 bw = (_width + 3) / 4, bh = (_height + 3) / 4;
499 	int32 pitch = bw * 4;
500 
501 	int16 seq_nb = READ_LE_UINT16(src + 2);
502 	int32 decoded_size = READ_LE_UINT32(src + 4);
503 	byte mask_flags = src[12];
504 	maketable(pitch, src[1]);
505 	int32 tmp;
506 
507 	switch (src[0]) {
508 	case 0:
509 		if ((_deltaBufs[_curtable] - _deltaBuf) > 0) {
510 			memset(_deltaBuf, 0, _deltaBufs[_curtable] - _deltaBuf);
511 		}
512 		tmp = (_deltaBuf + _deltaSize) - _deltaBufs[_curtable] - decoded_size;
513 		if (tmp > 0) {
514 			memset(_deltaBufs[_curtable] + decoded_size, 0, tmp);
515 		}
516 		memcpy(_deltaBufs[_curtable], src + 16, decoded_size);
517 		break;
518 	case 1:
519 		if ((seq_nb & 1) || !(mask_flags & 1)) {
520 			_curtable ^= 1;
521 		}
522 		proc1(_deltaBufs[_curtable], src + 16, _deltaBufs[_curtable ^ 1] - _deltaBufs[_curtable],
523 										bw, bh, pitch, _offsetTable);
524 		break;
525 	case 2:
526 		bompDecodeLine(_deltaBufs[_curtable], src + 16, decoded_size);
527 		if ((_deltaBufs[_curtable] - _deltaBuf) > 0) {
528 			memset(_deltaBuf, 0, _deltaBufs[_curtable] - _deltaBuf);
529 		}
530 		tmp = (_deltaBuf + _deltaSize) - _deltaBufs[_curtable] - decoded_size;
531 		if (tmp > 0) {
532 			memset(_deltaBufs[_curtable] + decoded_size, 0, tmp);
533 		}
534 		break;
535 	case 3:
536 		if ((seq_nb & 1) || !(mask_flags & 1)) {
537 			_curtable ^= 1;
538 		}
539 
540 		if ((mask_flags & 4) != 0) {
541 			proc3WithFDFE(_deltaBufs[_curtable], src + 16,
542 										_deltaBufs[_curtable ^ 1] - _deltaBufs[_curtable], bw, bh,
543 										pitch, _offsetTable);
544 		} else {
545 			proc3WithoutFDFE(_deltaBufs[_curtable], src + 16,
546 										_deltaBufs[_curtable ^ 1] - _deltaBufs[_curtable], bw, bh,
547 										pitch, _offsetTable);
548 		}
549 		break;
550 	case 4:
551 		if ((seq_nb & 1) || !(mask_flags & 1)) {
552 			_curtable ^= 1;
553 		}
554 
555 		if ((mask_flags & 4) != 0) {
556 			proc4WithFDFE(_deltaBufs[_curtable], src + 16,
557 										_deltaBufs[_curtable ^ 1] - _deltaBufs[_curtable], bw, bh,
558 										pitch, _offsetTable);
559 		} else {
560 			proc4WithoutFDFE(_deltaBufs[_curtable], src + 16,
561 										_deltaBufs[_curtable ^ 1] - _deltaBufs[_curtable], bw, bh,
562 										pitch, _offsetTable);
563 		}
564 		break;
565 	default:
566 		break;
567 	}
568 	_prevSeqNb = seq_nb;
569 
570 	memcpy(dst, _deltaBufs[_curtable], _frameSize);
571 }
572 
573 } // End of namespace Scumm
574