1 // Generated automatically with "cito". Do not edit.
2 #include <assert.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include "recoil.h"
6 
CiString_Substring(const char * str,int len)7 static char *CiString_Substring(const char *str, int len)
8 {
9 	char *p = malloc(len + 1);
10 	memcpy(p, str, len);
11 	p[len] = '\0';
12 	return p;
13 }
14 
CiString_Append(char ** str,const char * suffix)15 static void CiString_Append(char **str, const char *suffix)
16 {
17 	size_t suffixLen = strlen(suffix);
18 	if (suffixLen == 0)
19 		return;
20 	size_t prefixLen = strlen(*str);
21 	*str = realloc(*str, prefixLen + suffixLen + 1);
22 	memcpy(*str + prefixLen, suffix, suffixLen + 1);
23 }
24 
25 typedef void (*CiMethodPtr)(void *);
26 typedef struct {
27 	size_t count;
28 	size_t unitSize;
29 	size_t refCount;
30 	CiMethodPtr destructor;
31 } CiShared;
32 
CiShared_Make(size_t count,size_t unitSize,CiMethodPtr constructor,CiMethodPtr destructor)33 static void *CiShared_Make(size_t count, size_t unitSize, CiMethodPtr constructor, CiMethodPtr destructor)
34 {
35 	CiShared *self = (CiShared *) malloc(sizeof(CiShared) + count * unitSize);
36 	self->count = count;
37 	self->unitSize = unitSize;
38 	self->refCount = 1;
39 	self->destructor = destructor;
40 	if (constructor != NULL) {
41 		for (size_t i = 0; i < count; i++)
42 			constructor((char *) (self + 1) + i * unitSize);
43 	}
44 	return self + 1;
45 }
46 
CiShared_Release(void * ptr)47 static void CiShared_Release(void *ptr)
48 {
49 	if (ptr == NULL)
50 		return;
51 	CiShared *self = (CiShared *) ptr - 1;
52 	if (--self->refCount != 0)
53 		return;
54 	if (self->destructor != NULL) {
55 		for (size_t i = self->count; i > 0;)
56 			self->destructor((char *) ptr + --i * self->unitSize);
57 	}
58 	free(self);
59 }
60 
CiShared_Assign(void ** ptr,void * value)61 static void CiShared_Assign(void **ptr, void *value)
62 {
63 	CiShared_Release(*ptr);
64 	*ptr = value;
65 }
66 
67 /**
68  * Platform and pixel ratio.
69  */
70 typedef enum {
71 	RECOILResolution_AMIGA1X1,
72 	RECOILResolution_AMIGA2X1,
73 	RECOILResolution_AMIGA4X1,
74 	RECOILResolution_AMIGA8X1,
75 	RECOILResolution_AMIGA1X2,
76 	RECOILResolution_AMIGA1X4,
77 	RECOILResolution_AMSTRAD1X1,
78 	RECOILResolution_AMSTRAD2X1,
79 	RECOILResolution_AMSTRAD1X2,
80 	RECOILResolution_APPLE_I_I1X1,
81 	RECOILResolution_APPLE_I_IE1X2,
82 	RECOILResolution_APPLE_I_I_G_S1X1,
83 	RECOILResolution_APPLE_I_I_G_S1X2,
84 	RECOILResolution_MACINTOSH1X1,
85 	RECOILResolution_XE1X1,
86 	RECOILResolution_XE2X1,
87 	RECOILResolution_XE4X1,
88 	RECOILResolution_XE2X2,
89 	RECOILResolution_XE4X2,
90 	RECOILResolution_XE4X4,
91 	RECOILResolution_XE8X8,
92 	RECOILResolution_PORTFOLIO1X1,
93 	RECOILResolution_ST1X1,
94 	RECOILResolution_ST1X2,
95 	RECOILResolution_STE1X1,
96 	RECOILResolution_STE1X2,
97 	RECOILResolution_TT1X1,
98 	RECOILResolution_TT2X1,
99 	RECOILResolution_FALCON1X1,
100 	RECOILResolution_FALCON2X1,
101 	RECOILResolution_BBC1X1,
102 	RECOILResolution_BBC2X1,
103 	RECOILResolution_BBC1X2,
104 	RECOILResolution_VIC202X1,
105 	RECOILResolution_C161X1,
106 	RECOILResolution_C162X1,
107 	RECOILResolution_C641X1,
108 	RECOILResolution_C642X1,
109 	RECOILResolution_C1281X1,
110 	RECOILResolution_ELECTRONIKA1X1,
111 	RECOILResolution_FM_TOWNS1X1,
112 	RECOILResolution_MSX11X1,
113 	RECOILResolution_MSX14X4,
114 	RECOILResolution_MSX21X1,
115 	RECOILResolution_MSX22X1,
116 	RECOILResolution_MSX21X2,
117 	RECOILResolution_MSX2_PLUS1X1,
118 	RECOILResolution_MSX2_PLUS2X1,
119 	RECOILResolution_ORIC1X1,
120 	RECOILResolution_PC1X1,
121 	RECOILResolution_PC801X2,
122 	RECOILResolution_PC881X2,
123 	RECOILResolution_PC88_VA1X1,
124 	RECOILResolution_PC981X1,
125 	RECOILResolution_PLAY_STATION1X1,
126 	RECOILResolution_PSION31X1,
127 	RECOILResolution_SAM_COUPE1X1,
128 	RECOILResolution_X68_K1X1,
129 	RECOILResolution_SPECTRUM1X1,
130 	RECOILResolution_SPECTRUM4X4,
131 	RECOILResolution_TIMEX1X1,
132 	RECOILResolution_TIMEX1X2,
133 	RECOILResolution_TRS1X1,
134 	RECOILResolution_TRS1X2,
135 	RECOILResolution_COCO1X1,
136 	RECOILResolution_COCO2X2,
137 	RECOILResolution_ZX811X1
138 } RECOILResolution;
139 
140 typedef enum {
141 	IffType_ILBM,
142 	IffType_PBM,
143 	IffType_ACBM,
144 	IffType_RGB8,
145 	IffType_RGBN
146 } IffType;
147 
148 typedef enum {
149 	IceFrameMode_GR0,
150 	IceFrameMode_GR0_GTIA9,
151 	IceFrameMode_GR0_GTIA10,
152 	IceFrameMode_GR0_GTIA11,
153 	IceFrameMode_GR12,
154 	IceFrameMode_GR12_GTIA9,
155 	IceFrameMode_GR12_GTIA10,
156 	IceFrameMode_GR12_GTIA11,
157 	IceFrameMode_GR13_GTIA9,
158 	IceFrameMode_GR13_GTIA10,
159 	IceFrameMode_GR13_GTIA11
160 } IceFrameMode;
161 
162 typedef enum {
163 	AnticMode_BLANK,
164 	AnticMode_FOUR_COLOR,
165 	AnticMode_FIVE_COLOR,
166 	AnticMode_HI_RES
167 } AnticMode;
168 typedef struct Stream Stream;
169 typedef struct EndianStream EndianStream;
170 typedef struct DaliStream DaliStream;
171 typedef struct ZxpStream ZxpStream;
172 typedef struct SprStream SprStream;
173 typedef struct BitStream BitStream;
174 typedef struct X68KPicStream X68KPicStream;
175 typedef struct Mx1Stream Mx1Stream;
176 typedef struct MppPaletteStream MppPaletteStream;
177 typedef struct MultiPalette MultiPalette;
178 typedef struct ArtPalette ArtPalette;
179 typedef struct RastPalette RastPalette;
180 typedef struct HblPalette HblPalette;
181 typedef struct CtblPalette CtblPalette;
182 typedef struct ShamLacePalette ShamLacePalette;
183 typedef struct PchgPalette PchgPalette;
184 typedef struct RleStream RleStream;
185 typedef struct BldStream BldStream;
186 typedef struct DaVinciStream DaVinciStream;
187 typedef struct BbgStream BbgStream;
188 typedef struct MspStream MspStream;
189 typedef struct C64KoalaStream C64KoalaStream;
190 typedef struct GoDotStream GoDotStream;
191 typedef struct CmpStream CmpStream;
192 typedef struct DrpStream DrpStream;
193 typedef struct HpmStream HpmStream;
194 typedef struct PgcStream PgcStream;
195 typedef struct ScStream ScStream;
196 typedef struct CciStream CciStream;
197 typedef struct PackBitsStream PackBitsStream;
198 typedef struct SpcStream SpcStream;
199 typedef struct SpsStream SpsStream;
200 typedef struct ArtMaster88Stream ArtMaster88Stream;
201 typedef struct SrStream SrStream;
202 typedef struct PacStream PacStream;
203 typedef struct XlpStream XlpStream;
204 typedef struct AmstradStream AmstradStream;
205 typedef struct CpiStream CpiStream;
206 typedef struct XeKoalaStream XeKoalaStream;
207 typedef struct ImgStream ImgStream;
208 typedef struct CaStream CaStream;
209 typedef struct RgbStream RgbStream;
210 typedef struct TnyPcsStream TnyPcsStream;
211 typedef struct TnyStream TnyStream;
212 typedef struct PcsStream PcsStream;
213 typedef struct VdatStream VdatStream;
214 typedef struct HimStream HimStream;
215 typedef struct IcStream IcStream;
216 typedef struct DeepStream DeepStream;
217 typedef struct PackBytesStream PackBytesStream;
218 typedef struct Lz4Stream Lz4Stream;
219 typedef struct Tre1Stream Tre1Stream;
220 typedef struct Nl3Stream Nl3Stream;
221 typedef struct SfdnStream SfdnStream;
222 typedef struct G9bStream G9bStream;
223 typedef struct MigStream MigStream;
224 typedef struct Ice21Stream Ice21Stream;
225 typedef struct SpxStream SpxStream;
226 typedef struct Q4Stream Q4Stream;
227 typedef struct PiStream PiStream;
228 typedef struct A4rStream A4rStream;
229 typedef struct FanoTree FanoTree;
230 typedef struct RecentInts RecentInts;
231 typedef struct BlazingPaddlesBoundingBox BlazingPaddlesBoundingBox;
232 typedef struct IcnParser IcnParser;
233 typedef struct PInterpreter PInterpreter;
234 typedef struct GtiaRenderer GtiaRenderer;
235 typedef struct HcmRenderer HcmRenderer;
236 typedef struct GedRenderer GedRenderer;
237 typedef struct PgrRenderer PgrRenderer;
238 typedef struct MchRenderer MchRenderer;
239 typedef struct G2fRenderer G2fRenderer;
240 typedef struct InflateStream InflateStream;
241 
242 /**
243  * Read-only stream backed by a byte array.
244  */
245 struct Stream {
246 	uint8_t const *content;
247 	int contentOffset;
248 	int contentLength;
249 };
250 
251 /**
252  * Returns the next byte or -1 on EOF.
253  * @param self This <code>Stream</code>.
254  */
255 static int Stream_ReadByte(Stream *self);
256 
257 /**
258  * Advances the stream until after the first byte with the given value.
259  * Returns <code>false</code> on EOF.
260  * @param self This <code>Stream</code>.
261  */
262 static bool Stream_SkipUntilByte(Stream *self, int expected);
263 
264 /**
265  * Reads <code>count</code> bytes to <code>dest</code> starting at <code>destOffset</code>.
266  * Returns <code>true</code> on success, <code>false</code> if not enough data.
267  * @param self This <code>Stream</code>.
268  */
269 static bool Stream_ReadBytes(Stream *self, uint8_t *dest, int destOffset, int count);
270 
271 /**
272  * Reads a hexadecimal ASCII digit and returns its value.
273  * If there's no digit at the current stream position,
274  * leaves the position intact and returns -1.
275  * @param self This <code>Stream</code>.
276  */
277 static int Stream_ReadHexDigit(Stream *self);
278 
279 /**
280  * Reads a decimal integer in range 0-32000
281  * stored as ASCII digits followed by CRLF.
282  * Returns -1 on error.
283  * @param self This <code>Stream</code>.
284  */
285 static int Stream_ParseInt(Stream *self);
286 
287 /**
288  * Read-only stream with selectable endianess (little/big)
289  * for reading 16- and 32-bit integers.
290  */
291 struct EndianStream {
292 	Stream base;
293 	bool bigEndian;
294 };
295 
296 /**
297  * Reads a 16-bit unsigned integer.
298  * Returns -1 on EOF.
299  * @param self This <code>EndianStream</code>.
300  */
301 static int EndianStream_ReadWord(EndianStream *self);
302 
303 /**
304  * Reads a 32-bit integer assuming there's enough data.
305  * @param self This <code>EndianStream</code>.
306  */
307 static int EndianStream_ReadInt(EndianStream *self);
308 
309 struct DaliStream {
310 	Stream base;
311 };
312 
313 static bool DaliStream_Decode(DaliStream *self, int countLength, RECOIL *recoil, int paletteOffset, int mode);
314 
315 struct ZxpStream {
316 	Stream base;
317 };
318 
319 static int ZxpStream_ReadChar(ZxpStream *self);
320 
321 static bool ZxpStream_IsEof(const ZxpStream *self);
322 
323 struct SprStream {
324 	Stream base;
325 };
326 
327 /**
328  * Reads an integer in range 0 - Width-1
329  * in base <code>b</code>.
330  * returns -1 on error.
331  * @param self This <code>SprStream</code>.
332  */
333 static int SprStream_ReadBase(SprStream *self, int b);
334 
335 /**
336  * Reads a decimal, hexadecimal (with <code>$</code> prefix)
337  * or binary (with <code>%</code> prefix) integer.
338  * Skips leading whitespace.
339  * Returns -1 on error.
340  * @param self This <code>SprStream</code>.
341  */
342 static int SprStream_ReadInt(SprStream *self);
343 
344 typedef struct {
345 	int (*readBit)(BitStream *self);
346 } BitStreamVtbl;
347 /**
348  * Readable in-memory stream of bits, most-significant bit first.
349  */
350 struct BitStream {
351 	const BitStreamVtbl *vtbl;
352 	Stream base;
353 	int bits;
354 };
355 static void BitStream_Construct(BitStream *self);
356 
357 /**
358  * Reads one bit (0 or 1).
359  * Returns -1 on end of stream.
360  * @param self This <code>BitStream</code>.
361  */
362 static int BitStream_ReadBit(BitStream *self);
363 
364 /**
365  * Reads the requested number of bits and returns them
366  * as an unsigned integer with the first bit read as the most significant.
367  * Returns -1 on end of stream.
368  * @param self This <code>BitStream</code>.
369  */
370 static int BitStream_ReadBits(BitStream *self, int count);
371 
372 static int BitStream_ReadNl3Char(BitStream *self, bool skipSpace);
373 
374 struct X68KPicStream {
375 	BitStream base;
376 };
377 static void X68KPicStream_Construct(X68KPicStream *self);
378 
379 static int X68KPicStream_ReadLength(X68KPicStream *self);
380 
381 struct Mx1Stream {
382 	X68KPicStream base;
383 	uint8_t decodeTable[256];
384 };
385 static void Mx1Stream_Construct(Mx1Stream *self);
386 
387 static bool Mx1Stream_FindImage(Mx1Stream *self);
388 
389 static int Mx1Stream_ReadBit(Mx1Stream *self);
390 
391 struct MppPaletteStream {
392 	BitStream base;
393 };
394 static void MppPaletteStream_Construct(MppPaletteStream *self);
395 
396 static int MppPaletteStream_Read(MppPaletteStream *self);
397 
398 typedef struct {
399 	int (*readBit)(BitStream *self);
400 	void (*setLinePalette)(MultiPalette *self, RECOIL *recoil, int y);
401 } MultiPaletteVtbl;
402 struct MultiPalette {
403 	BitStream base;
404 };
405 static void MultiPalette_Construct(MultiPalette *self);
406 
407 struct ArtPalette {
408 	MultiPalette base;
409 };
410 static void ArtPalette_Construct(ArtPalette *self);
411 
412 static void ArtPalette_SetLinePalette(ArtPalette *self, RECOIL *recoil, int y);
413 
414 struct RastPalette {
415 	MultiPalette base;
416 	int colors;
417 };
418 static void RastPalette_Construct(RastPalette *self);
419 
420 static void RastPalette_SetLinePalette(RastPalette *self, RECOIL *recoil, int y);
421 
422 struct HblPalette {
423 	MultiPalette base;
424 };
425 static void HblPalette_Construct(HblPalette *self);
426 
427 static bool HblPalette_HasPalette(const HblPalette *self, int row);
428 
429 static bool HblPalette_Init(HblPalette *self);
430 
431 static void HblPalette_SetLinePalette(HblPalette *self, RECOIL *recoil, int y);
432 
433 struct CtblPalette {
434 	MultiPalette base;
435 	int colors;
436 };
437 static void CtblPalette_Construct(CtblPalette *self);
438 
439 static void CtblPalette_SetLinePalette(CtblPalette *self, RECOIL *recoil, int y);
440 
441 struct ShamLacePalette {
442 	MultiPalette base;
443 };
444 static void ShamLacePalette_Construct(ShamLacePalette *self);
445 
446 static void ShamLacePalette_SetLinePalette(ShamLacePalette *self, RECOIL *recoil, int y);
447 
448 struct PchgPalette {
449 	MultiPalette base;
450 	bool ocs;
451 	int startLine;
452 	int lineCount;
453 	uint8_t havePaletteChange[320];
454 	int treeOffset;
455 	int treeLastOffset;
456 	bool compressed;
457 };
458 static void PchgPalette_Construct(PchgPalette *self);
459 
460 static int PchgPalette_ReadHuffman(PchgPalette *self);
461 
462 static bool PchgPalette_Init(PchgPalette *self);
463 
464 static int PchgPalette_UnpackByte(PchgPalette *self);
465 
466 static void PchgPalette_SetOcsColors(PchgPalette *self, RECOIL *recoil, int paletteOffset, int count);
467 
468 static void PchgPalette_SetLinePalette(PchgPalette *self, RECOIL *recoil, int y);
469 
470 typedef struct {
471 	int (*readBit)(BitStream *self);
472 	bool (*readCommand)(RleStream *self);
473 	int (*readValue)(RleStream *self);
474 } RleStreamVtbl;
475 /**
476  * Readable in-memory Run-Length-Encoded stream.
477  * This class contains the compression logic.
478  * Subclasses must implement <code>ReadCommand()</code>
479  * and are allowed to override <code>ReadValue()</code>.
480  */
481 struct RleStream {
482 	BitStream base;
483 	int repeatCount;
484 	int repeatValue;
485 };
486 static void RleStream_Construct(RleStream *self);
487 
488 static int RleStream_ReadValue(RleStream *self);
489 
490 /**
491  * Returns the next uncompressed byte or -1 on error.
492  * @param self This <code>RleStream</code>.
493  */
494 static int RleStream_ReadRle(RleStream *self);
495 
496 /**
497  * Uncompresses bytes to <code>unpacked[unpackedOffset]</code>,<code>unpacked[unpackedOffset + unpackedStride]</code>,<code>unpacked[unpackedOffset + 2 * unpackedStride]</code>,
498  * ... until indexes are smaller than <code>unpackedEnd</code>.
499  * Returns <code>true</code> on success, <code>false</code> on error.
500  * @param self This <code>RleStream</code>.
501  */
502 static bool RleStream_Unpack(RleStream *self, uint8_t *unpacked, int unpackedOffset, int unpackedStride, int unpackedEnd);
503 
504 /**
505  * Uncompresses laiding out bytes vertically column by column,<code>unpackedStride</code> being line width.
506  * Returns <code>true</code> on success, <code>false</code> on error.
507  * @param self This <code>RleStream</code>.
508  */
509 static bool RleStream_UnpackColumns(RleStream *self, uint8_t *unpacked, int unpackedOffset, int unpackedStride, int unpackedEnd);
510 
511 /**
512  * Uncompresses bytes to <code>unpacked[unpackedOffset]</code>, <code>unpacked[unpackedOffset + 1]</code>,<code>unpacked[unpackedOffset + unpackedStride]</code>, <code>unpacked[unpackedOffset + unpackedStride + 1]</code>,<code>unpacked[unpackedOffset + 2 * unpackedStride]</code>, <code>unpacked[unpackedOffset + 2 * unpackedStride + 1]</code>,
513  * ... until indexes are smaller than <code>unpackedEnd</code>.
514  * Returns <code>true</code> on success, <code>false</code> on error.
515  * @param self This <code>RleStream</code>.
516  */
517 static bool RleStream_UnpackWords(RleStream *self, uint8_t *unpacked, int unpackedOffset, int unpackedStride, int unpackedEnd);
518 
519 /**
520  * Uncompresses after copying two literal bytes.
521  * Returns <code>true</code> on success, <code>false</code> on error.
522  * @param self This <code>RleStream</code>.
523  */
524 static bool RleStream_UnpackC64(RleStream *self, uint8_t *unpacked, int unpackedLength);
525 
526 struct BldStream {
527 	RleStream base;
528 };
529 static void BldStream_Construct(BldStream *self);
530 
531 static bool BldStream_ReadCommand(BldStream *self);
532 
533 struct DaVinciStream {
534 	RleStream base;
535 };
536 static void DaVinciStream_Construct(DaVinciStream *self);
537 
538 static int DaVinciStream_ReadValue(DaVinciStream *self);
539 
540 static bool DaVinciStream_ReadCommand(DaVinciStream *self);
541 
542 struct BbgStream {
543 	RleStream base;
544 	int valueBits;
545 	int countBits;
546 };
547 static void BbgStream_Construct(BbgStream *self);
548 
549 /**
550  * Reads the requested number of bits and returns them
551  * as an unsigned integer with the first bit read as the least significant.
552  * Returns -1 on end of stream.
553  * @param self This <code>BbgStream</code>.
554  */
555 static int BbgStream_ReadBitsReverse(BbgStream *self, int count);
556 
557 static bool BbgStream_ReadCommand(BbgStream *self);
558 
559 struct MspStream {
560 	RleStream base;
561 };
562 static void MspStream_Construct(MspStream *self);
563 
564 static bool MspStream_ReadCommand(MspStream *self);
565 
566 struct C64KoalaStream {
567 	RleStream base;
568 };
569 static void C64KoalaStream_Construct(C64KoalaStream *self);
570 
571 static bool C64KoalaStream_ReadCommand(C64KoalaStream *self);
572 
573 struct GoDotStream {
574 	RleStream base;
575 };
576 static void GoDotStream_Construct(GoDotStream *self);
577 
578 static bool GoDotStream_ReadCommand(GoDotStream *self);
579 
580 struct CmpStream {
581 	RleStream base;
582 	int escape;
583 };
584 static void CmpStream_Construct(CmpStream *self);
585 
586 static bool CmpStream_ReadCommand(CmpStream *self);
587 
588 struct DrpStream {
589 	RleStream base;
590 	int escape;
591 };
592 static void DrpStream_Construct(DrpStream *self);
593 
594 static bool DrpStream_ReadCommand(DrpStream *self);
595 
596 static uint8_t const *DrpStream_UnpackFile(uint8_t const *content, int contentLength, const char *signature, uint8_t *unpacked, int unpackedLength);
597 
598 struct HpmStream {
599 	RleStream base;
600 };
601 static void HpmStream_Construct(HpmStream *self);
602 
603 static bool HpmStream_ReadCommand(HpmStream *self);
604 
605 struct PgcStream {
606 	RleStream base;
607 };
608 static void PgcStream_Construct(PgcStream *self);
609 
610 static bool PgcStream_ReadCommand(PgcStream *self);
611 
612 struct ScStream {
613 	RleStream base;
614 };
615 static void ScStream_Construct(ScStream *self);
616 
617 static bool ScStream_ReadCommand(ScStream *self);
618 
619 struct CciStream {
620 	RleStream base;
621 };
622 static void CciStream_Construct(CciStream *self);
623 
624 static bool CciStream_ReadCommand(CciStream *self);
625 
626 static bool CciStream_UnpackGr15(CciStream *self, uint8_t *unpacked, int unpackedOffset);
627 
628 struct PackBitsStream {
629 	RleStream base;
630 };
631 static void PackBitsStream_Construct(PackBitsStream *self);
632 
633 static bool PackBitsStream_ReadCommand(PackBitsStream *self);
634 
635 static bool PackBitsStream_UnpackBitplaneLines(PackBitsStream *self, uint8_t *unpacked, int width, int height, int bitplanes, bool compressed, bool hasMask);
636 
637 struct SpcStream {
638 	RleStream base;
639 };
640 static void SpcStream_Construct(SpcStream *self);
641 
642 static bool SpcStream_ReadCommand(SpcStream *self);
643 
644 struct SpsStream {
645 	RleStream base;
646 };
647 static void SpsStream_Construct(SpsStream *self);
648 
649 static bool SpsStream_ReadCommand(SpsStream *self);
650 
651 struct ArtMaster88Stream {
652 	RleStream base;
653 	int escape;
654 };
655 static void ArtMaster88Stream_Construct(ArtMaster88Stream *self);
656 
657 static bool ArtMaster88Stream_ReadCommand(ArtMaster88Stream *self);
658 
659 static bool ArtMaster88Stream_SkipChunk(ArtMaster88Stream *self);
660 
661 struct SrStream {
662 	RleStream base;
663 };
664 static void SrStream_Construct(SrStream *self);
665 
666 static bool SrStream_ReadCommand(SrStream *self);
667 
668 struct PacStream {
669 	RleStream base;
670 };
671 static void PacStream_Construct(PacStream *self);
672 
673 static bool PacStream_ReadCommand(PacStream *self);
674 
675 struct XlpStream {
676 	RleStream base;
677 };
678 static void XlpStream_Construct(XlpStream *self);
679 
680 static bool XlpStream_ReadCommand(XlpStream *self);
681 
682 struct AmstradStream {
683 	RleStream base;
684 	int blockLength;
685 };
686 static void AmstradStream_Construct(AmstradStream *self);
687 
688 static bool AmstradStream_ReadCommand(AmstradStream *self);
689 
690 static bool AmstradStream_UnpackFile(uint8_t const *content, int contentOffset, int contentLength, uint8_t *unpacked, int unpackedLength);
691 
692 struct CpiStream {
693 	RleStream base;
694 };
695 static void CpiStream_Construct(CpiStream *self);
696 
697 static bool CpiStream_ReadCommand(CpiStream *self);
698 
699 struct XeKoalaStream {
700 	RleStream base;
701 };
702 static void XeKoalaStream_Construct(XeKoalaStream *self);
703 
704 static bool XeKoalaStream_ReadCommand(XeKoalaStream *self);
705 
706 static bool XeKoalaStream_UnpackRaw(int type, uint8_t const *content, int contentOffset, int contentLength, uint8_t *unpacked, int unpackedLength);
707 
708 static bool XeKoalaStream_UnpackWrapped(uint8_t const *content, int contentLength, uint8_t *unpacked, int unpackedLength);
709 
710 struct ImgStream {
711 	RleStream base;
712 	int patternRepeatCount;
713 };
714 static void ImgStream_Construct(ImgStream *self);
715 
716 static int ImgStream_GetLineRepeatCount(ImgStream *self);
717 
718 static bool ImgStream_ReadCommand(ImgStream *self);
719 
720 struct CaStream {
721 	RleStream base;
722 	int escapeByte;
723 	int defaultValue;
724 };
725 static void CaStream_Construct(CaStream *self);
726 
727 static bool CaStream_ReadCommand(CaStream *self);
728 
729 static bool CaStream_UnpackCa(CaStream *self, uint8_t *unpacked, int unpackedOffset);
730 
731 static bool CaStream_UnpackDel(uint8_t const *content, int contentLength, uint8_t *unpacked, int blocks);
732 
733 struct RgbStream {
734 	RleStream base;
735 };
736 static void RgbStream_Construct(RgbStream *self);
737 
738 static int RgbStream_ReadValue(RgbStream *self);
739 
740 static bool RgbStream_ReadCommand(RgbStream *self);
741 
742 struct TnyPcsStream {
743 	RleStream base;
744 };
745 static void TnyPcsStream_Construct(TnyPcsStream *self);
746 
747 static bool TnyPcsStream_ReadTnyCommand(TnyPcsStream *self);
748 
749 struct TnyStream {
750 	TnyPcsStream base;
751 	int valueOffset;
752 	int valueLength;
753 };
754 static void TnyStream_Construct(TnyStream *self);
755 
756 static bool TnyStream_ReadCommand(TnyStream *self);
757 
758 static int TnyStream_ReadValue(TnyStream *self);
759 
760 struct PcsStream {
761 	TnyPcsStream base;
762 	int commandCount;
763 	bool palette;
764 };
765 static void PcsStream_Construct(PcsStream *self);
766 
767 static bool PcsStream_ReadCommand(PcsStream *self);
768 
769 static int PcsStream_ReadValue(PcsStream *self);
770 
771 static bool PcsStream_StartBlock(PcsStream *self);
772 
773 static bool PcsStream_EndBlock(PcsStream *self);
774 
775 static bool PcsStream_UnpackPcs(PcsStream *self, uint8_t *unpacked);
776 
777 struct VdatStream {
778 	TnyStream base;
779 };
780 static void VdatStream_Construct(VdatStream *self);
781 
782 static bool VdatStream_ReadCommand(VdatStream *self);
783 
784 struct HimStream {
785 	RleStream base;
786 };
787 static void HimStream_Construct(HimStream *self);
788 
789 static int HimStream_ReadValue(HimStream *self);
790 
791 static bool HimStream_ReadCommand(HimStream *self);
792 
793 struct IcStream {
794 	RleStream base;
795 };
796 static void IcStream_Construct(IcStream *self);
797 
798 static bool IcStream_ReadCount(IcStream *self);
799 
800 static bool IcStream_ReadCommand(IcStream *self);
801 
802 struct DeepStream {
803 	PackBitsStream base;
804 	int components;
805 	int componentShift[6];
806 	int currentByte;
807 	int line[10000];
808 };
809 static void DeepStream_Construct(DeepStream *self);
810 
811 static bool DeepStream_SetDpel(DeepStream *self, int chunkOffset, int chunkLength);
812 
813 static int DeepStream_ReadValue(DeepStream *self);
814 
815 static int DeepStream_ReadNibble(DeepStream *self);
816 
817 static bool DeepStream_ReadDeltaLine(DeepStream *self, int width, int tvdcOffset);
818 
819 struct PackBytesStream {
820 	Stream base;
821 	int count;
822 	int pattern;
823 };
824 static void PackBytesStream_Construct(PackBytesStream *self);
825 
826 static int PackBytesStream_ReadUnpacked(PackBytesStream *self);
827 
828 struct Lz4Stream {
829 	Stream base;
830 	uint8_t *unpacked;
831 	int unpackedOffset;
832 	int unpackedLength;
833 };
834 
835 static bool Lz4Stream_Copy(Lz4Stream *self, int count);
836 
837 static int Lz4Stream_ReadCount(Lz4Stream *self, int count);
838 
839 struct Tre1Stream {
840 	RleStream base;
841 	int lastRgb;
842 };
843 static void Tre1Stream_Construct(Tre1Stream *self);
844 
845 static bool Tre1Stream_ReadCommand(Tre1Stream *self);
846 
847 static int Tre1Stream_ReadValue(Tre1Stream *self);
848 
849 struct Nl3Stream {
850 	RleStream base;
851 };
852 static void Nl3Stream_Construct(Nl3Stream *self);
853 
854 static int Nl3Stream_ReadValue(Nl3Stream *self);
855 
856 static bool Nl3Stream_ReadCommand(Nl3Stream *self);
857 
858 struct SfdnStream {
859 	BitStream base;
860 };
861 static void SfdnStream_Construct(SfdnStream *self);
862 
863 static bool SfdnStream_Unpack(SfdnStream *self, uint8_t *unpacked, int unpackedLength);
864 
865 struct G9bStream {
866 	BitStream base;
867 };
868 static void G9bStream_Construct(G9bStream *self);
869 
870 static int G9bStream_ReadLength(G9bStream *self);
871 
872 static bool G9bStream_Unpack(G9bStream *self, uint8_t *unpacked, int headerLength, int unpackedLength);
873 
874 struct MigStream {
875 	BitStream base;
876 };
877 static void MigStream_Construct(MigStream *self);
878 
879 static int MigStream_Unpack(MigStream *self, uint8_t *unpacked);
880 
881 struct Ice21Stream {
882 	uint8_t const *content;
883 	int contentOffset;
884 	int contentStart;
885 	int bits;
886 };
887 
888 static int Ice21Stream_GetUnpackedLength(const Ice21Stream *self);
889 
890 static int Ice21Stream_ReadBit(Ice21Stream *self);
891 
892 static int Ice21Stream_ReadBits(Ice21Stream *self, int count);
893 
894 static int Ice21Stream_CountOnes(Ice21Stream *self, int max);
895 
896 static int Ice21Stream_ReadLiteralLength(Ice21Stream *self);
897 
898 static int Ice21Stream_ReadEncoded(Ice21Stream *self, int maxCount, uint8_t const *extraBits, int const *offsets);
899 
900 static bool Ice21Stream_Unpack(Ice21Stream *self, uint8_t *unpacked, int unpackedStart, int unpackedEnd);
901 
902 struct SpxStream {
903 	Ice21Stream base;
904 };
905 
906 static int SpxStream_ReadCount(SpxStream *self);
907 
908 static bool SpxStream_UnpackV2(SpxStream *self, uint8_t *unpacked, int unpackedLength);
909 
910 struct Q4Stream {
911 	RleStream base;
912 	int codeBits;
913 	uint8_t unpacked[65536];
914 	int lastRepeatValue;
915 };
916 static void Q4Stream_Construct(Q4Stream *self);
917 
918 static int Q4Stream_StartChunk(Q4Stream *self);
919 
920 static int Q4Stream_ReadCode(Q4Stream *self);
921 
922 static bool Q4Stream_UnpackQ4(Q4Stream *self);
923 
924 static bool Q4Stream_ReadCommand(Q4Stream *self);
925 
926 struct PiStream {
927 	BitStream base;
928 	uint8_t *indexes;
929 	uint8_t recentColors[65536];
930 };
931 static void PiStream_Construct(PiStream *self);
932 static void PiStream_Destruct(PiStream *self);
933 
934 static int PiStream_ReadInt(PiStream *self, int bits, int maxBits);
935 
936 static bool PiStream_UnpackLiteral(PiStream *self, int indexesOffset, int depth);
937 
938 static bool PiStream_UnpackTwoLiterals(PiStream *self, int indexesOffset, int indexesLength, int depth);
939 
940 static int PiStream_ReadPosition(PiStream *self);
941 
942 static bool PiStream_Unpack(PiStream *self, int width, int height, int depth);
943 
944 struct A4rStream {
945 	Stream base;
946 	int outerFlags;
947 	int innerFlags;
948 	uint8_t unpacked[11248];
949 	int unpackedOffset;
950 };
951 static void A4rStream_Construct(A4rStream *self);
952 
953 static int A4rStream_ReadFlag(A4rStream *self);
954 
955 static bool A4rStream_CopyByte(A4rStream *self);
956 
957 static bool A4rStream_CopyBlock(A4rStream *self, int distance, int count);
958 
959 static bool A4rStream_UnpackA4r(A4rStream *self);
960 
961 struct FanoTree {
962 	int count[16];
963 	uint8_t values[256];
964 };
965 
966 static void FanoTree_Create(FanoTree *self, uint8_t const *content, int contentOffset, int codeCount);
967 
968 static int FanoTree_ReadCode(const FanoTree *self, BitStream *bitStream);
969 
970 /**
971  * Dictionary of <code>Count</code> key-value pairs.
972  * A key is an integer between zero and <code>Count-1</code>. A value is an int.
973  * The dictionary always contains exactly <code>Count</code> mappings. The values are initially all zeros.
974  * The pairs are ordered by their last usage, from Most Recently Used (MRU) to Least Recently Used (LRU).
975  * When you add or retrieve a value, it becomes the Most Recently Used.
976  * When you add a value, the Least Recently Used is discarded.
977  */
978 struct RecentInts {
979 	int value[128];
980 	uint8_t prev[128];
981 	uint8_t next[128];
982 	int head;
983 };
984 static void RecentInts_Construct(RecentInts *self);
985 
986 /**
987  * Store the value.
988  * Will use the Least Recently Used key.
989  * Its previous value is discarded and now it maps to <code>value</code>
990  * and becomes the Most Recently Used.
991  * @param self This <code>RecentInts</code>.
992  */
993 static void RecentInts_Add(RecentInts *self, int value);
994 
995 /**
996  * Retrieve a value by key.
997  * @param self This <code>RecentInts</code>.
998  */
999 static int RecentInts_Get(RecentInts *self, int key);
1000 
1001 struct BlazingPaddlesBoundingBox {
1002 	int left;
1003 	int top;
1004 	int right;
1005 	int bottom;
1006 };
1007 
1008 static bool BlazingPaddlesBoundingBox_Calculate(BlazingPaddlesBoundingBox *self, uint8_t const *content, int contentLength, int index, int startAddress);
1009 
1010 struct IcnParser {
1011 	Stream base;
1012 };
1013 
1014 static bool IcnParser_SkipWhitespace(IcnParser *self);
1015 
1016 static bool IcnParser_Expect(IcnParser *self, const char *s);
1017 
1018 static int IcnParser_ParseHex(IcnParser *self);
1019 
1020 static int IcnParser_ParseDefine(IcnParser *self, const char *s);
1021 
1022 struct PInterpreter {
1023 	Stream base;
1024 	uint8_t screen[768];
1025 	int screenOffset;
1026 	bool newLineWorks;
1027 	int bottomOffset;
1028 	int bottomCode;
1029 };
1030 
1031 static int PInterpreter_ReadNumber(PInterpreter *self);
1032 
1033 static int PInterpreter_PrintString(PInterpreter *self, int offset);
1034 
1035 static bool PInterpreter_Print(PInterpreter *self);
1036 
1037 static bool PInterpreter_DPeek(PInterpreter *self, int expectedX, int expectedAddress);
1038 
1039 static bool PInterpreter_Let(PInterpreter *self);
1040 
1041 static bool PInterpreter_DoIf(PInterpreter *self);
1042 
1043 static bool PInterpreter_DoFor(PInterpreter *self);
1044 
1045 static bool PInterpreter_Poke(PInterpreter *self);
1046 
1047 static bool PInterpreter_Next(PInterpreter *self);
1048 
1049 static bool PInterpreter_Run(PInterpreter *self);
1050 
1051 typedef struct {
1052 	int (*getHiresColor)(const GtiaRenderer *self, int c);
1053 	int (*getPlayfieldByte)(GtiaRenderer *self, int y, int column);
1054 } GtiaRendererVtbl;
1055 struct GtiaRenderer {
1056 	const GtiaRendererVtbl *vtbl;
1057 	uint8_t playerHpos[4];
1058 	uint8_t missileHpos[4];
1059 	uint8_t playerSize[4];
1060 	uint8_t missileSize[4];
1061 	int playerSizeCounter[4];
1062 	int missileSizeCounter[4];
1063 	uint8_t playerGraphics[4];
1064 	int missileGraphics;
1065 	uint8_t playerShiftRegister[4];
1066 	int missileShiftRegister;
1067 	uint8_t colors[9];
1068 	int prior;
1069 	uint8_t const *content;
1070 	int playfieldColumns;
1071 };
1072 
1073 static void GtiaRenderer_SetPlayerSize(GtiaRenderer *self, int i, int size);
1074 
1075 static void GtiaRenderer_SetSpriteSizes(uint8_t *sizes, int value);
1076 
1077 static void GtiaRenderer_Poke(GtiaRenderer *self, int addr, int value);
1078 
1079 static void GtiaRenderer_ProcessSpriteDma(GtiaRenderer *self, uint8_t const *content, int missileOffset);
1080 
1081 static int GtiaRenderer_GetPmg(GtiaRenderer *self, int hpos, int objects);
1082 
1083 static int GtiaRenderer_GetColor(const GtiaRenderer *self, int objects);
1084 
1085 static void GtiaRenderer_StartLine(GtiaRenderer *self, int startHpos);
1086 
1087 static int GtiaRenderer_GetHiresColor(const GtiaRenderer *self, int c);
1088 
1089 static int GtiaRenderer_DrawSpan(GtiaRenderer *self, int y, int hpos, int untilHpos, AnticMode anticMode, uint8_t *frame, int width);
1090 
1091 static void GtiaRenderer_SetG2fColors(GtiaRenderer *self, int contentOffset, int contentStride, int count, int gtiaMode);
1092 
1093 struct HcmRenderer {
1094 	GtiaRenderer base;
1095 };
1096 static void HcmRenderer_Construct(HcmRenderer *self);
1097 
1098 static int HcmRenderer_GetPlayfieldByte(HcmRenderer *self, int y, int column);
1099 
1100 struct GedRenderer {
1101 	GtiaRenderer base;
1102 };
1103 static void GedRenderer_Construct(GedRenderer *self);
1104 
1105 static int GedRenderer_GetPlayfieldByte(GedRenderer *self, int y, int column);
1106 
1107 struct PgrRenderer {
1108 	GtiaRenderer base;
1109 	int screenOffset;
1110 };
1111 static void PgrRenderer_Construct(PgrRenderer *self);
1112 
1113 static int PgrRenderer_GetPlayfieldByte(PgrRenderer *self, int y, int column);
1114 
1115 struct MchRenderer {
1116 	GtiaRenderer base;
1117 	bool dliPlus;
1118 };
1119 static void MchRenderer_Construct(MchRenderer *self);
1120 
1121 static int MchRenderer_GetPlayfieldByte(MchRenderer *self, int y, int column);
1122 
1123 struct G2fRenderer {
1124 	GtiaRenderer base;
1125 	int fontOffset;
1126 	int inverse2Offset;
1127 	int vbxeOffset;
1128 };
1129 static void G2fRenderer_Construct(G2fRenderer *self);
1130 
1131 static int G2fRenderer_GetHiresColor(const G2fRenderer *self, int c);
1132 
1133 static int G2fRenderer_GetPlayfieldByte(G2fRenderer *self, int y, int column);
1134 
1135 static bool G2fRenderer_SetSprite(uint8_t *hpos, uint8_t *sizes, int i, uint8_t const *content, int spriteOffset);
1136 
1137 struct InflateStream {
1138 	Stream base;
1139 	int bits;
1140 	uint8_t symbolCodeLength[318];
1141 	int nBitCodeCount[32];
1142 	int nBitCodeOffset[32];
1143 	int16_t codeToSymbol[318];
1144 };
1145 
1146 static int InflateStream_ReadBit(InflateStream *self);
1147 
1148 static int InflateStream_ReadBits(InflateStream *self, int count);
1149 
1150 static void InflateStream_BuildHuffmanTrees(InflateStream *self);
1151 
1152 static int InflateStream_FetchCode(InflateStream *self, int tree);
1153 
1154 static int InflateStream_Inflate(InflateStream *self, uint8_t *unpacked, int unpackedLength);
1155 
1156 static int InflateStream_Uncompress(InflateStream *self, uint8_t *unpacked, int unpackedLength);
1157 
1158 typedef struct {
1159 	int (*readFile)(const RECOIL *self, const char *filename, uint8_t *content, int contentLength);
1160 } RECOILVtbl;
1161 /**
1162  * Decoder of images in formats native to vintage computers.
1163  * Decodes file contents passed as a byte array
1164  * into a 24-bit RGB bitmap.
1165  */
1166 struct RECOIL {
1167 	const RECOILVtbl *vtbl;
1168 	int width;
1169 	int height;
1170 	int pixels[2854278];
1171 	RECOILResolution resolution;
1172 	int frames;
1173 	int leftSkip;
1174 	int contentPalette[256];
1175 	int atari8Palette[256];
1176 	uint8_t gtiaColors[16];
1177 	uint8_t colorInUse[2097152];
1178 	int colors;
1179 	int palette[256];
1180 };
1181 static void RECOIL_Construct(RECOIL *self);
1182 static const int RECOIL_BBC_PALETTE[16] = { 0, 16711680, 65280, 16776960, 255, 16711935, 65535, 16777215, 0, 16711680, 65280, 16776960, 255, 16711935, 65535, 16777215 };
1183 static const int RECOIL_BBC_PALETTE2_BIT[4] = { 0, 16711680, 16776960, 16777215 };
1184 static const int RECOIL_BBC_PALETTE1_BIT[2] = { 0, 16777215 };
1185 static const int RECOIL_AMSTRAD_PALETTE[32] = { 8421504, 8421504, 65408, 16777088, 128, 16711808, 32896, 16744576, 16711808, 16777088, 16776960, 16777215, 16711680, 16711935, 16744448, 16744703,
1186 	128, 65408, 65280, 65535, 0, 255, 32768, 33023, 8388736, 8454016, 8453888, 8454143, 8388608, 8388863, 8421376, 8421631 };
1187 static const uint8_t RECOIL_MSX2_DEFAULT_PALETTE[32] = { 0, 0, 0, 0, 17, 6, 51, 7, 23, 1, 39, 3, 81, 1, 39, 6,
1188 	113, 1, 115, 3, 97, 6, 100, 6, 17, 4, 101, 2, 85, 5, 119, 7 };
1189 static const int RECOIL_C64_PALETTE[16] = { 0, 16777215, 6829867, 7382194, 7290246, 5803331, 3483769, 12109679, 7294757, 4405504, 10119001, 4473924, 7105644, 10146436, 7102133, 9803157 };
1190 
1191 /**
1192  * Initializes decoded image size and resolution.
1193  * @param self This <code>RECOIL</code>.
1194  */
1195 static bool RECOIL_SetSize(RECOIL *self, int width, int height, RECOILResolution resolution);
1196 
1197 static bool RECOIL_SetSizeStOrFalcon(RECOIL *self, int width, int height, int bitplanes, bool squarePixels);
1198 
1199 static bool RECOIL_SetScaledSize(RECOIL *self, int width, int height, RECOILResolution resolution);
1200 
1201 static void RECOIL_SetScaledPixel(RECOIL *self, int x, int y, int rgb);
1202 
1203 /**
1204  * Reads a 32-bit big endian integer from a byte array.
1205  */
1206 static int RECOIL_Get32BigEndian(uint8_t const *content, int contentOffset);
1207 
1208 /**
1209  * Reads a 32-bit little endian integer from a byte array.
1210  */
1211 static int RECOIL_Get32LittleEndian(uint8_t const *content, int contentOffset);
1212 
1213 static int RECOIL_GetNibble(uint8_t const *content, int contentOffset, int index);
1214 
1215 static bool RECOIL_IsStringAt(uint8_t const *content, int contentOffset, const char *s);
1216 
1217 static bool RECOIL_CopyPrevious(uint8_t *unpacked, int unpackedOffset, int distance, int count);
1218 
1219 static bool RECOIL_ApplyBlend(RECOIL *self);
1220 
1221 /**
1222  * Reads a companion file to the specified byte array.
1223  * Implement this method in a subclass to enable support for multi-file images.
1224  * Returns the number of bytes read (up to <code>contentLength</code>) or -1 on error.
1225  * @param self This <code>RECOIL</code>.
1226  * @param filename Name of the file to read.
1227  * @param content Out: target for the file contents.
1228  * @param contentLength Maximum number of bytes to read.
1229  */
1230 static int RECOIL_ReadFile(const RECOIL *self, const char *filename, uint8_t *content, int contentLength);
1231 
1232 static int RECOIL_ReadCompanionFile(const RECOIL *self, const char *baseFilename, const char *upperExt, const char *lowerExt, uint8_t *content, int contentLength);
1233 
1234 static bool RECOIL_DecodeBru(RECOIL *self, uint8_t const *content, int contentLength);
1235 
1236 static void RECOIL_DecodeBytes(RECOIL *self, uint8_t const *content, int contentOffset);
1237 
1238 static void RECOIL_DecodeNibbles(RECOIL *self, uint8_t const *content, int contentOffset, int contentStride);
1239 
1240 static int RECOIL_GetB5G5R5Color(int c);
1241 
1242 static int RECOIL_GetR5G5B5Color(int c);
1243 
1244 static int RECOIL_GetG6R5B5Color(int c);
1245 
1246 static int RECOIL_Get729Color(int c);
1247 
1248 static int RECOIL_GetFalconTrueColor(uint8_t const *content, int contentOffset);
1249 
1250 static int RECOIL_GetBitplanePixel(uint8_t const *content, int contentOffset, int x, int bitplanes, int bytesPerBitplane);
1251 
1252 static int RECOIL_GetBitplaneWordsPixel(uint8_t const *content, int contentOffset, int x, int bitplanes);
1253 
1254 /**
1255  * Decodes Atari ST/Falcon interleaved bitplanes.
1256  * Each 16 pixels are encoded in N consecutive 16-bit words.
1257  * @param self This <code>RECOIL</code>.
1258  */
1259 static void RECOIL_DecodeBitplanes(RECOIL *self, uint8_t const *content, int contentOffset, int contentStride, int bitplanes, int pixelsOffset, int width, int height);
1260 
1261 static void RECOIL_DecodeScaledBitplanes(RECOIL *self, uint8_t const *content, int contentOffset, int width, int height, int bitplanes, bool ehb, MultiPalette *multiPalette);
1262 
1263 static bool RECOIL_DecodeMono(RECOIL *self, uint8_t const *content, int contentOffset, int contentLength, bool wordAlign);
1264 
1265 static bool RECOIL_DecodeBlackAndWhite(RECOIL *self, uint8_t const *content, int contentOffset, int contentLength, bool wordAlign, int backgroundColor);
1266 
1267 static bool RECOIL_DecodeRleBlackAndWhite(RECOIL *self, RleStream *rle, int backgroundColor);
1268 
1269 static void RECOIL_DecodeBlackAndWhiteFont(RECOIL *self, uint8_t const *content, int contentOffset, int contentLength, int fontHeight);
1270 
1271 static bool RECOIL_DecodePgf(RECOIL *self, uint8_t const *content, int contentLength);
1272 
1273 static bool RECOIL_DecodePgc(RECOIL *self, uint8_t const *content, int contentLength);
1274 
1275 static bool RECOIL_DecodePsion3Pic(RECOIL *self, uint8_t const *content, int contentLength);
1276 
1277 static bool RECOIL_DecodeTrsHr(RECOIL *self, uint8_t const *content, int contentLength);
1278 
1279 static bool RECOIL_DecodeTrsShr(RECOIL *self, uint8_t const *content, int contentLength);
1280 
1281 static bool RECOIL_DecodeRle(RECOIL *self, uint8_t const *content, int contentLength);
1282 
1283 static bool RECOIL_DecodeClp(RECOIL *self, uint8_t const *content, int contentLength);
1284 
1285 static bool RECOIL_DecodeCocoMax(RECOIL *self, uint8_t const *content, int contentLength);
1286 
1287 static bool RECOIL_DecodeP11(RECOIL *self, uint8_t const *content, int contentLength);
1288 
1289 static bool RECOIL_DecodeMac(RECOIL *self, uint8_t const *content, int contentLength);
1290 
1291 static void RECOIL_DecodePlayStation(uint8_t const *content, int contentOffset, int *pixels, int pixelsLength);
1292 
1293 static int RECOIL_DecodeTimPalette(RECOIL *self, uint8_t const *content, int contentLength, int colors);
1294 
1295 static bool RECOIL_DecodeTim(RECOIL *self, uint8_t const *content, int contentLength);
1296 
1297 static bool RECOIL_DecodeBb0(RECOIL *self, uint8_t const *content, int contentLength, int const *palette);
1298 
1299 static bool RECOIL_DecodeBb1(RECOIL *self, uint8_t const *content, int contentLength, int const *palette);
1300 
1301 static bool RECOIL_DecodeBb2(RECOIL *self, uint8_t const *content, int contentLength, int const *palette);
1302 
1303 static bool RECOIL_DecodeBb4(RECOIL *self, uint8_t const *content, int contentLength, int const *palette);
1304 
1305 static bool RECOIL_DecodeBb5(RECOIL *self, uint8_t const *content, int contentLength, int const *palette);
1306 
1307 static bool RECOIL_DecodeBbg(RECOIL *self, uint8_t const *content, int contentLength);
1308 
1309 static int RECOIL_GetOricHeader(uint8_t const *content, int contentLength);
1310 
1311 static bool RECOIL_DecodeChs(RECOIL *self, uint8_t const *content, int contentLength);
1312 
1313 static bool RECOIL_DecodeHrs(RECOIL *self, uint8_t const *content, int contentLength);
1314 
1315 static int RECOIL_GetAmstradHeader(uint8_t const *content, int contentLength);
1316 
1317 static bool RECOIL_DecodeAmstradFnt(RECOIL *self, uint8_t const *content, int contentLength);
1318 
1319 static bool RECOIL_DecodeAmstradMode2(RECOIL *self, uint8_t const *content, int contentOffset, int width, int height);
1320 
1321 static bool RECOIL_DecodeHgb(RECOIL *self, uint8_t const *content, int contentLength);
1322 
1323 static int RECOIL_SetAmstradPalette(RECOIL *self, const char *filename);
1324 
1325 static void RECOIL_DecodeAmstradMode0Line(RECOIL *self, uint8_t const *content, int lineOffset, int y);
1326 
1327 static void RECOIL_DecodeAmstradMode1Line(RECOIL *self, uint8_t const *content, int lineOffset, int y);
1328 
1329 static bool RECOIL_DecodeAmstradScr(RECOIL *self, const char *filename, uint8_t const *content, int contentLength);
1330 
1331 static bool RECOIL_DecodeWin(RECOIL *self, const char *filename, uint8_t const *content, int contentLength);
1332 
1333 static bool RECOIL_DecodeCm5(RECOIL *self, const char *filename, uint8_t const *content, int contentLength);
1334 
1335 static bool RECOIL_DecodeSgx(RECOIL *self, uint8_t const *content, int contentLength);
1336 
1337 static bool RECOIL_SetAmstradFirmwarePalette(RECOIL *self, uint8_t const *content, int contentOffset, int count);
1338 
1339 static bool RECOIL_SetAmstradFirmwarePalette16(RECOIL *self, uint8_t const *content);
1340 
1341 static bool RECOIL_DecodePphFrame(RECOIL *self, const char *filename, const char *upperExt, const char *lowerExt, uint8_t *bitmap, uint8_t const *pph, int yOffset);
1342 
1343 static bool RECOIL_DecodePph(RECOIL *self, const char *filename, uint8_t const *content, int contentLength);
1344 
1345 static bool RECOIL_DecodeZx81(RECOIL *self, uint8_t const *screen);
1346 
1347 static bool RECOIL_DecodeZx81Raw(RECOIL *self, uint8_t const *content, int contentLength);
1348 
1349 static bool RECOIL_DecodeZp1(RECOIL *self, uint8_t const *content, int contentLength);
1350 
1351 static bool RECOIL_DecodeP(RECOIL *self, uint8_t const *content, int contentLength);
1352 
1353 static int RECOIL_GetZxColor(int c);
1354 
1355 static void RECOIL_SetZx(RECOIL *self, RECOILResolution resolution);
1356 
1357 static int RECOIL_GetG3R3B2Color(int c);
1358 
1359 static void RECOIL_SetUlaPlus(RECOIL *self, uint8_t const *content, int paletteOffset);
1360 
1361 static int RECOIL_GetZxLineOffset(int y);
1362 
1363 static void RECOIL_DecodeZx(RECOIL *self, uint8_t const *content, int bitmapOffset, int attributesOffset, int attributesMode, int pixelsOffset);
1364 
1365 static void RECOIL_DecodeTimexHires(RECOIL *self, uint8_t const *content, int contentOffset, int pixelsOffset);
1366 
1367 static bool RECOIL_DecodeHrg(RECOIL *self, uint8_t const *content, int contentLength);
1368 
1369 static bool RECOIL_DecodeZxIfl(RECOIL *self, uint8_t const *content, int contentLength);
1370 
1371 static bool RECOIL_DecodeMcMlt(RECOIL *self, uint8_t const *content, int contentLength, int bitmapOffset);
1372 
1373 static bool RECOIL_DecodeZxImg(RECOIL *self, uint8_t const *content, int contentLength);
1374 
1375 static bool RECOIL_DecodeMg(RECOIL *self, uint8_t const *content, int contentLength);
1376 
1377 static bool RECOIL_DecodeAtr(RECOIL *self, uint8_t const *content, int contentLength);
1378 
1379 static bool RECOIL_DecodeHlr(RECOIL *self, uint8_t const *content, int contentLength);
1380 
1381 static bool RECOIL_DecodeStl(RECOIL *self, uint8_t const *content, int contentLength);
1382 
1383 static bool RECOIL_DecodeZxRgb3(RECOIL *self, uint8_t const *content, int contentLength, uint8_t const *frameComponents);
1384 
1385 static bool RECOIL_DecodeZxRgb(RECOIL *self, uint8_t const *content, int contentLength);
1386 
1387 static bool RECOIL_Decode3(RECOIL *self, uint8_t const *content, int contentLength);
1388 
1389 static bool RECOIL_DecodeCh8(RECOIL *self, uint8_t const *content, int contentLength);
1390 
1391 static bool RECOIL_DecodeZxp(RECOIL *self, uint8_t const *content, int contentLength);
1392 
1393 static bool RECOIL_DecodeBsc(RECOIL *self, uint8_t const *content, int contentLength);
1394 
1395 static bool RECOIL_DecodeChrd(RECOIL *self, uint8_t const *content, int contentLength);
1396 
1397 static int RECOIL_GetBspBitmapPixel(uint8_t const *content, int bitmapOffset, int x, int y);
1398 
1399 static bool RECOIL_DecodeBspFrame(RECOIL *self, int pixelsOffset, uint8_t const *content, int contentLength, int bitmapOffset, int borderOffset);
1400 
1401 static bool RECOIL_DecodeBsp(RECOIL *self, uint8_t const *content, int contentLength);
1402 
1403 static bool RECOIL_DecodeNxi(RECOIL *self, uint8_t const *content, int contentLength);
1404 
1405 static bool RECOIL_DecodeSxg(RECOIL *self, uint8_t const *content, int contentLength);
1406 
1407 static void RECOIL_SetMsx1Palette(RECOIL *self);
1408 
1409 static int RECOIL_GetMsxHeader(uint8_t const *content);
1410 
1411 static bool RECOIL_IsMsxPalette(uint8_t const *content, int contentOffset);
1412 
1413 static void RECOIL_SetMsxPalette(RECOIL *self, uint8_t const *content, int contentOffset, int colors);
1414 
1415 static void RECOIL_SetMsx2Palette(RECOIL *self, uint8_t const *content, int contentOffset, int contentLength);
1416 
1417 static void RECOIL_DecodeSc2Sc4(RECOIL *self, uint8_t const *content, int contentOffset, RECOILResolution resolution);
1418 
1419 static void RECOIL_DecodeMsxSprites(RECOIL *self, uint8_t const *content, int mode, int attributesOffset, int patternsOffset);
1420 
1421 static bool RECOIL_DecodeSc2(RECOIL *self, uint8_t const *content, int contentLength);
1422 
1423 static void RECOIL_DecodeSc3Screen(RECOIL *self, uint8_t const *content, int contentOffset, bool isLong);
1424 
1425 static bool RECOIL_DecodeSc3(RECOIL *self, uint8_t const *content, int contentLength);
1426 
1427 static bool RECOIL_DecodeSc4(RECOIL *self, uint8_t const *content, int contentLength);
1428 
1429 static int RECOIL_GetMsx128Height(const RECOIL *self, uint8_t const *content, int contentLength);
1430 
1431 static void RECOIL_DecodeMsxScreen(RECOIL *self, uint8_t const *content, int contentOffset, uint8_t const *interlace, int height, int mode, int interlaceMask);
1432 
1433 static bool RECOIL_DecodeMsxSc(RECOIL *self, const char *filename, uint8_t const *content, int contentOffset, const char *upperExt, const char *lowerExt, int height, int mode);
1434 
1435 static bool RECOIL_DecodeSc5(RECOIL *self, const char *filename, uint8_t const *content, int contentLength);
1436 
1437 static void RECOIL_SetMsxCompanionPalette(RECOIL *self, const char *filename, const char *upperExt, const char *lowerExt);
1438 
1439 static bool RECOIL_DecodeSr5(RECOIL *self, const char *filename, uint8_t const *content, int contentLength);
1440 
1441 static bool RECOIL_DecodeMsx6(RECOIL *self, uint8_t const *content, int contentOffset);
1442 
1443 static void RECOIL_SetMsx6DefaultPalette(RECOIL *self);
1444 
1445 static bool RECOIL_DecodeSc6(RECOIL *self, const char *filename, uint8_t const *content, int contentLength);
1446 
1447 static void RECOIL_SetMsx6Palette(RECOIL *self, const char *filename);
1448 
1449 static bool RECOIL_DecodeSr6(RECOIL *self, const char *filename, uint8_t const *content, int contentLength);
1450 
1451 static bool RECOIL_DecodeGl6(RECOIL *self, const char *filename, uint8_t const *content, int contentLength);
1452 
1453 static uint8_t const *RECOIL_UnpackSr(uint8_t const *content, int contentLength, uint8_t *unpacked);
1454 
1455 static bool RECOIL_DecodeSc7(RECOIL *self, const char *filename, uint8_t const *content, int contentLength);
1456 
1457 static bool RECOIL_DecodeSri(RECOIL *self, const char *filename, uint8_t const *content, int contentLength);
1458 
1459 static bool RECOIL_DecodeSr7(RECOIL *self, const char *filename, uint8_t const *content, int contentLength);
1460 
1461 static bool RECOIL_DecodeGl16(RECOIL *self, const char *filename, uint8_t const *content, int contentLength, RECOILResolution resolution, const char *upperExt, const char *lowerExt);
1462 
1463 static bool RECOIL_DecodeGl5(RECOIL *self, const char *filename, uint8_t const *content, int contentLength);
1464 
1465 static bool RECOIL_DecodeGl7(RECOIL *self, const char *filename, uint8_t const *content, int contentLength);
1466 
1467 static void RECOIL_SetSc8Palette(RECOIL *self);
1468 
1469 static bool RECOIL_DecodeSc8(RECOIL *self, const char *filename, uint8_t const *content, int contentLength);
1470 
1471 static bool RECOIL_DecodeGl8(RECOIL *self, uint8_t const *content, int contentLength);
1472 
1473 static bool RECOIL_DecodePct(RECOIL *self, uint8_t const *content, int contentLength);
1474 
1475 static int RECOIL_DecodeMsxYjk(const RECOIL *self, uint8_t const *content, int contentOffset, int x, bool usePalette);
1476 
1477 static void RECOIL_DecodeMsxYjkScreen(RECOIL *self, uint8_t const *content, int contentOffset, bool usePalette);
1478 
1479 static void RECOIL_DecodeSccSca(RECOIL *self, const char *filename, uint8_t const *content, int contentLength, int height, bool usePalette);
1480 
1481 static bool RECOIL_DecodeScc(RECOIL *self, const char *filename, uint8_t const *content, int contentLength);
1482 
1483 static bool RECOIL_DecodeSca(RECOIL *self, const char *filename, uint8_t const *content, int contentLength);
1484 
1485 static bool RECOIL_DecodeGlYjk(RECOIL *self, const char *filename, uint8_t const *content, int contentLength);
1486 
1487 static bool RECOIL_SetG9bPalette(RECOIL *self, uint8_t const *content, int colors);
1488 
1489 static void RECOIL_DecodeG9bUnpacked(RECOIL *self, uint8_t const *content, int depth);
1490 
1491 static bool RECOIL_DecodeG9b(RECOIL *self, uint8_t const *content, int contentLength);
1492 
1493 static int RECOIL_GetMigMode(int reg0, int reg1, int reg19, int length);
1494 
1495 static bool RECOIL_DecodeMig(RECOIL *self, uint8_t const *content, int contentLength);
1496 
1497 static bool RECOIL_DecodeHgr(RECOIL *self, uint8_t const *content, int contentLength);
1498 
1499 static bool RECOIL_DecodeAppleIIDhr(RECOIL *self, uint8_t const *content, int contentLength);
1500 
1501 static void RECOIL_SetAppleIIGSPalette(RECOIL *self, uint8_t const *content, int contentOffset, int reverse);
1502 
1503 static void RECOIL_DecodeShrLine(RECOIL *self, uint8_t const *content, int y);
1504 
1505 static bool RECOIL_DecodeAppleIIShr(RECOIL *self, uint8_t const *content, int contentLength);
1506 
1507 static bool RECOIL_DecodeSh3(RECOIL *self, uint8_t const *content, int contentLength);
1508 
1509 static void RECOIL_DrawSprByte(RECOIL *self, int x1, int y, int b);
1510 
1511 static bool RECOIL_DecodeAppleSpr(RECOIL *self, uint8_t const *content, int contentLength);
1512 
1513 static bool RECOIL_DecodePackBytes(RECOIL *self, PackBytesStream *stream, int pixelsOffset, int unpackedBytes);
1514 
1515 static bool RECOIL_DecodePaintworks(RECOIL *self, uint8_t const *content, int contentLength);
1516 
1517 static bool RECOIL_Decode3201(RECOIL *self, uint8_t const *content, int contentLength);
1518 
1519 static bool RECOIL_DecodeApfShr(RECOIL *self, uint8_t const *content, int contentLength);
1520 
1521 static bool RECOIL_DecodeScs4(RECOIL *self, uint8_t const *content, int contentLength);
1522 
1523 static int RECOIL_GetX68KColor(int color);
1524 
1525 static bool RECOIL_DecodeX68KPicChain(RECOIL *self, BitStream *stream, int pixelsOffset, int color);
1526 
1527 static bool RECOIL_DecodeX68KPicScreen(RECOIL *self, X68KPicStream *stream, int pixelsLength, int platform, int depth);
1528 
1529 static bool RECOIL_DecodeX68KPic(RECOIL *self, uint8_t const *content, int contentLength);
1530 
1531 static void RECOIL_SetPc88EightPixels(RECOIL *self, int column, int y, int b);
1532 
1533 static bool RECOIL_DecodeDaVinci(RECOIL *self, uint8_t const *content, int contentLength);
1534 
1535 static bool RECOIL_DecodeArtMaster88(RECOIL *self, uint8_t const *content, int contentLength);
1536 
1537 static bool RECOIL_DecodeNl3(RECOIL *self, uint8_t const *content, int contentLength);
1538 
1539 static bool RECOIL_DecodeMl1Chain(RECOIL *self, X68KPicStream *stream, int pixelsOffset, int rgb);
1540 
1541 static int RECOIL_DecodeMl1Mx1(RECOIL *self, X68KPicStream *stream, int imageOffset);
1542 
1543 static bool RECOIL_DecodeMl1(RECOIL *self, uint8_t const *content, int contentLength);
1544 
1545 static bool RECOIL_DecodeMx1Tiles(RECOIL *self, Mx1Stream *stream, int width, int height, int shift);
1546 
1547 static bool RECOIL_DecodeMx1(RECOIL *self, uint8_t const *content, int contentLength);
1548 
1549 static int RECOIL_UnpackZim(uint8_t const *content, int contentOffset, int end, uint8_t const *flags, uint8_t *unpacked, int unpackedLength);
1550 
1551 static bool RECOIL_DecodeZim(RECOIL *self, uint8_t const *content, int contentLength);
1552 
1553 static bool RECOIL_DecodeQ4(RECOIL *self, uint8_t const *content, int contentLength);
1554 
1555 static RECOILResolution RECOIL_GetPiPlatform(uint8_t const *content, int contentOffset, bool highPixel);
1556 
1557 static bool RECOIL_DecodePi(RECOIL *self, uint8_t const *content, int contentLength);
1558 
1559 static void RECOIL_SetMagPalette(RECOIL *self, uint8_t const *content, int paletteOffset, int colors);
1560 
1561 static bool RECOIL_DecodeMaki1(RECOIL *self, uint8_t const *content, int contentLength);
1562 
1563 static bool RECOIL_UnpackMag(uint8_t const *content, int headerOffset, int contentLength, int bytesPerLine, int height, uint8_t *unpacked);
1564 
1565 static bool RECOIL_DecodeMag(RECOIL *self, uint8_t const *content, int contentLength);
1566 
1567 static bool RECOIL_DecodeVbm(RECOIL *self, uint8_t const *content, int contentLength);
1568 
1569 static bool RECOIL_DecodeBrus(RECOIL *self, uint8_t const *content, int contentLength);
1570 
1571 static void RECOIL_SetC16Palette(RECOIL *self);
1572 
1573 static bool RECOIL_DecodeP4i(RECOIL *self, uint8_t const *content, int contentLength);
1574 
1575 static bool RECOIL_Decode64c(RECOIL *self, uint8_t const *content, int contentLength);
1576 
1577 static bool RECOIL_DecodeG(RECOIL *self, uint8_t const *content, int contentLength);
1578 
1579 static bool RECOIL_DecodeCle(RECOIL *self, uint8_t const *content, int contentLength);
1580 
1581 static bool RECOIL_Decode4bt(RECOIL *self, uint8_t const *content, int contentLength);
1582 
1583 static void RECOIL_DecodeC64HiresFrame(RECOIL *self, uint8_t const *content, int bitmapOffset, int videoMatrixOffset, int pixelsOffset);
1584 
1585 static void RECOIL_DecodeC64MulticolorFrame(RECOIL *self, uint8_t const *content, int bitmapOffset, int videoMatrixOffset, int colorOffset, int background, int pixelsOffset);
1586 
1587 static bool RECOIL_DecodeC64Multicolor(RECOIL *self, int width, uint8_t const *content, int bitmapOffset, int videoMatrixOffset, int colorOffset, int background);
1588 
1589 static bool RECOIL_DecodeOcp(RECOIL *self, uint8_t const *content, int contentLength);
1590 
1591 static bool RECOIL_DecodeC64Hir(RECOIL *self, uint8_t const *content, int contentLength);
1592 
1593 static bool RECOIL_DecodeIhe(RECOIL *self, uint8_t const *content, int contentLength);
1594 
1595 static bool RECOIL_DecodeIph(RECOIL *self, uint8_t const *content, int contentLength);
1596 
1597 static bool RECOIL_DecodeHed(RECOIL *self, uint8_t const *content, int contentLength);
1598 
1599 static bool RECOIL_DecodeDd(RECOIL *self, uint8_t const *content, int contentLength);
1600 
1601 static bool RECOIL_DecodeJj(RECOIL *self, uint8_t const *content, int contentLength);
1602 
1603 static bool RECOIL_DecodeHfc(RECOIL *self, uint8_t const *content, int contentLength);
1604 
1605 static bool RECOIL_DecodeAfl(RECOIL *self, uint8_t const *content, int contentLength);
1606 
1607 static bool RECOIL_DecodePmg(RECOIL *self, uint8_t const *content, int contentLength);
1608 
1609 static bool RECOIL_DecodeKoa(RECOIL *self, uint8_t const *content, int contentLength);
1610 
1611 static bool RECOIL_DecodeGg(RECOIL *self, uint8_t const *content, int contentLength);
1612 
1613 static bool RECOIL_DecodeDol(RECOIL *self, uint8_t const *content, int contentLength);
1614 
1615 static bool RECOIL_DecodeAmi(RECOIL *self, uint8_t const *content, int contentLength);
1616 
1617 static bool RECOIL_DecodeHlf(RECOIL *self, uint8_t const *content, int contentLength);
1618 
1619 static bool RECOIL_DecodeMci(RECOIL *self, uint8_t const *content, int contentLength);
1620 
1621 static bool RECOIL_DecodeDrz(RECOIL *self, uint8_t const *content, int contentLength);
1622 
1623 static bool RECOIL_DecodeDrl(RECOIL *self, uint8_t const *content, int contentLength);
1624 
1625 static void RECOIL_DecodeMleFrame(RECOIL *self, uint8_t const *content, int contentOffset, int pixelsOffset);
1626 
1627 static bool RECOIL_DecodeMle(RECOIL *self, uint8_t const *content, int contentLength);
1628 
1629 static bool RECOIL_DecodeHimUnpacked(RECOIL *self, uint8_t const *content);
1630 
1631 static bool RECOIL_DecodeHim(RECOIL *self, uint8_t const *content, int contentLength);
1632 
1633 static bool RECOIL_DecodeEci(RECOIL *self, uint8_t const *content, int contentLength);
1634 
1635 static bool RECOIL_DecodeEcp(RECOIL *self, uint8_t const *content, int contentLength);
1636 
1637 static bool RECOIL_DecodeFli(RECOIL *self, uint8_t const *content, int contentLength);
1638 
1639 static bool RECOIL_DecodeBml(RECOIL *self, uint8_t const *content, int contentLength);
1640 
1641 static bool RECOIL_DecodeFbi(RECOIL *self, uint8_t const *content, int contentLength);
1642 
1643 static bool RECOIL_DecodeFfli(RECOIL *self, uint8_t const *content, int contentLength);
1644 
1645 static bool RECOIL_DecodeIfli(RECOIL *self, uint8_t const *content, int bitmap1Offset, int bitmap2Offset, int videoMatrix1Offset, int videoMatrix2Offset, int colorOffset, int background);
1646 
1647 static bool RECOIL_DecodePpUnpacked(RECOIL *self, uint8_t const *content);
1648 
1649 static bool RECOIL_DecodePp(RECOIL *self, uint8_t const *content, int contentLength);
1650 
1651 static bool RECOIL_DecodeGun(RECOIL *self, uint8_t const *content, int contentLength);
1652 
1653 static bool RECOIL_DecodeFunUnpacked(RECOIL *self, uint8_t const *content);
1654 
1655 static bool RECOIL_DecodeC64Fun(RECOIL *self, uint8_t const *content, int contentLength);
1656 
1657 static bool RECOIL_DecodeBfli(RECOIL *self, uint8_t const *content, int contentLength);
1658 
1659 static bool RECOIL_DecodeLp3(RECOIL *self, uint8_t const *content, int contentLength);
1660 
1661 static bool RECOIL_DecodeVic(RECOIL *self, uint8_t const *content, int contentLength);
1662 
1663 static bool RECOIL_DecodeA(RECOIL *self, uint8_t const *content, int contentLength);
1664 
1665 static bool RECOIL_DecodeSpd(RECOIL *self, uint8_t const *content, int contentLength);
1666 
1667 static bool RECOIL_DecodePetScreen(RECOIL *self, uint8_t const *content, int screenOffset, int colorsOffset, int backgroundOffset, int columns, int rows);
1668 
1669 static bool RECOIL_DecodePet(RECOIL *self, uint8_t const *content, int contentLength);
1670 
1671 static bool RECOIL_DecodeScrCol(RECOIL *self, const char *filename, uint8_t const *content, int contentLength);
1672 
1673 static bool RECOIL_DecodeFpr(RECOIL *self, uint8_t const *content, int contentLength);
1674 
1675 static bool RECOIL_DecodeCtm(RECOIL *self, uint8_t const *content, int contentLength);
1676 
1677 static bool RECOIL_DecodeDoo(RECOIL *self, uint8_t const *content, int contentLength);
1678 
1679 static bool RECOIL_DecodeDa4(RECOIL *self, uint8_t const *content, int contentLength);
1680 
1681 static bool RECOIL_DecodeCmp(RECOIL *self, uint8_t const *content, int contentLength);
1682 
1683 static bool RECOIL_DecodeBld(RECOIL *self, uint8_t const *content, int contentLength);
1684 
1685 static bool RECOIL_DecodeCrg(RECOIL *self, uint8_t const *content, int contentLength);
1686 
1687 static bool RECOIL_DecodePac(RECOIL *self, uint8_t const *content, int contentLength);
1688 
1689 static int RECOIL_FillPscLine(uint8_t *unpacked, int unpackedOffset, int value);
1690 
1691 static int RECOIL_CopyPscLines(uint8_t *unpacked, int unpackedOffset, int count);
1692 
1693 static bool RECOIL_DecodePsc(RECOIL *self, uint8_t const *content, int contentLength);
1694 
1695 static bool RECOIL_DecodeCp3(RECOIL *self, uint8_t const *content, int contentLength);
1696 
1697 static bool RECOIL_DecodeStFnt(RECOIL *self, uint8_t const *content, int contentLength);
1698 
1699 static bool RECOIL_DecodeGdosFnt(RECOIL *self, uint8_t const *content, int contentLength);
1700 
1701 static bool RECOIL_IsStePalette(uint8_t const *content, int contentOffset, int colors);
1702 
1703 static int RECOIL_GetStColor(const RECOIL *self, uint8_t const *content, int contentOffset);
1704 
1705 static void RECOIL_SetStPalette(RECOIL *self, uint8_t const *content, int contentOffset, int colors);
1706 
1707 static int RECOIL_GetSteInterlacedColor(int rgb);
1708 
1709 static int RECOIL_GetStVdiColor(uint8_t const *content, int contentOffset);
1710 
1711 static void RECOIL_SetStVdiColor(RECOIL *self, int i, int rgb, int bitplanes);
1712 
1713 static void RECOIL_SetStVdiPalette(RECOIL *self, uint8_t const *content, int contentOffset, int colors, int bitplanes);
1714 
1715 static int RECOIL_GetStLowPixel(uint8_t const *content, int contentOffset, int x);
1716 
1717 static bool RECOIL_DecodeStLowWithStride(RECOIL *self, uint8_t const *bitmap, int bitmapOffset, int bitmapStride, uint8_t const *palette, int paletteOffset, int width, int height);
1718 
1719 static bool RECOIL_DecodeStLow(RECOIL *self, uint8_t const *bitmap, int bitmapOffset, uint8_t const *palette, int paletteOffset, int width, int height);
1720 
1721 static void RECOIL_DecodeStMedium(RECOIL *self, uint8_t const *bitmap, int bitmapOffset, uint8_t const *palette, int paletteOffset, int width, int height, int blend);
1722 
1723 static bool RECOIL_DecodeSrt(RECOIL *self, uint8_t const *content, int contentLength);
1724 
1725 static bool RECOIL_DecodeSt(RECOIL *self, uint8_t const *bitmap, int bitmapOffset, uint8_t const *palette, int paletteOffset, int mode, int doubleHeight);
1726 
1727 static bool RECOIL_DecodeStPi(RECOIL *self, uint8_t const *content, int contentLength);
1728 
1729 static bool RECOIL_DecodePc(RECOIL *self, uint8_t const *content, int contentLength);
1730 
1731 static bool RECOIL_DecodeEza(RECOIL *self, uint8_t const *content, int contentLength);
1732 
1733 static bool RECOIL_DecodeNeo(RECOIL *self, const char *filename, uint8_t const *content, int contentLength);
1734 
1735 static bool RECOIL_DecodeArtDirector(RECOIL *self, uint8_t const *content, int contentLength);
1736 
1737 static bool RECOIL_DecodeSsb(RECOIL *self, uint8_t const *content, int contentLength);
1738 
1739 static bool RECOIL_DecodeGfaArtist(RECOIL *self, uint8_t const *content, int contentLength);
1740 
1741 static bool RECOIL_DecodePaletteMaster(RECOIL *self, uint8_t const *content, int contentLength);
1742 
1743 static bool RECOIL_DecodeCel(RECOIL *self, uint8_t const *content, int contentLength);
1744 
1745 static bool RECOIL_DecodeMur(RECOIL *self, const char *filename, uint8_t const *content, int contentLength);
1746 
1747 static bool RECOIL_DecodeKid(RECOIL *self, uint8_t const *content, int contentLength);
1748 
1749 static bool RECOIL_DecodeStPpp(RECOIL *self, uint8_t const *content, int contentLength);
1750 
1751 static bool RECOIL_DecodeStRgb(RECOIL *self, uint8_t const *content, int contentLength);
1752 
1753 static bool RECOIL_DecodeSd(RECOIL *self, uint8_t const *content, int contentLength, int mode);
1754 
1755 static bool RECOIL_DecodeIc(RECOIL *self, uint8_t const *content, int contentLength);
1756 
1757 static bool RECOIL_DecodeGraphicsProcessor(RECOIL *self, uint8_t const *content, int contentLength);
1758 
1759 static bool RECOIL_DecodeDaliCompressed(RECOIL *self, uint8_t const *content, int contentLength, int mode);
1760 
1761 static bool RECOIL_DecodeRgh(RECOIL *self, uint8_t const *content, int contentLength);
1762 
1763 static bool RECOIL_DecodeSc(RECOIL *self, uint8_t const *content, int contentLength);
1764 
1765 static bool RECOIL_DecodeGfb(RECOIL *self, uint8_t const *content, int contentLength);
1766 
1767 static bool RECOIL_DecodeCa(RECOIL *self, uint8_t const *content, int contentLength);
1768 
1769 static bool RECOIL_DecodeTny(RECOIL *self, uint8_t const *content, int contentLength);
1770 
1771 static bool RECOIL_DecodeCptFul(RECOIL *self, uint8_t const *content, int contentOffset, int contentLength, HblPalette *palette);
1772 
1773 static bool RECOIL_DecodeCpt(RECOIL *self, const char *filename, uint8_t const *content, int contentLength);
1774 
1775 static bool RECOIL_DecodeFul(RECOIL *self, uint8_t const *content, int contentLength);
1776 
1777 static void RECOIL_SetDefaultStPalette(RECOIL *self, int bitplanes);
1778 
1779 static bool RECOIL_IsTimg(uint8_t const *content);
1780 
1781 static bool RECOIL_IsXimg(uint8_t const *content);
1782 
1783 static bool RECOIL_IsSttt(uint8_t const *content, int bitplanes);
1784 
1785 static bool RECOIL_DecodeStImg(RECOIL *self, uint8_t const *content, int contentLength);
1786 
1787 static bool RECOIL_DecodeStLowBlend(RECOIL *self, uint8_t const *bitmap, int bitmapOffset, uint8_t const *palette, int paletteOffset, int width, int height);
1788 
1789 static bool RECOIL_DecodeDuo(RECOIL *self, uint8_t const *content, int contentLength);
1790 
1791 static bool RECOIL_DecodeDu2(RECOIL *self, uint8_t const *content, int contentLength);
1792 
1793 static bool RECOIL_DecodeP3c(RECOIL *self, uint8_t const *content, int contentLength);
1794 
1795 static bool RECOIL_UnpackLz4(const RECOIL *self, uint8_t const *content, int contentLength, uint8_t *unpacked, int unpackedLength);
1796 
1797 static bool RECOIL_DecodePl4(RECOIL *self, uint8_t const *content, int contentLength);
1798 
1799 static bool RECOIL_DecodeSpuScreen(RECOIL *self, uint8_t const *content, int bitmapOffset, int height, bool enhanced);
1800 
1801 static bool RECOIL_DecodeSpu(RECOIL *self, uint8_t const *content, int contentLength);
1802 
1803 static bool RECOIL_UnpackSpc(RleStream *rle, uint8_t *unpacked);
1804 
1805 static bool RECOIL_DecodeStSpc(RECOIL *self, uint8_t const *content, int contentLength);
1806 
1807 static bool RECOIL_DecodeSps(RECOIL *self, uint8_t const *content, int contentLength);
1808 
1809 static bool RECOIL_UnpackAndDecodeSpx(RECOIL *self, SpxStream *stream, int contentLength, int height, uint8_t *unpacked);
1810 
1811 static bool RECOIL_DecodeSpx(RECOIL *self, uint8_t const *content, int contentLength);
1812 
1813 static int RECOIL_GetStLowSeparateBitplanes(uint8_t const *content, int contentOffset, int bitplaneLength, int x);
1814 
1815 static bool RECOIL_DecodePci(RECOIL *self, uint8_t const *content, int contentLength);
1816 
1817 static void RECOIL_DecodePcsScreen(RECOIL *self, uint8_t const *unpacked, int pixelsOffset);
1818 
1819 static bool RECOIL_DecodePcs(RECOIL *self, uint8_t const *content, int contentLength);
1820 
1821 static uint8_t const *RECOIL_UnpackPbx(const RECOIL *self, uint8_t const *content, int contentLength, uint8_t *unpacked, int bitmapOffset, int bytesPer16Pixels, int unpackedLength);
1822 
1823 static bool RECOIL_DecodePbx01(RECOIL *self, uint8_t const *content, int contentLength, int bitplanes, int lineHeight);
1824 
1825 static void RECOIL_DecodePbx8(RECOIL *self, uint8_t const *content, int paletteOffset, int bitmapOffset, int pixelsOffset);
1826 
1827 static bool RECOIL_DecodePbx(RECOIL *self, uint8_t const *content, int contentLength);
1828 
1829 static void RECOIL_DecodeMppScreen(RECOIL *self, uint8_t const *content, int paletteOffset, int paletteLength, int pixelsOffset);
1830 
1831 static bool RECOIL_DecodeMpp(RECOIL *self, uint8_t const *content, int contentLength);
1832 
1833 static bool RECOIL_DecodeHrm(RECOIL *self, uint8_t const *content, int contentLength);
1834 
1835 static bool RECOIL_DecodeStIcn(RECOIL *self, uint8_t const *content, int contentLength);
1836 
1837 static bool RECOIL_DecodeCe(RECOIL *self, uint8_t const *content, int contentLength);
1838 
1839 static bool RECOIL_DecodeIbi(RECOIL *self, uint8_t const *content, int contentLength);
1840 
1841 static bool RECOIL_DecodeFalconGrayscale(RECOIL *self, uint8_t const *content, int contentOffset, int contentLength, int width, int height);
1842 
1843 static bool RECOIL_DecodeBw(RECOIL *self, uint8_t const *content, int contentLength);
1844 
1845 static bool RECOIL_DecodeFalconHir(RECOIL *self, uint8_t const *content, int contentLength);
1846 
1847 static bool RECOIL_DecodeRw(RECOIL *self, uint8_t const *content, int contentLength);
1848 
1849 static int RECOIL_GetR8G8B8Color(uint8_t const *content, int contentOffset);
1850 
1851 static void RECOIL_DecodeR8G8B8Colors(uint8_t const *content, int contentOffset, int count, int *destination);
1852 
1853 static void RECOIL_DecodeR8G8G8X8Colors(RECOIL *self, uint8_t const *content, int contentOffset, int count);
1854 
1855 static bool RECOIL_DecodeIim(RECOIL *self, uint8_t const *content, int contentLength);
1856 
1857 static void RECOIL_SetFalconPalette(RECOIL *self, uint8_t const *content, int contentOffset);
1858 
1859 static void RECOIL_DecodeFalconPalette(RECOIL *self, uint8_t const *content, int bitplanesOffset, int paletteOffset, int width, int height);
1860 
1861 static bool RECOIL_DecodeFuckpaint(RECOIL *self, uint8_t const *content, int contentLength);
1862 
1863 static bool RECOIL_DecodeDg1(RECOIL *self, uint8_t const *content, int contentLength);
1864 
1865 static bool RECOIL_DecodeDc1(RECOIL *self, uint8_t const *content, int contentLength);
1866 
1867 static bool RECOIL_DecodeDel(RECOIL *self, uint8_t const *content, int contentLength);
1868 
1869 static bool RECOIL_DecodeDph(RECOIL *self, uint8_t const *content, int contentLength);
1870 
1871 static bool RECOIL_DecodeFalconTrueColor(RECOIL *self, uint8_t const *content, int contentOffset, int width, int height, RECOILResolution resolution);
1872 
1873 static bool RECOIL_DecodeFalconTrueColorVariable(RECOIL *self, uint8_t const *content, int contentLength, int widthOffset, int dataOffset);
1874 
1875 static bool RECOIL_DecodeFtc(RECOIL *self, uint8_t const *content, int contentLength);
1876 
1877 static bool RECOIL_DecodeXga(RECOIL *self, uint8_t const *content, int contentLength);
1878 
1879 static bool RECOIL_DecodeGod(RECOIL *self, uint8_t const *content, int contentLength);
1880 
1881 static bool RECOIL_DecodeTrp(RECOIL *self, uint8_t const *content, int contentLength);
1882 
1883 static bool RECOIL_DecodeTru(RECOIL *self, uint8_t const *content, int contentLength);
1884 
1885 static bool RECOIL_DecodeTg1(RECOIL *self, uint8_t const *content, int contentLength);
1886 
1887 static bool RECOIL_DecodeTcp(RECOIL *self, uint8_t const *content, int contentLength);
1888 
1889 static bool RECOIL_DecodeTre(RECOIL *self, uint8_t const *content, int contentLength);
1890 
1891 static bool RECOIL_DecodeRag(RECOIL *self, uint8_t const *content, int contentLength);
1892 
1893 static bool RECOIL_DecodeFalconFun(RECOIL *self, uint8_t const *content, int contentLength);
1894 
1895 static bool RECOIL_DecodeEsm(RECOIL *self, uint8_t const *content, int contentLength);
1896 
1897 static bool RECOIL_DecodeFalconPix(RECOIL *self, uint8_t const *content, int contentLength);
1898 
1899 static bool RECOIL_DecodePntUnpacked(RECOIL *self, uint8_t const *content, uint8_t const *bitmap, int bitmapOffset, int width, int height);
1900 
1901 static bool RECOIL_DecodeFalconPnt(RECOIL *self, uint8_t const *content, int contentLength);
1902 
1903 static void RECOIL_SetOcsColor(RECOIL *self, int c, int r, int gb);
1904 
1905 static void RECOIL_SetOcsPalette(RECOIL *self, uint8_t const *content, int contentOffset, int colors);
1906 
1907 static bool RECOIL_DecodeAmigaPlanar(RECOIL *self, uint8_t const *content, int contentOffset, int width, int height, int bitplanes, int const *palette);
1908 
1909 static bool RECOIL_DecodeInfo(RECOIL *self, uint8_t const *content, int contentLength);
1910 
1911 static bool RECOIL_DecodeAbkSprite(RECOIL *self, uint8_t const *content, int contentLength);
1912 
1913 static bool RECOIL_DecodeAbk(RECOIL *self, uint8_t const *content, int contentLength);
1914 
1915 static RECOILResolution RECOIL_GetAmigaAspectRatio(int xRatio, int yRatio, RECOILResolution resolution);
1916 
1917 static RECOILResolution RECOIL_GetCamgAspectRatio(int camg, RECOILResolution resolution);
1918 
1919 static bool RECOIL_DecodeDeep(RECOIL *self, uint8_t const *content, int contentLength);
1920 
1921 static bool RECOIL_DecodeRgbn(RECOIL *self, uint8_t const *content, int contentOffset, int contentLength, int width, int height, bool rgb8);
1922 
1923 static bool RECOIL_DecodeRast(RECOIL *self, uint8_t const *content, int contentOffset, int contentLength, uint8_t const *unpacked, int width, int height, int bitplanes);
1924 
1925 static void RECOIL_DecodeHam(RECOIL *self, uint8_t const *unpacked, int width, int height, int bitplanes, MultiPalette *multiPalette);
1926 
1927 static int RECOIL_GetHameNibble(const RECOIL *self, uint8_t const *content, int contentOffset, int x);
1928 
1929 static int RECOIL_GetHameByte(const RECOIL *self, uint8_t const *content, int contentOffset, int x);
1930 
1931 static bool RECOIL_IsHame(const RECOIL *self, uint8_t const *content, int contentOffset);
1932 
1933 static void RECOIL_DecodeHame(RECOIL *self, uint8_t const *content, int width);
1934 
1935 static int RECOIL_GetDctvValue(const RECOIL *self, uint8_t const *content, int contentOffset, int x, int bitplanes);
1936 
1937 static bool RECOIL_IsDctv(const RECOIL *self, uint8_t const *content, int contentOffset, int bitplanes);
1938 
1939 static int RECOIL_ClampByte(int x);
1940 
1941 static bool RECOIL_DecodeDctv(RECOIL *self, uint8_t const *content, int width, int height, RECOILResolution resolution, int bitplanes);
1942 
1943 static bool RECOIL_DecodeIffUnpacked(RECOIL *self, uint8_t const *unpacked, int width, int height, RECOILResolution resolution, int bitplanes, int colors, int camg, MultiPalette *multiPalette);
1944 
1945 static bool RECOIL_DecodeIff(RECOIL *self, uint8_t const *content, int contentLength, RECOILResolution resolution);
1946 
1947 static bool RECOIL_DecodeFlfFont(RECOIL *self, uint8_t const *content, int contentOffset, int contentLength, int columns, int rows, RECOILResolution resolution, int const *palette, int colors, int xMask, int cMask);
1948 
1949 static bool RECOIL_DecodeFlf(RECOIL *self, uint8_t const *content, int contentLength);
1950 
1951 static int RECOIL_ParseAtari8ExecutableHeader(uint8_t const *content, int contentOffset);
1952 
1953 static int RECOIL_GetAtari8ExecutableOffset(uint8_t const *content, int contentLength);
1954 
1955 static bool RECOIL_SetAtari8RawSize(RECOIL *self, uint8_t const *content, int contentLength, RECOILResolution resolution);
1956 
1957 static void RECOIL_SetGtiaColor(RECOIL *self, int reg, int value);
1958 
1959 static void RECOIL_SetPM123PF0123Bak(RECOIL *self, uint8_t const *content, int contentOffset);
1960 
1961 static void RECOIL_SetGtiaColors(RECOIL *self, uint8_t const *content, int contentOffset);
1962 
1963 static void RECOIL_SetPF21(RECOIL *self, uint8_t const *content, int contentOffset);
1964 
1965 static void RECOIL_SetXeOsDefaultColors(RECOIL *self);
1966 
1967 static void RECOIL_SetGr15DefaultColors(RECOIL *self);
1968 
1969 static void RECOIL_SetBakPF012(RECOIL *self, uint8_t const *content, int contentOffset, int contentStride);
1970 
1971 static void RECOIL_SetBakPF0123(RECOIL *self, uint8_t const *content, int contentOffset);
1972 
1973 static void RECOIL_SetPF012Bak(RECOIL *self, uint8_t const *content, int contentOffset);
1974 
1975 static void RECOIL_SetPF0123Bak(RECOIL *self, uint8_t const *content, int contentOffset);
1976 
1977 static void RECOIL_SetPF0123Even(RECOIL *self, uint8_t const *content, int contentOffset);
1978 
1979 static void RECOIL_DecodeAtari8Gr8(const RECOIL *self, uint8_t const *content, int contentOffset, uint8_t *frame, int frameOffset, int height);
1980 
1981 static void RECOIL_DecodeAtari8Gr15(const RECOIL *self, uint8_t const *content, int contentOffset, int contentStride, uint8_t *frame, int frameOffset, int frameStride, int height);
1982 
1983 static void RECOIL_DecodeAtari8Gr7(const RECOIL *self, uint8_t const *content, int contentOffset, uint8_t *frame, int frameOffset, int height);
1984 
1985 static void RECOIL_DecodeAtari8Gr3(const RECOIL *self, uint8_t const *content, uint8_t *frame);
1986 
1987 static void RECOIL_DecodeAtari8Gr9(const RECOIL *self, uint8_t const *content, int contentOffset, int contentStride, uint8_t *frame, int frameOffset, int frameStride, int width, int height);
1988 
1989 static void RECOIL_DecodeAtari8Gr11(const RECOIL *self, uint8_t const *content, int contentOffset, uint8_t *frame, int frameOffset, int frameStride, int height);
1990 
1991 static void RECOIL_DecodeAtari8Gr10(const RECOIL *self, uint8_t const *content, int contentOffset, uint8_t *frame, int frameOffset, int frameStride, int height);
1992 
1993 static void RECOIL_DecodeAtari8Gr11PalBlend(const RECOIL *self, uint8_t const *content, int contentOffset, int contentStride, uint8_t *frame, int y);
1994 
1995 static int RECOIL_ToAtari8Char(int ascii);
1996 
1997 static void RECOIL_DecodeAtari8Gr0Line(const RECOIL *self, uint8_t const *characters, int charactersOffset, uint8_t const *font, int fontOffset, uint8_t *frame, int frameOffset, int lines);
1998 
1999 static void RECOIL_DecodeAtari8Gr0(RECOIL *self, uint8_t const *characters, int charactersStride, uint8_t const *font, int fontOffset, uint8_t *frame);
2000 
2001 static void RECOIL_DecodeAtari8Gr1Line(const RECOIL *self, uint8_t const *content, int charactersOffset, uint8_t const *font, int fontOffset, uint8_t *frame, int frameOffset, int doubleLine);
2002 
2003 static void RECOIL_DecodeAtari8Gr12Line(const RECOIL *self, uint8_t const *characters, int charactersOffset, uint8_t const *font, int fontOffset, uint8_t *frame, int frameOffset, int doubleLine);
2004 
2005 static void RECOIL_DecodeAtari8Player(const RECOIL *self, uint8_t const *content, int contentOffset, int color, uint8_t *frame, int frameOffset, int height, bool multi);
2006 
2007 static bool RECOIL_ApplyAtari8Palette(RECOIL *self, uint8_t const *frame);
2008 
2009 static bool RECOIL_ApplyAtari8PaletteBlend(RECOIL *self, uint8_t const *frame1, uint8_t const *frame2);
2010 
2011 static bool RECOIL_ApplyAtari8PaletteBlend3(RECOIL *self, uint8_t const *frame1, uint8_t const *frame2, uint8_t const *frame3);
2012 
2013 static bool RECOIL_DecodeGr8(RECOIL *self, uint8_t const *content, int contentLength);
2014 
2015 static bool RECOIL_DecodeDrg(RECOIL *self, uint8_t const *content, int contentLength);
2016 
2017 static bool RECOIL_DecodeGr8Raw(RECOIL *self, uint8_t const *content, int contentLength, int width, int height);
2018 
2019 static bool RECOIL_DecodeGhg(RECOIL *self, uint8_t const *content, int contentLength);
2020 
2021 static bool RECOIL_DecodeCpr(RECOIL *self, uint8_t const *content, int contentLength);
2022 
2023 static bool RECOIL_DecodeSg3(RECOIL *self, uint8_t const *content, int contentLength);
2024 
2025 static bool RECOIL_DecodeGr3(RECOIL *self, uint8_t const *content, int contentLength);
2026 
2027 static bool RECOIL_DecodeDit(RECOIL *self, uint8_t const *content, int contentLength);
2028 
2029 static bool RECOIL_DecodeGr7(RECOIL *self, uint8_t const *content, int contentOffset, int contentSize);
2030 
2031 static bool RECOIL_DecodeRys(RECOIL *self, uint8_t const *content, int contentLength);
2032 
2033 static bool RECOIL_DecodeBkg(RECOIL *self, uint8_t const *content, int contentLength);
2034 
2035 static bool RECOIL_DecodeAtari8Artist(RECOIL *self, uint8_t const *content, int contentLength);
2036 
2037 static bool RECOIL_DecodeGr9(RECOIL *self, uint8_t const *content, int contentLength);
2038 
2039 static bool RECOIL_DecodeRap(RECOIL *self, uint8_t const *content, int contentLength);
2040 
2041 static bool RECOIL_DecodeTxe(RECOIL *self, uint8_t const *content, int contentLength);
2042 
2043 static bool RECOIL_DecodeGr9x4(RECOIL *self, uint8_t const *content, int contentOffset, int width, int height);
2044 
2045 static bool RECOIL_DecodeGr9p(RECOIL *self, uint8_t const *content, int contentLength);
2046 
2047 static bool RECOIL_DecodeFge(RECOIL *self, uint8_t const *content, int contentLength);
2048 
2049 static bool RECOIL_Decode16x16x16(RECOIL *self, uint8_t const *content, int contentOffset, int colbak);
2050 
2051 static bool RECOIL_DecodeTx0(RECOIL *self, uint8_t const *content, int contentLength);
2052 
2053 static bool RECOIL_DecodeTxs(RECOIL *self, uint8_t const *content, int contentLength);
2054 
2055 static bool RECOIL_DecodeA4r(RECOIL *self, uint8_t const *content, int contentLength);
2056 
2057 static bool RECOIL_DecodeG11(RECOIL *self, uint8_t const *content, int contentLength);
2058 
2059 static bool RECOIL_DecodeG10(RECOIL *self, uint8_t const *content, int contentLength);
2060 
2061 static bool RECOIL_DecodeG09(RECOIL *self, uint8_t const *content, int contentLength);
2062 
2063 static bool RECOIL_DecodeSkp(RECOIL *self, uint8_t const *content, int contentLength);
2064 
2065 static bool RECOIL_DecodeKss(RECOIL *self, uint8_t const *content, int contentLength);
2066 
2067 static bool RECOIL_DecodeMic(RECOIL *self, const char *filename, uint8_t const *content, int contentLength);
2068 
2069 static bool RECOIL_DecodeHpm(RECOIL *self, uint8_t const *content, int contentLength);
2070 
2071 static bool RECOIL_DecodeCpi(RECOIL *self, uint8_t const *content, int contentLength);
2072 
2073 static bool RECOIL_DecodeWnd(RECOIL *self, uint8_t const *content, int contentLength);
2074 
2075 static void RECOIL_DecodeAt800Players(const RECOIL *self, uint8_t const *content, uint8_t *frame);
2076 
2077 static void RECOIL_DecodeAt800Missiles(const RECOIL *self, uint8_t const *content, int contentOffset, uint8_t *frame, int frameOffset);
2078 
2079 static bool RECOIL_DecodePla(RECOIL *self, uint8_t const *content, int contentLength);
2080 
2081 static bool RECOIL_DecodeMis(RECOIL *self, uint8_t const *content, int contentLength);
2082 
2083 static bool RECOIL_Decode4pl(RECOIL *self, uint8_t const *content, int contentLength);
2084 
2085 static bool RECOIL_Decode4mi(RECOIL *self, uint8_t const *content, int contentLength);
2086 
2087 static bool RECOIL_Decode4pm(RECOIL *self, uint8_t const *content, int contentLength);
2088 
2089 static bool RECOIL_DecodeAtari8Spr(RECOIL *self, uint8_t const *content, int contentLength);
2090 
2091 static bool RECOIL_DecodeMsl(RECOIL *self, uint8_t const *content, int contentLength);
2092 
2093 static bool RECOIL_DecodeMpl(RECOIL *self, uint8_t const *content, int contentLength);
2094 
2095 static bool RECOIL_DecodeLdm(RECOIL *self, uint8_t const *content, int contentLength);
2096 
2097 static bool RECOIL_DecodePmd(RECOIL *self, uint8_t const *content, int contentLength);
2098 
2099 static bool RECOIL_DecodeApl(RECOIL *self, uint8_t const *content, int contentLength);
2100 
2101 static bool RECOIL_DecodeAtari8Hr(RECOIL *self, uint8_t const *content, int contentLength);
2102 
2103 static bool RECOIL_DecodeMcppVariable(RECOIL *self, uint8_t const *content, int bitmapOffset, int colorsOffset, int width, int height);
2104 
2105 static bool RECOIL_DecodeMcpp(RECOIL *self, uint8_t const *content, int contentLength);
2106 
2107 static bool RECOIL_DecodeIld(RECOIL *self, uint8_t const *content, int contentLength);
2108 
2109 static bool RECOIL_DecodeInp(RECOIL *self, uint8_t const *content, int contentLength);
2110 
2111 static bool RECOIL_DecodeIge(RECOIL *self, uint8_t const *content, int contentLength);
2112 
2113 static bool RECOIL_DecodeInt(RECOIL *self, uint8_t const *content, int contentLength);
2114 
2115 static bool RECOIL_DecodeIst(RECOIL *self, uint8_t const *content, int contentLength);
2116 
2117 static bool RECOIL_DecodeGr15Blend(RECOIL *self, uint8_t const *content, int bitmapOffset, int colorsOffset, int height);
2118 
2119 static bool RECOIL_DecodeMcp(RECOIL *self, uint8_t const *content, int contentLength);
2120 
2121 static bool RECOIL_DecodeAtari8Raw(RECOIL *self, uint8_t const *content, int contentLength);
2122 
2123 static bool RECOIL_DecodeXlp(RECOIL *self, uint8_t const *content, int contentLength);
2124 
2125 static bool RECOIL_DecodeAtari8Max(RECOIL *self, uint8_t const *content, int contentLength);
2126 
2127 static bool RECOIL_DecodeHr2(RECOIL *self, uint8_t const *content, int contentLength);
2128 
2129 static bool RECOIL_DecodeLum(RECOIL *self, const char *filename, uint8_t const *content, int contentLength);
2130 
2131 static bool RECOIL_DecodeApc(RECOIL *self, uint8_t const *content, int contentLength);
2132 
2133 static bool RECOIL_Decode256(RECOIL *self, uint8_t const *content, int contentLength);
2134 
2135 static bool RECOIL_DecodeAp3(RECOIL *self, uint8_t const *content, int contentLength);
2136 
2137 static bool RECOIL_DecodeBgp(RECOIL *self, uint8_t const *content, int contentLength);
2138 
2139 static bool RECOIL_DecodeHip(RECOIL *self, uint8_t const *content, int contentLength);
2140 
2141 static bool RECOIL_DecodeG9s(RECOIL *self, uint8_t const *content, int contentLength);
2142 
2143 static bool RECOIL_DecodeIns(RECOIL *self, uint8_t const *content, int contentLength);
2144 
2145 static bool RECOIL_DecodePls(RECOIL *self, uint8_t const *content, int contentLength);
2146 
2147 static bool RECOIL_DecodeAps(RECOIL *self, uint8_t const *content, int contentLength);
2148 
2149 static bool RECOIL_DecodeIls(RECOIL *self, uint8_t const *content, int contentLength);
2150 
2151 static bool RECOIL_DecodeApp(RECOIL *self, uint8_t const *content, int contentLength);
2152 
2153 static bool RECOIL_DecodeHps(RECOIL *self, uint8_t const *content, int contentLength);
2154 
2155 static bool RECOIL_DecodeTip(RECOIL *self, uint8_t const *content, int contentLength);
2156 
2157 static bool RECOIL_DecodeCin(RECOIL *self, uint8_t const *content, int contentLength);
2158 
2159 static bool RECOIL_DecodeCci(RECOIL *self, uint8_t const *content, int contentLength);
2160 
2161 static bool RECOIL_DecodeAgs(RECOIL *self, uint8_t const *content, int contentLength);
2162 
2163 static bool RECOIL_UnpackRip(const RECOIL *self, uint8_t const *content, int contentOffset, int contentLength, uint8_t *unpacked, int unpackedLength);
2164 
2165 static bool RECOIL_DecodeRip(RECOIL *self, uint8_t const *content, int contentLength);
2166 
2167 static bool RECOIL_DecodeVzi(RECOIL *self, uint8_t const *content, int contentLength);
2168 
2169 static bool RECOIL_DecodeRm(RECOIL *self, uint8_t const *content, int contentLength, int mode, RECOILResolution resolution);
2170 
2171 static bool RECOIL_DecodeAgp(RECOIL *self, uint8_t const *content, int contentLength);
2172 
2173 static bool RECOIL_DecodeShc(RECOIL *self, uint8_t const *content, int contentLength);
2174 
2175 static bool RECOIL_DecodeMgp(RECOIL *self, uint8_t const *content, int contentLength);
2176 
2177 static bool RECOIL_DecodeGad(RECOIL *self, uint8_t const *content, int contentLength);
2178 
2179 static bool RECOIL_DecodeFwa(RECOIL *self, uint8_t const *content, int contentLength);
2180 
2181 static bool RECOIL_DecodeAtari8Font(RECOIL *self, uint8_t const *characters, uint8_t const *font, int fontOffset);
2182 
2183 static bool RECOIL_DecodeAtari8Fnt(RECOIL *self, uint8_t const *content, int contentLength);
2184 
2185 static bool RECOIL_DecodeF80(RECOIL *self, uint8_t const *content, int contentLength);
2186 
2187 static bool RECOIL_DecodeSxs(RECOIL *self, uint8_t const *content, int contentLength);
2188 
2189 static bool RECOIL_DecodeFn2(RECOIL *self, uint8_t const *content, int contentLength);
2190 
2191 static bool RECOIL_DecodeNlq(RECOIL *self, uint8_t const *content, int contentLength);
2192 
2193 static bool RECOIL_DecodeGr1(RECOIL *self, uint8_t const *content, int contentLength, int doubleHeight);
2194 
2195 static bool RECOIL_DecodeAcs(RECOIL *self, uint8_t const *content, int contentLength);
2196 
2197 static bool RECOIL_DecodeJgp(RECOIL *self, uint8_t const *content, int contentLength);
2198 
2199 static bool RECOIL_DecodeLeo(RECOIL *self, uint8_t const *content, int contentLength);
2200 
2201 static bool RECOIL_DecodeSif(RECOIL *self, uint8_t const *content, int contentLength);
2202 
2203 static bool RECOIL_DecodeDlm(RECOIL *self, uint8_t const *content, int contentLength);
2204 
2205 static void RECOIL_DecodeAtari8Gr0Screen(RECOIL *self, uint8_t const *content, uint8_t const *font);
2206 
2207 static bool RECOIL_DecodeGr0(RECOIL *self, uint8_t const *content, int contentLength);
2208 
2209 static bool RECOIL_DecodeSge(RECOIL *self, uint8_t const *content, int contentLength);
2210 
2211 static bool RECOIL_DecodeAsciiArtEditor(RECOIL *self, uint8_t const *content, int contentLength);
2212 
2213 static bool RECOIL_DecodeAll(RECOIL *self, uint8_t const *content, int contentLength);
2214 
2215 static bool RECOIL_DecodeKpr(RECOIL *self, uint8_t const *content, int contentLength);
2216 
2217 static bool RECOIL_DecodeEnvisionCommon(RECOIL *self, uint8_t const *content, int mode, int columns, int rows, int charactersOffset, int const *fontId2Offset);
2218 
2219 static bool RECOIL_DecodeEnvision(RECOIL *self, uint8_t const *content, int contentLength);
2220 
2221 static bool RECOIL_DecodeEnvisionPC(RECOIL *self, uint8_t const *content, int contentLength);
2222 
2223 static bool RECOIL_DecodeMcs(RECOIL *self, uint8_t const *content, int contentLength);
2224 
2225 static int RECOIL_Gr12GtiaNibbleToGr8(int nibble, int ch, bool gtia10);
2226 
2227 static int RECOIL_Gr12GtiaByteToGr8(int b, int ch, bool gtia10);
2228 
2229 static void RECOIL_DecodeIceFrame(const RECOIL *self, uint8_t const *content, int charactersOffset, int fontOffset, uint8_t *frame, IceFrameMode mode);
2230 
2231 static bool RECOIL_VerifyIce(RECOIL *self, uint8_t const *content, int contentLength, bool font, int fontLength, int imageLength, RECOILResolution resolution);
2232 
2233 static void RECOIL_DecodeIce20Frame(const RECOIL *self, uint8_t const *content, bool second, int fontOffset, uint8_t *frame, int mode);
2234 
2235 static bool RECOIL_DecodeAtari8Ice(RECOIL *self, uint8_t const *content, int contentLength, bool font, int mode);
2236 
2237 static bool RECOIL_DecodeIp2(RECOIL *self, uint8_t const *content, int contentLength);
2238 
2239 static void RECOIL_DecodeAtari8RgbScreen(RECOIL *self, uint8_t const *screens, int screensOffset, int color, uint8_t *frame);
2240 
2241 static bool RECOIL_DecodeAtari8Rgb(RECOIL *self, uint8_t const *content, int contentLength);
2242 
2243 static bool RECOIL_DrawBlazingPaddlesVector(const RECOIL *self, uint8_t const *content, int contentLength, uint8_t *frame, int frameOffset, int index, int startAddress);
2244 
2245 static bool RECOIL_DecodeBlazingPaddlesVectors(RECOIL *self, uint8_t const *content, int contentLength, int startAddress);
2246 
2247 static bool RECOIL_DecodeChr(RECOIL *self, uint8_t const *content, int contentLength);
2248 
2249 static bool RECOIL_DecodeShp(RECOIL *self, uint8_t const *content, int contentLength);
2250 
2251 static void RECOIL_DrawSpcChar(uint8_t *pixels, int x1, int y1, int ch);
2252 
2253 static void RECOIL_DrawSpcLine(uint8_t *pixels, int x1, int y1, int x2, int y2, int color);
2254 
2255 static void RECOIL_PlotSpcPattern(uint8_t *pixels, int x, int y, int pattern);
2256 
2257 static void RECOIL_DrawSpcBrush(uint8_t *pixels, int x1, int y1, int brush, int pattern);
2258 
2259 static bool RECOIL_FillSpc(uint8_t *pixels, int x, int y, int pattern);
2260 
2261 static bool RECOIL_DecodeAtari8Spc(RECOIL *self, uint8_t const *content, int contentLength);
2262 
2263 static bool RECOIL_DecodeHcm(RECOIL *self, uint8_t const *content, int contentLength);
2264 
2265 static bool RECOIL_DecodeGed(RECOIL *self, uint8_t const *content, int contentLength);
2266 
2267 static bool RECOIL_DecodePgr(RECOIL *self, uint8_t const *content, int contentLength);
2268 
2269 static bool RECOIL_HasG2fRaster(uint8_t const *content, int contentOffset, int count, int hitClr);
2270 
2271 static bool RECOIL_DecodeMch(RECOIL *self, uint8_t const *content, int contentLength);
2272 
2273 static bool RECOIL_G2fHasRaster(uint8_t const *content, int contentOffset);
2274 
2275 static bool RECOIL_DecodeG2fUnpacked(RECOIL *self, uint8_t const *content, int contentLength);
2276 
2277 static bool RECOIL_DecodeG2f(RECOIL *self, uint8_t const *content, int contentLength);
2278 
2279 static bool RECOIL_DecodeDap(RECOIL *self, uint8_t const *content, int contentLength);
2280 
2281 static bool RECOIL_DecodeHs2(RECOIL *self, uint8_t const *content, int contentLength);
2282 
2283 static bool RECOIL_DecodeImage72Fnt(RECOIL *self, uint8_t const *content, int contentLength);
2284 
2285 static bool RECOIL_DecodeMsp(RECOIL *self, uint8_t const *content, int contentLength);
2286 
2287 static bool RECOIL_DecodeAwbmPalette(RECOIL *self, uint8_t const *content, int contentLength, int paletteOffset, int colors);
2288 
2289 static bool RECOIL_DecodeAwbm(RECOIL *self, uint8_t const *content, int contentLength);
2290 
2291 static bool RECOIL_DecodeEpa(RECOIL *self, uint8_t const *content, int contentLength);
2292 
2293 static bool RECOIL_DecodeElectronika(RECOIL *self, uint8_t const *content);
2294 
2295 static bool RECOIL_DecodePic(RECOIL *self, uint8_t const *content, int contentLength);
2296 
2297 static bool RECOIL_DecodeScr(RECOIL *self, const char *filename, uint8_t const *content, int contentLength);
2298 
2299 static int RECOIL_GetPackedExt(const char *filename);
2300 
2301 /**
2302  * Calculates palette for the decoded picture.
2303  * @param self This <code>RECOIL</code>.
2304  */
2305 static void RECOIL_CalculatePalette(RECOIL *self);
2306 
2307 static void RECOIL_SortPalette(RECOIL *self, int start, int end);
2308 
2309 /**
2310  * Find the index of the <code>rgb</code> color in the sorted palette.
2311  * @param self This <code>RECOIL</code>.
2312  */
2313 static int RECOIL_FindInSortedPalette(const RECOIL *self, int rgb);
2314 
2315 static const uint8_t CiResource_altirrapal_pal[768] = {
2316 	0, 0, 0, 17, 17, 17, 34, 34, 34, 51, 51, 51, 68, 68, 68, 85,
2317 	85, 85, 102, 102, 102, 119, 119, 119, 136, 136, 136, 153, 153, 153, 170, 170,
2318 	170, 187, 187, 187, 204, 204, 204, 221, 221, 221, 238, 238, 238, 255, 255, 255,
2319 	63, 0, 0, 80, 5, 0, 97, 22, 0, 114, 39, 0, 131, 56, 0, 148,
2320 	73, 0, 165, 90, 1, 182, 107, 18, 199, 124, 35, 216, 141, 52, 233, 158,
2321 	69, 250, 175, 86, 255, 192, 103, 255, 209, 120, 255, 226, 137, 255, 243, 154,
2322 	80, 0, 0, 97, 0, 0, 114, 3, 0, 131, 20, 3, 148, 37, 20, 165,
2323 	54, 37, 182, 71, 54, 199, 88, 71, 216, 105, 88, 233, 122, 105, 250, 139,
2324 	122, 255, 156, 139, 255, 173, 156, 255, 190, 173, 255, 207, 190, 255, 224, 207,
2325 	84, 0, 3, 101, 0, 20, 118, 0, 37, 135, 8, 54, 152, 25, 71, 169,
2326 	42, 88, 186, 59, 105, 203, 76, 122, 220, 93, 139, 237, 110, 156, 254, 127,
2327 	173, 255, 144, 190, 255, 161, 207, 255, 178, 224, 255, 195, 241, 255, 212, 255,
2328 	79, 0, 53, 96, 0, 70, 113, 0, 87, 130, 1, 104, 147, 18, 121, 164,
2329 	35, 138, 181, 52, 155, 198, 69, 172, 215, 86, 189, 232, 103, 206, 249, 120,
2330 	223, 255, 137, 240, 255, 154, 255, 255, 171, 255, 255, 188, 255, 255, 205, 255,
2331 	61, 0, 104, 78, 0, 121, 95, 0, 138, 112, 0, 155, 129, 17, 172, 146,
2332 	34, 189, 163, 51, 206, 180, 68, 223, 197, 85, 240, 214, 102, 255, 231, 119,
2333 	255, 248, 136, 255, 255, 153, 255, 255, 170, 255, 255, 187, 255, 255, 204, 255,
2334 	32, 0, 139, 49, 0, 156, 66, 0, 173, 83, 8, 190, 100, 25, 207, 117,
2335 	42, 224, 134, 59, 241, 151, 76, 255, 168, 93, 255, 185, 110, 255, 202, 127,
2336 	255, 219, 144, 255, 236, 161, 255, 253, 178, 255, 255, 195, 255, 255, 212, 255,
2337 	0, 0, 137, 0, 8, 154, 0, 25, 171, 16, 42, 188, 33, 59, 205, 50,
2338 	76, 222, 67, 93, 239, 84, 110, 255, 101, 127, 255, 118, 144, 255, 135, 161,
2339 	255, 152, 178, 255, 169, 195, 255, 186, 212, 255, 203, 229, 255, 220, 246, 255,
2340 	0, 12, 101, 0, 29, 118, 0, 46, 135, 0, 63, 152, 5, 80, 169, 22,
2341 	97, 186, 39, 114, 203, 56, 131, 220, 73, 148, 237, 90, 165, 254, 107, 182,
2342 	255, 124, 199, 255, 141, 216, 255, 158, 233, 255, 175, 250, 255, 192, 255, 255,
2343 	0, 31, 48, 0, 48, 65, 0, 65, 82, 0, 82, 99, 0, 99, 116, 5,
2344 	116, 133, 22, 133, 150, 39, 150, 167, 56, 167, 184, 73, 184, 201, 90, 201,
2345 	218, 107, 218, 235, 124, 235, 252, 141, 252, 255, 158, 255, 255, 175, 255, 255,
2346 	0, 43, 0, 0, 60, 14, 0, 77, 31, 0, 94, 48, 0, 111, 65, 1,
2347 	128, 82, 18, 145, 99, 35, 162, 116, 52, 179, 133, 69, 196, 150, 86, 213,
2348 	167, 103, 230, 184, 120, 247, 201, 137, 255, 218, 154, 255, 235, 171, 255, 252,
2349 	0, 51, 0, 0, 68, 0, 0, 85, 0, 0, 102, 0, 7, 119, 0, 24,
2350 	136, 0, 41, 153, 0, 58, 170, 15, 75, 187, 32, 92, 204, 49, 109, 221,
2351 	66, 126, 238, 83, 143, 255, 100, 160, 255, 117, 177, 255, 134, 194, 255, 151,
2352 	0, 43, 0, 0, 60, 0, 2, 77, 0, 19, 94, 0, 36, 111, 0, 53,
2353 	128, 0, 70, 145, 0, 87, 162, 0, 104, 179, 0, 121, 196, 14, 138, 213,
2354 	31, 155, 230, 48, 172, 247, 65, 189, 255, 82, 206, 255, 99, 223, 255, 116,
2355 	1, 28, 0, 18, 45, 0, 35, 62, 0, 52, 79, 0, 69, 96, 0, 86,
2356 	113, 0, 103, 130, 0, 120, 147, 0, 137, 164, 0, 154, 181, 3, 171, 198,
2357 	20, 188, 215, 37, 205, 232, 54, 222, 249, 71, 239, 255, 88, 255, 255, 105,
2358 	35, 9, 0, 52, 26, 0, 69, 43, 0, 86, 60, 0, 103, 77, 0, 120,
2359 	94, 0, 137, 111, 0, 154, 128, 0, 171, 145, 0, 188, 162, 16, 205, 179,
2360 	33, 222, 196, 50, 239, 213, 67, 255, 230, 84, 255, 247, 101, 255, 255, 118,
2361 	63, 0, 0, 80, 5, 0, 97, 22, 0, 114, 39, 0, 131, 56, 0, 148,
2362 	73, 0, 165, 90, 1, 182, 107, 18, 199, 124, 35, 216, 141, 52, 233, 158,
2363 	69, 250, 175, 86, 255, 192, 103, 255, 209, 120, 255, 226, 137, 255, 243, 154 };
2364 static const uint8_t CiResource_atari8_fnt[1024] = {
2365 	0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 24, 24, 24, 0, 24, 0,
2366 	0, 102, 102, 102, 0, 0, 0, 0, 0, 102, 255, 102, 102, 255, 102, 0,
2367 	24, 62, 96, 60, 6, 124, 24, 0, 0, 102, 108, 24, 48, 102, 70, 0,
2368 	28, 54, 28, 56, 111, 102, 59, 0, 0, 24, 24, 24, 0, 0, 0, 0,
2369 	0, 14, 28, 24, 24, 28, 14, 0, 0, 112, 56, 24, 24, 56, 112, 0,
2370 	0, 102, 60, 255, 60, 102, 0, 0, 0, 24, 24, 126, 24, 24, 0, 0,
2371 	0, 0, 0, 0, 0, 24, 24, 48, 0, 0, 0, 126, 0, 0, 0, 0,
2372 	0, 0, 0, 0, 0, 24, 24, 0, 0, 6, 12, 24, 48, 96, 64, 0,
2373 	0, 60, 102, 110, 118, 102, 60, 0, 0, 24, 56, 24, 24, 24, 126, 0,
2374 	0, 60, 102, 12, 24, 48, 126, 0, 0, 126, 12, 24, 12, 102, 60, 0,
2375 	0, 12, 28, 60, 108, 126, 12, 0, 0, 126, 96, 124, 6, 102, 60, 0,
2376 	0, 60, 96, 124, 102, 102, 60, 0, 0, 126, 6, 12, 24, 48, 48, 0,
2377 	0, 60, 102, 60, 102, 102, 60, 0, 0, 60, 102, 62, 6, 12, 56, 0,
2378 	0, 0, 24, 24, 0, 24, 24, 0, 0, 0, 24, 24, 0, 24, 24, 48,
2379 	6, 12, 24, 48, 24, 12, 6, 0, 0, 0, 126, 0, 0, 126, 0, 0,
2380 	96, 48, 24, 12, 24, 48, 96, 0, 0, 60, 102, 12, 24, 0, 24, 0,
2381 	0, 60, 102, 110, 110, 96, 62, 0, 0, 24, 60, 102, 102, 126, 102, 0,
2382 	0, 124, 102, 124, 102, 102, 124, 0, 0, 60, 102, 96, 96, 102, 60, 0,
2383 	0, 120, 108, 102, 102, 108, 120, 0, 0, 126, 96, 124, 96, 96, 126, 0,
2384 	0, 126, 96, 124, 96, 96, 96, 0, 0, 62, 96, 96, 110, 102, 62, 0,
2385 	0, 102, 102, 126, 102, 102, 102, 0, 0, 126, 24, 24, 24, 24, 126, 0,
2386 	0, 6, 6, 6, 6, 102, 60, 0, 0, 102, 108, 120, 120, 108, 102, 0,
2387 	0, 96, 96, 96, 96, 96, 126, 0, 0, 99, 119, 127, 107, 99, 99, 0,
2388 	0, 102, 118, 126, 126, 110, 102, 0, 0, 60, 102, 102, 102, 102, 60, 0,
2389 	0, 124, 102, 102, 124, 96, 96, 0, 0, 60, 102, 102, 102, 108, 54, 0,
2390 	0, 124, 102, 102, 124, 108, 102, 0, 0, 60, 96, 60, 6, 6, 60, 0,
2391 	0, 126, 24, 24, 24, 24, 24, 0, 0, 102, 102, 102, 102, 102, 126, 0,
2392 	0, 102, 102, 102, 102, 60, 24, 0, 0, 99, 99, 107, 127, 119, 99, 0,
2393 	0, 102, 102, 60, 60, 102, 102, 0, 0, 102, 102, 60, 24, 24, 24, 0,
2394 	0, 126, 12, 24, 48, 96, 126, 0, 0, 30, 24, 24, 24, 24, 30, 0,
2395 	0, 64, 96, 48, 24, 12, 6, 0, 0, 120, 24, 24, 24, 24, 120, 0,
2396 	0, 8, 28, 54, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0,
2397 	0, 54, 127, 127, 62, 28, 8, 0, 24, 24, 24, 31, 31, 24, 24, 24,
2398 	3, 3, 3, 3, 3, 3, 3, 3, 24, 24, 24, 248, 248, 0, 0, 0,
2399 	24, 24, 24, 248, 248, 24, 24, 24, 0, 0, 0, 248, 248, 24, 24, 24,
2400 	3, 7, 14, 28, 56, 112, 224, 192, 192, 224, 112, 56, 28, 14, 7, 3,
2401 	1, 3, 7, 15, 31, 63, 127, 255, 0, 0, 0, 0, 15, 15, 15, 15,
2402 	128, 192, 224, 240, 248, 252, 254, 255, 15, 15, 15, 15, 0, 0, 0, 0,
2403 	240, 240, 240, 240, 0, 0, 0, 0, 255, 255, 0, 0, 0, 0, 0, 0,
2404 	0, 0, 0, 0, 0, 0, 255, 255, 0, 0, 0, 0, 240, 240, 240, 240,
2405 	0, 28, 28, 119, 119, 8, 28, 0, 0, 0, 0, 31, 31, 24, 24, 24,
2406 	0, 0, 0, 255, 255, 0, 0, 0, 24, 24, 24, 255, 255, 24, 24, 24,
2407 	0, 0, 60, 126, 126, 126, 60, 0, 0, 0, 0, 0, 255, 255, 255, 255,
2408 	192, 192, 192, 192, 192, 192, 192, 192, 0, 0, 0, 255, 255, 24, 24, 24,
2409 	24, 24, 24, 255, 255, 0, 0, 0, 240, 240, 240, 240, 240, 240, 240, 240,
2410 	24, 24, 24, 31, 31, 0, 0, 0, 120, 96, 120, 96, 126, 24, 30, 0,
2411 	0, 24, 60, 126, 24, 24, 24, 0, 0, 24, 24, 24, 126, 60, 24, 0,
2412 	0, 24, 48, 126, 48, 24, 0, 0, 0, 24, 12, 126, 12, 24, 0, 0,
2413 	0, 24, 60, 126, 126, 60, 24, 0, 0, 0, 60, 6, 62, 102, 62, 0,
2414 	0, 96, 96, 124, 102, 102, 124, 0, 0, 0, 60, 96, 96, 96, 60, 0,
2415 	0, 6, 6, 62, 102, 102, 62, 0, 0, 0, 60, 102, 126, 96, 60, 0,
2416 	0, 14, 24, 62, 24, 24, 24, 0, 0, 0, 62, 102, 102, 62, 6, 124,
2417 	0, 96, 96, 124, 102, 102, 102, 0, 0, 24, 0, 56, 24, 24, 60, 0,
2418 	0, 6, 0, 6, 6, 6, 6, 60, 0, 96, 96, 108, 120, 108, 102, 0,
2419 	0, 56, 24, 24, 24, 24, 60, 0, 0, 0, 102, 127, 127, 107, 99, 0,
2420 	0, 0, 124, 102, 102, 102, 102, 0, 0, 0, 60, 102, 102, 102, 60, 0,
2421 	0, 0, 124, 102, 102, 124, 96, 96, 0, 0, 62, 102, 102, 62, 6, 6,
2422 	0, 0, 124, 102, 96, 96, 96, 0, 0, 0, 62, 96, 60, 6, 124, 0,
2423 	0, 24, 126, 24, 24, 24, 14, 0, 0, 0, 102, 102, 102, 102, 62, 0,
2424 	0, 0, 102, 102, 102, 60, 24, 0, 0, 0, 99, 107, 127, 62, 54, 0,
2425 	0, 0, 102, 60, 24, 60, 102, 0, 0, 0, 102, 102, 102, 62, 12, 120,
2426 	0, 0, 126, 12, 24, 48, 126, 0, 0, 24, 60, 126, 126, 24, 60, 0,
2427 	24, 24, 24, 24, 24, 24, 24, 24, 0, 126, 120, 124, 110, 102, 6, 0,
2428 	8, 24, 56, 120, 56, 24, 8, 0, 16, 24, 28, 30, 28, 24, 16, 0 };
2429 static const uint8_t CiResource_c16_pal[768] = {
2430 	3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
2431 	3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
2432 	3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
2433 	47, 47, 47, 61, 61, 61, 66, 66, 66, 86, 85, 90, 132, 126, 133, 178,
2434 	172, 179, 202, 202, 202, 249, 249, 249, 47, 47, 47, 61, 61, 61, 66, 66,
2435 	66, 86, 85, 90, 132, 126, 133, 178, 172, 179, 202, 202, 202, 249, 249, 249,
2436 	104, 16, 16, 117, 30, 32, 123, 40, 32, 144, 60, 59, 187, 103, 104, 233,
2437 	146, 146, 255, 172, 172, 255, 246, 242, 104, 16, 16, 117, 30, 32, 123, 40,
2438 	32, 144, 60, 59, 187, 103, 104, 233, 146, 146, 255, 172, 172, 255, 246, 242,
2439 	0, 66, 66, 0, 80, 79, 2, 86, 89, 23, 109, 114, 69, 150, 150, 108,
2440 	195, 193, 133, 216, 224, 209, 255, 255, 0, 66, 66, 0, 80, 79, 2, 86,
2441 	89, 23, 109, 114, 69, 150, 150, 108, 195, 193, 133, 216, 224, 209, 255, 255,
2442 	88, 0, 109, 106, 16, 120, 111, 26, 130, 135, 45, 153, 175, 88, 195, 217,
2443 	134, 240, 243, 156, 255, 255, 233, 255, 88, 0, 109, 106, 16, 120, 111, 26,
2444 	130, 135, 45, 153, 175, 88, 195, 217, 134, 240, 243, 156, 255, 255, 233, 255,
2445 	0, 78, 0, 4, 92, 0, 10, 101, 9, 31, 123, 21, 74, 167, 62, 121,
2446 	209, 118, 146, 234, 138, 219, 255, 211, 0, 78, 0, 4, 92, 0, 10, 101,
2447 	9, 31, 123, 21, 74, 167, 62, 121, 209, 118, 146, 234, 138, 219, 255, 211,
2448 	25, 28, 148, 42, 42, 163, 48, 52, 167, 70, 73, 193, 115, 115, 236, 157,
2449 	161, 255, 183, 186, 255, 240, 255, 255, 25, 28, 148, 42, 42, 163, 48, 52,
2450 	167, 70, 73, 193, 115, 115, 236, 157, 161, 255, 183, 186, 255, 240, 255, 255,
2451 	56, 56, 0, 76, 71, 0, 80, 81, 0, 102, 99, 0, 146, 141, 17, 189,
2452 	190, 64, 214, 211, 91, 255, 255, 163, 56, 56, 0, 76, 71, 0, 80, 81,
2453 	0, 102, 99, 0, 146, 141, 17, 189, 190, 64, 214, 211, 91, 255, 255, 163,
2454 	86, 32, 0, 105, 47, 0, 110, 54, 0, 132, 76, 13, 175, 120, 50, 220,
2455 	162, 97, 243, 190, 121, 255, 255, 193, 86, 32, 0, 105, 47, 0, 110, 54,
2456 	0, 132, 76, 13, 175, 120, 50, 220, 162, 97, 243, 190, 121, 255, 255, 193,
2457 	75, 40, 0, 89, 56, 0, 101, 64, 0, 115, 85, 0, 161, 128, 32, 209,
2458 	169, 76, 230, 197, 101, 255, 255, 178, 75, 40, 0, 89, 56, 0, 101, 64,
2459 	0, 115, 85, 0, 161, 128, 32, 209, 169, 76, 230, 197, 101, 255, 255, 178,
2460 	22, 72, 0, 38, 86, 0, 44, 92, 0, 64, 114, 0, 108, 158, 18, 147,
2461 	200, 61, 176, 224, 87, 252, 255, 162, 22, 72, 0, 38, 86, 0, 44, 92,
2462 	0, 64, 114, 0, 108, 158, 18, 147, 200, 61, 176, 224, 87, 252, 255, 162,
2463 	105, 7, 47, 117, 21, 65, 125, 30, 69, 145, 51, 94, 186, 95, 137, 233,
2464 	138, 177, 255, 164, 207, 255, 238, 255, 105, 7, 47, 117, 21, 65, 125, 30,
2465 	69, 145, 51, 94, 186, 95, 137, 233, 138, 177, 255, 164, 207, 255, 238, 255,
2466 	0, 70, 38, 0, 88, 61, 1, 97, 69, 25, 116, 92, 70, 159, 131, 111,
2467 	205, 171, 137, 229, 200, 209, 255, 255, 0, 70, 38, 0, 88, 61, 1, 97,
2468 	69, 25, 116, 92, 70, 159, 131, 111, 205, 171, 137, 229, 200, 209, 255, 255,
2469 	6, 42, 128, 21, 61, 143, 28, 69, 153, 50, 89, 174, 97, 133, 221, 138,
2470 	180, 255, 164, 202, 255, 235, 255, 255, 6, 42, 128, 21, 61, 143, 28, 69,
2471 	153, 50, 89, 174, 97, 133, 221, 138, 180, 255, 164, 202, 255, 235, 255, 255,
2472 	42, 20, 155, 57, 34, 174, 66, 45, 173, 89, 63, 195, 132, 108, 239, 178,
2473 	154, 255, 200, 184, 255, 255, 248, 255, 42, 20, 155, 57, 34, 174, 66, 45,
2474 	173, 89, 63, 195, 132, 108, 239, 178, 154, 255, 200, 184, 255, 255, 248, 255,
2475 	11, 73, 0, 25, 89, 0, 29, 98, 0, 50, 118, 0, 93, 163, 41, 136,
2476 	203, 89, 162, 229, 122, 237, 255, 188, 11, 73, 0, 25, 89, 0, 29, 98,
2477 	0, 50, 118, 0, 93, 163, 41, 136, 203, 89, 162, 229, 122, 237, 255, 188 };
2478 static const uint8_t CiResource_c64_fnt[2048] = {
2479 	60, 102, 110, 110, 96, 98, 60, 0, 24, 60, 102, 126, 102, 102, 102, 0,
2480 	124, 102, 102, 124, 102, 102, 124, 0, 60, 102, 96, 96, 96, 102, 60, 0,
2481 	120, 108, 102, 102, 102, 108, 120, 0, 126, 96, 96, 120, 96, 96, 126, 0,
2482 	126, 96, 96, 120, 96, 96, 96, 0, 60, 102, 96, 110, 102, 102, 60, 0,
2483 	102, 102, 102, 126, 102, 102, 102, 0, 60, 24, 24, 24, 24, 24, 60, 0,
2484 	30, 12, 12, 12, 12, 108, 56, 0, 102, 108, 120, 112, 120, 108, 102, 0,
2485 	96, 96, 96, 96, 96, 96, 126, 0, 99, 119, 127, 107, 99, 99, 99, 0,
2486 	102, 118, 126, 126, 110, 102, 102, 0, 60, 102, 102, 102, 102, 102, 60, 0,
2487 	124, 102, 102, 124, 96, 96, 96, 0, 60, 102, 102, 102, 102, 60, 14, 0,
2488 	124, 102, 102, 124, 120, 108, 102, 0, 60, 102, 96, 60, 6, 102, 60, 0,
2489 	126, 24, 24, 24, 24, 24, 24, 0, 102, 102, 102, 102, 102, 102, 60, 0,
2490 	102, 102, 102, 102, 102, 60, 24, 0, 99, 99, 99, 107, 127, 119, 99, 0,
2491 	102, 102, 60, 24, 60, 102, 102, 0, 102, 102, 102, 60, 24, 24, 24, 0,
2492 	126, 6, 12, 24, 48, 96, 126, 0, 60, 48, 48, 48, 48, 48, 60, 0,
2493 	12, 18, 48, 124, 48, 98, 252, 0, 60, 12, 12, 12, 12, 12, 60, 0,
2494 	0, 24, 60, 126, 24, 24, 24, 24, 0, 16, 48, 127, 127, 48, 16, 0,
2495 	0, 0, 0, 0, 0, 0, 0, 0, 24, 24, 24, 24, 0, 0, 24, 0,
2496 	102, 102, 102, 0, 0, 0, 0, 0, 102, 102, 255, 102, 255, 102, 102, 0,
2497 	24, 62, 96, 60, 6, 124, 24, 0, 98, 102, 12, 24, 48, 102, 70, 0,
2498 	60, 102, 60, 56, 103, 102, 63, 0, 6, 12, 24, 0, 0, 0, 0, 0,
2499 	12, 24, 48, 48, 48, 24, 12, 0, 48, 24, 12, 12, 12, 24, 48, 0,
2500 	0, 102, 60, 255, 60, 102, 0, 0, 0, 24, 24, 126, 24, 24, 0, 0,
2501 	0, 0, 0, 0, 0, 24, 24, 48, 0, 0, 0, 126, 0, 0, 0, 0,
2502 	0, 0, 0, 0, 0, 24, 24, 0, 0, 3, 6, 12, 24, 48, 96, 0,
2503 	60, 102, 110, 118, 102, 102, 60, 0, 24, 24, 56, 24, 24, 24, 126, 0,
2504 	60, 102, 6, 12, 48, 96, 126, 0, 60, 102, 6, 28, 6, 102, 60, 0,
2505 	6, 14, 30, 102, 127, 6, 6, 0, 126, 96, 124, 6, 6, 102, 60, 0,
2506 	60, 102, 96, 124, 102, 102, 60, 0, 126, 102, 12, 24, 24, 24, 24, 0,
2507 	60, 102, 102, 60, 102, 102, 60, 0, 60, 102, 102, 62, 6, 102, 60, 0,
2508 	0, 0, 24, 0, 0, 24, 0, 0, 0, 0, 24, 0, 0, 24, 24, 48,
2509 	14, 24, 48, 96, 48, 24, 14, 0, 0, 0, 126, 0, 126, 0, 0, 0,
2510 	112, 24, 12, 6, 12, 24, 112, 0, 60, 102, 6, 12, 24, 0, 24, 0,
2511 	0, 0, 0, 255, 255, 0, 0, 0, 8, 28, 62, 127, 127, 28, 62, 0,
2512 	24, 24, 24, 24, 24, 24, 24, 24, 0, 0, 0, 255, 255, 0, 0, 0,
2513 	0, 0, 255, 255, 0, 0, 0, 0, 0, 255, 255, 0, 0, 0, 0, 0,
2514 	0, 0, 0, 0, 255, 255, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48,
2515 	12, 12, 12, 12, 12, 12, 12, 12, 0, 0, 0, 224, 240, 56, 24, 24,
2516 	24, 24, 28, 15, 7, 0, 0, 0, 24, 24, 56, 240, 224, 0, 0, 0,
2517 	192, 192, 192, 192, 192, 192, 255, 255, 192, 224, 112, 56, 28, 14, 7, 3,
2518 	3, 7, 14, 28, 56, 112, 224, 192, 255, 255, 192, 192, 192, 192, 192, 192,
2519 	255, 255, 3, 3, 3, 3, 3, 3, 0, 60, 126, 126, 126, 126, 60, 0,
2520 	0, 0, 0, 0, 0, 255, 255, 0, 54, 127, 127, 127, 62, 28, 8, 0,
2521 	96, 96, 96, 96, 96, 96, 96, 96, 0, 0, 0, 7, 15, 28, 24, 24,
2522 	195, 231, 126, 60, 60, 126, 231, 195, 0, 60, 126, 102, 102, 126, 60, 0,
2523 	24, 24, 102, 102, 24, 24, 60, 0, 6, 6, 6, 6, 6, 6, 6, 6,
2524 	8, 28, 62, 127, 62, 28, 8, 0, 24, 24, 24, 255, 255, 24, 24, 24,
2525 	192, 192, 48, 48, 192, 192, 48, 48, 24, 24, 24, 24, 24, 24, 24, 24,
2526 	0, 0, 3, 62, 118, 54, 54, 0, 255, 127, 63, 31, 15, 7, 3, 1,
2527 	0, 0, 0, 0, 0, 0, 0, 0, 240, 240, 240, 240, 240, 240, 240, 240,
2528 	0, 0, 0, 0, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0,
2529 	0, 0, 0, 0, 0, 0, 0, 255, 192, 192, 192, 192, 192, 192, 192, 192,
2530 	204, 204, 51, 51, 204, 204, 51, 51, 3, 3, 3, 3, 3, 3, 3, 3,
2531 	0, 0, 0, 0, 204, 204, 51, 51, 255, 254, 252, 248, 240, 224, 192, 128,
2532 	3, 3, 3, 3, 3, 3, 3, 3, 24, 24, 24, 31, 31, 24, 24, 24,
2533 	0, 0, 0, 0, 15, 15, 15, 15, 24, 24, 24, 31, 31, 0, 0, 0,
2534 	0, 0, 0, 248, 248, 24, 24, 24, 0, 0, 0, 0, 0, 0, 255, 255,
2535 	0, 0, 0, 31, 31, 24, 24, 24, 24, 24, 24, 255, 255, 0, 0, 0,
2536 	0, 0, 0, 255, 255, 24, 24, 24, 24, 24, 24, 248, 248, 24, 24, 24,
2537 	192, 192, 192, 192, 192, 192, 192, 192, 224, 224, 224, 224, 224, 224, 224, 224,
2538 	7, 7, 7, 7, 7, 7, 7, 7, 255, 255, 0, 0, 0, 0, 0, 0,
2539 	255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255,
2540 	3, 3, 3, 3, 3, 3, 255, 255, 0, 0, 0, 0, 240, 240, 240, 240,
2541 	15, 15, 15, 15, 0, 0, 0, 0, 24, 24, 24, 248, 248, 0, 0, 0,
2542 	240, 240, 240, 240, 0, 0, 0, 0, 240, 240, 240, 240, 15, 15, 15, 15,
2543 	195, 153, 145, 145, 159, 153, 195, 255, 231, 195, 153, 129, 153, 153, 153, 255,
2544 	131, 153, 153, 131, 153, 153, 131, 255, 195, 153, 159, 159, 159, 153, 195, 255,
2545 	135, 147, 153, 153, 153, 147, 135, 255, 129, 159, 159, 135, 159, 159, 129, 255,
2546 	129, 159, 159, 135, 159, 159, 159, 255, 195, 153, 159, 145, 153, 153, 195, 255,
2547 	153, 153, 153, 129, 153, 153, 153, 255, 195, 231, 231, 231, 231, 231, 195, 255,
2548 	225, 243, 243, 243, 243, 147, 199, 255, 153, 147, 135, 143, 135, 147, 153, 255,
2549 	159, 159, 159, 159, 159, 159, 129, 255, 156, 136, 128, 148, 156, 156, 156, 255,
2550 	153, 137, 129, 129, 145, 153, 153, 255, 195, 153, 153, 153, 153, 153, 195, 255,
2551 	131, 153, 153, 131, 159, 159, 159, 255, 195, 153, 153, 153, 153, 195, 241, 255,
2552 	131, 153, 153, 131, 135, 147, 153, 255, 195, 153, 159, 195, 249, 153, 195, 255,
2553 	129, 231, 231, 231, 231, 231, 231, 255, 153, 153, 153, 153, 153, 153, 195, 255,
2554 	153, 153, 153, 153, 153, 195, 231, 255, 156, 156, 156, 148, 128, 136, 156, 255,
2555 	153, 153, 195, 231, 195, 153, 153, 255, 153, 153, 153, 195, 231, 231, 231, 255,
2556 	129, 249, 243, 231, 207, 159, 129, 255, 195, 207, 207, 207, 207, 207, 195, 255,
2557 	243, 237, 207, 131, 207, 157, 3, 255, 195, 243, 243, 243, 243, 243, 195, 255,
2558 	255, 231, 195, 129, 231, 231, 231, 231, 255, 239, 207, 128, 128, 207, 239, 255,
2559 	255, 255, 255, 255, 255, 255, 255, 255, 231, 231, 231, 231, 255, 255, 231, 255,
2560 	153, 153, 153, 255, 255, 255, 255, 255, 153, 153, 0, 153, 0, 153, 153, 255,
2561 	231, 193, 159, 195, 249, 131, 231, 255, 157, 153, 243, 231, 207, 153, 185, 255,
2562 	195, 153, 195, 199, 152, 153, 192, 255, 249, 243, 231, 255, 255, 255, 255, 255,
2563 	243, 231, 207, 207, 207, 231, 243, 255, 207, 231, 243, 243, 243, 231, 207, 255,
2564 	255, 153, 195, 0, 195, 153, 255, 255, 255, 231, 231, 129, 231, 231, 255, 255,
2565 	255, 255, 255, 255, 255, 231, 231, 207, 255, 255, 255, 129, 255, 255, 255, 255,
2566 	255, 255, 255, 255, 255, 231, 231, 255, 255, 252, 249, 243, 231, 207, 159, 255,
2567 	195, 153, 145, 137, 153, 153, 195, 255, 231, 231, 199, 231, 231, 231, 129, 255,
2568 	195, 153, 249, 243, 207, 159, 129, 255, 195, 153, 249, 227, 249, 153, 195, 255,
2569 	249, 241, 225, 153, 128, 249, 249, 255, 129, 159, 131, 249, 249, 153, 195, 255,
2570 	195, 153, 159, 131, 153, 153, 195, 255, 129, 153, 243, 231, 231, 231, 231, 255,
2571 	195, 153, 153, 195, 153, 153, 195, 255, 195, 153, 153, 193, 249, 153, 195, 255,
2572 	255, 255, 231, 255, 255, 231, 255, 255, 255, 255, 231, 255, 255, 231, 231, 207,
2573 	241, 231, 207, 159, 207, 231, 241, 255, 255, 255, 129, 255, 129, 255, 255, 255,
2574 	143, 231, 243, 249, 243, 231, 143, 255, 195, 153, 249, 243, 231, 255, 231, 255,
2575 	255, 255, 255, 0, 0, 255, 255, 255, 247, 227, 193, 128, 128, 227, 193, 255,
2576 	231, 231, 231, 231, 231, 231, 231, 231, 255, 255, 255, 0, 0, 255, 255, 255,
2577 	255, 255, 0, 0, 255, 255, 255, 255, 255, 0, 0, 255, 255, 255, 255, 255,
2578 	255, 255, 255, 255, 0, 0, 255, 255, 207, 207, 207, 207, 207, 207, 207, 207,
2579 	243, 243, 243, 243, 243, 243, 243, 243, 255, 255, 255, 31, 15, 199, 231, 231,
2580 	231, 231, 227, 240, 248, 255, 255, 255, 231, 231, 199, 15, 31, 255, 255, 255,
2581 	63, 63, 63, 63, 63, 63, 0, 0, 63, 31, 143, 199, 227, 241, 248, 252,
2582 	252, 248, 241, 227, 199, 143, 31, 63, 0, 0, 63, 63, 63, 63, 63, 63,
2583 	0, 0, 252, 252, 252, 252, 252, 252, 255, 195, 129, 129, 129, 129, 195, 255,
2584 	255, 255, 255, 255, 255, 0, 0, 255, 201, 128, 128, 128, 193, 227, 247, 255,
2585 	159, 159, 159, 159, 159, 159, 159, 159, 255, 255, 255, 248, 240, 227, 231, 231,
2586 	60, 24, 129, 195, 195, 129, 24, 60, 255, 195, 129, 153, 153, 129, 195, 255,
2587 	231, 231, 153, 153, 231, 231, 195, 255, 249, 249, 249, 249, 249, 249, 249, 249,
2588 	247, 227, 193, 128, 193, 227, 247, 255, 231, 231, 231, 0, 0, 231, 231, 231,
2589 	63, 63, 207, 207, 63, 63, 207, 207, 231, 231, 231, 231, 231, 231, 231, 231,
2590 	255, 255, 252, 193, 137, 201, 201, 255, 0, 128, 192, 224, 240, 248, 252, 254,
2591 	255, 255, 255, 255, 255, 255, 255, 255, 15, 15, 15, 15, 15, 15, 15, 15,
2592 	255, 255, 255, 255, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255,
2593 	255, 255, 255, 255, 255, 255, 255, 0, 63, 63, 63, 63, 63, 63, 63, 63,
2594 	51, 51, 204, 204, 51, 51, 204, 204, 252, 252, 252, 252, 252, 252, 252, 252,
2595 	255, 255, 255, 255, 51, 51, 204, 204, 0, 1, 3, 7, 15, 31, 63, 127,
2596 	252, 252, 252, 252, 252, 252, 252, 252, 231, 231, 231, 224, 224, 231, 231, 231,
2597 	255, 255, 255, 255, 240, 240, 240, 240, 231, 231, 231, 224, 224, 255, 255, 255,
2598 	255, 255, 255, 7, 7, 231, 231, 231, 255, 255, 255, 255, 255, 255, 0, 0,
2599 	255, 255, 255, 224, 224, 231, 231, 231, 231, 231, 231, 0, 0, 255, 255, 255,
2600 	255, 255, 255, 0, 0, 231, 231, 231, 231, 231, 231, 7, 7, 231, 231, 231,
2601 	63, 63, 63, 63, 63, 63, 63, 63, 31, 31, 31, 31, 31, 31, 31, 31,
2602 	248, 248, 248, 248, 248, 248, 248, 248, 0, 0, 255, 255, 255, 255, 255, 255,
2603 	0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0,
2604 	252, 252, 252, 252, 252, 252, 0, 0, 255, 255, 255, 255, 15, 15, 15, 15,
2605 	240, 240, 240, 240, 255, 255, 255, 255, 231, 231, 231, 7, 7, 255, 255, 255,
2606 	15, 15, 15, 15, 255, 255, 255, 255, 15, 15, 15, 15, 240, 240, 240, 240 };
2607 static const uint8_t CiResource_zx81_fnt[512] = {
2608 	0, 0, 0, 0, 0, 0, 0, 0, 240, 240, 240, 240, 0, 0, 0, 0,
2609 	15, 15, 15, 15, 0, 0, 0, 0, 255, 255, 255, 255, 0, 0, 0, 0,
2610 	0, 0, 0, 0, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
2611 	15, 15, 15, 15, 240, 240, 240, 240, 255, 255, 255, 255, 240, 240, 240, 240,
2612 	170, 85, 170, 85, 170, 85, 170, 85, 0, 0, 0, 0, 170, 85, 170, 85,
2613 	170, 85, 170, 85, 0, 0, 0, 0, 0, 36, 36, 0, 0, 0, 0, 0,
2614 	0, 28, 34, 120, 32, 32, 126, 0, 0, 8, 62, 40, 62, 10, 62, 8,
2615 	0, 0, 0, 16, 0, 0, 16, 0, 0, 60, 66, 4, 8, 0, 8, 0,
2616 	0, 4, 8, 8, 8, 8, 4, 0, 0, 32, 16, 16, 16, 16, 32, 0,
2617 	0, 0, 16, 8, 4, 8, 16, 0, 0, 0, 4, 8, 16, 8, 4, 0,
2618 	0, 0, 0, 62, 0, 62, 0, 0, 0, 0, 8, 8, 62, 8, 8, 0,
2619 	0, 0, 0, 0, 62, 0, 0, 0, 0, 0, 20, 8, 62, 8, 20, 0,
2620 	0, 0, 2, 4, 8, 16, 32, 0, 0, 0, 16, 0, 0, 16, 16, 32,
2621 	0, 0, 0, 0, 0, 8, 8, 16, 0, 0, 0, 0, 0, 24, 24, 0,
2622 	0, 60, 70, 74, 82, 98, 60, 0, 0, 24, 40, 8, 8, 8, 62, 0,
2623 	0, 60, 66, 2, 60, 64, 126, 0, 0, 60, 66, 12, 2, 66, 60, 0,
2624 	0, 8, 24, 40, 72, 126, 8, 0, 0, 126, 64, 124, 2, 66, 60, 0,
2625 	0, 60, 64, 124, 66, 66, 60, 0, 0, 126, 2, 4, 8, 16, 16, 0,
2626 	0, 60, 66, 60, 66, 66, 60, 0, 0, 60, 66, 66, 62, 2, 60, 0,
2627 	0, 60, 66, 66, 126, 66, 66, 0, 0, 124, 66, 124, 66, 66, 124, 0,
2628 	0, 60, 66, 64, 64, 66, 60, 0, 0, 120, 68, 66, 66, 68, 120, 0,
2629 	0, 126, 64, 124, 64, 64, 126, 0, 0, 126, 64, 124, 64, 64, 64, 0,
2630 	0, 60, 66, 64, 78, 66, 60, 0, 0, 66, 66, 126, 66, 66, 66, 0,
2631 	0, 62, 8, 8, 8, 8, 62, 0, 0, 2, 2, 2, 66, 66, 60, 0,
2632 	0, 68, 72, 112, 72, 68, 66, 0, 0, 64, 64, 64, 64, 64, 126, 0,
2633 	0, 66, 102, 90, 66, 66, 66, 0, 0, 66, 98, 82, 74, 70, 66, 0,
2634 	0, 60, 66, 66, 66, 66, 60, 0, 0, 124, 66, 66, 124, 64, 64, 0,
2635 	0, 60, 66, 66, 82, 74, 60, 0, 0, 124, 66, 66, 124, 68, 66, 0,
2636 	0, 60, 64, 60, 2, 66, 60, 0, 0, 254, 16, 16, 16, 16, 16, 0,
2637 	0, 66, 66, 66, 66, 66, 60, 0, 0, 66, 66, 66, 66, 36, 24, 0,
2638 	0, 66, 66, 66, 66, 90, 36, 0, 0, 66, 36, 24, 24, 36, 66, 0,
2639 	0, 130, 68, 40, 16, 16, 16, 0, 0, 126, 4, 8, 16, 32, 126, 0 };
2640 
Stream_ReadByte(Stream * self)2641 static int Stream_ReadByte(Stream *self)
2642 {
2643 	if (self->contentOffset >= self->contentLength)
2644 		return -1;
2645 	return self->content[self->contentOffset++];
2646 }
2647 
Stream_SkipUntilByte(Stream * self,int expected)2648 static bool Stream_SkipUntilByte(Stream *self, int expected)
2649 {
2650 	for (;;) {
2651 		int b = Stream_ReadByte(self);
2652 		if (b < 0)
2653 			return false;
2654 		if (b == expected)
2655 			return true;
2656 	}
2657 }
2658 
Stream_ReadBytes(Stream * self,uint8_t * dest,int destOffset,int count)2659 static bool Stream_ReadBytes(Stream *self, uint8_t *dest, int destOffset, int count)
2660 {
2661 	int nextOffset = self->contentOffset + count;
2662 	if (nextOffset > self->contentLength)
2663 		return false;
2664 	memcpy(dest + destOffset, self->content + self->contentOffset, count);
2665 	self->contentOffset = nextOffset;
2666 	return true;
2667 }
2668 
Stream_ReadHexDigit(Stream * self)2669 static int Stream_ReadHexDigit(Stream *self)
2670 {
2671 	if (self->contentOffset >= self->contentLength)
2672 		return -1;
2673 	int c = self->content[self->contentOffset++];
2674 	if (c >= 48 && c <= 57)
2675 		return c - 48;
2676 	if (c >= 65 && c <= 70)
2677 		return c - 55;
2678 	if (c >= 97 && c <= 102)
2679 		return c - 87;
2680 	self->contentOffset--;
2681 	return -1;
2682 }
2683 
Stream_ParseInt(Stream * self)2684 static int Stream_ParseInt(Stream *self)
2685 {
2686 	for (int r = 0;;) {
2687 		int c = Stream_ReadByte(self);
2688 		if (c < 48 || c > 57) {
2689 			if (c != 13 || Stream_ReadByte(self) != 10)
2690 				return -1;
2691 			return r;
2692 		}
2693 		if (r > 3200)
2694 			return -1;
2695 		r = r * 10 + c - 48;
2696 	}
2697 }
2698 
EndianStream_ReadWord(EndianStream * self)2699 static int EndianStream_ReadWord(EndianStream *self)
2700 {
2701 	if (self->base.contentOffset + 1 >= self->base.contentLength)
2702 		return -1;
2703 	int first = self->base.content[self->base.contentOffset];
2704 	int second = self->base.content[self->base.contentOffset + 1];
2705 	self->base.contentOffset += 2;
2706 	return self->bigEndian ? first << 8 | second : first | second << 8;
2707 }
2708 
EndianStream_ReadInt(EndianStream * self)2709 static int EndianStream_ReadInt(EndianStream *self)
2710 {
2711 	int value = self->bigEndian ? RECOIL_Get32BigEndian(self->base.content, self->base.contentOffset) : RECOIL_Get32LittleEndian(self->base.content, self->base.contentOffset);
2712 	self->base.contentOffset += 4;
2713 	return value;
2714 }
2715 
DaliStream_Decode(DaliStream * self,int countLength,RECOIL * recoil,int paletteOffset,int mode)2716 static bool DaliStream_Decode(DaliStream *self, int countLength, RECOIL *recoil, int paletteOffset, int mode)
2717 {
2718 	uint8_t unpacked[32000];
2719 	int valueOffset = self->base.contentOffset + countLength - 4;
2720 	int count = 1;
2721 	for (int x = 0; x < 160; x += 4) {
2722 		for (int unpackedOffset = x; unpackedOffset < 32000; unpackedOffset += 160) {
2723 			if (--count <= 0) {
2724 				if (valueOffset + 7 >= self->base.contentLength)
2725 					return false;
2726 				count = self->base.content[self->base.contentOffset++];
2727 				if (count == 0)
2728 					return false;
2729 				valueOffset += 4;
2730 			}
2731 			memcpy(unpacked + unpackedOffset, self->base.content + valueOffset, 4);
2732 		}
2733 	}
2734 	return RECOIL_DecodeSt(recoil, unpacked, 0, self->base.content, paletteOffset, mode, 0);
2735 }
2736 
ZxpStream_ReadChar(ZxpStream * self)2737 static int ZxpStream_ReadChar(ZxpStream *self)
2738 {
2739 	int c = Stream_ReadByte(&self->base);
2740 	if (c == 13 && self->base.contentOffset < self->base.contentLength && self->base.content[self->base.contentOffset] == 10) {
2741 		self->base.contentOffset++;
2742 		return 10;
2743 	}
2744 	return c;
2745 }
2746 
ZxpStream_IsEof(const ZxpStream * self)2747 static bool ZxpStream_IsEof(const ZxpStream *self)
2748 {
2749 	return self->base.contentOffset >= self->base.contentLength;
2750 }
2751 
SprStream_ReadBase(SprStream * self,int b)2752 static int SprStream_ReadBase(SprStream *self, int b)
2753 {
2754 	int r = Stream_ReadHexDigit(&self->base);
2755 	if (r < 0 || r >= b)
2756 		return -1;
2757 	do {
2758 		int d = Stream_ReadHexDigit(&self->base);
2759 		if (d < 0)
2760 			return r;
2761 		if (d >= b)
2762 			return -1;
2763 		r = r * b + d;
2764 	}
2765 	while (r < 320);
2766 	return -1;
2767 }
2768 
SprStream_ReadInt(SprStream * self)2769 static int SprStream_ReadInt(SprStream *self)
2770 {
2771 	while (self->base.contentOffset < self->base.contentLength) {
2772 		int c = self->base.content[self->base.contentOffset];
2773 		switch (c) {
2774 		case 32:
2775 		case 9:
2776 		case 13:
2777 		case 10:
2778 			self->base.contentOffset++;
2779 			break;
2780 		case 36:
2781 			self->base.contentOffset++;
2782 			return SprStream_ReadBase(self, 16);
2783 		case 37:
2784 			self->base.contentOffset++;
2785 			return SprStream_ReadBase(self, 2);
2786 		default:
2787 			return SprStream_ReadBase(self, 10);
2788 		}
2789 	}
2790 	return -1;
2791 }
2792 
BitStream_Construct(BitStream * self)2793 static void BitStream_Construct(BitStream *self)
2794 {
2795 	static const BitStreamVtbl vtbl = {
2796 		BitStream_ReadBit,
2797 	};
2798 	self->vtbl = &vtbl;
2799 	self->bits = 0;
2800 }
2801 
BitStream_ReadBit(BitStream * self)2802 static int BitStream_ReadBit(BitStream *self)
2803 {
2804 	if ((self->bits & 127) == 0) {
2805 		if (self->base.contentOffset >= self->base.contentLength)
2806 			return -1;
2807 		self->bits = self->base.content[self->base.contentOffset++] << 1 | 1;
2808 	}
2809 	else
2810 		self->bits <<= 1;
2811 	return self->bits >> 8 & 1;
2812 }
2813 
BitStream_ReadBits(BitStream * self,int count)2814 static int BitStream_ReadBits(BitStream *self, int count)
2815 {
2816 	int result = 0;
2817 	while (--count >= 0) {
2818 		int bit = self->vtbl->readBit(self);
2819 		if (bit < 0)
2820 			return -1;
2821 		result = result << 1 | bit;
2822 	}
2823 	return result;
2824 }
2825 
BitStream_ReadNl3Char(BitStream * self,bool skipSpace)2826 static int BitStream_ReadNl3Char(BitStream *self, bool skipSpace)
2827 {
2828 	int e;
2829 	do
2830 		e = Stream_ReadByte(&self->base);
2831 	while (e == 13 || e == 10 || (skipSpace && e == 32));
2832 	if (e != 239)
2833 		return e;
2834 	if (self->base.contentOffset + 1 >= self->base.contentLength)
2835 		return -1;
2836 	switch (self->base.content[self->base.contentOffset++]) {
2837 	case 189:
2838 		e = self->base.content[self->base.contentOffset++];
2839 		if (e >= 160 && e <= 191)
2840 			return e;
2841 		break;
2842 	case 190:
2843 		e = self->base.content[self->base.contentOffset++];
2844 		if (e >= 128 && e <= 159)
2845 			return e + 64;
2846 		break;
2847 	default:
2848 		break;
2849 	}
2850 	return -1;
2851 }
2852 
X68KPicStream_Construct(X68KPicStream * self)2853 static void X68KPicStream_Construct(X68KPicStream *self)
2854 {
2855 	BitStream_Construct(&self->base);
2856 }
2857 
X68KPicStream_ReadLength(X68KPicStream * self)2858 static int X68KPicStream_ReadLength(X68KPicStream *self)
2859 {
2860 	for (int bits = 1; bits < 21; bits++) {
2861 		switch (self->base.vtbl->readBit(&self->base)) {
2862 		case 0:
2863 			;
2864 			int length = BitStream_ReadBits(&self->base, bits);
2865 			if (length < 0)
2866 				return -1;
2867 			return length + (1 << bits) - 1;
2868 		case 1:
2869 			break;
2870 		default:
2871 			return -1;
2872 		}
2873 	}
2874 	return -1;
2875 }
2876 
Mx1Stream_Construct(Mx1Stream * self)2877 static void Mx1Stream_Construct(Mx1Stream *self)
2878 {
2879 	X68KPicStream_Construct(&self->base);
2880 	static const BitStreamVtbl vtbl = {
2881 		(int (*)(BitStream *self)) Mx1Stream_ReadBit,
2882 	};
2883 	self->base.base.vtbl = &vtbl;
2884 	int d = 0;
2885 	for (int e = 0; e < 256; e++) {
2886 		if ((e >= 33 && e <= 126 && e != 34 && e != 39 && e != 44 && e != 64 && e != 92 && e != 96) || (e >= 161 && e <= 200))
2887 			self->decodeTable[e] = (uint8_t) d++;
2888 		else
2889 			self->decodeTable[e] = 128;
2890 	}
2891 }
2892 
Mx1Stream_FindImage(Mx1Stream * self)2893 static bool Mx1Stream_FindImage(Mx1Stream *self)
2894 {
2895 	for (;;) {
2896 		int lineOffset = self->base.base.base.contentOffset;
2897 		for (;;) {
2898 			int c = Stream_ReadByte(&self->base.base.base);
2899 			if (c < 0)
2900 				return false;
2901 			if (c == 13 || c == 10)
2902 				break;
2903 		}
2904 		if (self->base.base.base.contentOffset - lineOffset >= 17 && RECOIL_IsStringAt(self->base.base.base.content, lineOffset, "@@@ ") && RECOIL_IsStringAt(self->base.base.base.content, self->base.base.base.contentOffset - 11, "lines) @@@")) {
2905 			self->base.base.bits = 0;
2906 			return true;
2907 		}
2908 	}
2909 }
2910 
Mx1Stream_ReadBit(Mx1Stream * self)2911 static int Mx1Stream_ReadBit(Mx1Stream *self)
2912 {
2913 	if ((self->base.base.bits & 63) == 0) {
2914 		int e = BitStream_ReadNl3Char(&self->base.base, true);
2915 		if (e < 0)
2916 			return -1;
2917 		int d = self->decodeTable[e];
2918 		if (d >= 128)
2919 			return -1;
2920 		self->base.base.bits = d << 1 | 1;
2921 	}
2922 	else
2923 		self->base.base.bits <<= 1;
2924 	return self->base.base.bits >> 7 & 1;
2925 }
2926 
MppPaletteStream_Construct(MppPaletteStream * self)2927 static void MppPaletteStream_Construct(MppPaletteStream *self)
2928 {
2929 	BitStream_Construct(&self->base);
2930 }
2931 
MppPaletteStream_Read(MppPaletteStream * self)2932 static int MppPaletteStream_Read(MppPaletteStream *self)
2933 {
2934 	int rgb;
2935 	switch (self->base.base.content[4] & 3) {
2936 	case 0:
2937 		rgb = BitStream_ReadBits(&self->base, 9);
2938 		rgb = (rgb & 448) << 10 | (rgb & 56) << 5 | (rgb & 7);
2939 		return rgb << 5 | rgb << 2 | (rgb >> 1 & 197379);
2940 	case 1:
2941 		rgb = BitStream_ReadBits(&self->base, 12);
2942 		rgb = (rgb & 1792) << 9 | (rgb & 2160) << 5 | (rgb & 135) << 1 | (rgb & 8) >> 3;
2943 		return rgb << 4 | rgb;
2944 	case 3:
2945 		return RECOIL_GetSteInterlacedColor(BitStream_ReadBits(&self->base, 15));
2946 	default:
2947 		return 0;
2948 	}
2949 }
2950 
MultiPalette_Construct(MultiPalette * self)2951 static void MultiPalette_Construct(MultiPalette *self)
2952 {
2953 	BitStream_Construct(&self->base);
2954 }
2955 
ArtPalette_Construct(ArtPalette * self)2956 static void ArtPalette_Construct(ArtPalette *self)
2957 {
2958 	MultiPalette_Construct(&self->base);
2959 	static const MultiPaletteVtbl vtbl = {
2960 		BitStream_ReadBit,
2961 		(void (*)(MultiPalette *self, RECOIL *recoil, int y)) ArtPalette_SetLinePalette,
2962 	};
2963 	self->base.base.vtbl = (const BitStreamVtbl *) &vtbl;
2964 }
2965 
ArtPalette_SetLinePalette(ArtPalette * self,RECOIL * recoil,int y)2966 static void ArtPalette_SetLinePalette(ArtPalette *self, RECOIL *recoil, int y)
2967 {
2968 	if ((y & 1) == 0)
2969 		RECOIL_SetStPalette(recoil, self->base.base.base.content, 32768 + (y << 4), 16);
2970 }
2971 
RastPalette_Construct(RastPalette * self)2972 static void RastPalette_Construct(RastPalette *self)
2973 {
2974 	MultiPalette_Construct(&self->base);
2975 	static const MultiPaletteVtbl vtbl = {
2976 		BitStream_ReadBit,
2977 		(void (*)(MultiPalette *self, RECOIL *recoil, int y)) RastPalette_SetLinePalette,
2978 	};
2979 	self->base.base.vtbl = (const BitStreamVtbl *) &vtbl;
2980 }
2981 
RastPalette_SetLinePalette(RastPalette * self,RECOIL * recoil,int y)2982 static void RastPalette_SetLinePalette(RastPalette *self, RECOIL *recoil, int y)
2983 {
2984 	int paletteLength = (1 + self->colors) << 1;
2985 	for (int offset = self->base.base.base.contentOffset; offset <= self->base.base.base.contentLength - paletteLength; offset += paletteLength) {
2986 		if (y == (self->base.base.base.content[offset] << 8 | self->base.base.base.content[offset + 1])) {
2987 			RECOIL_SetStPalette(recoil, self->base.base.base.content, offset + 2, self->colors);
2988 			break;
2989 		}
2990 	}
2991 }
2992 
HblPalette_Construct(HblPalette * self)2993 static void HblPalette_Construct(HblPalette *self)
2994 {
2995 	MultiPalette_Construct(&self->base);
2996 	static const MultiPaletteVtbl vtbl = {
2997 		BitStream_ReadBit,
2998 		(void (*)(MultiPalette *self, RECOIL *recoil, int y)) HblPalette_SetLinePalette,
2999 	};
3000 	self->base.base.vtbl = (const BitStreamVtbl *) &vtbl;
3001 }
3002 
HblPalette_HasPalette(const HblPalette * self,int row)3003 static bool HblPalette_HasPalette(const HblPalette *self, int row)
3004 {
3005 	return self->base.base.base.content[row << 1] != 255 || self->base.base.base.content[row << 1 | 1] != 255;
3006 }
3007 
HblPalette_Init(HblPalette * self)3008 static bool HblPalette_Init(HblPalette *self)
3009 {
3010 	if (!HblPalette_HasPalette(self, 0))
3011 		return false;
3012 	self->base.base.base.contentOffset = 896;
3013 	for (int row = 1; row < 50; row++) {
3014 		if (HblPalette_HasPalette(self, row))
3015 			self->base.base.base.contentOffset += 48;
3016 	}
3017 	return self->base.base.base.contentOffset <= self->base.base.base.contentLength;
3018 }
3019 
HblPalette_SetLinePalette(HblPalette * self,RECOIL * recoil,int y)3020 static void HblPalette_SetLinePalette(HblPalette *self, RECOIL *recoil, int y)
3021 {
3022 	if ((y & 3) == 0 && HblPalette_HasPalette(self, y >> 2)) {
3023 		self->base.base.base.contentOffset -= 48;
3024 		int bitplanes = RECOIL_GetWidth(recoil) == 320 || y == 0 ? 4 : 2;
3025 		for (int c = 0; c < 1 << bitplanes; c++) {
3026 			int offset = self->base.base.base.contentOffset + c * 3;
3027 			int rgb = (self->base.base.base.content[offset] << 16 | self->base.base.base.content[offset + 1] << 8 | self->base.base.base.content[offset + 2]) & 460551;
3028 			RECOIL_SetStVdiColor(recoil, c, rgb << 5 | rgb << 2 | (rgb >> 1 & 197379), bitplanes);
3029 		}
3030 	}
3031 }
3032 
CtblPalette_Construct(CtblPalette * self)3033 static void CtblPalette_Construct(CtblPalette *self)
3034 {
3035 	MultiPalette_Construct(&self->base);
3036 	static const MultiPaletteVtbl vtbl = {
3037 		BitStream_ReadBit,
3038 		(void (*)(MultiPalette *self, RECOIL *recoil, int y)) CtblPalette_SetLinePalette,
3039 	};
3040 	self->base.base.vtbl = (const BitStreamVtbl *) &vtbl;
3041 }
3042 
CtblPalette_SetLinePalette(CtblPalette * self,RECOIL * recoil,int y)3043 static void CtblPalette_SetLinePalette(CtblPalette *self, RECOIL *recoil, int y)
3044 {
3045 	RECOIL_SetOcsPalette(recoil, self->base.base.base.content, self->base.base.base.contentOffset + (y * self->colors << 1), self->colors);
3046 }
3047 
ShamLacePalette_Construct(ShamLacePalette * self)3048 static void ShamLacePalette_Construct(ShamLacePalette *self)
3049 {
3050 	MultiPalette_Construct(&self->base);
3051 	static const MultiPaletteVtbl vtbl = {
3052 		BitStream_ReadBit,
3053 		(void (*)(MultiPalette *self, RECOIL *recoil, int y)) ShamLacePalette_SetLinePalette,
3054 	};
3055 	self->base.base.vtbl = (const BitStreamVtbl *) &vtbl;
3056 }
3057 
ShamLacePalette_SetLinePalette(ShamLacePalette * self,RECOIL * recoil,int y)3058 static void ShamLacePalette_SetLinePalette(ShamLacePalette *self, RECOIL *recoil, int y)
3059 {
3060 	RECOIL_SetOcsPalette(recoil, self->base.base.base.content, self->base.base.base.contentOffset + (y >> 1 << 5), 16);
3061 }
3062 
PchgPalette_Construct(PchgPalette * self)3063 static void PchgPalette_Construct(PchgPalette *self)
3064 {
3065 	MultiPalette_Construct(&self->base);
3066 	static const MultiPaletteVtbl vtbl = {
3067 		BitStream_ReadBit,
3068 		(void (*)(MultiPalette *self, RECOIL *recoil, int y)) PchgPalette_SetLinePalette,
3069 	};
3070 	self->base.base.vtbl = (const BitStreamVtbl *) &vtbl;
3071 }
3072 
PchgPalette_ReadHuffman(PchgPalette * self)3073 static int PchgPalette_ReadHuffman(PchgPalette *self)
3074 {
3075 	int offset = self->treeLastOffset;
3076 	for (;;) {
3077 		switch (self->base.base.vtbl->readBit(&self->base.base)) {
3078 		case 0:
3079 			offset -= 2;
3080 			if (offset < self->treeOffset)
3081 				return -1;
3082 			if ((self->base.base.base.content[offset] & 129) == 1)
3083 				return self->base.base.base.content[offset + 1];
3084 			break;
3085 		case 1:
3086 			;
3087 			int hi = self->base.base.base.content[offset];
3088 			int lo = self->base.base.base.content[offset + 1];
3089 			if (hi < 128)
3090 				return lo;
3091 			offset += (hi - 256) << 8 | lo;
3092 			if (offset < self->treeOffset)
3093 				return -1;
3094 			break;
3095 		default:
3096 			return -1;
3097 		}
3098 	}
3099 }
3100 
PchgPalette_Init(PchgPalette * self)3101 static bool PchgPalette_Init(PchgPalette *self)
3102 {
3103 	if (self->base.base.base.contentOffset + 20 > self->base.base.base.contentLength || self->base.base.base.content[self->base.base.base.contentOffset] != 0)
3104 		return false;
3105 	switch (self->base.base.base.content[self->base.base.base.contentOffset + 3] & 3) {
3106 	case 1:
3107 		self->ocs = true;
3108 		break;
3109 	case 2:
3110 		self->ocs = false;
3111 		break;
3112 	default:
3113 		return false;
3114 	}
3115 	self->startLine = self->base.base.base.content[self->base.base.base.contentOffset + 4] << 8 | self->base.base.base.content[self->base.base.base.contentOffset + 5];
3116 	self->lineCount = self->base.base.base.content[self->base.base.base.contentOffset + 6] << 8 | self->base.base.base.content[self->base.base.base.contentOffset + 7];
3117 	int havePaletteChangeLength = (self->lineCount + 31) >> 5 << 2;
3118 	if (havePaletteChangeLength > 320)
3119 		return false;
3120 	switch (self->base.base.base.content[self->base.base.base.contentOffset + 1]) {
3121 	case 0:
3122 		self->base.base.base.contentOffset += 20;
3123 		if (!Stream_ReadBytes(&self->base.base.base, self->havePaletteChange, 0, havePaletteChangeLength))
3124 			return false;
3125 		self->compressed = false;
3126 		break;
3127 	case 1:
3128 		self->treeOffset = self->base.base.base.contentOffset + 28;
3129 		if (self->treeOffset > self->base.base.base.contentLength)
3130 			return false;
3131 		int treeLength = RECOIL_Get32BigEndian(self->base.base.base.content, self->base.base.base.contentOffset + 20);
3132 		if (treeLength < 2 || treeLength > 1022)
3133 			return false;
3134 		self->base.base.base.contentOffset = self->treeOffset + treeLength;
3135 		self->treeLastOffset = self->base.base.base.contentOffset - 2;
3136 		for (int i = 0; i < havePaletteChangeLength; i++) {
3137 			int b = PchgPalette_ReadHuffman(self);
3138 			if (b < 0)
3139 				return false;
3140 			self->havePaletteChange[i] = (uint8_t) b;
3141 		}
3142 		self->compressed = true;
3143 		break;
3144 	default:
3145 		return false;
3146 	}
3147 	return true;
3148 }
3149 
PchgPalette_UnpackByte(PchgPalette * self)3150 static int PchgPalette_UnpackByte(PchgPalette *self)
3151 {
3152 	return self->compressed ? PchgPalette_ReadHuffman(self) : Stream_ReadByte(&self->base.base.base);
3153 }
3154 
PchgPalette_SetOcsColors(PchgPalette * self,RECOIL * recoil,int paletteOffset,int count)3155 static void PchgPalette_SetOcsColors(PchgPalette *self, RECOIL *recoil, int paletteOffset, int count)
3156 {
3157 	while (--count >= 0) {
3158 		int rr = PchgPalette_UnpackByte(self);
3159 		if (rr < 0)
3160 			return;
3161 		int gb = PchgPalette_UnpackByte(self);
3162 		if (gb < 0)
3163 			return;
3164 		RECOIL_SetOcsColor(recoil, paletteOffset + (rr >> 4), rr, gb);
3165 	}
3166 }
3167 
PchgPalette_SetLinePalette(PchgPalette * self,RECOIL * recoil,int y)3168 static void PchgPalette_SetLinePalette(PchgPalette *self, RECOIL *recoil, int y)
3169 {
3170 	y -= self->startLine;
3171 	if (y < 0 || y >= self->lineCount)
3172 		return;
3173 	if ((self->havePaletteChange[y >> 3] >> (~y & 7) & 1) == 0)
3174 		return;
3175 	int count = PchgPalette_UnpackByte(self);
3176 	if (count < 0)
3177 		return;
3178 	int count2 = PchgPalette_UnpackByte(self);
3179 	if (count2 < 0)
3180 		return;
3181 	if (self->ocs) {
3182 		PchgPalette_SetOcsColors(self, recoil, 0, count);
3183 		PchgPalette_SetOcsColors(self, recoil, 16, count2);
3184 	}
3185 	else {
3186 		count = count << 8 | count2;
3187 		while (--count >= 0) {
3188 			if (PchgPalette_UnpackByte(self) != 0)
3189 				return;
3190 			int c = PchgPalette_UnpackByte(self);
3191 			if (c < 0 || PchgPalette_UnpackByte(self) < 0)
3192 				return;
3193 			int r = PchgPalette_UnpackByte(self);
3194 			if (r < 0)
3195 				return;
3196 			int b = PchgPalette_UnpackByte(self);
3197 			if (b < 0)
3198 				return;
3199 			int g = PchgPalette_UnpackByte(self);
3200 			if (g < 0)
3201 				return;
3202 			recoil->contentPalette[c] = r << 16 | g << 8 | b;
3203 		}
3204 	}
3205 }
3206 
RleStream_Construct(RleStream * self)3207 static void RleStream_Construct(RleStream *self)
3208 {
3209 	BitStream_Construct(&self->base);
3210 	self->repeatCount = 0;
3211 }
3212 
RleStream_ReadValue(RleStream * self)3213 static int RleStream_ReadValue(RleStream *self)
3214 {
3215 	return Stream_ReadByte(&self->base.base);
3216 }
3217 
RleStream_ReadRle(RleStream * self)3218 static int RleStream_ReadRle(RleStream *self)
3219 {
3220 	while (self->repeatCount == 0) {
3221 		if (!((const RleStreamVtbl *) self->base.vtbl)->readCommand(self))
3222 			return -1;
3223 	}
3224 	self->repeatCount--;
3225 	if (self->repeatValue >= 0)
3226 		return self->repeatValue;
3227 	return ((const RleStreamVtbl *) self->base.vtbl)->readValue(self);
3228 }
3229 
RleStream_Unpack(RleStream * self,uint8_t * unpacked,int unpackedOffset,int unpackedStride,int unpackedEnd)3230 static bool RleStream_Unpack(RleStream *self, uint8_t *unpacked, int unpackedOffset, int unpackedStride, int unpackedEnd)
3231 {
3232 	for (; unpackedOffset < unpackedEnd; unpackedOffset += unpackedStride) {
3233 		int b = RleStream_ReadRle(self);
3234 		if (b < 0)
3235 			return false;
3236 		unpacked[unpackedOffset] = (uint8_t) b;
3237 	}
3238 	return true;
3239 }
3240 
RleStream_UnpackColumns(RleStream * self,uint8_t * unpacked,int unpackedOffset,int unpackedStride,int unpackedEnd)3241 static bool RleStream_UnpackColumns(RleStream *self, uint8_t *unpacked, int unpackedOffset, int unpackedStride, int unpackedEnd)
3242 {
3243 	for (int x = 0; x < unpackedStride; x++) {
3244 		if (!RleStream_Unpack(self, unpacked, unpackedOffset + x, unpackedStride, unpackedEnd))
3245 			return false;
3246 	}
3247 	return true;
3248 }
3249 
RleStream_UnpackWords(RleStream * self,uint8_t * unpacked,int unpackedOffset,int unpackedStride,int unpackedEnd)3250 static bool RleStream_UnpackWords(RleStream *self, uint8_t *unpacked, int unpackedOffset, int unpackedStride, int unpackedEnd)
3251 {
3252 	for (; unpackedOffset < unpackedEnd; unpackedOffset += unpackedStride) {
3253 		int b = RleStream_ReadRle(self);
3254 		if (b < 0)
3255 			return false;
3256 		unpacked[unpackedOffset] = (uint8_t) b;
3257 		b = RleStream_ReadRle(self);
3258 		if (b < 0)
3259 			return false;
3260 		unpacked[unpackedOffset + 1] = (uint8_t) b;
3261 	}
3262 	return true;
3263 }
3264 
RleStream_UnpackC64(RleStream * self,uint8_t * unpacked,int unpackedLength)3265 static bool RleStream_UnpackC64(RleStream *self, uint8_t *unpacked, int unpackedLength)
3266 {
3267 	unpacked[0] = self->base.base.content[0];
3268 	unpacked[1] = self->base.base.content[1];
3269 	return RleStream_Unpack(self, unpacked, 2, 1, unpackedLength);
3270 }
3271 
BldStream_Construct(BldStream * self)3272 static void BldStream_Construct(BldStream *self)
3273 {
3274 	RleStream_Construct(&self->base);
3275 	static const RleStreamVtbl vtbl = {
3276 		BitStream_ReadBit,
3277 		(bool (*)(RleStream *self)) BldStream_ReadCommand,
3278 		RleStream_ReadValue,
3279 	};
3280 	self->base.base.vtbl = (const BitStreamVtbl *) &vtbl;
3281 }
3282 
BldStream_ReadCommand(BldStream * self)3283 static bool BldStream_ReadCommand(BldStream *self)
3284 {
3285 	int b = Stream_ReadByte(&self->base.base.base);
3286 	if (b < 0)
3287 		return false;
3288 	self->base.repeatValue = b;
3289 	if (b == 0 || b == 255) {
3290 		b = Stream_ReadByte(&self->base.base.base);
3291 		if (b < 0)
3292 			return false;
3293 		self->base.repeatCount = b + 1;
3294 	}
3295 	else
3296 		self->base.repeatCount = 1;
3297 	return true;
3298 }
3299 
DaVinciStream_Construct(DaVinciStream * self)3300 static void DaVinciStream_Construct(DaVinciStream *self)
3301 {
3302 	RleStream_Construct(&self->base);
3303 	static const RleStreamVtbl vtbl = {
3304 		BitStream_ReadBit,
3305 		(bool (*)(RleStream *self)) DaVinciStream_ReadCommand,
3306 		(int (*)(RleStream *self)) DaVinciStream_ReadValue,
3307 	};
3308 	self->base.base.vtbl = (const BitStreamVtbl *) &vtbl;
3309 }
3310 
DaVinciStream_ReadValue(DaVinciStream * self)3311 static int DaVinciStream_ReadValue(DaVinciStream *self)
3312 {
3313 	if (self->base.base.base.contentOffset + 3 > self->base.base.base.contentLength)
3314 		return -1;
3315 	self->base.base.base.contentOffset += 3;
3316 	return self->base.base.base.content[self->base.base.base.contentOffset - 2] << 16 | self->base.base.base.content[self->base.base.base.contentOffset - 1] << 8 | self->base.base.base.content[self->base.base.base.contentOffset - 3];
3317 }
3318 
DaVinciStream_ReadCommand(DaVinciStream * self)3319 static bool DaVinciStream_ReadCommand(DaVinciStream *self)
3320 {
3321 	int b = Stream_ReadByte(&self->base.base.base);
3322 	if (b < 0)
3323 		return false;
3324 	if (b >= 128) {
3325 		self->base.repeatValue = ((const RleStreamVtbl *) self->base.base.vtbl)->readValue(&self->base);
3326 		b &= 127;
3327 	}
3328 	else
3329 		self->base.repeatValue = -1;
3330 	self->base.repeatCount = b;
3331 	return true;
3332 }
3333 
BbgStream_Construct(BbgStream * self)3334 static void BbgStream_Construct(BbgStream *self)
3335 {
3336 	RleStream_Construct(&self->base);
3337 	static const RleStreamVtbl vtbl = {
3338 		BitStream_ReadBit,
3339 		(bool (*)(RleStream *self)) BbgStream_ReadCommand,
3340 		RleStream_ReadValue,
3341 	};
3342 	self->base.base.vtbl = (const BitStreamVtbl *) &vtbl;
3343 }
3344 
BbgStream_ReadBitsReverse(BbgStream * self,int count)3345 static int BbgStream_ReadBitsReverse(BbgStream *self, int count)
3346 {
3347 	int result = 0;
3348 	for (int i = 0; i < count; i++) {
3349 		switch (self->base.base.vtbl->readBit(&self->base.base)) {
3350 		case 0:
3351 			break;
3352 		case 1:
3353 			result |= 1 << i;
3354 			break;
3355 		default:
3356 			return -1;
3357 		}
3358 	}
3359 	return result;
3360 }
3361 
BbgStream_ReadCommand(BbgStream * self)3362 static bool BbgStream_ReadCommand(BbgStream *self)
3363 {
3364 	switch (self->base.base.vtbl->readBit(&self->base.base)) {
3365 	case 0:
3366 		self->base.repeatCount = 1;
3367 		break;
3368 	case 1:
3369 		self->base.repeatCount = BbgStream_ReadBitsReverse(self, self->countBits);
3370 		if (self->base.repeatCount <= 0)
3371 			return false;
3372 		break;
3373 	default:
3374 		return false;
3375 	}
3376 	self->base.repeatValue = BbgStream_ReadBitsReverse(self, self->valueBits);
3377 	return true;
3378 }
3379 
MspStream_Construct(MspStream * self)3380 static void MspStream_Construct(MspStream *self)
3381 {
3382 	RleStream_Construct(&self->base);
3383 	static const RleStreamVtbl vtbl = {
3384 		BitStream_ReadBit,
3385 		(bool (*)(RleStream *self)) MspStream_ReadCommand,
3386 		RleStream_ReadValue,
3387 	};
3388 	self->base.base.vtbl = (const BitStreamVtbl *) &vtbl;
3389 }
3390 
MspStream_ReadCommand(MspStream * self)3391 static bool MspStream_ReadCommand(MspStream *self)
3392 {
3393 	int b = Stream_ReadByte(&self->base.base.base);
3394 	if (b < 0)
3395 		return false;
3396 	if (b == 0) {
3397 		self->base.repeatCount = Stream_ReadByte(&self->base.base.base);
3398 		self->base.repeatValue = Stream_ReadByte(&self->base.base.base);
3399 	}
3400 	else {
3401 		self->base.repeatCount = b;
3402 		self->base.repeatValue = -1;
3403 	}
3404 	return true;
3405 }
3406 
C64KoalaStream_Construct(C64KoalaStream * self)3407 static void C64KoalaStream_Construct(C64KoalaStream *self)
3408 {
3409 	RleStream_Construct(&self->base);
3410 	static const RleStreamVtbl vtbl = {
3411 		BitStream_ReadBit,
3412 		(bool (*)(RleStream *self)) C64KoalaStream_ReadCommand,
3413 		RleStream_ReadValue,
3414 	};
3415 	self->base.base.vtbl = (const BitStreamVtbl *) &vtbl;
3416 }
3417 
C64KoalaStream_ReadCommand(C64KoalaStream * self)3418 static bool C64KoalaStream_ReadCommand(C64KoalaStream *self)
3419 {
3420 	int b = Stream_ReadByte(&self->base.base.base);
3421 	if (b < 0)
3422 		return false;
3423 	if (b == 254) {
3424 		self->base.repeatValue = Stream_ReadByte(&self->base.base.base);
3425 		self->base.repeatCount = Stream_ReadByte(&self->base.base.base);
3426 	}
3427 	else {
3428 		self->base.repeatValue = b;
3429 		self->base.repeatCount = 1;
3430 	}
3431 	return true;
3432 }
3433 
GoDotStream_Construct(GoDotStream * self)3434 static void GoDotStream_Construct(GoDotStream *self)
3435 {
3436 	RleStream_Construct(&self->base);
3437 	static const RleStreamVtbl vtbl = {
3438 		BitStream_ReadBit,
3439 		(bool (*)(RleStream *self)) GoDotStream_ReadCommand,
3440 		RleStream_ReadValue,
3441 	};
3442 	self->base.base.vtbl = (const BitStreamVtbl *) &vtbl;
3443 }
3444 
GoDotStream_ReadCommand(GoDotStream * self)3445 static bool GoDotStream_ReadCommand(GoDotStream *self)
3446 {
3447 	int b = Stream_ReadByte(&self->base.base.base);
3448 	if (b < 0)
3449 		return false;
3450 	if (b == 173) {
3451 		self->base.repeatCount = Stream_ReadByte(&self->base.base.base);
3452 		if (self->base.repeatCount == 0)
3453 			self->base.repeatCount = 256;
3454 		self->base.repeatValue = Stream_ReadByte(&self->base.base.base);
3455 	}
3456 	else {
3457 		self->base.repeatCount = 1;
3458 		self->base.repeatValue = b;
3459 	}
3460 	return true;
3461 }
3462 
CmpStream_Construct(CmpStream * self)3463 static void CmpStream_Construct(CmpStream *self)
3464 {
3465 	RleStream_Construct(&self->base);
3466 	static const RleStreamVtbl vtbl = {
3467 		BitStream_ReadBit,
3468 		(bool (*)(RleStream *self)) CmpStream_ReadCommand,
3469 		RleStream_ReadValue,
3470 	};
3471 	self->base.base.vtbl = (const BitStreamVtbl *) &vtbl;
3472 }
3473 
CmpStream_ReadCommand(CmpStream * self)3474 static bool CmpStream_ReadCommand(CmpStream *self)
3475 {
3476 	int b = Stream_ReadByte(&self->base.base.base);
3477 	if (b == self->escape) {
3478 		b = Stream_ReadByte(&self->base.base.base);
3479 		if (b < 0)
3480 			return false;
3481 		self->base.repeatCount = 1 + b;
3482 		self->base.repeatValue = Stream_ReadByte(&self->base.base.base);
3483 	}
3484 	else {
3485 		self->base.repeatCount = 1;
3486 		self->base.repeatValue = b;
3487 	}
3488 	return true;
3489 }
3490 
DrpStream_Construct(DrpStream * self)3491 static void DrpStream_Construct(DrpStream *self)
3492 {
3493 	RleStream_Construct(&self->base);
3494 	static const RleStreamVtbl vtbl = {
3495 		BitStream_ReadBit,
3496 		(bool (*)(RleStream *self)) DrpStream_ReadCommand,
3497 		RleStream_ReadValue,
3498 	};
3499 	self->base.base.vtbl = (const BitStreamVtbl *) &vtbl;
3500 }
3501 
DrpStream_ReadCommand(DrpStream * self)3502 static bool DrpStream_ReadCommand(DrpStream *self)
3503 {
3504 	int b = Stream_ReadByte(&self->base.base.base);
3505 	if (b < 0)
3506 		return false;
3507 	if (b == self->escape) {
3508 		self->base.repeatCount = Stream_ReadByte(&self->base.base.base);
3509 		self->base.repeatValue = Stream_ReadByte(&self->base.base.base);
3510 	}
3511 	else {
3512 		self->base.repeatCount = 1;
3513 		self->base.repeatValue = b;
3514 	}
3515 	return true;
3516 }
3517 
DrpStream_UnpackFile(uint8_t const * content,int contentLength,const char * signature,uint8_t * unpacked,int unpackedLength)3518 static uint8_t const *DrpStream_UnpackFile(uint8_t const *content, int contentLength, const char *signature, uint8_t *unpacked, int unpackedLength)
3519 {
3520 	if (contentLength > 16 && RECOIL_IsStringAt(content, 2, signature)) {
3521 		DrpStream rle;
3522 		DrpStream_Construct(&rle);
3523 		rle.base.base.base.content = content;
3524 		rle.base.base.base.contentOffset = 16;
3525 		rle.base.base.base.contentLength = contentLength;
3526 		rle.escape = content[15];
3527 		if (!RleStream_UnpackC64(&rle.base, unpacked, unpackedLength))
3528 			return NULL;
3529 		return unpacked;
3530 	}
3531 	if (contentLength != unpackedLength)
3532 		return NULL;
3533 	return content;
3534 }
3535 
HpmStream_Construct(HpmStream * self)3536 static void HpmStream_Construct(HpmStream *self)
3537 {
3538 	RleStream_Construct(&self->base);
3539 	static const RleStreamVtbl vtbl = {
3540 		BitStream_ReadBit,
3541 		(bool (*)(RleStream *self)) HpmStream_ReadCommand,
3542 		RleStream_ReadValue,
3543 	};
3544 	self->base.base.vtbl = (const BitStreamVtbl *) &vtbl;
3545 }
3546 
HpmStream_ReadCommand(HpmStream * self)3547 static bool HpmStream_ReadCommand(HpmStream *self)
3548 {
3549 	int b = Stream_ReadByte(&self->base.base.base);
3550 	if (b < 0)
3551 		return false;
3552 	if (b == 0) {
3553 		self->base.repeatValue = Stream_ReadByte(&self->base.base.base);
3554 		self->base.repeatCount = Stream_ReadByte(&self->base.base.base);
3555 	}
3556 	else {
3557 		self->base.repeatCount = b;
3558 		self->base.repeatValue = -1;
3559 	}
3560 	return true;
3561 }
3562 
PgcStream_Construct(PgcStream * self)3563 static void PgcStream_Construct(PgcStream *self)
3564 {
3565 	RleStream_Construct(&self->base);
3566 	static const RleStreamVtbl vtbl = {
3567 		BitStream_ReadBit,
3568 		(bool (*)(RleStream *self)) PgcStream_ReadCommand,
3569 		RleStream_ReadValue,
3570 	};
3571 	self->base.base.vtbl = (const BitStreamVtbl *) &vtbl;
3572 }
3573 
PgcStream_ReadCommand(PgcStream * self)3574 static bool PgcStream_ReadCommand(PgcStream *self)
3575 {
3576 	int b = Stream_ReadByte(&self->base.base.base);
3577 	if (b < 0)
3578 		return false;
3579 	if (b < 128) {
3580 		self->base.repeatCount = b;
3581 		self->base.repeatValue = -1;
3582 	}
3583 	else {
3584 		self->base.repeatCount = b - 128;
3585 		self->base.repeatValue = Stream_ReadByte(&self->base.base.base);
3586 	}
3587 	return true;
3588 }
3589 
ScStream_Construct(ScStream * self)3590 static void ScStream_Construct(ScStream *self)
3591 {
3592 	RleStream_Construct(&self->base);
3593 	static const RleStreamVtbl vtbl = {
3594 		BitStream_ReadBit,
3595 		(bool (*)(RleStream *self)) ScStream_ReadCommand,
3596 		RleStream_ReadValue,
3597 	};
3598 	self->base.base.vtbl = (const BitStreamVtbl *) &vtbl;
3599 }
3600 
ScStream_ReadCommand(ScStream * self)3601 static bool ScStream_ReadCommand(ScStream *self)
3602 {
3603 	int b = Stream_ReadByte(&self->base.base.base);
3604 	if (b < 0)
3605 		return false;
3606 	if (b < 128) {
3607 		self->base.repeatCount = b;
3608 		self->base.repeatValue = Stream_ReadByte(&self->base.base.base);
3609 	}
3610 	else {
3611 		self->base.repeatCount = b - 128;
3612 		self->base.repeatValue = -1;
3613 	}
3614 	return true;
3615 }
3616 
CciStream_Construct(CciStream * self)3617 static void CciStream_Construct(CciStream *self)
3618 {
3619 	RleStream_Construct(&self->base);
3620 	static const RleStreamVtbl vtbl = {
3621 		BitStream_ReadBit,
3622 		(bool (*)(RleStream *self)) CciStream_ReadCommand,
3623 		RleStream_ReadValue,
3624 	};
3625 	self->base.base.vtbl = (const BitStreamVtbl *) &vtbl;
3626 }
3627 
CciStream_ReadCommand(CciStream * self)3628 static bool CciStream_ReadCommand(CciStream *self)
3629 {
3630 	int b = Stream_ReadByte(&self->base.base.base);
3631 	if (b < 0)
3632 		return false;
3633 	if (b < 128) {
3634 		self->base.repeatCount = b + 1;
3635 		self->base.repeatValue = -1;
3636 	}
3637 	else {
3638 		self->base.repeatCount = b - 127;
3639 		self->base.repeatValue = Stream_ReadByte(&self->base.base.base);
3640 	}
3641 	return true;
3642 }
3643 
CciStream_UnpackGr15(CciStream * self,uint8_t * unpacked,int unpackedOffset)3644 static bool CciStream_UnpackGr15(CciStream *self, uint8_t *unpacked, int unpackedOffset)
3645 {
3646 	self->base.base.base.contentOffset += 4;
3647 	self->base.repeatCount = 0;
3648 	for (int x = 0; x < 40; x++) {
3649 		if (!RleStream_Unpack(&self->base, unpacked, unpackedOffset + x, 80, 7680))
3650 			return false;
3651 	}
3652 	return true;
3653 }
3654 
PackBitsStream_Construct(PackBitsStream * self)3655 static void PackBitsStream_Construct(PackBitsStream *self)
3656 {
3657 	RleStream_Construct(&self->base);
3658 	static const RleStreamVtbl vtbl = {
3659 		BitStream_ReadBit,
3660 		(bool (*)(RleStream *self)) PackBitsStream_ReadCommand,
3661 		RleStream_ReadValue,
3662 	};
3663 	self->base.base.vtbl = (const BitStreamVtbl *) &vtbl;
3664 }
3665 
PackBitsStream_ReadCommand(PackBitsStream * self)3666 static bool PackBitsStream_ReadCommand(PackBitsStream *self)
3667 {
3668 	int b = Stream_ReadByte(&self->base.base.base);
3669 	if (b < 0)
3670 		return false;
3671 	if (b < 128) {
3672 		self->base.repeatCount = b + 1;
3673 		self->base.repeatValue = -1;
3674 	}
3675 	else {
3676 		self->base.repeatCount = 257 - b;
3677 		self->base.repeatValue = ((const RleStreamVtbl *) self->base.base.vtbl)->readValue(&self->base);
3678 	}
3679 	return true;
3680 }
3681 
PackBitsStream_UnpackBitplaneLines(PackBitsStream * self,uint8_t * unpacked,int width,int height,int bitplanes,bool compressed,bool hasMask)3682 static bool PackBitsStream_UnpackBitplaneLines(PackBitsStream *self, uint8_t *unpacked, int width, int height, int bitplanes, bool compressed, bool hasMask)
3683 {
3684 	int bytesPerBitplane = (width + 15) >> 4 << 1;
3685 	int bytesPerLine = bitplanes * bytesPerBitplane;
3686 	for (int y = 0; y < height; y++) {
3687 		for (int bitplane = 0; bitplane < bitplanes; bitplane++) {
3688 			for (int w = bitplane << 1; w < bytesPerLine; w += bitplanes << 1) {
3689 				for (int x = 0; x < 2; x++) {
3690 					int b = compressed ? RleStream_ReadRle(&self->base) : Stream_ReadByte(&self->base.base.base);
3691 					if (b < 0)
3692 						return false;
3693 					unpacked[y * bytesPerLine + w + x] = (uint8_t) b;
3694 				}
3695 			}
3696 		}
3697 		if (hasMask) {
3698 			for (int x = 0; x < bytesPerBitplane; x++) {
3699 				int b = compressed ? RleStream_ReadRle(&self->base) : Stream_ReadByte(&self->base.base.base);
3700 				if (b < 0)
3701 					return false;
3702 			}
3703 		}
3704 	}
3705 	return true;
3706 }
3707 
SpcStream_Construct(SpcStream * self)3708 static void SpcStream_Construct(SpcStream *self)
3709 {
3710 	RleStream_Construct(&self->base);
3711 	static const RleStreamVtbl vtbl = {
3712 		BitStream_ReadBit,
3713 		(bool (*)(RleStream *self)) SpcStream_ReadCommand,
3714 		RleStream_ReadValue,
3715 	};
3716 	self->base.base.vtbl = (const BitStreamVtbl *) &vtbl;
3717 }
3718 
SpcStream_ReadCommand(SpcStream * self)3719 static bool SpcStream_ReadCommand(SpcStream *self)
3720 {
3721 	int b = Stream_ReadByte(&self->base.base.base);
3722 	if (b < 0)
3723 		return false;
3724 	if (b < 128) {
3725 		self->base.repeatCount = b + 1;
3726 		self->base.repeatValue = -1;
3727 	}
3728 	else {
3729 		self->base.repeatCount = 258 - b;
3730 		self->base.repeatValue = Stream_ReadByte(&self->base.base.base);
3731 	}
3732 	return true;
3733 }
3734 
SpsStream_Construct(SpsStream * self)3735 static void SpsStream_Construct(SpsStream *self)
3736 {
3737 	RleStream_Construct(&self->base);
3738 	static const RleStreamVtbl vtbl = {
3739 		BitStream_ReadBit,
3740 		(bool (*)(RleStream *self)) SpsStream_ReadCommand,
3741 		RleStream_ReadValue,
3742 	};
3743 	self->base.base.vtbl = (const BitStreamVtbl *) &vtbl;
3744 }
3745 
SpsStream_ReadCommand(SpsStream * self)3746 static bool SpsStream_ReadCommand(SpsStream *self)
3747 {
3748 	int b = Stream_ReadByte(&self->base.base.base);
3749 	if (b < 0)
3750 		return false;
3751 	if (b < 128) {
3752 		self->base.repeatCount = b + 3;
3753 		self->base.repeatValue = Stream_ReadByte(&self->base.base.base);
3754 	}
3755 	else {
3756 		self->base.repeatCount = b - 127;
3757 		self->base.repeatValue = -1;
3758 	}
3759 	return true;
3760 }
3761 
ArtMaster88Stream_Construct(ArtMaster88Stream * self)3762 static void ArtMaster88Stream_Construct(ArtMaster88Stream *self)
3763 {
3764 	RleStream_Construct(&self->base);
3765 	static const RleStreamVtbl vtbl = {
3766 		BitStream_ReadBit,
3767 		(bool (*)(RleStream *self)) ArtMaster88Stream_ReadCommand,
3768 		RleStream_ReadValue,
3769 	};
3770 	self->base.base.vtbl = (const BitStreamVtbl *) &vtbl;
3771 	self->escape = -1;
3772 }
3773 
ArtMaster88Stream_ReadCommand(ArtMaster88Stream * self)3774 static bool ArtMaster88Stream_ReadCommand(ArtMaster88Stream *self)
3775 {
3776 	int b = Stream_ReadByte(&self->base.base.base);
3777 	if (b < 0)
3778 		return false;
3779 	if (b == self->escape) {
3780 		b = Stream_ReadByte(&self->base.base.base);
3781 		if (b < 0)
3782 			return false;
3783 		self->base.repeatCount = (b - 1) & 255;
3784 		self->escape = -1;
3785 	}
3786 	else {
3787 		self->base.repeatCount = 1;
3788 		self->escape = self->base.repeatValue = b;
3789 	}
3790 	return true;
3791 }
3792 
ArtMaster88Stream_SkipChunk(ArtMaster88Stream * self)3793 static bool ArtMaster88Stream_SkipChunk(ArtMaster88Stream *self)
3794 {
3795 	if (self->base.base.base.contentOffset + 1 >= self->base.base.base.contentLength)
3796 		return false;
3797 	int length = self->base.base.base.content[self->base.base.base.contentOffset] | self->base.base.base.content[self->base.base.base.contentOffset + 1] << 8;
3798 	if (length < 2)
3799 		return false;
3800 	self->base.base.base.contentOffset += length;
3801 	return true;
3802 }
3803 
SrStream_Construct(SrStream * self)3804 static void SrStream_Construct(SrStream *self)
3805 {
3806 	RleStream_Construct(&self->base);
3807 	static const RleStreamVtbl vtbl = {
3808 		BitStream_ReadBit,
3809 		(bool (*)(RleStream *self)) SrStream_ReadCommand,
3810 		RleStream_ReadValue,
3811 	};
3812 	self->base.base.vtbl = (const BitStreamVtbl *) &vtbl;
3813 }
3814 
SrStream_ReadCommand(SrStream * self)3815 static bool SrStream_ReadCommand(SrStream *self)
3816 {
3817 	int b = Stream_ReadByte(&self->base.base.base);
3818 	switch (b) {
3819 	case -1:
3820 		return false;
3821 	case 0:
3822 		self->base.repeatCount = Stream_ReadByte(&self->base.base.base);
3823 		if (self->base.repeatCount == 0)
3824 			self->base.repeatCount = 256;
3825 		self->base.repeatValue = Stream_ReadByte(&self->base.base.base);
3826 		return true;
3827 	case 1:
3828 	case 2:
3829 	case 3:
3830 	case 4:
3831 	case 5:
3832 	case 6:
3833 	case 7:
3834 	case 8:
3835 	case 9:
3836 	case 10:
3837 	case 11:
3838 	case 12:
3839 	case 13:
3840 	case 14:
3841 	case 15:
3842 		self->base.repeatCount = b;
3843 		self->base.repeatValue = Stream_ReadByte(&self->base.base.base);
3844 		return true;
3845 	default:
3846 		self->base.repeatCount = 1;
3847 		self->base.repeatValue = b;
3848 		return true;
3849 	}
3850 }
3851 
PacStream_Construct(PacStream * self)3852 static void PacStream_Construct(PacStream *self)
3853 {
3854 	RleStream_Construct(&self->base);
3855 	static const RleStreamVtbl vtbl = {
3856 		BitStream_ReadBit,
3857 		(bool (*)(RleStream *self)) PacStream_ReadCommand,
3858 		RleStream_ReadValue,
3859 	};
3860 	self->base.base.vtbl = (const BitStreamVtbl *) &vtbl;
3861 }
3862 
PacStream_ReadCommand(PacStream * self)3863 static bool PacStream_ReadCommand(PacStream *self)
3864 {
3865 	int b = Stream_ReadByte(&self->base.base.base);
3866 	if (b < 0)
3867 		return false;
3868 	if (b == self->base.base.base.content[4]) {
3869 		b = Stream_ReadByte(&self->base.base.base);
3870 		if (b < 0)
3871 			return false;
3872 		self->base.repeatCount = b + 1;
3873 		self->base.repeatValue = self->base.base.base.content[5];
3874 	}
3875 	else if (b == self->base.base.base.content[6]) {
3876 		self->base.repeatValue = Stream_ReadByte(&self->base.base.base);
3877 		if (self->base.repeatValue < 0)
3878 			return false;
3879 		b = Stream_ReadByte(&self->base.base.base);
3880 		if (b < 0)
3881 			return false;
3882 		self->base.repeatCount = b + 1;
3883 	}
3884 	else {
3885 		self->base.repeatCount = 1;
3886 		self->base.repeatValue = b;
3887 	}
3888 	return true;
3889 }
3890 
XlpStream_Construct(XlpStream * self)3891 static void XlpStream_Construct(XlpStream *self)
3892 {
3893 	RleStream_Construct(&self->base);
3894 	static const RleStreamVtbl vtbl = {
3895 		BitStream_ReadBit,
3896 		(bool (*)(RleStream *self)) XlpStream_ReadCommand,
3897 		RleStream_ReadValue,
3898 	};
3899 	self->base.base.vtbl = (const BitStreamVtbl *) &vtbl;
3900 }
3901 
XlpStream_ReadCommand(XlpStream * self)3902 static bool XlpStream_ReadCommand(XlpStream *self)
3903 {
3904 	int b = Stream_ReadByte(&self->base.base.base);
3905 	if (b < 0)
3906 		return false;
3907 	bool rle;
3908 	if (b < 128)
3909 		rle = false;
3910 	else {
3911 		b -= 128;
3912 		rle = true;
3913 	}
3914 	self->base.repeatCount = b;
3915 	if (b >= 64) {
3916 		b = Stream_ReadByte(&self->base.base.base);
3917 		if (b < 0)
3918 			return false;
3919 		self->base.repeatCount = (self->base.repeatCount - 64) << 8 | b;
3920 	}
3921 	self->base.repeatValue = rle ? Stream_ReadByte(&self->base.base.base) : -1;
3922 	return true;
3923 }
3924 
AmstradStream_Construct(AmstradStream * self)3925 static void AmstradStream_Construct(AmstradStream *self)
3926 {
3927 	RleStream_Construct(&self->base);
3928 	static const RleStreamVtbl vtbl = {
3929 		BitStream_ReadBit,
3930 		(bool (*)(RleStream *self)) AmstradStream_ReadCommand,
3931 		RleStream_ReadValue,
3932 	};
3933 	self->base.base.vtbl = (const BitStreamVtbl *) &vtbl;
3934 }
3935 
AmstradStream_ReadCommand(AmstradStream * self)3936 static bool AmstradStream_ReadCommand(AmstradStream *self)
3937 {
3938 	while (self->blockLength <= 0) {
3939 		if (Stream_ReadByte(&self->base.base.base) != 77 || Stream_ReadByte(&self->base.base.base) != 74 || Stream_ReadByte(&self->base.base.base) != 72)
3940 			return false;
3941 		int lo = Stream_ReadByte(&self->base.base.base);
3942 		if (lo < 0)
3943 			return false;
3944 		int hi = Stream_ReadByte(&self->base.base.base);
3945 		if (hi < 0)
3946 			return false;
3947 		self->blockLength = hi << 8 | lo;
3948 	}
3949 	int b = Stream_ReadByte(&self->base.base.base);
3950 	if (b < 0)
3951 		return false;
3952 	if (b == 1) {
3953 		self->base.repeatCount = Stream_ReadByte(&self->base.base.base);
3954 		if (self->base.repeatCount == 0)
3955 			self->base.repeatCount = 256;
3956 		self->base.repeatValue = Stream_ReadByte(&self->base.base.base);
3957 	}
3958 	else {
3959 		self->base.repeatCount = 1;
3960 		self->base.repeatValue = b;
3961 	}
3962 	self->blockLength -= self->base.repeatCount;
3963 	return true;
3964 }
3965 
AmstradStream_UnpackFile(uint8_t const * content,int contentOffset,int contentLength,uint8_t * unpacked,int unpackedLength)3966 static bool AmstradStream_UnpackFile(uint8_t const *content, int contentOffset, int contentLength, uint8_t *unpacked, int unpackedLength)
3967 {
3968 	AmstradStream rle;
3969 	AmstradStream_Construct(&rle);
3970 	rle.base.base.base.content = content;
3971 	rle.base.base.base.contentOffset = contentOffset;
3972 	rle.base.base.base.contentLength = contentLength;
3973 	rle.blockLength = 0;
3974 	return RleStream_Unpack(&rle.base, unpacked, 0, 1, unpackedLength);
3975 }
3976 
CpiStream_Construct(CpiStream * self)3977 static void CpiStream_Construct(CpiStream *self)
3978 {
3979 	RleStream_Construct(&self->base);
3980 	static const RleStreamVtbl vtbl = {
3981 		BitStream_ReadBit,
3982 		(bool (*)(RleStream *self)) CpiStream_ReadCommand,
3983 		RleStream_ReadValue,
3984 	};
3985 	self->base.base.vtbl = (const BitStreamVtbl *) &vtbl;
3986 }
3987 
CpiStream_ReadCommand(CpiStream * self)3988 static bool CpiStream_ReadCommand(CpiStream *self)
3989 {
3990 	int b = Stream_ReadByte(&self->base.base.base);
3991 	if (b < 0)
3992 		return false;
3993 	if (self->base.base.base.contentOffset + 1 < self->base.base.base.contentLength && self->base.base.base.content[self->base.base.base.contentOffset] == b) {
3994 		self->base.base.base.contentOffset++;
3995 		self->base.repeatCount = 1 + self->base.base.base.content[self->base.base.base.contentOffset++];
3996 	}
3997 	else
3998 		self->base.repeatCount = 1;
3999 	self->base.repeatValue = b;
4000 	return true;
4001 }
4002 
XeKoalaStream_Construct(XeKoalaStream * self)4003 static void XeKoalaStream_Construct(XeKoalaStream *self)
4004 {
4005 	RleStream_Construct(&self->base);
4006 	static const RleStreamVtbl vtbl = {
4007 		BitStream_ReadBit,
4008 		(bool (*)(RleStream *self)) XeKoalaStream_ReadCommand,
4009 		RleStream_ReadValue,
4010 	};
4011 	self->base.base.vtbl = (const BitStreamVtbl *) &vtbl;
4012 }
4013 
XeKoalaStream_ReadCommand(XeKoalaStream * self)4014 static bool XeKoalaStream_ReadCommand(XeKoalaStream *self)
4015 {
4016 	int b = Stream_ReadByte(&self->base.base.base);
4017 	if (b < 0)
4018 		return false;
4019 	bool rle;
4020 	if (b < 128)
4021 		rle = true;
4022 	else {
4023 		b -= 128;
4024 		rle = false;
4025 	}
4026 	if (b == 0) {
4027 		int hi = Stream_ReadByte(&self->base.base.base);
4028 		if (hi < 0)
4029 			return false;
4030 		b = Stream_ReadByte(&self->base.base.base);
4031 		if (b < 0)
4032 			return false;
4033 		b |= hi << 8;
4034 	}
4035 	self->base.repeatCount = b;
4036 	self->base.repeatValue = rle ? Stream_ReadByte(&self->base.base.base) : -1;
4037 	return true;
4038 }
4039 
XeKoalaStream_UnpackRaw(int type,uint8_t const * content,int contentOffset,int contentLength,uint8_t * unpacked,int unpackedLength)4040 static bool XeKoalaStream_UnpackRaw(int type, uint8_t const *content, int contentOffset, int contentLength, uint8_t *unpacked, int unpackedLength)
4041 {
4042 	XeKoalaStream rle;
4043 	XeKoalaStream_Construct(&rle);
4044 	rle.base.base.base.content = content;
4045 	rle.base.base.base.contentOffset = contentOffset;
4046 	rle.base.base.base.contentLength = contentLength;
4047 	switch (type) {
4048 	case 0:
4049 		if (contentLength - contentOffset != unpackedLength)
4050 			return false;
4051 		memcpy(unpacked, content + contentOffset, unpackedLength);
4052 		return true;
4053 	case 1:
4054 		for (int x = 0; x < 40; x++) {
4055 			for (int unpackedOffset = x; unpackedOffset < 80; unpackedOffset += 40) {
4056 				if (!RleStream_Unpack(&rle.base, unpacked, unpackedOffset, 80, unpackedLength))
4057 					return false;
4058 			}
4059 		}
4060 		return true;
4061 	case 2:
4062 		return RleStream_Unpack(&rle.base, unpacked, 0, 1, unpackedLength);
4063 	default:
4064 		return false;
4065 	}
4066 }
4067 
XeKoalaStream_UnpackWrapped(uint8_t const * content,int contentLength,uint8_t * unpacked,int unpackedLength)4068 static bool XeKoalaStream_UnpackWrapped(uint8_t const *content, int contentLength, uint8_t *unpacked, int unpackedLength)
4069 {
4070 	return contentLength >= 26 && content[0] == 255 && content[1] == 128 && content[2] == 201 && content[3] == 199 && content[4] >= 26 && content[4] < contentLength && content[5] == 0 && content[6] == 1 && content[8] == 14 && content[9] == 0 && content[10] == 40 && content[11] == 0 && content[12] == 192 && content[20] == 0 && content[21] == 0 && XeKoalaStream_UnpackRaw(content[7], content, content[4] + 1, contentLength, unpacked, unpackedLength);
4071 }
4072 
ImgStream_Construct(ImgStream * self)4073 static void ImgStream_Construct(ImgStream *self)
4074 {
4075 	RleStream_Construct(&self->base);
4076 	static const RleStreamVtbl vtbl = {
4077 		BitStream_ReadBit,
4078 		(bool (*)(RleStream *self)) ImgStream_ReadCommand,
4079 		RleStream_ReadValue,
4080 	};
4081 	self->base.base.vtbl = (const BitStreamVtbl *) &vtbl;
4082 	self->patternRepeatCount = 0;
4083 }
4084 
ImgStream_GetLineRepeatCount(ImgStream * self)4085 static int ImgStream_GetLineRepeatCount(ImgStream *self)
4086 {
4087 	if (self->base.repeatCount == 0 && self->base.base.base.contentOffset < self->base.base.base.contentLength - 4 && self->base.base.base.content[self->base.base.base.contentOffset] == 0 && self->base.base.base.content[self->base.base.base.contentOffset + 1] == 0 && self->base.base.base.content[self->base.base.base.contentOffset + 2] == 255) {
4088 		self->base.base.base.contentOffset += 4;
4089 		return self->base.base.base.content[self->base.base.base.contentOffset - 1] + 1;
4090 	}
4091 	return 1;
4092 }
4093 
ImgStream_ReadCommand(ImgStream * self)4094 static bool ImgStream_ReadCommand(ImgStream *self)
4095 {
4096 	if (self->patternRepeatCount > 1) {
4097 		self->patternRepeatCount--;
4098 		self->base.repeatCount = self->base.base.base.content[6] << 8 | self->base.base.base.content[7];
4099 		self->base.base.base.contentOffset -= self->base.repeatCount;
4100 		return true;
4101 	}
4102 	int b = Stream_ReadByte(&self->base.base.base);
4103 	switch (b) {
4104 	case -1:
4105 		return false;
4106 	case 0:
4107 		b = Stream_ReadByte(&self->base.base.base);
4108 		if (b < 0)
4109 			return false;
4110 		if (b == 0) {
4111 			b = Stream_ReadByte(&self->base.base.base);
4112 			if (b < 0)
4113 				return false;
4114 			self->base.repeatCount = b + 1;
4115 			self->base.repeatValue = 256;
4116 			return true;
4117 		}
4118 		self->patternRepeatCount = b;
4119 		self->base.repeatCount = self->base.base.base.content[6] << 8 | self->base.base.base.content[7];
4120 		self->base.repeatValue = -1;
4121 		return true;
4122 	case 128:
4123 		self->base.repeatCount = Stream_ReadByte(&self->base.base.base);
4124 		if (self->base.repeatCount < 0)
4125 			return false;
4126 		if (self->base.repeatCount == 0)
4127 			self->base.repeatCount = 256;
4128 		self->base.repeatValue = -1;
4129 		return true;
4130 	default:
4131 		self->base.repeatCount = b & 127;
4132 		self->base.repeatValue = b >= 128 ? 255 : 0;
4133 		return true;
4134 	}
4135 }
4136 
CaStream_Construct(CaStream * self)4137 static void CaStream_Construct(CaStream *self)
4138 {
4139 	RleStream_Construct(&self->base);
4140 	static const RleStreamVtbl vtbl = {
4141 		BitStream_ReadBit,
4142 		(bool (*)(RleStream *self)) CaStream_ReadCommand,
4143 		RleStream_ReadValue,
4144 	};
4145 	self->base.base.vtbl = (const BitStreamVtbl *) &vtbl;
4146 }
4147 
CaStream_ReadCommand(CaStream * self)4148 static bool CaStream_ReadCommand(CaStream *self)
4149 {
4150 	int b = Stream_ReadByte(&self->base.base.base);
4151 	if (b < 0)
4152 		return false;
4153 	if (b != self->escapeByte) {
4154 		self->base.repeatCount = 1;
4155 		self->base.repeatValue = b;
4156 		return true;
4157 	}
4158 	int c = Stream_ReadByte(&self->base.base.base);
4159 	if (c < 0)
4160 		return false;
4161 	if (c == self->escapeByte) {
4162 		self->base.repeatCount = 1;
4163 		self->base.repeatValue = c;
4164 		return true;
4165 	}
4166 	b = Stream_ReadByte(&self->base.base.base);
4167 	if (b < 0)
4168 		return false;
4169 	switch (c) {
4170 	case 0:
4171 		self->base.repeatCount = b + 1;
4172 		self->base.repeatValue = Stream_ReadByte(&self->base.base.base);
4173 		break;
4174 	case 1:
4175 		c = Stream_ReadByte(&self->base.base.base);
4176 		if (c < 0)
4177 			return false;
4178 		self->base.repeatCount = (b << 8) + c + 1;
4179 		self->base.repeatValue = Stream_ReadByte(&self->base.base.base);
4180 		break;
4181 	case 2:
4182 		if (b == 0)
4183 			self->base.repeatCount = 32000;
4184 		else {
4185 			c = Stream_ReadByte(&self->base.base.base);
4186 			if (c < 0)
4187 				return false;
4188 			self->base.repeatCount = (b << 8) + c + 1;
4189 		}
4190 		self->base.repeatValue = self->defaultValue;
4191 		break;
4192 	default:
4193 		self->base.repeatCount = c + 1;
4194 		self->base.repeatValue = b;
4195 		break;
4196 	}
4197 	return true;
4198 }
4199 
CaStream_UnpackCa(CaStream * self,uint8_t * unpacked,int unpackedOffset)4200 static bool CaStream_UnpackCa(CaStream *self, uint8_t *unpacked, int unpackedOffset)
4201 {
4202 	if (self->base.base.base.contentOffset > self->base.base.base.contentLength - 4)
4203 		return false;
4204 	self->escapeByte = self->base.base.base.content[self->base.base.base.contentOffset];
4205 	self->defaultValue = self->base.base.base.content[self->base.base.base.contentOffset + 1];
4206 	int unpackedStep = self->base.base.base.content[self->base.base.base.contentOffset + 2] << 8 | self->base.base.base.content[self->base.base.base.contentOffset + 3];
4207 	if (unpackedStep >= 32000)
4208 		return false;
4209 	self->base.repeatCount = 0;
4210 	if (unpackedStep == 0) {
4211 		self->base.repeatCount = 32000;
4212 		self->base.repeatValue = self->defaultValue;
4213 		unpackedStep = 1;
4214 	}
4215 	self->base.base.base.contentOffset += 4;
4216 	return RleStream_UnpackColumns(&self->base, unpacked, unpackedOffset, unpackedStep, unpackedOffset + 32000);
4217 }
4218 
CaStream_UnpackDel(uint8_t const * content,int contentLength,uint8_t * unpacked,int blocks)4219 static bool CaStream_UnpackDel(uint8_t const *content, int contentLength, uint8_t *unpacked, int blocks)
4220 {
4221 	CaStream rle;
4222 	CaStream_Construct(&rle);
4223 	rle.base.base.base.content = content;
4224 	rle.base.base.base.contentOffset = blocks << 2;
4225 	if (rle.base.base.base.contentOffset >= contentLength)
4226 		return false;
4227 	for (int block = 0; block < blocks; block++) {
4228 		rle.base.base.base.contentLength = rle.base.base.base.contentOffset + RECOIL_Get32BigEndian(content, block << 2);
4229 		if (rle.base.base.base.contentLength > contentLength || rle.base.base.base.contentLength < rle.base.base.base.contentOffset || !CaStream_UnpackCa(&rle, unpacked, block * 32000))
4230 			return false;
4231 		rle.base.base.base.contentOffset = rle.base.base.base.contentLength;
4232 	}
4233 	if (blocks == 2) {
4234 		rle.base.base.base.contentLength = contentLength;
4235 		return CaStream_UnpackCa(&rle, unpacked, 64000);
4236 	}
4237 	return true;
4238 }
4239 
RgbStream_Construct(RgbStream * self)4240 static void RgbStream_Construct(RgbStream *self)
4241 {
4242 	RleStream_Construct(&self->base);
4243 	static const RleStreamVtbl vtbl = {
4244 		BitStream_ReadBit,
4245 		(bool (*)(RleStream *self)) RgbStream_ReadCommand,
4246 		(int (*)(RleStream *self)) RgbStream_ReadValue,
4247 	};
4248 	self->base.base.vtbl = (const BitStreamVtbl *) &vtbl;
4249 }
4250 
RgbStream_ReadValue(RgbStream * self)4251 static int RgbStream_ReadValue(RgbStream *self)
4252 {
4253 	return BitStream_ReadBits(&self->base.base, 12);
4254 }
4255 
RgbStream_ReadCommand(RgbStream * self)4256 static bool RgbStream_ReadCommand(RgbStream *self)
4257 {
4258 	int b = BitStream_ReadBits(&self->base.base, 4);
4259 	if (b < 0)
4260 		return false;
4261 	bool rle;
4262 	if (b < 8)
4263 		rle = true;
4264 	else {
4265 		b -= 8;
4266 		rle = false;
4267 	}
4268 	if (b == 0) {
4269 		b = BitStream_ReadBits(&self->base.base, 4);
4270 		if (b < 0)
4271 			return false;
4272 		b += 7;
4273 	}
4274 	if (rle) {
4275 		self->base.repeatValue = ((const RleStreamVtbl *) self->base.base.vtbl)->readValue(&self->base);
4276 		b++;
4277 	}
4278 	else
4279 		self->base.repeatValue = -1;
4280 	self->base.repeatCount = b;
4281 	return true;
4282 }
4283 
TnyPcsStream_Construct(TnyPcsStream * self)4284 static void TnyPcsStream_Construct(TnyPcsStream *self)
4285 {
4286 	RleStream_Construct(&self->base);
4287 }
4288 
TnyPcsStream_ReadTnyCommand(TnyPcsStream * self)4289 static bool TnyPcsStream_ReadTnyCommand(TnyPcsStream *self)
4290 {
4291 	int b = Stream_ReadByte(&self->base.base.base);
4292 	if (b < 0)
4293 		return false;
4294 	if (b < 128) {
4295 		if (b == 0 || b == 1) {
4296 			if (self->base.base.base.contentOffset >= self->base.base.base.contentLength - 1)
4297 				return false;
4298 			self->base.repeatCount = self->base.base.base.content[self->base.base.base.contentOffset] << 8 | self->base.base.base.content[self->base.base.base.contentOffset + 1];
4299 			self->base.base.base.contentOffset += 2;
4300 		}
4301 		else
4302 			self->base.repeatCount = b;
4303 		self->base.repeatValue = b == 1 ? -1 : ((const RleStreamVtbl *) self->base.base.vtbl)->readValue(&self->base);
4304 	}
4305 	else {
4306 		self->base.repeatCount = 256 - b;
4307 		self->base.repeatValue = -1;
4308 	}
4309 	return true;
4310 }
4311 
TnyStream_Construct(TnyStream * self)4312 static void TnyStream_Construct(TnyStream *self)
4313 {
4314 	TnyPcsStream_Construct(&self->base);
4315 	static const RleStreamVtbl vtbl = {
4316 		BitStream_ReadBit,
4317 		(bool (*)(RleStream *self)) TnyStream_ReadCommand,
4318 		(int (*)(RleStream *self)) TnyStream_ReadValue,
4319 	};
4320 	self->base.base.base.vtbl = (const BitStreamVtbl *) &vtbl;
4321 }
4322 
TnyStream_ReadCommand(TnyStream * self)4323 static bool TnyStream_ReadCommand(TnyStream *self)
4324 {
4325 	return TnyPcsStream_ReadTnyCommand(&self->base);
4326 }
4327 
TnyStream_ReadValue(TnyStream * self)4328 static int TnyStream_ReadValue(TnyStream *self)
4329 {
4330 	if (self->valueOffset + 1 >= self->valueLength)
4331 		return -1;
4332 	int value = self->base.base.base.base.content[self->valueOffset] << 8 | self->base.base.base.base.content[self->valueOffset + 1];
4333 	self->valueOffset += 2;
4334 	return value;
4335 }
4336 
PcsStream_Construct(PcsStream * self)4337 static void PcsStream_Construct(PcsStream *self)
4338 {
4339 	TnyPcsStream_Construct(&self->base);
4340 	static const RleStreamVtbl vtbl = {
4341 		BitStream_ReadBit,
4342 		(bool (*)(RleStream *self)) PcsStream_ReadCommand,
4343 		(int (*)(RleStream *self)) PcsStream_ReadValue,
4344 	};
4345 	self->base.base.base.vtbl = (const BitStreamVtbl *) &vtbl;
4346 }
4347 
PcsStream_ReadCommand(PcsStream * self)4348 static bool PcsStream_ReadCommand(PcsStream *self)
4349 {
4350 	if (self->commandCount <= 0)
4351 		return false;
4352 	self->commandCount--;
4353 	return TnyPcsStream_ReadTnyCommand(&self->base);
4354 }
4355 
PcsStream_ReadValue(PcsStream * self)4356 static int PcsStream_ReadValue(PcsStream *self)
4357 {
4358 	if (!self->palette)
4359 		return Stream_ReadByte(&self->base.base.base.base);
4360 	if (self->base.base.base.base.contentOffset >= self->base.base.base.base.contentLength - 1)
4361 		return -1;
4362 	int value = self->base.base.base.base.content[self->base.base.base.base.contentOffset] << 8 | self->base.base.base.base.content[self->base.base.base.base.contentOffset + 1];
4363 	self->base.base.base.base.contentOffset += 2;
4364 	return value;
4365 }
4366 
PcsStream_StartBlock(PcsStream * self)4367 static bool PcsStream_StartBlock(PcsStream *self)
4368 {
4369 	if (self->base.base.base.base.contentOffset >= self->base.base.base.base.contentLength - 1)
4370 		return false;
4371 	self->commandCount = self->base.base.base.base.content[self->base.base.base.base.contentOffset] << 8 | self->base.base.base.base.content[self->base.base.base.base.contentOffset + 1];
4372 	self->base.base.base.base.contentOffset += 2;
4373 	return true;
4374 }
4375 
PcsStream_EndBlock(PcsStream * self)4376 static bool PcsStream_EndBlock(PcsStream *self)
4377 {
4378 	while (self->base.base.repeatCount > 0 || self->commandCount > 0) {
4379 		if (RleStream_ReadRle(&self->base.base) < 0)
4380 			return false;
4381 	}
4382 	return true;
4383 }
4384 
PcsStream_UnpackPcs(PcsStream * self,uint8_t * unpacked)4385 static bool PcsStream_UnpackPcs(PcsStream *self, uint8_t *unpacked)
4386 {
4387 	self->palette = false;
4388 	if (!PcsStream_StartBlock(self) || !RleStream_Unpack(&self->base.base, unpacked, 0, 1, 32000) || !PcsStream_EndBlock(self))
4389 		return false;
4390 	self->palette = true;
4391 	if (!PcsStream_StartBlock(self))
4392 		return false;
4393 	for (int unpackedOffset = 32000; unpackedOffset < 51136; unpackedOffset += 2) {
4394 		int b = RleStream_ReadRle(&self->base.base);
4395 		if (b < 0)
4396 			return false;
4397 		unpacked[unpackedOffset] = (uint8_t) (b >> 8);
4398 		unpacked[unpackedOffset + 1] = (uint8_t) b;
4399 	}
4400 	return PcsStream_EndBlock(self);
4401 }
4402 
VdatStream_Construct(VdatStream * self)4403 static void VdatStream_Construct(VdatStream *self)
4404 {
4405 	TnyStream_Construct(&self->base);
4406 	static const RleStreamVtbl vtbl = {
4407 		BitStream_ReadBit,
4408 		(bool (*)(RleStream *self)) VdatStream_ReadCommand,
4409 		(int (*)(RleStream *self)) TnyStream_ReadValue,
4410 	};
4411 	self->base.base.base.base.vtbl = (const BitStreamVtbl *) &vtbl;
4412 }
4413 
VdatStream_ReadCommand(VdatStream * self)4414 static bool VdatStream_ReadCommand(VdatStream *self)
4415 {
4416 	int b = Stream_ReadByte(&self->base.base.base.base.base);
4417 	if (b < 0)
4418 		return false;
4419 	if (b < 128) {
4420 		if (b == 0 || b == 1) {
4421 			self->base.base.base.repeatCount = ((const RleStreamVtbl *) self->base.base.base.base.vtbl)->readValue(&self->base.base.base);
4422 			if (self->base.base.base.repeatCount < 0)
4423 				return false;
4424 		}
4425 		else
4426 			self->base.base.base.repeatCount = b;
4427 		self->base.base.base.repeatValue = b == 0 ? -1 : ((const RleStreamVtbl *) self->base.base.base.base.vtbl)->readValue(&self->base.base.base);
4428 	}
4429 	else {
4430 		self->base.base.base.repeatCount = 256 - b;
4431 		self->base.base.base.repeatValue = -1;
4432 	}
4433 	return true;
4434 }
4435 
HimStream_Construct(HimStream * self)4436 static void HimStream_Construct(HimStream *self)
4437 {
4438 	RleStream_Construct(&self->base);
4439 	static const RleStreamVtbl vtbl = {
4440 		BitStream_ReadBit,
4441 		(bool (*)(RleStream *self)) HimStream_ReadCommand,
4442 		(int (*)(RleStream *self)) HimStream_ReadValue,
4443 	};
4444 	self->base.base.vtbl = (const BitStreamVtbl *) &vtbl;
4445 }
4446 
HimStream_ReadValue(HimStream * self)4447 static int HimStream_ReadValue(HimStream *self)
4448 {
4449 	if (self->base.base.base.contentOffset < 18)
4450 		return -1;
4451 	return self->base.base.base.content[self->base.base.base.contentOffset--];
4452 }
4453 
HimStream_ReadCommand(HimStream * self)4454 static bool HimStream_ReadCommand(HimStream *self)
4455 {
4456 	int b = ((const RleStreamVtbl *) self->base.base.vtbl)->readValue(&self->base);
4457 	switch (b) {
4458 	case -1:
4459 		return false;
4460 	case 0:
4461 		self->base.repeatCount = ((const RleStreamVtbl *) self->base.base.vtbl)->readValue(&self->base);
4462 		if (self->base.repeatCount <= 0)
4463 			return false;
4464 		self->base.repeatValue = ((const RleStreamVtbl *) self->base.base.vtbl)->readValue(&self->base);
4465 		return true;
4466 	default:
4467 		self->base.repeatCount = b - 1;
4468 		self->base.repeatValue = -1;
4469 		return true;
4470 	}
4471 }
4472 
IcStream_Construct(IcStream * self)4473 static void IcStream_Construct(IcStream *self)
4474 {
4475 	RleStream_Construct(&self->base);
4476 	static const RleStreamVtbl vtbl = {
4477 		BitStream_ReadBit,
4478 		(bool (*)(RleStream *self)) IcStream_ReadCommand,
4479 		RleStream_ReadValue,
4480 	};
4481 	self->base.base.vtbl = (const BitStreamVtbl *) &vtbl;
4482 }
4483 
IcStream_ReadCount(IcStream * self)4484 static bool IcStream_ReadCount(IcStream *self)
4485 {
4486 	self->base.repeatCount = 257;
4487 	while (Stream_ReadByte(&self->base.base.base) == 1)
4488 		self->base.repeatCount += 256;
4489 	int b = Stream_ReadByte(&self->base.base.base);
4490 	if (b < 0)
4491 		return false;
4492 	self->base.repeatCount += b;
4493 	return true;
4494 }
4495 
IcStream_ReadCommand(IcStream * self)4496 static bool IcStream_ReadCommand(IcStream *self)
4497 {
4498 	int b = Stream_ReadByte(&self->base.base.base);
4499 	int escape = self->base.base.base.content[66];
4500 	if (b != escape) {
4501 		self->base.repeatCount = 1;
4502 		self->base.repeatValue = b;
4503 		return true;
4504 	}
4505 	b = Stream_ReadByte(&self->base.base.base);
4506 	if (b == escape) {
4507 		self->base.repeatCount = 1;
4508 		self->base.repeatValue = b;
4509 		return true;
4510 	}
4511 	switch (b) {
4512 	case -1:
4513 		return false;
4514 	case 0:
4515 		b = Stream_ReadByte(&self->base.base.base);
4516 		if (b < 0)
4517 			return false;
4518 		self->base.repeatCount = b + 1;
4519 		break;
4520 	case 1:
4521 		if (!IcStream_ReadCount(self))
4522 			return false;
4523 		break;
4524 	case 2:
4525 		b = Stream_ReadByte(&self->base.base.base);
4526 		switch (b) {
4527 		case -1:
4528 			return false;
4529 		case 0:
4530 			self->base.repeatCount = 32000;
4531 			break;
4532 		case 1:
4533 			if (!IcStream_ReadCount(self))
4534 				return false;
4535 			break;
4536 		case 2:
4537 			while (Stream_ReadByte(&self->base.base.base) > 0) {
4538 			}
4539 			self->base.repeatCount = 0;
4540 			break;
4541 		default:
4542 			self->base.repeatCount = b + 1;
4543 			break;
4544 		}
4545 		self->base.repeatValue = 0;
4546 		return true;
4547 	default:
4548 		self->base.repeatCount = b + 1;
4549 		break;
4550 	}
4551 	self->base.repeatValue = Stream_ReadByte(&self->base.base.base);
4552 	return true;
4553 }
4554 
DeepStream_Construct(DeepStream * self)4555 static void DeepStream_Construct(DeepStream *self)
4556 {
4557 	PackBitsStream_Construct(&self->base);
4558 	static const RleStreamVtbl vtbl = {
4559 		BitStream_ReadBit,
4560 		(bool (*)(RleStream *self)) PackBitsStream_ReadCommand,
4561 		(int (*)(RleStream *self)) DeepStream_ReadValue,
4562 	};
4563 	self->base.base.base.vtbl = (const BitStreamVtbl *) &vtbl;
4564 	self->components = 0;
4565 }
4566 
DeepStream_SetDpel(DeepStream * self,int chunkOffset,int chunkLength)4567 static bool DeepStream_SetDpel(DeepStream *self, int chunkOffset, int chunkLength)
4568 {
4569 	if (chunkLength < 8 || self->base.base.base.base.content[chunkOffset + 8] != 0 || self->base.base.base.base.content[chunkOffset + 9] != 0 || self->base.base.base.base.content[chunkOffset + 10] != 0)
4570 		return false;
4571 	self->components = self->base.base.base.base.content[chunkOffset + 11];
4572 	if (self->components > 6 || chunkLength != (self->components + 1) << 2)
4573 		return false;
4574 	for (int c = 0; c < self->components; c++) {
4575 		int offset = chunkOffset + 12 + c * 4;
4576 		if (self->base.base.base.base.content[offset] != 0 || self->base.base.base.base.content[offset + 2] != 0 || self->base.base.base.base.content[offset + 3] != 8)
4577 			return false;
4578 		int shift;
4579 		switch (self->base.base.base.base.content[offset + 1]) {
4580 		case 1:
4581 			shift = 16;
4582 			break;
4583 		case 2:
4584 			shift = 8;
4585 			break;
4586 		case 3:
4587 			shift = 0;
4588 			break;
4589 		case 4:
4590 		case 9:
4591 		case 10:
4592 		case 11:
4593 		case 17:
4594 			shift = -1;
4595 			break;
4596 		default:
4597 			return false;
4598 		}
4599 		self->componentShift[c] = shift;
4600 	}
4601 	return true;
4602 }
4603 
DeepStream_ReadValue(DeepStream * self)4604 static int DeepStream_ReadValue(DeepStream *self)
4605 {
4606 	int rgb = 0;
4607 	for (int c = 0; c < self->components; c++) {
4608 		int b = Stream_ReadByte(&self->base.base.base.base);
4609 		if (b < 0)
4610 			return -1;
4611 		int shift = self->componentShift[c];
4612 		if (shift >= 0)
4613 			rgb |= b << shift;
4614 	}
4615 	return rgb;
4616 }
4617 
DeepStream_ReadNibble(DeepStream * self)4618 static int DeepStream_ReadNibble(DeepStream *self)
4619 {
4620 	if (self->currentByte < 0) {
4621 		self->currentByte = Stream_ReadByte(&self->base.base.base.base);
4622 		if (self->currentByte < 0)
4623 			return -1;
4624 		return self->currentByte >> 4;
4625 	}
4626 	int result = self->currentByte & 15;
4627 	self->currentByte = -1;
4628 	return result;
4629 }
4630 
DeepStream_ReadDeltaLine(DeepStream * self,int width,int tvdcOffset)4631 static bool DeepStream_ReadDeltaLine(DeepStream *self, int width, int tvdcOffset)
4632 {
4633 	for (int c = 0; c < self->components; c++) {
4634 		int count = 0;
4635 		int value = 0;
4636 		self->currentByte = -1;
4637 		for (int x = 0; x < width; x++) {
4638 			if (count == 0) {
4639 				int i = DeepStream_ReadNibble(self);
4640 				if (i < 0)
4641 					return false;
4642 				int delta = self->base.base.base.base.content[tvdcOffset + i * 2 + 1];
4643 				if (delta == 0) {
4644 					if (self->base.base.base.base.content[tvdcOffset + i * 2] == 0) {
4645 						count = DeepStream_ReadNibble(self);
4646 						if (count < 0)
4647 							return false;
4648 					}
4649 				}
4650 				else
4651 					value = (value + delta) & 255;
4652 			}
4653 			else
4654 				count--;
4655 			int rgb = c == 0 ? 0 : self->line[x];
4656 			int shift = self->componentShift[c];
4657 			if (shift >= 0)
4658 				rgb |= value << shift;
4659 			self->line[x] = rgb;
4660 		}
4661 	}
4662 	return true;
4663 }
4664 
PackBytesStream_Construct(PackBytesStream * self)4665 static void PackBytesStream_Construct(PackBytesStream *self)
4666 {
4667 	self->count = 1;
4668 	self->pattern = 0;
4669 }
4670 
PackBytesStream_ReadUnpacked(PackBytesStream * self)4671 static int PackBytesStream_ReadUnpacked(PackBytesStream *self)
4672 {
4673 	if (--self->count == 0) {
4674 		if (self->base.contentOffset >= self->base.contentLength)
4675 			return -1;
4676 		int b = self->base.content[self->base.contentOffset++];
4677 		self->count = (b & 63) + 1;
4678 		if (b >= 128)
4679 			self->count <<= 2;
4680 		static const uint8_t PATTERNS[4] = { 0, 1, 4, 1 };
4681 		self->pattern = PATTERNS[b >> 6];
4682 	}
4683 	else if ((self->count & (self->pattern - 1)) == 0)
4684 		self->base.contentOffset -= self->pattern;
4685 	return Stream_ReadByte(&self->base);
4686 }
4687 
Lz4Stream_Copy(Lz4Stream * self,int count)4688 static bool Lz4Stream_Copy(Lz4Stream *self, int count)
4689 {
4690 	if (self->unpackedOffset + count > self->unpackedLength || !Stream_ReadBytes(&self->base, self->unpacked, self->unpackedOffset, count))
4691 		return false;
4692 	self->unpackedOffset += count;
4693 	return true;
4694 }
4695 
Lz4Stream_ReadCount(Lz4Stream * self,int count)4696 static int Lz4Stream_ReadCount(Lz4Stream *self, int count)
4697 {
4698 	if (count == 15) {
4699 		int b;
4700 		do {
4701 			b = Stream_ReadByte(&self->base);
4702 			if (b < 0)
4703 				return -1;
4704 			count += b;
4705 		}
4706 		while (b == 255);
4707 	}
4708 	return count;
4709 }
4710 
Tre1Stream_Construct(Tre1Stream * self)4711 static void Tre1Stream_Construct(Tre1Stream *self)
4712 {
4713 	RleStream_Construct(&self->base);
4714 	static const RleStreamVtbl vtbl = {
4715 		BitStream_ReadBit,
4716 		(bool (*)(RleStream *self)) Tre1Stream_ReadCommand,
4717 		(int (*)(RleStream *self)) Tre1Stream_ReadValue,
4718 	};
4719 	self->base.base.vtbl = (const BitStreamVtbl *) &vtbl;
4720 	self->lastRgb = -1;
4721 }
4722 
Tre1Stream_ReadCommand(Tre1Stream * self)4723 static bool Tre1Stream_ReadCommand(Tre1Stream *self)
4724 {
4725 	self->base.repeatCount = Stream_ReadByte(&self->base.base.base);
4726 	if (self->base.repeatCount <= 0)
4727 		return false;
4728 	if (self->base.repeatCount == 255) {
4729 		if (self->base.base.base.contentOffset + 1 >= self->base.base.base.contentLength)
4730 			return false;
4731 		self->base.repeatCount = 255 + (self->base.base.base.content[self->base.base.base.contentOffset] << 8) + self->base.base.base.content[self->base.base.base.contentOffset + 1];
4732 		self->base.base.base.contentOffset += 2;
4733 	}
4734 	self->base.repeatValue = self->lastRgb;
4735 	self->lastRgb = -1;
4736 	return true;
4737 }
4738 
Tre1Stream_ReadValue(Tre1Stream * self)4739 static int Tre1Stream_ReadValue(Tre1Stream *self)
4740 {
4741 	if (self->base.base.base.contentOffset + 1 >= self->base.base.base.contentLength)
4742 		return -1;
4743 	self->lastRgb = RECOIL_GetFalconTrueColor(self->base.base.base.content, self->base.base.base.contentOffset);
4744 	self->base.base.base.contentOffset += 2;
4745 	return self->lastRgb;
4746 }
4747 
Nl3Stream_Construct(Nl3Stream * self)4748 static void Nl3Stream_Construct(Nl3Stream *self)
4749 {
4750 	RleStream_Construct(&self->base);
4751 	static const RleStreamVtbl vtbl = {
4752 		BitStream_ReadBit,
4753 		(bool (*)(RleStream *self)) Nl3Stream_ReadCommand,
4754 		(int (*)(RleStream *self)) Nl3Stream_ReadValue,
4755 	};
4756 	self->base.base.vtbl = (const BitStreamVtbl *) &vtbl;
4757 }
4758 
Nl3Stream_ReadValue(Nl3Stream * self)4759 static int Nl3Stream_ReadValue(Nl3Stream *self)
4760 {
4761 	int e = BitStream_ReadNl3Char(&self->base.base, false);
4762 	if (e < 32)
4763 		return -1;
4764 	if (e < 127)
4765 		return e - 32;
4766 	if (e < 160)
4767 		return -1;
4768 	if (e < 224)
4769 		return e - 65;
4770 	if (e == 253)
4771 		return 159;
4772 	if (e == 254)
4773 		return 160;
4774 	return -1;
4775 }
4776 
Nl3Stream_ReadCommand(Nl3Stream * self)4777 static bool Nl3Stream_ReadCommand(Nl3Stream *self)
4778 {
4779 	int b = ((const RleStreamVtbl *) self->base.base.vtbl)->readValue(&self->base);
4780 	if (b < 0 || b > 127)
4781 		return false;
4782 	self->base.repeatValue = b & 63;
4783 	if (b < 64)
4784 		self->base.repeatCount = 1;
4785 	else {
4786 		b = ((const RleStreamVtbl *) self->base.base.vtbl)->readValue(&self->base);
4787 		if (b < 0)
4788 			return false;
4789 		self->base.repeatCount = b + 2;
4790 	}
4791 	return true;
4792 }
4793 
SfdnStream_Construct(SfdnStream * self)4794 static void SfdnStream_Construct(SfdnStream *self)
4795 {
4796 	BitStream_Construct(&self->base);
4797 }
4798 
SfdnStream_Unpack(SfdnStream * self,uint8_t * unpacked,int unpackedLength)4799 static bool SfdnStream_Unpack(SfdnStream *self, uint8_t *unpacked, int unpackedLength)
4800 {
4801 	if (self->base.base.contentLength < 22 + (unpackedLength >> 1) || !RECOIL_IsStringAt(self->base.base.content, 0, "S101") || (self->base.base.content[4] | self->base.base.content[5] << 8) != unpackedLength)
4802 		return false;
4803 	self->base.base.contentOffset = 22;
4804 	int current = BitStream_ReadBits(&self->base, 4);
4805 	int hi = -1;
4806 	for (int unpackedOffset = 0;;) {
4807 		if (hi < 0)
4808 			hi = current;
4809 		else {
4810 			unpacked[unpackedOffset++] = (uint8_t) (hi << 4 | current);
4811 			if (unpackedOffset >= unpackedLength)
4812 				return true;
4813 			hi = -1;
4814 		}
4815 		int code;
4816 		int bit;
4817 		for (code = 0;; code += 2) {
4818 			bit = self->base.vtbl->readBit(&self->base);
4819 			if (bit == 0)
4820 				break;
4821 			if (bit < 0 || code >= 14)
4822 				return false;
4823 		}
4824 		bit = self->base.vtbl->readBit(&self->base);
4825 		if (bit < 0)
4826 			return false;
4827 		code += bit;
4828 		current = (current - self->base.base.content[6 + code]) & 15;
4829 	}
4830 }
4831 
G9bStream_Construct(G9bStream * self)4832 static void G9bStream_Construct(G9bStream *self)
4833 {
4834 	BitStream_Construct(&self->base);
4835 }
4836 
G9bStream_ReadLength(G9bStream * self)4837 static int G9bStream_ReadLength(G9bStream *self)
4838 {
4839 	for (int length = 1; length < 65536;) {
4840 		switch (self->base.vtbl->readBit(&self->base)) {
4841 		case 0:
4842 			return length + 1;
4843 		case 1:
4844 			break;
4845 		default:
4846 			return -1;
4847 		}
4848 		length <<= 1;
4849 		switch (self->base.vtbl->readBit(&self->base)) {
4850 		case 0:
4851 			break;
4852 		case 1:
4853 			length++;
4854 			break;
4855 		default:
4856 			return -1;
4857 		}
4858 	}
4859 	return -2;
4860 }
4861 
G9bStream_Unpack(G9bStream * self,uint8_t * unpacked,int headerLength,int unpackedLength)4862 static bool G9bStream_Unpack(G9bStream *self, uint8_t *unpacked, int headerLength, int unpackedLength)
4863 {
4864 	self->base.base.contentOffset = headerLength + 3;
4865 	for (int unpackedOffset = headerLength; unpackedOffset < unpackedLength;) {
4866 		int b;
4867 		switch (self->base.vtbl->readBit(&self->base)) {
4868 		case 0:
4869 			b = Stream_ReadByte(&self->base.base);
4870 			if (b < 0)
4871 				return false;
4872 			unpacked[unpackedOffset++] = (uint8_t) b;
4873 			break;
4874 		case 1:
4875 			;
4876 			int length = G9bStream_ReadLength(self);
4877 			if (length == -2) {
4878 				self->base.base.contentOffset += 2;
4879 				self->base.bits = 0;
4880 				break;
4881 			}
4882 			if (length < 0 || unpackedOffset + length > unpackedLength)
4883 				return false;
4884 			int distance = Stream_ReadByte(&self->base.base);
4885 			if (distance < 0)
4886 				return false;
4887 			if (distance >= 128) {
4888 				b = BitStream_ReadBits(&self->base, 4);
4889 				if (b < 0)
4890 					return false;
4891 				distance += (b - 1) << 7;
4892 			}
4893 			distance++;
4894 			if (unpackedOffset - distance < headerLength)
4895 				return false;
4896 			do {
4897 				unpacked[unpackedOffset] = unpacked[unpackedOffset - distance];
4898 				unpackedOffset++;
4899 			}
4900 			while (--length > 0);
4901 			break;
4902 		default:
4903 			return false;
4904 		}
4905 	}
4906 	return true;
4907 }
4908 
MigStream_Construct(MigStream * self)4909 static void MigStream_Construct(MigStream *self)
4910 {
4911 	BitStream_Construct(&self->base);
4912 }
4913 
MigStream_Unpack(MigStream * self,uint8_t * unpacked)4914 static int MigStream_Unpack(MigStream *self, uint8_t *unpacked)
4915 {
4916 	self->base.base.contentOffset = 15;
4917 	for (int unpackedOffset = 0; unpackedOffset < 108800;) {
4918 		int c = self->base.vtbl->readBit(&self->base);
4919 		if (c < 0)
4920 			return -1;
4921 		int b = Stream_ReadByte(&self->base.base);
4922 		if (b < 0)
4923 			return -1;
4924 		if (c == 0)
4925 			unpacked[unpackedOffset++] = (uint8_t) b;
4926 		else {
4927 			if (b >= 128) {
4928 				c = BitStream_ReadBits(&self->base, 4);
4929 				if (c < 0)
4930 					return -1;
4931 				b += (c - 1) << 7;
4932 			}
4933 			int distance = b + 1;
4934 			if (unpackedOffset - distance < 0)
4935 				return -1;
4936 			c = -1;
4937 			do {
4938 				b = self->base.vtbl->readBit(&self->base);
4939 				if (b < 0)
4940 					return -1;
4941 				c++;
4942 			}
4943 			while (b != 0);
4944 			int length = BitStream_ReadBits(&self->base, c);
4945 			if (length < 0)
4946 				return -1;
4947 			if (c >= 16) {
4948 				self->base.base.contentOffset += 4;
4949 				if (self->base.base.contentOffset >= self->base.base.contentLength)
4950 					return unpackedOffset;
4951 				self->base.bits = 0;
4952 			}
4953 			else {
4954 				length += (1 << c) + 1;
4955 				if (unpackedOffset + length > 108800)
4956 					return -1;
4957 				do {
4958 					unpacked[unpackedOffset] = unpacked[unpackedOffset - distance];
4959 					unpackedOffset++;
4960 				}
4961 				while (--length > 0);
4962 			}
4963 		}
4964 	}
4965 	return -1;
4966 }
4967 
Ice21Stream_GetUnpackedLength(const Ice21Stream * self)4968 static int Ice21Stream_GetUnpackedLength(const Ice21Stream *self)
4969 {
4970 	if (self->contentStart + 16 > self->contentOffset || !RECOIL_IsStringAt(self->content, self->contentStart, "Ice!") || RECOIL_Get32BigEndian(self->content, self->contentStart + 4) != self->contentOffset - self->contentStart)
4971 		return -1;
4972 	return RECOIL_Get32BigEndian(self->content, self->contentStart + 8);
4973 }
4974 
Ice21Stream_ReadBit(Ice21Stream * self)4975 static int Ice21Stream_ReadBit(Ice21Stream *self)
4976 {
4977 	int b = self->bits;
4978 	int next = b & 2147483647;
4979 	if (next == 0) {
4980 		self->contentOffset -= 4;
4981 		if (self->contentOffset < self->contentStart)
4982 			return -1;
4983 		b = RECOIL_Get32BigEndian(self->content, self->contentOffset);
4984 		self->bits = (b & 2147483647) << 1 | 1;
4985 	}
4986 	else
4987 		self->bits = next << 1;
4988 	return b >> 31 & 1;
4989 }
4990 
Ice21Stream_ReadBits(Ice21Stream * self,int count)4991 static int Ice21Stream_ReadBits(Ice21Stream *self, int count)
4992 {
4993 	int result = 0;
4994 	while (--count >= 0) {
4995 		int bit = Ice21Stream_ReadBit(self);
4996 		if (bit < 0)
4997 			return -1;
4998 		result = result << 1 | bit;
4999 	}
5000 	return result;
5001 }
5002 
Ice21Stream_CountOnes(Ice21Stream * self,int max)5003 static int Ice21Stream_CountOnes(Ice21Stream *self, int max)
5004 {
5005 	for (int result = 0; result < max; result++) {
5006 		switch (Ice21Stream_ReadBit(self)) {
5007 		case -1:
5008 			return -1;
5009 		case 0:
5010 			return result;
5011 		default:
5012 			break;
5013 		}
5014 	}
5015 	return max;
5016 }
5017 
Ice21Stream_ReadLiteralLength(Ice21Stream * self)5018 static int Ice21Stream_ReadLiteralLength(Ice21Stream *self)
5019 {
5020 	int o = 1;
5021 	for (int n = 0;; n++) {
5022 		static const uint8_t BITS[6] = { 1, 2, 2, 3, 8, 15 };
5023 		int c = BITS[n];
5024 		int b = Ice21Stream_ReadBits(self, c);
5025 		if (b < 0)
5026 			return -1;
5027 		c = (1 << c) - 1;
5028 		if (b < c || n == 5)
5029 			return o + b;
5030 		o += c;
5031 	}
5032 }
5033 
Ice21Stream_ReadEncoded(Ice21Stream * self,int maxCount,uint8_t const * extraBits,int const * offsets)5034 static int Ice21Stream_ReadEncoded(Ice21Stream *self, int maxCount, uint8_t const *extraBits, int const *offsets)
5035 {
5036 	int n = Ice21Stream_CountOnes(self, maxCount);
5037 	if (n < 0)
5038 		return -1;
5039 	int b = Ice21Stream_ReadBits(self, extraBits[n]);
5040 	if (b < 0)
5041 		return -1;
5042 	return offsets[n] + b;
5043 }
5044 
Ice21Stream_Unpack(Ice21Stream * self,uint8_t * unpacked,int unpackedStart,int unpackedEnd)5045 static bool Ice21Stream_Unpack(Ice21Stream *self, uint8_t *unpacked, int unpackedStart, int unpackedEnd)
5046 {
5047 	self->contentStart += 12;
5048 	self->contentOffset -= 4;
5049 	self->bits = RECOIL_Get32BigEndian(self->content, self->contentOffset);
5050 	for (int unpackedOffset = unpackedEnd; unpackedOffset > unpackedStart;) {
5051 		int length;
5052 		switch (Ice21Stream_ReadBit(self)) {
5053 		case -1:
5054 			return false;
5055 		case 1:
5056 			length = Ice21Stream_ReadLiteralLength(self);
5057 			if (length > unpackedOffset - unpackedStart)
5058 				length = unpackedOffset - unpackedStart;
5059 			self->contentOffset -= length;
5060 			if (self->contentOffset < self->contentStart)
5061 				return false;
5062 			unpackedOffset -= length;
5063 			memcpy(unpacked + unpackedOffset, self->content + self->contentOffset, length);
5064 			if (unpackedOffset == unpackedStart)
5065 				return true;
5066 			break;
5067 		default:
5068 			break;
5069 		}
5070 		static const uint8_t LENGTH_EXTRA_BITS[5] = { 0, 0, 1, 2, 10 };
5071 		static const int LENGTH_OFFSETS[5] = { 0, 1, 2, 4, 8 };
5072 		length = Ice21Stream_ReadEncoded(self, 4, LENGTH_EXTRA_BITS, LENGTH_OFFSETS);
5073 		int offset;
5074 		switch (length) {
5075 		case -1:
5076 			return false;
5077 		case 0:
5078 			switch (Ice21Stream_ReadBit(self)) {
5079 			case -1:
5080 				return false;
5081 			case 0:
5082 				offset = Ice21Stream_ReadBits(self, 6);
5083 				if (offset < 0)
5084 					return false;
5085 				break;
5086 			default:
5087 				offset = Ice21Stream_ReadBits(self, 9);
5088 				if (offset < 0)
5089 					return false;
5090 				offset += 64;
5091 				break;
5092 			}
5093 			break;
5094 		default:
5095 			;
5096 			static const uint8_t OFFSET_EXTRA_BITS[3] = { 8, 5, 12 };
5097 			static const int OFFSET_OFFSETS[3] = { 32, 0, 288 };
5098 			offset = Ice21Stream_ReadEncoded(self, 2, OFFSET_EXTRA_BITS, OFFSET_OFFSETS);
5099 			if (offset < 0)
5100 				return false;
5101 			break;
5102 		}
5103 		length += 2;
5104 		offset += length;
5105 		if (unpackedOffset + offset > unpackedEnd)
5106 			return false;
5107 		if (length > unpackedOffset - unpackedStart)
5108 			length = unpackedOffset - unpackedStart;
5109 		unpackedOffset -= length;
5110 		memcpy(unpacked + unpackedOffset, unpacked + unpackedOffset + offset, length);
5111 	}
5112 	return true;
5113 }
5114 
SpxStream_ReadCount(SpxStream * self)5115 static int SpxStream_ReadCount(SpxStream *self)
5116 {
5117 	int b = Ice21Stream_ReadBits(&self->base, 2);
5118 	if (b < 0)
5119 		return -1;
5120 	return Ice21Stream_ReadBits(&self->base, (b + 1) << 2);
5121 }
5122 
SpxStream_UnpackV2(SpxStream * self,uint8_t * unpacked,int unpackedLength)5123 static bool SpxStream_UnpackV2(SpxStream *self, uint8_t *unpacked, int unpackedLength)
5124 {
5125 	self->base.bits = 0;
5126 	for (int unpackedOffset = unpackedLength; unpackedOffset > 0;) {
5127 		int count;
5128 		switch (Ice21Stream_ReadBit(&self->base)) {
5129 		case -1:
5130 			return false;
5131 		case 0:
5132 			count = SpxStream_ReadCount(self);
5133 			if (count <= 0)
5134 				return false;
5135 			if (count > unpackedOffset)
5136 				count = unpackedOffset;
5137 			for (int i = 0; i < count; i++) {
5138 				int b = Ice21Stream_ReadBits(&self->base, 8);
5139 				if (b < 0)
5140 					return false;
5141 				unpacked[--unpackedOffset] = (uint8_t) b;
5142 			}
5143 			if (unpackedOffset == 0)
5144 				return true;
5145 			if (count == 65535)
5146 				continue;
5147 			break;
5148 		default:
5149 			break;
5150 		}
5151 		int distance = SpxStream_ReadCount(self);
5152 		if (distance <= 0 || unpackedOffset + distance > unpackedLength)
5153 			return false;
5154 		count = SpxStream_ReadCount(self);
5155 		if (count < 0)
5156 			return false;
5157 		count += 3;
5158 		if (count > unpackedOffset)
5159 			count = unpackedOffset;
5160 		do {
5161 			unpackedOffset--;
5162 			unpacked[unpackedOffset] = unpacked[unpackedOffset + distance];
5163 		}
5164 		while (--count > 0);
5165 	}
5166 	return true;
5167 }
5168 
Q4Stream_Construct(Q4Stream * self)5169 static void Q4Stream_Construct(Q4Stream *self)
5170 {
5171 	RleStream_Construct(&self->base);
5172 	static const RleStreamVtbl vtbl = {
5173 		BitStream_ReadBit,
5174 		(bool (*)(RleStream *self)) Q4Stream_ReadCommand,
5175 		RleStream_ReadValue,
5176 	};
5177 	self->base.base.vtbl = (const BitStreamVtbl *) &vtbl;
5178 }
5179 
Q4Stream_StartChunk(Q4Stream * self)5180 static int Q4Stream_StartChunk(Q4Stream *self)
5181 {
5182 	if (self->base.base.base.contentOffset + 6 > self->base.base.base.contentLength)
5183 		return -1;
5184 	int chunkLength = self->base.base.base.content[self->base.base.base.contentOffset] | self->base.base.base.content[self->base.base.base.contentOffset + 1] << 8;
5185 	self->base.base.base.contentOffset += 6;
5186 	self->base.base.base.contentLength = self->base.base.base.contentOffset + chunkLength;
5187 	return self->base.base.base.contentLength;
5188 }
5189 
Q4Stream_ReadCode(Q4Stream * self)5190 static int Q4Stream_ReadCode(Q4Stream *self)
5191 {
5192 	do {
5193 		int value = BitStream_ReadBits(&self->base.base, self->codeBits);
5194 		switch (value) {
5195 		case -1:
5196 		case 0:
5197 			return -1;
5198 		case 1:
5199 			break;
5200 		default:
5201 			return value - 2;
5202 		}
5203 	}
5204 	while (++self->codeBits <= 15);
5205 	return -1;
5206 }
5207 
Q4Stream_UnpackQ4(Q4Stream * self)5208 static bool Q4Stream_UnpackQ4(Q4Stream *self)
5209 {
5210 	self->base.base.bits = 0;
5211 	self->codeBits = 3;
5212 	int unpackedLength = 0;
5213 	int offsets[16384];
5214 	for (int codes = 17; codes < 16384; codes++) {
5215 		int code = Q4Stream_ReadCode(self);
5216 		if (code < 0 || code >= codes) {
5217 			self->base.base.base.content = self->unpacked;
5218 			self->base.base.base.contentOffset = 0;
5219 			self->base.base.base.contentLength = unpackedLength;
5220 			self->lastRepeatValue = 0;
5221 			return true;
5222 		}
5223 		offsets[codes] = unpackedLength;
5224 		if (code <= 16) {
5225 			if (unpackedLength >= 65536)
5226 				return false;
5227 			self->unpacked[unpackedLength++] = (uint8_t) code;
5228 		}
5229 		else {
5230 			int sourceOffset = offsets[code];
5231 			int endOffset = offsets[code + 1];
5232 			if (unpackedLength + endOffset - sourceOffset >= 65536)
5233 				return false;
5234 			do
5235 				self->unpacked[unpackedLength++] = self->unpacked[sourceOffset++];
5236 			while (sourceOffset <= endOffset);
5237 		}
5238 	}
5239 	return false;
5240 }
5241 
Q4Stream_ReadCommand(Q4Stream * self)5242 static bool Q4Stream_ReadCommand(Q4Stream *self)
5243 {
5244 	int b = Stream_ReadByte(&self->base.base.base);
5245 	if (b < 0)
5246 		return false;
5247 	if (b < 16) {
5248 		self->base.repeatCount = 1;
5249 		self->base.repeatValue = b;
5250 		return true;
5251 	}
5252 	b = Stream_ReadByte(&self->base.base.base);
5253 	if (b == 0) {
5254 		self->lastRepeatValue = Stream_ReadByte(&self->base.base.base);
5255 		if (self->lastRepeatValue < 0 || self->lastRepeatValue >= 16)
5256 			return false;
5257 		b = Stream_ReadByte(&self->base.base.base);
5258 	}
5259 	if (b < 0)
5260 		return false;
5261 	self->base.repeatCount = b * 17;
5262 	b = Stream_ReadByte(&self->base.base.base);
5263 	if (b < 0)
5264 		return false;
5265 	self->base.repeatCount += b;
5266 	self->base.repeatValue = self->lastRepeatValue;
5267 	return true;
5268 }
5269 
PiStream_Construct(PiStream * self)5270 static void PiStream_Construct(PiStream *self)
5271 {
5272 	BitStream_Construct(&self->base);
5273 	self->indexes = NULL;
5274 }
5275 
PiStream_Destruct(PiStream * self)5276 static void PiStream_Destruct(PiStream *self)
5277 {
5278 	CiShared_Release(self->indexes);
5279 }
5280 
PiStream_ReadInt(PiStream * self,int bits,int maxBits)5281 static int PiStream_ReadInt(PiStream *self, int bits, int maxBits)
5282 {
5283 	for (; bits < maxBits; bits++) {
5284 		int b = self->base.vtbl->readBit(&self->base);
5285 		if (b == 0)
5286 			break;
5287 		if (b < 0)
5288 			return -1;
5289 	}
5290 	return 1 << bits | BitStream_ReadBits(&self->base, bits);
5291 }
5292 
PiStream_UnpackLiteral(PiStream * self,int indexesOffset,int depth)5293 static bool PiStream_UnpackLiteral(PiStream *self, int indexesOffset, int depth)
5294 {
5295 	int offset;
5296 	switch (self->base.vtbl->readBit(&self->base)) {
5297 	case 1:
5298 		offset = self->base.vtbl->readBit(&self->base);
5299 		break;
5300 	case 0:
5301 		offset = PiStream_ReadInt(self, 1, depth - 1);
5302 		break;
5303 	default:
5304 		return false;
5305 	}
5306 	if (offset < 0)
5307 		return false;
5308 	int recentOffset = indexesOffset == 0 ? 0 : self->indexes[indexesOffset - 1] << 8;
5309 	offset += recentOffset;
5310 	int c = self->recentColors[offset];
5311 	for (; offset > recentOffset; offset--)
5312 		self->recentColors[offset] = self->recentColors[offset - 1];
5313 	self->recentColors[offset] = (uint8_t) c;
5314 	self->indexes[indexesOffset] = (uint8_t) c;
5315 	return true;
5316 }
5317 
PiStream_UnpackTwoLiterals(PiStream * self,int indexesOffset,int indexesLength,int depth)5318 static bool PiStream_UnpackTwoLiterals(PiStream *self, int indexesOffset, int indexesLength, int depth)
5319 {
5320 	if (!PiStream_UnpackLiteral(self, indexesOffset, depth))
5321 		return false;
5322 	return indexesOffset + 1 >= indexesLength || PiStream_UnpackLiteral(self, indexesOffset + 1, depth);
5323 }
5324 
PiStream_ReadPosition(PiStream * self)5325 static int PiStream_ReadPosition(PiStream *self)
5326 {
5327 	int position = BitStream_ReadBits(&self->base, 2);
5328 	if (position != 3)
5329 		return position;
5330 	position = self->base.vtbl->readBit(&self->base);
5331 	if (position < 0)
5332 		return -1;
5333 	return 3 + position;
5334 }
5335 
PiStream_Unpack(PiStream * self,int width,int height,int depth)5336 static bool PiStream_Unpack(PiStream *self, int width, int height, int depth)
5337 {
5338 	int colors = 1 << depth;
5339 	for (int i = 0; i < colors; i++)
5340 		for (int j = 0; j < colors; j++)
5341 			self->recentColors[i << 8 | j] = (uint8_t) ((i - j) & (colors - 1));
5342 	int indexesLength = width * height;
5343 	CiShared_Assign((void **) &self->indexes, (uint8_t *) CiShared_Make(indexesLength, sizeof(uint8_t), NULL, NULL));
5344 	if (!PiStream_UnpackTwoLiterals(self, 0, indexesLength, depth))
5345 		return false;
5346 	int lastPosition = -1;
5347 	for (int indexesOffset = 0; indexesOffset < indexesLength;) {
5348 		int position = PiStream_ReadPosition(self);
5349 		if (position < 0)
5350 			return false;
5351 		if (position == lastPosition) {
5352 			do {
5353 				if (!PiStream_UnpackTwoLiterals(self, indexesOffset, indexesLength, depth))
5354 					return false;
5355 				indexesOffset += 2;
5356 			}
5357 			while (indexesOffset < indexesLength && self->base.vtbl->readBit(&self->base) == 1);
5358 			lastPosition = -1;
5359 		}
5360 		else {
5361 			int length = PiStream_ReadInt(self, 0, 23);
5362 			if (length < 0)
5363 				return false;
5364 			lastPosition = position;
5365 			switch (position) {
5366 			case 0:
5367 				position = indexesOffset == 0 ? 0 : indexesOffset - 2;
5368 				position = self->indexes[position] == self->indexes[position + 1] ? 2 : 4;
5369 				break;
5370 			case 1:
5371 				position = width;
5372 				break;
5373 			case 2:
5374 				position = width << 1;
5375 				break;
5376 			case 3:
5377 				position = width - 1;
5378 				break;
5379 			case 4:
5380 				position = width + 1;
5381 				break;
5382 			default:
5383 				assert(false);
5384 			}
5385 			int copyEnd = indexesOffset + (length << 1);
5386 			if (copyEnd > indexesLength)
5387 				copyEnd = indexesLength;
5388 			for (; indexesOffset < copyEnd; indexesOffset++) {
5389 				int sourceOffset = indexesOffset - position;
5390 				if (sourceOffset < 0)
5391 					sourceOffset &= 1;
5392 				self->indexes[indexesOffset] = self->indexes[sourceOffset];
5393 			}
5394 		}
5395 	}
5396 	return true;
5397 }
5398 
A4rStream_Construct(A4rStream * self)5399 static void A4rStream_Construct(A4rStream *self)
5400 {
5401 	self->outerFlags = 0;
5402 	self->innerFlags = 0;
5403 }
5404 
A4rStream_ReadFlag(A4rStream * self)5405 static int A4rStream_ReadFlag(A4rStream *self)
5406 {
5407 	if ((self->innerFlags & 127) == 0) {
5408 		if ((self->outerFlags & 127) == 0) {
5409 			if (self->base.contentOffset >= self->base.contentLength)
5410 				return -1;
5411 			self->outerFlags = self->base.content[self->base.contentOffset++] << 1 | 1;
5412 		}
5413 		else
5414 			self->outerFlags <<= 1;
5415 		if ((self->outerFlags & 256) == 0)
5416 			self->innerFlags = 1;
5417 		else {
5418 			if (self->base.contentOffset >= self->base.contentLength)
5419 				return -1;
5420 			self->innerFlags = self->base.content[self->base.contentOffset++] << 1 | 1;
5421 		}
5422 	}
5423 	else
5424 		self->innerFlags <<= 1;
5425 	return self->innerFlags >> 8 & 1;
5426 }
5427 
A4rStream_CopyByte(A4rStream * self)5428 static bool A4rStream_CopyByte(A4rStream *self)
5429 {
5430 	int b = Stream_ReadByte(&self->base);
5431 	if (b < 0 || self->unpackedOffset < 0 || self->unpackedOffset >= 11248)
5432 		return false;
5433 	self->unpacked[self->unpackedOffset++] = (uint8_t) b;
5434 	return true;
5435 }
5436 
A4rStream_CopyBlock(A4rStream * self,int distance,int count)5437 static bool A4rStream_CopyBlock(A4rStream *self, int distance, int count)
5438 {
5439 	if (self->unpackedOffset < 0)
5440 		return false;
5441 	int nextOffset = self->unpackedOffset + count;
5442 	if (nextOffset > 11248 || !RECOIL_CopyPrevious(self->unpacked, self->unpackedOffset, distance, count))
5443 		return false;
5444 	self->unpackedOffset = nextOffset;
5445 	return true;
5446 }
5447 
A4rStream_UnpackA4r(A4rStream * self)5448 static bool A4rStream_UnpackA4r(A4rStream *self)
5449 {
5450 	memset(self->unpacked, 0, sizeof(self->unpacked));
5451 	self->unpackedOffset = -1;
5452 	for (;;) {
5453 		switch (A4rStream_ReadFlag(self)) {
5454 		case 0:
5455 			if (!A4rStream_CopyByte(self))
5456 				return false;
5457 			break;
5458 		case 1:
5459 			;
5460 			int b = Stream_ReadByte(&self->base);
5461 			switch (b) {
5462 			case -1:
5463 				return false;
5464 			case 0:
5465 				if (self->base.contentOffset >= self->base.contentLength - 2)
5466 					return false;
5467 				b = Stream_ReadByte(&self->base);
5468 				self->unpackedOffset = b + (Stream_ReadByte(&self->base) << 8) + 128 - 19984;
5469 				if (!A4rStream_CopyByte(self))
5470 					return false;
5471 				break;
5472 			case 1:
5473 				b = Stream_ReadByte(&self->base);
5474 				switch (b) {
5475 				case -1:
5476 					return false;
5477 				case 0:
5478 					return true;
5479 				default:
5480 					if (!A4rStream_CopyBlock(self, 1, b + 2))
5481 						return false;
5482 					break;
5483 				}
5484 				break;
5485 			default:
5486 				if (!A4rStream_CopyBlock(self, 128 - (b >> 1), 2 + (b & 1)))
5487 					return false;
5488 				break;
5489 			}
5490 			break;
5491 		default:
5492 			return false;
5493 		}
5494 	}
5495 }
5496 
FanoTree_Create(FanoTree * self,uint8_t const * content,int contentOffset,int codeCount)5497 static void FanoTree_Create(FanoTree *self, uint8_t const *content, int contentOffset, int codeCount)
5498 {
5499 	memset(self->count, 0, sizeof(self->count));
5500 	for (int code = 0; code < codeCount; code++)
5501 		self->count[RECOIL_GetNibble(content, contentOffset, code)]++;
5502 	int positions[16];
5503 	int position = 0;
5504 	for (int bits = 0; bits < 16; bits++) {
5505 		positions[bits] = position;
5506 		position += self->count[bits];
5507 	}
5508 	for (int code = 0; code < codeCount; code++)
5509 		self->values[positions[RECOIL_GetNibble(content, contentOffset, code)]++] = (uint8_t) code;
5510 }
5511 
FanoTree_ReadCode(const FanoTree * self,BitStream * bitStream)5512 static int FanoTree_ReadCode(const FanoTree *self, BitStream *bitStream)
5513 {
5514 	int code = 0;
5515 	int valuesOffset = self->count[0];
5516 	for (int bits = 1; bits < 16; bits++) {
5517 		int bit = bitStream->vtbl->readBit(bitStream);
5518 		if (bit < 0)
5519 			return -1;
5520 		code = code << 1 | bit;
5521 		int count = self->count[bits];
5522 		if (code < count)
5523 			return self->values[valuesOffset + code];
5524 		code -= count;
5525 		valuesOffset += count;
5526 	}
5527 	return -1;
5528 }
5529 
RecentInts_Construct(RecentInts * self)5530 static void RecentInts_Construct(RecentInts *self)
5531 {
5532 	for (int _i0 = 0; _i0 < 128; _i0++) {
5533 		self->value[_i0] = 0;
5534 	}
5535 	self->head = 0;
5536 	for (int i = 0; i < 128; i++) {
5537 		self->prev[i] = (uint8_t) ((i + 1) & 127);
5538 		self->next[i] = (uint8_t) ((i - 1) & 127);
5539 	}
5540 }
5541 
RecentInts_Add(RecentInts * self,int value)5542 static void RecentInts_Add(RecentInts *self, int value)
5543 {
5544 	self->head = self->prev[self->head];
5545 	self->value[self->head] = value;
5546 }
5547 
RecentInts_Get(RecentInts * self,int key)5548 static int RecentInts_Get(RecentInts *self, int key)
5549 {
5550 	if (key != self->head) {
5551 		int prev = self->prev[key];
5552 		int next = self->next[key];
5553 		self->next[prev] = (uint8_t) next;
5554 		self->prev[next] = (uint8_t) prev;
5555 		int tail = self->prev[self->head];
5556 		self->next[tail] = (uint8_t) key;
5557 		self->prev[key] = (uint8_t) tail;
5558 		self->prev[self->head] = (uint8_t) key;
5559 		self->next[key] = (uint8_t) self->head;
5560 		self->head = key;
5561 	}
5562 	return self->value[key];
5563 }
5564 
BlazingPaddlesBoundingBox_Calculate(BlazingPaddlesBoundingBox * self,uint8_t const * content,int contentLength,int index,int startAddress)5565 static bool BlazingPaddlesBoundingBox_Calculate(BlazingPaddlesBoundingBox *self, uint8_t const *content, int contentLength, int index, int startAddress)
5566 {
5567 	index <<= 1;
5568 	if (index + 1 >= contentLength)
5569 		return false;
5570 	int contentOffset = content[index] + (content[index + 1] << 8) - startAddress;
5571 	if (contentOffset < 0)
5572 		return false;
5573 	self->left = self->top = self->right = self->bottom = 0;
5574 	int x = 0;
5575 	int y = 0;
5576 	while (contentOffset < contentLength) {
5577 		int control = content[contentOffset++];
5578 		if (control == 8)
5579 			return true;
5580 		int len = (control >> 4) + 1;
5581 		switch (control & 3) {
5582 		case 0:
5583 			x += len;
5584 			if (self->right < x)
5585 				self->right = x;
5586 			break;
5587 		case 1:
5588 			x -= len;
5589 			if (self->left > x)
5590 				self->left = x;
5591 			break;
5592 		case 2:
5593 			y -= len;
5594 			if (self->top > y)
5595 				self->top = y;
5596 			break;
5597 		case 3:
5598 			y += len;
5599 			if (self->bottom < y)
5600 				self->bottom = y;
5601 			break;
5602 		default:
5603 			assert(false);
5604 		}
5605 	}
5606 	return false;
5607 }
5608 
IcnParser_SkipWhitespace(IcnParser * self)5609 static bool IcnParser_SkipWhitespace(IcnParser *self)
5610 {
5611 	bool got = false;
5612 	while (self->base.contentOffset < self->base.contentLength) {
5613 		switch (self->base.content[self->base.contentOffset]) {
5614 		case 32:
5615 		case 9:
5616 		case 13:
5617 		case 10:
5618 			self->base.contentOffset++;
5619 			got = true;
5620 			break;
5621 		case 47:
5622 			if (self->base.contentOffset >= self->base.contentLength - 3 || self->base.content[self->base.contentOffset + 1] != 42)
5623 				return false;
5624 			self->base.contentOffset += 3;
5625 			do {
5626 				if (++self->base.contentOffset > self->base.contentLength)
5627 					return false;
5628 			}
5629 			while (self->base.content[self->base.contentOffset - 2] != 42 || self->base.content[self->base.contentOffset - 1] != 47);
5630 			got = true;
5631 			break;
5632 		default:
5633 			return got;
5634 		}
5635 	}
5636 	return true;
5637 }
5638 
IcnParser_Expect(IcnParser * self,const char * s)5639 static bool IcnParser_Expect(IcnParser *self, const char *s)
5640 {
5641 	if (!IcnParser_SkipWhitespace(self))
5642 		return false;
5643 	int length = (int) strlen(s);
5644 	for (int i = 0; i < length; i++)
5645 		if (Stream_ReadByte(&self->base) != s[i])
5646 			return false;
5647 	return true;
5648 }
5649 
IcnParser_ParseHex(IcnParser * self)5650 static int IcnParser_ParseHex(IcnParser *self)
5651 {
5652 	if (!IcnParser_Expect(self, "0x"))
5653 		return -1;
5654 	int r = 0;
5655 	for (;;) {
5656 		int d = Stream_ReadHexDigit(&self->base);
5657 		if (d < 0)
5658 			return r;
5659 		if (r >> 12 != 0)
5660 			return -1;
5661 		r = r << 4 | d;
5662 	}
5663 }
5664 
IcnParser_ParseDefine(IcnParser * self,const char * s)5665 static int IcnParser_ParseDefine(IcnParser *self, const char *s)
5666 {
5667 	if (!IcnParser_Expect(self, "#define") || !IcnParser_Expect(self, s))
5668 		return -1;
5669 	return IcnParser_ParseHex(self);
5670 }
5671 
PInterpreter_ReadNumber(PInterpreter * self)5672 static int PInterpreter_ReadNumber(PInterpreter *self)
5673 {
5674 	for (;;) {
5675 		switch (Stream_ReadByte(&self->base)) {
5676 		case 21:
5677 		case 22:
5678 		case 27:
5679 		case 28:
5680 		case 29:
5681 		case 30:
5682 		case 31:
5683 		case 32:
5684 		case 33:
5685 		case 34:
5686 		case 35:
5687 		case 36:
5688 		case 37:
5689 		case 42:
5690 			break;
5691 		case 126:
5692 			if (self->base.contentOffset > self->base.contentLength - 5)
5693 				return -1;
5694 			int exp = Stream_ReadByte(&self->base);
5695 			int m0 = Stream_ReadByte(&self->base);
5696 			int m1 = Stream_ReadByte(&self->base);
5697 			self->base.contentOffset += 2;
5698 			if (exp > 144 || m0 >= 128)
5699 				return -1;
5700 			if (exp <= 128)
5701 				return 0;
5702 			return ((m0 | 128) << 8 | m1) >> (144 - exp);
5703 		default:
5704 			return -1;
5705 		}
5706 	}
5707 }
5708 
PInterpreter_PrintString(PInterpreter * self,int offset)5709 static int PInterpreter_PrintString(PInterpreter *self, int offset)
5710 {
5711 	for (;;) {
5712 		if (offset >= self->base.contentLength)
5713 			return -1;
5714 		int c = self->base.content[offset++];
5715 		if (c == 11)
5716 			break;
5717 		if (self->screenOffset >= 768)
5718 			return -1;
5719 		if (c == 192)
5720 			c = 11;
5721 		else if ((c & 127) >= 64)
5722 			return -1;
5723 		self->screen[self->screenOffset++] = (uint8_t) c;
5724 		self->newLineWorks = (self->screenOffset & 31) != 0;
5725 	}
5726 	return offset;
5727 }
5728 
PInterpreter_Print(PInterpreter * self)5729 static bool PInterpreter_Print(PInterpreter *self)
5730 {
5731 	for (;;) {
5732 		switch (Stream_ReadByte(&self->base)) {
5733 		case 11:
5734 			self->base.contentOffset = PInterpreter_PrintString(self, self->base.contentOffset);
5735 			if (self->base.contentOffset < 0)
5736 				return false;
5737 			break;
5738 		case 193:
5739 			;
5740 			int row = PInterpreter_ReadNumber(self);
5741 			if (row < 0 || row > 21 || Stream_ReadByte(&self->base) != 26)
5742 				return false;
5743 			int column = PInterpreter_ReadNumber(self);
5744 			if (column < 0 || column > 31)
5745 				return false;
5746 			self->screenOffset = row << 5 | column;
5747 			self->newLineWorks = true;
5748 			break;
5749 		case 0:
5750 		case 25:
5751 			break;
5752 		case 118:
5753 			self->base.contentOffset--;
5754 			if (self->base.content[self->base.contentOffset - 1] != 25) {
5755 				if (self->newLineWorks)
5756 					self->screenOffset = (self->screenOffset & -32) + 32;
5757 				self->newLineWorks = true;
5758 			}
5759 			return true;
5760 		default:
5761 			return false;
5762 		}
5763 	}
5764 }
5765 
PInterpreter_DPeek(PInterpreter * self,int expectedX,int expectedAddress)5766 static bool PInterpreter_DPeek(PInterpreter *self, int expectedX, int expectedAddress)
5767 {
5768 	return Stream_ReadByte(&self->base) == 20 && PInterpreter_ReadNumber(self) == expectedX && Stream_ReadByte(&self->base) == 21 && Stream_ReadByte(&self->base) == 211 && PInterpreter_ReadNumber(self) == expectedAddress && Stream_ReadByte(&self->base) == 21 && PInterpreter_ReadNumber(self) == 256 && Stream_ReadByte(&self->base) == 23 && Stream_ReadByte(&self->base) == 211 && PInterpreter_ReadNumber(self) == expectedAddress + 1;
5769 }
5770 
PInterpreter_Let(PInterpreter * self)5771 static bool PInterpreter_Let(PInterpreter *self)
5772 {
5773 	switch (Stream_ReadByte(&self->base)) {
5774 	case 38:
5775 		if (Stream_ReadByte(&self->base) != 13 || Stream_ReadByte(&self->base) != 20 || Stream_ReadByte(&self->base) != 11)
5776 			return false;
5777 		self->bottomOffset = self->base.contentOffset;
5778 		for (;;) {
5779 			switch (Stream_ReadByte(&self->base)) {
5780 			case -1:
5781 				return false;
5782 			case 11:
5783 				return true;
5784 			default:
5785 				break;
5786 			}
5787 		}
5788 	case 56:
5789 		self->bottomCode |= 1;
5790 		return PInterpreter_DPeek(self, 3, 16400);
5791 	case 41:
5792 		self->bottomCode |= 2;
5793 		return PInterpreter_DPeek(self, 727, 16396);
5794 	default:
5795 		return false;
5796 	}
5797 }
5798 
PInterpreter_DoIf(PInterpreter * self)5799 static bool PInterpreter_DoIf(PInterpreter *self)
5800 {
5801 	return Stream_ReadByte(&self->base) == 198 && Stream_ReadByte(&self->base) == 38 && Stream_ReadByte(&self->base) == 13 && Stream_ReadByte(&self->base) == 221 && PInterpreter_ReadNumber(self) == 64 && Stream_ReadByte(&self->base) == 222 && Stream_ReadByte(&self->base) == 227;
5802 }
5803 
PInterpreter_DoFor(PInterpreter * self)5804 static bool PInterpreter_DoFor(PInterpreter *self)
5805 {
5806 	self->bottomCode |= 4;
5807 	return Stream_ReadByte(&self->base) == 43 && Stream_ReadByte(&self->base) == 20 && PInterpreter_ReadNumber(self) == 0 && Stream_ReadByte(&self->base) == 223 && PInterpreter_ReadNumber(self) == 63;
5808 }
5809 
PInterpreter_Poke(PInterpreter * self)5810 static bool PInterpreter_Poke(PInterpreter *self)
5811 {
5812 	self->bottomCode |= 8;
5813 	return Stream_ReadByte(&self->base) == 41 && Stream_ReadByte(&self->base) == 21 && Stream_ReadByte(&self->base) == 43 && Stream_ReadByte(&self->base) == 21 && Stream_ReadByte(&self->base) == 16 && Stream_ReadByte(&self->base) == 43 && Stream_ReadByte(&self->base) == 18 && PInterpreter_ReadNumber(self) == 31 && Stream_ReadByte(&self->base) == 17 && Stream_ReadByte(&self->base) == 26 && Stream_ReadByte(&self->base) == 211 && Stream_ReadByte(&self->base) == 16 && Stream_ReadByte(&self->base) == 56 && Stream_ReadByte(&self->base) == 21 && Stream_ReadByte(&self->base) == 43 && Stream_ReadByte(&self->base) == 17;
5814 }
5815 
PInterpreter_Next(PInterpreter * self)5816 static bool PInterpreter_Next(PInterpreter *self)
5817 {
5818 	if (Stream_ReadByte(&self->base) == 43 && self->bottomOffset > 0 && self->bottomCode == 15) {
5819 		self->screenOffset = 704;
5820 		return PInterpreter_PrintString(self, self->bottomOffset) >= 0;
5821 	}
5822 	return false;
5823 }
5824 
PInterpreter_Run(PInterpreter * self)5825 static bool PInterpreter_Run(PInterpreter *self)
5826 {
5827 	self->base.contentOffset = 116;
5828 	memset(self->screen, 0, sizeof(self->screen));
5829 	self->screenOffset = 0;
5830 	self->newLineWorks = true;
5831 	self->bottomOffset = -1;
5832 	self->bottomCode = 0;
5833 	for (;;) {
5834 		if (self->base.contentOffset > self->base.contentLength - 8)
5835 			return false;
5836 		if (Stream_ReadByte(&self->base) == 118)
5837 			return true;
5838 		self->base.contentOffset += 3;
5839 		switch (Stream_ReadByte(&self->base)) {
5840 		case 228:
5841 		case 229:
5842 		case 251:
5843 		case 253:
5844 			break;
5845 		case 227:
5846 		case 236:
5847 		case 242:
5848 			return true;
5849 		case 245:
5850 			if (!PInterpreter_Print(self))
5851 				return false;
5852 			break;
5853 		case 241:
5854 			if (!PInterpreter_Let(self))
5855 				return false;
5856 			break;
5857 		case 250:
5858 			if (!PInterpreter_DoIf(self))
5859 				return false;
5860 			break;
5861 		case 235:
5862 			if (!PInterpreter_DoFor(self))
5863 				return false;
5864 			break;
5865 		case 244:
5866 			if (!PInterpreter_Poke(self))
5867 				return false;
5868 			break;
5869 		case 243:
5870 			if (!PInterpreter_Next(self))
5871 				return false;
5872 			break;
5873 		default:
5874 			return false;
5875 		}
5876 		if (Stream_ReadByte(&self->base) != 118)
5877 			return false;
5878 	}
5879 }
5880 
GtiaRenderer_SetPlayerSize(GtiaRenderer * self,int i,int size)5881 static void GtiaRenderer_SetPlayerSize(GtiaRenderer *self, int i, int size)
5882 {
5883 	size &= 3;
5884 	self->playerSize[i] = (uint8_t) (size == 2 ? 1 : size + 1);
5885 }
5886 
GtiaRenderer_SetSpriteSizes(uint8_t * sizes,int value)5887 static void GtiaRenderer_SetSpriteSizes(uint8_t *sizes, int value)
5888 {
5889 	for (int i = 0; i < 4; i++) {
5890 		int size = value >> (i << 1) & 3;
5891 		sizes[i] = (uint8_t) (size == 2 ? 1 : size + 1);
5892 	}
5893 }
5894 
GtiaRenderer_Poke(GtiaRenderer * self,int addr,int value)5895 static void GtiaRenderer_Poke(GtiaRenderer *self, int addr, int value)
5896 {
5897 	switch (addr) {
5898 	case 0:
5899 	case 1:
5900 	case 2:
5901 	case 3:
5902 		self->playerHpos[addr] = (uint8_t) value;
5903 		break;
5904 	case 4:
5905 	case 5:
5906 	case 6:
5907 	case 7:
5908 		self->missileHpos[addr - 4] = (uint8_t) value;
5909 		break;
5910 	case 8:
5911 	case 9:
5912 	case 10:
5913 	case 11:
5914 		GtiaRenderer_SetPlayerSize(self, addr - 8, value);
5915 		break;
5916 	case 12:
5917 		GtiaRenderer_SetSpriteSizes(self->missileSize, value);
5918 		break;
5919 	case 13:
5920 	case 14:
5921 	case 15:
5922 	case 16:
5923 		self->playerGraphics[addr - 13] = (uint8_t) value;
5924 		break;
5925 	case 17:
5926 		self->missileGraphics = value;
5927 		break;
5928 	case 18:
5929 	case 19:
5930 	case 20:
5931 	case 21:
5932 	case 22:
5933 	case 23:
5934 	case 24:
5935 	case 25:
5936 	case 26:
5937 		self->colors[addr - 18] = (uint8_t) (value & 254);
5938 		break;
5939 	case 27:
5940 		self->prior = value;
5941 		break;
5942 	default:
5943 		break;
5944 	}
5945 }
5946 
GtiaRenderer_ProcessSpriteDma(GtiaRenderer * self,uint8_t const * content,int missileOffset)5947 static void GtiaRenderer_ProcessSpriteDma(GtiaRenderer *self, uint8_t const *content, int missileOffset)
5948 {
5949 	self->missileGraphics = content[missileOffset];
5950 	for (int i = 0; i < 4; i++)
5951 		self->playerGraphics[i] = content[missileOffset + ((1 + i) << 8)];
5952 }
5953 
GtiaRenderer_GetPmg(GtiaRenderer * self,int hpos,int objects)5954 static int GtiaRenderer_GetPmg(GtiaRenderer *self, int hpos, int objects)
5955 {
5956 	for (int i = 0; i < 4; i++) {
5957 		if (self->playerHpos[i] == hpos) {
5958 			self->playerShiftRegister[i] |= self->playerGraphics[i];
5959 			self->playerSizeCounter[i] = self->playerSize[i];
5960 		}
5961 		if (self->missileHpos[i] == hpos) {
5962 			self->missileShiftRegister |= self->missileGraphics & 3 << (i << 1);
5963 			self->missileSizeCounter[i] = self->missileSize[i];
5964 		}
5965 	}
5966 	if ((self->prior & 16) != 0 && (self->missileShiftRegister & 170) != 0)
5967 		objects |= 128;
5968 	for (int i = 0; i < 4; i++) {
5969 		if ((self->playerShiftRegister[i] & 128) != 0 || ((self->prior & 16) == 0 && (self->missileShiftRegister & 2 << (i << 1)) != 0))
5970 			objects |= 1 << i;
5971 		if (--self->playerSizeCounter[i] == 0) {
5972 			self->playerShiftRegister[i] = (uint8_t) (self->playerShiftRegister[i] << 1);
5973 			self->playerSizeCounter[i] = self->playerSize[i];
5974 		}
5975 		if (--self->missileSizeCounter[i] == 0) {
5976 			int mask = 1 << (i << 1);
5977 			self->missileShiftRegister = (self->missileShiftRegister & ~(mask * 3)) | (self->missileShiftRegister & mask) << 1;
5978 			self->missileSizeCounter[i] = self->missileSize[i];
5979 		}
5980 	}
5981 	return objects;
5982 }
5983 
GtiaRenderer_GetColor(const GtiaRenderer * self,int objects)5984 static int GtiaRenderer_GetColor(const GtiaRenderer *self, int objects)
5985 {
5986 	if (objects == 0)
5987 		return self->colors[8];
5988 	int prior = self->prior;
5989 	int color = 0;
5990 	if ((objects & 3) != 0) {
5991 		if (((objects & 48) == 0 || (prior & 12) == 0) && ((objects & 192) == 0 || (prior & 4) == 0)) {
5992 			if ((objects & 1) != 0) {
5993 				color = self->colors[0];
5994 				if ((objects & 2) != 0 && (prior & 32) != 0)
5995 					color |= self->colors[1];
5996 			}
5997 			else
5998 				color = self->colors[1];
5999 		}
6000 	}
6001 	else if ((objects & 12) != 0) {
6002 		if (((objects & 192) == 0 || (prior & 6) == 0) && ((objects & 48) == 0 || (prior & 1) != 0)) {
6003 			if ((objects & 4) != 0) {
6004 				color = self->colors[2];
6005 				if ((objects & 8) != 0 && (prior & 32) != 0)
6006 					color |= self->colors[3];
6007 			}
6008 			else
6009 				color = self->colors[3];
6010 		}
6011 	}
6012 	if ((objects & 192) != 0 && ((objects & 12) == 0 || (prior & 9) == 0) && ((objects & 3) == 0 || (prior & 4) != 0)) {
6013 		return color | self->colors[(objects & 128) != 0 ? 7 : 6];
6014 	}
6015 	if ((objects & 48) != 0 && ((objects & 12) == 0 || (prior & 1) == 0) && ((objects & 3) == 0 || (prior & 3) == 0)) {
6016 		return color | self->colors[(objects & 16) != 0 ? 4 : 5];
6017 	}
6018 	return color;
6019 }
6020 
GtiaRenderer_StartLine(GtiaRenderer * self,int startHpos)6021 static void GtiaRenderer_StartLine(GtiaRenderer *self, int startHpos)
6022 {
6023 	memset(self->playerShiftRegister, 0, sizeof(self->playerShiftRegister));
6024 	self->missileShiftRegister = 0;
6025 	for (int hpos = startHpos - 31; hpos < startHpos; hpos++)
6026 		GtiaRenderer_GetPmg(self, hpos, 0);
6027 }
6028 
GtiaRenderer_GetHiresColor(const GtiaRenderer * self,int c)6029 static int GtiaRenderer_GetHiresColor(const GtiaRenderer *self, int c)
6030 {
6031 	return (c & 240) + (self->colors[5] & 14);
6032 }
6033 
GtiaRenderer_DrawSpan(GtiaRenderer * self,int y,int hpos,int untilHpos,AnticMode anticMode,uint8_t * frame,int width)6034 static int GtiaRenderer_DrawSpan(GtiaRenderer *self, int y, int hpos, int untilHpos, AnticMode anticMode, uint8_t *frame, int width)
6035 {
6036 	int gtiaMode = self->prior >> 6;
6037 	for (; hpos < untilHpos; hpos++) {
6038 		int x = hpos;
6039 		int objects = 0;
6040 		int playfield = 0;
6041 		if (gtiaMode == 2) {
6042 			x--;
6043 			objects = 1;
6044 		}
6045 		if (anticMode != AnticMode_BLANK) {
6046 			int column = (x >> 2) + (self->playfieldColumns >> 1) - 32;
6047 			if (column >= 0 && column < self->playfieldColumns) {
6048 				playfield = self->vtbl->getPlayfieldByte(self, y, column);
6049 				bool inverseChar = playfield >= 256;
6050 				if (inverseChar && anticMode == AnticMode_HI_RES)
6051 					playfield = 511 - playfield;
6052 				if (gtiaMode == 0) {
6053 					playfield = playfield >> ((~x & 3) << 1) & 3;
6054 					objects = anticMode == AnticMode_HI_RES ? 64 : anticMode == AnticMode_FIVE_COLOR && playfield == 3 && inverseChar ? 128 : 8 << playfield & 112;
6055 				}
6056 				else {
6057 					if ((x & 2) == 0)
6058 						playfield >>= 4;
6059 					playfield &= 15;
6060 					if (gtiaMode == 2) {
6061 						static const uint8_t GTIA10_OBJECTS[16] = { 1, 2, 4, 8, 16, 32, 64, 128, 0, 0, 0, 0, 16, 32, 64, 128 };
6062 						objects = GTIA10_OBJECTS[playfield];
6063 					}
6064 				}
6065 			}
6066 		}
6067 		objects = GtiaRenderer_GetPmg(self, hpos, objects);
6068 		int c = GtiaRenderer_GetColor(self, objects);
6069 		int frameOffset = y * width + ((hpos + (width >> 2) - 128) << 1);
6070 		switch (gtiaMode) {
6071 		case 0:
6072 			if (anticMode != AnticMode_HI_RES)
6073 				break;
6074 			frame[frameOffset] = (uint8_t) ((playfield & 2) == 0 ? c : self->vtbl->getHiresColor(self, c));
6075 			frame[frameOffset + 1] = (uint8_t) ((playfield & 1) == 0 ? c : self->vtbl->getHiresColor(self, c));
6076 			continue;
6077 		case 2:
6078 			break;
6079 		default:
6080 			if ((objects & 15) != 0)
6081 				break;
6082 			assert(objects == 0 || objects == 128);
6083 			if (gtiaMode == 1)
6084 				c |= playfield;
6085 			else if (playfield == 0)
6086 				c &= 240;
6087 			else
6088 				c |= playfield << 4;
6089 			break;
6090 		}
6091 		frame[frameOffset + 1] = frame[frameOffset] = (uint8_t) c;
6092 	}
6093 	return hpos;
6094 }
6095 
GtiaRenderer_SetG2fColors(GtiaRenderer * self,int contentOffset,int contentStride,int count,int gtiaMode)6096 static void GtiaRenderer_SetG2fColors(GtiaRenderer *self, int contentOffset, int contentStride, int count, int gtiaMode)
6097 {
6098 	static const uint8_t NORMAL_REGISTERS[9] = { 8, 4, 5, 6, 7, 0, 1, 2, 3 };
6099 	for (int i = 0; i < count; i++)
6100 		self->colors[(gtiaMode & 192) == 128 ? i : NORMAL_REGISTERS[i]] = (uint8_t) (self->content[contentOffset + i * contentStride] & 254);
6101 }
6102 
HcmRenderer_Construct(HcmRenderer * self)6103 static void HcmRenderer_Construct(HcmRenderer *self)
6104 {
6105 	static const GtiaRendererVtbl vtbl = {
6106 		GtiaRenderer_GetHiresColor,
6107 		(int (*)(GtiaRenderer *self, int y, int column)) HcmRenderer_GetPlayfieldByte,
6108 	};
6109 	self->base.vtbl = &vtbl;
6110 }
6111 
HcmRenderer_GetPlayfieldByte(HcmRenderer * self,int y,int column)6112 static int HcmRenderer_GetPlayfieldByte(HcmRenderer *self, int y, int column)
6113 {
6114 	return self->base.content[2064 + (y << 5) + column];
6115 }
6116 
GedRenderer_Construct(GedRenderer * self)6117 static void GedRenderer_Construct(GedRenderer *self)
6118 {
6119 	static const GtiaRendererVtbl vtbl = {
6120 		GtiaRenderer_GetHiresColor,
6121 		(int (*)(GtiaRenderer *self, int y, int column)) GedRenderer_GetPlayfieldByte,
6122 	};
6123 	self->base.vtbl = &vtbl;
6124 }
6125 
GedRenderer_GetPlayfieldByte(GedRenderer * self,int y,int column)6126 static int GedRenderer_GetPlayfieldByte(GedRenderer *self, int y, int column)
6127 {
6128 	return self->base.content[3302 + y * 40 + column];
6129 }
6130 
PgrRenderer_Construct(PgrRenderer * self)6131 static void PgrRenderer_Construct(PgrRenderer *self)
6132 {
6133 	static const GtiaRendererVtbl vtbl = {
6134 		GtiaRenderer_GetHiresColor,
6135 		(int (*)(GtiaRenderer *self, int y, int column)) PgrRenderer_GetPlayfieldByte,
6136 	};
6137 	self->base.vtbl = &vtbl;
6138 }
6139 
PgrRenderer_GetPlayfieldByte(PgrRenderer * self,int y,int column)6140 static int PgrRenderer_GetPlayfieldByte(PgrRenderer *self, int y, int column)
6141 {
6142 	return self->base.content[self->screenOffset + column];
6143 }
6144 
MchRenderer_Construct(MchRenderer * self)6145 static void MchRenderer_Construct(MchRenderer *self)
6146 {
6147 	static const GtiaRendererVtbl vtbl = {
6148 		GtiaRenderer_GetHiresColor,
6149 		(int (*)(GtiaRenderer *self, int y, int column)) MchRenderer_GetPlayfieldByte,
6150 	};
6151 	self->base.vtbl = &vtbl;
6152 }
6153 
MchRenderer_GetPlayfieldByte(MchRenderer * self,int y,int column)6154 static int MchRenderer_GetPlayfieldByte(MchRenderer *self, int y, int column)
6155 {
6156 	int offset = ((y >> 3) * self->base.playfieldColumns + column) * 9;
6157 	int shift = self->dliPlus && (y & 4) != 0 ? 2 : 1;
6158 	return (self->base.content[offset] << shift & 256) | self->base.content[offset + 1 + (y & 7)];
6159 }
6160 
G2fRenderer_Construct(G2fRenderer * self)6161 static void G2fRenderer_Construct(G2fRenderer *self)
6162 {
6163 	static const GtiaRendererVtbl vtbl = {
6164 		(int (*)(const GtiaRenderer *self, int c)) G2fRenderer_GetHiresColor,
6165 		(int (*)(GtiaRenderer *self, int y, int column)) G2fRenderer_GetPlayfieldByte,
6166 	};
6167 	self->base.vtbl = &vtbl;
6168 }
6169 
G2fRenderer_GetHiresColor(const G2fRenderer * self,int c)6170 static int G2fRenderer_GetHiresColor(const G2fRenderer *self, int c)
6171 {
6172 	return self->vbxeOffset >= 0 ? self->base.colors[5] : (c & 240) + (self->base.colors[5] & 14);
6173 }
6174 
G2fRenderer_GetPlayfieldByte(G2fRenderer * self,int y,int column)6175 static int G2fRenderer_GetPlayfieldByte(G2fRenderer *self, int y, int column)
6176 {
6177 	if (self->vbxeOffset >= 0) {
6178 		int colorOffset = self->vbxeOffset + 3 + ((24 - (self->base.playfieldColumns >> 1) + column) * 240 + y / self->base.content[self->vbxeOffset + 2]) * 12 + 2;
6179 		self->base.colors[4] = self->base.content[colorOffset];
6180 		self->base.colors[5] = self->base.content[colorOffset + 2];
6181 		self->base.colors[6] = self->base.content[colorOffset + 4];
6182 	}
6183 	int charOffset = (y >> 3) * self->base.playfieldColumns + column;
6184 	int ch = self->base.content[3 + charOffset];
6185 	int inverse = self->inverse2Offset >= 0 && (y & 4) != 0 ? self->base.content[self->inverse2Offset + charOffset] : ch;
6186 	return (inverse & 128) << 1 | self->base.content[self->fontOffset + ((ch & 127) << 3) + (y & 7)];
6187 }
6188 
G2fRenderer_SetSprite(uint8_t * hpos,uint8_t * sizes,int i,uint8_t const * content,int spriteOffset)6189 static bool G2fRenderer_SetSprite(uint8_t *hpos, uint8_t *sizes, int i, uint8_t const *content, int spriteOffset)
6190 {
6191 	spriteOffset += i << 10;
6192 	int value = content[spriteOffset + 1];
6193 	if (value >= 128) {
6194 		hpos[i] = 0;
6195 		return true;
6196 	}
6197 	value &= 15;
6198 	switch (value) {
6199 	case 0:
6200 		value = 1;
6201 		break;
6202 	case 1:
6203 	case 2:
6204 	case 4:
6205 		break;
6206 	default:
6207 		return false;
6208 	}
6209 	sizes[i] = (uint8_t) value;
6210 	hpos[i] = (uint8_t) (32 + content[spriteOffset]);
6211 	return true;
6212 }
6213 
InflateStream_ReadBit(InflateStream * self)6214 static int InflateStream_ReadBit(InflateStream *self)
6215 {
6216 	if (self->bits <= 1) {
6217 		if (self->base.contentOffset >= self->base.contentLength)
6218 			return -1;
6219 		self->bits = self->base.content[self->base.contentOffset++] | 256;
6220 	}
6221 	int result = self->bits & 1;
6222 	self->bits >>= 1;
6223 	return result;
6224 }
6225 
InflateStream_ReadBits(InflateStream * self,int count)6226 static int InflateStream_ReadBits(InflateStream *self, int count)
6227 {
6228 	int result = 0;
6229 	for (int rank = 0; rank < count; rank++) {
6230 		switch (InflateStream_ReadBit(self)) {
6231 		case -1:
6232 			return -1;
6233 		case 1:
6234 			result |= 1 << rank;
6235 			break;
6236 		default:
6237 			break;
6238 		}
6239 	}
6240 	return result;
6241 }
6242 
InflateStream_BuildHuffmanTrees(InflateStream * self)6243 static void InflateStream_BuildHuffmanTrees(InflateStream *self)
6244 {
6245 	memset(self->nBitCodeCount, 0, sizeof(self->nBitCodeCount));
6246 	for (int i = 0; i < 318; i++)
6247 		self->nBitCodeCount[self->symbolCodeLength[i]]++;
6248 	int offset = 0;
6249 	for (int i = 0; i < 32; i++) {
6250 		self->nBitCodeOffset[i] = offset;
6251 		offset += self->nBitCodeCount[i];
6252 	}
6253 	for (int i = 0; i < 318; i++)
6254 		self->codeToSymbol[self->nBitCodeOffset[self->symbolCodeLength[i]]++] = (int16_t) i;
6255 }
6256 
InflateStream_FetchCode(InflateStream * self,int tree)6257 static int InflateStream_FetchCode(InflateStream *self, int tree)
6258 {
6259 	int code = 0;
6260 	do {
6261 		int bit = InflateStream_ReadBit(self);
6262 		if (bit < 0)
6263 			return -1;
6264 		code = (code << 1) + bit - self->nBitCodeCount[++tree];
6265 		if (code < 0)
6266 			return self->codeToSymbol[self->nBitCodeOffset[tree] + code];
6267 	}
6268 	while ((tree & 15) != 15);
6269 	return -1;
6270 }
6271 
InflateStream_Inflate(InflateStream * self,uint8_t * unpacked,int unpackedLength)6272 static int InflateStream_Inflate(InflateStream *self, uint8_t *unpacked, int unpackedLength)
6273 {
6274 	int unpackedOffset = 0;
6275 	self->bits = 0;
6276 	int lastBlock;
6277 	do {
6278 		lastBlock = InflateStream_ReadBit(self);
6279 		int count;
6280 		switch (InflateStream_ReadBits(self, 2)) {
6281 		case 0:
6282 			self->bits = 0;
6283 			count = InflateStream_ReadBits(self, 16);
6284 			if (InflateStream_ReadBits(self, 16) != (count ^ 65535))
6285 				return -1;
6286 			if (count > unpackedLength - unpackedOffset)
6287 				count = unpackedLength - unpackedOffset;
6288 			if (!Stream_ReadBytes(&self->base, unpacked, unpackedOffset, count))
6289 				return -1;
6290 			unpackedOffset += count;
6291 			if (unpackedOffset == unpackedLength)
6292 				return unpackedOffset;
6293 			continue;
6294 		case 1:
6295 			for (int i = 0; i < 144; i++)
6296 				self->symbolCodeLength[i] = 8;
6297 			for (int i = 144; i < 256; i++)
6298 				self->symbolCodeLength[i] = 9;
6299 			for (int i = 256; i < 280; i++)
6300 				self->symbolCodeLength[i] = 7;
6301 			for (int i = 280; i < 288; i++)
6302 				self->symbolCodeLength[i] = 8;
6303 			for (int i = 288; i < 318; i++)
6304 				self->symbolCodeLength[i] = 21;
6305 			break;
6306 		case 2:
6307 			;
6308 			int primaryCodes = 257 + InflateStream_ReadBits(self, 5);
6309 			int codes = 289 + InflateStream_ReadBits(self, 5);
6310 			if (codes > 318)
6311 				return -1;
6312 			int temporaryCodes = InflateStream_ReadBits(self, 4);
6313 			if (temporaryCodes < 0)
6314 				return -1;
6315 			temporaryCodes += 4;
6316 			memset(self->symbolCodeLength, 0, sizeof(self->symbolCodeLength));
6317 			for (int i = 0; i < temporaryCodes; i++) {
6318 				int bits = InflateStream_ReadBits(self, 3);
6319 				if (bits < 0)
6320 					return -1;
6321 				static const uint8_t TEMP_SYMBOLS[19] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2,
6322 					14, 1, 15 };
6323 				self->symbolCodeLength[TEMP_SYMBOLS[i]] = (uint8_t) bits;
6324 			}
6325 			InflateStream_BuildHuffmanTrees(self);
6326 			int length = 0;
6327 			count = 1;
6328 			for (int i = 0; i < codes; i++) {
6329 				if (--count == 0) {
6330 					int symbol = InflateStream_FetchCode(self, 0);
6331 					switch (symbol) {
6332 					case -1:
6333 						return -1;
6334 					case 16:
6335 						count = InflateStream_ReadBits(self, 2);
6336 						if (count < 0)
6337 							return -1;
6338 						count += 3;
6339 						break;
6340 					case 17:
6341 						length = 0;
6342 						count = InflateStream_ReadBits(self, 3);
6343 						if (count < 0)
6344 							return -1;
6345 						count += 3;
6346 						break;
6347 					case 18:
6348 						length = 0;
6349 						count = InflateStream_ReadBits(self, 7);
6350 						if (count < 0)
6351 							return -1;
6352 						count += 11;
6353 						break;
6354 					default:
6355 						length = symbol;
6356 						count = 1;
6357 						break;
6358 					}
6359 				}
6360 				if (i == primaryCodes)
6361 					i = 288;
6362 				self->symbolCodeLength[i] = (uint8_t) (i < 288 ? length : 16 + length);
6363 			}
6364 			break;
6365 		default:
6366 			return -1;
6367 		}
6368 		InflateStream_BuildHuffmanTrees(self);
6369 		for (;;) {
6370 			int symbol = InflateStream_FetchCode(self, 0);
6371 			if (symbol < 0)
6372 				return -1;
6373 			else if (symbol < 256)
6374 				unpacked[unpackedOffset++] = (uint8_t) symbol;
6375 			else if (symbol == 256)
6376 				break;
6377 			else {
6378 				switch (symbol) {
6379 				case 257:
6380 				case 258:
6381 				case 259:
6382 				case 260:
6383 				case 261:
6384 				case 262:
6385 				case 263:
6386 				case 264:
6387 					count = symbol - 254;
6388 					break;
6389 				case 285:
6390 					count = 258;
6391 					break;
6392 				case 286:
6393 				case 287:
6394 					return -1;
6395 				default:
6396 					symbol -= 261;
6397 					count = InflateStream_ReadBits(self, symbol >> 2);
6398 					if (count < 0)
6399 						return -1;
6400 					count += ((4 + (symbol & 3)) << (symbol >> 2)) + 3;
6401 					break;
6402 				}
6403 				symbol = InflateStream_FetchCode(self, 16);
6404 				int distance;
6405 				switch (symbol) {
6406 				case -1:
6407 					return -1;
6408 				case 288:
6409 				case 289:
6410 				case 290:
6411 				case 291:
6412 					distance = symbol - 287;
6413 					break;
6414 				default:
6415 					symbol -= 290;
6416 					distance = InflateStream_ReadBits(self, symbol >> 1);
6417 					if (distance < 0)
6418 						return -1;
6419 					distance += ((2 + (symbol & 1)) << (symbol >> 1)) + 1;
6420 					break;
6421 				}
6422 				if (count > unpackedLength - unpackedOffset)
6423 					count = unpackedLength - unpackedOffset;
6424 				if (!RECOIL_CopyPrevious(unpacked, unpackedOffset, distance, count))
6425 					return -1;
6426 				unpackedOffset += count;
6427 			}
6428 			if (unpackedOffset == unpackedLength)
6429 				return unpackedOffset;
6430 		}
6431 	}
6432 	while (lastBlock == 0);
6433 	return unpackedOffset;
6434 }
6435 
InflateStream_Uncompress(InflateStream * self,uint8_t * unpacked,int unpackedLength)6436 static int InflateStream_Uncompress(InflateStream *self, uint8_t *unpacked, int unpackedLength)
6437 {
6438 	int b0 = Stream_ReadByte(&self->base);
6439 	if ((b0 & 143) != 8)
6440 		return -1;
6441 	int b1 = Stream_ReadByte(&self->base);
6442 	if ((b1 & 32) != 0 || (b0 << 8 | b1) % 31 != 0)
6443 		return -1;
6444 	return InflateStream_Inflate(self, unpacked, unpackedLength);
6445 }
6446 
RECOIL_Construct(RECOIL * self)6447 static void RECOIL_Construct(RECOIL *self)
6448 {
6449 	static const RECOILVtbl vtbl = {
6450 		RECOIL_ReadFile,
6451 	};
6452 	self->vtbl = &vtbl;
6453 	RECOIL_SetAtari8Palette(self, NULL);
6454 }
6455 
RECOIL_New(void)6456 RECOIL *RECOIL_New(void)
6457 {
6458 	RECOIL *self = (RECOIL *) malloc(sizeof(RECOIL));
6459 	if (self != NULL)
6460 		RECOIL_Construct(self);
6461 	return self;
6462 }
6463 
RECOIL_Delete(RECOIL * self)6464 void RECOIL_Delete(RECOIL *self)
6465 {
6466 	free(self);
6467 }
6468 
RECOIL_GetWidth(const RECOIL * self)6469 int RECOIL_GetWidth(const RECOIL *self)
6470 {
6471 	return self->width;
6472 }
6473 
RECOIL_GetHeight(const RECOIL * self)6474 int RECOIL_GetHeight(const RECOIL *self)
6475 {
6476 	return self->height;
6477 }
6478 
RECOIL_GetPixels(const RECOIL * self)6479 int const *RECOIL_GetPixels(const RECOIL *self)
6480 {
6481 	return self->pixels;
6482 }
6483 
RECOIL_GetPlatform(const RECOIL * self)6484 const char *RECOIL_GetPlatform(const RECOIL *self)
6485 {
6486 	switch (self->resolution) {
6487 	case RECOILResolution_AMIGA1X1:
6488 	case RECOILResolution_AMIGA2X1:
6489 	case RECOILResolution_AMIGA4X1:
6490 	case RECOILResolution_AMIGA8X1:
6491 	case RECOILResolution_AMIGA1X2:
6492 	case RECOILResolution_AMIGA1X4:
6493 		return "Amiga";
6494 	case RECOILResolution_AMSTRAD1X1:
6495 	case RECOILResolution_AMSTRAD2X1:
6496 	case RECOILResolution_AMSTRAD1X2:
6497 		return "Amstrad CPC";
6498 	case RECOILResolution_APPLE_I_I1X1:
6499 		return "Apple II";
6500 	case RECOILResolution_APPLE_I_IE1X2:
6501 		return "Apple IIe";
6502 	case RECOILResolution_APPLE_I_I_G_S1X1:
6503 	case RECOILResolution_APPLE_I_I_G_S1X2:
6504 		return "Apple IIGS";
6505 	case RECOILResolution_MACINTOSH1X1:
6506 		return "Apple Macintosh";
6507 	case RECOILResolution_XE1X1:
6508 	case RECOILResolution_XE2X1:
6509 	case RECOILResolution_XE4X1:
6510 	case RECOILResolution_XE2X2:
6511 	case RECOILResolution_XE4X2:
6512 	case RECOILResolution_XE4X4:
6513 	case RECOILResolution_XE8X8:
6514 		return "Atari 8-bit";
6515 	case RECOILResolution_PORTFOLIO1X1:
6516 		return "Atari Portfolio";
6517 	case RECOILResolution_ST1X1:
6518 	case RECOILResolution_ST1X2:
6519 		return "Atari ST";
6520 	case RECOILResolution_STE1X1:
6521 	case RECOILResolution_STE1X2:
6522 		return "Atari STE";
6523 	case RECOILResolution_TT1X1:
6524 	case RECOILResolution_TT2X1:
6525 		return "Atari TT";
6526 	case RECOILResolution_FALCON1X1:
6527 	case RECOILResolution_FALCON2X1:
6528 		return "Atari Falcon";
6529 	case RECOILResolution_BBC1X1:
6530 	case RECOILResolution_BBC2X1:
6531 	case RECOILResolution_BBC1X2:
6532 		return "BBC Micro";
6533 	case RECOILResolution_VIC202X1:
6534 		return "Commodore VIC-20";
6535 	case RECOILResolution_C161X1:
6536 	case RECOILResolution_C162X1:
6537 		return "Commodore 16";
6538 	case RECOILResolution_C641X1:
6539 	case RECOILResolution_C642X1:
6540 		return "Commodore 64";
6541 	case RECOILResolution_C1281X1:
6542 		return "Commodore 128";
6543 	case RECOILResolution_ELECTRONIKA1X1:
6544 		return "Electronika BK";
6545 	case RECOILResolution_FM_TOWNS1X1:
6546 		return "FM Towns";
6547 	case RECOILResolution_MSX11X1:
6548 	case RECOILResolution_MSX14X4:
6549 		return "MSX";
6550 	case RECOILResolution_MSX21X1:
6551 	case RECOILResolution_MSX22X1:
6552 	case RECOILResolution_MSX21X2:
6553 		return "MSX2";
6554 	case RECOILResolution_MSX2_PLUS1X1:
6555 	case RECOILResolution_MSX2_PLUS2X1:
6556 		return "MSX2+";
6557 	case RECOILResolution_ORIC1X1:
6558 		return "Oric";
6559 	case RECOILResolution_PC1X1:
6560 		return "PC";
6561 	case RECOILResolution_PC801X2:
6562 		return "NEC PC-80";
6563 	case RECOILResolution_PC881X2:
6564 		return "NEC PC-88";
6565 	case RECOILResolution_PC88_VA1X1:
6566 		return "NEC PC-88 VA";
6567 	case RECOILResolution_PC981X1:
6568 		return "NEC PC-98";
6569 	case RECOILResolution_PLAY_STATION1X1:
6570 		return "PlayStation";
6571 	case RECOILResolution_PSION31X1:
6572 		return "Psion Series 3";
6573 	case RECOILResolution_SAM_COUPE1X1:
6574 		return "SAM Coupe";
6575 	case RECOILResolution_X68_K1X1:
6576 		return "Sharp X68000";
6577 	case RECOILResolution_SPECTRUM1X1:
6578 	case RECOILResolution_SPECTRUM4X4:
6579 		return "ZX Spectrum";
6580 	case RECOILResolution_TIMEX1X1:
6581 	case RECOILResolution_TIMEX1X2:
6582 		return "Timex 2048";
6583 	case RECOILResolution_TRS1X1:
6584 	case RECOILResolution_TRS1X2:
6585 		return "TRS-80";
6586 	case RECOILResolution_COCO1X1:
6587 	case RECOILResolution_COCO2X2:
6588 		return "TRS-80 Color Computer";
6589 	case RECOILResolution_ZX811X1:
6590 		return "ZX81";
6591 	default:
6592 		return "Unknown";
6593 	}
6594 }
6595 
RECOIL_GetOriginalWidth(const RECOIL * self)6596 int RECOIL_GetOriginalWidth(const RECOIL *self)
6597 {
6598 	switch (self->resolution) {
6599 	case RECOILResolution_AMIGA2X1:
6600 	case RECOILResolution_AMSTRAD2X1:
6601 	case RECOILResolution_XE2X1:
6602 	case RECOILResolution_XE2X2:
6603 	case RECOILResolution_TT2X1:
6604 	case RECOILResolution_FALCON2X1:
6605 	case RECOILResolution_BBC2X1:
6606 	case RECOILResolution_VIC202X1:
6607 	case RECOILResolution_C162X1:
6608 	case RECOILResolution_C642X1:
6609 	case RECOILResolution_COCO2X2:
6610 	case RECOILResolution_MSX22X1:
6611 	case RECOILResolution_MSX2_PLUS2X1:
6612 		return self->width >> 1;
6613 	case RECOILResolution_AMIGA4X1:
6614 	case RECOILResolution_MSX14X4:
6615 	case RECOILResolution_SPECTRUM4X4:
6616 	case RECOILResolution_XE4X1:
6617 	case RECOILResolution_XE4X2:
6618 	case RECOILResolution_XE4X4:
6619 		return self->width >> 2;
6620 	case RECOILResolution_AMIGA8X1:
6621 	case RECOILResolution_XE8X8:
6622 		return self->width >> 3;
6623 	default:
6624 		return self->width;
6625 	}
6626 }
6627 
RECOIL_GetOriginalHeight(const RECOIL * self)6628 int RECOIL_GetOriginalHeight(const RECOIL *self)
6629 {
6630 	switch (self->resolution) {
6631 	case RECOILResolution_AMIGA1X2:
6632 	case RECOILResolution_AMSTRAD1X2:
6633 	case RECOILResolution_APPLE_I_IE1X2:
6634 	case RECOILResolution_APPLE_I_I_G_S1X2:
6635 	case RECOILResolution_XE2X2:
6636 	case RECOILResolution_XE4X2:
6637 	case RECOILResolution_ST1X2:
6638 	case RECOILResolution_STE1X2:
6639 	case RECOILResolution_BBC1X2:
6640 	case RECOILResolution_MSX21X2:
6641 	case RECOILResolution_PC801X2:
6642 	case RECOILResolution_PC881X2:
6643 	case RECOILResolution_TIMEX1X2:
6644 	case RECOILResolution_TRS1X2:
6645 	case RECOILResolution_COCO2X2:
6646 		return self->height >> 1;
6647 	case RECOILResolution_AMIGA1X4:
6648 	case RECOILResolution_MSX14X4:
6649 	case RECOILResolution_SPECTRUM4X4:
6650 	case RECOILResolution_XE4X4:
6651 		return self->height >> 2;
6652 	case RECOILResolution_XE8X8:
6653 		return self->height >> 3;
6654 	default:
6655 		return self->height;
6656 	}
6657 }
6658 
RECOIL_GetFrames(const RECOIL * self)6659 int RECOIL_GetFrames(const RECOIL *self)
6660 {
6661 	return self->frames;
6662 }
6663 
RECOIL_SetSize(RECOIL * self,int width,int height,RECOILResolution resolution)6664 static bool RECOIL_SetSize(RECOIL *self, int width, int height, RECOILResolution resolution)
6665 {
6666 	if (width <= 0 || width > 10000 || height <= 0 || height > 2560 || width * height > 2854278)
6667 		return false;
6668 	self->width = width;
6669 	self->height = height;
6670 	self->resolution = resolution;
6671 	self->frames = 1;
6672 	self->colors = -1;
6673 	self->leftSkip = 0;
6674 	return true;
6675 }
6676 
RECOIL_SetSizeStOrFalcon(RECOIL * self,int width,int height,int bitplanes,bool squarePixels)6677 static bool RECOIL_SetSizeStOrFalcon(RECOIL *self, int width, int height, int bitplanes, bool squarePixels)
6678 {
6679 	RECOILResolution resolution = RECOILResolution_FALCON1X1;
6680 	switch (bitplanes) {
6681 	case 1:
6682 		if (width <= 640 && height <= 400)
6683 			resolution = RECOILResolution_ST1X1;
6684 		break;
6685 	case 2:
6686 		if (!squarePixels && width == 640 && height == 200) {
6687 			height <<= 1;
6688 			resolution = RECOILResolution_STE1X2;
6689 		}
6690 		break;
6691 	case 4:
6692 		if (width <= 320 && height <= 200)
6693 			resolution = RECOILResolution_STE1X1;
6694 		break;
6695 	case 8:
6696 		if (!squarePixels && width == 320 && height == 480) {
6697 			width <<= 1;
6698 			resolution = RECOILResolution_TT2X1;
6699 		}
6700 		break;
6701 	default:
6702 		break;
6703 	}
6704 	return RECOIL_SetSize(self, width, height, resolution);
6705 }
6706 
RECOIL_SetScaledSize(RECOIL * self,int width,int height,RECOILResolution resolution)6707 static bool RECOIL_SetScaledSize(RECOIL *self, int width, int height, RECOILResolution resolution)
6708 {
6709 	switch (resolution) {
6710 	case RECOILResolution_AMIGA2X1:
6711 	case RECOILResolution_FALCON2X1:
6712 	case RECOILResolution_MSX22X1:
6713 	case RECOILResolution_MSX2_PLUS2X1:
6714 		width <<= 1;
6715 		break;
6716 	case RECOILResolution_AMIGA4X1:
6717 		width <<= 2;
6718 		break;
6719 	case RECOILResolution_AMIGA8X1:
6720 		width <<= 3;
6721 		break;
6722 	case RECOILResolution_AMIGA1X2:
6723 	case RECOILResolution_ST1X2:
6724 	case RECOILResolution_STE1X2:
6725 	case RECOILResolution_MSX21X2:
6726 	case RECOILResolution_PC801X2:
6727 	case RECOILResolution_PC881X2:
6728 		height <<= 1;
6729 		break;
6730 	case RECOILResolution_AMIGA1X4:
6731 		height <<= 2;
6732 		break;
6733 	default:
6734 		break;
6735 	}
6736 	return RECOIL_SetSize(self, width, height, resolution);
6737 }
6738 
RECOIL_SetScaledPixel(RECOIL * self,int x,int y,int rgb)6739 static void RECOIL_SetScaledPixel(RECOIL *self, int x, int y, int rgb)
6740 {
6741 	int offset = y * self->width;
6742 	switch (self->resolution) {
6743 	case RECOILResolution_AMIGA2X1:
6744 	case RECOILResolution_TT2X1:
6745 	case RECOILResolution_FALCON2X1:
6746 	case RECOILResolution_MSX22X1:
6747 	case RECOILResolution_MSX2_PLUS2X1:
6748 		offset += x << 1;
6749 		self->pixels[offset + 1] = self->pixels[offset] = rgb;
6750 		break;
6751 	case RECOILResolution_AMIGA4X1:
6752 		offset += x << 2;
6753 		self->pixels[offset + 3] = self->pixels[offset + 2] = self->pixels[offset + 1] = self->pixels[offset] = rgb;
6754 		break;
6755 	case RECOILResolution_AMIGA8X1:
6756 		offset += x << 3;
6757 		for (x = 0; x < 8; x++)
6758 			self->pixels[offset + x] = rgb;
6759 		break;
6760 	case RECOILResolution_AMIGA1X2:
6761 	case RECOILResolution_APPLE_I_I_G_S1X2:
6762 	case RECOILResolution_ST1X2:
6763 	case RECOILResolution_STE1X2:
6764 	case RECOILResolution_PC801X2:
6765 	case RECOILResolution_PC881X2:
6766 	case RECOILResolution_MSX21X2:
6767 	case RECOILResolution_TRS1X2:
6768 		offset = (offset << 1) + x;
6769 		self->pixels[offset + self->width] = self->pixels[offset] = rgb;
6770 		break;
6771 	case RECOILResolution_AMIGA1X4:
6772 		offset = (offset << 2) + x;
6773 		self->pixels[offset + self->width * 3] = self->pixels[offset + self->width * 2] = self->pixels[offset + self->width] = self->pixels[offset] = rgb;
6774 		break;
6775 	default:
6776 		self->pixels[offset + x] = rgb;
6777 		break;
6778 	}
6779 }
6780 
RECOIL_Get32BigEndian(uint8_t const * content,int contentOffset)6781 static int RECOIL_Get32BigEndian(uint8_t const *content, int contentOffset)
6782 {
6783 	return content[contentOffset] << 24 | content[contentOffset + 1] << 16 | content[contentOffset + 2] << 8 | content[contentOffset + 3];
6784 }
6785 
RECOIL_Get32LittleEndian(uint8_t const * content,int contentOffset)6786 static int RECOIL_Get32LittleEndian(uint8_t const *content, int contentOffset)
6787 {
6788 	return content[contentOffset] | content[contentOffset + 1] << 8 | content[contentOffset + 2] << 16 | content[contentOffset + 3] << 24;
6789 }
6790 
RECOIL_GetNibble(uint8_t const * content,int contentOffset,int index)6791 static int RECOIL_GetNibble(uint8_t const *content, int contentOffset, int index)
6792 {
6793 	int b = content[contentOffset + (index >> 1)];
6794 	return (index & 1) == 0 ? b >> 4 : b & 15;
6795 }
6796 
RECOIL_IsStringAt(uint8_t const * content,int contentOffset,const char * s)6797 static bool RECOIL_IsStringAt(uint8_t const *content, int contentOffset, const char *s)
6798 {
6799 	int length = (int) strlen(s);
6800 	for (int i = 0; i < length; i++)
6801 		if (content[contentOffset + i] != s[i])
6802 			return false;
6803 	return true;
6804 }
6805 
RECOIL_CopyPrevious(uint8_t * unpacked,int unpackedOffset,int distance,int count)6806 static bool RECOIL_CopyPrevious(uint8_t *unpacked, int unpackedOffset, int distance, int count)
6807 {
6808 	if (distance > unpackedOffset)
6809 		return false;
6810 	do {
6811 		unpacked[unpackedOffset] = unpacked[unpackedOffset - distance];
6812 		unpackedOffset++;
6813 	}
6814 	while (--count > 0);
6815 	return true;
6816 }
6817 
RECOIL_ApplyBlend(RECOIL * self)6818 static bool RECOIL_ApplyBlend(RECOIL *self)
6819 {
6820 	int pixelsLength = self->width * self->height;
6821 	self->frames = 2;
6822 	for (int i = 0; i < pixelsLength; i++) {
6823 		int rgb1 = self->pixels[i];
6824 		int rgb2 = self->pixels[pixelsLength + i];
6825 		self->pixels[i] = (rgb1 & rgb2) + ((rgb1 ^ rgb2) >> 1 & 8355711);
6826 	}
6827 	return true;
6828 }
6829 
RECOIL_ReadFile(const RECOIL * self,const char * filename,uint8_t * content,int contentLength)6830 static int RECOIL_ReadFile(const RECOIL *self, const char *filename, uint8_t *content, int contentLength)
6831 {
6832 	return -1;
6833 }
6834 
RECOIL_ReadCompanionFile(const RECOIL * self,const char * baseFilename,const char * upperExt,const char * lowerExt,uint8_t * content,int contentLength)6835 static int RECOIL_ReadCompanionFile(const RECOIL *self, const char *baseFilename, const char *upperExt, const char *lowerExt, uint8_t *content, int contentLength)
6836 {
6837 	int i = (int) strlen(baseFilename);
6838 	bool lower = false;
6839 	for (;;) {
6840 		int c = baseFilename[--i];
6841 		if (c >= 97)
6842 			lower = true;
6843 		else if (c == 46)
6844 			break;
6845 	}
6846 	char *filename = CiString_Substring(baseFilename, i + 1);
6847 	CiString_Append(&filename, lower ? lowerExt : upperExt);
6848 	int returnValue = self->vtbl->readFile(self, filename, content, contentLength);
6849 	free(filename);
6850 	return returnValue;
6851 }
6852 
RECOIL_DecodeBru(RECOIL * self,uint8_t const * content,int contentLength)6853 static bool RECOIL_DecodeBru(RECOIL *self, uint8_t const *content, int contentLength)
6854 {
6855 	if (contentLength != 64)
6856 		return false;
6857 	RECOIL_SetSize(self, 8, 8, RECOILResolution_ST1X1);
6858 	for (int i = 0; i < 64; i++) {
6859 		switch (content[i]) {
6860 		case 0:
6861 			self->pixels[i] = 0;
6862 			break;
6863 		case 1:
6864 			self->pixels[i] = 16777215;
6865 			break;
6866 		default:
6867 			return false;
6868 		}
6869 	}
6870 	return true;
6871 }
6872 
RECOIL_DecodeBytes(RECOIL * self,uint8_t const * content,int contentOffset)6873 static void RECOIL_DecodeBytes(RECOIL *self, uint8_t const *content, int contentOffset)
6874 {
6875 	int width = RECOIL_GetOriginalWidth(self);
6876 	int height = RECOIL_GetOriginalHeight(self);
6877 	for (int y = 0; y < height; y++)
6878 		for (int x = 0; x < width; x++)
6879 			RECOIL_SetScaledPixel(self, x, y, self->contentPalette[content[contentOffset + y * width + x]]);
6880 }
6881 
RECOIL_DecodeNibbles(RECOIL * self,uint8_t const * content,int contentOffset,int contentStride)6882 static void RECOIL_DecodeNibbles(RECOIL *self, uint8_t const *content, int contentOffset, int contentStride)
6883 {
6884 	int width = RECOIL_GetOriginalWidth(self);
6885 	int height = RECOIL_GetOriginalHeight(self);
6886 	for (int y = 0; y < height; y++)
6887 		for (int x = 0; x < width; x++)
6888 			RECOIL_SetScaledPixel(self, x, y, self->contentPalette[RECOIL_GetNibble(content, contentOffset + y * contentStride, x)]);
6889 }
6890 
RECOIL_GetB5G5R5Color(int c)6891 static int RECOIL_GetB5G5R5Color(int c)
6892 {
6893 	c = (c & 31) << 19 | (c & 992) << 6 | (c >> 7 & 248);
6894 	return c | (c >> 5 & 460551);
6895 }
6896 
RECOIL_GetR5G5B5Color(int c)6897 static int RECOIL_GetR5G5B5Color(int c)
6898 {
6899 	c = (c & 31744) << 9 | (c & 992) << 6 | (c & 31) << 3;
6900 	return c | (c >> 5 & 460551);
6901 }
6902 
RECOIL_GetG6R5B5Color(int c)6903 static int RECOIL_GetG6R5B5Color(int c)
6904 {
6905 	c = (c & 992) << 14 | (c & 64512) | (c & 31) << 3;
6906 	return c | (c >> 5 & 458759) | (c >> 6 & 768);
6907 }
6908 
RECOIL_Get729Color(int c)6909 static int RECOIL_Get729Color(int c)
6910 {
6911 	int r = c / 81;
6912 	int g = c / 9 % 9;
6913 	int b = c % 9;
6914 	return r * 255 >> 3 << 16 | g * 255 >> 3 << 8 | b * 255 >> 3;
6915 }
6916 
RECOIL_GetFalconTrueColor(uint8_t const * content,int contentOffset)6917 static int RECOIL_GetFalconTrueColor(uint8_t const *content, int contentOffset)
6918 {
6919 	int rg = content[contentOffset];
6920 	int gb = content[contentOffset + 1];
6921 	int rgb = (rg & 248) << 16 | (rg & 7) << 13 | (gb & 224) << 5 | (gb & 31) << 3;
6922 	rgb |= (rgb >> 5 & 458759) | (rgb >> 6 & 768);
6923 	return rgb;
6924 }
6925 
RECOIL_GetBitplanePixel(uint8_t const * content,int contentOffset,int x,int bitplanes,int bytesPerBitplane)6926 static int RECOIL_GetBitplanePixel(uint8_t const *content, int contentOffset, int x, int bitplanes, int bytesPerBitplane)
6927 {
6928 	int bit = ~x & 7;
6929 	int c = 0;
6930 	for (int bitplane = bitplanes; --bitplane >= 0;)
6931 		c = c << 1 | (content[contentOffset + bitplane * bytesPerBitplane] >> bit & 1);
6932 	return c;
6933 }
6934 
RECOIL_GetBitplaneWordsPixel(uint8_t const * content,int contentOffset,int x,int bitplanes)6935 static int RECOIL_GetBitplaneWordsPixel(uint8_t const *content, int contentOffset, int x, int bitplanes)
6936 {
6937 	return RECOIL_GetBitplanePixel(content, contentOffset + (x >> 3 & -2) * bitplanes + (x >> 3 & 1), x, bitplanes, 2);
6938 }
6939 
RECOIL_DecodeBitplanes(RECOIL * self,uint8_t const * content,int contentOffset,int contentStride,int bitplanes,int pixelsOffset,int width,int height)6940 static void RECOIL_DecodeBitplanes(RECOIL *self, uint8_t const *content, int contentOffset, int contentStride, int bitplanes, int pixelsOffset, int width, int height)
6941 {
6942 	while (--height >= 0) {
6943 		for (int x = 0; x < width; x++) {
6944 			int c = RECOIL_GetBitplaneWordsPixel(content, contentOffset, x, bitplanes);
6945 			self->pixels[pixelsOffset + x] = self->contentPalette[c];
6946 		}
6947 		contentOffset += contentStride;
6948 		pixelsOffset += self->width;
6949 	}
6950 }
6951 
RECOIL_DecodeScaledBitplanes(RECOIL * self,uint8_t const * content,int contentOffset,int width,int height,int bitplanes,bool ehb,MultiPalette * multiPalette)6952 static void RECOIL_DecodeScaledBitplanes(RECOIL *self, uint8_t const *content, int contentOffset, int width, int height, int bitplanes, bool ehb, MultiPalette *multiPalette)
6953 {
6954 	int contentStride = ((width + 15) >> 4 << 1) * bitplanes;
6955 	for (int y = 0; y < height; y++) {
6956 		if (multiPalette != NULL)
6957 			((const MultiPaletteVtbl *) multiPalette->base.vtbl)->setLinePalette(multiPalette, self, y);
6958 		if (ehb) {
6959 			for (int c = 0; c < 32; c++)
6960 				self->contentPalette[32 + c] = self->contentPalette[c] >> 1 & 8355711;
6961 		}
6962 		for (int x = 0; x < width; x++) {
6963 			int c = RECOIL_GetBitplaneWordsPixel(content, contentOffset, x, bitplanes);
6964 			RECOIL_SetScaledPixel(self, x, y, self->contentPalette[c]);
6965 		}
6966 		contentOffset += contentStride;
6967 	}
6968 }
6969 
RECOIL_DecodeMono(RECOIL * self,uint8_t const * content,int contentOffset,int contentLength,bool wordAlign)6970 static bool RECOIL_DecodeMono(RECOIL *self, uint8_t const *content, int contentOffset, int contentLength, bool wordAlign)
6971 {
6972 	int contentStride = (self->width + 7) >> 3;
6973 	if (wordAlign)
6974 		contentStride += contentStride & 1;
6975 	if (contentLength != contentOffset + contentStride * self->height)
6976 		return false;
6977 	RECOIL_DecodeBitplanes(self, content, contentOffset, contentStride, 1, 0, self->width, self->height);
6978 	return true;
6979 }
6980 
RECOIL_DecodeBlackAndWhite(RECOIL * self,uint8_t const * content,int contentOffset,int contentLength,bool wordAlign,int backgroundColor)6981 static bool RECOIL_DecodeBlackAndWhite(RECOIL *self, uint8_t const *content, int contentOffset, int contentLength, bool wordAlign, int backgroundColor)
6982 {
6983 	self->contentPalette[0] = backgroundColor;
6984 	self->contentPalette[1] = backgroundColor ^ 16777215;
6985 	return RECOIL_DecodeMono(self, content, contentOffset, contentLength, wordAlign);
6986 }
6987 
RECOIL_DecodeRleBlackAndWhite(RECOIL * self,RleStream * rle,int backgroundColor)6988 static bool RECOIL_DecodeRleBlackAndWhite(RECOIL *self, RleStream *rle, int backgroundColor)
6989 {
6990 	int width = RECOIL_GetOriginalWidth(self);
6991 	int height = RECOIL_GetOriginalHeight(self);
6992 	for (int y = 0; y < height; y++) {
6993 		int b = 0;
6994 		for (int x = 0; x < width; x++) {
6995 			if ((x & 7) == 0) {
6996 				b = RleStream_ReadRle(rle);
6997 				if (b < 0)
6998 					return false;
6999 			}
7000 			RECOIL_SetScaledPixel(self, x, y, (b >> (~x & 7) & 1) == 0 ? backgroundColor : backgroundColor ^ 16777215);
7001 		}
7002 	}
7003 	return true;
7004 }
7005 
RECOIL_DecodeBlackAndWhiteFont(RECOIL * self,uint8_t const * content,int contentOffset,int contentLength,int fontHeight)7006 static void RECOIL_DecodeBlackAndWhiteFont(RECOIL *self, uint8_t const *content, int contentOffset, int contentLength, int fontHeight)
7007 {
7008 	for (int y = 0; y < self->height; y++) {
7009 		for (int x = 0; x < 256; x++) {
7010 			int row = y % fontHeight;
7011 			int offset = contentOffset + ((y - row) << 5) + (x >> 3) * fontHeight + row;
7012 			int c;
7013 			if (offset < contentLength) {
7014 				c = content[offset] >> (~x & 7) & 1;
7015 				if (c != 0)
7016 					c = 16777215;
7017 			}
7018 			else
7019 				c = 0;
7020 			self->pixels[(y << 8) + x] = c;
7021 		}
7022 	}
7023 }
7024 
RECOIL_DecodePgf(RECOIL * self,uint8_t const * content,int contentLength)7025 static bool RECOIL_DecodePgf(RECOIL *self, uint8_t const *content, int contentLength)
7026 {
7027 	RECOIL_SetSize(self, 240, 64, RECOILResolution_PORTFOLIO1X1);
7028 	return RECOIL_DecodeBlackAndWhite(self, content, 0, contentLength, false, 16777215);
7029 }
7030 
RECOIL_DecodePgc(RECOIL * self,uint8_t const * content,int contentLength)7031 static bool RECOIL_DecodePgc(RECOIL *self, uint8_t const *content, int contentLength)
7032 {
7033 	if (contentLength < 33 || content[0] != 80 || content[1] != 71 || content[2] != 1)
7034 		return false;
7035 	RECOIL_SetSize(self, 240, 64, RECOILResolution_PORTFOLIO1X1);
7036 	PgcStream rle;
7037 	PgcStream_Construct(&rle);
7038 	rle.base.base.base.content = content;
7039 	rle.base.base.base.contentOffset = 3;
7040 	rle.base.base.base.contentLength = contentLength;
7041 	return RECOIL_DecodeRleBlackAndWhite(self, &rle.base, 16777215);
7042 }
7043 
RECOIL_DecodePsion3Pic(RECOIL * self,uint8_t const * content,int contentLength)7044 static bool RECOIL_DecodePsion3Pic(RECOIL *self, uint8_t const *content, int contentLength)
7045 {
7046 	if (contentLength < 22 || content[0] != 80 || content[1] != 73 || content[2] != 67 || content[3] != 220 || content[4] != 48 || content[5] != 48 || (content[6] == 0 && content[7] == 0))
7047 		return false;
7048 	int width = content[10] | content[11] << 8;
7049 	int height = content[12] | content[13] << 8;
7050 	int bitmapLength = content[14] | content[15] << 8;
7051 	int stride = (width + 15) >> 4 << 1;
7052 	if (bitmapLength != height * stride)
7053 		return false;
7054 	int bitmapOffset = 20 + RECOIL_Get32LittleEndian(content, 16);
7055 	if (bitmapOffset < 20 || contentLength < bitmapOffset + bitmapLength)
7056 		return false;
7057 	if (!RECOIL_SetSize(self, width, height, RECOILResolution_PSION31X1))
7058 		return false;
7059 	for (int y = 0; y < height; y++) {
7060 		for (int x = 0; x < width; x++) {
7061 			self->pixels[y * width + x] = (content[bitmapOffset + (x >> 3)] >> (x & 7) & 1) == 0 ? 16777215 : 0;
7062 		}
7063 		bitmapOffset += stride;
7064 	}
7065 	return true;
7066 }
7067 
RECOIL_DecodeTrsHr(RECOIL * self,uint8_t const * content,int contentLength)7068 static bool RECOIL_DecodeTrsHr(RECOIL *self, uint8_t const *content, int contentLength)
7069 {
7070 	switch (contentLength) {
7071 	case 19200:
7072 	case 19328:
7073 	case 19456:
7074 		break;
7075 	default:
7076 		return false;
7077 	}
7078 	RECOIL_SetSize(self, 640, 480, RECOILResolution_TRS1X2);
7079 	for (int y = 0; y < 240; y++) {
7080 		for (int x = 0; x < 640; x++) {
7081 			int c = content[y * 80 + (x >> 3)] >> (~x & 7) & 1;
7082 			if (c != 0)
7083 				c = 16777215;
7084 			int pixelsOffset = y * 1280 + x;
7085 			self->pixels[pixelsOffset + 640] = self->pixels[pixelsOffset] = c;
7086 		}
7087 	}
7088 	return true;
7089 }
7090 
RECOIL_DecodeTrsShr(RECOIL * self,uint8_t const * content,int contentLength)7091 static bool RECOIL_DecodeTrsShr(RECOIL *self, uint8_t const *content, int contentLength)
7092 {
7093 	RECOIL_SetSize(self, 640, 480, RECOILResolution_TRS1X2);
7094 	PgcStream rle;
7095 	PgcStream_Construct(&rle);
7096 	rle.base.base.base.content = content;
7097 	rle.base.base.base.contentOffset = 0;
7098 	rle.base.base.base.contentLength = contentLength;
7099 	return RECOIL_DecodeRleBlackAndWhite(self, &rle.base, 0);
7100 }
7101 
RECOIL_DecodeRle(RECOIL * self,uint8_t const * content,int contentLength)7102 static bool RECOIL_DecodeRle(RECOIL *self, uint8_t const *content, int contentLength)
7103 {
7104 	if (contentLength < 520 || content[0] != 27 || content[1] != 71 || content[2] != 72)
7105 		return false;
7106 	RECOIL_SetSize(self, 256, 192, RECOILResolution_TRS1X1);
7107 	int count = 0;
7108 	int contentOffset = 3;
7109 	int c = 16777215;
7110 	for (int pixelsOffset = 0; pixelsOffset < 49152; pixelsOffset++) {
7111 		while (count == 0) {
7112 			if (contentOffset >= contentLength)
7113 				return false;
7114 			count = content[contentOffset++];
7115 			if (count < 32 || count > 127) {
7116 				if (pixelsOffset == 49151) {
7117 					self->pixels[pixelsOffset] = c;
7118 					return true;
7119 				}
7120 				return false;
7121 			}
7122 			c ^= 16777215;
7123 			count -= 32;
7124 		}
7125 		self->pixels[pixelsOffset] = c;
7126 		count--;
7127 	}
7128 	return true;
7129 }
7130 
RECOIL_DecodeClp(RECOIL * self,uint8_t const * content,int contentLength)7131 static bool RECOIL_DecodeClp(RECOIL *self, uint8_t const *content, int contentLength)
7132 {
7133 	if (contentLength != 306 || content[305] != 100)
7134 		return false;
7135 	for (int i = 0; i < 25; i++) {
7136 		static const uint8_t HEADER[25] = { 0, 0, 0, 3, 1, 94, 0, 0, 32, 0, 32, 1, 1, 44, 0, 10,
7137 			0, 56, 0, 32, 0, 56, 0, 32, 5 };
7138 		if (content[i] != HEADER[i])
7139 			return false;
7140 	}
7141 	RECOIL_SetSize(self, 40, 56, RECOILResolution_COCO1X1);
7142 	return RECOIL_DecodeBlackAndWhite(self, content, 25, 305, false, 16777215);
7143 }
7144 
RECOIL_DecodeCocoMax(RECOIL * self,uint8_t const * content,int contentLength)7145 static bool RECOIL_DecodeCocoMax(RECOIL *self, uint8_t const *content, int contentLength)
7146 {
7147 	switch (contentLength) {
7148 	case 6154:
7149 	case 6155:
7150 	case 6272:
7151 	case 7168:
7152 		break;
7153 	default:
7154 		return false;
7155 	}
7156 	if (content[0] != 0 || content[1] != 24 || content[2] > 1 || content[3] != 14 || content[4] != 0)
7157 		return false;
7158 	RECOIL_SetSize(self, 256, 192, RECOILResolution_COCO1X1);
7159 	return RECOIL_DecodeBlackAndWhite(self, content, 5, 6149, false, 0);
7160 }
7161 
RECOIL_DecodeP11(RECOIL * self,uint8_t const * content,int contentLength)7162 static bool RECOIL_DecodeP11(RECOIL *self, uint8_t const *content, int contentLength)
7163 {
7164 	if ((contentLength != 3083 && contentLength != 3243) || content[0] != 0 || content[1] != 12 || content[3] != 14 || content[4] != 0)
7165 		return false;
7166 	RECOIL_SetSize(self, 256, 192, RECOILResolution_COCO2X2);
7167 	for (int y = 0; y < 192; y++) {
7168 		for (int x = 0; x < 256; x++) {
7169 			static const int PALETTE[4] = { 524032, 16776960, 3868927, 13369403 };
7170 			int c = content[5 + ((y & -2) << 4) + (x >> 3)] >> (~x & 6) & 3;
7171 			self->pixels[(y << 8) + x] = PALETTE[c];
7172 		}
7173 	}
7174 	return true;
7175 }
7176 
RECOIL_DecodeMac(RECOIL * self,uint8_t const * content,int contentLength)7177 static bool RECOIL_DecodeMac(RECOIL *self, uint8_t const *content, int contentLength)
7178 {
7179 	if (contentLength < 512)
7180 		return false;
7181 	int contentOffset = RECOIL_IsStringAt(content, 65, "PNTG") ? 128 : 0;
7182 	if (content[contentOffset] != 0 || content[contentOffset + 1] != 0 || content[contentOffset + 2] != 0 || content[contentOffset + 3] > 3)
7183 		return false;
7184 	RECOIL_SetSize(self, 576, 720, RECOILResolution_MACINTOSH1X1);
7185 	PackBitsStream rle;
7186 	PackBitsStream_Construct(&rle);
7187 	rle.base.base.base.content = content;
7188 	rle.base.base.base.contentOffset = contentOffset + 512;
7189 	rle.base.base.base.contentLength = contentLength;
7190 	return RECOIL_DecodeRleBlackAndWhite(self, &rle.base, 16777215);
7191 }
7192 
RECOIL_DecodePlayStation(uint8_t const * content,int contentOffset,int * pixels,int pixelsLength)7193 static void RECOIL_DecodePlayStation(uint8_t const *content, int contentOffset, int *pixels, int pixelsLength)
7194 {
7195 	for (int i = 0; i < pixelsLength; i++)
7196 		pixels[i] = RECOIL_GetB5G5R5Color(content[contentOffset + (i << 1)] | content[contentOffset + (i << 1) + 1] << 8);
7197 }
7198 
RECOIL_DecodeTimPalette(RECOIL * self,uint8_t const * content,int contentLength,int colors)7199 static int RECOIL_DecodeTimPalette(RECOIL *self, uint8_t const *content, int contentLength, int colors)
7200 {
7201 	if ((content[16] | content[17] << 8) != colors)
7202 		return -1;
7203 	int paletteCount = content[18] | content[19] << 8;
7204 	if (paletteCount == 0)
7205 		return -1;
7206 	int bitmapOffset = 20 + (paletteCount * colors << 1);
7207 	if (RECOIL_Get32LittleEndian(content, 8) != bitmapOffset - 8 || contentLength < bitmapOffset + 12)
7208 		return -1;
7209 	int width = (content[bitmapOffset + 8] | content[bitmapOffset + 9] << 8) << 1;
7210 	int height = content[bitmapOffset + 10] | content[bitmapOffset + 11] << 8;
7211 	if (contentLength < bitmapOffset + 12 + width * height)
7212 		return -1;
7213 	if (colors == 16)
7214 		width <<= 1;
7215 	if (!RECOIL_SetSize(self, width, height, RECOILResolution_PLAY_STATION1X1))
7216 		return -1;
7217 	RECOIL_DecodePlayStation(content, 20, self->contentPalette, colors);
7218 	return bitmapOffset + 12;
7219 }
7220 
RECOIL_DecodeTim(RECOIL * self,uint8_t const * content,int contentLength)7221 static bool RECOIL_DecodeTim(RECOIL *self, uint8_t const *content, int contentLength)
7222 {
7223 	if (contentLength < 20 || RECOIL_Get32LittleEndian(content, 0) != 16)
7224 		return false;
7225 	int pixelsLength;
7226 	int bitmapOffset;
7227 	switch (content[4] & 15) {
7228 	case 2:
7229 		;
7230 		int width = content[16] | content[17] << 8;
7231 		int height = content[18] | content[19] << 8;
7232 		pixelsLength = width * height;
7233 		if (contentLength < 20 + (pixelsLength << 1) || !RECOIL_SetSize(self, width, height, RECOILResolution_PLAY_STATION1X1))
7234 			return false;
7235 		RECOIL_DecodePlayStation(content, 20, self->pixels, pixelsLength);
7236 		return true;
7237 	case 8:
7238 		bitmapOffset = RECOIL_DecodeTimPalette(self, content, contentLength, 16);
7239 		if (bitmapOffset < 0)
7240 			return false;
7241 		pixelsLength = self->width * self->height;
7242 		for (int i = 0; i < pixelsLength; i++) {
7243 			int b = content[bitmapOffset + (i >> 1)];
7244 			self->pixels[i] = self->contentPalette[(i & 1) == 0 ? b & 15 : b >> 4];
7245 		}
7246 		return true;
7247 	case 9:
7248 		bitmapOffset = RECOIL_DecodeTimPalette(self, content, contentLength, 256);
7249 		if (bitmapOffset < 0)
7250 			return false;
7251 		RECOIL_DecodeBytes(self, content, bitmapOffset);
7252 		return true;
7253 	default:
7254 		return false;
7255 	}
7256 }
7257 
RECOIL_DecodeBb0(RECOIL * self,uint8_t const * content,int contentLength,int const * palette)7258 static bool RECOIL_DecodeBb0(RECOIL *self, uint8_t const *content, int contentLength, int const *palette)
7259 {
7260 	if (contentLength != 20480)
7261 		return false;
7262 	RECOIL_SetSize(self, 640, 512, RECOILResolution_BBC1X2);
7263 	for (int y = 0; y < 256; y++) {
7264 		for (int x = 0; x < 640; x++) {
7265 			int c = content[(y & -8) * 80 + (x & -8) + (y & 7)] >> (~x & 7) & 1;
7266 			int pixelsOffset = y * 1280 + x;
7267 			self->pixels[pixelsOffset + 640] = self->pixels[pixelsOffset] = palette[c];
7268 		}
7269 	}
7270 	return true;
7271 }
7272 
RECOIL_DecodeBb1(RECOIL * self,uint8_t const * content,int contentLength,int const * palette)7273 static bool RECOIL_DecodeBb1(RECOIL *self, uint8_t const *content, int contentLength, int const *palette)
7274 {
7275 	if (contentLength != 20480)
7276 		return false;
7277 	RECOIL_SetSize(self, 320, 256, RECOILResolution_BBC1X1);
7278 	for (int y = 0; y < 256; y++) {
7279 		for (int x = 0; x < 320; x++) {
7280 			int c = content[(y & -8) * 80 + ((x & -4) << 1) + (y & 7)] >> (~x & 3);
7281 			self->pixels[y * 320 + x] = palette[(c >> 3 & 2) + (c & 1)];
7282 		}
7283 	}
7284 	return true;
7285 }
7286 
RECOIL_DecodeBb2(RECOIL * self,uint8_t const * content,int contentLength,int const * palette)7287 static bool RECOIL_DecodeBb2(RECOIL *self, uint8_t const *content, int contentLength, int const *palette)
7288 {
7289 	if (contentLength != 20480)
7290 		return false;
7291 	RECOIL_SetSize(self, 320, 256, RECOILResolution_BBC2X1);
7292 	for (int y = 0; y < 256; y++) {
7293 		for (int x = 0; x < 160; x++) {
7294 			int c = content[(y & -8) * 80 + ((x & -2) << 2) + (y & 7)] >> (~x & 1);
7295 			int pixelsOffset = (y * 160 + x) << 1;
7296 			self->pixels[pixelsOffset + 1] = self->pixels[pixelsOffset] = palette[(c >> 3 & 8) + (c >> 2 & 4) + (c >> 1 & 2) + (c & 1)];
7297 		}
7298 	}
7299 	return true;
7300 }
7301 
RECOIL_DecodeBb4(RECOIL * self,uint8_t const * content,int contentLength,int const * palette)7302 static bool RECOIL_DecodeBb4(RECOIL *self, uint8_t const *content, int contentLength, int const *palette)
7303 {
7304 	if (contentLength != 10240)
7305 		return false;
7306 	RECOIL_SetSize(self, 320, 256, RECOILResolution_BBC1X1);
7307 	for (int y = 0; y < 256; y++) {
7308 		for (int x = 0; x < 320; x++) {
7309 			int c = content[(y & -8) * 40 + (x & -8) + (y & 7)] >> (~x & 7) & 1;
7310 			self->pixels[y * 320 + x] = palette[c];
7311 		}
7312 	}
7313 	return true;
7314 }
7315 
RECOIL_DecodeBb5(RECOIL * self,uint8_t const * content,int contentLength,int const * palette)7316 static bool RECOIL_DecodeBb5(RECOIL *self, uint8_t const *content, int contentLength, int const *palette)
7317 {
7318 	if (contentLength != 10240)
7319 		return false;
7320 	RECOIL_SetSize(self, 320, 256, RECOILResolution_BBC2X1);
7321 	for (int y = 0; y < 256; y++) {
7322 		for (int x = 0; x < 160; x++) {
7323 			int c = content[(y & -8) * 40 + ((x & -4) << 1) + (y & 7)] >> (~x & 3);
7324 			int pixelsOffset = (y * 160 + x) << 1;
7325 			self->pixels[pixelsOffset + 1] = self->pixels[pixelsOffset] = palette[(c >> 3 & 2) + (c & 1)];
7326 		}
7327 	}
7328 	return true;
7329 }
7330 
RECOIL_DecodeBbg(RECOIL * self,uint8_t const * content,int contentLength)7331 static bool RECOIL_DecodeBbg(RECOIL *self, uint8_t const *content, int contentLength)
7332 {
7333 	BbgStream rle;
7334 	BbgStream_Construct(&rle);
7335 	rle.base.base.base.content = content;
7336 	rle.base.base.base.contentOffset = 0;
7337 	rle.base.base.base.contentLength = contentLength;
7338 	rle.valueBits = BbgStream_ReadBitsReverse(&rle, 8);
7339 	if (rle.valueBits < 1 || rle.valueBits > 8)
7340 		return false;
7341 	int mode = BbgStream_ReadBitsReverse(&rle, 8);
7342 	int unpackedLength;
7343 	switch (mode) {
7344 	case 0:
7345 	case 1:
7346 	case 2:
7347 		unpackedLength = 20480;
7348 		break;
7349 	case 4:
7350 	case 5:
7351 		unpackedLength = 10240;
7352 		break;
7353 	default:
7354 		return false;
7355 	}
7356 	for (int i = 15; i >= 0; i--) {
7357 		int c = BbgStream_ReadBitsReverse(&rle, 4);
7358 		if (c < 0)
7359 			return false;
7360 		self->contentPalette[i] = RECOIL_BBC_PALETTE[c];
7361 	}
7362 	int unpackedStep = BbgStream_ReadBitsReverse(&rle, 8);
7363 	if (unpackedStep <= 0)
7364 		return false;
7365 	rle.countBits = BbgStream_ReadBitsReverse(&rle, 8);
7366 	if (rle.countBits < 1 || rle.countBits > 8)
7367 		return false;
7368 	uint8_t unpacked[20480];
7369 	for (int x = unpackedStep - 1; x >= 0; x--) {
7370 		if (!RleStream_Unpack(&rle.base, unpacked, x, unpackedStep, unpackedLength))
7371 			return false;
7372 	}
7373 	switch (mode) {
7374 	case 0:
7375 		return RECOIL_DecodeBb0(self, unpacked, unpackedLength, self->contentPalette);
7376 	case 1:
7377 		return RECOIL_DecodeBb1(self, unpacked, unpackedLength, self->contentPalette);
7378 	case 2:
7379 		return RECOIL_DecodeBb2(self, unpacked, unpackedLength, self->contentPalette);
7380 	case 4:
7381 		return RECOIL_DecodeBb4(self, unpacked, unpackedLength, self->contentPalette);
7382 	case 5:
7383 		return RECOIL_DecodeBb5(self, unpacked, unpackedLength, self->contentPalette);
7384 	default:
7385 		return false;
7386 	}
7387 }
7388 
RECOIL_GetOricHeader(uint8_t const * content,int contentLength)7389 static int RECOIL_GetOricHeader(uint8_t const *content, int contentLength)
7390 {
7391 	if (contentLength < 26 || content[0] != 22 || content[1] != 22 || content[2] != 22 || content[3] != 36 || content[4] != 0 || content[5] != 0 || content[6] != 128 || content[7] != 0 || content[12] != 0)
7392 		return 0;
7393 	int contentOffset = 13;
7394 	while (content[contentOffset++] != 0) {
7395 		if (contentOffset >= 26)
7396 			return 0;
7397 	}
7398 	return contentOffset;
7399 }
7400 
RECOIL_DecodeChs(RECOIL * self,uint8_t const * content,int contentLength)7401 static bool RECOIL_DecodeChs(RECOIL *self, uint8_t const *content, int contentLength)
7402 {
7403 	int contentOffset = RECOIL_GetOricHeader(content, contentLength);
7404 	switch (contentLength - contentOffset) {
7405 	case 768:
7406 	case 769:
7407 		break;
7408 	default:
7409 		return false;
7410 	}
7411 	RECOIL_SetSize(self, 256, 24, RECOILResolution_ORIC1X1);
7412 	RECOIL_DecodeBlackAndWhiteFont(self, content, contentOffset, contentLength, 8);
7413 	return true;
7414 }
7415 
RECOIL_DecodeHrs(RECOIL * self,uint8_t const * content,int contentLength)7416 static bool RECOIL_DecodeHrs(RECOIL *self, uint8_t const *content, int contentLength)
7417 {
7418 	int contentOffset = RECOIL_GetOricHeader(content, contentLength);
7419 	if (contentOffset + 8000 != contentLength)
7420 		return false;
7421 	RECOIL_SetSize(self, 240, 200, RECOILResolution_ORIC1X1);
7422 	for (int y = 0; y < 200; y++) {
7423 		int paper = 0;
7424 		int ink = 7;
7425 		for (int col = 0; col < 40; col++) {
7426 			int offset = y * 40 + col;
7427 			int b = content[contentOffset + offset];
7428 			int inverse = b >= 128 ? 7 : 0;
7429 			switch (b & 120) {
7430 			case 0:
7431 				ink = b & 7;
7432 				b = 0;
7433 				break;
7434 			case 8:
7435 			case 24:
7436 				b = 0;
7437 				break;
7438 			case 16:
7439 				paper = b & 7;
7440 				b = 0;
7441 				break;
7442 			default:
7443 				break;
7444 			}
7445 			for (int x = 0; x < 6; x++)
7446 				self->pixels[offset * 6 + x] = RECOIL_BBC_PALETTE[((b >> (5 - x) & 1) == 0 ? paper : ink) ^ inverse];
7447 		}
7448 	}
7449 	return true;
7450 }
7451 
RECOIL_GetAmstradHeader(uint8_t const * content,int contentLength)7452 static int RECOIL_GetAmstradHeader(uint8_t const *content, int contentLength)
7453 {
7454 	if (contentLength < 128 || (content[24] | content[25] << 8) != contentLength - 128 || content[64] != content[24] || content[65] != content[25] || content[66] != 0)
7455 		return 0;
7456 	int sum = 0;
7457 	for (int i = 0; i < 67; i++)
7458 		sum += content[i];
7459 	if ((content[67] | content[68] << 8) != sum)
7460 		return 0;
7461 	return 128;
7462 }
7463 
RECOIL_DecodeAmstradFnt(RECOIL * self,uint8_t const * content,int contentLength)7464 static bool RECOIL_DecodeAmstradFnt(RECOIL *self, uint8_t const *content, int contentLength)
7465 {
7466 	int contentOffset = RECOIL_GetAmstradHeader(content, contentLength);
7467 	if (contentLength != contentOffset + 768 && (contentLength != 896 || contentOffset != 0))
7468 		return false;
7469 	RECOIL_SetSize(self, 256, 24, RECOILResolution_AMSTRAD1X1);
7470 	RECOIL_DecodeBlackAndWhiteFont(self, content, contentOffset, contentLength, 8);
7471 	return true;
7472 }
7473 
RECOIL_DecodeAmstradMode2(RECOIL * self,uint8_t const * content,int contentOffset,int width,int height)7474 static bool RECOIL_DecodeAmstradMode2(RECOIL *self, uint8_t const *content, int contentOffset, int width, int height)
7475 {
7476 	RECOIL_SetSize(self, width, height << 1, RECOILResolution_AMSTRAD1X2);
7477 	for (int y = 0; y < height; y++) {
7478 		for (int x = 0; x < width; x++) {
7479 			int offset = (y * width << 1) + x;
7480 			int c = content[contentOffset + ((y & 7) << 11) + (((y >> 3) * width + x) >> 3)] >> (~x & 7) & 1;
7481 			self->pixels[offset + width] = self->pixels[offset] = self->contentPalette[c];
7482 		}
7483 	}
7484 	return true;
7485 }
7486 
RECOIL_DecodeHgb(RECOIL * self,uint8_t const * content,int contentLength)7487 static bool RECOIL_DecodeHgb(RECOIL *self, uint8_t const *content, int contentLength)
7488 {
7489 	int contentOffset = RECOIL_GetAmstradHeader(content, contentLength);
7490 	if (contentLength != contentOffset + 16384)
7491 		return false;
7492 	self->contentPalette[0] = 0;
7493 	self->contentPalette[1] = 16777215;
7494 	return RECOIL_DecodeAmstradMode2(self, content, contentOffset, 512, 256);
7495 }
7496 
RECOIL_SetAmstradPalette(RECOIL * self,const char * filename)7497 static int RECOIL_SetAmstradPalette(RECOIL *self, const char *filename)
7498 {
7499 	uint8_t pal[368];
7500 	int palLength = RECOIL_ReadCompanionFile(self, filename, "PAL", "pal", pal, 368);
7501 	int palOffset = RECOIL_GetAmstradHeader(pal, palLength);
7502 	if (palLength != palOffset + 239)
7503 		return -1;
7504 	for (int i = 0; i < 16; i++) {
7505 		int c = pal[palOffset + 3 + i * 12];
7506 		if (c < 64 || c > 95)
7507 			return -1;
7508 		self->contentPalette[i] = RECOIL_AMSTRAD_PALETTE[c - 64];
7509 	}
7510 	return pal[palOffset];
7511 }
7512 
RECOIL_DecodeAmstradMode0Line(RECOIL * self,uint8_t const * content,int lineOffset,int y)7513 static void RECOIL_DecodeAmstradMode0Line(RECOIL *self, uint8_t const *content, int lineOffset, int y)
7514 {
7515 	int skip = self->resolution == RECOILResolution_AMSTRAD1X1 ? (y ^ (y >= self->height ? 1 : 0)) & 1 : 0;
7516 	for (int x = 0; x < self->width; x++) {
7517 		int i = x + skip;
7518 		int b = i >= self->width ? 0 : content[lineOffset + (i >> 2)];
7519 		if ((i & 2) == 0)
7520 			b >>= 1;
7521 		self->pixels[y * self->width + x] = self->contentPalette[((b & 1) << 3) + (b >> 2 & 4) + (b >> 1 & 2) + (b >> 6 & 1)];
7522 	}
7523 }
7524 
RECOIL_DecodeAmstradMode1Line(RECOIL * self,uint8_t const * content,int lineOffset,int y)7525 static void RECOIL_DecodeAmstradMode1Line(RECOIL *self, uint8_t const *content, int lineOffset, int y)
7526 {
7527 	for (int x = 0; x < self->width; x++) {
7528 		int b = content[lineOffset + (x >> 2)] >> (~x & 3);
7529 		self->pixels[y * self->width + x] = self->contentPalette[((b & 1) << 1) + (b >> 4 & 1)];
7530 	}
7531 }
7532 
RECOIL_DecodeAmstradScr(RECOIL * self,const char * filename,uint8_t const * content,int contentLength)7533 static bool RECOIL_DecodeAmstradScr(RECOIL *self, const char *filename, uint8_t const *content, int contentLength)
7534 {
7535 	uint8_t unpacked[16384];
7536 	int contentOffset = RECOIL_GetAmstradHeader(content, contentLength);
7537 	switch (contentLength - contentOffset) {
7538 	case 16336:
7539 	case 16384:
7540 		break;
7541 	default:
7542 		if (!AmstradStream_UnpackFile(content, contentOffset, contentLength, unpacked, 16384))
7543 			return false;
7544 		content = unpacked;
7545 		contentOffset = 0;
7546 		break;
7547 	}
7548 	switch (RECOIL_SetAmstradPalette(self, filename)) {
7549 	case 0:
7550 		RECOIL_SetSize(self, 320, 200, RECOILResolution_AMSTRAD2X1);
7551 		for (int y = 0; y < 200; y++)
7552 			RECOIL_DecodeAmstradMode0Line(self, content, contentOffset + ((y & 7) << 11) + (y >> 3) * 80, y);
7553 		return true;
7554 	case 1:
7555 		RECOIL_SetSize(self, 320, 200, RECOILResolution_AMSTRAD1X1);
7556 		for (int y = 0; y < 200; y++)
7557 			RECOIL_DecodeAmstradMode1Line(self, content, contentOffset + ((y & 7) << 11) + (y >> 3) * 80, y);
7558 		return true;
7559 	case 2:
7560 		return RECOIL_DecodeAmstradMode2(self, content, contentOffset, 640, 200);
7561 	default:
7562 		return false;
7563 	}
7564 }
7565 
RECOIL_DecodeWin(RECOIL * self,const char * filename,uint8_t const * content,int contentLength)7566 static bool RECOIL_DecodeWin(RECOIL *self, const char *filename, uint8_t const *content, int contentLength)
7567 {
7568 	if (contentLength < 6)
7569 		return false;
7570 	int width = content[contentLength - 4] | content[contentLength - 3] << 8;
7571 	if (width == 0 || width > 640)
7572 		return false;
7573 	int height = content[contentLength - 2];
7574 	if (height == 0 || height > 200)
7575 		return false;
7576 	int bytesPerLine = (width + 7) >> 3;
7577 	uint8_t unpacked[16000];
7578 	int contentOffset = RECOIL_GetAmstradHeader(content, contentLength);
7579 	if (contentLength != contentOffset + bytesPerLine * height + 5) {
7580 		if (!AmstradStream_UnpackFile(content, contentOffset, contentLength, unpacked, bytesPerLine * height))
7581 			return false;
7582 		content = unpacked;
7583 		contentOffset = 0;
7584 	}
7585 	if (RECOIL_SetAmstradPalette(self, filename) != 0)
7586 		return false;
7587 	width >>= 1;
7588 	RECOIL_SetSize(self, width, height, RECOILResolution_AMSTRAD2X1);
7589 	for (int y = 0; y < height; y++)
7590 		RECOIL_DecodeAmstradMode0Line(self, content, contentOffset + y * bytesPerLine, y);
7591 	return true;
7592 }
7593 
RECOIL_DecodeCm5(RECOIL * self,const char * filename,uint8_t const * content,int contentLength)7594 static bool RECOIL_DecodeCm5(RECOIL *self, const char *filename, uint8_t const *content, int contentLength)
7595 {
7596 	if (contentLength != 2049)
7597 		return false;
7598 	uint8_t gfx[18433];
7599 	if (RECOIL_ReadCompanionFile(self, filename, "GFX", "gfx", gfx, 18433) != 18432)
7600 		return false;
7601 	RECOIL_SetSize(self, 288, 256, RECOILResolution_AMSTRAD1X1);
7602 	for (int y = 0; y < 256; y++) {
7603 		for (int x = 0; x < 288; x++) {
7604 			int c;
7605 			switch (gfx[y * 72 + (x >> 2)] >> (~x & 3) & 17) {
7606 			case 0:
7607 				c = 3 + (y << 3) + x / 48;
7608 				break;
7609 			case 1:
7610 				c = 1 + (y << 3);
7611 				break;
7612 			case 16:
7613 				c = 2 + (y << 3);
7614 				break;
7615 			default:
7616 				c = 0;
7617 				break;
7618 			}
7619 			c = content[c];
7620 			if (c < 64 || c > 95)
7621 				return false;
7622 			self->pixels[y * 288 + x] = RECOIL_AMSTRAD_PALETTE[c - 64];
7623 		}
7624 	}
7625 	return true;
7626 }
7627 
RECOIL_DecodeSgx(RECOIL * self,uint8_t const * content,int contentLength)7628 static bool RECOIL_DecodeSgx(RECOIL *self, uint8_t const *content, int contentLength)
7629 {
7630 	int width = 0;
7631 	int height = 0;
7632 	int chunkLeft = 0;
7633 	int rowHeight = 0;
7634 	for (int contentOffset = 0; contentOffset + 3 < contentLength;) {
7635 		int chunkStride = content[contentOffset];
7636 		if (chunkStride == 0)
7637 			break;
7638 		if (chunkStride == 255) {
7639 			if (width == 0)
7640 				width = chunkLeft;
7641 			else if (chunkLeft != width)
7642 				return false;
7643 			chunkLeft = 0;
7644 			contentOffset += 3;
7645 		}
7646 		else {
7647 			int chunkWidth;
7648 			int chunkHeight;
7649 			if (chunkStride <= 63) {
7650 				chunkWidth = content[contentOffset + 1];
7651 				if ((chunkWidth + 3) >> 2 != chunkStride)
7652 					return false;
7653 				chunkHeight = content[contentOffset + 2];
7654 				contentOffset += 3;
7655 			}
7656 			else if (chunkStride == 64) {
7657 				if (contentOffset + 8 >= contentLength || content[contentOffset + 1] != 5)
7658 					return false;
7659 				chunkStride = content[contentOffset + 2] | content[contentOffset + 3] << 8;
7660 				chunkWidth = content[contentOffset + 4] | content[contentOffset + 5] << 8;
7661 				if ((chunkWidth + 1) >> 1 != chunkStride)
7662 					return false;
7663 				chunkHeight = content[contentOffset + 6] | content[contentOffset + 7] << 8;
7664 				contentOffset += 8;
7665 			}
7666 			else
7667 				return false;
7668 			if (chunkLeft == 0)
7669 				height += rowHeight = chunkHeight;
7670 			else if (chunkHeight != rowHeight)
7671 				return false;
7672 			chunkLeft += chunkWidth;
7673 			contentOffset += chunkHeight * chunkStride;
7674 			if (contentOffset > contentLength)
7675 				return false;
7676 		}
7677 	}
7678 	if (width == 0)
7679 		width = chunkLeft;
7680 	else if (chunkLeft != width)
7681 		return false;
7682 	if (!RECOIL_SetSize(self, width, height, RECOILResolution_AMSTRAD1X1))
7683 		return false;
7684 	chunkLeft = 0;
7685 	int chunkTop = 0;
7686 	rowHeight = 0;
7687 	for (int contentOffset = 0; contentOffset + 3 < contentLength;) {
7688 		int chunkStride = content[contentOffset];
7689 		if (chunkStride == 0)
7690 			break;
7691 		if (chunkStride == 255) {
7692 			chunkLeft = 0;
7693 			chunkTop += rowHeight;
7694 			contentOffset += 3;
7695 		}
7696 		else {
7697 			int chunkWidth;
7698 			if (chunkStride <= 63) {
7699 				chunkWidth = content[contentOffset + 1];
7700 				rowHeight = content[contentOffset + 2];
7701 				contentOffset += 3;
7702 				for (int y = 0; y < rowHeight; y++) {
7703 					for (int x = 0; x < chunkWidth; x++) {
7704 						int b = content[contentOffset + (x >> 2)] >> (~x & 3);
7705 						static const int PALETTE4[4] = { 16777215, 11184810, 0, 5592405 };
7706 						self->pixels[(chunkTop + y) * width + chunkLeft + x] = PALETTE4[(b >> 3 & 2) + (b & 1)];
7707 					}
7708 					contentOffset += chunkStride;
7709 				}
7710 			}
7711 			else {
7712 				chunkStride = content[contentOffset + 2] | content[contentOffset + 3] << 8;
7713 				chunkWidth = content[contentOffset + 4] | content[contentOffset + 5] << 8;
7714 				rowHeight = content[contentOffset + 6] | content[contentOffset + 7] << 8;
7715 				contentOffset += 8;
7716 				for (int y = 0; y < rowHeight; y++) {
7717 					for (int x = 0; x < chunkWidth; x++) {
7718 						int c = RECOIL_GetNibble(content, contentOffset, x);
7719 						static const int PALETTE16[16] = { 16777088, 0, 16744448, 8388608, 65535, 128, 8421631, 255, 16777215, 32768, 65280, 16711935, 16776960, 8421504, 16744576, 16711680 };
7720 						self->pixels[(chunkTop + y) * width + chunkLeft + x] = PALETTE16[c];
7721 					}
7722 					contentOffset += chunkStride;
7723 				}
7724 			}
7725 			chunkLeft += chunkWidth;
7726 		}
7727 	}
7728 	return true;
7729 }
7730 
RECOIL_SetAmstradFirmwarePalette(RECOIL * self,uint8_t const * content,int contentOffset,int count)7731 static bool RECOIL_SetAmstradFirmwarePalette(RECOIL *self, uint8_t const *content, int contentOffset, int count)
7732 {
7733 	for (int i = 0; i < count; i++) {
7734 		int c = content[contentOffset + i];
7735 		if (c > 26)
7736 			return false;
7737 		static const uint8_t TRI_LEVEL[3] = { 0, 128, 255 };
7738 		self->contentPalette[i] = TRI_LEVEL[c / 3 % 3] << 16 | TRI_LEVEL[c / 9] << 8 | TRI_LEVEL[c % 3];
7739 	}
7740 	return true;
7741 }
7742 
RECOIL_SetAmstradFirmwarePalette16(RECOIL * self,uint8_t const * content)7743 static bool RECOIL_SetAmstradFirmwarePalette16(RECOIL *self, uint8_t const *content)
7744 {
7745 	return content[5] == 1 && RECOIL_SetAmstradFirmwarePalette(self, content, 6, 16);
7746 }
7747 
RECOIL_DecodePphFrame(RECOIL * self,const char * filename,const char * upperExt,const char * lowerExt,uint8_t * bitmap,uint8_t const * pph,int yOffset)7748 static bool RECOIL_DecodePphFrame(RECOIL *self, const char *filename, const char *upperExt, const char *lowerExt, uint8_t *bitmap, uint8_t const *pph, int yOffset)
7749 {
7750 	int bitmapStride = self->width >> 2;
7751 	int bitmapLength = self->height * bitmapStride;
7752 	if (RECOIL_ReadCompanionFile(self, filename, upperExt, lowerExt, bitmap, bitmapLength + 1) != bitmapLength)
7753 		return false;
7754 	if (pph[0] == 5) {
7755 		int paletteOffset = 6;
7756 		int paletteLines = 0;
7757 		for (int y = 0; y < self->height; y++) {
7758 			if (paletteLines == 0) {
7759 				if (!RECOIL_SetAmstradFirmwarePalette(self, pph, paletteOffset, 4))
7760 					return false;
7761 				paletteOffset += 4;
7762 				if (paletteOffset < (1 + pph[5]) * 5) {
7763 					paletteLines = pph[paletteOffset++];
7764 					if (paletteLines == 0)
7765 						return false;
7766 				}
7767 				else
7768 					paletteLines = 272;
7769 			}
7770 			RECOIL_DecodeAmstradMode1Line(self, bitmap, y * bitmapStride, yOffset + y);
7771 			paletteLines--;
7772 		}
7773 	}
7774 	else {
7775 		for (int y = 0; y < self->height; y++)
7776 			RECOIL_DecodeAmstradMode0Line(self, bitmap, y * bitmapStride, yOffset + y);
7777 	}
7778 	return true;
7779 }
7780 
RECOIL_DecodePph(RECOIL * self,const char * filename,uint8_t const * content,int contentLength)7781 static bool RECOIL_DecodePph(RECOIL *self, const char *filename, uint8_t const *content, int contentLength)
7782 {
7783 	if (contentLength < 10)
7784 		return false;
7785 	RECOILResolution resolution;
7786 	switch (content[0]) {
7787 	case 3:
7788 		if (contentLength != 22 || !RECOIL_SetAmstradFirmwarePalette16(self, content))
7789 			return false;
7790 		resolution = RECOILResolution_AMSTRAD1X1;
7791 		break;
7792 	case 4:
7793 		if (contentLength != 22 || !RECOIL_SetAmstradFirmwarePalette16(self, content))
7794 			return false;
7795 		resolution = RECOILResolution_AMSTRAD2X1;
7796 		break;
7797 	case 5:
7798 		if (contentLength != (1 + content[5]) * 5)
7799 			return false;
7800 		resolution = RECOILResolution_AMSTRAD1X1;
7801 		break;
7802 	default:
7803 		return false;
7804 	}
7805 	int width = content[1] | content[2] << 8;
7806 	if (width == 0 || width > 384 || (width & 3) != 0)
7807 		return false;
7808 	int height = content[3] | content[4] << 8;
7809 	if (height == 0 || height > 272)
7810 		return false;
7811 	RECOIL_SetSize(self, width, height, resolution);
7812 	uint8_t bitmap[26113];
7813 	return RECOIL_DecodePphFrame(self, filename, "ODD", "odd", bitmap, content, 0) && RECOIL_DecodePphFrame(self, filename, "EVE", "eve", bitmap, content, height) && RECOIL_ApplyBlend(self);
7814 }
7815 
RECOIL_DecodeZx81(RECOIL * self,uint8_t const * screen)7816 static bool RECOIL_DecodeZx81(RECOIL *self, uint8_t const *screen)
7817 {
7818 	RECOIL_SetSize(self, 256, 192, RECOILResolution_ZX811X1);
7819 	uint8_t const *font = CiResource_zx81_fnt;
7820 	for (int y = 0; y < 192; y++) {
7821 		for (int x = 0; x < 256; x++) {
7822 			int c = screen[y >> 3 << 5 | x >> 3];
7823 			int b = font[(c & 63) << 3 | (y & 7)] >> (~x & 7) & 1;
7824 			self->pixels[y << 8 | x] = b == c >> 7 ? 16777215 : 0;
7825 		}
7826 	}
7827 	return true;
7828 }
7829 
RECOIL_DecodeZx81Raw(RECOIL * self,uint8_t const * content,int contentLength)7830 static bool RECOIL_DecodeZx81Raw(RECOIL *self, uint8_t const *content, int contentLength)
7831 {
7832 	if (contentLength != 792)
7833 		return false;
7834 	uint8_t screen[768];
7835 	for (int y = 0; y < 24; y++) {
7836 		if (content[y * 33 + 32] != 118)
7837 			return false;
7838 		memcpy(screen + y * 32, content + y * 33, 32);
7839 	}
7840 	return RECOIL_DecodeZx81(self, screen);
7841 }
7842 
RECOIL_DecodeZp1(RECOIL * self,uint8_t const * content,int contentLength)7843 static bool RECOIL_DecodeZp1(RECOIL *self, uint8_t const *content, int contentLength)
7844 {
7845 	uint8_t screen[768];
7846 	Stream s;
7847 	s.content = content;
7848 	s.contentOffset = 0;
7849 	s.contentLength = contentLength;
7850 	for (int i = 0; i < 768; i++) {
7851 		int hi = Stream_ReadHexDigit(&s);
7852 		if (hi < 0)
7853 			return false;
7854 		int lo = Stream_ReadHexDigit(&s);
7855 		if (lo < 0)
7856 			return false;
7857 		screen[i] = (uint8_t) (hi << 4 | lo);
7858 	}
7859 	return RECOIL_DecodeZx81(self, screen);
7860 }
7861 
RECOIL_DecodeP(RECOIL * self,uint8_t const * content,int contentLength)7862 static bool RECOIL_DecodeP(RECOIL *self, uint8_t const *content, int contentLength)
7863 {
7864 	PInterpreter interp;
7865 	interp.base.content = content;
7866 	interp.base.contentLength = contentLength;
7867 	return PInterpreter_Run(&interp) && RECOIL_DecodeZx81(self, interp.screen);
7868 }
7869 
RECOIL_GetZxColor(int c)7870 static int RECOIL_GetZxColor(int c)
7871 {
7872 	return (c >> 1 & 1) * 16711680 | (c >> 2 & 1) * 65280 | (c & 1) * 255;
7873 }
7874 
RECOIL_SetZx(RECOIL * self,RECOILResolution resolution)7875 static void RECOIL_SetZx(RECOIL *self, RECOILResolution resolution)
7876 {
7877 	RECOIL_SetSize(self, 256, 192, resolution);
7878 	for (int i = 0; i < 64; i++) {
7879 		int rgb = RECOIL_GetZxColor(i);
7880 		if ((i & 16) == 0)
7881 			rgb &= 13487565;
7882 		self->contentPalette[i] = rgb;
7883 	}
7884 }
7885 
RECOIL_GetG3R3B2Color(int c)7886 static int RECOIL_GetG3R3B2Color(int c)
7887 {
7888 	return (c & 28) * 73 >> 3 << 16 | (c >> 5) * 73 >> 1 << 8 | (c & 3) * 85;
7889 }
7890 
RECOIL_SetUlaPlus(RECOIL * self,uint8_t const * content,int paletteOffset)7891 static void RECOIL_SetUlaPlus(RECOIL *self, uint8_t const *content, int paletteOffset)
7892 {
7893 	RECOIL_SetSize(self, 256, 192, RECOILResolution_SPECTRUM1X1);
7894 	for (int i = 0; i < 64; i++)
7895 		self->contentPalette[i] = RECOIL_GetG3R3B2Color(content[paletteOffset + i]);
7896 }
7897 
RECOIL_GetZxLineOffset(int y)7898 static int RECOIL_GetZxLineOffset(int y)
7899 {
7900 	return ((y & 192) << 5) + ((y & 7) << 8) + ((y & 56) << 2);
7901 }
7902 
RECOIL_DecodeZx(RECOIL * self,uint8_t const * content,int bitmapOffset,int attributesOffset,int attributesMode,int pixelsOffset)7903 static void RECOIL_DecodeZx(RECOIL *self, uint8_t const *content, int bitmapOffset, int attributesOffset, int attributesMode, int pixelsOffset)
7904 {
7905 	for (int y = 0; y < 192; y++) {
7906 		for (int x = 0; x < 256; x++) {
7907 			int col = x >> 3;
7908 			int c;
7909 			switch (bitmapOffset) {
7910 			case -3:
7911 				c = x ^ y;
7912 				break;
7913 			case -2:
7914 				c = content[84 + (y & 7)] >> (~x & 7);
7915 				break;
7916 			case -1:
7917 				c = content[y << 5 | col] >> (~x & 7);
7918 				break;
7919 			default:
7920 				c = content[bitmapOffset + RECOIL_GetZxLineOffset(y) + col] >> (~x & 7);
7921 				break;
7922 			}
7923 			c &= 1;
7924 			if (attributesMode == -3) {
7925 				if (c != 0)
7926 					c = 16777215;
7927 			}
7928 			else {
7929 				int a;
7930 				switch (attributesMode) {
7931 				case -2:
7932 					if (col < 8)
7933 						a = attributesOffset + (y >> 3 << 4);
7934 					else if (col < 24)
7935 						a = (attributesOffset == 18688 ? 12536 : 15608) + (y << 4);
7936 					else
7937 						a = attributesOffset + (y >> 3 << 4) - 16;
7938 					break;
7939 				case -1:
7940 					a = attributesOffset + RECOIL_GetZxLineOffset(y);
7941 					break;
7942 				default:
7943 					a = attributesOffset + (y >> attributesMode << 5);
7944 					break;
7945 				}
7946 				a = content[a + col];
7947 				c = self->contentPalette[(a >> 2 & 48) | (c == 0 ? 8 | (a >> 3 & 7) : a & 7)];
7948 			}
7949 			self->pixels[pixelsOffset + (y << 8) + x] = c;
7950 		}
7951 	}
7952 }
7953 
RECOIL_DecodeTimexHires(RECOIL * self,uint8_t const * content,int contentOffset,int pixelsOffset)7954 static void RECOIL_DecodeTimexHires(RECOIL *self, uint8_t const *content, int contentOffset, int pixelsOffset)
7955 {
7956 	int inkColor = RECOIL_GetZxColor(content[contentOffset + 12288] >> 3);
7957 	for (int y = 0; y < 192; y++) {
7958 		for (int x = 0; x < 512; x++) {
7959 			int c = content[contentOffset + (x & 8) * 768 + RECOIL_GetZxLineOffset(y) + (x >> 4)] >> (~x & 7) & 1;
7960 			int offset = pixelsOffset + (y << 10) + x;
7961 			self->pixels[offset + 512] = self->pixels[offset] = c == 0 ? inkColor ^ 16777215 : inkColor;
7962 		}
7963 	}
7964 }
7965 
RECOIL_DecodeHrg(RECOIL * self,uint8_t const * content,int contentLength)7966 static bool RECOIL_DecodeHrg(RECOIL *self, uint8_t const *content, int contentLength)
7967 {
7968 	if (contentLength != 24578)
7969 		return false;
7970 	RECOIL_SetSize(self, 512, 384, RECOILResolution_TIMEX1X2);
7971 	RECOIL_DecodeTimexHires(self, content, 0, 0);
7972 	RECOIL_DecodeTimexHires(self, content, 12289, 196608);
7973 	return RECOIL_ApplyBlend(self);
7974 }
7975 
RECOIL_DecodeZxIfl(RECOIL * self,uint8_t const * content,int contentLength)7976 static bool RECOIL_DecodeZxIfl(RECOIL *self, uint8_t const *content, int contentLength)
7977 {
7978 	if (contentLength != 9216)
7979 		return false;
7980 	RECOIL_SetZx(self, RECOILResolution_SPECTRUM1X1);
7981 	RECOIL_DecodeZx(self, content, 0, 6144, 1, 0);
7982 	return true;
7983 }
7984 
RECOIL_DecodeMcMlt(RECOIL * self,uint8_t const * content,int contentLength,int bitmapOffset)7985 static bool RECOIL_DecodeMcMlt(RECOIL *self, uint8_t const *content, int contentLength, int bitmapOffset)
7986 {
7987 	if (contentLength != 12288)
7988 		return false;
7989 	RECOIL_SetZx(self, RECOILResolution_SPECTRUM1X1);
7990 	RECOIL_DecodeZx(self, content, bitmapOffset, 6144, 0, 0);
7991 	return true;
7992 }
7993 
RECOIL_DecodeZxImg(RECOIL * self,uint8_t const * content,int contentLength)7994 static bool RECOIL_DecodeZxImg(RECOIL *self, uint8_t const *content, int contentLength)
7995 {
7996 	if (contentLength != 13824)
7997 		return false;
7998 	RECOIL_SetZx(self, RECOILResolution_SPECTRUM1X1);
7999 	RECOIL_DecodeZx(self, content, 0, 6144, 3, 0);
8000 	RECOIL_DecodeZx(self, content, 6912, 13056, 3, 49152);
8001 	return RECOIL_ApplyBlend(self);
8002 }
8003 
RECOIL_DecodeMg(RECOIL * self,uint8_t const * content,int contentLength)8004 static bool RECOIL_DecodeMg(RECOIL *self, uint8_t const *content, int contentLength)
8005 {
8006 	if (contentLength < 14080 || content[0] != 77 || content[1] != 71 || content[2] != 72 || content[3] != 1)
8007 		return false;
8008 	int attributesMode;
8009 	switch (content[4]) {
8010 	case 1:
8011 		if (contentLength != 19456)
8012 			return false;
8013 		RECOIL_SetZx(self, RECOILResolution_SPECTRUM1X1);
8014 		RECOIL_DecodeZx(self, content, 256, 18688, -2, 0);
8015 		RECOIL_DecodeZx(self, content, 6400, 19072, -2, 49152);
8016 		return RECOIL_ApplyBlend(self);
8017 	case 2:
8018 		attributesMode = 1;
8019 		break;
8020 	case 4:
8021 		attributesMode = 2;
8022 		break;
8023 	case 8:
8024 		attributesMode = 3;
8025 		break;
8026 	default:
8027 		return false;
8028 	}
8029 	if (contentLength != 12544 + (12288 >> attributesMode))
8030 		return false;
8031 	RECOIL_SetZx(self, RECOILResolution_SPECTRUM1X1);
8032 	RECOIL_DecodeZx(self, content, 256, 12544, attributesMode, 0);
8033 	RECOIL_DecodeZx(self, content, 6400, 12544 + (6144 >> attributesMode), attributesMode, 49152);
8034 	return RECOIL_ApplyBlend(self);
8035 }
8036 
RECOIL_DecodeAtr(RECOIL * self,uint8_t const * content,int contentLength)8037 static bool RECOIL_DecodeAtr(RECOIL *self, uint8_t const *content, int contentLength)
8038 {
8039 	if (contentLength != 768)
8040 		return false;
8041 	RECOIL_SetZx(self, RECOILResolution_SPECTRUM1X1);
8042 	RECOIL_DecodeZx(self, content, -3, 0, 3, 0);
8043 	return true;
8044 }
8045 
RECOIL_DecodeHlr(RECOIL * self,uint8_t const * content,int contentLength)8046 static bool RECOIL_DecodeHlr(RECOIL *self, uint8_t const *content, int contentLength)
8047 {
8048 	if (contentLength != 1628 || content[0] != 118 || content[1] != 175 || content[2] != 211 || content[3] != 254 || content[4] != 33 || content[5] != 0 || content[6] != 88)
8049 		return false;
8050 	RECOIL_SetZx(self, RECOILResolution_SPECTRUM1X1);
8051 	RECOIL_DecodeZx(self, content, -2, 92, 3, 0);
8052 	RECOIL_DecodeZx(self, content, -2, 860, 3, 49152);
8053 	return RECOIL_ApplyBlend(self);
8054 }
8055 
RECOIL_DecodeStl(RECOIL * self,uint8_t const * content,int contentLength)8056 static bool RECOIL_DecodeStl(RECOIL *self, uint8_t const *content, int contentLength)
8057 {
8058 	if (contentLength != 3072)
8059 		return false;
8060 	RECOIL_SetSize(self, 256, 192, RECOILResolution_SPECTRUM4X4);
8061 	for (int f = 0; f < 2; f++) {
8062 		for (int y = 0; y < 192; y++) {
8063 			for (int x = 0; x < 256; x++) {
8064 				int b = content[(y & -4) << 4 | (x >> 2 & -4) | f << 1 | (x >> 3 & 1)];
8065 				int rgb = RECOIL_GetZxColor((x & 4) == 0 ? b >> 3 : b);
8066 				if ((b & 64) == 0)
8067 					rgb &= 13487565;
8068 				self->pixels[(f * 192 + y) << 8 | x] = rgb;
8069 			}
8070 		}
8071 	}
8072 	return RECOIL_ApplyBlend(self);
8073 }
8074 
RECOIL_DecodeZxRgb3(RECOIL * self,uint8_t const * content,int contentLength,uint8_t const * frameComponents)8075 static bool RECOIL_DecodeZxRgb3(RECOIL *self, uint8_t const *content, int contentLength, uint8_t const *frameComponents)
8076 {
8077 	if (contentLength != 18432)
8078 		return false;
8079 	RECOIL_SetSize(self, 256, 192, RECOILResolution_SPECTRUM1X1);
8080 	self->frames = 3;
8081 	for (int y = 0; y < 192; y++) {
8082 		for (int x = 0; x < 256; x++) {
8083 			int offset = RECOIL_GetZxLineOffset(y) + (x >> 3);
8084 			int c = 0;
8085 			for (int frame = 0; frame < 3; frame++) {
8086 				if ((content[frame * 6144 + offset] >> (~x & 7) & 1) != 0)
8087 					c |= 255 << frameComponents[frame];
8088 			}
8089 			self->pixels[(y << 8) + x] = c;
8090 		}
8091 	}
8092 	return true;
8093 }
8094 
RECOIL_DecodeZxRgb(RECOIL * self,uint8_t const * content,int contentLength)8095 static bool RECOIL_DecodeZxRgb(RECOIL *self, uint8_t const *content, int contentLength)
8096 {
8097 	static const uint8_t FRAME_COMPONENTS[3] = { 16, 8, 0 };
8098 	return RECOIL_DecodeZxRgb3(self, content, contentLength, FRAME_COMPONENTS);
8099 }
8100 
RECOIL_Decode3(RECOIL * self,uint8_t const * content,int contentLength)8101 static bool RECOIL_Decode3(RECOIL *self, uint8_t const *content, int contentLength)
8102 {
8103 	static const uint8_t FRAME_COMPONENTS[3] = { 0, 16, 8 };
8104 	return RECOIL_DecodeZxRgb3(self, content, contentLength, FRAME_COMPONENTS);
8105 }
8106 
RECOIL_DecodeCh8(RECOIL * self,uint8_t const * content,int contentLength)8107 static bool RECOIL_DecodeCh8(RECOIL *self, uint8_t const *content, int contentLength)
8108 {
8109 	int height;
8110 	switch (contentLength) {
8111 	case 768:
8112 		height = 24;
8113 		break;
8114 	case 2048:
8115 		height = 64;
8116 		break;
8117 	default:
8118 		return false;
8119 	}
8120 	RECOIL_SetSize(self, 256, height, RECOILResolution_SPECTRUM1X1);
8121 	RECOIL_DecodeBlackAndWhiteFont(self, content, 0, contentLength, 8);
8122 	return true;
8123 }
8124 
RECOIL_DecodeZxp(RECOIL * self,uint8_t const * content,int contentLength)8125 static bool RECOIL_DecodeZxp(RECOIL *self, uint8_t const *content, int contentLength)
8126 {
8127 	if (contentLength < 51670 || !RECOIL_IsStringAt(content, 0, "ZX-Paintbrush "))
8128 		return false;
8129 	int contentOffset = 14;
8130 	if (RECOIL_IsStringAt(content, 14, "extended "))
8131 		contentOffset = 23;
8132 	if (!RECOIL_IsStringAt(content, contentOffset, "image"))
8133 		return false;
8134 	ZxpStream s;
8135 	s.base.content = content;
8136 	s.base.contentOffset = contentOffset + 5;
8137 	s.base.contentLength = contentLength;
8138 	if (ZxpStream_ReadChar(&s) != 10 || ZxpStream_ReadChar(&s) != 10)
8139 		return false;
8140 	uint8_t scr[12288];
8141 	for (int y = 0; y < 192; y++) {
8142 		int b = 0;
8143 		for (int x = 0; x < 256; x++) {
8144 			int bit = ~x & 7;
8145 			switch (ZxpStream_ReadChar(&s)) {
8146 			case 42:
8147 			case 48:
8148 				break;
8149 			case 49:
8150 				b |= 1 << bit;
8151 				break;
8152 			default:
8153 				return false;
8154 			}
8155 			if (bit == 0) {
8156 				scr[y << 5 | x >> 3] = (uint8_t) b;
8157 				b = 0;
8158 			}
8159 		}
8160 		if (ZxpStream_ReadChar(&s) != 10)
8161 			return false;
8162 	}
8163 	if (ZxpStream_ReadChar(&s) != 10)
8164 		return false;
8165 	for (int y = 0; y < 192; y++) {
8166 		if (y == 24 && ZxpStream_IsEof(&s)) {
8167 			RECOIL_SetZx(self, RECOILResolution_SPECTRUM1X1);
8168 			RECOIL_DecodeZx(self, scr, -1, 6144, 3, 0);
8169 			return true;
8170 		}
8171 		for (int x = 0; x < 32; x++) {
8172 			int hi = Stream_ReadHexDigit(&s.base);
8173 			if (hi < 0)
8174 				return false;
8175 			int lo = Stream_ReadHexDigit(&s.base);
8176 			if (lo < 0)
8177 				return false;
8178 			scr[6144 + (y << 5) + x] = (uint8_t) ((hi << 4) + lo);
8179 			if (ZxpStream_ReadChar(&s) != (x < 31 ? 32 : 10))
8180 				return false;
8181 		}
8182 	}
8183 	if (!ZxpStream_IsEof(&s))
8184 		return false;
8185 	RECOIL_SetZx(self, RECOILResolution_SPECTRUM1X1);
8186 	RECOIL_DecodeZx(self, scr, -1, 6144, 0, 0);
8187 	return true;
8188 }
8189 
RECOIL_DecodeBsc(RECOIL * self,uint8_t const * content,int contentLength)8190 static bool RECOIL_DecodeBsc(RECOIL *self, uint8_t const *content, int contentLength)
8191 {
8192 	int borderOffset;
8193 	switch (contentLength) {
8194 	case 11136:
8195 		borderOffset = 6912;
8196 		break;
8197 	case 11904:
8198 		borderOffset = 7680;
8199 		break;
8200 	default:
8201 		return false;
8202 	}
8203 	RECOIL_SetSize(self, 384, 304, RECOILResolution_SPECTRUM1X1);
8204 	for (int y = 0; y < 304; y++) {
8205 		int c = 0;
8206 		for (int x = 0; x < 384; x++) {
8207 			if (y >= 64 && y < 256 && x >= 64 && x < 320) {
8208 				int bY = y - 64;
8209 				int col = (x >> 3) - 8;
8210 				int a = 6144 + (bY >> 3 << 5) + col;
8211 				if (contentLength == 11904 && (bY & 4) != 0)
8212 					a += 768;
8213 				c = a = content[a];
8214 				if ((content[RECOIL_GetZxLineOffset(bY) + col] >> (~x & 7) & 1) == 0)
8215 					c >>= 3;
8216 				c = RECOIL_GetZxColor(c);
8217 				if ((a & 64) == 0)
8218 					c &= 13487565;
8219 			}
8220 			else if ((x & 7) == 0) {
8221 				c = content[borderOffset];
8222 				if ((x & 8) != 0) {
8223 					borderOffset++;
8224 					c >>= 3;
8225 				}
8226 				c = RECOIL_GetZxColor(c) & 13487565;
8227 			}
8228 			self->pixels[y * 384 + x] = c;
8229 		}
8230 	}
8231 	return true;
8232 }
8233 
RECOIL_DecodeChrd(RECOIL * self,uint8_t const * content,int contentLength)8234 static bool RECOIL_DecodeChrd(RECOIL *self, uint8_t const *content, int contentLength)
8235 {
8236 	if (contentLength < 15 || !RECOIL_IsStringAt(content, 0, "chr$"))
8237 		return false;
8238 	int columns = content[4];
8239 	int rows = content[5];
8240 	int bytesPerCell = content[6];
8241 	int cells = rows * columns;
8242 	int frames;
8243 	switch (bytesPerCell) {
8244 	case 9:
8245 		frames = 1;
8246 		break;
8247 	case 18:
8248 		if (cells << 7 > 2854278)
8249 			return false;
8250 		frames = 2;
8251 		break;
8252 	default:
8253 		return false;
8254 	}
8255 	if (contentLength != 7 + cells * bytesPerCell || !RECOIL_SetSize(self, columns << 3, rows << 3, RECOILResolution_SPECTRUM1X1))
8256 		return false;
8257 	int contentOffset = 7;
8258 	for (int row = 0; row < rows; row++) {
8259 		for (int column = 0; column < columns; column++) {
8260 			for (int frame = 0; frame < frames; frame++) {
8261 				int a = content[contentOffset + 8];
8262 				for (int y = 0; y < 8; y++) {
8263 					for (int x = 0; x < 8; x++) {
8264 						int c = content[contentOffset + y] >> (7 - x) & 1;
8265 						c = RECOIL_GetZxColor(c == 0 ? a >> 3 : a);
8266 						if ((a & 64) == 0)
8267 							c &= 13487565;
8268 						self->pixels[(((((frame * rows + row) << 3) + y) * columns + column) << 3) + x] = c;
8269 					}
8270 				}
8271 				contentOffset += 9;
8272 			}
8273 		}
8274 	}
8275 	if (frames == 2)
8276 		RECOIL_ApplyBlend(self);
8277 	return true;
8278 }
8279 
RECOIL_GetBspBitmapPixel(uint8_t const * content,int bitmapOffset,int x,int y)8280 static int RECOIL_GetBspBitmapPixel(uint8_t const *content, int bitmapOffset, int x, int y)
8281 {
8282 	int col = x >> 3;
8283 	int a = content[bitmapOffset + 6144 + (y >> 3 << 5) + col];
8284 	int c = a;
8285 	if ((content[bitmapOffset + RECOIL_GetZxLineOffset(y) + col] >> (~x & 7) & 1) == 0)
8286 		c >>= 3;
8287 	c = RECOIL_GetZxColor(c);
8288 	if ((a & 64) == 0)
8289 		c &= 13487565;
8290 	return c;
8291 }
8292 
RECOIL_DecodeBspFrame(RECOIL * self,int pixelsOffset,uint8_t const * content,int contentLength,int bitmapOffset,int borderOffset)8293 static bool RECOIL_DecodeBspFrame(RECOIL *self, int pixelsOffset, uint8_t const *content, int contentLength, int bitmapOffset, int borderOffset)
8294 {
8295 	for (int y = 0; y < self->height; y++) {
8296 		int c = 0;
8297 		int b = 1;
8298 		for (int x = 0; x < self->width; x++) {
8299 			if (borderOffset < 0)
8300 				c = RECOIL_GetBspBitmapPixel(content, bitmapOffset, x, y);
8301 			else if (x >= 64 && x < 320 && y >= 64 && y < 256) {
8302 				c = RECOIL_GetBspBitmapPixel(content, bitmapOffset, x - 64, y - 64);
8303 				b = 1;
8304 			}
8305 			else if (b > 0) {
8306 				if (--b == 0) {
8307 					if (borderOffset >= contentLength)
8308 						return false;
8309 					b = content[borderOffset++];
8310 					c = RECOIL_GetZxColor(b) & 13487565;
8311 					b >>= 3;
8312 					switch (b) {
8313 					case 0:
8314 						break;
8315 					case 1:
8316 						if (borderOffset >= contentLength)
8317 							return false;
8318 						b = content[borderOffset++];
8319 						break;
8320 					case 2:
8321 						b = 12;
8322 						break;
8323 					default:
8324 						b += 13;
8325 						break;
8326 					}
8327 					b <<= 1;
8328 				}
8329 			}
8330 			self->pixels[pixelsOffset + y * self->width + x] = c;
8331 		}
8332 	}
8333 	return true;
8334 }
8335 
RECOIL_DecodeBsp(RECOIL * self,uint8_t const * content,int contentLength)8336 static bool RECOIL_DecodeBsp(RECOIL *self, uint8_t const *content, int contentLength)
8337 {
8338 	if (contentLength < 6982)
8339 		return false;
8340 	if ((content[3] & 64) == 0) {
8341 		RECOIL_SetSize(self, 256, 192, RECOILResolution_SPECTRUM1X1);
8342 		RECOIL_DecodeBspFrame(self, 0, content, contentLength, 70, -1);
8343 		if (content[3] < 128)
8344 			return true;
8345 		return contentLength == 13894 && RECOIL_DecodeBspFrame(self, 49152, content, contentLength, 6982, -1) && RECOIL_ApplyBlend(self);
8346 	}
8347 	RECOIL_SetSize(self, 384, 304, RECOILResolution_SPECTRUM1X1);
8348 	if (content[3] < 128)
8349 		return RECOIL_DecodeBspFrame(self, 0, content, contentLength, 70, 6982);
8350 	return RECOIL_DecodeBspFrame(self, 0, content, contentLength, 72, 13896) && RECOIL_DecodeBspFrame(self, 116736, content, contentLength, 6984, content[70] | content[71] << 8) && RECOIL_ApplyBlend(self);
8351 }
8352 
RECOIL_DecodeNxi(RECOIL * self,uint8_t const * content,int contentLength)8353 static bool RECOIL_DecodeNxi(RECOIL *self, uint8_t const *content, int contentLength)
8354 {
8355 	if (contentLength != 49664)
8356 		return false;
8357 	for (int i = 0; i < 256; i++) {
8358 		int c = content[i << 1];
8359 		self->contentPalette[i] = (c >> 5) * 73 >> 1 << 16 | (c >> 2 & 7) * 73 >> 1 << 8 | ((c & 3) << 1 | (content[(i << 1) + 1] & 1)) * 73 >> 1;
8360 	}
8361 	RECOIL_SetSize(self, 256, 192, RECOILResolution_SPECTRUM1X1);
8362 	RECOIL_DecodeBytes(self, content, 512);
8363 	return true;
8364 }
8365 
RECOIL_DecodeSxg(RECOIL * self,uint8_t const * content,int contentLength)8366 static bool RECOIL_DecodeSxg(RECOIL *self, uint8_t const *content, int contentLength)
8367 {
8368 	if (contentLength < 19 || content[0] != 127 || content[1] != 83 || content[2] != 88 || content[3] != 71 || content[6] != 0)
8369 		return false;
8370 	int width = content[8] | content[9] << 8;
8371 	int height = content[10] | content[11] << 8;
8372 	if (!RECOIL_SetSize(self, width, height, RECOILResolution_SPECTRUM1X1))
8373 		return false;
8374 	int paletteOffset = 14 + content[12] + (content[13] << 8);
8375 	int bitmapOffset = 16 + content[14] + (content[15] << 8);
8376 	int paletteLength = bitmapOffset - paletteOffset;
8377 	if ((paletteLength & 1) != 0 || paletteLength > 512)
8378 		return false;
8379 	memset(self->contentPalette, 0, sizeof(self->contentPalette));
8380 	int colors = paletteLength >> 1;
8381 	for (int i = 0; i < colors; i++) {
8382 		int offset = paletteOffset + (i << 1);
8383 		int c = content[offset] | content[offset + 1] << 8;
8384 		if (c < 32768) {
8385 			int r = c >> 10;
8386 			int g = c >> 5 & 31;
8387 			int b = c & 31;
8388 			if (r > 24 || g > 24 || b > 24)
8389 				return false;
8390 			c = r * 255 / 24 << 16 | g * 255 / 24 << 8 | b * 255 / 24;
8391 		}
8392 		else
8393 			c = RECOIL_GetR5G5B5Color(c);
8394 		self->contentPalette[i] = c;
8395 	}
8396 	switch (content[7]) {
8397 	case 1:
8398 		if ((width & 1) != 0 || contentLength != bitmapOffset + (width >> 1) * height)
8399 			return false;
8400 		RECOIL_DecodeNibbles(self, content, bitmapOffset, width >> 1);
8401 		return true;
8402 	case 2:
8403 		if (contentLength != bitmapOffset + width * height)
8404 			return false;
8405 		RECOIL_DecodeBytes(self, content, bitmapOffset);
8406 		return true;
8407 	default:
8408 		return false;
8409 	}
8410 }
8411 
RECOIL_SetMsx1Palette(RECOIL * self)8412 static void RECOIL_SetMsx1Palette(RECOIL *self)
8413 {
8414 	self->contentPalette[0] = 2048;
8415 	self->contentPalette[1] = 1024;
8416 	self->contentPalette[2] = 3849027;
8417 	self->contentPalette[3] = 7394167;
8418 	self->contentPalette[4] = 5528023;
8419 	self->contentPalette[5] = 8092648;
8420 	self->contentPalette[6] = 11756363;
8421 	self->contentPalette[7] = 6414311;
8422 	self->contentPalette[8] = 13920851;
8423 	self->contentPalette[9] = 16289399;
8424 	self->contentPalette[10] = 13092697;
8425 	self->contentPalette[11] = 14275713;
8426 	self->contentPalette[12] = 3581243;
8427 	self->contentPalette[13] = 11561902;
8428 	self->contentPalette[14] = 13095109;
8429 	self->contentPalette[15] = 16449528;
8430 }
8431 
RECOIL_GetMsxHeader(uint8_t const * content)8432 static int RECOIL_GetMsxHeader(uint8_t const *content)
8433 {
8434 	if (content[1] != 0 || content[2] != 0 || content[5] != 0 || content[6] != 0)
8435 		return -1;
8436 	return content[3] | content[4] << 8;
8437 }
8438 
RECOIL_IsMsxPalette(uint8_t const * content,int contentOffset)8439 static bool RECOIL_IsMsxPalette(uint8_t const *content, int contentOffset)
8440 {
8441 	int ored = 0;
8442 	for (int i = 0; i < 16; i++) {
8443 		int rb = content[contentOffset + (i << 1)];
8444 		int g = content[contentOffset + (i << 1) + 1];
8445 		if ((rb & 136) != 0 || (g & 248) != 0)
8446 			return false;
8447 		ored |= rb | g;
8448 	}
8449 	return ored != 0;
8450 }
8451 
RECOIL_SetMsxPalette(RECOIL * self,uint8_t const * content,int contentOffset,int colors)8452 static void RECOIL_SetMsxPalette(RECOIL *self, uint8_t const *content, int contentOffset, int colors)
8453 {
8454 	for (int i = 0; i < colors; i++) {
8455 		int rb = content[contentOffset + (i << 1)];
8456 		int g = content[contentOffset + (i << 1) + 1];
8457 		int rgb = (rb & 112) << 12 | (rb & 7) | (g & 7) << 8;
8458 		self->contentPalette[i] = rgb << 5 | rgb << 2 | (rgb >> 1 & 197379);
8459 	}
8460 }
8461 
RECOIL_SetMsx2Palette(RECOIL * self,uint8_t const * content,int contentOffset,int contentLength)8462 static void RECOIL_SetMsx2Palette(RECOIL *self, uint8_t const *content, int contentOffset, int contentLength)
8463 {
8464 	if (contentLength >= contentOffset + 32)
8465 		RECOIL_SetMsxPalette(self, content, contentOffset, 16);
8466 	else
8467 		RECOIL_SetMsxPalette(self, RECOIL_MSX2_DEFAULT_PALETTE, 0, 16);
8468 }
8469 
RECOIL_DecodeSc2Sc4(RECOIL * self,uint8_t const * content,int contentOffset,RECOILResolution resolution)8470 static void RECOIL_DecodeSc2Sc4(RECOIL *self, uint8_t const *content, int contentOffset, RECOILResolution resolution)
8471 {
8472 	RECOIL_SetSize(self, 256, 192, resolution);
8473 	for (int y = 0; y < 192; y++) {
8474 		int fontOffset = contentOffset + ((y & 192) << 5) + (y & 7);
8475 		for (int x = 0; x < 256; x++) {
8476 			int b = fontOffset + (content[contentOffset + 6144 + ((y & -8) << 2) + (x >> 3)] << 3);
8477 			int c = content[8192 + b];
8478 			self->pixels[(y << 8) + x] = self->contentPalette[(content[b] >> (~x & 7) & 1) == 0 ? c & 15 : c >> 4];
8479 		}
8480 	}
8481 }
8482 
RECOIL_DecodeMsxSprites(RECOIL * self,uint8_t const * content,int mode,int attributesOffset,int patternsOffset)8483 static void RECOIL_DecodeMsxSprites(RECOIL *self, uint8_t const *content, int mode, int attributesOffset, int patternsOffset)
8484 {
8485 	int height = mode <= 4 ? 192 : 212;
8486 	for (int y = 0; y < height; y++) {
8487 		for (int x = 0; x < 256; x++) {
8488 			int color = 0;
8489 			bool enableOr = false;
8490 			int spritesPerLine = mode >= 4 ? 8 : 4;
8491 			for (int sprite = 0; sprite < 32; sprite++) {
8492 				int attributeOffset = attributesOffset + (sprite << 2);
8493 				int spriteY = content[attributeOffset];
8494 				if (spriteY == (mode >= 4 ? 216 : 208))
8495 					break;
8496 				int row = (y - spriteY - 1) & 255;
8497 				if (row >= 16)
8498 					continue;
8499 				if (--spritesPerLine < 0)
8500 					break;
8501 				int c = content[mode >= 4 ? attributesOffset - 512 + (sprite << 4) + row : attributeOffset + 3];
8502 				if (mode < 4 || (c & 64) == 0) {
8503 					if (color != 0)
8504 						break;
8505 					enableOr = true;
8506 				}
8507 				else if (!enableOr)
8508 					continue;
8509 				int column = x - content[attributeOffset + 1];
8510 				if (c >= 128)
8511 					column += 32;
8512 				if (column < 0 || column >= 16)
8513 					continue;
8514 				int pattern = patternsOffset + ((content[attributeOffset + 2] & 252) << 3) + row;
8515 				if ((content[pattern + ((column & 8) << 1)] >> (~column & 7) & 1) == 0)
8516 					continue;
8517 				color |= c;
8518 				if (mode >= 4)
8519 					color |= 16;
8520 			}
8521 			if (color != 0) {
8522 				int offset;
8523 				switch (mode) {
8524 				case 6:
8525 					offset = (y << 10) + (x << 1);
8526 					self->pixels[offset + 512] = self->pixels[offset] = self->contentPalette[color >> 2 & 3];
8527 					self->pixels[offset + 513] = self->pixels[offset + 1] = self->contentPalette[color & 3];
8528 					break;
8529 				case 7:
8530 					offset = (y << 10) + (x << 1);
8531 					self->pixels[offset + 513] = self->pixels[offset + 512] = self->pixels[offset + 1] = self->pixels[offset] = self->contentPalette[color & 15];
8532 					break;
8533 				default:
8534 					self->pixels[(y << 8) + x] = self->contentPalette[color & 15];
8535 					break;
8536 				}
8537 			}
8538 		}
8539 	}
8540 }
8541 
RECOIL_DecodeSc2(RECOIL * self,uint8_t const * content,int contentLength)8542 static bool RECOIL_DecodeSc2(RECOIL *self, uint8_t const *content, int contentLength)
8543 {
8544 	if (contentLength < 14343 || content[0] != 254 || RECOIL_GetMsxHeader(content) < 14335)
8545 		return false;
8546 	if (RECOIL_IsMsxPalette(content, 7047)) {
8547 		RECOIL_SetMsxPalette(self, content, 7047, 16);
8548 		RECOIL_DecodeSc2Sc4(self, content, 7, RECOILResolution_MSX21X1);
8549 	}
8550 	else {
8551 		RECOIL_SetMsx1Palette(self);
8552 		RECOIL_DecodeSc2Sc4(self, content, 7, RECOILResolution_MSX11X1);
8553 	}
8554 	if (contentLength == 16391)
8555 		RECOIL_DecodeMsxSprites(self, content, 2, 6919, 14343);
8556 	return true;
8557 }
8558 
RECOIL_DecodeSc3Screen(RECOIL * self,uint8_t const * content,int contentOffset,bool isLong)8559 static void RECOIL_DecodeSc3Screen(RECOIL *self, uint8_t const *content, int contentOffset, bool isLong)
8560 {
8561 	RECOIL_SetSize(self, 256, 192, RECOILResolution_MSX14X4);
8562 	for (int y = 0; y < 192; y++) {
8563 		for (int x = 0; x < 256; x++) {
8564 			int c = isLong ? content[2055 + ((y & -8) << 2) + (x >> 3)] : (y & 224) + (x >> 3);
8565 			c = content[contentOffset + (c << 3) + (y >> 2 & 7)] >> (~x & 4) & 15;
8566 			self->pixels[(y << 8) + x] = self->contentPalette[c];
8567 		}
8568 	}
8569 }
8570 
RECOIL_DecodeSc3(RECOIL * self,uint8_t const * content,int contentLength)8571 static bool RECOIL_DecodeSc3(RECOIL *self, uint8_t const *content, int contentLength)
8572 {
8573 	if (contentLength < 1543 || content[0] != 254 || RECOIL_GetMsxHeader(content) < 1535)
8574 		return false;
8575 	if (contentLength >= 8263 && RECOIL_IsMsxPalette(content, 8231))
8576 		RECOIL_SetMsxPalette(self, content, 8231, 16);
8577 	else
8578 		RECOIL_SetMsx1Palette(self);
8579 	RECOIL_DecodeSc3Screen(self, content, 7, contentLength >= 2823);
8580 	if (contentLength == 16391)
8581 		RECOIL_DecodeMsxSprites(self, content, 3, 6919, 14343);
8582 	return true;
8583 }
8584 
RECOIL_DecodeSc4(RECOIL * self,uint8_t const * content,int contentLength)8585 static bool RECOIL_DecodeSc4(RECOIL *self, uint8_t const *content, int contentLength)
8586 {
8587 	if (contentLength < 16391 || content[0] != 254 || RECOIL_GetMsxHeader(content) < 16383)
8588 		return false;
8589 	RECOIL_SetMsxPalette(self, content, 7047, 16);
8590 	RECOIL_DecodeSc2Sc4(self, content, 7, RECOILResolution_MSX21X1);
8591 	RECOIL_DecodeMsxSprites(self, content, 4, 7687, 14343);
8592 	return true;
8593 }
8594 
RECOIL_GetMsx128Height(const RECOIL * self,uint8_t const * content,int contentLength)8595 static int RECOIL_GetMsx128Height(const RECOIL *self, uint8_t const *content, int contentLength)
8596 {
8597 	if (contentLength < 135 || content[0] != 254)
8598 		return -1;
8599 	int header = RECOIL_GetMsxHeader(content);
8600 	if (header < 127)
8601 		return -1;
8602 	int height = (header + 1) >> 7;
8603 	if (contentLength < 7 + (height << 7))
8604 		return -1;
8605 	return height < 212 ? height : 212;
8606 }
8607 
RECOIL_DecodeMsxScreen(RECOIL * self,uint8_t const * content,int contentOffset,uint8_t const * interlace,int height,int mode,int interlaceMask)8608 static void RECOIL_DecodeMsxScreen(RECOIL *self, uint8_t const *content, int contentOffset, uint8_t const *interlace, int height, int mode, int interlaceMask)
8609 {
8610 	if (interlaceMask != 0) {
8611 		RECOIL_SetSize(self, 512, height << 1, mode >= 10 ? RECOILResolution_MSX2_PLUS2X1 : mode >> 1 == 3 ? RECOILResolution_MSX21X1 : RECOILResolution_MSX22X1);
8612 		self->frames = 2;
8613 	}
8614 	else if (mode >> 1 == 3)
8615 		RECOIL_SetSize(self, 512, height << 1, RECOILResolution_MSX21X2);
8616 	else
8617 		RECOIL_SetSize(self, 256, height, mode >= 10 ? RECOILResolution_MSX2_PLUS1X1 : RECOILResolution_MSX21X1);
8618 	for (int y = 0; y < self->height; y++) {
8619 		uint8_t const *screen = (y & interlaceMask) == 0 ? content : interlace;
8620 		int screenOffset = (y & interlaceMask) == 0 || content != interlace ? contentOffset : contentOffset + (mode <= 6 ? 27143 : 54279);
8621 		for (int x = 0; x < self->width; x++) {
8622 			int rgb = 0;
8623 			switch (mode) {
8624 			case 5:
8625 				rgb = self->contentPalette[RECOIL_GetNibble(screen, screenOffset + (y >> interlaceMask << 7), x >> interlaceMask)];
8626 				break;
8627 			case 6:
8628 				rgb = self->contentPalette[screen[screenOffset + (y >> 1 << 7) + (x >> 2)] >> ((~x & 3) << 1) & 3];
8629 				break;
8630 			case 7:
8631 				rgb = self->contentPalette[RECOIL_GetNibble(screen, screenOffset + (y >> 1 << 8), x)];
8632 				break;
8633 			case 8:
8634 				rgb = self->contentPalette[screen[screenOffset + (y >> interlaceMask << 8) + (x >> interlaceMask)]];
8635 				break;
8636 			case 10:
8637 				rgb = RECOIL_DecodeMsxYjk(self, screen, screenOffset + (y >> interlaceMask << 8), x >> interlaceMask, true);
8638 				break;
8639 			case 12:
8640 				rgb = RECOIL_DecodeMsxYjk(self, screen, screenOffset + (y >> interlaceMask << 8), x >> interlaceMask, false);
8641 				break;
8642 			default:
8643 				assert(false);
8644 			}
8645 			self->pixels[y * self->width + x] = rgb;
8646 		}
8647 	}
8648 }
8649 
RECOIL_DecodeMsxSc(RECOIL * self,const char * filename,uint8_t const * content,int contentOffset,const char * upperExt,const char * lowerExt,int height,int mode)8650 static bool RECOIL_DecodeMsxSc(RECOIL *self, const char *filename, uint8_t const *content, int contentOffset, const char *upperExt, const char *lowerExt, int height, int mode)
8651 {
8652 	if (filename != NULL) {
8653 		uint8_t interlace[54279];
8654 		int interlaceLength = 7 + (height << (mode <= 6 ? 7 : 8));
8655 		if (RECOIL_ReadCompanionFile(self, filename, upperExt, lowerExt, interlace, interlaceLength) == interlaceLength && interlace[0] == 254 && RECOIL_GetMsxHeader(interlace) >= interlaceLength - 8) {
8656 			RECOIL_DecodeMsxScreen(self, content, contentOffset, interlace, height, mode, 1);
8657 			return true;
8658 		}
8659 	}
8660 	RECOIL_DecodeMsxScreen(self, content, contentOffset, NULL, height, mode, 0);
8661 	return false;
8662 }
8663 
RECOIL_DecodeSc5(RECOIL * self,const char * filename,uint8_t const * content,int contentLength)8664 static bool RECOIL_DecodeSc5(RECOIL *self, const char *filename, uint8_t const *content, int contentLength)
8665 {
8666 	int height = RECOIL_GetMsx128Height(self, content, contentLength);
8667 	if (height <= 0)
8668 		return false;
8669 	RECOIL_SetMsx2Palette(self, content, 30343, contentLength);
8670 	if (!RECOIL_DecodeMsxSc(self, filename, content, 7, "S15", "s15", height, 5) && contentLength == 32775)
8671 		RECOIL_DecodeMsxSprites(self, content, 5, 30215, 30727);
8672 	return true;
8673 }
8674 
RECOIL_SetMsxCompanionPalette(RECOIL * self,const char * filename,const char * upperExt,const char * lowerExt)8675 static void RECOIL_SetMsxCompanionPalette(RECOIL *self, const char *filename, const char *upperExt, const char *lowerExt)
8676 {
8677 	uint8_t palette[32];
8678 	RECOIL_SetMsxPalette(self, RECOIL_ReadCompanionFile(self, filename, upperExt, lowerExt, palette, 32) == 32 ? palette : RECOIL_MSX2_DEFAULT_PALETTE, 0, 16);
8679 }
8680 
RECOIL_DecodeSr5(RECOIL * self,const char * filename,uint8_t const * content,int contentLength)8681 static bool RECOIL_DecodeSr5(RECOIL *self, const char *filename, uint8_t const *content, int contentLength)
8682 {
8683 	int height = RECOIL_GetMsx128Height(self, content, contentLength);
8684 	if (height <= 0)
8685 		return false;
8686 	RECOIL_SetMsxCompanionPalette(self, filename, "PL5", "pl5");
8687 	RECOIL_SetSize(self, 256, height, RECOILResolution_MSX21X1);
8688 	RECOIL_DecodeNibbles(self, content, 7, 128);
8689 	return true;
8690 }
8691 
RECOIL_DecodeMsx6(RECOIL * self,uint8_t const * content,int contentOffset)8692 static bool RECOIL_DecodeMsx6(RECOIL *self, uint8_t const *content, int contentOffset)
8693 {
8694 	int height = RECOIL_GetOriginalHeight(self);
8695 	for (int y = 0; y < height; y++) {
8696 		for (int x = 0; x < self->width; x++) {
8697 			int offset = y * self->width + x;
8698 			int b = content[contentOffset + (offset >> 2)];
8699 			RECOIL_SetScaledPixel(self, x, y, self->contentPalette[b >> ((~offset & 3) << 1) & 3]);
8700 		}
8701 	}
8702 	return true;
8703 }
8704 
RECOIL_SetMsx6DefaultPalette(RECOIL * self)8705 static void RECOIL_SetMsx6DefaultPalette(RECOIL *self)
8706 {
8707 	self->contentPalette[0] = 0;
8708 	self->contentPalette[1] = 2396708;
8709 	self->contentPalette[2] = 2415396;
8710 	self->contentPalette[3] = 7208813;
8711 }
8712 
RECOIL_DecodeSc6(RECOIL * self,const char * filename,uint8_t const * content,int contentLength)8713 static bool RECOIL_DecodeSc6(RECOIL *self, const char *filename, uint8_t const *content, int contentLength)
8714 {
8715 	int height = RECOIL_GetMsx128Height(self, content, contentLength);
8716 	if (height <= 0)
8717 		return false;
8718 	if (contentLength >= 30351)
8719 		RECOIL_SetMsxPalette(self, content, 30343, 4);
8720 	else
8721 		RECOIL_SetMsx6DefaultPalette(self);
8722 	if (!RECOIL_DecodeMsxSc(self, filename, content, 7, "S16", "s16", height, 6) && contentLength == 32775)
8723 		RECOIL_DecodeMsxSprites(self, content, 6, 30215, 30727);
8724 	return true;
8725 }
8726 
RECOIL_SetMsx6Palette(RECOIL * self,const char * filename)8727 static void RECOIL_SetMsx6Palette(RECOIL *self, const char *filename)
8728 {
8729 	uint8_t palette[8];
8730 	if (RECOIL_ReadCompanionFile(self, filename, "PL6", "pl6", palette, 8) == 8)
8731 		RECOIL_SetMsxPalette(self, palette, 0, 4);
8732 	else
8733 		RECOIL_SetMsx6DefaultPalette(self);
8734 }
8735 
RECOIL_DecodeSr6(RECOIL * self,const char * filename,uint8_t const * content,int contentLength)8736 static bool RECOIL_DecodeSr6(RECOIL *self, const char *filename, uint8_t const *content, int contentLength)
8737 {
8738 	int height = RECOIL_GetMsx128Height(self, content, contentLength);
8739 	if (height <= 0)
8740 		return false;
8741 	RECOIL_SetSize(self, 512, height << 1, RECOILResolution_MSX21X2);
8742 	RECOIL_SetMsx6Palette(self, filename);
8743 	return RECOIL_DecodeMsx6(self, content, 7);
8744 }
8745 
RECOIL_DecodeGl6(RECOIL * self,const char * filename,uint8_t const * content,int contentLength)8746 static bool RECOIL_DecodeGl6(RECOIL *self, const char *filename, uint8_t const *content, int contentLength)
8747 {
8748 	if (contentLength < 5)
8749 		return false;
8750 	int width = content[0] | content[1] << 8;
8751 	int height = content[2] | content[3] << 8;
8752 	if (contentLength < 4 + ((width * height + 3) >> 2) || !RECOIL_SetSize(self, width, height << 1, RECOILResolution_MSX21X2))
8753 		return false;
8754 	if (filename != NULL)
8755 		RECOIL_SetMsx6Palette(self, filename);
8756 	else {
8757 		self->contentPalette[0] = 16777215;
8758 		self->contentPalette[1] = 0;
8759 		self->contentPalette[3] = self->contentPalette[2] = 0;
8760 	}
8761 	return RECOIL_DecodeMsx6(self, content, 4);
8762 }
8763 
RECOIL_UnpackSr(uint8_t const * content,int contentLength,uint8_t * unpacked)8764 static uint8_t const *RECOIL_UnpackSr(uint8_t const *content, int contentLength, uint8_t *unpacked)
8765 {
8766 	if (contentLength < 7)
8767 		return NULL;
8768 	switch (content[0]) {
8769 	case 254:
8770 		if (contentLength < 54279 || RECOIL_GetMsxHeader(content) < 54271)
8771 			return NULL;
8772 		return content;
8773 	case 253:
8774 		if (7 + RECOIL_GetMsxHeader(content) != contentLength)
8775 			return NULL;
8776 		SrStream rle;
8777 		SrStream_Construct(&rle);
8778 		rle.base.base.base.content = content;
8779 		rle.base.base.base.contentOffset = 7;
8780 		rle.base.base.base.contentLength = contentLength;
8781 		RleStream_Unpack(&rle.base, unpacked, 7, 1, 54279);
8782 		return unpacked;
8783 	default:
8784 		return NULL;
8785 	}
8786 }
8787 
RECOIL_DecodeSc7(RECOIL * self,const char * filename,uint8_t const * content,int contentLength)8788 static bool RECOIL_DecodeSc7(RECOIL *self, const char *filename, uint8_t const *content, int contentLength)
8789 {
8790 	if (contentLength < 54279 || content[0] != 254 || RECOIL_GetMsxHeader(content) < 54271)
8791 		return false;
8792 	RECOIL_SetMsx2Palette(self, content, 64135, contentLength);
8793 	if (!RECOIL_DecodeMsxSc(self, filename, content, 7, "S17", "s17", 212, 7) && contentLength == 64167)
8794 		RECOIL_DecodeMsxSprites(self, content, 7, 64007, 61447);
8795 	return true;
8796 }
8797 
RECOIL_DecodeSri(RECOIL * self,const char * filename,uint8_t const * content,int contentLength)8798 static bool RECOIL_DecodeSri(RECOIL *self, const char *filename, uint8_t const *content, int contentLength)
8799 {
8800 	if (contentLength != 108544)
8801 		return false;
8802 	RECOIL_SetMsxCompanionPalette(self, filename, "PL7", "pl7");
8803 	RECOIL_SetSize(self, 512, 424, RECOILResolution_MSX21X1);
8804 	self->frames = 2;
8805 	RECOIL_DecodeNibbles(self, content, 0, 256);
8806 	return true;
8807 }
8808 
RECOIL_DecodeSr7(RECOIL * self,const char * filename,uint8_t const * content,int contentLength)8809 static bool RECOIL_DecodeSr7(RECOIL *self, const char *filename, uint8_t const *content, int contentLength)
8810 {
8811 	uint8_t unpacked[54279] = { 0 };
8812 	content = RECOIL_UnpackSr(content, contentLength, unpacked);
8813 	if (content == NULL)
8814 		return false;
8815 	RECOIL_SetMsxCompanionPalette(self, filename, "PL7", "pl7");
8816 	RECOIL_SetSize(self, 512, 424, RECOILResolution_MSX21X2);
8817 	RECOIL_DecodeNibbles(self, content, 7, 256);
8818 	return true;
8819 }
8820 
RECOIL_DecodeGl16(RECOIL * self,const char * filename,uint8_t const * content,int contentLength,RECOILResolution resolution,const char * upperExt,const char * lowerExt)8821 static bool RECOIL_DecodeGl16(RECOIL *self, const char *filename, uint8_t const *content, int contentLength, RECOILResolution resolution, const char *upperExt, const char *lowerExt)
8822 {
8823 	if (contentLength < 5)
8824 		return false;
8825 	int width = content[0] | content[1] << 8;
8826 	int height = content[2] | content[3] << 8;
8827 	if (contentLength < 4 + ((width * height + 1) >> 1) || !RECOIL_SetScaledSize(self, width, height, resolution))
8828 		return false;
8829 	RECOIL_SetMsxCompanionPalette(self, filename, upperExt, lowerExt);
8830 	for (int y = 0; y < height; y++)
8831 		for (int x = 0; x < width; x++)
8832 			RECOIL_SetScaledPixel(self, x, y, self->contentPalette[RECOIL_GetNibble(content, 4, y * width + x)]);
8833 	return true;
8834 }
8835 
RECOIL_DecodeGl5(RECOIL * self,const char * filename,uint8_t const * content,int contentLength)8836 static bool RECOIL_DecodeGl5(RECOIL *self, const char *filename, uint8_t const *content, int contentLength)
8837 {
8838 	return RECOIL_DecodeGl16(self, filename, content, contentLength, RECOILResolution_MSX21X1, "PL5", "pl5");
8839 }
8840 
RECOIL_DecodeGl7(RECOIL * self,const char * filename,uint8_t const * content,int contentLength)8841 static bool RECOIL_DecodeGl7(RECOIL *self, const char *filename, uint8_t const *content, int contentLength)
8842 {
8843 	return RECOIL_DecodeGl16(self, filename, content, contentLength, RECOILResolution_MSX21X2, "PL7", "pl7");
8844 }
8845 
RECOIL_SetSc8Palette(RECOIL * self)8846 static void RECOIL_SetSc8Palette(RECOIL *self)
8847 {
8848 	for (int c = 0; c < 256; c++) {
8849 		static const uint8_t BLUES[4] = { 0, 2, 4, 7 };
8850 		int rgb = (c & 28) << 14 | (c & 224) << 3 | BLUES[c & 3];
8851 		self->contentPalette[c] = rgb << 5 | rgb << 2 | (rgb >> 1 & 197379);
8852 	}
8853 }
8854 
RECOIL_DecodeSc8(RECOIL * self,const char * filename,uint8_t const * content,int contentLength)8855 static bool RECOIL_DecodeSc8(RECOIL *self, const char *filename, uint8_t const *content, int contentLength)
8856 {
8857 	uint8_t unpacked[54279] = { 0 };
8858 	content = RECOIL_UnpackSr(content, contentLength, unpacked);
8859 	if (content == NULL)
8860 		return false;
8861 	RECOIL_SetSc8Palette(self);
8862 	if (!RECOIL_DecodeMsxSc(self, filename, content, 7, "S18", "s18", 212, 8) && contentLength == 64167) {
8863 		static const uint8_t SPRITE_PALETTE[32] = { 0, 0, 2, 0, 48, 0, 50, 0, 0, 3, 2, 3, 48, 3, 50, 3,
8864 			114, 4, 7, 0, 112, 0, 119, 0, 0, 7, 7, 7, 112, 7, 119, 7 };
8865 		RECOIL_SetMsxPalette(self, SPRITE_PALETTE, 0, 16);
8866 		RECOIL_DecodeMsxSprites(self, content, 8, 64007, 61447);
8867 	}
8868 	return true;
8869 }
8870 
RECOIL_DecodeGl8(RECOIL * self,uint8_t const * content,int contentLength)8871 static bool RECOIL_DecodeGl8(RECOIL *self, uint8_t const *content, int contentLength)
8872 {
8873 	if (contentLength < 5)
8874 		return false;
8875 	int width = content[0] | content[1] << 8;
8876 	int height = content[2] | content[3] << 8;
8877 	if (contentLength != 4 + width * height || !RECOIL_SetSize(self, width, height, RECOILResolution_MSX21X1))
8878 		return false;
8879 	RECOIL_SetSc8Palette(self);
8880 	RECOIL_DecodeBytes(self, content, 4);
8881 	return true;
8882 }
8883 
RECOIL_DecodePct(RECOIL * self,uint8_t const * content,int contentLength)8884 static bool RECOIL_DecodePct(RECOIL *self, uint8_t const *content, int contentLength)
8885 {
8886 	if (contentLength < 384 || (!RECOIL_IsStringAt(content, 0, "DYNAMIC") && !RECOIL_IsStringAt(content, 0, "E U R O")) || !RECOIL_IsStringAt(content, 7, " PUBLISHER "))
8887 		return false;
8888 	int height;
8889 	int contentOffset;
8890 	if (RECOIL_IsStringAt(content, 18, "SCREEN")) {
8891 		height = 704;
8892 		contentOffset = 384;
8893 	}
8894 	else if (RECOIL_IsStringAt(content, 18, "FONT")) {
8895 		height = 160;
8896 		contentOffset = 512;
8897 	}
8898 	else
8899 		return false;
8900 	RECOIL_SetSize(self, 512, height << 1, RECOILResolution_MSX21X2);
8901 	CciStream rle;
8902 	CciStream_Construct(&rle);
8903 	rle.base.base.base.content = content;
8904 	rle.base.base.base.contentOffset = contentOffset;
8905 	rle.base.base.base.contentLength = contentLength;
8906 	for (int y = 0; y < height; y++) {
8907 		int b = 0;
8908 		for (int x = 0; x < 512; x++) {
8909 			if ((x & 7) == 0) {
8910 				b = RleStream_ReadRle(&rle.base);
8911 				if (b < 0)
8912 					return false;
8913 			}
8914 			int offset = (y << 10) + x;
8915 			self->pixels[offset + 512] = self->pixels[offset] = (b >> ((x ^ 3) & 7) & 1) == 0 ? 16777215 : 0;
8916 		}
8917 	}
8918 	return true;
8919 }
8920 
RECOIL_DecodeMsxYjk(const RECOIL * self,uint8_t const * content,int contentOffset,int x,bool usePalette)8921 static int RECOIL_DecodeMsxYjk(const RECOIL *self, uint8_t const *content, int contentOffset, int x, bool usePalette)
8922 {
8923 	int y = content[contentOffset + x] >> 3;
8924 	if (usePalette && (y & 1) != 0)
8925 		return self->contentPalette[y >> 1];
8926 	int rgb;
8927 	if ((x | 3) >= self->width) {
8928 		rgb = y * 65793;
8929 	}
8930 	else {
8931 		x = contentOffset + (x & -4);
8932 		int k = (content[x] & 7) | (content[x + 1] & 7) << 3;
8933 		int j = (content[x + 2] & 7) | (content[x + 3] & 7) << 3;
8934 		k -= (k & 32) << 1;
8935 		j -= (j & 32) << 1;
8936 		int r = y + j;
8937 		if (r < 0)
8938 			r = 0;
8939 		else if (r > 31)
8940 			r = 31;
8941 		int g = y + k;
8942 		if (g < 0)
8943 			g = 0;
8944 		else if (g > 31)
8945 			g = 31;
8946 		int b = (((5 * y - k) >> 1) - j) >> 1;
8947 		if (b < 0)
8948 			b = 0;
8949 		else if (b > 31)
8950 			b = 31;
8951 		rgb = r << 16 | g << 8 | b;
8952 	}
8953 	return rgb << 3 | (rgb >> 2 & 460551);
8954 }
8955 
RECOIL_DecodeMsxYjkScreen(RECOIL * self,uint8_t const * content,int contentOffset,bool usePalette)8956 static void RECOIL_DecodeMsxYjkScreen(RECOIL *self, uint8_t const *content, int contentOffset, bool usePalette)
8957 {
8958 	int width = RECOIL_GetOriginalWidth(self);
8959 	for (int y = 0; y < self->height; y++)
8960 		for (int x = 0; x < width; x++)
8961 			RECOIL_SetScaledPixel(self, x, y, RECOIL_DecodeMsxYjk(self, content, contentOffset + y * width, x, usePalette));
8962 }
8963 
RECOIL_DecodeSccSca(RECOIL * self,const char * filename,uint8_t const * content,int contentLength,int height,bool usePalette)8964 static void RECOIL_DecodeSccSca(RECOIL *self, const char *filename, uint8_t const *content, int contentLength, int height, bool usePalette)
8965 {
8966 	if (!RECOIL_DecodeMsxSc(self, filename, content, 7, usePalette ? "S1A" : "S1C", usePalette ? "s1a" : "s1c", height, usePalette ? 10 : 12) && contentLength == 64167 && content[0] == 254) {
8967 		RECOIL_SetMsxPalette(self, content, 64135, 16);
8968 		RECOIL_DecodeMsxSprites(self, content, 12, 64007, 61447);
8969 	}
8970 }
8971 
RECOIL_DecodeScc(RECOIL * self,const char * filename,uint8_t const * content,int contentLength)8972 static bool RECOIL_DecodeScc(RECOIL *self, const char *filename, uint8_t const *content, int contentLength)
8973 {
8974 	int height;
8975 	if (contentLength >= 49159 && content[0] == 254 && RECOIL_GetMsxHeader(content) == 49151)
8976 		height = 192;
8977 	else {
8978 		uint8_t unpacked[54279] = { 0 };
8979 		content = RECOIL_UnpackSr(content, contentLength, unpacked);
8980 		if (content == NULL)
8981 			return false;
8982 		height = 212;
8983 	}
8984 	RECOIL_DecodeSccSca(self, filename, content, contentLength, height, false);
8985 	return true;
8986 }
8987 
RECOIL_DecodeSca(RECOIL * self,const char * filename,uint8_t const * content,int contentLength)8988 static bool RECOIL_DecodeSca(RECOIL *self, const char *filename, uint8_t const *content, int contentLength)
8989 {
8990 	if (contentLength < 64167 || content[0] != 254 || RECOIL_GetMsxHeader(content) < 54271)
8991 		return false;
8992 	RECOIL_SetMsxPalette(self, content, 64135, 16);
8993 	RECOIL_DecodeSccSca(self, filename, content, contentLength, 212, true);
8994 	return true;
8995 }
8996 
RECOIL_DecodeGlYjk(RECOIL * self,const char * filename,uint8_t const * content,int contentLength)8997 static bool RECOIL_DecodeGlYjk(RECOIL *self, const char *filename, uint8_t const *content, int contentLength)
8998 {
8999 	if (contentLength < 8)
9000 		return false;
9001 	int width = content[0] | content[1] << 8;
9002 	int height = content[2] | content[3] << 8;
9003 	if (contentLength != 4 + width * height || !RECOIL_SetSize(self, width, height, RECOILResolution_MSX2_PLUS1X1))
9004 		return false;
9005 	if (filename != NULL)
9006 		RECOIL_SetMsxCompanionPalette(self, filename, "PLA", "pla");
9007 	RECOIL_DecodeMsxYjkScreen(self, content, 4, filename != NULL);
9008 	return true;
9009 }
9010 
RECOIL_SetG9bPalette(RECOIL * self,uint8_t const * content,int colors)9011 static bool RECOIL_SetG9bPalette(RECOIL *self, uint8_t const *content, int colors)
9012 {
9013 	for (int c = 0; c < colors; c++) {
9014 		int offset = 16 + c * 3;
9015 		int rgb = content[offset] << 16 | content[offset + 1] << 8 | content[offset + 2];
9016 		if ((rgb & 14737632) != 0)
9017 			return false;
9018 		self->contentPalette[c] = rgb << 3 | (rgb >> 2 & 460551);
9019 	}
9020 	return true;
9021 }
9022 
RECOIL_DecodeG9bUnpacked(RECOIL * self,uint8_t const * content,int depth)9023 static void RECOIL_DecodeG9bUnpacked(RECOIL *self, uint8_t const *content, int depth)
9024 {
9025 	int pixelsLength;
9026 	switch (depth) {
9027 	case 4:
9028 		RECOIL_DecodeNibbles(self, content, 64, (self->width + 1) >> 1);
9029 		break;
9030 	case 8:
9031 		RECOIL_DecodeBytes(self, content, 208);
9032 		break;
9033 	case 0:
9034 		pixelsLength = self->width * self->height;
9035 		for (int i = 0; i < pixelsLength; i++) {
9036 			int y = content[16 + i] >> 3;
9037 			int x = 16 + (i & -4);
9038 			int v = (content[x] & 7) | (content[x + 1] & 7) << 3;
9039 			int u = (content[x + 2] & 7) | (content[x + 3] & 7) << 3;
9040 			u -= (u & 32) << 1;
9041 			v -= (v & 32) << 1;
9042 			int r = y + u;
9043 			if (r < 0)
9044 				r = 0;
9045 			else if (r > 31)
9046 				r = 31;
9047 			int g = (((5 * y - v) >> 1) - u) >> 1;
9048 			if (g < 0)
9049 				g = 0;
9050 			else if (g > 31)
9051 				g = 31;
9052 			int b = y + v;
9053 			if (b < 0)
9054 				b = 0;
9055 			else if (b > 31)
9056 				b = 31;
9057 			int rgb = r << 16 | g << 8 | b;
9058 			self->pixels[i] = rgb << 3 | (rgb >> 2 & 460551);
9059 		}
9060 		break;
9061 	case 16:
9062 		pixelsLength = self->width * self->height;
9063 		for (int i = 0; i < pixelsLength; i++) {
9064 			int c = content[16 + (i << 1)] | content[17 + (i << 1)] << 8;
9065 			int rgb = (c & 992) << 14 | (c & 31744) << 1 | (c & 31) << 3;
9066 			self->pixels[i] = rgb | (rgb >> 5 & 460551);
9067 		}
9068 		break;
9069 	default:
9070 		assert(false);
9071 	}
9072 }
9073 
RECOIL_DecodeG9b(RECOIL * self,uint8_t const * content,int contentLength)9074 static bool RECOIL_DecodeG9b(RECOIL *self, uint8_t const *content, int contentLength)
9075 {
9076 	if (contentLength < 17 || content[0] != 71 || content[1] != 57 || content[2] != 66 || content[3] != 11 || content[4] != 0)
9077 		return false;
9078 	int depth = content[5];
9079 	int headerLength = 16 + content[7] * 3;
9080 	int width = content[8] | content[9] << 8;
9081 	int height = content[10] | content[11] << 8;
9082 	if (contentLength <= headerLength || !RECOIL_SetSize(self, width, height, RECOILResolution_MSX2_PLUS1X1))
9083 		return false;
9084 	int unpackedLength = headerLength + ((width * depth + 7) >> 3) * height;
9085 	switch (depth) {
9086 	case 4:
9087 		if (content[7] != 16 || !RECOIL_SetG9bPalette(self, content, 16))
9088 			return false;
9089 		break;
9090 	case 8:
9091 		switch (content[7]) {
9092 		case 0:
9093 			if (content[6] != 192 || (width & 3) != 0)
9094 				return false;
9095 			depth = 0;
9096 			break;
9097 		case 64:
9098 			if (!RECOIL_SetG9bPalette(self, content, 64))
9099 				return false;
9100 			for (int c = 64; c < 256; c++)
9101 				self->contentPalette[c] = 0;
9102 			break;
9103 		default:
9104 			return false;
9105 		}
9106 		break;
9107 	case 16:
9108 		break;
9109 	default:
9110 		return false;
9111 	}
9112 	switch (content[12]) {
9113 	case 0:
9114 		if (contentLength != unpackedLength)
9115 			return false;
9116 		RECOIL_DecodeG9bUnpacked(self, content, depth);
9117 		return true;
9118 	case 1:
9119 		;
9120 		uint8_t *unpacked = (uint8_t *) CiShared_Make(unpackedLength, sizeof(uint8_t), NULL, NULL);
9121 		G9bStream s;
9122 		G9bStream_Construct(&s);
9123 		s.base.base.content = content;
9124 		s.base.base.contentLength = contentLength;
9125 		bool ok = G9bStream_Unpack(&s, unpacked, headerLength, unpackedLength);
9126 		if (ok)
9127 			RECOIL_DecodeG9bUnpacked(self, unpacked, depth);
9128 		bool returnValue = ok;
9129 		CiShared_Release(unpacked);
9130 		return returnValue;
9131 	default:
9132 		return false;
9133 	}
9134 }
9135 
RECOIL_GetMigMode(int reg0,int reg1,int reg19,int length)9136 static int RECOIL_GetMigMode(int reg0, int reg1, int reg19, int length)
9137 {
9138 	return (reg0 & 14) | (reg1 & 24) << 1 | (reg19 & 24) << 3 | length << 8;
9139 }
9140 
RECOIL_DecodeMig(RECOIL * self,uint8_t const * content,int contentLength)9141 static bool RECOIL_DecodeMig(RECOIL *self, uint8_t const *content, int contentLength)
9142 {
9143 	if (contentLength < 16 || !RECOIL_IsStringAt(content, 0, "MSXMIG") || RECOIL_Get32LittleEndian(content, 6) != contentLength - 6)
9144 		return false;
9145 	uint8_t unpacked[108800];
9146 	MigStream s;
9147 	MigStream_Construct(&s);
9148 	s.base.base.content = content;
9149 	s.base.base.contentLength = contentLength;
9150 	int unpackedLength = MigStream_Unpack(&s, unpacked);
9151 	int colors = 0;
9152 	uint8_t registers[256] = { 0 };
9153 	for (int unpackedOffset = 0; unpackedOffset < unpackedLength;) {
9154 		switch (unpacked[unpackedOffset]) {
9155 		case 0:
9156 			if (unpackedOffset + 1 >= unpackedLength)
9157 				return false;
9158 			int c = unpacked[unpackedOffset + 1];
9159 			if (unpackedOffset + 2 + c * 3 > unpackedLength)
9160 				return false;
9161 			for (int i = 0; i < c; i++) {
9162 				int offset = unpackedOffset + 2 + i * 3;
9163 				int r = unpacked[offset];
9164 				int m = unpacked[offset + 2];
9165 				registers[r] = (uint8_t) ((registers[r] & ~m) | (unpacked[offset + 1] & m));
9166 			}
9167 			unpackedOffset += 2 + c * 3;
9168 			break;
9169 		case 1:
9170 			if (unpackedOffset + 2 >= unpackedLength || unpacked[unpackedOffset + 1] != 0)
9171 				return false;
9172 			colors = unpacked[unpackedOffset + 2];
9173 			if (unpackedOffset + 3 + (colors << 1) > unpackedLength)
9174 				return false;
9175 			RECOIL_SetMsxPalette(self, unpacked, unpackedOffset + 3, colors);
9176 			unpackedOffset += 3 + (colors << 1);
9177 			break;
9178 		case 2:
9179 			if (unpackedOffset + 7 >= unpackedLength || unpacked[unpackedOffset + 1] != 0 || unpacked[unpackedOffset + 2] != 0 || unpacked[unpackedOffset + 3] != 0 || unpacked[unpackedOffset + 4] != 0 || unpacked[unpackedOffset + 6] != 0)
9180 				return false;
9181 			int length = unpacked[unpackedOffset + 5];
9182 			unpackedOffset += 7;
9183 			int interlaceMask;
9184 			switch (registers[9] & 12) {
9185 			case 0:
9186 				if (unpackedOffset + (length << 8) + 1 != unpackedLength)
9187 					return false;
9188 				interlaceMask = 0;
9189 				break;
9190 			case 12:
9191 				if (unpackedOffset + (length << 9) + 7 + 1 != unpackedLength || unpacked[unpackedOffset + (length << 8)] != 2 || unpacked[unpackedOffset + (length << 8) + 1] != 0 || unpacked[unpackedOffset + (length << 8) + 4] != 0 || unpacked[unpackedOffset + (length << 8) + 5] != length || unpacked[unpackedOffset + (length << 8) + 6] != 0)
9192 					return false;
9193 				interlaceMask = 1;
9194 				break;
9195 			default:
9196 				return false;
9197 			}
9198 			int mode;
9199 			switch (RECOIL_GetMigMode(registers[0], registers[1], registers[25], length)) {
9200 			case 14338:
9201 				if (colors < 16 || interlaceMask != 0)
9202 					return false;
9203 				RECOIL_DecodeSc2Sc4(self, unpacked, unpackedOffset, RECOILResolution_MSX21X1);
9204 				return true;
9205 			case 1552:
9206 				if (colors < 16 || interlaceMask != 0)
9207 					return false;
9208 				RECOIL_DecodeSc3Screen(self, unpacked, unpackedOffset, false);
9209 				return true;
9210 			case 27142:
9211 				if (colors < 16)
9212 					return false;
9213 				mode = 5;
9214 				break;
9215 			case 27144:
9216 				if (colors < 4)
9217 					return false;
9218 				mode = 6;
9219 				break;
9220 			case 54282:
9221 				if (colors < 16)
9222 					return false;
9223 				mode = 7;
9224 				break;
9225 			case 54286:
9226 				RECOIL_SetSc8Palette(self);
9227 				mode = 8;
9228 				break;
9229 			case 54478:
9230 				if (colors < 16)
9231 					return false;
9232 				mode = 10;
9233 				break;
9234 			case 54350:
9235 				mode = 12;
9236 				break;
9237 			default:
9238 				return false;
9239 			}
9240 			RECOIL_DecodeMsxScreen(self, unpacked, unpackedOffset, unpacked, 212, mode, interlaceMask);
9241 			return true;
9242 		default:
9243 			return false;
9244 		}
9245 	}
9246 	return false;
9247 }
9248 
RECOIL_DecodeHgr(RECOIL * self,uint8_t const * content,int contentLength)9249 static bool RECOIL_DecodeHgr(RECOIL *self, uint8_t const *content, int contentLength)
9250 {
9251 	if (contentLength < 8184)
9252 		return false;
9253 	RECOIL_SetSize(self, 280, 192, RECOILResolution_APPLE_I_I1X1);
9254 	for (int y = 0; y < 192; y++) {
9255 		int lineOffset = (y & 7) << 10 | (y & 56) << 4 | (y >> 6) * 40;
9256 		for (int x = 0; x < 280; x++) {
9257 			int c = content[lineOffset + x / 7] >> x % 7 & 1;
9258 			if (c != 0)
9259 				c = 16777215;
9260 			self->pixels[y * 280 + x] = c;
9261 		}
9262 	}
9263 	return true;
9264 }
9265 
RECOIL_DecodeAppleIIDhr(RECOIL * self,uint8_t const * content,int contentLength)9266 static bool RECOIL_DecodeAppleIIDhr(RECOIL *self, uint8_t const *content, int contentLength)
9267 {
9268 	if (contentLength != 16384)
9269 		return false;
9270 	RECOIL_SetSize(self, 560, 384, RECOILResolution_APPLE_I_IE1X2);
9271 	for (int y = 0; y < 192; y++) {
9272 		int lineOffset = (y & 7) << 10 | (y & 56) << 4 | (y >> 6) * 40;
9273 		for (int x = 0; x < 560; x++) {
9274 			int b = x / 7;
9275 			int c = content[((b & 1) << 13) + lineOffset + (b >> 1)] >> x % 7 & 1;
9276 			if (c != 0)
9277 				c = 16777215;
9278 			int pixelsOffset = y * 1120 + x;
9279 			self->pixels[pixelsOffset + 560] = self->pixels[pixelsOffset] = c;
9280 		}
9281 	}
9282 	return true;
9283 }
9284 
RECOIL_SetAppleIIGSPalette(RECOIL * self,uint8_t const * content,int contentOffset,int reverse)9285 static void RECOIL_SetAppleIIGSPalette(RECOIL *self, uint8_t const *content, int contentOffset, int reverse)
9286 {
9287 	for (int c = 0; c < 16; c++) {
9288 		int offset = contentOffset + ((c ^ reverse) << 1);
9289 		int gb = content[offset];
9290 		int r = content[offset + 1] & 15;
9291 		int g = gb >> 4;
9292 		int b = gb & 15;
9293 		int rgb = r << 16 | g << 8 | b;
9294 		rgb |= rgb << 4;
9295 		self->contentPalette[c] = rgb;
9296 	}
9297 }
9298 
RECOIL_DecodeShrLine(RECOIL * self,uint8_t const * content,int y)9299 static void RECOIL_DecodeShrLine(RECOIL *self, uint8_t const *content, int y)
9300 {
9301 	for (int x = 0; x < 320; x++)
9302 		self->pixels[y * 320 + x] = self->contentPalette[RECOIL_GetNibble(content, y * 160, x)];
9303 }
9304 
RECOIL_DecodeAppleIIShr(RECOIL * self,uint8_t const * content,int contentLength)9305 static bool RECOIL_DecodeAppleIIShr(RECOIL *self, uint8_t const *content, int contentLength)
9306 {
9307 	if (contentLength != 32768)
9308 		return false;
9309 	RECOIL_SetSize(self, 320, 200, RECOILResolution_APPLE_I_I_G_S1X1);
9310 	for (int y = 0; y < 200; y++) {
9311 		RECOIL_SetAppleIIGSPalette(self, content, 32256 + ((content[32000 + y] & 15) << 5), 0);
9312 		RECOIL_DecodeShrLine(self, content, y);
9313 	}
9314 	return true;
9315 }
9316 
RECOIL_DecodeSh3(RECOIL * self,uint8_t const * content,int contentLength)9317 static bool RECOIL_DecodeSh3(RECOIL *self, uint8_t const *content, int contentLength)
9318 {
9319 	if (contentLength != 38400)
9320 		return false;
9321 	RECOIL_SetSize(self, 320, 200, RECOILResolution_APPLE_I_I_G_S1X1);
9322 	for (int y = 0; y < 200; y++) {
9323 		RECOIL_SetAppleIIGSPalette(self, content, 32000 + (y << 5), 15);
9324 		RECOIL_DecodeShrLine(self, content, y);
9325 	}
9326 	return true;
9327 }
9328 
RECOIL_DrawSprByte(RECOIL * self,int x1,int y,int b)9329 static void RECOIL_DrawSprByte(RECOIL *self, int x1, int y, int b)
9330 {
9331 	for (int x = 0; x < 8; x++) {
9332 		if ((b >> (7 - x) & 1) != 0)
9333 			self->pixels[y * 320 + x1 + x] = 16777215;
9334 	}
9335 }
9336 
RECOIL_DecodeAppleSpr(RECOIL * self,uint8_t const * content,int contentLength)9337 static bool RECOIL_DecodeAppleSpr(RECOIL *self, uint8_t const *content, int contentLength)
9338 {
9339 	RECOIL_SetSize(self, 320, 200, RECOILResolution_APPLE_I_I1X1);
9340 	for (int i = 0; i < 64000; i++)
9341 		self->pixels[i] = 0;
9342 	SprStream s;
9343 	s.base.content = content;
9344 	s.base.contentOffset = 0;
9345 	s.base.contentLength = contentLength;
9346 	for (;;) {
9347 		int cols = SprStream_ReadInt(&s);
9348 		if (cols < 0)
9349 			return false;
9350 		int rows = SprStream_ReadInt(&s);
9351 		if (rows < 0)
9352 			return false;
9353 		int order = SprStream_ReadInt(&s);
9354 		if (order < 0)
9355 			return false;
9356 		int x = SprStream_ReadInt(&s);
9357 		if (x < 0)
9358 			return false;
9359 		int y = SprStream_ReadInt(&s);
9360 		if (y < 0)
9361 			return false;
9362 		if (rows == 0)
9363 			break;
9364 		if (cols == 0 || x + (cols << 3) > 320 || y + rows > 200)
9365 			return false;
9366 		if (order == 2) {
9367 			for (int col = 0; col < cols; col++) {
9368 				for (int row = 0; row < rows; row++) {
9369 					int b = SprStream_ReadInt(&s);
9370 					if (b < 0)
9371 						return false;
9372 					RECOIL_DrawSprByte(self, x + (col << 3), y + row, b);
9373 				}
9374 			}
9375 		}
9376 		else {
9377 			for (int row = 0; row < rows; row++) {
9378 				for (int col = 0; col < cols; col++) {
9379 					int b = SprStream_ReadInt(&s);
9380 					if (b < 0)
9381 						return false;
9382 					RECOIL_DrawSprByte(self, x + (col << 3), y + row, b);
9383 				}
9384 			}
9385 		}
9386 	}
9387 	return true;
9388 }
9389 
RECOIL_DecodePackBytes(RECOIL * self,PackBytesStream * stream,int pixelsOffset,int unpackedBytes)9390 static bool RECOIL_DecodePackBytes(RECOIL *self, PackBytesStream *stream, int pixelsOffset, int unpackedBytes)
9391 {
9392 	for (int x = 0; x < unpackedBytes; x++) {
9393 		int b = PackBytesStream_ReadUnpacked(stream);
9394 		if (b < 0)
9395 			return false;
9396 		if (self->resolution == RECOILResolution_APPLE_I_I_G_S1X2) {
9397 			int offset = (pixelsOffset << 1) + (x << 2);
9398 			self->pixels[offset + self->width] = self->pixels[offset] = self->contentPalette[8 + (b >> 6)];
9399 			self->pixels[offset + self->width + 1] = self->pixels[offset + 1] = self->contentPalette[12 + (b >> 4 & 3)];
9400 			self->pixels[offset + self->width + 2] = self->pixels[offset + 2] = self->contentPalette[b >> 2 & 3];
9401 			self->pixels[offset + self->width + 3] = self->pixels[offset + 3] = self->contentPalette[4 + (b & 3)];
9402 		}
9403 		else {
9404 			self->pixels[pixelsOffset + (x << 1)] = self->contentPalette[b >> 4];
9405 			self->pixels[pixelsOffset + (x << 1) + 1] = self->contentPalette[b & 15];
9406 		}
9407 	}
9408 	return true;
9409 }
9410 
RECOIL_DecodePaintworks(RECOIL * self,uint8_t const * content,int contentLength)9411 static bool RECOIL_DecodePaintworks(RECOIL *self, uint8_t const *content, int contentLength)
9412 {
9413 	if (contentLength < 1041)
9414 		return false;
9415 	RECOIL_SetSize(self, 320, 396, RECOILResolution_APPLE_I_I_G_S1X1);
9416 	RECOIL_SetAppleIIGSPalette(self, content, 0, 0);
9417 	PackBytesStream stream;
9418 	PackBytesStream_Construct(&stream);
9419 	stream.base.content = content;
9420 	stream.base.contentOffset = 546;
9421 	stream.base.contentLength = contentLength;
9422 	return RECOIL_DecodePackBytes(self, &stream, 0, 63360);
9423 }
9424 
RECOIL_Decode3201(RECOIL * self,uint8_t const * content,int contentLength)9425 static bool RECOIL_Decode3201(RECOIL *self, uint8_t const *content, int contentLength)
9426 {
9427 	if (contentLength < 6654 || content[0] != 193 || content[1] != 208 || content[2] != 208 || content[3] != 0)
9428 		return false;
9429 	RECOIL_SetSize(self, 320, 200, RECOILResolution_APPLE_I_I_G_S1X1);
9430 	PackBytesStream stream;
9431 	PackBytesStream_Construct(&stream);
9432 	stream.base.content = content;
9433 	stream.base.contentOffset = 6404;
9434 	stream.base.contentLength = contentLength;
9435 	for (int y = 0; y < 200; y++) {
9436 		RECOIL_SetAppleIIGSPalette(self, content, 4 + (y << 5), 15);
9437 		if (!RECOIL_DecodePackBytes(self, &stream, y * 320, 160))
9438 			return false;
9439 	}
9440 	return true;
9441 }
9442 
RECOIL_DecodeApfShr(RECOIL * self,uint8_t const * content,int contentLength)9443 static bool RECOIL_DecodeApfShr(RECOIL *self, uint8_t const *content, int contentLength)
9444 {
9445 	if (contentLength < 1249 || content[4] != 4 || !RECOIL_IsStringAt(content, 5, "MAIN") || content[14] != 0)
9446 		return false;
9447 	int paletteCount = content[13];
9448 	if (paletteCount > 16)
9449 		return false;
9450 	int dirOffset = 17 + (paletteCount << 5);
9451 	if (dirOffset >= contentLength)
9452 		return false;
9453 	int mode = content[9] & 240;
9454 	int width = content[11] | content[12] << 8;
9455 	int height = content[dirOffset - 2] | content[dirOffset - 1] << 8;
9456 	int bytesPerLine;
9457 	switch (mode) {
9458 	case 0:
9459 		if ((width & 1) != 0 || !RECOIL_SetSize(self, width, height, RECOILResolution_APPLE_I_I_G_S1X1))
9460 			return false;
9461 		bytesPerLine = width >> 1;
9462 		break;
9463 	case 128:
9464 		if ((width & 3) != 0 || !RECOIL_SetSize(self, width, height << 1, RECOILResolution_APPLE_I_I_G_S1X2))
9465 			return false;
9466 		bytesPerLine = width >> 2;
9467 		break;
9468 	default:
9469 		return false;
9470 	}
9471 	int multipalOffset = -1;
9472 	int contentOffset = 0;
9473 	if (height == 200) {
9474 		for (int chunkLength = RECOIL_Get32LittleEndian(content, 0);;) {
9475 			if (chunkLength <= 0)
9476 				return false;
9477 			contentOffset += chunkLength;
9478 			if (contentOffset < 0 || contentOffset + 6415 > contentLength)
9479 				break;
9480 			chunkLength = RECOIL_Get32LittleEndian(content, contentOffset);
9481 			if (chunkLength == 6415 && content[contentOffset + 4] == 8 && RECOIL_IsStringAt(content, contentOffset + 5, "MULTIPAL") && content[contentOffset + 13] == 200 && content[contentOffset + 14] == 0) {
9482 				multipalOffset = contentOffset + 15;
9483 				break;
9484 			}
9485 		}
9486 	}
9487 	contentOffset = dirOffset + (height << 2);
9488 	if (contentOffset >= contentLength)
9489 		return false;
9490 	PackBytesStream stream;
9491 	PackBytesStream_Construct(&stream);
9492 	stream.base.content = content;
9493 	stream.base.contentOffset = contentOffset;
9494 	stream.base.contentLength = contentLength;
9495 	for (int y = 0; y < height; y++) {
9496 		if (multipalOffset >= 0)
9497 			RECOIL_SetAppleIIGSPalette(self, content, multipalOffset + (y << 5), 0);
9498 		else {
9499 			int lineMode = content[dirOffset + (y << 2) + 2];
9500 			int palette = lineMode & 15;
9501 			if ((lineMode & 240) != mode || palette >= paletteCount || content[dirOffset + (y << 2) + 3] != 0)
9502 				return false;
9503 			RECOIL_SetAppleIIGSPalette(self, content, 15 + (palette << 5), 0);
9504 		}
9505 		if (!RECOIL_DecodePackBytes(self, &stream, y * width, bytesPerLine))
9506 			return false;
9507 	}
9508 	return true;
9509 }
9510 
RECOIL_DecodeScs4(RECOIL * self,uint8_t const * content,int contentLength)9511 static bool RECOIL_DecodeScs4(RECOIL *self, uint8_t const *content, int contentLength)
9512 {
9513 	if (contentLength != 24617 || content[24616] != 255)
9514 		return false;
9515 	for (int i = 0; i < 16; i++) {
9516 		int c = content[24576 + i];
9517 		int rgb = 0;
9518 		if ((c & 1) != 0)
9519 			rgb |= 73;
9520 		if ((c & 2) != 0)
9521 			rgb |= 4784128;
9522 		if ((c & 4) != 0)
9523 			rgb |= 18688;
9524 		if ((c & 8) != 0)
9525 			rgb |= 2368548;
9526 		if ((c & 16) != 0)
9527 			rgb |= 146;
9528 		if ((c & 32) != 0)
9529 			rgb |= 9568256;
9530 		if ((c & 64) != 0)
9531 			rgb |= 37376;
9532 		self->contentPalette[i] = rgb;
9533 	}
9534 	RECOIL_SetSize(self, 256, 192, RECOILResolution_SAM_COUPE1X1);
9535 	RECOIL_DecodeNibbles(self, content, 0, 128);
9536 	return true;
9537 }
9538 
RECOIL_GetX68KColor(int color)9539 static int RECOIL_GetX68KColor(int color)
9540 {
9541 	int rgb = (color & 1984) << 13 | (color & 63488) | (color & 62) << 2;
9542 	if ((color & 1) != 0)
9543 		rgb |= 263172;
9544 	return rgb | (rgb >> 6 & 197379);
9545 }
9546 
RECOIL_DecodeX68KPicChain(RECOIL * self,BitStream * stream,int pixelsOffset,int color)9547 static bool RECOIL_DecodeX68KPicChain(RECOIL *self, BitStream *stream, int pixelsOffset, int color)
9548 {
9549 	for (;;) {
9550 		switch (BitStream_ReadBits(stream, 2)) {
9551 		case 0:
9552 			switch (stream->vtbl->readBit(stream)) {
9553 			case 0:
9554 				return true;
9555 			case 1:
9556 				break;
9557 			default:
9558 				return false;
9559 			}
9560 			switch (stream->vtbl->readBit(stream)) {
9561 			case 0:
9562 				pixelsOffset -= 2;
9563 				break;
9564 			case 1:
9565 				pixelsOffset += 2;
9566 				break;
9567 			default:
9568 				return false;
9569 			}
9570 			break;
9571 		case 1:
9572 			pixelsOffset--;
9573 			break;
9574 		case 2:
9575 			break;
9576 		case 3:
9577 			pixelsOffset++;
9578 			break;
9579 		default:
9580 			return false;
9581 		}
9582 		pixelsOffset += self->width;
9583 		if (pixelsOffset >= self->width * self->height)
9584 			return false;
9585 		self->pixels[pixelsOffset] = color;
9586 	}
9587 }
9588 
RECOIL_DecodeX68KPicScreen(RECOIL * self,X68KPicStream * stream,int pixelsLength,int platform,int depth)9589 static bool RECOIL_DecodeX68KPicScreen(RECOIL *self, X68KPicStream *stream, int pixelsLength, int platform, int depth)
9590 {
9591 	for (int pixelsOffset = 0; pixelsOffset < pixelsLength; pixelsOffset++)
9592 		self->pixels[pixelsOffset] = -1;
9593 	RecentInts colors;
9594 	RecentInts_Construct(&colors);
9595 	int color = 0;
9596 	for (int pixelsOffset = -1;;) {
9597 		int length = X68KPicStream_ReadLength(stream);
9598 		if (length < 0)
9599 			return false;
9600 		while (--length > 0) {
9601 			int got = self->pixels[++pixelsOffset];
9602 			if (got < 0)
9603 				self->pixels[pixelsOffset] = color;
9604 			else
9605 				color = got;
9606 			if (pixelsOffset >= pixelsLength - 1)
9607 				return true;
9608 		}
9609 		if (depth <= 8) {
9610 			color = BitStream_ReadBits(&stream->base, depth);
9611 			if (color < 0)
9612 				return false;
9613 			color = self->contentPalette[color];
9614 		}
9615 		else {
9616 			switch (stream->base.vtbl->readBit(&stream->base)) {
9617 			case 0:
9618 				color = BitStream_ReadBits(&stream->base, depth);
9619 				if (color < 0)
9620 					return false;
9621 				switch (platform) {
9622 				case 0:
9623 					if (depth == 15)
9624 						color <<= 1;
9625 					color = RECOIL_GetX68KColor(color);
9626 					break;
9627 				case 17:
9628 					color = RECOIL_GetG6R5B5Color(color);
9629 					break;
9630 				default:
9631 					break;
9632 				}
9633 				RecentInts_Add(&colors, color);
9634 				break;
9635 			case 1:
9636 				color = BitStream_ReadBits(&stream->base, 7);
9637 				if (color < 0)
9638 					return false;
9639 				color = RecentInts_Get(&colors, color);
9640 				break;
9641 			default:
9642 				return false;
9643 			}
9644 		}
9645 		self->pixels[++pixelsOffset] = color;
9646 		if (pixelsOffset >= pixelsLength - 1)
9647 			return true;
9648 		switch (stream->base.vtbl->readBit(&stream->base)) {
9649 		case 0:
9650 			break;
9651 		case 1:
9652 			if (!RECOIL_DecodeX68KPicChain(self, &stream->base, pixelsOffset, color))
9653 				return false;
9654 			break;
9655 		default:
9656 			return false;
9657 		}
9658 	}
9659 }
9660 
RECOIL_DecodeX68KPic(RECOIL * self,uint8_t const * content,int contentLength)9661 static bool RECOIL_DecodeX68KPic(RECOIL *self, uint8_t const *content, int contentLength)
9662 {
9663 	if (contentLength < 14 || content[0] != 80 || content[1] != 73 || content[2] != 67)
9664 		return false;
9665 	RECOILResolution resolution = RECOIL_IsStringAt(content, 3, "/MM/") ? RECOILResolution_MSX21X1 : RECOILResolution_X68_K1X1;
9666 	X68KPicStream stream;
9667 	X68KPicStream_Construct(&stream);
9668 	stream.base.base.content = content;
9669 	stream.base.base.contentOffset = 3;
9670 	stream.base.base.contentLength = contentLength;
9671 	for (;;) {
9672 		int b = Stream_ReadByte(&stream.base.base);
9673 		if (b < 0)
9674 			return false;
9675 		if (b == 26)
9676 			break;
9677 		if (b == 47 && resolution == RECOILResolution_MSX21X1 && stream.base.base.contentOffset + 4 < contentLength && content[stream.base.base.contentOffset] == 77 && content[stream.base.base.contentOffset + 1] == 83) {
9678 			b = content[stream.base.base.contentOffset + 2];
9679 			if (b >= 65 && b <= 67)
9680 				resolution = RECOILResolution_MSX2_PLUS1X1;
9681 		}
9682 	}
9683 	if (!Stream_SkipUntilByte(&stream.base.base, 0))
9684 		return false;
9685 	int platform = BitStream_ReadBits(&stream.base, 16);
9686 	int depth = BitStream_ReadBits(&stream.base, 16);
9687 	int width = BitStream_ReadBits(&stream.base, 16);
9688 	int height = BitStream_ReadBits(&stream.base, 16);
9689 	int pixelsLength = width * height;
9690 	switch (platform) {
9691 	case 0:
9692 		if (!RECOIL_SetSize(self, width, height, resolution))
9693 			return false;
9694 		break;
9695 	case 17:
9696 		return depth == 16 && RECOIL_SetSize(self, width, height, RECOILResolution_PC88_VA1X1) && RECOIL_DecodeX68KPicScreen(self, &stream, pixelsLength, 17, 16);
9697 	case 33:
9698 		if (depth != 16 || !RECOIL_SetSize(self, width, height << 1, RECOILResolution_PC88_VA1X1) || !RECOIL_DecodeX68KPicScreen(self, &stream, pixelsLength, 33, 16))
9699 			return false;
9700 		for (int offset = pixelsLength - 1; offset >= 0; offset--) {
9701 			int color = self->pixels[offset];
9702 			self->pixels[(offset << 1) + 1] = RECOIL_GetG3R3B2Color(color >> 8);
9703 			self->pixels[offset << 1] = RECOIL_GetG3R3B2Color(color & 255);
9704 		}
9705 		return true;
9706 	case 2:
9707 		if (!RECOIL_SetSize(self, width, height, RECOILResolution_FM_TOWNS1X1))
9708 			return false;
9709 		stream.base.base.contentOffset += 6;
9710 		break;
9711 	case 31:
9712 		if (!RECOIL_SetSize(self, width, height, RECOILResolution_X68_K1X1))
9713 			return false;
9714 		stream.base.base.contentOffset += 6;
9715 		break;
9716 	default:
9717 		return false;
9718 	}
9719 	switch (depth) {
9720 	case 4:
9721 	case 8:
9722 		for (int c = 0; c < 1 << depth; c++) {
9723 			int color = BitStream_ReadBits(&stream.base, 16);
9724 			if (color < 0)
9725 				return false;
9726 			self->contentPalette[c] = RECOIL_GetX68KColor(color);
9727 		}
9728 		break;
9729 	case 15:
9730 	case 16:
9731 		break;
9732 	default:
9733 		return false;
9734 	}
9735 	return RECOIL_DecodeX68KPicScreen(self, &stream, pixelsLength, 0, depth);
9736 }
9737 
RECOIL_SetPc88EightPixels(RECOIL * self,int column,int y,int b)9738 static void RECOIL_SetPc88EightPixels(RECOIL *self, int column, int y, int b)
9739 {
9740 	for (int x = 0; x < 8; x++) {
9741 		int offset = y * 1280 + column + x;
9742 		self->pixels[offset + 640] = self->pixels[offset] = (b >> (7 - x) & 65793) * 255;
9743 	}
9744 }
9745 
RECOIL_DecodeDaVinci(RECOIL * self,uint8_t const * content,int contentLength)9746 static bool RECOIL_DecodeDaVinci(RECOIL *self, uint8_t const *content, int contentLength)
9747 {
9748 	if ((contentLength & 255) != 0)
9749 		return false;
9750 	RECOIL_SetSize(self, 640, 400, RECOILResolution_PC881X2);
9751 	DaVinciStream rle;
9752 	DaVinciStream_Construct(&rle);
9753 	rle.base.base.base.content = content;
9754 	rle.base.base.base.contentOffset = 0;
9755 	rle.base.base.base.contentLength = contentLength;
9756 	for (int y = 0; y < 200; y++) {
9757 		for (int column = 0; column < 640; column += 8) {
9758 			int b = RleStream_ReadRle(&rle.base);
9759 			if (b < 0)
9760 				return false;
9761 			RECOIL_SetPc88EightPixels(self, column, y, b);
9762 		}
9763 	}
9764 	return rle.base.repeatCount == 0 && contentLength - rle.base.base.base.contentOffset < 256;
9765 }
9766 
RECOIL_DecodeArtMaster88(RECOIL * self,uint8_t const * content,int contentLength)9767 static bool RECOIL_DecodeArtMaster88(RECOIL *self, uint8_t const *content, int contentLength)
9768 {
9769 	if (contentLength < 42 || !RECOIL_IsStringAt(content, 0, "SS_SIF    0.0") || content[17] != 32 || content[19] != 66 || content[20] != 82 || content[21] != 71 || content[24] != 128 || content[25] != 2 || content[26] != 200 || content[27] != 0)
9770 		return false;
9771 	RECOIL_SetSize(self, 640, 400, RECOILResolution_PC881X2);
9772 	ArtMaster88Stream rle;
9773 	ArtMaster88Stream_Construct(&rle);
9774 	rle.base.base.base.content = content;
9775 	rle.base.base.base.contentOffset = 40;
9776 	rle.base.base.base.contentLength = contentLength;
9777 	if (content[16] == 73 && !ArtMaster88Stream_SkipChunk(&rle))
9778 		return false;
9779 	if (content[18] == 66 && !ArtMaster88Stream_SkipChunk(&rle))
9780 		return false;
9781 	uint8_t blue[16000];
9782 	uint8_t red[16000];
9783 	if (!RleStream_Unpack(&rle.base, blue, 0, 1, 16000) || !RleStream_Unpack(&rle.base, red, 0, 1, 16000))
9784 		return false;
9785 	int offset = 0;
9786 	for (int y = 0; y < 200; y++) {
9787 		for (int column = 0; column < 640; column += 8) {
9788 			int g = RleStream_ReadRle(&rle.base);
9789 			if (g < 0)
9790 				return false;
9791 			RECOIL_SetPc88EightPixels(self, column, y, red[offset] << 16 | g << 8 | blue[offset]);
9792 			offset++;
9793 		}
9794 	}
9795 	return true;
9796 }
9797 
RECOIL_DecodeNl3(RECOIL * self,uint8_t const * content,int contentLength)9798 static bool RECOIL_DecodeNl3(RECOIL *self, uint8_t const *content, int contentLength)
9799 {
9800 	Nl3Stream stream;
9801 	Nl3Stream_Construct(&stream);
9802 	stream.base.base.base.content = content;
9803 	stream.base.base.base.contentOffset = 0;
9804 	stream.base.base.base.contentLength = contentLength;
9805 	for (int i = 0; i < 64; i++) {
9806 		int c = ((const RleStreamVtbl *) stream.base.base.vtbl)->readValue(&stream.base);
9807 		if (c < 0 || c > 127)
9808 			return false;
9809 		c |= ((const RleStreamVtbl *) stream.base.base.vtbl)->readValue(&stream.base) << 7;
9810 		if (c < 0 || c >= 729)
9811 			return false;
9812 		self->contentPalette[i] = RECOIL_Get729Color(c);
9813 	}
9814 	RECOIL_SetSize(self, 160, 100, RECOILResolution_PC981X1);
9815 	for (int x = 0; x < 160; x++) {
9816 		for (int y = 0; y < 100; y++) {
9817 			int b = RleStream_ReadRle(&stream.base);
9818 			if (b < 0)
9819 				return false;
9820 			self->pixels[y * 160 + x] = self->contentPalette[b];
9821 		}
9822 	}
9823 	return true;
9824 }
9825 
RECOIL_DecodeMl1Chain(RECOIL * self,X68KPicStream * stream,int pixelsOffset,int rgb)9826 static bool RECOIL_DecodeMl1Chain(RECOIL *self, X68KPicStream *stream, int pixelsOffset, int rgb)
9827 {
9828 	for (;;) {
9829 		switch (stream->base.vtbl->readBit(&stream->base)) {
9830 		case 0:
9831 			break;
9832 		case 1:
9833 			switch (BitStream_ReadBits(&stream->base, 2)) {
9834 			case 0:
9835 				pixelsOffset++;
9836 				break;
9837 			case 1:
9838 				pixelsOffset--;
9839 				break;
9840 			case 2:
9841 				return true;
9842 			case 3:
9843 				switch (stream->base.vtbl->readBit(&stream->base)) {
9844 				case 0:
9845 					pixelsOffset += 2;
9846 					break;
9847 				case 1:
9848 					pixelsOffset -= 2;
9849 					break;
9850 				default:
9851 					return false;
9852 				}
9853 				break;
9854 			default:
9855 				return false;
9856 			}
9857 			break;
9858 		default:
9859 			return false;
9860 		}
9861 		pixelsOffset += self->width;
9862 		if (pixelsOffset < 0 || pixelsOffset >= self->width * self->height)
9863 			return false;
9864 		self->pixels[pixelsOffset] = rgb;
9865 	}
9866 }
9867 
RECOIL_DecodeMl1Mx1(RECOIL * self,X68KPicStream * stream,int imageOffset)9868 static int RECOIL_DecodeMl1Mx1(RECOIL *self, X68KPicStream *stream, int imageOffset)
9869 {
9870 	if (BitStream_ReadBits(&stream->base, 32) != 825241626 || BitStream_ReadBits(&stream->base, 32) < 0 || BitStream_ReadBits(&stream->base, 16) < 0)
9871 		return -1;
9872 	int left = BitStream_ReadBits(&stream->base, 16);
9873 	int top = BitStream_ReadBits(&stream->base, 16);
9874 	int width = BitStream_ReadBits(&stream->base, 16) - left + 1;
9875 	int height = BitStream_ReadBits(&stream->base, 16) - top + 1;
9876 	for (int i = 0; i < 624; i++) {
9877 		if (stream->base.vtbl->readBit(&stream->base) < 0)
9878 			return -1;
9879 	}
9880 	int mode = BitStream_ReadBits(&stream->base, 2);
9881 	int lastColor;
9882 	switch (mode) {
9883 	case 0:
9884 		lastColor = 127;
9885 		break;
9886 	case 1:
9887 	case 2:
9888 		lastColor = BitStream_ReadBits(&stream->base, 7);
9889 		break;
9890 	default:
9891 		return -1;
9892 	}
9893 	if (imageOffset == -1) {
9894 		if (!RECOIL_SetSize(self, width, height, RECOILResolution_PC981X1))
9895 			return -1;
9896 		imageOffset = 0;
9897 	}
9898 	memset(self->contentPalette, 0, sizeof(self->contentPalette));
9899 	for (int i = 0; i <= lastColor; i++) {
9900 		int j = 0;
9901 		if (mode > 0)
9902 			j = BitStream_ReadBits(&stream->base, 7);
9903 		int c = BitStream_ReadBits(&stream->base, 10);
9904 		if (c < 0 || c >= 729)
9905 			return -1;
9906 		self->contentPalette[mode == 1 ? j : i] = RECOIL_Get729Color(c);
9907 	}
9908 	for (int y = 0; y < height; y++) {
9909 		for (int x = 0; x < width; x++)
9910 			self->pixels[imageOffset + y * self->width + x] = 1;
9911 	}
9912 	int distance = 1;
9913 	int rgb = 0;
9914 	for (int y = 0; y < height; y++) {
9915 		for (int x = 0; x < width; x++) {
9916 			int pixelsOffset = imageOffset + y * self->width + x;
9917 			if (--distance > 0) {
9918 				int old = self->pixels[pixelsOffset];
9919 				if (old == 1)
9920 					self->pixels[pixelsOffset] = rgb;
9921 				else
9922 					rgb = old;
9923 			}
9924 			else {
9925 				distance = X68KPicStream_ReadLength(stream);
9926 				if (distance < 0)
9927 					return -1;
9928 				int c = mode == 2 ? X68KPicStream_ReadLength(stream) - 1 : BitStream_ReadBits(&stream->base, 7);
9929 				if (c < 0 || c >= 128)
9930 					return -1;
9931 				rgb = self->contentPalette[c];
9932 				switch (stream->base.vtbl->readBit(&stream->base)) {
9933 				case 0:
9934 					break;
9935 				case 1:
9936 					if (!RECOIL_DecodeMl1Chain(self, stream, pixelsOffset, rgb))
9937 						return -1;
9938 					break;
9939 				default:
9940 					return -1;
9941 				}
9942 				self->pixels[pixelsOffset] = rgb;
9943 			}
9944 		}
9945 	}
9946 	return distance == 1 && X68KPicStream_ReadLength(stream) == width * height + 1 ? height : -1;
9947 }
9948 
RECOIL_DecodeMl1(RECOIL * self,uint8_t const * content,int contentLength)9949 static bool RECOIL_DecodeMl1(RECOIL *self, uint8_t const *content, int contentLength)
9950 {
9951 	X68KPicStream stream;
9952 	X68KPicStream_Construct(&stream);
9953 	stream.base.base.content = content;
9954 	stream.base.base.contentOffset = 0;
9955 	stream.base.base.contentLength = contentLength;
9956 	return RECOIL_DecodeMl1Mx1(self, &stream, -1) > 0;
9957 }
9958 
RECOIL_DecodeMx1Tiles(RECOIL * self,Mx1Stream * stream,int width,int height,int shift)9959 static bool RECOIL_DecodeMx1Tiles(RECOIL *self, Mx1Stream *stream, int width, int height, int shift)
9960 {
9961 	if (!RECOIL_SetSize(self, width << shift, height << shift, RECOILResolution_PC981X1))
9962 		return false;
9963 	for (int y = 0; y < self->height; y += height) {
9964 		for (int x = 0; x < self->width; x += width) {
9965 			if (!Mx1Stream_FindImage(stream) || RECOIL_DecodeMl1Mx1(self, &stream->base, y * self->width + x) < 0)
9966 				return false;
9967 		}
9968 	}
9969 	return true;
9970 }
9971 
RECOIL_DecodeMx1(RECOIL * self,uint8_t const * content,int contentLength)9972 static bool RECOIL_DecodeMx1(RECOIL *self, uint8_t const *content, int contentLength)
9973 {
9974 	Mx1Stream stream;
9975 	Mx1Stream_Construct(&stream);
9976 	stream.base.base.base.content = content;
9977 	stream.base.base.base.contentOffset = 0;
9978 	stream.base.base.base.contentLength = contentLength;
9979 	if (!Mx1Stream_FindImage(&stream) || RECOIL_DecodeMl1Mx1(self, &stream.base, -1) < 0)
9980 		return false;
9981 	if (!Mx1Stream_FindImage(&stream))
9982 		return true;
9983 	int sameSizeImages = 1;
9984 	int width = self->width;
9985 	int height = self->height;
9986 	do {
9987 		if (RECOIL_DecodeMl1Mx1(self, &stream.base, -1) < 0)
9988 			return false;
9989 		if (sameSizeImages > 0 && self->width == width && self->height == height)
9990 			sameSizeImages++;
9991 		else {
9992 			if (width < self->width)
9993 				width = self->width;
9994 			if (sameSizeImages > 0) {
9995 				height *= sameSizeImages;
9996 				sameSizeImages = 0;
9997 			}
9998 			height += self->height;
9999 		}
10000 	}
10001 	while (Mx1Stream_FindImage(&stream));
10002 	stream.base.base.base.contentOffset = 0;
10003 	switch (sameSizeImages) {
10004 	case 4:
10005 		return RECOIL_DecodeMx1Tiles(self, &stream, width, height, 1);
10006 	case 16:
10007 		return RECOIL_DecodeMx1Tiles(self, &stream, width, height, 2);
10008 	case 0:
10009 		break;
10010 	default:
10011 		height *= sameSizeImages;
10012 		break;
10013 	}
10014 	if (!RECOIL_SetSize(self, width, height, RECOILResolution_PC981X1))
10015 		return false;
10016 	int pixelsLength = width * height;
10017 	for (int pixelsOffset = 0; pixelsOffset < pixelsLength; pixelsOffset++)
10018 		self->pixels[pixelsOffset] = 0;
10019 	int imageOffset = 0;
10020 	while (Mx1Stream_FindImage(&stream))
10021 		imageOffset += RECOIL_DecodeMl1Mx1(self, &stream.base, imageOffset) * width;
10022 	return true;
10023 }
10024 
RECOIL_UnpackZim(uint8_t const * content,int contentOffset,int end,uint8_t const * flags,uint8_t * unpacked,int unpackedLength)10025 static int RECOIL_UnpackZim(uint8_t const *content, int contentOffset, int end, uint8_t const *flags, uint8_t *unpacked, int unpackedLength)
10026 {
10027 	for (int unpackedOffset = 0; unpackedOffset < unpackedLength; unpackedOffset++) {
10028 		if (contentOffset < end && (flags[unpackedOffset >> 3] >> (~unpackedOffset & 7) & 1) != 0)
10029 			unpacked[unpackedOffset] = content[contentOffset++];
10030 		else
10031 			unpacked[unpackedOffset] = 0;
10032 	}
10033 	return contentOffset;
10034 }
10035 
RECOIL_DecodeZim(RECOIL * self,uint8_t const * content,int contentLength)10036 static bool RECOIL_DecodeZim(RECOIL *self, uint8_t const *content, int contentLength)
10037 {
10038 	if (contentLength < 700 || !RECOIL_IsStringAt(content, 0, "FORMAT-A"))
10039 		return false;
10040 	int contentOffset = 512 + ((content[506] | content[507] << 8) << 1);
10041 	if (contentOffset + 26 > contentLength || content[contentOffset] != 0 || content[contentOffset + 1] != 0 || content[contentOffset + 2] != 0 || content[contentOffset + 3] != 0 || content[contentOffset + 20] != 1 || content[contentOffset + 21] != 0)
10042 		return false;
10043 	int width = content[contentOffset + 4] + (content[contentOffset + 5] << 8) + 1;
10044 	int height = content[contentOffset + 6] + (content[contentOffset + 7] << 8) + 1;
10045 	if (!RECOIL_SetSize(self, width, height, RECOILResolution_PC981X1))
10046 		return false;
10047 	contentOffset += 24;
10048 	if (content[contentOffset - 2] != 0 || content[contentOffset - 1] != 0) {
10049 		if (contentOffset + 66 > contentLength)
10050 			return false;
10051 		for (int c = 0; c < 16; c++) {
10052 			self->contentPalette[c] = content[contentOffset + 1] << 16 | content[contentOffset + 2] << 8 | content[contentOffset];
10053 			contentOffset += 4;
10054 		}
10055 	}
10056 	else {
10057 		for (int c = 0; c < 16; c++)
10058 			self->contentPalette[c] = RECOIL_GetZxColor(c);
10059 		self->contentPalette[8] = 16777215;
10060 	}
10061 	int pixelsLength = width * height;
10062 	for (int pixelsOffset = 0; pixelsOffset < pixelsLength; pixelsOffset++)
10063 		self->pixels[pixelsOffset] = self->contentPalette[0];
10064 	uint8_t h1[1];
10065 	uint8_t h2[8];
10066 	uint8_t h3[64];
10067 	uint8_t data[512];
10068 	contentOffset += 2 + ((content[contentOffset] | content[contentOffset + 1] << 8) << 1);
10069 	while (contentOffset + 1 < contentLength) {
10070 		int dot = content[contentOffset] | content[contentOffset + 1] << 8;
10071 		if (dot == 0)
10072 			return true;
10073 		if (contentOffset + 10 >= contentLength)
10074 			return false;
10075 		int x = content[contentOffset + 2] | content[contentOffset + 3] << 8;
10076 		if (x >= width)
10077 			return false;
10078 		int y = content[contentOffset + 4] | content[contentOffset + 5] << 8;
10079 		if (y >= height)
10080 			return false;
10081 		int len = content[contentOffset + 6] | content[contentOffset + 7] << 8;
10082 		int end = contentOffset + 8 + len;
10083 		if (end >= contentLength)
10084 			return false;
10085 		int size = content[contentOffset + 8] | content[contentOffset + 9] << 8;
10086 		if (size > 512 || (size & 3) != 0 || size << 1 < dot)
10087 			return false;
10088 		int pixelsOffset = y * width + x;
10089 		if (pixelsOffset + dot > pixelsLength)
10090 			return false;
10091 		h1[0] = content[contentOffset + 10];
10092 		contentOffset += 11;
10093 		contentOffset = RECOIL_UnpackZim(content, contentOffset, end, h1, h2, 8);
10094 		contentOffset = RECOIL_UnpackZim(content, contentOffset, end, h2, h3, 64);
10095 		contentOffset = RECOIL_UnpackZim(content, contentOffset, end, h3, data, size);
10096 		for (int i = 1; i < size; i++)
10097 			data[i] ^= data[i - 1];
10098 		for (int i = 2; i < size; i++)
10099 			data[i] ^= data[i - 2];
10100 		size >>= 2;
10101 		for (int i = 0; i < dot; i++) {
10102 			int bit = ~i & 7;
10103 			int c = (data[i >> 3] >> bit & 1) << 3 | (data[size + (i >> 3)] >> bit & 1) << 2 | (data[2 * size + (i >> 3)] >> bit & 1) << 1 | (data[3 * size + (i >> 3)] >> bit & 1);
10104 			self->pixels[pixelsOffset + i] = self->contentPalette[c];
10105 		}
10106 	}
10107 	return false;
10108 }
10109 
RECOIL_DecodeQ4(RECOIL * self,uint8_t const * content,int contentLength)10110 static bool RECOIL_DecodeQ4(RECOIL *self, uint8_t const *content, int contentLength)
10111 {
10112 	if (contentLength < 22 || (content[2] != 2 && (content[1] > 1 || content[3] > 1)) || content[8] + (content[9] << 8) != contentLength || !RECOIL_IsStringAt(content, 11, "MAJYO"))
10113 		return false;
10114 	Q4Stream rle;
10115 	Q4Stream_Construct(&rle);
10116 	rle.base.base.base.content = content;
10117 	rle.base.base.base.contentOffset = 16;
10118 	rle.base.base.base.contentLength = contentLength;
10119 	int nextChunkOffset = Q4Stream_StartChunk(&rle);
10120 	if (nextChunkOffset < 0 || !Q4Stream_UnpackQ4(&rle))
10121 		return false;
10122 	for (int i = 0; i < 16; i++) {
10123 		int rgb = 0;
10124 		for (int c = 0; c < 3; c++) {
10125 			if (RleStream_ReadRle(&rle.base) < 0)
10126 				return false;
10127 			int b = RleStream_ReadRle(&rle.base);
10128 			if (b < 0)
10129 				return false;
10130 			rgb = rgb << 8 | b * 17;
10131 		}
10132 		self->contentPalette[(i & 8) | (i & 1) << 2 | (i >> 1 & 3)] = rgb;
10133 	}
10134 	RECOIL_SetSize(self, 640, 400, RECOILResolution_PC981X1);
10135 	int chunkPixels = 0;
10136 	for (int i = 0; i < 256000; i++) {
10137 		if (--chunkPixels <= 0) {
10138 			chunkPixels = (content[nextChunkOffset + 4] | content[nextChunkOffset + 5] << 8) << 1;
10139 			rle.base.base.base.content = content;
10140 			rle.base.base.base.contentOffset = nextChunkOffset;
10141 			rle.base.base.base.contentLength = contentLength;
10142 			nextChunkOffset = Q4Stream_StartChunk(&rle);
10143 			if (nextChunkOffset < 0 || !Q4Stream_UnpackQ4(&rle))
10144 				return false;
10145 		}
10146 		int b = RleStream_ReadRle(&rle.base);
10147 		if (b < 0)
10148 			b = 0;
10149 		self->pixels[i] = self->contentPalette[b];
10150 	}
10151 	return true;
10152 }
10153 
RECOIL_GetPiPlatform(uint8_t const * content,int contentOffset,bool highPixel)10154 static RECOILResolution RECOIL_GetPiPlatform(uint8_t const *content, int contentOffset, bool highPixel)
10155 {
10156 	switch (RECOIL_Get32LittleEndian(content, contentOffset)) {
10157 	case 1314344788:
10158 		return RECOILResolution_FM_TOWNS1X1;
10159 	case 808993616:
10160 		return RECOILResolution_PC801X2;
10161 	case 943211344:
10162 		return RECOILResolution_PC881X2;
10163 	case 1096172368:
10164 		return highPixel ? RECOILResolution_PC881X2 : RECOILResolution_PC88_VA1X1;
10165 	case 827872077:
10166 	case 844649293:
10167 	case 1347965773:
10168 	case 1381520205:
10169 		return highPixel ? RECOILResolution_MSX21X2 : RECOILResolution_MSX21X1;
10170 	case 1261975128:
10171 		return RECOILResolution_X68_K1X1;
10172 	default:
10173 		return highPixel ? RECOILResolution_PC881X2 : RECOILResolution_PC981X1;
10174 	}
10175 }
10176 
RECOIL_DecodePi(RECOIL * self,uint8_t const * content,int contentLength)10177 static bool RECOIL_DecodePi(RECOIL *self, uint8_t const *content, int contentLength)
10178 {
10179 	if (contentLength < 18 || content[0] != 80 || content[1] != 105)
10180 		return false;
10181 	PiStream s;
10182 	PiStream_Construct(&s);
10183 	s.base.base.content = content;
10184 	s.base.base.contentOffset = 2;
10185 	s.base.base.contentLength = contentLength;
10186 	if (!Stream_SkipUntilByte(&s.base.base, 26) || !Stream_SkipUntilByte(&s.base.base, 0)) {
10187 		PiStream_Destruct(&s);
10188 		return false;
10189 	}
10190 	int contentOffset = s.base.base.contentOffset;
10191 	if (contentOffset + 14 > contentLength) {
10192 		PiStream_Destruct(&s);
10193 		return false;
10194 	}
10195 	int depth = content[contentOffset + 3];
10196 	s.base.base.contentOffset = contentOffset + 14 + (3 << depth);
10197 	if (content[contentOffset] != 0 || (depth != 4 && depth != 8) || content[contentOffset + 8] != 0 || content[contentOffset + 9] != 0) {
10198 		PiStream_Destruct(&s);
10199 		return false;
10200 	}
10201 	int width = content[contentOffset + 10] << 8 | content[contentOffset + 11];
10202 	int height = content[contentOffset + 12] << 8 | content[contentOffset + 13];
10203 	RECOILResolution resolution = RECOIL_GetPiPlatform(content, contentOffset + 4, content[contentOffset + 1] == 2 && content[contentOffset + 2] == 1);
10204 	if (!RECOIL_SetScaledSize(self, width, height, resolution)) {
10205 		PiStream_Destruct(&s);
10206 		return false;
10207 	}
10208 	if (PiStream_Unpack(&s, width, height, depth)) {
10209 		RECOIL_DecodeR8G8B8Colors(content, contentOffset + 14, 1 << depth, self->contentPalette);
10210 		RECOIL_DecodeBytes(self, s.indexes, 0);
10211 		PiStream_Destruct(&s);
10212 		return true;
10213 	}
10214 	PiStream_Destruct(&s);
10215 	return false;
10216 }
10217 
RECOIL_SetMagPalette(RECOIL * self,uint8_t const * content,int paletteOffset,int colors)10218 static void RECOIL_SetMagPalette(RECOIL *self, uint8_t const *content, int paletteOffset, int colors)
10219 {
10220 	for (int c = 0; c < colors; c++) {
10221 		int offset = paletteOffset + c * 3;
10222 		self->contentPalette[c] = content[offset + 1] << 16 | content[offset] << 8 | content[offset + 2];
10223 	}
10224 }
10225 
RECOIL_DecodeMaki1(RECOIL * self,uint8_t const * content,int contentLength)10226 static bool RECOIL_DecodeMaki1(RECOIL *self, uint8_t const *content, int contentLength)
10227 {
10228 	if (contentLength < 1096 || content[40] != 0 || content[41] != 0 || content[42] != 0 || content[43] != 0 || content[44] != 2 || content[45] != 128 || content[46] != 1 || content[47] != 144)
10229 		return false;
10230 	RECOIL_SetSize(self, 640, 400, RECOIL_GetPiPlatform(content, 8, false));
10231 	RECOIL_SetMagPalette(self, content, 48, 16);
10232 	int contentOffset = 1096;
10233 	int haveBuffer[8000];
10234 	BitStream haveBlock;
10235 	BitStream_Construct(&haveBlock);
10236 	haveBlock.base.content = content;
10237 	haveBlock.base.contentOffset = 96;
10238 	haveBlock.base.contentLength = 1096;
10239 	for (int i = 0; i < 8000; i++) {
10240 		int have = 0;
10241 		if (haveBlock.vtbl->readBit(&haveBlock) == 1) {
10242 			if (contentOffset + 1 >= contentLength)
10243 				return false;
10244 			have = content[contentOffset] << 8 | content[contentOffset + 1];
10245 			contentOffset += 2;
10246 		}
10247 		haveBuffer[i] = have;
10248 	}
10249 	int xorYOffset = content[6] == 65 ? 2 : 0;
10250 	uint8_t indexBuffer[1280] = { 0 };
10251 	for (int y = 0; y < 400; y++) {
10252 		for (int x = 0; x < 320; x++) {
10253 			int row = y & 3;
10254 			int index = indexBuffer[(row ^ xorYOffset) * 320 + x];
10255 			if ((haveBuffer[(y & -4) * 20 + (x >> 2)] >> (15 - (row << 2) - (x & 3)) & 1) != 0) {
10256 				if (contentOffset >= contentLength)
10257 					return false;
10258 				index ^= content[contentOffset++];
10259 			}
10260 			indexBuffer[row * 320 + x] = (uint8_t) index;
10261 			int pixelsOffset = (y * 320 + x) << 1;
10262 			self->pixels[pixelsOffset] = self->contentPalette[index >> 4];
10263 			self->pixels[pixelsOffset + 1] = self->contentPalette[index & 15];
10264 		}
10265 	}
10266 	return true;
10267 }
10268 
RECOIL_UnpackMag(uint8_t const * content,int headerOffset,int contentLength,int bytesPerLine,int height,uint8_t * unpacked)10269 static bool RECOIL_UnpackMag(uint8_t const *content, int headerOffset, int contentLength, int bytesPerLine, int height, uint8_t *unpacked)
10270 {
10271 	BitStream haveDelta;
10272 	BitStream_Construct(&haveDelta);
10273 	haveDelta.base.content = content;
10274 	haveDelta.base.contentOffset = headerOffset + RECOIL_Get32LittleEndian(content, headerOffset + 12);
10275 	haveDelta.base.contentLength = contentLength;
10276 	int deltaOffset = headerOffset + RECOIL_Get32LittleEndian(content, headerOffset + 16);
10277 	int colorOffset = headerOffset + RECOIL_Get32LittleEndian(content, headerOffset + 24);
10278 	if (haveDelta.base.contentOffset < 0 || deltaOffset < 0 || colorOffset < 0)
10279 		return false;
10280 	uint8_t deltas[2500] = { 0 };
10281 	for (int y = 0; y < height; y++) {
10282 		int delta = 0;
10283 		for (int x = 0; x < bytesPerLine; x++) {
10284 			if ((x & 1) == 0) {
10285 				delta = deltas[x >> 2];
10286 				if ((x & 2) == 0) {
10287 					switch (haveDelta.vtbl->readBit(&haveDelta)) {
10288 					case 0:
10289 						break;
10290 					case 1:
10291 						if (deltaOffset >= contentLength)
10292 							return false;
10293 						delta ^= content[deltaOffset++];
10294 						deltas[x >> 2] = (uint8_t) delta;
10295 						break;
10296 					default:
10297 						return false;
10298 					}
10299 					delta >>= 4;
10300 				}
10301 				else
10302 					delta &= 15;
10303 			}
10304 			if (delta == 0) {
10305 				if (colorOffset >= contentLength)
10306 					return false;
10307 				unpacked[y * bytesPerLine + x] = content[colorOffset++];
10308 			}
10309 			else {
10310 				static const uint8_t DELTA_X[16] = { 0, 2, 4, 8, 0, 2, 0, 2, 4, 0, 2, 4, 0, 2, 4, 0 };
10311 				static const uint8_t DELTA_Y[16] = { 0, 0, 0, 0, 1, 1, 2, 2, 2, 4, 4, 4, 8, 8, 8, 16 };
10312 				int sourceX = x - DELTA_X[delta];
10313 				int sourceY = y - DELTA_Y[delta];
10314 				if (sourceX < 0 || sourceY < 0)
10315 					return false;
10316 				unpacked[y * bytesPerLine + x] = unpacked[sourceY * bytesPerLine + sourceX];
10317 			}
10318 		}
10319 		if ((bytesPerLine & 1) != 0 && delta == 0)
10320 			colorOffset++;
10321 		if (((bytesPerLine + 1) & 2) != 0 && (deltas[bytesPerLine >> 2] & 15) == 0)
10322 			colorOffset += 2;
10323 	}
10324 	return true;
10325 }
10326 
RECOIL_DecodeMag(RECOIL * self,uint8_t const * content,int contentLength)10327 static bool RECOIL_DecodeMag(RECOIL *self, uint8_t const *content, int contentLength)
10328 {
10329 	if (contentLength < 8)
10330 		return false;
10331 	if (RECOIL_IsStringAt(content, 0, "MAKI01A ") || RECOIL_IsStringAt(content, 0, "MAKI01B "))
10332 		return RECOIL_DecodeMaki1(self, content, contentLength);
10333 	if (!RECOIL_IsStringAt(content, 0, "MAKI02  "))
10334 		return false;
10335 	int headerOffset = 0;
10336 	do {
10337 		if (headerOffset >= contentLength)
10338 			return false;
10339 	}
10340 	while (content[headerOffset++] != 26);
10341 	if (headerOffset + 80 > contentLength || content[headerOffset] != 0)
10342 		return false;
10343 	int width = content[headerOffset + 8] - content[headerOffset + 4] + ((content[headerOffset + 9] - content[headerOffset + 5]) << 8) + 1;
10344 	int height = content[headerOffset + 10] - content[headerOffset + 6] + ((content[headerOffset + 11] - content[headerOffset + 7]) << 8) + 1;
10345 	int bytesPerLine;
10346 	int colors;
10347 	if (content[headerOffset + 3] < 128) {
10348 		bytesPerLine = (width + 1) >> 1;
10349 		colors = 16;
10350 	}
10351 	else {
10352 		if (headerOffset + 800 >= contentLength)
10353 			return false;
10354 		bytesPerLine = width;
10355 		colors = 256;
10356 	}
10357 	RECOILResolution resolution;
10358 	int msxMode = 0;
10359 	switch (content[headerOffset + 1]) {
10360 	case 0:
10361 	case 136:
10362 		resolution = (content[headerOffset + 3] & 1) == 0 ? RECOILResolution_PC88_VA1X1 : RECOILResolution_PC881X2;
10363 		break;
10364 	case 3:
10365 		msxMode = content[headerOffset + 2] & 252;
10366 		switch (msxMode) {
10367 		case 0:
10368 		case 20:
10369 		case 84:
10370 			resolution = RECOILResolution_MSX21X1;
10371 			break;
10372 		case 4:
10373 			resolution = RECOILResolution_MSX21X2;
10374 			break;
10375 		case 16:
10376 		case 80:
10377 			resolution = RECOILResolution_MSX22X1;
10378 			break;
10379 		case 32:
10380 		case 64:
10381 			if (colors == 16)
10382 				width >>= 1;
10383 			resolution = RECOILResolution_MSX2_PLUS2X1;
10384 			break;
10385 		case 36:
10386 		case 68:
10387 			if (colors == 16)
10388 				width >>= 1;
10389 			resolution = RECOILResolution_MSX2_PLUS1X1;
10390 			break;
10391 		case 96:
10392 			width = bytesPerLine << 2;
10393 			resolution = RECOILResolution_MSX21X1;
10394 			break;
10395 		case 100:
10396 			width = bytesPerLine << 2;
10397 			resolution = RECOILResolution_MSX21X2;
10398 			break;
10399 		default:
10400 			return false;
10401 		}
10402 		break;
10403 	case 98:
10404 	case 112:
10405 		resolution = RECOILResolution_PC981X1;
10406 		break;
10407 	case 104:
10408 		resolution = RECOILResolution_X68_K1X1;
10409 		break;
10410 	case 128:
10411 		resolution = RECOILResolution_PC801X2;
10412 		break;
10413 	case 153:
10414 		resolution = RECOILResolution_MACINTOSH1X1;
10415 		break;
10416 	default:
10417 		resolution = (content[headerOffset + 3] & 1) == 0 ? RECOILResolution_MSX21X1 : RECOILResolution_MSX21X2;
10418 		break;
10419 	}
10420 	if (!RECOIL_SetScaledSize(self, width, height, resolution))
10421 		return false;
10422 	uint8_t *unpacked = (uint8_t *) CiShared_Make(bytesPerLine * height, sizeof(uint8_t), NULL, NULL);
10423 	if (!RECOIL_UnpackMag(content, headerOffset, contentLength, bytesPerLine, height, unpacked)) {
10424 		CiShared_Release(unpacked);
10425 		return false;
10426 	}
10427 	RECOIL_SetMagPalette(self, content, headerOffset + 32, colors);
10428 	switch (msxMode) {
10429 	case 32:
10430 	case 36:
10431 		RECOIL_DecodeMsxYjkScreen(self, unpacked, 0, true);
10432 		break;
10433 	case 64:
10434 	case 68:
10435 		RECOIL_DecodeMsxYjkScreen(self, unpacked, 0, false);
10436 		break;
10437 	case 96:
10438 	case 100:
10439 		RECOIL_DecodeMsx6(self, unpacked, 0);
10440 		break;
10441 	default:
10442 		if (colors == 16)
10443 			RECOIL_DecodeNibbles(self, unpacked, 0, bytesPerLine);
10444 		else
10445 			RECOIL_DecodeBytes(self, unpacked, 0);
10446 		break;
10447 	}
10448 	CiShared_Release(unpacked);
10449 	return true;
10450 }
10451 
RECOIL_DecodeVbm(RECOIL * self,uint8_t const * content,int contentLength)10452 static bool RECOIL_DecodeVbm(RECOIL *self, uint8_t const *content, int contentLength)
10453 {
10454 	if (contentLength < 9 || content[0] != 66 || content[1] != 77 || content[2] != 203 || content[3] != 2)
10455 		return false;
10456 	int width = content[4] << 8 | content[5];
10457 	int height = content[6] << 8 | content[7];
10458 	return RECOIL_SetSize(self, width, height, RECOILResolution_C1281X1) && RECOIL_DecodeBlackAndWhite(self, content, 8, contentLength, false, 16777215);
10459 }
10460 
RECOIL_DecodeBrus(RECOIL * self,uint8_t const * content,int contentLength)10461 static bool RECOIL_DecodeBrus(RECOIL *self, uint8_t const *content, int contentLength)
10462 {
10463 	if (contentLength < 20 || !RECOIL_IsStringAt(content, 2, "BRUS") || content[6] != 4 || content[10] != 1 || content[11] != 2)
10464 		return false;
10465 	int columns = content[12];
10466 	if (columns == 0 || columns > 90)
10467 		return false;
10468 	int height = content[13] | content[14] << 8;
10469 	if (height == 0 || height > 700)
10470 		return false;
10471 	int width = columns << 3;
10472 	RECOIL_SetSize(self, width, height, RECOILResolution_C1281X1);
10473 	int bitmapLength = height * columns;
10474 	uint8_t bitmap[63000];
10475 	PgcStream rle;
10476 	PgcStream_Construct(&rle);
10477 	rle.base.base.base.content = content;
10478 	rle.base.base.base.contentOffset = 18;
10479 	rle.base.base.base.contentLength = contentLength;
10480 	if (!RleStream_Unpack(&rle.base, bitmap, 0, 1, bitmapLength))
10481 		return false;
10482 	int contentOffset = rle.base.base.base.contentOffset;
10483 	if (contentOffset + 4 >= contentLength || !RECOIL_IsStringAt(content, contentOffset, "COLR")) {
10484 		return RECOIL_DecodeBlackAndWhite(self, bitmap, 0, bitmapLength, false, 16777215);
10485 	}
10486 	rle.base.base.base.contentOffset = contentOffset + 4;
10487 	uint8_t colors[180];
10488 	for (int y = 0; y < height; y++) {
10489 		if ((y & 7) == 0 && !RleStream_Unpack(&rle.base, colors, 0, 1, columns << 1))
10490 			return false;
10491 		for (int x = 0; x < width; x++) {
10492 			int column = x >> 3;
10493 			int c = colors[(y & 1) * columns + column];
10494 			if ((bitmap[y * columns + column] >> (~x & 7) & 1) == 0)
10495 				c >>= 4;
10496 			static const int PALETTE[16] = { 0, 5592405, 170, 5592575, 43520, 5635925, 43690, 5636095, 11141120, 16733525, 11141290, 16733695, 11162880, 16777045, 11184810, 16777215 };
10497 			self->pixels[y * width + x] = PALETTE[c & 15];
10498 		}
10499 	}
10500 	return true;
10501 }
10502 
RECOIL_SetC16Palette(RECOIL * self)10503 static void RECOIL_SetC16Palette(RECOIL *self)
10504 {
10505 	uint8_t const *pal = CiResource_c16_pal;
10506 	for (int i = 0; i < 256; i++)
10507 		self->contentPalette[i] = pal[i * 3] << 16 | pal[i * 3 + 1] << 8 | pal[i * 3 + 2];
10508 }
10509 
RECOIL_DecodeP4i(RECOIL * self,uint8_t const * content,int contentLength)10510 static bool RECOIL_DecodeP4i(RECOIL *self, uint8_t const *content, int contentLength)
10511 {
10512 	switch (contentLength) {
10513 	case 10050:
10514 		if (RECOIL_IsStringAt(content, 1020, "MULT")) {
10515 			RECOIL_SetSize(self, 320, 200, RECOILResolution_C162X1);
10516 			RECOIL_SetC16Palette(self);
10517 			for (int y = 0; y < 200; y++) {
10518 				for (int x = 0; x < 320; x++) {
10519 					int offset = (y & -8) * 40 + (x & -8) + (y & 7);
10520 					int c = content[2050 + offset] >> (~x & 6) & 3;
10521 					switch (c) {
10522 					case 0:
10523 						c = content[1025];
10524 						break;
10525 					case 1:
10526 						offset >>= 3;
10527 						c = (content[1026 + offset] & 240) | (content[2 + offset] & 7);
10528 						break;
10529 					case 2:
10530 						offset >>= 3;
10531 						c = (content[1026 + offset] & 15) << 4 | content[2 + offset] >> 4;
10532 						break;
10533 					default:
10534 						c = content[1024];
10535 						break;
10536 					}
10537 					self->pixels[y * 320 + x] = self->contentPalette[c];
10538 				}
10539 			}
10540 		}
10541 		else {
10542 			RECOIL_SetSize(self, 320, 200, RECOILResolution_C161X1);
10543 			RECOIL_SetC16Palette(self);
10544 			for (int y = 0; y < 200; y++) {
10545 				for (int x = 0; x < 320; x++) {
10546 					int offset = (y & -8) * 40 + (x & -8) + (y & 7);
10547 					int c = content[2050 + offset] >> (~x & 7) & 1;
10548 					offset >>= 3;
10549 					if (c == 0)
10550 						c = (content[1026 + offset] & 15) << 4 | content[2 + offset] >> 4;
10551 					else
10552 						c = (content[1026 + offset] & 240) | (content[2 + offset] & 7);
10553 					self->pixels[y * 320 + x] = self->contentPalette[c];
10554 				}
10555 			}
10556 		}
10557 		break;
10558 	case 2050:
10559 		RECOIL_SetSize(self, 256, 64, RECOILResolution_C162X1);
10560 		RECOIL_SetC16Palette(self);
10561 		for (int y = 0; y < 64; y++) {
10562 			for (int x = 0; x < 256; x++) {
10563 				static const uint8_t LOGO_COLORS[4] = { 0, 19, 21, 23 };
10564 				int c = LOGO_COLORS[content[2 + ((x & -8) << 3) + y] >> (~x & 6) & 3];
10565 				self->pixels[(y << 8) + x] = self->contentPalette[c];
10566 			}
10567 		}
10568 		break;
10569 	default:
10570 		return false;
10571 	}
10572 	return true;
10573 }
10574 
RECOIL_Decode64c(RECOIL * self,uint8_t const * content,int contentLength)10575 static bool RECOIL_Decode64c(RECOIL *self, uint8_t const *content, int contentLength)
10576 {
10577 	if (contentLength < 10 || contentLength > 2050 || content[0] != 0)
10578 		return false;
10579 	RECOIL_SetSize(self, 256, (contentLength + 253) >> 8 << 3, RECOILResolution_C641X1);
10580 	RECOIL_DecodeBlackAndWhiteFont(self, content, 2, contentLength, 8);
10581 	return true;
10582 }
10583 
RECOIL_DecodeG(RECOIL * self,uint8_t const * content,int contentLength)10584 static bool RECOIL_DecodeG(RECOIL *self, uint8_t const *content, int contentLength)
10585 {
10586 	if (contentLength != 514 || content[0] != 66 || content[1] != 0)
10587 		return false;
10588 	RECOIL_SetSize(self, 256, 16, RECOILResolution_C641X1);
10589 	RECOIL_DecodeBlackAndWhiteFont(self, content, 2, 514, 8);
10590 	return true;
10591 }
10592 
RECOIL_DecodeCle(RECOIL * self,uint8_t const * content,int contentLength)10593 static bool RECOIL_DecodeCle(RECOIL *self, uint8_t const *content, int contentLength)
10594 {
10595 	if (contentLength != 8194)
10596 		return false;
10597 	RECOIL_SetSize(self, 320, 200, RECOILResolution_C641X1);
10598 	int palette[4];
10599 	palette[0] = RECOIL_C64_PALETTE[content[8004] & 15];
10600 	palette[1] = RECOIL_C64_PALETTE[content[8002] >> 4];
10601 	palette[2] = RECOIL_C64_PALETTE[content[8002] & 15];
10602 	palette[3] = RECOIL_C64_PALETTE[content[8003] & 15];
10603 	for (int y = 0; y < 200; y++) {
10604 		for (int x = 0; x < 320; x++)
10605 			self->pixels[y * 320 + x] = palette[content[2 + (y & -8) * 40 + (x & -8) + (y & 7)] >> (~x & 6) & 3];
10606 	}
10607 	return true;
10608 }
10609 
RECOIL_Decode4bt(RECOIL * self,uint8_t const * content,int contentLength)10610 static bool RECOIL_Decode4bt(RECOIL *self, uint8_t const *content, int contentLength)
10611 {
10612 	if (contentLength < 5 || !RECOIL_IsStringAt(content, 0, "GOD0") || content[contentLength - 1] != 173)
10613 		return false;
10614 	uint8_t unpacked[32000];
10615 	GoDotStream rle;
10616 	GoDotStream_Construct(&rle);
10617 	rle.base.base.base.content = content;
10618 	rle.base.base.base.contentOffset = 4;
10619 	rle.base.base.base.contentLength = contentLength - 1;
10620 	if (!RleStream_Unpack(&rle.base, unpacked, 0, 1, 32000))
10621 		return false;
10622 	RECOIL_SetSize(self, 320, 200, RECOILResolution_C641X1);
10623 	for (int y = 0; y < 200; y++) {
10624 		for (int x = 0; x < 320; x++) {
10625 			static const uint8_t BY_BRIGHTNESS[16] = { 0, 6, 9, 11, 2, 4, 8, 12, 14, 10, 5, 15, 3, 7, 13, 1 };
10626 			int c = unpacked[(y & -8) * 160 + (((x & -8) + (y & 7)) << 2) + (x >> 1 & 3)];
10627 			self->pixels[y * 320 + x] = RECOIL_C64_PALETTE[BY_BRIGHTNESS[(x & 1) == 0 ? c >> 4 : c & 15]];
10628 		}
10629 	}
10630 	return true;
10631 }
10632 
RECOIL_DecodeC64HiresFrame(RECOIL * self,uint8_t const * content,int bitmapOffset,int videoMatrixOffset,int pixelsOffset)10633 static void RECOIL_DecodeC64HiresFrame(RECOIL *self, uint8_t const *content, int bitmapOffset, int videoMatrixOffset, int pixelsOffset)
10634 {
10635 	bool afli = self->width == 296;
10636 	for (int y = 0; y < self->height; y++) {
10637 		for (int x = 0; x < self->width; x++) {
10638 			int offset = (y & -8) * 40 + (x & -8) + (y & 7);
10639 			int c = content[bitmapOffset + offset] >> (~x & 7) & 1;
10640 			int v;
10641 			if (videoMatrixOffset >= 0) {
10642 				offset >>= 3;
10643 				if (afli)
10644 					offset += (y & 7) << 10;
10645 				v = content[videoMatrixOffset + offset];
10646 			}
10647 			else
10648 				v = -videoMatrixOffset;
10649 			c = c == 0 ? v & 15 : v >> 4;
10650 			self->pixels[pixelsOffset + y * self->width + x] = RECOIL_C64_PALETTE[c];
10651 		}
10652 	}
10653 }
10654 
RECOIL_DecodeC64MulticolorFrame(RECOIL * self,uint8_t const * content,int bitmapOffset,int videoMatrixOffset,int colorOffset,int background,int pixelsOffset)10655 static void RECOIL_DecodeC64MulticolorFrame(RECOIL *self, uint8_t const *content, int bitmapOffset, int videoMatrixOffset, int colorOffset, int background, int pixelsOffset)
10656 {
10657 	bool fli = self->width == 296;
10658 	bool bottomBfli = pixelsOffset != 0 && self->height == 400;
10659 	for (int y = 0; y < 200; y++) {
10660 		int lineBackground;
10661 		if (background >= 0)
10662 			lineBackground = background;
10663 		else if (background == -16209 && y >= 177)
10664 			lineBackground = content[y < 197 ? 18233 + y : 18429];
10665 		else
10666 			lineBackground = content[y - background];
10667 		for (int x = 0; x < self->width; x++) {
10668 			int c = lineBackground;
10669 			int i = x + self->leftSkip;
10670 			if (i >= 0) {
10671 				int offset = (y & -8) * 40 + (i & -8) + (y & 7);
10672 				if (bottomBfli)
10673 					offset = (offset - 168) & 8191;
10674 				switch (content[bitmapOffset + offset] >> (~i & 6) & 3) {
10675 				case 1:
10676 					offset >>= 3;
10677 					if (fli)
10678 						offset += (y & 7) << 10;
10679 					c = content[videoMatrixOffset + offset] >> 4;
10680 					break;
10681 				case 2:
10682 					offset >>= 3;
10683 					if (fli)
10684 						offset += (y & 7) << 10;
10685 					c = content[videoMatrixOffset + offset];
10686 					break;
10687 				case 3:
10688 					c = colorOffset < 0 ? content[-colorOffset] : content[colorOffset + (offset >> 3)];
10689 					break;
10690 				default:
10691 					break;
10692 				}
10693 			}
10694 			self->pixels[pixelsOffset + y * self->width + x] = RECOIL_C64_PALETTE[c & 15];
10695 		}
10696 	}
10697 }
10698 
RECOIL_DecodeC64Multicolor(RECOIL * self,int width,uint8_t const * content,int bitmapOffset,int videoMatrixOffset,int colorOffset,int background)10699 static bool RECOIL_DecodeC64Multicolor(RECOIL *self, int width, uint8_t const *content, int bitmapOffset, int videoMatrixOffset, int colorOffset, int background)
10700 {
10701 	RECOIL_SetSize(self, width, 200, RECOILResolution_C642X1);
10702 	RECOIL_DecodeC64MulticolorFrame(self, content, bitmapOffset, videoMatrixOffset, colorOffset, background, 0);
10703 	return true;
10704 }
10705 
RECOIL_DecodeOcp(RECOIL * self,uint8_t const * content,int contentLength)10706 static bool RECOIL_DecodeOcp(RECOIL *self, uint8_t const *content, int contentLength)
10707 {
10708 	return contentLength == 10018 && RECOIL_DecodeC64Multicolor(self, 320, content, 2, 8002, 9018, content[9003]);
10709 }
10710 
RECOIL_DecodeC64Hir(RECOIL * self,uint8_t const * content,int contentLength)10711 static bool RECOIL_DecodeC64Hir(RECOIL *self, uint8_t const *content, int contentLength)
10712 {
10713 	switch (contentLength) {
10714 	case 8002:
10715 	case 8194:
10716 		break;
10717 	default:
10718 		return false;
10719 	}
10720 	RECOIL_SetSize(self, 320, 200, RECOILResolution_C641X1);
10721 	RECOIL_DecodeC64HiresFrame(self, content, 2, -16, 0);
10722 	return true;
10723 }
10724 
RECOIL_DecodeIhe(RECOIL * self,uint8_t const * content,int contentLength)10725 static bool RECOIL_DecodeIhe(RECOIL *self, uint8_t const *content, int contentLength)
10726 {
10727 	if (contentLength != 16194)
10728 		return false;
10729 	RECOIL_SetSize(self, 320, 200, RECOILResolution_C641X1);
10730 	RECOIL_DecodeC64HiresFrame(self, content, 2, -12, 0);
10731 	RECOIL_DecodeC64HiresFrame(self, content, 8194, -12, 64000);
10732 	return RECOIL_ApplyBlend(self);
10733 }
10734 
RECOIL_DecodeIph(RECOIL * self,uint8_t const * content,int contentLength)10735 static bool RECOIL_DecodeIph(RECOIL *self, uint8_t const *content, int contentLength)
10736 {
10737 	switch (contentLength) {
10738 	case 9002:
10739 	case 9003:
10740 	case 9009:
10741 		break;
10742 	default:
10743 		return false;
10744 	}
10745 	RECOIL_SetSize(self, 320, 200, RECOILResolution_C641X1);
10746 	RECOIL_DecodeC64HiresFrame(self, content, 2, 8002, 0);
10747 	return true;
10748 }
10749 
RECOIL_DecodeHed(RECOIL * self,uint8_t const * content,int contentLength)10750 static bool RECOIL_DecodeHed(RECOIL *self, uint8_t const *content, int contentLength)
10751 {
10752 	if (contentLength != 9218)
10753 		return false;
10754 	RECOIL_SetSize(self, 320, 200, RECOILResolution_C641X1);
10755 	RECOIL_DecodeC64HiresFrame(self, content, 2, 8194, 0);
10756 	return true;
10757 }
10758 
RECOIL_DecodeDd(RECOIL * self,uint8_t const * content,int contentLength)10759 static bool RECOIL_DecodeDd(RECOIL *self, uint8_t const *content, int contentLength)
10760 {
10761 	switch (contentLength) {
10762 	case 9026:
10763 	case 9218:
10764 	case 9346:
10765 		break;
10766 	default:
10767 		return false;
10768 	}
10769 	RECOIL_SetSize(self, 320, 200, RECOILResolution_C641X1);
10770 	RECOIL_DecodeC64HiresFrame(self, content, 1026, 2, 0);
10771 	return true;
10772 }
10773 
RECOIL_DecodeJj(RECOIL * self,uint8_t const * content,int contentLength)10774 static bool RECOIL_DecodeJj(RECOIL *self, uint8_t const *content, int contentLength)
10775 {
10776 	if (contentLength < 2)
10777 		return false;
10778 	uint8_t unpacked[9026];
10779 	C64KoalaStream rle;
10780 	C64KoalaStream_Construct(&rle);
10781 	rle.base.base.base.content = content;
10782 	rle.base.base.base.contentOffset = 2;
10783 	rle.base.base.base.contentLength = contentLength;
10784 	return RleStream_UnpackC64(&rle.base, unpacked, 9026) && RECOIL_DecodeDd(self, unpacked, 9026);
10785 }
10786 
RECOIL_DecodeHfc(RECOIL * self,uint8_t const * content,int contentLength)10787 static bool RECOIL_DecodeHfc(RECOIL *self, uint8_t const *content, int contentLength)
10788 {
10789 	if (contentLength != 16386)
10790 		return false;
10791 	RECOIL_SetSize(self, 296, 112, RECOILResolution_C641X1);
10792 	RECOIL_DecodeC64HiresFrame(self, content, 26, 8197, 0);
10793 	return true;
10794 }
10795 
RECOIL_DecodeAfl(RECOIL * self,uint8_t const * content,int contentLength)10796 static bool RECOIL_DecodeAfl(RECOIL *self, uint8_t const *content, int contentLength)
10797 {
10798 	if (contentLength != 16385)
10799 		return false;
10800 	RECOIL_SetSize(self, 296, 200, RECOILResolution_C641X1);
10801 	RECOIL_DecodeC64HiresFrame(self, content, 8218, 5, 0);
10802 	return true;
10803 }
10804 
RECOIL_DecodePmg(RECOIL * self,uint8_t const * content,int contentLength)10805 static bool RECOIL_DecodePmg(RECOIL *self, uint8_t const *content, int contentLength)
10806 {
10807 	return contentLength == 9332 && RECOIL_DecodeC64Multicolor(self, 320, content, 116, 8308, -8119, content[8116]);
10808 }
10809 
RECOIL_DecodeKoa(RECOIL * self,uint8_t const * content,int contentLength)10810 static bool RECOIL_DecodeKoa(RECOIL *self, uint8_t const *content, int contentLength)
10811 {
10812 	switch (contentLength) {
10813 	case 10001:
10814 		return RECOIL_DecodeC64Multicolor(self, 320, content, 0, 8000, 9000, content[10000]);
10815 	case 10003:
10816 	case 10006:
10817 		return RECOIL_DecodeC64Multicolor(self, 320, content, 2, 8002, 9002, content[10002]);
10818 	default:
10819 		return false;
10820 	}
10821 }
10822 
RECOIL_DecodeGg(RECOIL * self,uint8_t const * content,int contentLength)10823 static bool RECOIL_DecodeGg(RECOIL *self, uint8_t const *content, int contentLength)
10824 {
10825 	if (contentLength < 2)
10826 		return false;
10827 	uint8_t unpacked[10003];
10828 	C64KoalaStream rle;
10829 	C64KoalaStream_Construct(&rle);
10830 	rle.base.base.base.content = content;
10831 	rle.base.base.base.contentOffset = 2;
10832 	rle.base.base.base.contentLength = contentLength;
10833 	return RleStream_UnpackC64(&rle.base, unpacked, 10003) && RECOIL_DecodeKoa(self, unpacked, 10003);
10834 }
10835 
RECOIL_DecodeDol(RECOIL * self,uint8_t const * content,int contentLength)10836 static bool RECOIL_DecodeDol(RECOIL *self, uint8_t const *content, int contentLength)
10837 {
10838 	switch (contentLength) {
10839 	case 10241:
10840 	case 10242:
10841 	case 10050:
10842 		break;
10843 	default:
10844 		return false;
10845 	}
10846 	return RECOIL_DecodeC64Multicolor(self, 320, content, 2050, 1026, 2, content[2026]);
10847 }
10848 
RECOIL_DecodeAmi(RECOIL * self,uint8_t const * content,int contentLength)10849 static bool RECOIL_DecodeAmi(RECOIL *self, uint8_t const *content, int contentLength)
10850 {
10851 	if (contentLength < 2)
10852 		return false;
10853 	uint8_t unpacked[10259];
10854 	DrpStream rle;
10855 	DrpStream_Construct(&rle);
10856 	rle.base.base.base.content = content;
10857 	rle.base.base.base.contentOffset = 2;
10858 	rle.base.base.base.contentLength = contentLength;
10859 	rle.escape = 194;
10860 	return RleStream_UnpackC64(&rle.base, unpacked, 10259) && RECOIL_DecodeKoa(self, unpacked, 10003);
10861 }
10862 
RECOIL_DecodeHlf(RECOIL * self,uint8_t const * content,int contentLength)10863 static bool RECOIL_DecodeHlf(RECOIL *self, uint8_t const *content, int contentLength)
10864 {
10865 	if (contentLength != 24578)
10866 		return false;
10867 	RECOIL_SetSize(self, 320, 200, RECOILResolution_C641X1);
10868 	RECOIL_DecodeC64HiresFrame(self, content, 2, 9218, 0);
10869 	RECOIL_DecodeC64HiresFrame(self, content, 16386, 10242, 64000);
10870 	return RECOIL_ApplyBlend(self);
10871 }
10872 
RECOIL_DecodeMci(RECOIL * self,uint8_t const * content,int contentLength)10873 static bool RECOIL_DecodeMci(RECOIL *self, uint8_t const *content, int contentLength)
10874 {
10875 	if (contentLength != 19434)
10876 		return false;
10877 	RECOIL_SetSize(self, 320, 200, RECOILResolution_C641X1);
10878 	RECOIL_DecodeC64MulticolorFrame(self, content, 1026, 2, 18434, content[1002], 0);
10879 	self->leftSkip = -1;
10880 	RECOIL_DecodeC64MulticolorFrame(self, content, 9218, 17410, 18434, content[1002], 64000);
10881 	return RECOIL_ApplyBlend(self);
10882 }
10883 
RECOIL_DecodeDrz(RECOIL * self,uint8_t const * content,int contentLength)10884 static bool RECOIL_DecodeDrz(RECOIL *self, uint8_t const *content, int contentLength)
10885 {
10886 	uint8_t unpacked[10051];
10887 	content = DrpStream_UnpackFile(content, contentLength, "DRAZPAINT 1.4", unpacked, 10051);
10888 	return content != NULL && RECOIL_DecodeC64Multicolor(self, 320, content, 2050, 1026, 2, content[10050]);
10889 }
10890 
RECOIL_DecodeDrl(RECOIL * self,uint8_t const * content,int contentLength)10891 static bool RECOIL_DecodeDrl(RECOIL *self, uint8_t const *content, int contentLength)
10892 {
10893 	uint8_t unpacked[18242];
10894 	content = DrpStream_UnpackFile(content, contentLength, "DRAZLACE! 1.0", unpacked, 18242);
10895 	if (content == NULL)
10896 		return false;
10897 	int shift = content[10052];
10898 	if (shift > 1)
10899 		return false;
10900 	RECOIL_SetSize(self, 320, 200, shift == 0 ? RECOILResolution_C642X1 : RECOILResolution_C641X1);
10901 	RECOIL_DecodeC64MulticolorFrame(self, content, 2050, 1026, 2, content[10050], 0);
10902 	self->leftSkip = -shift;
10903 	RECOIL_DecodeC64MulticolorFrame(self, content, 10242, 1026, 2, content[10050], 64000);
10904 	return RECOIL_ApplyBlend(self);
10905 }
10906 
RECOIL_DecodeMleFrame(RECOIL * self,uint8_t const * content,int contentOffset,int pixelsOffset)10907 static void RECOIL_DecodeMleFrame(RECOIL *self, uint8_t const *content, int contentOffset, int pixelsOffset)
10908 {
10909 	for (int y = 0; y < 56; y++) {
10910 		for (int x = 0; x < 320; x++) {
10911 			int c = 0;
10912 			int i = x + self->leftSkip;
10913 			if (i >= 0) {
10914 				int ch = (y >> 3) * 40 + (i >> 3);
10915 				if (ch < 256) {
10916 					static const uint8_t COLORS[4] = { 0, 9, 8, 5 };
10917 					c = COLORS[content[contentOffset + (ch << 3) + (y & 7)] >> (~i & 6) & 3];
10918 				}
10919 			}
10920 			self->pixels[pixelsOffset + y * self->width + x] = RECOIL_C64_PALETTE[c];
10921 		}
10922 	}
10923 }
10924 
RECOIL_DecodeMle(RECOIL * self,uint8_t const * content,int contentLength)10925 static bool RECOIL_DecodeMle(RECOIL *self, uint8_t const *content, int contentLength)
10926 {
10927 	if (contentLength != 4098)
10928 		return false;
10929 	RECOIL_SetSize(self, 320, 56, RECOILResolution_C641X1);
10930 	RECOIL_DecodeMleFrame(self, content, 2050, 0);
10931 	self->leftSkip = -1;
10932 	RECOIL_DecodeMleFrame(self, content, 2, 17920);
10933 	return RECOIL_ApplyBlend(self);
10934 }
10935 
RECOIL_DecodeHimUnpacked(RECOIL * self,uint8_t const * content)10936 static bool RECOIL_DecodeHimUnpacked(RECOIL *self, uint8_t const *content)
10937 {
10938 	RECOIL_SetSize(self, 296, 192, RECOILResolution_C641X1);
10939 	RECOIL_DecodeC64HiresFrame(self, content, 346, 8237, 0);
10940 	return true;
10941 }
10942 
RECOIL_DecodeHim(RECOIL * self,uint8_t const * content,int contentLength)10943 static bool RECOIL_DecodeHim(RECOIL *self, uint8_t const *content, int contentLength)
10944 {
10945 	if (contentLength < 18 || content[0] != 0 || content[1] != 64)
10946 		return false;
10947 	if (content[3] == 255)
10948 		return contentLength == 16385 && RECOIL_DecodeHimUnpacked(self, content);
10949 	if (content[2] + (content[3] << 8) != 16381 + contentLength || content[4] != 242 || content[5] != 127)
10950 		return false;
10951 	uint8_t unpacked[16372];
10952 	HimStream rle;
10953 	HimStream_Construct(&rle);
10954 	rle.base.base.base.content = content;
10955 	rle.base.base.base.contentOffset = contentLength - 1;
10956 	for (int unpackedOffset = 16371; unpackedOffset >= 322; unpackedOffset--) {
10957 		int b = RleStream_ReadRle(&rle.base);
10958 		if (b < 0)
10959 			return false;
10960 		unpacked[unpackedOffset] = (uint8_t) b;
10961 	}
10962 	return RECOIL_DecodeHimUnpacked(self, unpacked);
10963 }
10964 
RECOIL_DecodeEci(RECOIL * self,uint8_t const * content,int contentLength)10965 static bool RECOIL_DecodeEci(RECOIL *self, uint8_t const *content, int contentLength)
10966 {
10967 	if (contentLength != 32770)
10968 		return false;
10969 	RECOIL_SetSize(self, 296, 200, RECOILResolution_C641X1);
10970 	RECOIL_DecodeC64HiresFrame(self, content, 26, 8197, 0);
10971 	RECOIL_DecodeC64HiresFrame(self, content, 16410, 24581, 59200);
10972 	return RECOIL_ApplyBlend(self);
10973 }
10974 
RECOIL_DecodeEcp(RECOIL * self,uint8_t const * content,int contentLength)10975 static bool RECOIL_DecodeEcp(RECOIL *self, uint8_t const *content, int contentLength)
10976 {
10977 	if (contentLength < 6)
10978 		return false;
10979 	uint8_t unpacked[32770];
10980 	DrpStream rle;
10981 	DrpStream_Construct(&rle);
10982 	rle.base.base.base.content = content;
10983 	rle.base.base.base.contentOffset = 3;
10984 	rle.base.base.base.contentLength = contentLength;
10985 	rle.escape = content[2];
10986 	return RleStream_Unpack(&rle.base, unpacked, 2, 1, 32770) && RECOIL_DecodeEci(self, unpacked, 32770);
10987 }
10988 
RECOIL_DecodeFli(RECOIL * self,uint8_t const * content,int contentLength)10989 static bool RECOIL_DecodeFli(RECOIL *self, uint8_t const *content, int contentLength)
10990 {
10991 	switch (contentLength) {
10992 	case 17218:
10993 	case 17409:
10994 	case 17410:
10995 		break;
10996 	default:
10997 		return false;
10998 	}
10999 	RECOIL_DecodeC64Multicolor(self, 296, content, 9242, 1029, 5, 0);
11000 	return true;
11001 }
11002 
RECOIL_DecodeBml(RECOIL * self,uint8_t const * content,int contentLength)11003 static bool RECOIL_DecodeBml(RECOIL *self, uint8_t const *content, int contentLength)
11004 {
11005 	switch (contentLength) {
11006 	case 17474:
11007 	case 17665:
11008 	case 17666:
11009 		break;
11010 	default:
11011 		return false;
11012 	}
11013 	RECOIL_DecodeC64Multicolor(self, 296, content, 9498, 1285, 261, -2);
11014 	return true;
11015 }
11016 
RECOIL_DecodeFbi(RECOIL * self,uint8_t const * content,int contentLength)11017 static bool RECOIL_DecodeFbi(RECOIL *self, uint8_t const *content, int contentLength)
11018 {
11019 	uint8_t unpacked[17216];
11020 	int unpackedOffset = 17216;
11021 	for (int contentOffset = contentLength; contentOffset > 18;) {
11022 		int count = 1;
11023 		int b = content[--contentOffset];
11024 		if (b == content[2]) {
11025 			if (contentOffset <= 19)
11026 				return false;
11027 			count = content[--contentOffset];
11028 			if (count == 0)
11029 				count = 256;
11030 			b = content[--contentOffset];
11031 		}
11032 		if (unpackedOffset < count)
11033 			return false;
11034 		do
11035 			unpacked[--unpackedOffset] = (uint8_t) b;
11036 		while (--count > 0);
11037 	}
11038 	if (unpackedOffset != 0)
11039 		return false;
11040 	RECOIL_DecodeC64Multicolor(self, 296, unpacked, 9240, 1027, 3, 0);
11041 	return true;
11042 }
11043 
RECOIL_DecodeFfli(RECOIL * self,uint8_t const * content,int contentLength)11044 static bool RECOIL_DecodeFfli(RECOIL *self, uint8_t const *content, int contentLength)
11045 {
11046 	if (contentLength != 26115 || content[2] != 102)
11047 		return false;
11048 	RECOIL_DecodeC64Multicolor(self, 296, content, 9499, 1286, 262, -3);
11049 	RECOIL_DecodeC64MulticolorFrame(self, content, 9499, 17670, 262, -25859, 59200);
11050 	return RECOIL_ApplyBlend(self);
11051 }
11052 
RECOIL_DecodeIfli(RECOIL * self,uint8_t const * content,int bitmap1Offset,int bitmap2Offset,int videoMatrix1Offset,int videoMatrix2Offset,int colorOffset,int background)11053 static bool RECOIL_DecodeIfli(RECOIL *self, uint8_t const *content, int bitmap1Offset, int bitmap2Offset, int videoMatrix1Offset, int videoMatrix2Offset, int colorOffset, int background)
11054 {
11055 	RECOIL_SetSize(self, 296, 200, RECOILResolution_C641X1);
11056 	RECOIL_DecodeC64MulticolorFrame(self, content, bitmap1Offset + 24, videoMatrix1Offset + 3, colorOffset + 3, background, 0);
11057 	self->leftSkip = -1;
11058 	RECOIL_DecodeC64MulticolorFrame(self, content, bitmap2Offset + 24, videoMatrix2Offset + 3, colorOffset + 3, background, 59200);
11059 	return RECOIL_ApplyBlend(self);
11060 }
11061 
RECOIL_DecodePpUnpacked(RECOIL * self,uint8_t const * content)11062 static bool RECOIL_DecodePpUnpacked(RECOIL *self, uint8_t const *content)
11063 {
11064 	return RECOIL_DecodeIfli(self, content, 9218, 25602, 1026, 17410, 2, content[17281]);
11065 }
11066 
RECOIL_DecodePp(RECOIL * self,uint8_t const * content,int contentLength)11067 static bool RECOIL_DecodePp(RECOIL *self, uint8_t const *content, int contentLength)
11068 {
11069 	if (contentLength < 8)
11070 		return false;
11071 	if (content[2] == 16 && content[3] == 16 && content[4] == 16) {
11072 		uint8_t unpacked[33602];
11073 		CmpStream rle;
11074 		CmpStream_Construct(&rle);
11075 		rle.base.base.base.content = content;
11076 		rle.base.base.base.contentOffset = 6;
11077 		rle.base.base.base.contentLength = contentLength;
11078 		rle.escape = content[5];
11079 		return RleStream_Unpack(&rle.base, unpacked, 2, 1, 33602) && RleStream_ReadRle(&rle.base) < 0 && RECOIL_DecodePpUnpacked(self, unpacked);
11080 	}
11081 	return contentLength == 33602 && RECOIL_DecodePpUnpacked(self, content);
11082 }
11083 
RECOIL_DecodeGun(RECOIL * self,uint8_t const * content,int contentLength)11084 static bool RECOIL_DecodeGun(RECOIL *self, uint8_t const *content, int contentLength)
11085 {
11086 	if (contentLength != 33602 && contentLength != 33603)
11087 		return false;
11088 	return RECOIL_DecodeIfli(self, content, 8194, 25602, 2, 17410, 16386, -16209);
11089 }
11090 
RECOIL_DecodeFunUnpacked(RECOIL * self,uint8_t const * content)11091 static bool RECOIL_DecodeFunUnpacked(RECOIL *self, uint8_t const *content)
11092 {
11093 	return RECOIL_DecodeIfli(self, content, 8210, 25594, 18, 17402, 16402, 0);
11094 }
11095 
RECOIL_DecodeC64Fun(RECOIL * self,uint8_t const * content,int contentLength)11096 static bool RECOIL_DecodeC64Fun(RECOIL *self, uint8_t const *content, int contentLength)
11097 {
11098 	if (contentLength < 18 || !RECOIL_IsStringAt(content, 2, "FUNPAINT (MT) "))
11099 		return false;
11100 	if (content[16] != 0) {
11101 		uint8_t unpacked[33694];
11102 		DrpStream rle;
11103 		DrpStream_Construct(&rle);
11104 		rle.base.base.base.content = content;
11105 		rle.base.base.base.contentOffset = 18;
11106 		rle.base.base.base.contentLength = contentLength;
11107 		rle.escape = content[17];
11108 		return RleStream_Unpack(&rle.base, unpacked, 18, 1, 33694) && RleStream_ReadRle(&rle.base) < 0 && RECOIL_DecodeFunUnpacked(self, unpacked);
11109 	}
11110 	return contentLength == 33694 && RECOIL_DecodeFunUnpacked(self, content);
11111 }
11112 
RECOIL_DecodeBfli(RECOIL * self,uint8_t const * content,int contentLength)11113 static bool RECOIL_DecodeBfli(RECOIL *self, uint8_t const *content, int contentLength)
11114 {
11115 	if (contentLength != 33795 || content[2] != 98)
11116 		return false;
11117 	RECOIL_SetSize(self, 296, 400, RECOILResolution_C642X1);
11118 	RECOIL_DecodeC64MulticolorFrame(self, content, 9243, 1030, 6, 0, 0);
11119 	RECOIL_DecodeC64MulticolorFrame(self, content, 25603, 17411, 3, 0, 59200);
11120 	return true;
11121 }
11122 
RECOIL_DecodeLp3(RECOIL * self,uint8_t const * content,int contentLength)11123 static bool RECOIL_DecodeLp3(RECOIL *self, uint8_t const *content, int contentLength)
11124 {
11125 	switch (contentLength) {
11126 	case 4098:
11127 	case 4174:
11128 		break;
11129 	default:
11130 		return false;
11131 	}
11132 	if (content[0] != 0 || content[1] != 24)
11133 		return false;
11134 	RECOIL_SetSize(self, 320, 400, RECOILResolution_C642X1);
11135 	uint8_t colors[4];
11136 	if (contentLength == 4174) {
11137 		colors[0] = (uint8_t) (content[2045] & 15);
11138 		colors[1] = (uint8_t) (content[2047] & 15);
11139 		colors[2] = (uint8_t) (content[2048] & 15);
11140 		colors[3] = (uint8_t) (content[2046] & 7);
11141 	}
11142 	else {
11143 		colors[0] = 0;
11144 		colors[1] = 10;
11145 		colors[2] = 2;
11146 		colors[3] = 1;
11147 	}
11148 	for (int y = 0; y < 400; y++) {
11149 		for (int x = 0; x < 320; x++) {
11150 			int c = content[2 + (y >> 3) * 40 + (x >> 3)];
11151 			c = content[2050 + (c << 3) + (y & 7)] >> (~x & 6) & 3;
11152 			self->pixels[y * 320 + x] = RECOIL_C64_PALETTE[colors[c]];
11153 		}
11154 	}
11155 	return true;
11156 }
11157 
RECOIL_DecodeVic(RECOIL * self,uint8_t const * content,int contentLength)11158 static bool RECOIL_DecodeVic(RECOIL *self, uint8_t const *content, int contentLength)
11159 {
11160 	switch (contentLength) {
11161 	case 9002:
11162 	case 9003:
11163 	case 9009:
11164 		return RECOIL_DecodeIph(self, content, contentLength);
11165 	case 10018:
11166 		return RECOIL_DecodeOcp(self, content, contentLength);
11167 	case 10241:
11168 	case 10242:
11169 		return RECOIL_DecodeDol(self, content, contentLength);
11170 	case 17218:
11171 	case 17409:
11172 	case 17410:
11173 		return RECOIL_DecodeFli(self, content, contentLength);
11174 	case 17474:
11175 	case 17665:
11176 	case 17666:
11177 		return RECOIL_DecodeBml(self, content, contentLength);
11178 	case 18242:
11179 		return RECOIL_DecodeDrl(self, content, contentLength);
11180 	case 33602:
11181 	case 33603:
11182 		return RECOIL_DecodeGun(self, content, contentLength);
11183 	case 33694:
11184 		return RECOIL_DecodeC64Fun(self, content, contentLength);
11185 	default:
11186 		return false;
11187 	}
11188 }
11189 
RECOIL_DecodeA(RECOIL * self,uint8_t const * content,int contentLength)11190 static bool RECOIL_DecodeA(RECOIL *self, uint8_t const *content, int contentLength)
11191 {
11192 	if (contentLength != 8130 || content[0] != 66 || content[1] != 0)
11193 		return false;
11194 	RECOIL_SetSize(self, 416, 182, RECOILResolution_C642X1);
11195 	for (int y = 0; y < 182; y++) {
11196 		for (int x = 0; x < 416; x++) {
11197 			int c = 11;
11198 			int row = y % 23;
11199 			if (row < 21) {
11200 				int column = x % 26;
11201 				if (column < 24) {
11202 					int spriteNo = x / 26 + (y / 23 << 4);
11203 					if (spriteNo < 127) {
11204 						int spriteOffset = 2 + (spriteNo << 6);
11205 						switch (content[spriteOffset + row * 3 + (column >> 3)] >> (~column & 6) & 3) {
11206 						case 1:
11207 							c = 0;
11208 							break;
11209 						case 2:
11210 							c = content[spriteOffset + 63] & 15;
11211 							break;
11212 						case 3:
11213 							c = 1;
11214 							break;
11215 						default:
11216 							break;
11217 						}
11218 					}
11219 				}
11220 			}
11221 			self->pixels[y * 416 + x] = RECOIL_C64_PALETTE[c];
11222 		}
11223 	}
11224 	return true;
11225 }
11226 
RECOIL_DecodeSpd(RECOIL * self,uint8_t const * content,int contentLength)11227 static bool RECOIL_DecodeSpd(RECOIL *self, uint8_t const *content, int contentLength)
11228 {
11229 	if (contentLength < 67)
11230 		return false;
11231 	int headerLength;
11232 	int spriteCount;
11233 	if (content[0] == 83 && content[1] == 80 && content[2] == 68 && content[3] == 1) {
11234 		headerLength = 6;
11235 		spriteCount = content[4] + 1;
11236 		if (contentLength < 9 + (spriteCount << 6))
11237 			return false;
11238 	}
11239 	else {
11240 		if ((contentLength & 63) != 3 || content[0] > 15 || content[1] > 15 || content[2] > 15)
11241 			return false;
11242 		headerLength = 0;
11243 		spriteCount = contentLength >> 6;
11244 	}
11245 	RECOILResolution resolution = RECOILResolution_C642X1;
11246 	for (int spriteNo = 0; spriteNo < spriteCount; spriteNo++) {
11247 		if (content[headerLength + 66 + (spriteNo << 6)] < 128) {
11248 			resolution = RECOILResolution_C641X1;
11249 			break;
11250 		}
11251 	}
11252 	int width;
11253 	int height;
11254 	if (spriteCount <= 16) {
11255 		width = spriteCount * 26 - 2;
11256 		height = 21;
11257 	}
11258 	else {
11259 		width = 414;
11260 		height = ((spriteCount + 15) >> 4) * 23 - 2;
11261 	}
11262 	if (!RECOIL_SetSize(self, width, height, resolution))
11263 		return false;
11264 	for (int y = 0; y < height; y++) {
11265 		for (int x = 0; x < width; x++) {
11266 			int c = 0;
11267 			int row = y % 23;
11268 			if (row < 21) {
11269 				int column = x % 26;
11270 				if (column < 24) {
11271 					int spriteNo = x / 26 + (y / 23 << 4);
11272 					if (spriteNo < spriteCount) {
11273 						int spriteOffset = 3 + (spriteNo << 6);
11274 						int b = content[headerLength + spriteOffset + row * 3 + (column >> 3)];
11275 						if (content[headerLength + spriteOffset + 63] < 128) {
11276 							if ((b >> (~column & 7) & 1) != 0)
11277 								c = spriteOffset + 63;
11278 						}
11279 						else {
11280 							switch (b >> (~column & 6) & 3) {
11281 							case 1:
11282 								c = 1;
11283 								break;
11284 							case 2:
11285 								c = spriteOffset + 63;
11286 								break;
11287 							case 3:
11288 								c = 2;
11289 								break;
11290 							default:
11291 								break;
11292 							}
11293 						}
11294 					}
11295 				}
11296 			}
11297 			self->pixels[y * width + x] = RECOIL_C64_PALETTE[content[headerLength + c] & 15];
11298 		}
11299 	}
11300 	return true;
11301 }
11302 
RECOIL_DecodePetScreen(RECOIL * self,uint8_t const * content,int screenOffset,int colorsOffset,int backgroundOffset,int columns,int rows)11303 static bool RECOIL_DecodePetScreen(RECOIL *self, uint8_t const *content, int screenOffset, int colorsOffset, int backgroundOffset, int columns, int rows)
11304 {
11305 	int width = columns << 3;
11306 	int height = rows << 3;
11307 	if (!RECOIL_SetSize(self, width, height, RECOILResolution_C641X1))
11308 		return false;
11309 	uint8_t const *font = CiResource_c64_fnt;
11310 	for (int y = 0; y < height; y++) {
11311 		for (int x = 0; x < width; x++) {
11312 			int offset = (y >> 3) * columns + (x >> 3);
11313 			if ((font[content[screenOffset + offset] << 3 | (y & 7)] >> (~x & 7) & 1) == 0)
11314 				offset = backgroundOffset;
11315 			else
11316 				offset += colorsOffset;
11317 			self->pixels[y * width + x] = RECOIL_C64_PALETTE[content[offset] & 15];
11318 		}
11319 	}
11320 	return true;
11321 }
11322 
RECOIL_DecodePet(RECOIL * self,uint8_t const * content,int contentLength)11323 static bool RECOIL_DecodePet(RECOIL *self, uint8_t const *content, int contentLength)
11324 {
11325 	return contentLength == 2026 && RECOIL_DecodePetScreen(self, content, 2, 1026, 1003, 40, 25);
11326 }
11327 
RECOIL_DecodeScrCol(RECOIL * self,const char * filename,uint8_t const * content,int contentLength)11328 static bool RECOIL_DecodeScrCol(RECOIL *self, const char *filename, uint8_t const *content, int contentLength)
11329 {
11330 	if (contentLength != 1002)
11331 		return false;
11332 	uint8_t colors[1003];
11333 	if (RECOIL_ReadCompanionFile(self, filename, "COL", "col", colors, 1003) != 1002)
11334 		return false;
11335 	RECOIL_SetSize(self, 320, 200, RECOILResolution_C641X1);
11336 	uint8_t const *font = CiResource_c64_fnt;
11337 	for (int y = 0; y < 200; y++) {
11338 		for (int x = 0; x < 320; x++) {
11339 			int offset = 2 + (y & -8) * 5 + (x >> 3);
11340 			int c;
11341 			if ((font[content[offset] << 3 | (y & 7)] >> (~x & 7) & 1) == 0)
11342 				c = 0;
11343 			else
11344 				c = colors[offset] & 15;
11345 			self->pixels[y * 320 + x] = RECOIL_C64_PALETTE[c];
11346 		}
11347 	}
11348 	return true;
11349 }
11350 
RECOIL_DecodeFpr(RECOIL * self,uint8_t const * content,int contentLength)11351 static bool RECOIL_DecodeFpr(RECOIL *self, uint8_t const *content, int contentLength)
11352 {
11353 	if (contentLength != 18370)
11354 		return false;
11355 	RECOIL_SetSize(self, 320, 200, RECOILResolution_C642X1);
11356 	for (int y = 0; y < 200; y++) {
11357 		for (int x = 0; x < 320; x++) {
11358 			int offset = (y >> 3) * 40 + (x >> 3);
11359 			int c = x < 24 ? 255 : content[2178 + offset + ((y & 7) << 10)];
11360 			switch (content[10370 + (offset << 3) + (y & 7)] >> (~x & 6) & 3) {
11361 			case 0:
11362 				c = 0;
11363 				break;
11364 			case 1:
11365 				c >>= 4;
11366 				break;
11367 			case 3:
11368 				c = x < 24 ? content[898 + y] >> 4 : content[1154 + offset];
11369 				break;
11370 			default:
11371 				break;
11372 			}
11373 			if (x < 24) {
11374 				switch (content[2 + (((((y + 1) & 2) != 0 ? 5 : 0) + y / 42) << 6) + (y >> 1) % 21 * 3 + (x >> 3)] >> (~x & 6) & 3) {
11375 				case 1:
11376 					c = content[642 + y];
11377 					break;
11378 				case 2:
11379 					c = content[1098];
11380 					break;
11381 				case 3:
11382 					c = content[1099];
11383 					break;
11384 				default:
11385 					break;
11386 				}
11387 			}
11388 			self->pixels[y * 320 + x] = RECOIL_C64_PALETTE[c & 15];
11389 		}
11390 	}
11391 	return true;
11392 }
11393 
RECOIL_DecodeCtm(RECOIL * self,uint8_t const * content,int contentLength)11394 static bool RECOIL_DecodeCtm(RECOIL *self, uint8_t const *content, int contentLength)
11395 {
11396 	if (contentLength < 30 || content[0] != 67 || content[1] != 84 || content[2] != 77 || content[3] != 5)
11397 		return false;
11398 	int colorMethod = content[8];
11399 	if (colorMethod > 2)
11400 		return false;
11401 	int flags = content[9];
11402 	bool tiles = (flags & 1) != 0;
11403 	if (colorMethod == 1 && !tiles)
11404 		return false;
11405 	bool charex = (flags & 2) != 0;
11406 	bool multi = (flags & 4) != 0;
11407 	int charCount = content[10] + (content[11] << 8) + 1;
11408 	int tileCount = tiles ? content[12] + (content[13] << 8) + 1 : 0;
11409 	int tileWidth = tiles ? content[14] : 1;
11410 	int tileHeight = tiles ? content[15] : 1;
11411 	if (tileWidth == 0 || tileHeight == 0)
11412 		return false;
11413 	int mapWidth = content[16] | content[17] << 8;
11414 	int mapHeight = content[18] | content[19] << 8;
11415 	int tilesOffset = 20 + charCount * 9;
11416 	int tileColorsOffset = charex ? tilesOffset : tilesOffset + tileCount * (tileWidth * tileHeight << 1);
11417 	int mapOffset = colorMethod == 1 ? tileColorsOffset + tileCount : tileColorsOffset;
11418 	if (contentLength != mapOffset + (mapWidth * mapHeight << 1))
11419 		return false;
11420 	int width = mapWidth * tileWidth << 3;
11421 	int height = mapHeight * tileHeight << 3;
11422 	if (!RECOIL_SetSize(self, width, height, multi ? RECOILResolution_C642X1 : RECOILResolution_C641X1))
11423 		return false;
11424 	for (int y = 0; y < height; y++) {
11425 		int mapRowOffset = mapOffset + ((y >> 3) / tileHeight * mapWidth << 1);
11426 		for (int x = 0; x < width; x++) {
11427 			int mapTileOffset = mapRowOffset + ((x >> 3) / tileWidth << 1);
11428 			int tile = content[mapTileOffset] | content[mapTileOffset + 1] << 8;
11429 			int ch;
11430 			if (tiles) {
11431 				if (tile >= tileCount)
11432 					return false;
11433 				ch = (tile * tileHeight + (y >> 3) % tileHeight) * tileWidth + (x >> 3) % tileWidth;
11434 				if (!charex) {
11435 					int tileOffset = tilesOffset + (ch << 1);
11436 					ch = content[tileOffset] | content[tileOffset + 1] << 8;
11437 				}
11438 			}
11439 			else
11440 				ch = tile;
11441 			if (ch >= charCount)
11442 				return false;
11443 			int foregroundOffset;
11444 			switch (colorMethod) {
11445 			case 1:
11446 				foregroundOffset = tileColorsOffset + tile;
11447 				break;
11448 			case 2:
11449 				foregroundOffset = 20 + (charCount << 3) + ch;
11450 				break;
11451 			default:
11452 				foregroundOffset = 7;
11453 				break;
11454 			}
11455 			int c = content[20 + (ch << 3) + (y & 7)];
11456 			if (multi) {
11457 				c = c >> (~x & 6) & 3;
11458 				if (c == 3)
11459 					c = content[foregroundOffset] & 7;
11460 				else
11461 					c = content[4 + c];
11462 			}
11463 			else {
11464 				c = c >> (~x & 7) & 1;
11465 				c = content[c == 0 ? 4 : foregroundOffset];
11466 			}
11467 			self->pixels[y * width + x] = RECOIL_C64_PALETTE[c & 15];
11468 		}
11469 	}
11470 	return true;
11471 }
11472 
RECOIL_DecodeDoo(RECOIL * self,uint8_t const * content,int contentLength)11473 static bool RECOIL_DecodeDoo(RECOIL *self, uint8_t const *content, int contentLength)
11474 {
11475 	RECOIL_SetSize(self, 640, 400, RECOILResolution_ST1X1);
11476 	return RECOIL_DecodeBlackAndWhite(self, content, 0, contentLength, false, 16777215);
11477 }
11478 
RECOIL_DecodeDa4(RECOIL * self,uint8_t const * content,int contentLength)11479 static bool RECOIL_DecodeDa4(RECOIL *self, uint8_t const *content, int contentLength)
11480 {
11481 	RECOIL_SetSize(self, 640, 800, RECOILResolution_ST1X1);
11482 	return RECOIL_DecodeBlackAndWhite(self, content, 0, contentLength, false, 16777215);
11483 }
11484 
RECOIL_DecodeCmp(RECOIL * self,uint8_t const * content,int contentLength)11485 static bool RECOIL_DecodeCmp(RECOIL *self, uint8_t const *content, int contentLength)
11486 {
11487 	if (contentLength < 5)
11488 		return false;
11489 	switch (content[1]) {
11490 	case 0:
11491 		RECOIL_SetSize(self, 640, 400, RECOILResolution_ST1X1);
11492 		break;
11493 	case 200:
11494 		RECOIL_SetSize(self, 640, 800, RECOILResolution_ST1X1);
11495 		break;
11496 	default:
11497 		return false;
11498 	}
11499 	CmpStream rle;
11500 	CmpStream_Construct(&rle);
11501 	rle.base.base.base.content = content;
11502 	rle.base.base.base.contentOffset = 2;
11503 	rle.base.base.base.contentLength = contentLength;
11504 	rle.escape = content[0];
11505 	return RECOIL_DecodeRleBlackAndWhite(self, &rle.base, 16777215);
11506 }
11507 
RECOIL_DecodeBld(RECOIL * self,uint8_t const * content,int contentLength)11508 static bool RECOIL_DecodeBld(RECOIL *self, uint8_t const *content, int contentLength)
11509 {
11510 	if (contentLength < 5)
11511 		return false;
11512 	int width = content[0] << 8 | content[1];
11513 	int height = content[2] << 8 | content[3];
11514 	if (content[0] < 128)
11515 		return RECOIL_SetSize(self, width, height, RECOILResolution_ST1X1) && RECOIL_DecodeBlackAndWhite(self, content, 4, contentLength, false, 16777215);
11516 	if (!RECOIL_SetSize(self, 65536 - width, height, RECOILResolution_ST1X1))
11517 		return false;
11518 	BldStream rle;
11519 	BldStream_Construct(&rle);
11520 	rle.base.base.base.content = content;
11521 	rle.base.base.base.contentOffset = 4;
11522 	rle.base.base.base.contentLength = contentLength;
11523 	return RECOIL_DecodeRleBlackAndWhite(self, &rle.base, 16777215);
11524 }
11525 
RECOIL_DecodeCrg(RECOIL * self,uint8_t const * content,int contentLength)11526 static bool RECOIL_DecodeCrg(RECOIL *self, uint8_t const *content, int contentLength)
11527 {
11528 	if (contentLength < 43 || !RECOIL_IsStringAt(content, 0, "CALAMUSCRG") || content[10] != 3 || content[11] != 232 || content[12] != 0 || content[13] != 2)
11529 		return false;
11530 	int width = RECOIL_Get32BigEndian(content, 20);
11531 	int height = RECOIL_Get32BigEndian(content, 24);
11532 	if (!RECOIL_SetSize(self, width, height, RECOILResolution_ST1X1))
11533 		return false;
11534 	CciStream rle;
11535 	CciStream_Construct(&rle);
11536 	rle.base.base.base.content = content;
11537 	rle.base.base.base.contentOffset = 42;
11538 	rle.base.base.base.contentLength = contentLength;
11539 	return RECOIL_DecodeRleBlackAndWhite(self, &rle.base, 16777215);
11540 }
11541 
RECOIL_DecodePac(RECOIL * self,uint8_t const * content,int contentLength)11542 static bool RECOIL_DecodePac(RECOIL *self, uint8_t const *content, int contentLength)
11543 {
11544 	if (contentLength < 8 || content[0] != 112 || content[1] != 77 || content[2] != 56)
11545 		return false;
11546 	int unpackedStride;
11547 	switch (content[3]) {
11548 	case 53:
11549 		unpackedStride = 1;
11550 		break;
11551 	case 54:
11552 		unpackedStride = 80;
11553 		break;
11554 	default:
11555 		return false;
11556 	}
11557 	PacStream rle;
11558 	PacStream_Construct(&rle);
11559 	rle.base.base.base.content = content;
11560 	rle.base.base.base.contentOffset = 7;
11561 	rle.base.base.base.contentLength = contentLength;
11562 	uint8_t unpacked[32000];
11563 	return RleStream_UnpackColumns(&rle.base, unpacked, 0, unpackedStride, 32000) && RECOIL_DecodeDoo(self, unpacked, 32000);
11564 }
11565 
RECOIL_FillPscLine(uint8_t * unpacked,int unpackedOffset,int value)11566 static int RECOIL_FillPscLine(uint8_t *unpacked, int unpackedOffset, int value)
11567 {
11568 	for (int i = 0; i < 80; i++)
11569 		unpacked[unpackedOffset + i] = (uint8_t) value;
11570 	return unpackedOffset + 80;
11571 }
11572 
RECOIL_CopyPscLines(uint8_t * unpacked,int unpackedOffset,int count)11573 static int RECOIL_CopyPscLines(uint8_t *unpacked, int unpackedOffset, int count)
11574 {
11575 	if (unpackedOffset < 80 || unpackedOffset + count * 80 > 32000)
11576 		return -1;
11577 	do {
11578 		memcpy(unpacked + unpackedOffset, unpacked + unpackedOffset - 80, 80);
11579 		unpackedOffset += 80;
11580 	}
11581 	while (--count > 0);
11582 	return unpackedOffset;
11583 }
11584 
RECOIL_DecodePsc(RECOIL * self,uint8_t const * content,int contentLength)11585 static bool RECOIL_DecodePsc(RECOIL *self, uint8_t const *content, int contentLength)
11586 {
11587 	if (contentLength < 18 || !RECOIL_IsStringAt(content, 0, "tm89PS") || content[6] != 0 || content[7] != 203 || content[8] != 2 || content[9] != 1 || content[10] != 2 || content[11] != 127 || content[12] != 1 || content[13] != 143)
11588 		return false;
11589 	uint8_t unpacked[32000];
11590 	if (content[14] == 99 && contentLength == 32016 && content[32015] == 255)
11591 		memcpy(unpacked, content + 15, 32000);
11592 	else {
11593 		int contentOffset = 14;
11594 		for (int unpackedOffset = 0; unpackedOffset < 32000;) {
11595 			if (contentOffset + 1 >= contentLength)
11596 				return false;
11597 			switch (content[contentOffset++]) {
11598 			case 0:
11599 				unpackedOffset = RECOIL_FillPscLine(unpacked, unpackedOffset, 0);
11600 				break;
11601 			case 10:
11602 				unpackedOffset = RECOIL_CopyPscLines(unpacked, unpackedOffset, 1 + content[contentOffset++]);
11603 				if (unpackedOffset < 0)
11604 					return false;
11605 				break;
11606 			case 12:
11607 				unpackedOffset = RECOIL_CopyPscLines(unpacked, unpackedOffset, 257 + content[contentOffset++]);
11608 				if (unpackedOffset < 0)
11609 					return false;
11610 				break;
11611 			case 100:
11612 				unpackedOffset = RECOIL_FillPscLine(unpacked, unpackedOffset, content[contentOffset++]);
11613 				break;
11614 			case 102:
11615 				if (contentOffset + 2 >= contentLength)
11616 					return false;
11617 				for (int i = 0; i < 80; i += 2)
11618 					memcpy(unpacked + unpackedOffset + i, content + contentOffset, 2);
11619 				contentOffset += 2;
11620 				unpackedOffset += 80;
11621 				break;
11622 			case 110:
11623 				if (contentOffset + 80 >= contentLength)
11624 					return false;
11625 				memcpy(unpacked + unpackedOffset, content + contentOffset, 80);
11626 				contentOffset += 80;
11627 				unpackedOffset += 80;
11628 				break;
11629 			case 200:
11630 				unpackedOffset = RECOIL_FillPscLine(unpacked, unpackedOffset, 255);
11631 				break;
11632 			default:
11633 				return false;
11634 			}
11635 		}
11636 		if (contentOffset >= contentLength || content[contentOffset] != 255)
11637 			return false;
11638 	}
11639 	return RECOIL_DecodeDoo(self, unpacked, 32000);
11640 }
11641 
RECOIL_DecodeCp3(RECOIL * self,uint8_t const * content,int contentLength)11642 static bool RECOIL_DecodeCp3(RECOIL *self, uint8_t const *content, int contentLength)
11643 {
11644 	if (contentLength < 4)
11645 		return false;
11646 	int countLength = (1 + (content[0] << 8) + content[1]) << 2;
11647 	if (contentLength <= countLength)
11648 		return false;
11649 	int valueOffset = countLength;
11650 	uint8_t unpacked[32000];
11651 	int unpackedOffset = 0;
11652 	int count;
11653 	for (int countOffset = 4; countOffset < countLength; countOffset += 4) {
11654 		count = (content[countOffset] << 8 | content[countOffset + 1]) << 3;
11655 		if (valueOffset + count + 8 > contentLength || unpackedOffset + count > 32000)
11656 			return false;
11657 		memcpy(unpacked + unpackedOffset, content + valueOffset, count);
11658 		valueOffset += count;
11659 		unpackedOffset += count;
11660 		count = (content[countOffset + 2] << 8 | content[countOffset + 3]) << 3;
11661 		if (unpackedOffset + count > 32000)
11662 			return false;
11663 		for (int offset = 0; offset < count; offset += 8)
11664 			memcpy(unpacked + unpackedOffset + offset, content + valueOffset, 8);
11665 		valueOffset += 8;
11666 		unpackedOffset += count;
11667 	}
11668 	count = 32000 - unpackedOffset;
11669 	if (valueOffset + count != contentLength)
11670 		return false;
11671 	memcpy(unpacked + unpackedOffset, content + valueOffset, count);
11672 	return RECOIL_DecodeDoo(self, unpacked, 32000);
11673 }
11674 
RECOIL_DecodeStFnt(RECOIL * self,uint8_t const * content,int contentLength)11675 static bool RECOIL_DecodeStFnt(RECOIL *self, uint8_t const *content, int contentLength)
11676 {
11677 	switch (contentLength) {
11678 	case 2050:
11679 		RECOIL_SetSize(self, 256, 64, RECOILResolution_ST1X1);
11680 		break;
11681 	case 4096:
11682 	case 4098:
11683 		RECOIL_SetSize(self, 256, 128, RECOILResolution_ST1X1);
11684 		break;
11685 	default:
11686 		return false;
11687 	}
11688 	if ((contentLength & 2) != 0) {
11689 		if (content[contentLength - 2] != 0 || content[contentLength - 2] > 1)
11690 			return false;
11691 		contentLength -= 2;
11692 	}
11693 	RECOIL_DecodeBlackAndWhiteFont(self, content, 0, contentLength, 16);
11694 	return true;
11695 }
11696 
RECOIL_DecodeGdosFnt(RECOIL * self,uint8_t const * content,int contentLength)11697 static bool RECOIL_DecodeGdosFnt(RECOIL *self, uint8_t const *content, int contentLength)
11698 {
11699 	if (contentLength < 88 || content[62] != 85 || content[63] != 85)
11700 		return false;
11701 	EndianStream stream;
11702 	if (content[3] == 0) {
11703 		if (content[2] == 0)
11704 			return false;
11705 		stream.bigEndian = false;
11706 	}
11707 	else if (content[2] == 0)
11708 		stream.bigEndian = true;
11709 	else
11710 		return false;
11711 	stream.base.content = content;
11712 	stream.base.contentLength = contentLength;
11713 	stream.base.contentOffset = 36;
11714 	int firstCharacter = EndianStream_ReadWord(&stream);
11715 	int lastCharacter = EndianStream_ReadWord(&stream);
11716 	if (firstCharacter > lastCharacter)
11717 		return false;
11718 	stream.base.contentOffset = 72;
11719 	int characterOffset = EndianStream_ReadInt(&stream);
11720 	if (characterOffset <= 0 || characterOffset >= contentLength)
11721 		return false;
11722 	int bitmapOffset = EndianStream_ReadInt(&stream);
11723 	if (bitmapOffset < 0 || bitmapOffset >= contentLength)
11724 		return false;
11725 	int bytesPerLine = EndianStream_ReadWord(&stream);
11726 	if (bytesPerLine == 0)
11727 		return false;
11728 	int height = EndianStream_ReadWord(&stream);
11729 	if (height == 0 || bitmapOffset + height * bytesPerLine > contentLength)
11730 		return false;
11731 	int characterEndOffset = characterOffset + ((lastCharacter - firstCharacter + 2) << 1);
11732 	if (characterEndOffset > bitmapOffset)
11733 		return false;
11734 	int width = height << 4;
11735 	if (width > 10000)
11736 		width = 10000;
11737 	stream.base.contentOffset = characterOffset;
11738 	stream.base.contentLength = characterEndOffset;
11739 	int leftX = 0;
11740 	int nextX = 0;
11741 	int row;
11742 	for (row = 0; nextX >= 0 && (row + height) * width <= 2854278; row += height) {
11743 		int rightX;
11744 		do {
11745 			rightX = nextX;
11746 			nextX = EndianStream_ReadWord(&stream);
11747 			if (nextX < rightX) {
11748 				if (nextX < 0)
11749 					break;
11750 				return false;
11751 			}
11752 			if (nextX > bytesPerLine << 3) {
11753 				nextX = -1;
11754 				break;
11755 			}
11756 		}
11757 		while (nextX - leftX <= width);
11758 		for (int y = 0; y < height; y++) {
11759 			for (int x = 0; x < width; x++) {
11760 				int fontX = leftX + x;
11761 				int c;
11762 				if (fontX < rightX) {
11763 					int offset = bitmapOffset + y * bytesPerLine + (fontX >> 3);
11764 					c = (content[offset] >> (~fontX & 7) & 1) == 0 ? 16777215 : 0;
11765 				}
11766 				else
11767 					c = 16777215;
11768 				self->pixels[(row + y) * width + x] = c;
11769 			}
11770 		}
11771 		leftX = rightX;
11772 	}
11773 	return RECOIL_SetSize(self, width, row, RECOILResolution_ST1X1);
11774 }
11775 
RECOIL_IsStePalette(uint8_t const * content,int contentOffset,int colors)11776 static bool RECOIL_IsStePalette(uint8_t const *content, int contentOffset, int colors)
11777 {
11778 	while (--colors >= 0) {
11779 		if ((content[contentOffset] & 8) != 0 || (content[contentOffset + 1] & 136) != 0)
11780 			return true;
11781 		contentOffset += 2;
11782 	}
11783 	return false;
11784 }
11785 
RECOIL_GetStColor(const RECOIL * self,uint8_t const * content,int contentOffset)11786 static int RECOIL_GetStColor(const RECOIL *self, uint8_t const *content, int contentOffset)
11787 {
11788 	int r = content[contentOffset];
11789 	int gb = content[contentOffset + 1];
11790 	int rgb;
11791 	switch (self->resolution) {
11792 	case RECOILResolution_ST1X1:
11793 	case RECOILResolution_ST1X2:
11794 		rgb = (r & 7) << 16 | (gb & 112) << 4 | (gb & 7);
11795 		return rgb << 5 | rgb << 2 | (rgb >> 1 & 197379);
11796 	default:
11797 		rgb = (r & 7) << 17 | (r & 8) << 13 | (gb & 112) << 5 | (gb & 135) << 1 | (gb & 8) >> 3;
11798 		return rgb << 4 | rgb;
11799 	}
11800 }
11801 
RECOIL_SetStPalette(RECOIL * self,uint8_t const * content,int contentOffset,int colors)11802 static void RECOIL_SetStPalette(RECOIL *self, uint8_t const *content, int contentOffset, int colors)
11803 {
11804 	for (int c = 0; c < colors; c++)
11805 		self->contentPalette[c] = RECOIL_GetStColor(self, content, contentOffset + c * 2);
11806 }
11807 
RECOIL_GetSteInterlacedColor(int rgb)11808 static int RECOIL_GetSteInterlacedColor(int rgb)
11809 {
11810 	rgb = (rgb & 1792) << 10 | (rgb & 2160) << 6 | (rgb & 16519) << 2 | (rgb & 8192) >> 5 | (rgb & 8) >> 2 | (rgb & 4096) >> 12;
11811 	return rgb << 3 | (rgb >> 2 & 460551);
11812 }
11813 
RECOIL_GetStVdiColor(uint8_t const * content,int contentOffset)11814 static int RECOIL_GetStVdiColor(uint8_t const *content, int contentOffset)
11815 {
11816 	int rgb = 0;
11817 	for (int i = 0; i < 6; i += 2) {
11818 		int c = content[contentOffset + i] << 8 | content[contentOffset + i + 1];
11819 		c = c < 1000 ? c * 255 / 1000 : 255;
11820 		rgb = rgb << 8 | c;
11821 	}
11822 	return rgb;
11823 }
11824 
RECOIL_SetStVdiColor(RECOIL * self,int i,int rgb,int bitplanes)11825 static void RECOIL_SetStVdiColor(RECOIL *self, int i, int rgb, int bitplanes)
11826 {
11827 	switch (i) {
11828 	case 1:
11829 		i = (1 << bitplanes) - 1;
11830 		break;
11831 	case 2:
11832 		i = 1;
11833 		break;
11834 	case 3:
11835 		i = 2;
11836 		break;
11837 	case 5:
11838 		i = 6;
11839 		break;
11840 	case 6:
11841 		i = 3;
11842 		break;
11843 	case 7:
11844 		i = 5;
11845 		break;
11846 	case 8:
11847 		i = 7;
11848 		break;
11849 	case 9:
11850 		i = 8;
11851 		break;
11852 	case 10:
11853 		i = 9;
11854 		break;
11855 	case 11:
11856 		i = 10;
11857 		break;
11858 	case 13:
11859 		i = 14;
11860 		break;
11861 	case 14:
11862 		i = 11;
11863 		break;
11864 	case 15:
11865 		i = 13;
11866 		break;
11867 	case 255:
11868 		i = 15;
11869 		break;
11870 	default:
11871 		break;
11872 	}
11873 	self->contentPalette[i] = rgb;
11874 }
11875 
RECOIL_SetStVdiPalette(RECOIL * self,uint8_t const * content,int contentOffset,int colors,int bitplanes)11876 static void RECOIL_SetStVdiPalette(RECOIL *self, uint8_t const *content, int contentOffset, int colors, int bitplanes)
11877 {
11878 	for (int i = 0; i < colors; i++)
11879 		RECOIL_SetStVdiColor(self, i, RECOIL_GetStVdiColor(content, contentOffset + i * 6), bitplanes);
11880 }
11881 
RECOIL_GetStLowPixel(uint8_t const * content,int contentOffset,int x)11882 static int RECOIL_GetStLowPixel(uint8_t const *content, int contentOffset, int x)
11883 {
11884 	return RECOIL_GetBitplaneWordsPixel(content, contentOffset, x, 4);
11885 }
11886 
RECOIL_DecodeStLowWithStride(RECOIL * self,uint8_t const * bitmap,int bitmapOffset,int bitmapStride,uint8_t const * palette,int paletteOffset,int width,int height)11887 static bool RECOIL_DecodeStLowWithStride(RECOIL *self, uint8_t const *bitmap, int bitmapOffset, int bitmapStride, uint8_t const *palette, int paletteOffset, int width, int height)
11888 {
11889 	RECOIL_SetSize(self, width, height, RECOIL_IsStePalette(palette, paletteOffset, 16) ? RECOILResolution_STE1X1 : RECOILResolution_ST1X1);
11890 	RECOIL_SetStPalette(self, palette, paletteOffset, 16);
11891 	RECOIL_DecodeBitplanes(self, bitmap, bitmapOffset, bitmapStride, 4, 0, width, height);
11892 	return true;
11893 }
11894 
RECOIL_DecodeStLow(RECOIL * self,uint8_t const * bitmap,int bitmapOffset,uint8_t const * palette,int paletteOffset,int width,int height)11895 static bool RECOIL_DecodeStLow(RECOIL *self, uint8_t const *bitmap, int bitmapOffset, uint8_t const *palette, int paletteOffset, int width, int height)
11896 {
11897 	return RECOIL_DecodeStLowWithStride(self, bitmap, bitmapOffset, (width + 15) >> 4 << 3, palette, paletteOffset, width, height);
11898 }
11899 
RECOIL_DecodeStMedium(RECOIL * self,uint8_t const * bitmap,int bitmapOffset,uint8_t const * palette,int paletteOffset,int width,int height,int blend)11900 static void RECOIL_DecodeStMedium(RECOIL *self, uint8_t const *bitmap, int bitmapOffset, uint8_t const *palette, int paletteOffset, int width, int height, int blend)
11901 {
11902 	RECOIL_SetSize(self, width, height << 1, RECOIL_IsStePalette(palette, paletteOffset, 4) ? RECOILResolution_STE1X2 : RECOILResolution_ST1X2);
11903 	RECOIL_SetStPalette(self, palette, paletteOffset, 4);
11904 	RECOIL_DecodeScaledBitplanes(self, bitmap, bitmapOffset, width, height << blend, 2, false, NULL);
11905 }
11906 
RECOIL_DecodeSrt(RECOIL * self,uint8_t const * content,int contentLength)11907 static bool RECOIL_DecodeSrt(RECOIL *self, uint8_t const *content, int contentLength)
11908 {
11909 	if (contentLength != 32038 || !RECOIL_IsStringAt(content, 32000, "JHSy") || content[32004] != 0 || content[32005] != 1)
11910 		return false;
11911 	RECOIL_DecodeStMedium(self, content, 0, content, 32006, 640, 200, 0);
11912 	return true;
11913 }
11914 
RECOIL_DecodeSt(RECOIL * self,uint8_t const * bitmap,int bitmapOffset,uint8_t const * palette,int paletteOffset,int mode,int doubleHeight)11915 static bool RECOIL_DecodeSt(RECOIL *self, uint8_t const *bitmap, int bitmapOffset, uint8_t const *palette, int paletteOffset, int mode, int doubleHeight)
11916 {
11917 	switch (mode) {
11918 	case 0:
11919 		return RECOIL_DecodeStLow(self, bitmap, bitmapOffset, palette, paletteOffset, 320, 200 << doubleHeight);
11920 	case 1:
11921 		RECOIL_DecodeStMedium(self, bitmap, bitmapOffset, palette, paletteOffset, 640, 200 << doubleHeight, 0);
11922 		return true;
11923 	case 2:
11924 		RECOIL_SetSize(self, 640, 400 << doubleHeight, RECOILResolution_ST1X1);
11925 		return RECOIL_DecodeBlackAndWhite(self, bitmap, bitmapOffset, bitmapOffset + (32000 << doubleHeight), false, 16777215);
11926 	default:
11927 		return false;
11928 	}
11929 }
11930 
RECOIL_DecodeStPi(RECOIL * self,uint8_t const * content,int contentLength)11931 static bool RECOIL_DecodeStPi(RECOIL *self, uint8_t const *content, int contentLength)
11932 {
11933 	if (contentLength < 32034 || content[0] != 0)
11934 		return false;
11935 	switch (contentLength) {
11936 	case 32034:
11937 	case 32066:
11938 	case 32128:
11939 		return RECOIL_DecodeSt(self, content, 34, content, 2, content[1], 0);
11940 	case 38434:
11941 		return content[1] == 4 && RECOIL_DecodeStLow(self, content, 34, content, 2, 320, 240);
11942 	case 44834:
11943 		return content[1] == 0 && RECOIL_DecodeStLow(self, content, 34, content, 2, 320, 280);
11944 	case 64034:
11945 		return RECOIL_DecodeSt(self, content, 34, content, 2, content[1], 1);
11946 	case 116514:
11947 		return content[1] == 0 && RECOIL_DecodeStLow(self, content, 34, content, 2, 416, 560);
11948 	case 153606:
11949 		if (content[1] != 6)
11950 			return false;
11951 		RECOIL_SetSize(self, 1280, 960, RECOILResolution_TT1X1);
11952 		return RECOIL_DecodeBlackAndWhite(self, content, 6, contentLength, false, 16777215);
11953 	case 153634:
11954 		if (content[1] != 4)
11955 			return false;
11956 		RECOIL_SetSize(self, 640, 480, RECOILResolution_TT1X1);
11957 		RECOIL_SetStPalette(self, content, 2, 16);
11958 		RECOIL_DecodeBitplanes(self, content, 34, 320, 4, 0, 640, 480);
11959 		return true;
11960 	case 154114:
11961 		if (content[1] != 7)
11962 			return false;
11963 		RECOIL_SetSize(self, 640, 480, RECOILResolution_TT2X1);
11964 		RECOIL_SetStPalette(self, content, 2, 256);
11965 		RECOIL_DecodeScaledBitplanes(self, content, 514, 320, 480, 8, false, NULL);
11966 		return true;
11967 	default:
11968 		return false;
11969 	}
11970 }
11971 
RECOIL_DecodePc(RECOIL * self,uint8_t const * content,int contentLength)11972 static bool RECOIL_DecodePc(RECOIL *self, uint8_t const *content, int contentLength)
11973 {
11974 	if (contentLength < 68 || content[0] != 128 || content[1] > 2)
11975 		return false;
11976 	int bitplanes = 4 >> content[1];
11977 	PackBitsStream rle;
11978 	PackBitsStream_Construct(&rle);
11979 	rle.base.base.base.content = content;
11980 	rle.base.base.base.contentOffset = 34;
11981 	rle.base.base.base.contentLength = contentLength;
11982 	uint8_t unpacked[32000];
11983 	return PackBitsStream_UnpackBitplaneLines(&rle, unpacked, 320 << content[1], 200, bitplanes, true, false) && RECOIL_DecodeSt(self, unpacked, 0, content, 2, content[1], 0);
11984 }
11985 
RECOIL_DecodeEza(RECOIL * self,uint8_t const * content,int contentLength)11986 static bool RECOIL_DecodeEza(RECOIL *self, uint8_t const *content, int contentLength)
11987 {
11988 	if (contentLength < 44 || content[0] != 69 || content[1] != 90 || content[2] != 0 || content[3] != 200)
11989 		return false;
11990 	PackBitsStream rle;
11991 	PackBitsStream_Construct(&rle);
11992 	rle.base.base.base.content = content;
11993 	rle.base.base.base.contentOffset = 44;
11994 	rle.base.base.base.contentLength = contentLength;
11995 	uint8_t unpacked[32000];
11996 	return PackBitsStream_UnpackBitplaneLines(&rle, unpacked, 320, 200, 4, true, false) && RECOIL_DecodeStLow(self, unpacked, 0, content, 4, 320, 200);
11997 }
11998 
RECOIL_DecodeNeo(RECOIL * self,const char * filename,uint8_t const * content,int contentLength)11999 static bool RECOIL_DecodeNeo(RECOIL *self, const char *filename, uint8_t const *content, int contentLength)
12000 {
12001 	switch (contentLength) {
12002 	case 32128:
12003 		if (content[0] != 0 || content[1] != 0 || content[2] != 0)
12004 			return false;
12005 		if (content[3] == 0) {
12006 			uint8_t rst[6801];
12007 			if (RECOIL_ReadCompanionFile(self, filename, "RST", "rst", rst, 6801) == 6800) {
12008 				RECOIL_SetSize(self, 320, 200, RECOILResolution_ST1X1);
12009 				RECOIL_SetStPalette(self, content, 4, 16);
12010 				RastPalette palette;
12011 				RastPalette_Construct(&palette);
12012 				palette.base.base.base.content = rst;
12013 				palette.base.base.base.contentOffset = 0;
12014 				palette.base.base.base.contentLength = 6800;
12015 				palette.colors = 16;
12016 				RECOIL_DecodeScaledBitplanes(self, content, 128, 320, 200, 4, false, &palette.base);
12017 				return true;
12018 			}
12019 		}
12020 		return RECOIL_DecodeSt(self, content, 128, content, 4, content[3], 0);
12021 	case 128128:
12022 		return content[0] == 186 && content[1] == 190 && content[2] == 0 && content[3] == 0 && RECOIL_DecodeStLow(self, content, 128, content, 4, 640, 400);
12023 	default:
12024 		return false;
12025 	}
12026 }
12027 
RECOIL_DecodeArtDirector(RECOIL * self,uint8_t const * content,int contentLength)12028 static bool RECOIL_DecodeArtDirector(RECOIL *self, uint8_t const *content, int contentLength)
12029 {
12030 	return contentLength == 32512 && content[32287] < 8 && RECOIL_DecodeStLow(self, content, 0, content, 32000 + (content[32287] << 5), 320, 200);
12031 }
12032 
RECOIL_DecodeSsb(RECOIL * self,uint8_t const * content,int contentLength)12033 static bool RECOIL_DecodeSsb(RECOIL *self, uint8_t const *content, int contentLength)
12034 {
12035 	return contentLength == 32768 && RECOIL_DecodeStLow(self, content, 0, content, 32000, 320, 200);
12036 }
12037 
RECOIL_DecodeGfaArtist(RECOIL * self,uint8_t const * content,int contentLength)12038 static bool RECOIL_DecodeGfaArtist(RECOIL *self, uint8_t const *content, int contentLength)
12039 {
12040 	switch (contentLength) {
12041 	case 32032:
12042 		return RECOIL_DecodeStLow(self, content, 32, content, 0, 320, 200);
12043 	case 34360:
12044 		return RECOIL_DecodeStLow(self, content, 4, content, 32004, 320, 200);
12045 	default:
12046 		return false;
12047 	}
12048 }
12049 
RECOIL_DecodePaletteMaster(RECOIL * self,uint8_t const * content,int contentLength)12050 static bool RECOIL_DecodePaletteMaster(RECOIL *self, uint8_t const *content, int contentLength)
12051 {
12052 	if (contentLength != 36864 || content[35968] != 255 || content[35969] != 255)
12053 		return false;
12054 	RECOIL_SetSize(self, 320, 200, RECOILResolution_ST1X1);
12055 	ArtPalette palette;
12056 	ArtPalette_Construct(&palette);
12057 	palette.base.base.base.content = content;
12058 	RECOIL_DecodeScaledBitplanes(self, content, 0, 320, 200, 4, false, &palette.base);
12059 	return true;
12060 }
12061 
RECOIL_DecodeCel(RECOIL * self,uint8_t const * content,int contentLength)12062 static bool RECOIL_DecodeCel(RECOIL *self, uint8_t const *content, int contentLength)
12063 {
12064 	if (contentLength < 128 || content[0] != 255 || content[1] != 255 || content[2] != 0 || content[3] != 0)
12065 		return false;
12066 	int width = content[58] << 8 | content[59];
12067 	int height = content[60] << 8 | content[61];
12068 	return contentLength == 128 + ((width + 15) >> 4 << 3) * height && RECOIL_DecodeStLow(self, content, 128, content, 4, width, height);
12069 }
12070 
RECOIL_DecodeMur(RECOIL * self,const char * filename,uint8_t const * content,int contentLength)12071 static bool RECOIL_DecodeMur(RECOIL *self, const char *filename, uint8_t const *content, int contentLength)
12072 {
12073 	if (contentLength != 32000)
12074 		return false;
12075 	uint8_t pal[97];
12076 	if (RECOIL_ReadCompanionFile(self, filename, "PAL", "pal", pal, 97) != 96)
12077 		return false;
12078 	RECOIL_SetSize(self, 320, 200, RECOILResolution_STE1X1);
12079 	RECOIL_SetStVdiPalette(self, pal, 0, 16, 4);
12080 	RECOIL_DecodeBitplanes(self, content, 0, 160, 4, 0, 320, 200);
12081 	return true;
12082 }
12083 
RECOIL_DecodeKid(RECOIL * self,uint8_t const * content,int contentLength)12084 static bool RECOIL_DecodeKid(RECOIL *self, uint8_t const *content, int contentLength)
12085 {
12086 	return contentLength == 63054 && content[0] == 75 && content[1] == 68 && RECOIL_DecodeStLowWithStride(self, content, 34, 230, content, 2, 448, 274);
12087 }
12088 
RECOIL_DecodeStPpp(RECOIL * self,uint8_t const * content,int contentLength)12089 static bool RECOIL_DecodeStPpp(RECOIL *self, uint8_t const *content, int contentLength)
12090 {
12091 	return contentLength == 32079 && RECOIL_IsStringAt(content, 0, "PABLO PACKED PICTURE: Groupe CDND \r\n32036\r\n") && content[44] == 0 && content[45] == 125 && content[46] == 36 && RECOIL_DecodeSt(self, content, 79, content, 47, content[43], 0);
12092 }
12093 
RECOIL_DecodeStRgb(RECOIL * self,uint8_t const * content,int contentLength)12094 static bool RECOIL_DecodeStRgb(RECOIL *self, uint8_t const *content, int contentLength)
12095 {
12096 	if (contentLength != 96102)
12097 		return false;
12098 	RECOIL_SetSize(self, 320, 200, RECOILResolution_STE1X1);
12099 	self->frames = 3;
12100 	for (int i = 0; i < 64000; i++) {
12101 		int rgb = RECOIL_GetStLowPixel(content, 34, i) << 16 | RECOIL_GetStLowPixel(content, 32068, i) << 8 | RECOIL_GetStLowPixel(content, 64102, i);
12102 		self->pixels[i] = rgb * 17;
12103 	}
12104 	return true;
12105 }
12106 
RECOIL_DecodeSd(RECOIL * self,uint8_t const * content,int contentLength,int mode)12107 static bool RECOIL_DecodeSd(RECOIL *self, uint8_t const *content, int contentLength, int mode)
12108 {
12109 	return contentLength == 32128 && RECOIL_DecodeSt(self, content, 128, content, 4, mode, 0);
12110 }
12111 
RECOIL_DecodeIc(RECOIL * self,uint8_t const * content,int contentLength)12112 static bool RECOIL_DecodeIc(RECOIL *self, uint8_t const *content, int contentLength)
12113 {
12114 	if (contentLength < 68 || !RECOIL_IsStringAt(content, 0, "IMDC") || content[4] != 0 || content[64] != 200 || content[65] != 2)
12115 		return false;
12116 	uint8_t unpacked[32000];
12117 	IcStream rle;
12118 	IcStream_Construct(&rle);
12119 	rle.base.base.base.content = content;
12120 	rle.base.base.base.contentOffset = 67;
12121 	rle.base.base.base.contentLength = contentLength;
12122 	return RleStream_UnpackColumns(&rle.base, unpacked, 0, 160, 32000) && RECOIL_DecodeSt(self, unpacked, 0, content, 6, content[5], 0);
12123 }
12124 
RECOIL_DecodeGraphicsProcessor(RECOIL * self,uint8_t const * content,int contentLength)12125 static bool RECOIL_DecodeGraphicsProcessor(RECOIL *self, uint8_t const *content, int contentLength)
12126 {
12127 	if (contentLength < 493 || content[0] != 0)
12128 		return false;
12129 	int mode = content[1];
12130 	switch (mode) {
12131 	case 0:
12132 	case 1:
12133 	case 2:
12134 		return contentLength == 32331 && RECOIL_DecodeSt(self, content, 331, content, 2, mode, 0);
12135 	case 10:
12136 	case 11:
12137 	case 12:
12138 		break;
12139 	default:
12140 		return false;
12141 	}
12142 	mode -= 10;
12143 	int bitplanes = 4 >> mode;
12144 	uint8_t unpacked[32000];
12145 	int contentOffset = 333;
12146 	int count = 0;
12147 	for (int unpackedOffset = 0; unpackedOffset < 32000; unpackedOffset += bitplanes) {
12148 		if (count == 0) {
12149 			if (contentOffset + bitplanes >= contentLength)
12150 				return false;
12151 			count = content[contentOffset];
12152 			if (count == 0)
12153 				return false;
12154 			contentOffset += 1 + bitplanes;
12155 		}
12156 		memcpy(unpacked + unpackedOffset, content + contentOffset - bitplanes, bitplanes);
12157 		count--;
12158 	}
12159 	return RECOIL_DecodeSt(self, unpacked, 0, content, 2, mode, 0);
12160 }
12161 
RECOIL_DecodeDaliCompressed(RECOIL * self,uint8_t const * content,int contentLength,int mode)12162 static bool RECOIL_DecodeDaliCompressed(RECOIL *self, uint8_t const *content, int contentLength, int mode)
12163 {
12164 	DaliStream stream;
12165 	stream.base.content = content;
12166 	stream.base.contentOffset = 32;
12167 	stream.base.contentLength = contentLength;
12168 	int countLength = Stream_ParseInt(&stream.base);
12169 	return countLength > 0 && Stream_ParseInt(&stream.base) > 0 && DaliStream_Decode(&stream, countLength, self, 0, mode);
12170 }
12171 
RECOIL_DecodeRgh(RECOIL * self,uint8_t const * content,int contentLength)12172 static bool RECOIL_DecodeRgh(RECOIL *self, uint8_t const *content, int contentLength)
12173 {
12174 	if (contentLength < 14 || !RECOIL_IsStringAt(content, 0, "(c)F.MARCHAL"))
12175 		return false;
12176 	DaliStream stream;
12177 	stream.base.content = content;
12178 	stream.base.contentOffset = 12;
12179 	stream.base.contentLength = contentLength;
12180 	int countLength = Stream_ParseInt(&stream.base);
12181 	int paletteOffset = stream.base.contentOffset;
12182 	stream.base.contentOffset = paletteOffset + 32;
12183 	return DaliStream_Decode(&stream, countLength, self, paletteOffset, 0);
12184 }
12185 
RECOIL_DecodeSc(RECOIL * self,uint8_t const * content,int contentLength)12186 static bool RECOIL_DecodeSc(RECOIL *self, uint8_t const *content, int contentLength)
12187 {
12188 	if (contentLength < 128 || !RECOIL_IsStringAt(content, 54, "ANvisionA"))
12189 		return false;
12190 	int flags = content[63];
12191 	int doubleHeight;
12192 	switch (flags & 15) {
12193 	case 0:
12194 		doubleHeight = 1;
12195 		break;
12196 	case 1:
12197 	case 2:
12198 		doubleHeight = 0;
12199 		break;
12200 	default:
12201 		return false;
12202 	}
12203 	int bitmapLength = 32000 << doubleHeight;
12204 	int mode = flags >> 4 & 3;
12205 	if (flags >= 128) {
12206 		uint8_t unpacked[64000];
12207 		ScStream rle;
12208 		ScStream_Construct(&rle);
12209 		rle.base.base.base.content = content;
12210 		rle.base.base.base.contentOffset = 128;
12211 		rle.base.base.base.contentLength = contentLength;
12212 		int bytesPer16Pixels = 8 >> mode;
12213 		for (int bitplane = 0; bitplane < bytesPer16Pixels; bitplane += 2) {
12214 			if (!RleStream_UnpackWords(&rle.base, unpacked, bitplane, bytesPer16Pixels, bitmapLength))
12215 				return false;
12216 		}
12217 		return RECOIL_DecodeSt(self, unpacked, 0, content, 4, mode, doubleHeight);
12218 	}
12219 	return contentLength >= 128 + bitmapLength && RECOIL_DecodeSt(self, content, 128, content, 4, mode, doubleHeight);
12220 }
12221 
RECOIL_DecodeGfb(RECOIL * self,uint8_t const * content,int contentLength)12222 static bool RECOIL_DecodeGfb(RECOIL *self, uint8_t const *content, int contentLength)
12223 {
12224 	if (contentLength < 20 || !RECOIL_IsStringAt(content, 0, "GF25"))
12225 		return false;
12226 	int bitplanes;
12227 	switch (RECOIL_Get32BigEndian(content, 4)) {
12228 	case 2:
12229 		bitplanes = 1;
12230 		break;
12231 	case 4:
12232 		bitplanes = 2;
12233 		break;
12234 	case 16:
12235 		bitplanes = 4;
12236 		break;
12237 	case 256:
12238 		bitplanes = 8;
12239 		break;
12240 	default:
12241 		return false;
12242 	}
12243 	int width = RECOIL_Get32BigEndian(content, 8);
12244 	if (width <= 0)
12245 		return false;
12246 	int height = RECOIL_Get32BigEndian(content, 12);
12247 	if (height <= 0)
12248 		return false;
12249 	int bitmapLength = RECOIL_Get32BigEndian(content, 16);
12250 	if (bitmapLength <= 0)
12251 		return false;
12252 	if (1556 + bitmapLength != contentLength || bitmapLength != ((width + 15) >> 4 << 1) * bitplanes * height || !RECOIL_SetSizeStOrFalcon(self, width, height, bitplanes, false))
12253 		return false;
12254 	RECOIL_SetStVdiPalette(self, content, 20 + bitmapLength, 1 << bitplanes, bitplanes);
12255 	RECOIL_DecodeScaledBitplanes(self, content, 20, width, height, bitplanes, false, NULL);
12256 	return true;
12257 }
12258 
RECOIL_DecodeCa(RECOIL * self,uint8_t const * content,int contentLength)12259 static bool RECOIL_DecodeCa(RECOIL *self, uint8_t const *content, int contentLength)
12260 {
12261 	if (contentLength < 8 || content[0] != 67 || content[1] != 65)
12262 		return false;
12263 	int contentOffset;
12264 	switch (content[3]) {
12265 	case 0:
12266 		contentOffset = 36;
12267 		break;
12268 	case 1:
12269 		contentOffset = 12;
12270 		break;
12271 	case 2:
12272 		contentOffset = 4;
12273 		break;
12274 	default:
12275 		return false;
12276 	}
12277 	switch (content[2]) {
12278 	case 0:
12279 		return contentOffset + 32000 == contentLength && RECOIL_DecodeSt(self, content, contentOffset, content, 4, content[3], 0);
12280 	case 1:
12281 		{
12282 			uint8_t unpacked[32000];
12283 			CaStream rle;
12284 			CaStream_Construct(&rle);
12285 			rle.base.base.base.content = content;
12286 			rle.base.base.base.contentOffset = contentOffset;
12287 			rle.base.base.base.contentLength = contentLength;
12288 			return CaStream_UnpackCa(&rle, unpacked, 0) && RECOIL_DecodeSt(self, unpacked, 0, content, 4, content[3], 0);
12289 		}
12290 	default:
12291 		return false;
12292 	}
12293 }
12294 
RECOIL_DecodeTny(RECOIL * self,uint8_t const * content,int contentLength)12295 static bool RECOIL_DecodeTny(RECOIL *self, uint8_t const *content, int contentLength)
12296 {
12297 	if (contentLength < 42)
12298 		return false;
12299 	int mode = content[0];
12300 	int contentOffset;
12301 	if (mode > 2) {
12302 		if (mode > 5)
12303 			return false;
12304 		mode -= 3;
12305 		contentOffset = 4;
12306 	}
12307 	else
12308 		contentOffset = 0;
12309 	int controlLength = content[contentOffset + 33] << 8 | content[contentOffset + 34];
12310 	int valueLength = (content[contentOffset + 35] << 8 | content[contentOffset + 36]) << 1;
12311 	if (contentOffset + 37 + controlLength + valueLength > contentLength)
12312 		return false;
12313 	TnyStream rle;
12314 	TnyStream_Construct(&rle);
12315 	rle.base.base.base.base.content = content;
12316 	rle.base.base.base.base.contentOffset = contentOffset + 37;
12317 	rle.valueOffset = rle.base.base.base.base.contentLength = contentOffset + 37 + controlLength;
12318 	rle.valueLength = contentOffset + 37 + controlLength + valueLength;
12319 	uint8_t unpacked[32000];
12320 	for (int bitplane = 0; bitplane < 8; bitplane += 2) {
12321 		for (int x = bitplane; x < 160; x += 8) {
12322 			for (int unpackedOffset = x; unpackedOffset < 32000; unpackedOffset += 160) {
12323 				int b = RleStream_ReadRle(&rle.base.base);
12324 				if (b < 0)
12325 					return false;
12326 				unpacked[unpackedOffset] = (uint8_t) (b >> 8);
12327 				unpacked[unpackedOffset + 1] = (uint8_t) b;
12328 			}
12329 		}
12330 	}
12331 	return RECOIL_DecodeSt(self, unpacked, 0, content, contentOffset + 1, mode, 0);
12332 }
12333 
RECOIL_DecodeCptFul(RECOIL * self,uint8_t const * content,int contentOffset,int contentLength,HblPalette * palette)12334 static bool RECOIL_DecodeCptFul(RECOIL *self, uint8_t const *content, int contentOffset, int contentLength, HblPalette *palette)
12335 {
12336 	if (contentLength < contentOffset + 40 || content[contentOffset + 32] != 0)
12337 		return false;
12338 	int mode = content[contentOffset + 33];
12339 	if (mode > 2)
12340 		return false;
12341 	int bitplanes = 4 >> mode;
12342 	uint8_t unpacked[32000];
12343 	uint8_t isFilled[16000] = { 0 };
12344 	contentOffset += 34;
12345 	for (;;) {
12346 		int nextContentOffset = contentOffset + 4 + bitplanes * 2;
12347 		if (nextContentOffset > contentLength)
12348 			return false;
12349 		int repeatCount = content[contentOffset] << 8 | content[contentOffset + 1];
12350 		if (repeatCount == 65535) {
12351 			contentOffset = nextContentOffset;
12352 			break;
12353 		}
12354 		int offset = (content[contentOffset + 2] << 8 | content[contentOffset + 3]) * bitplanes;
12355 		do {
12356 			if (offset >= 16000)
12357 				return false;
12358 			memcpy(unpacked + (offset << 1), content + contentOffset + 4, bitplanes << 1);
12359 			isFilled[offset] = 1;
12360 			offset += bitplanes;
12361 		}
12362 		while (--repeatCount >= 0);
12363 		contentOffset = nextContentOffset;
12364 	}
12365 	for (int offset = 0; offset < 16000; offset += bitplanes) {
12366 		if (isFilled[offset] == 0) {
12367 			int nextContentOffset = contentOffset + bitplanes * 2;
12368 			if (nextContentOffset > contentLength)
12369 				return false;
12370 			memcpy(unpacked + (offset << 1), content + contentOffset, bitplanes << 1);
12371 			contentOffset = nextContentOffset;
12372 		}
12373 	}
12374 	if (palette == NULL)
12375 		return RECOIL_DecodeSt(self, unpacked, 0, content, 0, mode, 0);
12376 	if (mode == 0)
12377 		RECOIL_SetSize(self, 320, 200, RECOILResolution_ST1X1);
12378 	else
12379 		RECOIL_SetSize(self, 640, 400, RECOILResolution_ST1X2);
12380 	RECOIL_DecodeScaledBitplanes(self, unpacked, 0, 320 << mode, 200, bitplanes, false, &palette->base);
12381 	return true;
12382 }
12383 
RECOIL_DecodeCpt(RECOIL * self,const char * filename,uint8_t const * content,int contentLength)12384 static bool RECOIL_DecodeCpt(RECOIL *self, const char *filename, uint8_t const *content, int contentLength)
12385 {
12386 	if (contentLength < 40)
12387 		return false;
12388 	if (content[33] <= 1) {
12389 		uint8_t hbl[3249];
12390 		int hblLength = RECOIL_ReadCompanionFile(self, filename, "HBL", "hbl", hbl, 3249);
12391 		if (hblLength >= 896 && hblLength <= 3248) {
12392 			HblPalette palette;
12393 			HblPalette_Construct(&palette);
12394 			palette.base.base.base.content = hbl;
12395 			palette.base.base.base.contentLength = hblLength;
12396 			if (HblPalette_Init(&palette))
12397 				return RECOIL_DecodeCptFul(self, content, 0, contentLength, &palette);
12398 		}
12399 	}
12400 	return RECOIL_DecodeCptFul(self, content, 0, contentLength, NULL);
12401 }
12402 
RECOIL_DecodeFul(RECOIL * self,uint8_t const * content,int contentLength)12403 static bool RECOIL_DecodeFul(RECOIL *self, uint8_t const *content, int contentLength)
12404 {
12405 	if (contentLength < 1544)
12406 		return false;
12407 	HblPalette palette;
12408 	HblPalette_Construct(&palette);
12409 	palette.base.base.base.content = content;
12410 	palette.base.base.base.contentLength = contentLength;
12411 	return HblPalette_Init(&palette) && content[palette.base.base.base.contentOffset + 608 + 33] <= 1 && RECOIL_DecodeCptFul(self, content, palette.base.base.base.contentOffset + 608, contentLength, &palette);
12412 }
12413 
RECOIL_SetDefaultStPalette(RECOIL * self,int bitplanes)12414 static void RECOIL_SetDefaultStPalette(RECOIL *self, int bitplanes)
12415 {
12416 	self->contentPalette[0] = 16777215;
12417 	if (bitplanes >= 2) {
12418 		self->contentPalette[1] = 16711680;
12419 		self->contentPalette[2] = 65280;
12420 		if (bitplanes == 4) {
12421 			self->contentPalette[3] = 16776960;
12422 			self->contentPalette[4] = 255;
12423 			self->contentPalette[5] = 16711935;
12424 			self->contentPalette[6] = 65535;
12425 			self->contentPalette[7] = 11184810;
12426 			self->contentPalette[8] = 5592405;
12427 			self->contentPalette[9] = 11141120;
12428 			self->contentPalette[10] = 43520;
12429 			self->contentPalette[11] = 11184640;
12430 			self->contentPalette[12] = 170;
12431 			self->contentPalette[13] = 11141290;
12432 			self->contentPalette[14] = 43690;
12433 		}
12434 	}
12435 	self->contentPalette[(1 << bitplanes) - 1] = 0;
12436 }
12437 
RECOIL_IsTimg(uint8_t const * content)12438 static bool RECOIL_IsTimg(uint8_t const *content)
12439 {
12440 	if (!RECOIL_IsStringAt(content, 16, "TIMG") || content[20] != 0 || content[21] != 3)
12441 		return false;
12442 	for (int i = 22; i < 28; i += 2) {
12443 		if (content[i] != 0 || content[i + 1] != 5)
12444 			return false;
12445 	}
12446 	return true;
12447 }
12448 
RECOIL_IsXimg(uint8_t const * content)12449 static bool RECOIL_IsXimg(uint8_t const *content)
12450 {
12451 	return RECOIL_IsStringAt(content, 16, "XIMG") && content[20] == 0 && content[21] == 0;
12452 }
12453 
RECOIL_IsSttt(uint8_t const * content,int bitplanes)12454 static bool RECOIL_IsSttt(uint8_t const *content, int bitplanes)
12455 {
12456 	int colors = content[20] << 8 | content[21];
12457 	return RECOIL_IsStringAt(content, 16, "STTT") && colors == 1 << bitplanes;
12458 }
12459 
RECOIL_DecodeStImg(RECOIL * self,uint8_t const * content,int contentLength)12460 static bool RECOIL_DecodeStImg(RECOIL *self, uint8_t const *content, int contentLength)
12461 {
12462 	if (contentLength < 17 || content[0] != 0 || content[1] == 0 || content[1] > 3 || content[4] != 0)
12463 		return false;
12464 	int headerLength = (content[2] << 8 | content[3]) << 1;
12465 	if (headerLength < 16 || headerLength >= contentLength)
12466 		return false;
12467 	int bitplanes = content[5];
12468 	int width = content[12] << 8 | content[13];
12469 	int height = content[14] << 8 | content[15];
12470 	if (headerLength == 18 && content[16] == 0 && content[17] == 3) {
12471 		RECOIL_SetSize(self, width, height, RECOILResolution_FALCON1X1);
12472 		int contentOffset = 18;
12473 		int pixelsLength = width * height;
12474 		int count = 0;
12475 		for (int i = 0; i < pixelsLength; i++) {
12476 			if (count == 0) {
12477 				if (contentOffset + 1 >= contentLength)
12478 					return false;
12479 				if (content[contentOffset++] != 128)
12480 					return false;
12481 				count = content[contentOffset++];
12482 				if (count == 0)
12483 					return false;
12484 			}
12485 			if (contentOffset + 2 >= contentLength)
12486 				return false;
12487 			self->pixels[i] = content[contentOffset + 2] << 16 | content[contentOffset + 1] << 8 | content[contentOffset];
12488 			contentOffset += 3;
12489 			count--;
12490 		}
12491 		return true;
12492 	}
12493 	int xRatio = content[8] << 8 | content[9];
12494 	int yRatio = content[10] << 8 | content[11];
12495 	if (bitplanes <= 2 && width <= 640 && height <= 200 && yRatio * 2 > xRatio * 3)
12496 		RECOIL_SetSize(self, width, height << 1, RECOILResolution_ST1X2);
12497 	else if (bitplanes <= 8 && width <= 320 && height <= 480 && xRatio * 2 > yRatio * 3)
12498 		RECOIL_SetSize(self, width << 1, height, RECOILResolution_TT2X1);
12499 	else if (!RECOIL_SetSizeStOrFalcon(self, width, height, bitplanes, true))
12500 		return false;
12501 	switch (bitplanes) {
12502 	case 1:
12503 	case 2:
12504 	case 4:
12505 	case 8:
12506 		if (headerLength == 22 + (6 << bitplanes) && RECOIL_IsXimg(content)) {
12507 			for (int i = 0; i < 1 << bitplanes; i++)
12508 				self->contentPalette[i] = RECOIL_GetStVdiColor(content, 22 + i * 6);
12509 		}
12510 		else if (headerLength == 22 + (2 << bitplanes) && RECOIL_IsSttt(content, bitplanes))
12511 			RECOIL_SetStPalette(self, content, 22, 1 << bitplanes);
12512 		else if (bitplanes == 8) {
12513 			int rgb = 16777215;
12514 			for (int c = 0; c < 256; c++) {
12515 				self->contentPalette[c] = rgb;
12516 				for (int mask = 8421504;; mask >>= 1) {
12517 					rgb ^= mask;
12518 					if ((rgb & mask) == 0)
12519 						break;
12520 				}
12521 			}
12522 		}
12523 		else if (headerLength == 50 && content[16] == 0 && content[17] == 128)
12524 			RECOIL_SetStPalette(self, content, 18, 16);
12525 		else
12526 			RECOIL_SetDefaultStPalette(self, bitplanes);
12527 		break;
12528 	case 15:
12529 		if (headerLength != 28 || !RECOIL_IsTimg(content))
12530 			return false;
12531 		break;
12532 	case 16:
12533 	case 24:
12534 	case 32:
12535 		break;
12536 	default:
12537 		return false;
12538 	}
12539 	ImgStream rle;
12540 	ImgStream_Construct(&rle);
12541 	rle.base.base.base.content = content;
12542 	rle.base.base.base.contentOffset = headerLength;
12543 	rle.base.base.base.contentLength = contentLength;
12544 	int bytesPerBitplane = (width + 7) >> 3;
12545 	if (bitplanes == 24)
12546 		bytesPerBitplane = (bytesPerBitplane + 1) & -2;
12547 	int bytesPerLine = bitplanes * bytesPerBitplane;
12548 	uint8_t unpacked[40000] = { 0 };
12549 	for (int y = 0; y < height;) {
12550 		int lineRepeatCount = ImgStream_GetLineRepeatCount(&rle);
12551 		if (lineRepeatCount > height - y)
12552 			lineRepeatCount = height - y;
12553 		for (int x = 0; x < bytesPerLine; x++) {
12554 			int b = RleStream_ReadRle(&rle.base);
12555 			if (b < 0)
12556 				return false;
12557 			if (b != 256)
12558 				unpacked[x] = (uint8_t) b;
12559 		}
12560 		for (int x = 0; x < width; x++) {
12561 			int c;
12562 			switch (bitplanes) {
12563 			case 16:
12564 				c = RECOIL_GetFalconTrueColor(unpacked, x << 1);
12565 				break;
12566 			case 24:
12567 				c = RECOIL_GetR8G8B8Color(unpacked, x * 3);
12568 				break;
12569 			case 32:
12570 				c = RECOIL_GetR8G8B8Color(unpacked, (x << 2) + 1);
12571 				break;
12572 			default:
12573 				c = RECOIL_GetBitplanePixel(unpacked, x >> 3, x, bitplanes, bytesPerBitplane);
12574 				c = bitplanes == 15 ? RECOIL_GetB5G5R5Color(c) : self->contentPalette[c];
12575 				break;
12576 			}
12577 			for (int i = 0; i < lineRepeatCount; i++)
12578 				RECOIL_SetScaledPixel(self, x, y + i, c);
12579 		}
12580 		y += lineRepeatCount;
12581 	}
12582 	return true;
12583 }
12584 
RECOIL_DecodeStLowBlend(RECOIL * self,uint8_t const * bitmap,int bitmapOffset,uint8_t const * palette,int paletteOffset,int width,int height)12585 static bool RECOIL_DecodeStLowBlend(RECOIL *self, uint8_t const *bitmap, int bitmapOffset, uint8_t const *palette, int paletteOffset, int width, int height)
12586 {
12587 	RECOIL_DecodeStLow(self, bitmap, bitmapOffset, palette, paletteOffset, width, height);
12588 	RECOIL_DecodeBitplanes(self, bitmap, bitmapOffset + (width >> 1) * height, width >> 1, 4, width * height, width, height);
12589 	return RECOIL_ApplyBlend(self);
12590 }
12591 
RECOIL_DecodeDuo(RECOIL * self,uint8_t const * content,int contentLength)12592 static bool RECOIL_DecodeDuo(RECOIL *self, uint8_t const *content, int contentLength)
12593 {
12594 	return contentLength == 113600 && RECOIL_DecodeStLowBlend(self, content, 32, content, 0, 416, 273);
12595 }
12596 
RECOIL_DecodeDu2(RECOIL * self,uint8_t const * content,int contentLength)12597 static bool RECOIL_DecodeDu2(RECOIL *self, uint8_t const *content, int contentLength)
12598 {
12599 	if (contentLength != 113576 && contentLength != 113600)
12600 		return false;
12601 	RECOIL_DecodeStMedium(self, content, 8, content, 0, 832, 273, 1);
12602 	return RECOIL_ApplyBlend(self);
12603 }
12604 
RECOIL_DecodeP3c(RECOIL * self,uint8_t const * content,int contentLength)12605 static bool RECOIL_DecodeP3c(RECOIL *self, uint8_t const *content, int contentLength)
12606 {
12607 	CaStream rle;
12608 	CaStream_Construct(&rle);
12609 	rle.base.base.base.content = content;
12610 	rle.base.base.base.contentOffset = 0;
12611 	rle.base.base.base.contentLength = contentLength;
12612 	int compressedLength = Stream_ParseInt(&rle.base.base.base);
12613 	if (compressedLength < 0)
12614 		return false;
12615 	int paletteOffset = rle.base.base.base.contentOffset;
12616 	rle.base.base.base.contentLength = paletteOffset + 32 + compressedLength;
12617 	if (rle.base.base.base.contentLength >= contentLength)
12618 		return false;
12619 	rle.base.base.base.contentOffset = paletteOffset + 32;
12620 	uint8_t unpacked[64000];
12621 	if (!CaStream_UnpackCa(&rle, unpacked, 0))
12622 		return false;
12623 	rle.base.base.base.contentLength = contentLength;
12624 	compressedLength = Stream_ParseInt(&rle.base.base.base);
12625 	if (compressedLength < 0 || rle.base.base.base.contentOffset + compressedLength != contentLength)
12626 		return false;
12627 	rle.base.base.base.contentLength = contentLength;
12628 	return CaStream_UnpackCa(&rle, unpacked, 32000) && RECOIL_DecodeStLowBlend(self, unpacked, 0, content, paletteOffset, 320, 200);
12629 }
12630 
RECOIL_UnpackLz4(const RECOIL * self,uint8_t const * content,int contentLength,uint8_t * unpacked,int unpackedLength)12631 static bool RECOIL_UnpackLz4(const RECOIL *self, uint8_t const *content, int contentLength, uint8_t *unpacked, int unpackedLength)
12632 {
12633 	if (contentLength < 11 || content[0] != 4 || content[1] != 34 || content[2] != 77 || content[3] != 24 || (content[4] & 195) != 64)
12634 		return false;
12635 	Lz4Stream stream;
12636 	stream.base.content = content;
12637 	stream.base.contentOffset = 7;
12638 	if ((content[4] & 8) != 0)
12639 		stream.base.contentOffset += 8;
12640 	stream.unpacked = unpacked;
12641 	stream.unpackedOffset = 0;
12642 	stream.unpackedLength = unpackedLength;
12643 	for (;;) {
12644 		if (stream.base.contentOffset + 4 > contentLength)
12645 			return false;
12646 		int blockSize = RECOIL_Get32LittleEndian(content, stream.base.contentOffset);
12647 		stream.base.contentOffset += 4;
12648 		stream.base.contentLength = contentLength;
12649 		if (blockSize == 0)
12650 			break;
12651 		if (blockSize >> 31 != 0) {
12652 			if (!Lz4Stream_Copy(&stream, blockSize & 2147483647))
12653 				return false;
12654 			continue;
12655 		}
12656 		stream.base.contentLength = stream.base.contentOffset + blockSize;
12657 		if (stream.base.contentLength > contentLength)
12658 			return false;
12659 		for (;;) {
12660 			int token = Stream_ReadByte(&stream.base);
12661 			if (token < 0)
12662 				return false;
12663 			int count = Lz4Stream_ReadCount(&stream, token >> 4);
12664 			if (count < 0 || !Lz4Stream_Copy(&stream, count))
12665 				return false;
12666 			if (stream.base.contentOffset == stream.base.contentLength)
12667 				break;
12668 			if (stream.base.contentOffset > stream.base.contentLength - 2)
12669 				return false;
12670 			int distance = Stream_ReadByte(&stream.base);
12671 			distance += Stream_ReadByte(&stream.base) << 8;
12672 			if (distance == 0)
12673 				return false;
12674 			count = Lz4Stream_ReadCount(&stream, token & 15);
12675 			if (count < 0)
12676 				return false;
12677 			count += 4;
12678 			int nextOffset = stream.unpackedOffset + count;
12679 			if (nextOffset > unpackedLength || !RECOIL_CopyPrevious(unpacked, stream.unpackedOffset, distance, count))
12680 				return false;
12681 			stream.unpackedOffset = nextOffset;
12682 		}
12683 		if ((content[4] & 16) != 0)
12684 			stream.base.contentOffset += 4;
12685 	}
12686 	if ((content[4] & 4) != 0)
12687 		stream.base.contentOffset += 4;
12688 	return stream.base.contentOffset == contentLength && stream.unpackedOffset == unpackedLength;
12689 }
12690 
RECOIL_DecodePl4(RECOIL * self,uint8_t const * content,int contentLength)12691 static bool RECOIL_DecodePl4(RECOIL *self, uint8_t const *content, int contentLength)
12692 {
12693 	uint8_t unpacked[64070];
12694 	if (!RECOIL_UnpackLz4(self, content, contentLength, unpacked, 64070) || unpacked[0] != 0 || unpacked[1] != 0 || unpacked[32036] != 0 || unpacked[32037] != 0)
12695 		return false;
12696 	RECOIL_SetSize(self, 320, 200, RECOIL_IsStePalette(unpacked, 2, 16) || RECOIL_IsStePalette(unpacked, 32038, 16) ? RECOILResolution_STE1X1 : RECOILResolution_ST1X1);
12697 	RECOIL_SetStPalette(self, unpacked, 2, 16);
12698 	RECOIL_DecodeBitplanes(self, unpacked, 34, 160, 4, 0, 320, 200);
12699 	RECOIL_SetStPalette(self, unpacked, 32038, 16);
12700 	RECOIL_DecodeBitplanes(self, unpacked, 32070, 160, 4, 64000, 320, 200);
12701 	return RECOIL_ApplyBlend(self);
12702 }
12703 
RECOIL_DecodeSpuScreen(RECOIL * self,uint8_t const * content,int bitmapOffset,int height,bool enhanced)12704 static bool RECOIL_DecodeSpuScreen(RECOIL *self, uint8_t const *content, int bitmapOffset, int height, bool enhanced)
12705 {
12706 	int paletteOffset = bitmapOffset + height * 160;
12707 	if (!RECOIL_SetSize(self, 320, height, enhanced || RECOIL_IsStePalette(content, paletteOffset, height * 48) ? RECOILResolution_STE1X1 : RECOILResolution_ST1X1))
12708 		return false;
12709 	if (enhanced)
12710 		self->frames = 2;
12711 	int pixelsOffset = 0;
12712 	for (int y = 0; y < height; y++) {
12713 		for (int x = 0; x < 320; x++) {
12714 			int c = RECOIL_GetStLowPixel(content, bitmapOffset, pixelsOffset);
12715 			int x1 = c * 10 + 1 - (c & 1) * 6;
12716 			if (x >= x1 + 160)
12717 				c += 32;
12718 			else if (x >= x1)
12719 				c += 16;
12720 			int colorOffset = paletteOffset + y * 96 + (c << 1);
12721 			self->pixels[pixelsOffset++] = enhanced ? RECOIL_GetSteInterlacedColor(content[colorOffset] << 8 | content[colorOffset + 1]) : RECOIL_GetStColor(self, content, colorOffset);
12722 		}
12723 	}
12724 	return true;
12725 }
12726 
RECOIL_DecodeSpu(RECOIL * self,uint8_t const * content,int contentLength)12727 static bool RECOIL_DecodeSpu(RECOIL *self, uint8_t const *content, int contentLength)
12728 {
12729 	return contentLength == 51104 && RECOIL_DecodeSpuScreen(self, content, 160, 199, RECOIL_IsStringAt(content, 0, "5BIT"));
12730 }
12731 
RECOIL_UnpackSpc(RleStream * rle,uint8_t * unpacked)12732 static bool RECOIL_UnpackSpc(RleStream *rle, uint8_t *unpacked)
12733 {
12734 	for (int bitplane = 0; bitplane < 8; bitplane += 2) {
12735 		if (!RleStream_UnpackWords(rle, unpacked, 160 + bitplane, 8, 32000))
12736 			return false;
12737 	}
12738 	return true;
12739 }
12740 
RECOIL_DecodeStSpc(RECOIL * self,uint8_t const * content,int contentLength)12741 static bool RECOIL_DecodeStSpc(RECOIL *self, uint8_t const *content, int contentLength)
12742 {
12743 	if (contentLength < 12 || content[0] != 83 || content[1] != 80)
12744 		return false;
12745 	uint8_t unpacked[51104];
12746 	SpcStream rle;
12747 	SpcStream_Construct(&rle);
12748 	rle.base.base.base.content = content;
12749 	rle.base.base.base.contentOffset = 12;
12750 	rle.base.base.base.contentLength = contentLength;
12751 	if (!RECOIL_UnpackSpc(&rle.base, unpacked))
12752 		return false;
12753 	int contentOffset = 12 + RECOIL_Get32BigEndian(content, 4);
12754 	if (contentOffset < 12)
12755 		return false;
12756 	for (int unpackedOffset = 32000; unpackedOffset < 51104;) {
12757 		if (contentOffset >= contentLength - 1)
12758 			return false;
12759 		int got = (content[contentOffset] & 127) << 8 | content[contentOffset + 1];
12760 		contentOffset += 2;
12761 		for (int i = 0; i < 16; i++) {
12762 			if ((got >> i & 1) == 0) {
12763 				unpacked[unpackedOffset] = 0;
12764 				unpacked[unpackedOffset + 1] = 0;
12765 			}
12766 			else {
12767 				if (contentOffset >= contentLength - 1)
12768 					return false;
12769 				unpacked[unpackedOffset] = content[contentOffset];
12770 				unpacked[unpackedOffset + 1] = content[contentOffset + 1];
12771 				contentOffset += 2;
12772 			}
12773 			unpackedOffset += 2;
12774 		}
12775 	}
12776 	return RECOIL_DecodeSpuScreen(self, unpacked, 160, 199, false);
12777 }
12778 
RECOIL_DecodeSps(RECOIL * self,uint8_t const * content,int contentLength)12779 static bool RECOIL_DecodeSps(RECOIL *self, uint8_t const *content, int contentLength)
12780 {
12781 	if (contentLength < 13 || content[0] != 83 || content[1] != 80 || content[2] != 0 || content[3] != 0)
12782 		return false;
12783 	uint8_t unpacked[51104];
12784 	SpsStream rle;
12785 	SpsStream_Construct(&rle);
12786 	rle.base.base.base.content = content;
12787 	rle.base.base.base.contentOffset = 12;
12788 	rle.base.base.base.contentLength = contentLength;
12789 	if ((content[contentLength - 1] & 1) == 0) {
12790 		for (int bitplane = 0; bitplane < 8; bitplane += 2) {
12791 			for (int x = 0; x < 40; x++) {
12792 				if (!RleStream_Unpack(&rle.base, unpacked, 160 + ((x & -2) << 2) + bitplane + (x & 1), 160, 32000))
12793 					return false;
12794 			}
12795 		}
12796 	}
12797 	else if (!RECOIL_UnpackSpc(&rle.base, unpacked))
12798 		return false;
12799 	BitStream bitStream;
12800 	BitStream_Construct(&bitStream);
12801 	bitStream.base.content = content;
12802 	bitStream.base.contentOffset = 12 + RECOIL_Get32BigEndian(content, 4);
12803 	if (bitStream.base.contentOffset < 12)
12804 		return false;
12805 	bitStream.base.contentLength = contentLength;
12806 	for (int unpackedOffset = 32000; unpackedOffset < 51104;) {
12807 		int got = BitStream_ReadBits(&bitStream, 14);
12808 		if (got < 0)
12809 			return false;
12810 		got <<= 1;
12811 		for (int i = 15; i >= 0; i--) {
12812 			int rgb;
12813 			if ((got >> i & 1) == 0)
12814 				rgb = 0;
12815 			else {
12816 				rgb = BitStream_ReadBits(&bitStream, 9);
12817 				if (rgb < 0)
12818 					return false;
12819 			}
12820 			unpacked[unpackedOffset] = (uint8_t) (rgb >> 6);
12821 			unpacked[unpackedOffset + 1] = (uint8_t) ((rgb & 63) + (rgb & 56));
12822 			unpackedOffset += 2;
12823 		}
12824 	}
12825 	return RECOIL_DecodeSpuScreen(self, unpacked, 160, 199, false);
12826 }
12827 
RECOIL_UnpackAndDecodeSpx(RECOIL * self,SpxStream * stream,int contentLength,int height,uint8_t * unpacked)12828 static bool RECOIL_UnpackAndDecodeSpx(RECOIL *self, SpxStream *stream, int contentLength, int height, uint8_t *unpacked)
12829 {
12830 	uint8_t const *content = stream->base.content;
12831 	int bitmapLength = height * 160;
12832 	int paletteOffset = stream->base.contentOffset;
12833 	int paletteLength = RECOIL_Get32BigEndian(content, stream->base.contentStart - 4);
12834 	if (content[4] == 0)
12835 		memcpy(unpacked, content + stream->base.contentStart + 160, bitmapLength);
12836 	else if (content[3] == 1) {
12837 		if (!Ice21Stream_Unpack(&stream->base, unpacked, 0, bitmapLength))
12838 			return false;
12839 	}
12840 	else if (content[5] != 1)
12841 		return false;
12842 	else {
12843 		int packedLength = RECOIL_Get32BigEndian(content, stream->base.contentStart + 4);
12844 		int packedEnd = stream->base.contentStart + 8 + packedLength;
12845 		if (RECOIL_Get32BigEndian(content, stream->base.contentStart - 8) != 8 + packedLength || packedEnd > contentLength || packedEnd < 0)
12846 			return false;
12847 		stream->base.contentStart += 8;
12848 		stream->base.contentOffset = packedEnd;
12849 		if (!SpxStream_UnpackV2(stream, unpacked, height << 8))
12850 			return false;
12851 	}
12852 	if (content[5] == 0) {
12853 		if (paletteLength != height * 96)
12854 			return false;
12855 		memcpy(unpacked + bitmapLength, content + paletteOffset, paletteLength);
12856 	}
12857 	else if (content[3] == 1) {
12858 		stream->base.contentStart = paletteOffset;
12859 		stream->base.contentOffset = paletteOffset + paletteLength;
12860 		if (stream->base.contentOffset > contentLength || Ice21Stream_GetUnpackedLength(&stream->base) != height * 96 || !Ice21Stream_Unpack(&stream->base, unpacked, bitmapLength, height << 8))
12861 			return false;
12862 	}
12863 	return RECOIL_DecodeSpuScreen(self, unpacked, 0, height, false);
12864 }
12865 
RECOIL_DecodeSpx(RECOIL * self,uint8_t const * content,int contentLength)12866 static bool RECOIL_DecodeSpx(RECOIL *self, uint8_t const *content, int contentLength)
12867 {
12868 	if (contentLength < 12 || content[0] != 83 || content[1] != 80 || content[2] != 88)
12869 		return false;
12870 	int contentOffset = 10;
12871 	for (int zerosToSkip = 2;;) {
12872 		if (contentOffset + 16 >= contentLength)
12873 			return false;
12874 		if (content[contentOffset++] == 0) {
12875 			if (--zerosToSkip == 0)
12876 				break;
12877 		}
12878 	}
12879 	int bitmapLength = RECOIL_Get32BigEndian(content, contentOffset);
12880 	SpxStream stream;
12881 	stream.base.content = content;
12882 	stream.base.contentStart = contentOffset + 8;
12883 	stream.base.contentOffset = contentOffset + 8 + bitmapLength;
12884 	if (stream.base.contentOffset > contentLength)
12885 		return false;
12886 	switch (content[4]) {
12887 	case 0:
12888 		bitmapLength -= 160;
12889 		break;
12890 	case 1:
12891 		switch (content[3]) {
12892 		case 1:
12893 			bitmapLength = Ice21Stream_GetUnpackedLength(&stream.base) - 160;
12894 			break;
12895 		case 2:
12896 			bitmapLength = RECOIL_Get32BigEndian(content, contentOffset + 4) - 320;
12897 			break;
12898 		default:
12899 			return false;
12900 		}
12901 		break;
12902 	default:
12903 		return false;
12904 	}
12905 	if (bitmapLength <= 0 || bitmapLength % 160 != 0)
12906 		return false;
12907 	int height = bitmapLength / 160;
12908 	uint8_t *unpacked = (uint8_t *) CiShared_Make(height << 8, sizeof(uint8_t), NULL, NULL);
12909 	bool returnValue = RECOIL_UnpackAndDecodeSpx(self, &stream, contentLength, height, unpacked);
12910 	CiShared_Release(unpacked);
12911 	return returnValue;
12912 }
12913 
RECOIL_GetStLowSeparateBitplanes(uint8_t const * content,int contentOffset,int bitplaneLength,int x)12914 static int RECOIL_GetStLowSeparateBitplanes(uint8_t const *content, int contentOffset, int bitplaneLength, int x)
12915 {
12916 	return RECOIL_GetBitplanePixel(content, contentOffset + (x >> 3), x, 4, bitplaneLength);
12917 }
12918 
RECOIL_DecodePci(RECOIL * self,uint8_t const * content,int contentLength)12919 static bool RECOIL_DecodePci(RECOIL *self, uint8_t const *content, int contentLength)
12920 {
12921 	if (contentLength != 115648)
12922 		return false;
12923 	RECOIL_SetSize(self, 352, 278, RECOIL_IsStePalette(content, 97856, 8896) ? RECOILResolution_STE1X1 : RECOILResolution_ST1X1);
12924 	int bitmapOffset = 0;
12925 	for (int y = 0; y < 556; y++) {
12926 		if (y == 278)
12927 			bitmapOffset = 48928;
12928 		RECOIL_SetStPalette(self, content, 97856 + (y << 5), 16);
12929 		for (int x = 0; x < 352; x++)
12930 			self->pixels[y * 352 + x] = self->contentPalette[RECOIL_GetStLowSeparateBitplanes(content, bitmapOffset, 12232, x)];
12931 		bitmapOffset += 44;
12932 	}
12933 	return RECOIL_ApplyBlend(self);
12934 }
12935 
RECOIL_DecodePcsScreen(RECOIL * self,uint8_t const * unpacked,int pixelsOffset)12936 static void RECOIL_DecodePcsScreen(RECOIL *self, uint8_t const *unpacked, int pixelsOffset)
12937 {
12938 	for (int y = 0; y < 199; y++) {
12939 		for (int x = 0; x < 320; x++) {
12940 			int c = RECOIL_GetStLowSeparateBitplanes(unpacked, 40 + y * 40, 8000, x) << 1;
12941 			if (x >= c * 2) {
12942 				if (c < 28) {
12943 					if (x >= c * 2 + 76) {
12944 						if (x >= 176 + c * 5 - (c & 2) * 3)
12945 							c += 32;
12946 						c += 32;
12947 					}
12948 				}
12949 				else if (x >= c * 2 + 92)
12950 					c += 32;
12951 				c += 32;
12952 			}
12953 			self->pixels[pixelsOffset++] = RECOIL_GetStColor(self, unpacked, 32000 + y * 96 + c);
12954 		}
12955 	}
12956 }
12957 
RECOIL_DecodePcs(RECOIL * self,uint8_t const * content,int contentLength)12958 static bool RECOIL_DecodePcs(RECOIL *self, uint8_t const *content, int contentLength)
12959 {
12960 	if (contentLength < 18 || content[0] != 1 || content[1] != 64 || content[2] != 0 || content[3] != 200)
12961 		return false;
12962 	PcsStream rle;
12963 	PcsStream_Construct(&rle);
12964 	rle.base.base.base.base.content = content;
12965 	rle.base.base.base.base.contentOffset = 6;
12966 	rle.base.base.base.base.contentLength = contentLength;
12967 	uint8_t unpacked1[51136];
12968 	if (!PcsStream_UnpackPcs(&rle, unpacked1))
12969 		return false;
12970 	RECOIL_SetSize(self, 320, 199, RECOIL_IsStePalette(unpacked1, 32000, 9616) ? RECOILResolution_STE1X1 : RECOILResolution_ST1X1);
12971 	RECOIL_DecodePcsScreen(self, unpacked1, 0);
12972 	if (content[4] == 0)
12973 		return true;
12974 	uint8_t unpacked2[51136];
12975 	if (!PcsStream_UnpackPcs(&rle, unpacked2))
12976 		return false;
12977 	if ((content[4] & 1) == 0) {
12978 		for (int i = 0; i < 32000; i++)
12979 			unpacked2[i] ^= unpacked1[i];
12980 	}
12981 	if ((content[4] & 2) == 0) {
12982 		for (int i = 32000; i < 51136; i++)
12983 			unpacked2[i] ^= unpacked1[i];
12984 	}
12985 	RECOIL_DecodePcsScreen(self, unpacked2, 63680);
12986 	return RECOIL_ApplyBlend(self);
12987 }
12988 
RECOIL_UnpackPbx(const RECOIL * self,uint8_t const * content,int contentLength,uint8_t * unpacked,int bitmapOffset,int bytesPer16Pixels,int unpackedLength)12989 static uint8_t const *RECOIL_UnpackPbx(const RECOIL *self, uint8_t const *content, int contentLength, uint8_t *unpacked, int bitmapOffset, int bytesPer16Pixels, int unpackedLength)
12990 {
12991 	if (content[4] != 128 || content[5] != 1)
12992 		return contentLength == unpackedLength ? content : NULL;
12993 	PackBitsStream rle;
12994 	PackBitsStream_Construct(&rle);
12995 	rle.base.base.base.content = content;
12996 	rle.base.base.base.contentOffset = 128;
12997 	rle.base.base.base.contentLength = contentLength;
12998 	if (!RleStream_Unpack(&rle.base, unpacked, 128, 1, bitmapOffset))
12999 		return NULL;
13000 	for (int bitplane = 0; bitplane < bytesPer16Pixels; bitplane += 2) {
13001 		for (int x = bitplane; x < 160; x += bytesPer16Pixels) {
13002 			if (!RleStream_UnpackWords(&rle.base, unpacked, bitmapOffset + x, 160, unpackedLength))
13003 				return NULL;
13004 		}
13005 	}
13006 	return unpacked;
13007 }
13008 
RECOIL_DecodePbx01(RECOIL * self,uint8_t const * content,int contentLength,int bitplanes,int lineHeight)13009 static bool RECOIL_DecodePbx01(RECOIL *self, uint8_t const *content, int contentLength, int bitplanes, int lineHeight)
13010 {
13011 	uint8_t unpacked[32512];
13012 	content = RECOIL_UnpackPbx(self, content, contentLength, unpacked, 512, bitplanes << 1, 32512);
13013 	if (content == NULL || content[161] != 0)
13014 		return false;
13015 	int paletteOffset = 128;
13016 	for (int y = 0; y < 200; y++) {
13017 		if (paletteOffset < 512 && y == content[paletteOffset + 33]) {
13018 			RECOIL_SetStPalette(self, content, paletteOffset, 16);
13019 			do
13020 				paletteOffset += 48;
13021 			while (paletteOffset < 512 && content[paletteOffset + 34] == 0 && content[paletteOffset + 35] == 0);
13022 		}
13023 		RECOIL_DecodeBitplanes(self, content, 512 + y * 160, 0, bitplanes, y * lineHeight * self->width, self->width, lineHeight);
13024 	}
13025 	return true;
13026 }
13027 
RECOIL_DecodePbx8(RECOIL * self,uint8_t const * content,int paletteOffset,int bitmapOffset,int pixelsOffset)13028 static void RECOIL_DecodePbx8(RECOIL *self, uint8_t const *content, int paletteOffset, int bitmapOffset, int pixelsOffset)
13029 {
13030 	for (int y = 0; y < 200; y++) {
13031 		for (int x = 0; x < 320; x++) {
13032 			int c = RECOIL_GetStLowPixel(content, bitmapOffset + y * 160, x);
13033 			if (x >= (c > 7 ? 88 : 76) + c * 10 - (c & 1) * 6)
13034 				c += 16;
13035 			self->pixels[pixelsOffset + x] = RECOIL_GetStColor(self, content, paletteOffset + (y << 6) + (c << 1));
13036 		}
13037 		pixelsOffset += 320;
13038 	}
13039 }
13040 
RECOIL_DecodePbx(RECOIL * self,uint8_t const * content,int contentLength)13041 static bool RECOIL_DecodePbx(RECOIL *self, uint8_t const *content, int contentLength)
13042 {
13043 	if (contentLength < 128 || content[0] != 0 || content[1] != 0 || content[2] != 0)
13044 		return false;
13045 	switch (content[3]) {
13046 	case 0:
13047 		RECOIL_SetSize(self, 320, 200, RECOILResolution_ST1X1);
13048 		return RECOIL_DecodePbx01(self, content, contentLength, 4, 1);
13049 	case 1:
13050 		RECOIL_SetSize(self, 640, 400, RECOILResolution_ST1X2);
13051 		return RECOIL_DecodePbx01(self, content, contentLength, 2, 2);
13052 	case 128:
13053 		{
13054 			uint8_t unpacked[44928];
13055 			content = RECOIL_UnpackPbx(self, content, contentLength, unpacked, 12928, 8, 44928);
13056 			if (content == NULL)
13057 				return false;
13058 			RECOIL_SetSize(self, 320, 200, RECOILResolution_ST1X1);
13059 			RECOIL_DecodePbx8(self, content, 128, 12928, 0);
13060 			return true;
13061 		}
13062 	case 129:
13063 		{
13064 			uint8_t unpacked[57728];
13065 			content = RECOIL_UnpackPbx(self, content, contentLength, unpacked, 25728, 8, 57728);
13066 			if (content == NULL)
13067 				return false;
13068 			RECOIL_SetSize(self, 320, 200, RECOILResolution_ST1X1);
13069 			RECOIL_DecodePbx8(self, content, 128, 25728, 0);
13070 			RECOIL_DecodePbx8(self, content, 12928, 25728, 64000);
13071 			return RECOIL_ApplyBlend(self);
13072 		}
13073 	default:
13074 		return false;
13075 	}
13076 }
13077 
RECOIL_DecodeMppScreen(RECOIL * self,uint8_t const * content,int paletteOffset,int paletteLength,int pixelsOffset)13078 static void RECOIL_DecodeMppScreen(RECOIL *self, uint8_t const *content, int paletteOffset, int paletteLength, int pixelsOffset)
13079 {
13080 	int mode = content[3];
13081 	int bitmapOffset = paletteOffset + paletteLength;
13082 	int palette[16] = { 0 };
13083 	MppPaletteStream paletteStream;
13084 	MppPaletteStream_Construct(&paletteStream);
13085 	paletteStream.base.base.content = content;
13086 	paletteStream.base.base.contentOffset = paletteOffset;
13087 	paletteStream.base.base.contentLength = bitmapOffset;
13088 	for (int y = 0; y < self->height; y++) {
13089 		for (int c = mode == 3 ? 6 : 1; c < 16; c++)
13090 			palette[c] = MppPaletteStream_Read(&paletteStream);
13091 		static const uint8_t FIRST_CHANGE_X[4] = { 33, 9, 4, 69 };
13092 		int changeX = FIRST_CHANGE_X[mode];
13093 		int changeColor = 0;
13094 		for (int x = 0; x < self->width; x++) {
13095 			if (x == changeX) {
13096 				static const uint8_t RIGHT_BORDER_COLOR[4] = { 32, 16, 32, 127 };
13097 				palette[changeColor & 15] = changeColor == RIGHT_BORDER_COLOR[mode] ? 0 : MppPaletteStream_Read(&paletteStream);
13098 				switch (mode) {
13099 				case 0:
13100 				case 3:
13101 					switch (changeColor) {
13102 					case 15:
13103 						changeX += mode == 0 ? 88 : 112;
13104 						break;
13105 					case 31:
13106 						changeX += 12;
13107 						break;
13108 					case 37:
13109 						changeX += 100;
13110 						break;
13111 					default:
13112 						changeX += 4;
13113 						break;
13114 					}
13115 					break;
13116 				case 1:
13117 					changeX += (changeColor & 1) == 0 ? 4 : 16;
13118 					break;
13119 				case 2:
13120 					changeX += 8;
13121 					break;
13122 				default:
13123 					assert(false);
13124 				}
13125 				changeColor++;
13126 			}
13127 			self->pixels[pixelsOffset + x] = palette[RECOIL_GetStLowPixel(content, bitmapOffset, x)];
13128 		}
13129 		bitmapOffset += self->width >> 1;
13130 		pixelsOffset += self->width;
13131 	}
13132 }
13133 
RECOIL_DecodeMpp(RECOIL * self,uint8_t const * content,int contentLength)13134 static bool RECOIL_DecodeMpp(RECOIL *self, uint8_t const *content, int contentLength)
13135 {
13136 	if (contentLength < 12 || content[0] != 77 || content[1] != 80 || content[2] != 80)
13137 		return false;
13138 	int mode = content[3];
13139 	if (mode > 3)
13140 		return false;
13141 	int width = mode < 3 ? 320 : 416;
13142 	int height = mode < 3 ? 199 : 273;
13143 	static const uint8_t MODE_COLORS_PER_LINE[4] = { 52, 46, 54, 48 };
13144 	int paletteLength = MODE_COLORS_PER_LINE[mode] * height;
13145 	switch (content[4] & 3) {
13146 	case 0:
13147 		RECOIL_SetSize(self, width, height, RECOILResolution_ST1X1);
13148 		paletteLength *= 9;
13149 		break;
13150 	case 1:
13151 		RECOIL_SetSize(self, width, height, RECOILResolution_STE1X1);
13152 		paletteLength *= 12;
13153 		break;
13154 	case 3:
13155 		RECOIL_SetSize(self, width, height, RECOILResolution_STE1X1);
13156 		self->frames = 2;
13157 		paletteLength *= 15;
13158 		break;
13159 	default:
13160 		return false;
13161 	}
13162 	paletteLength = (paletteLength + 15) >> 4 << 1;
13163 	int paletteOffset = 12 + RECOIL_Get32BigEndian(content, 8);
13164 	if (paletteOffset < 12)
13165 		return false;
13166 	int pixelsLength = width * height;
13167 	if (contentLength != paletteOffset + ((paletteLength + (pixelsLength >> 1)) << (content[4] >> 2 & 1)))
13168 		return false;
13169 	RECOIL_DecodeMppScreen(self, content, paletteOffset, paletteLength, 0);
13170 	if ((content[4] & 4) == 0)
13171 		return true;
13172 	RECOIL_DecodeMppScreen(self, content, paletteOffset + paletteLength + (pixelsLength >> 1), paletteLength, pixelsLength);
13173 	return RECOIL_ApplyBlend(self);
13174 }
13175 
RECOIL_DecodeHrm(RECOIL * self,uint8_t const * content,int contentLength)13176 static bool RECOIL_DecodeHrm(RECOIL *self, uint8_t const *content, int contentLength)
13177 {
13178 	if (contentLength != 92000)
13179 		return false;
13180 	RECOIL_SetSize(self, 640, 400, RECOILResolution_STE1X2);
13181 	self->frames = 2;
13182 	for (int y = 0; y < 400; y++) {
13183 		for (int x = 0; x < 640; x++) {
13184 			int offset = y * 160 + (x >> 2 & -4) + (x >> 3 & 1);
13185 			int bit = ~x & 7;
13186 			int c = (content[offset] >> bit & 1) | (content[offset + 2] >> bit & 1) << 1;
13187 			static const uint8_t COLOR_OFFSETS[4] = { 80, 72, 40, 32 };
13188 			c += ((x + COLOR_OFFSETS[c]) / 80 << 2) - 1;
13189 			int rgb = RECOIL_GetStColor(self, content, 64000 + y * 70 + (c << 1));
13190 			int pixelsOffset = y * 640 + x;
13191 			if ((y & 1) == 0)
13192 				self->pixels[pixelsOffset] = rgb;
13193 			else {
13194 				int rgb1 = self->pixels[pixelsOffset - 640];
13195 				self->pixels[pixelsOffset] = self->pixels[pixelsOffset - 640] = (rgb1 & rgb) + ((rgb1 ^ rgb) >> 1 & 8355711);
13196 			}
13197 		}
13198 	}
13199 	return true;
13200 }
13201 
RECOIL_DecodeStIcn(RECOIL * self,uint8_t const * content,int contentLength)13202 static bool RECOIL_DecodeStIcn(RECOIL *self, uint8_t const *content, int contentLength)
13203 {
13204 	IcnParser parser;
13205 	parser.base.content = content;
13206 	parser.base.contentOffset = 0;
13207 	parser.base.contentLength = contentLength;
13208 	int width = IcnParser_ParseDefine(&parser, "ICON_W");
13209 	if (width <= 0 || width >= 256)
13210 		return false;
13211 	int height = IcnParser_ParseDefine(&parser, "ICON_H");
13212 	if (height <= 0 || height >= 256)
13213 		return false;
13214 	int size = IcnParser_ParseDefine(&parser, "ICONSIZE");
13215 	if (size != ((width + 15) >> 4) * height)
13216 		return false;
13217 	if (!IcnParser_Expect(&parser, "int") || !IcnParser_Expect(&parser, "image[ICONSIZE]") || !IcnParser_Expect(&parser, "=") || !IcnParser_Expect(&parser, "{"))
13218 		return false;
13219 	uint8_t bitmap[8192];
13220 	for (int i = 0;;) {
13221 		int value = IcnParser_ParseHex(&parser);
13222 		if (value < 0)
13223 			return false;
13224 		bitmap[i * 2] = (uint8_t) (value >> 8);
13225 		bitmap[i * 2 + 1] = (uint8_t) value;
13226 		if (++i >= size)
13227 			break;
13228 		if (parser.base.contentOffset >= contentLength)
13229 			return false;
13230 		if (content[parser.base.contentOffset++] != 44)
13231 			return false;
13232 	}
13233 	if (!IcnParser_Expect(&parser, "};"))
13234 		return false;
13235 	RECOIL_SetSize(self, width, height, RECOILResolution_ST1X1);
13236 	return RECOIL_DecodeBlackAndWhite(self, bitmap, 0, size << 1, true, 16777215);
13237 }
13238 
RECOIL_DecodeCe(RECOIL * self,uint8_t const * content,int contentLength)13239 static bool RECOIL_DecodeCe(RECOIL *self, uint8_t const *content, int contentLength)
13240 {
13241 	if (contentLength < 192022 || !RECOIL_IsStringAt(content, 0, "EYES") || content[4] != 0)
13242 		return false;
13243 	switch (content[5]) {
13244 	case 0:
13245 		if (contentLength != 192022)
13246 			return false;
13247 		RECOIL_SetSize(self, 320, 200, RECOILResolution_ST1X1);
13248 		for (int y = 0; y < 200; y++) {
13249 			for (int x = 0; x < 320; x++) {
13250 				int offset = 22 + x * 200 + y;
13251 				int rgb = content[offset] << 16 | content[64000 + offset] << 8 | content[128000 + offset];
13252 				if ((rgb & 12632256) != 0)
13253 					return false;
13254 				self->pixels[y * 320 + x] = rgb << 2 | (rgb >> 4 & 197379);
13255 			}
13256 		}
13257 		return true;
13258 	case 1:
13259 		if (contentLength != 256022)
13260 			return false;
13261 		RECOIL_SetSize(self, 640, 400, RECOILResolution_ST1X2);
13262 		for (int y = 0; y < 200; y++) {
13263 			for (int x = 0; x < 640; x++) {
13264 				int offset = (11 + x * 200 + y) << 1;
13265 				int c = content[offset] << 8 | content[offset + 1];
13266 				if (c >= 32768)
13267 					return false;
13268 				offset = y * 1280 + x;
13269 				self->pixels[offset + 640] = self->pixels[offset] = RECOIL_GetR5G5B5Color(c);
13270 			}
13271 		}
13272 		return true;
13273 	case 2:
13274 		if (contentLength != 256022)
13275 			return false;
13276 		RECOIL_SetSize(self, 640, 400, RECOILResolution_ST1X1);
13277 		for (int y = 0; y < 400; y++) {
13278 			for (int x = 0; x < 640; x++) {
13279 				int b = content[22 + x * 400 + (y & 1) * 200 + (y >> 1)];
13280 				if (b > 191)
13281 					return false;
13282 				self->pixels[y * 640 + x] = b * 4 / 3 * 65793;
13283 			}
13284 		}
13285 		return true;
13286 	default:
13287 		return false;
13288 	}
13289 }
13290 
RECOIL_DecodeIbi(RECOIL * self,uint8_t const * content,int contentLength)13291 static bool RECOIL_DecodeIbi(RECOIL *self, uint8_t const *content, int contentLength)
13292 {
13293 	if ((contentLength != 704 && contentLength != 1600) || content[0] != 73 || content[1] != 67 || content[2] != 66 || (content[3] != 73 && content[3] != 51) || content[8] != 0 || content[9] != 32 || content[10] != 0 || content[11] != 32)
13294 		return false;
13295 	RECOIL_SetSize(self, 32, 32, RECOILResolution_FALCON1X1);
13296 	RECOIL_SetDefaultStPalette(self, 4);
13297 	RECOIL_DecodeBitplanes(self, content, 64, 16, 4, 0, 32, 32);
13298 	return true;
13299 }
13300 
RECOIL_DecodeFalconGrayscale(RECOIL * self,uint8_t const * content,int contentOffset,int contentLength,int width,int height)13301 static bool RECOIL_DecodeFalconGrayscale(RECOIL *self, uint8_t const *content, int contentOffset, int contentLength, int width, int height)
13302 {
13303 	int pixelsLength = width * height;
13304 	if (contentLength != contentOffset + pixelsLength || !RECOIL_SetSize(self, width, height, RECOILResolution_FALCON1X1))
13305 		return false;
13306 	for (int i = 0; i < pixelsLength; i++)
13307 		self->pixels[i] = content[contentOffset + i] * 65793;
13308 	return true;
13309 }
13310 
RECOIL_DecodeBw(RECOIL * self,uint8_t const * content,int contentLength)13311 static bool RECOIL_DecodeBw(RECOIL *self, uint8_t const *content, int contentLength)
13312 {
13313 	if (contentLength < 11 || !RECOIL_IsStringAt(content, 0, "B&W256"))
13314 		return false;
13315 	int width = content[6] << 8 | content[7];
13316 	int height = content[8] << 8 | content[9];
13317 	return RECOIL_DecodeFalconGrayscale(self, content, 10, contentLength, width, height);
13318 }
13319 
RECOIL_DecodeFalconHir(RECOIL * self,uint8_t const * content,int contentLength)13320 static bool RECOIL_DecodeFalconHir(RECOIL *self, uint8_t const *content, int contentLength)
13321 {
13322 	if (contentLength < 11 || content[0] != 15 || content[1] != 15 || content[2] != 0 || content[3] != 1 || content[8] != 0 || content[9] != 1)
13323 		return false;
13324 	int width = content[4] << 8 | content[5];
13325 	int height = content[6] << 8 | content[7];
13326 	int pixelsLength = width * height;
13327 	if (contentLength != 10 + pixelsLength || !RECOIL_SetSize(self, width, height, RECOILResolution_FALCON1X1))
13328 		return false;
13329 	for (int i = 0; i < pixelsLength; i++) {
13330 		int b = content[10 + i];
13331 		if (b >= 128)
13332 			return false;
13333 		self->pixels[i] = b * 131586;
13334 	}
13335 	return true;
13336 }
13337 
RECOIL_DecodeRw(RECOIL * self,uint8_t const * content,int contentLength)13338 static bool RECOIL_DecodeRw(RECOIL *self, uint8_t const *content, int contentLength)
13339 {
13340 	switch (contentLength) {
13341 	case 64000:
13342 		RECOIL_SetSize(self, 320, 200, RECOILResolution_FALCON1X1);
13343 		break;
13344 	case 128000:
13345 		RECOIL_SetSize(self, 640, 200, RECOILResolution_FALCON1X1);
13346 		break;
13347 	case 256000:
13348 		RECOIL_SetSize(self, 640, 400, RECOILResolution_FALCON1X1);
13349 		break;
13350 	default:
13351 		return false;
13352 	}
13353 	for (int i = 0; i < contentLength; i++)
13354 		self->pixels[i] = (255 - content[i]) * 65793;
13355 	return true;
13356 }
13357 
RECOIL_GetR8G8B8Color(uint8_t const * content,int contentOffset)13358 static int RECOIL_GetR8G8B8Color(uint8_t const *content, int contentOffset)
13359 {
13360 	return content[contentOffset] << 16 | content[contentOffset + 1] << 8 | content[contentOffset + 2];
13361 }
13362 
RECOIL_DecodeR8G8B8Colors(uint8_t const * content,int contentOffset,int count,int * destination)13363 static void RECOIL_DecodeR8G8B8Colors(uint8_t const *content, int contentOffset, int count, int *destination)
13364 {
13365 	for (int i = 0; i < count; i++)
13366 		destination[i] = RECOIL_GetR8G8B8Color(content, contentOffset + i * 3);
13367 }
13368 
RECOIL_DecodeR8G8G8X8Colors(RECOIL * self,uint8_t const * content,int contentOffset,int count)13369 static void RECOIL_DecodeR8G8G8X8Colors(RECOIL *self, uint8_t const *content, int contentOffset, int count)
13370 {
13371 	for (int i = 0; i < count; i++)
13372 		self->pixels[i] = RECOIL_GetR8G8B8Color(content, contentOffset + (i << 2));
13373 }
13374 
RECOIL_DecodeIim(RECOIL * self,uint8_t const * content,int contentLength)13375 static bool RECOIL_DecodeIim(RECOIL *self, uint8_t const *content, int contentLength)
13376 {
13377 	if (contentLength < 17 || !RECOIL_IsStringAt(content, 0, "IS_IMAGE") || content[8] != 0)
13378 		return false;
13379 	int width = content[12] << 8 | content[13];
13380 	int height = content[14] << 8 | content[15];
13381 	int pixelsLength = width * height;
13382 	switch (content[9]) {
13383 	case 0:
13384 		return RECOIL_SetSize(self, width, height, RECOILResolution_FALCON1X1) && RECOIL_DecodeBlackAndWhite(self, content, 16, contentLength, false, 16777215);
13385 	case 1:
13386 		return RECOIL_DecodeFalconGrayscale(self, content, 16, contentLength, width, height);
13387 	case 4:
13388 		if (contentLength != 16 + pixelsLength * 3 || !RECOIL_SetSize(self, width, height, RECOILResolution_FALCON1X1))
13389 			return false;
13390 		RECOIL_DecodeR8G8B8Colors(content, 16, pixelsLength, self->pixels);
13391 		return true;
13392 	case 5:
13393 		if (contentLength != 16 + (pixelsLength << 2) || !RECOIL_SetSize(self, width, height, RECOILResolution_FALCON1X1))
13394 			return false;
13395 		RECOIL_DecodeR8G8G8X8Colors(self, content, 17, pixelsLength);
13396 		return true;
13397 	default:
13398 		return false;
13399 	}
13400 }
13401 
RECOIL_SetFalconPalette(RECOIL * self,uint8_t const * content,int contentOffset)13402 static void RECOIL_SetFalconPalette(RECOIL *self, uint8_t const *content, int contentOffset)
13403 {
13404 	for (int i = 0; i < 256; i++) {
13405 		int offset = contentOffset + (i << 2);
13406 		self->contentPalette[i] = content[offset] << 16 | content[offset + 1] << 8 | content[offset + 3];
13407 	}
13408 }
13409 
RECOIL_DecodeFalconPalette(RECOIL * self,uint8_t const * content,int bitplanesOffset,int paletteOffset,int width,int height)13410 static void RECOIL_DecodeFalconPalette(RECOIL *self, uint8_t const *content, int bitplanesOffset, int paletteOffset, int width, int height)
13411 {
13412 	RECOIL_SetFalconPalette(self, content, paletteOffset);
13413 	RECOIL_SetSize(self, width, height, RECOILResolution_FALCON1X1);
13414 	RECOIL_DecodeBitplanes(self, content, bitplanesOffset, width, 8, 0, width, height);
13415 }
13416 
RECOIL_DecodeFuckpaint(RECOIL * self,uint8_t const * content,int contentLength)13417 static bool RECOIL_DecodeFuckpaint(RECOIL *self, uint8_t const *content, int contentLength)
13418 {
13419 	switch (contentLength) {
13420 	case 65024:
13421 		RECOIL_DecodeFalconPalette(self, content, 1024, 0, 320, 200);
13422 		return true;
13423 	case 77824:
13424 		RECOIL_DecodeFalconPalette(self, content, 1024, 0, 320, 240);
13425 		return true;
13426 	case 308224:
13427 		RECOIL_DecodeFalconPalette(self, content, 1024, 0, 640, 480);
13428 		return true;
13429 	default:
13430 		return false;
13431 	}
13432 }
13433 
RECOIL_DecodeDg1(RECOIL * self,uint8_t const * content,int contentLength)13434 static bool RECOIL_DecodeDg1(RECOIL *self, uint8_t const *content, int contentLength)
13435 {
13436 	if (contentLength != 65032 || content[0] != 68 || content[1] != 71 || content[2] != 85 || content[3] != 1 || content[4] != 1 || content[5] != 64 || content[6] != 0 || content[7] != 200)
13437 		return false;
13438 	RECOIL_DecodeFalconPalette(self, content, 1032, 8, 320, 200);
13439 	return true;
13440 }
13441 
RECOIL_DecodeDc1(RECOIL * self,uint8_t const * content,int contentLength)13442 static bool RECOIL_DecodeDc1(RECOIL *self, uint8_t const *content, int contentLength)
13443 {
13444 	if (contentLength < 1042 || content[0] != 68 || content[1] != 71 || content[2] != 67 || content[4] != 1 || content[5] != 64 || content[6] != 0 || content[7] != 200)
13445 		return false;
13446 	int compression = content[3];
13447 	if (compression == 0) {
13448 		if (contentLength != 65034)
13449 			return false;
13450 		RECOIL_DecodeFalconPalette(self, content, 1034, 10, 320, 200);
13451 		return true;
13452 	}
13453 	if (compression > 3)
13454 		return false;
13455 	uint8_t unpacked[64000];
13456 	int contentOffset = 1038;
13457 	int valueBytes = 1 << (compression - 1);
13458 	int repeatCount = 0;
13459 	for (int bitplane = 0; bitplane < 16; bitplane += 2) {
13460 		for (int unpackedOffset = bitplane; unpackedOffset < 64000; unpackedOffset += 16) {
13461 			for (int x = 0; x < 2; x++) {
13462 				if (repeatCount == 0) {
13463 					int nextContentOffset = contentOffset + compression * 2;
13464 					if (nextContentOffset > contentLength) {
13465 						unpacked[unpackedOffset + x] = 0;
13466 						continue;
13467 					}
13468 					switch (compression) {
13469 					case 1:
13470 						repeatCount = content[contentOffset] + 1;
13471 						break;
13472 					case 2:
13473 						repeatCount = ((content[contentOffset] << 8) + content[contentOffset + 1] + 1) << 1;
13474 						break;
13475 					case 3:
13476 						repeatCount = ((content[contentOffset] << 8) + content[contentOffset + 1] + 1) << 2;
13477 						break;
13478 					default:
13479 						assert(false);
13480 					}
13481 					contentOffset = nextContentOffset;
13482 				}
13483 				unpacked[unpackedOffset + x] = content[contentOffset - (--repeatCount & (valueBytes - 1)) - 1];
13484 			}
13485 		}
13486 	}
13487 	RECOIL_SetFalconPalette(self, content, 10);
13488 	RECOIL_SetSize(self, 320, 200, RECOILResolution_FALCON1X1);
13489 	RECOIL_DecodeBitplanes(self, unpacked, 0, 320, 8, 0, 320, 200);
13490 	return true;
13491 }
13492 
RECOIL_DecodeDel(RECOIL * self,uint8_t const * content,int contentLength)13493 static bool RECOIL_DecodeDel(RECOIL *self, uint8_t const *content, int contentLength)
13494 {
13495 	uint8_t unpacked[96000];
13496 	return CaStream_UnpackDel(content, contentLength, unpacked, 2) && RECOIL_DecodeFuckpaint(self, unpacked, 77824);
13497 }
13498 
RECOIL_DecodeDph(RECOIL * self,uint8_t const * content,int contentLength)13499 static bool RECOIL_DecodeDph(RECOIL *self, uint8_t const *content, int contentLength)
13500 {
13501 	uint8_t *unpacked = (uint8_t *) CiShared_Make(320000, sizeof(uint8_t), NULL, NULL);
13502 	if (!CaStream_UnpackDel(content, contentLength, unpacked, 10)) {
13503 		CiShared_Release(unpacked);
13504 		return false;
13505 	}
13506 	RECOIL_SetFalconPalette(self, unpacked, 0);
13507 	RECOIL_SetSize(self, 640, 480, RECOILResolution_FALCON1X1);
13508 	RECOIL_DecodeBitplanes(self, unpacked, 1024, 320, 8, 0, 320, 240);
13509 	RECOIL_DecodeBitplanes(self, unpacked, 77824, 320, 8, 320, 320, 240);
13510 	RECOIL_DecodeBitplanes(self, unpacked, 154624, 320, 8, 153600, 320, 240);
13511 	RECOIL_DecodeBitplanes(self, unpacked, 231424, 320, 8, 153920, 320, 240);
13512 	CiShared_Release(unpacked);
13513 	return true;
13514 }
13515 
RECOIL_DecodeFalconTrueColor(RECOIL * self,uint8_t const * content,int contentOffset,int width,int height,RECOILResolution resolution)13516 static bool RECOIL_DecodeFalconTrueColor(RECOIL *self, uint8_t const *content, int contentOffset, int width, int height, RECOILResolution resolution)
13517 {
13518 	if (!RECOIL_SetScaledSize(self, width, height, resolution))
13519 		return false;
13520 	for (int y = 0; y < height; y++) {
13521 		for (int x = 0; x < width; x++) {
13522 			RECOIL_SetScaledPixel(self, x, y, RECOIL_GetFalconTrueColor(content, contentOffset));
13523 			contentOffset += 2;
13524 		}
13525 	}
13526 	return true;
13527 }
13528 
RECOIL_DecodeFalconTrueColorVariable(RECOIL * self,uint8_t const * content,int contentLength,int widthOffset,int dataOffset)13529 static bool RECOIL_DecodeFalconTrueColorVariable(RECOIL *self, uint8_t const *content, int contentLength, int widthOffset, int dataOffset)
13530 {
13531 	int width = content[widthOffset] << 8 | content[widthOffset + 1];
13532 	int height = content[widthOffset + 2] << 8 | content[widthOffset + 3];
13533 	return dataOffset + width * height * 2 == contentLength && RECOIL_DecodeFalconTrueColor(self, content, dataOffset, width, height, RECOILResolution_FALCON1X1);
13534 }
13535 
RECOIL_DecodeFtc(RECOIL * self,uint8_t const * content,int contentLength)13536 static bool RECOIL_DecodeFtc(RECOIL *self, uint8_t const *content, int contentLength)
13537 {
13538 	return contentLength == 184320 && RECOIL_DecodeFalconTrueColor(self, content, 0, 384, 240, RECOILResolution_FALCON1X1);
13539 }
13540 
RECOIL_DecodeXga(RECOIL * self,uint8_t const * content,int contentLength)13541 static bool RECOIL_DecodeXga(RECOIL *self, uint8_t const *content, int contentLength)
13542 {
13543 	switch (contentLength) {
13544 	case 153600:
13545 		return RECOIL_DecodeFalconTrueColor(self, content, 0, 320, 240, RECOILResolution_FALCON1X1);
13546 	case 368640:
13547 		return RECOIL_DecodeFalconTrueColor(self, content, 0, 384, 480, RECOILResolution_FALCON2X1);
13548 	default:
13549 		return false;
13550 	}
13551 }
13552 
RECOIL_DecodeGod(RECOIL * self,uint8_t const * content,int contentLength)13553 static bool RECOIL_DecodeGod(RECOIL *self, uint8_t const *content, int contentLength)
13554 {
13555 	return contentLength > 6 && RECOIL_DecodeFalconTrueColorVariable(self, content, contentLength, 2, 6);
13556 }
13557 
RECOIL_DecodeTrp(RECOIL * self,uint8_t const * content,int contentLength)13558 static bool RECOIL_DecodeTrp(RECOIL *self, uint8_t const *content, int contentLength)
13559 {
13560 	return contentLength >= 9 && (RECOIL_IsStringAt(content, 0, "TRUP") || RECOIL_IsStringAt(content, 0, "tru?")) && RECOIL_DecodeFalconTrueColorVariable(self, content, contentLength, 4, 8);
13561 }
13562 
RECOIL_DecodeTru(RECOIL * self,uint8_t const * content,int contentLength)13563 static bool RECOIL_DecodeTru(RECOIL *self, uint8_t const *content, int contentLength)
13564 {
13565 	return contentLength >= 256 && RECOIL_IsStringAt(content, 0, "Indy") && RECOIL_DecodeFalconTrueColorVariable(self, content, contentLength, 4, 256);
13566 }
13567 
RECOIL_DecodeTg1(RECOIL * self,uint8_t const * content,int contentLength)13568 static bool RECOIL_DecodeTg1(RECOIL *self, uint8_t const *content, int contentLength)
13569 {
13570 	return contentLength >= 20 && RECOIL_IsStringAt(content, 0, "COKE format.") && content[16] == 0 && content[17] == 18 && RECOIL_DecodeFalconTrueColorVariable(self, content, contentLength, 12, 18);
13571 }
13572 
RECOIL_DecodeTcp(RECOIL * self,uint8_t const * content,int contentLength)13573 static bool RECOIL_DecodeTcp(RECOIL *self, uint8_t const *content, int contentLength)
13574 {
13575 	return contentLength >= 218 && RECOIL_IsStringAt(content, 0, "TRUECOLR") && content[12] == 0 && content[13] == 18 && content[14] == 0 && content[15] == 1 && content[16] == 0 && content[17] == 1 && RECOIL_IsStringAt(content, 18, "PICT") && RECOIL_DecodeFalconTrueColorVariable(self, content, contentLength, 28, 216);
13576 }
13577 
RECOIL_DecodeTre(RECOIL * self,uint8_t const * content,int contentLength)13578 static bool RECOIL_DecodeTre(RECOIL *self, uint8_t const *content, int contentLength)
13579 {
13580 	if (contentLength < 13 || !RECOIL_IsStringAt(content, 0, "tre1"))
13581 		return false;
13582 	int width = content[4] << 8 | content[5];
13583 	int height = content[6] << 8 | content[7];
13584 	if (!RECOIL_SetSize(self, width, height, RECOILResolution_FALCON1X1))
13585 		return false;
13586 	Tre1Stream rle;
13587 	Tre1Stream_Construct(&rle);
13588 	rle.base.base.base.content = content;
13589 	rle.base.base.base.contentOffset = 12;
13590 	rle.base.base.base.contentLength = contentLength;
13591 	int pixelsLength = width * height;
13592 	for (int i = 0; i < pixelsLength; i++) {
13593 		int rgb = RleStream_ReadRle(&rle.base);
13594 		if (rgb < 0)
13595 			return false;
13596 		self->pixels[i] = rgb;
13597 	}
13598 	return true;
13599 }
13600 
RECOIL_DecodeRag(RECOIL * self,uint8_t const * content,int contentLength)13601 static bool RECOIL_DecodeRag(RECOIL *self, uint8_t const *content, int contentLength)
13602 {
13603 	if (contentLength < 55 || !RECOIL_IsStringAt(content, 0, "RAG-D!") || content[6] != 0 || content[7] != 0 || content[16] != 0)
13604 		return false;
13605 	int width = content[12] << 8 | content[13];
13606 	if ((width & 15) != 0)
13607 		return false;
13608 	int height = (content[14] << 8) + content[15] + 1;
13609 	int bitplanes = content[17];
13610 	int paletteLength = RECOIL_Get32BigEndian(content, 18);
13611 	switch (bitplanes) {
13612 	case 1:
13613 	case 2:
13614 	case 4:
13615 	case 8:
13616 		switch (paletteLength) {
13617 		case 32:
13618 			if (bitplanes > 4)
13619 				return false;
13620 			break;
13621 		case 1024:
13622 			break;
13623 		default:
13624 			return false;
13625 		}
13626 		int bytesPerLine = (width >> 3) * bitplanes;
13627 		if (30 + paletteLength + height * bytesPerLine > contentLength || !RECOIL_SetSize(self, width, height, RECOILResolution_FALCON1X1))
13628 			return false;
13629 		if (paletteLength == 32)
13630 			RECOIL_SetStPalette(self, content, 30, 16);
13631 		else
13632 			RECOIL_SetFalconPalette(self, content, 30);
13633 		RECOIL_DecodeBitplanes(self, content, 30 + paletteLength, bytesPerLine, bitplanes, 0, width, height);
13634 		return true;
13635 	case 16:
13636 		return paletteLength == 1024 && contentLength >= 1054 + width * height * 2 && RECOIL_DecodeFalconTrueColor(self, content, 1054, width, height, RECOILResolution_FALCON1X1);
13637 	default:
13638 		return false;
13639 	}
13640 }
13641 
RECOIL_DecodeFalconFun(RECOIL * self,uint8_t const * content,int contentLength)13642 static bool RECOIL_DecodeFalconFun(RECOIL *self, uint8_t const *content, int contentLength)
13643 {
13644 	if (contentLength < 14 || content[0] != 0 || content[1] != 10 || content[2] != 207 || content[3] != 226 || content[8] != 0)
13645 		return false;
13646 	int width = content[4] << 8 | content[5];
13647 	if ((width & 15) != 0)
13648 		return false;
13649 	int height = content[6] << 8 | content[7];
13650 	int bitplanes = content[9];
13651 	switch (bitplanes) {
13652 	case 1:
13653 	case 2:
13654 	case 4:
13655 	case 8:
13656 		;
13657 		int bytesPerLine = (width >> 3) * bitplanes;
13658 		int paletteOffset = 25 + height * bytesPerLine;
13659 		int colors = 1 << bitplanes;
13660 		if (contentLength != paletteOffset + colors * 6 || !RECOIL_SetSizeStOrFalcon(self, width, height, bitplanes, false))
13661 			return false;
13662 		if (bitplanes == 1)
13663 			RECOIL_SetDefaultStPalette(self, 1);
13664 		else
13665 			RECOIL_SetStVdiPalette(self, content, paletteOffset, colors, bitplanes);
13666 		RECOIL_DecodeScaledBitplanes(self, content, 13, width, height, bitplanes, false, NULL);
13667 		return true;
13668 	case 16:
13669 		return contentLength >= 13 + width * height * 2 && RECOIL_DecodeFalconTrueColor(self, content, 13, width, height, RECOILResolution_FALCON1X1);
13670 	default:
13671 		return false;
13672 	}
13673 }
13674 
RECOIL_DecodeEsm(RECOIL * self,uint8_t const * content,int contentLength)13675 static bool RECOIL_DecodeEsm(RECOIL *self, uint8_t const *content, int contentLength)
13676 {
13677 	if (contentLength < 812 || content[0] != 84 || content[1] != 77 || content[2] != 83 || content[3] != 0 || content[4] != 3 || content[5] != 44 || content[10] != 0)
13678 		return false;
13679 	int width = content[6] << 8 | content[7];
13680 	int height = content[8] << 8 | content[9];
13681 	if (!RECOIL_SetSize(self, width, height, RECOILResolution_FALCON1X1))
13682 		return false;
13683 	int pixelsLength = width * height;
13684 	switch (content[11]) {
13685 	case 1:
13686 		return RECOIL_DecodeBlackAndWhite(self, content, 812, contentLength, false, 16777215);
13687 	case 8:
13688 		if (contentLength != 812 + pixelsLength)
13689 			return false;
13690 		for (int i = 0; i < 256; i++)
13691 			self->contentPalette[i] = content[36 + i] << 16 | content[292 + i] << 8 | content[548 + i];
13692 		for (int i = 0; i < pixelsLength; i++)
13693 			self->pixels[i] = self->contentPalette[content[812 + i]];
13694 		return true;
13695 	case 24:
13696 		if (contentLength != 812 + pixelsLength * 3)
13697 			return false;
13698 		RECOIL_DecodeR8G8B8Colors(content, 812, pixelsLength, self->pixels);
13699 		return true;
13700 	default:
13701 		return false;
13702 	}
13703 }
13704 
RECOIL_DecodeFalconPix(RECOIL * self,uint8_t const * content,int contentLength)13705 static bool RECOIL_DecodeFalconPix(RECOIL *self, uint8_t const *content, int contentLength)
13706 {
13707 	if (contentLength < 15 || !RECOIL_IsStringAt(content, 0, "PIXT") || content[4] != 0)
13708 		return false;
13709 	int contentOffset;
13710 	switch (content[5]) {
13711 	case 1:
13712 		contentOffset = 14;
13713 		break;
13714 	case 2:
13715 		contentOffset = 16;
13716 		break;
13717 	default:
13718 		return false;
13719 	}
13720 	int width = content[8] << 8 | content[9];
13721 	if ((width & 15) != 0)
13722 		return false;
13723 	int bitplanes = content[7];
13724 	int height = content[10] << 8 | content[11];
13725 	int pixelsLength;
13726 	switch (bitplanes) {
13727 	case 1:
13728 		return content[6] == 1 && RECOIL_SetSizeStOrFalcon(self, width, height, 1, false) && RECOIL_DecodeBlackAndWhite(self, content, contentOffset, contentLength, true, 16777215);
13729 	case 2:
13730 	case 4:
13731 		;
13732 		int bitmapOffset = contentOffset + (3 << bitplanes);
13733 		if (content[6] != 1 || contentLength != bitmapOffset + (width >> 3) * bitplanes * height || !RECOIL_SetSizeStOrFalcon(self, width, height, bitplanes, false))
13734 			return false;
13735 		RECOIL_DecodeR8G8B8Colors(content, contentOffset, 1 << bitplanes, self->contentPalette);
13736 		RECOIL_DecodeScaledBitplanes(self, content, bitmapOffset, width, height, bitplanes, false, NULL);
13737 		return true;
13738 	case 8:
13739 		if (content[6] != 0 || contentLength != contentOffset + 768 + width * height || !RECOIL_SetSize(self, width, height, RECOILResolution_FALCON1X1))
13740 			return false;
13741 		RECOIL_DecodeR8G8B8Colors(content, contentOffset, 256, self->contentPalette);
13742 		RECOIL_DecodeBytes(self, content, contentOffset + 768);
13743 		return true;
13744 	case 16:
13745 		return content[6] == 1 && contentLength == contentOffset + width * height * 2 && RECOIL_DecodeFalconTrueColor(self, content, contentOffset, width, height, RECOILResolution_FALCON1X1);
13746 	case 24:
13747 		pixelsLength = width * height;
13748 		if (content[6] != 1 || contentLength != contentOffset + pixelsLength * 3 || !RECOIL_SetSize(self, width, height, RECOILResolution_FALCON1X1))
13749 			return false;
13750 		RECOIL_DecodeR8G8B8Colors(content, contentOffset, pixelsLength, self->pixels);
13751 		return true;
13752 	case 32:
13753 		pixelsLength = width * height;
13754 		if (contentLength != contentOffset + (pixelsLength << 2) || !RECOIL_SetSize(self, width, height, RECOILResolution_FALCON1X1))
13755 			return false;
13756 		RECOIL_DecodeR8G8G8X8Colors(self, content, contentOffset + 1, pixelsLength);
13757 		return true;
13758 	default:
13759 		return false;
13760 	}
13761 }
13762 
RECOIL_DecodePntUnpacked(RECOIL * self,uint8_t const * content,uint8_t const * bitmap,int bitmapOffset,int width,int height)13763 static bool RECOIL_DecodePntUnpacked(RECOIL *self, uint8_t const *content, uint8_t const *bitmap, int bitmapOffset, int width, int height)
13764 {
13765 	int bitplanes = content[13];
13766 	switch (bitplanes) {
13767 	case 1:
13768 	case 2:
13769 	case 4:
13770 	case 8:
13771 		if (!RECOIL_SetSizeStOrFalcon(self, width, height, bitplanes, false))
13772 			return false;
13773 		int paletteLength = content[6] << 8 | content[7];
13774 		RECOIL_SetStVdiPalette(self, content, 128, paletteLength, bitplanes);
13775 		RECOIL_DecodeScaledBitplanes(self, bitmap, bitmapOffset, width, height, bitplanes, false, NULL);
13776 		return true;
13777 	case 16:
13778 		return RECOIL_DecodeFalconTrueColor(self, bitmap, bitmapOffset, width, height, RECOILResolution_FALCON1X1);
13779 	case 24:
13780 		if (!RECOIL_SetSize(self, width, height, RECOILResolution_FALCON1X1))
13781 			return false;
13782 		for (int y = 0; y < height; y++) {
13783 			for (int x = 0; x < width; x++)
13784 				self->pixels[y * width + x] = RECOIL_GetR8G8B8Color(bitmap, bitmapOffset + x * 3);
13785 			bitmapOffset += ((width + 15) & -16) * 3;
13786 		}
13787 		return true;
13788 	default:
13789 		return false;
13790 	}
13791 }
13792 
RECOIL_DecodeFalconPnt(RECOIL * self,uint8_t const * content,int contentLength)13793 static bool RECOIL_DecodeFalconPnt(RECOIL *self, uint8_t const *content, int contentLength)
13794 {
13795 	if (contentLength < 128 || content[0] != 80 || content[1] != 78 || content[2] != 84 || content[3] != 0 || content[4] != 1 || content[5] != 0 || content[12] != 0 || content[14] != 0)
13796 		return false;
13797 	int paletteLength = content[6] << 8 | content[7];
13798 	int bitmapOffset = 128 + paletteLength * 6;
13799 	int bitmapLength = RECOIL_Get32BigEndian(content, 16);
13800 	if (bitmapLength <= 0 || contentLength < bitmapOffset + bitmapLength)
13801 		return false;
13802 	int width = content[8] << 8 | content[9];
13803 	int height = content[10] << 8 | content[11];
13804 	int bitplanes = content[13];
13805 	int unpackedLength = ((width + 15) >> 4 << 1) * height * bitplanes;
13806 	switch (content[15]) {
13807 	case 0:
13808 		return bitmapLength == unpackedLength && RECOIL_DecodePntUnpacked(self, content, content, bitmapOffset, width, height);
13809 	case 1:
13810 		;
13811 		uint8_t *unpacked = (uint8_t *) CiShared_Make(unpackedLength, sizeof(uint8_t), NULL, NULL);
13812 		PackBitsStream rle;
13813 		PackBitsStream_Construct(&rle);
13814 		rle.base.base.base.content = content;
13815 		rle.base.base.base.contentOffset = bitmapOffset;
13816 		rle.base.base.base.contentLength = contentLength;
13817 		bool returnValue = PackBitsStream_UnpackBitplaneLines(&rle, unpacked, width, height, bitplanes, true, false) && RECOIL_DecodePntUnpacked(self, content, unpacked, 0, width, height);
13818 		CiShared_Release(unpacked);
13819 		return returnValue;
13820 	default:
13821 		return false;
13822 	}
13823 }
13824 
RECOIL_SetOcsColor(RECOIL * self,int c,int r,int gb)13825 static void RECOIL_SetOcsColor(RECOIL *self, int c, int r, int gb)
13826 {
13827 	int rgb = (r & 15) << 16 | (gb & 240) << 4 | (gb & 15);
13828 	self->contentPalette[c] = rgb * 17;
13829 }
13830 
RECOIL_SetOcsPalette(RECOIL * self,uint8_t const * content,int contentOffset,int colors)13831 static void RECOIL_SetOcsPalette(RECOIL *self, uint8_t const *content, int contentOffset, int colors)
13832 {
13833 	for (int c = 0; c < colors; c++) {
13834 		int r = content[contentOffset++];
13835 		int gb = content[contentOffset++];
13836 		RECOIL_SetOcsColor(self, c, r, gb);
13837 	}
13838 }
13839 
RECOIL_DecodeAmigaPlanar(RECOIL * self,uint8_t const * content,int contentOffset,int width,int height,int bitplanes,int const * palette)13840 static bool RECOIL_DecodeAmigaPlanar(RECOIL *self, uint8_t const *content, int contentOffset, int width, int height, int bitplanes, int const *palette)
13841 {
13842 	if (!RECOIL_SetSize(self, width, height, RECOILResolution_AMIGA1X1))
13843 		return false;
13844 	int bytesPerLine = (width + 15) >> 4 << 1;
13845 	int bitplaneLength = height * bytesPerLine;
13846 	for (int y = 0; y < height; y++) {
13847 		for (int x = 0; x < width; x++) {
13848 			int c = RECOIL_GetBitplanePixel(content, contentOffset + y * bytesPerLine + (x >> 3), x, bitplanes, bitplaneLength);
13849 			self->pixels[y * width + x] = palette[c];
13850 		}
13851 	}
13852 	return true;
13853 }
13854 
RECOIL_DecodeInfo(RECOIL * self,uint8_t const * content,int contentLength)13855 static bool RECOIL_DecodeInfo(RECOIL *self, uint8_t const *content, int contentLength)
13856 {
13857 	if (contentLength < 98 || content[0] != 227 || content[1] != 16 || content[2] != 0 || content[3] != 1)
13858 		return false;
13859 	static const int OS1_PALETTE[4] = { 5614335, 16777215, 0, 16746496 };
13860 	static const int OS2_PALETTE[8] = { 9803157, 0, 16777215, 3893154, 8092539, 11513775, 11178108, 16755095 };
13861 	int const *palette;
13862 	switch (RECOIL_Get32BigEndian(content, 44)) {
13863 	case 0:
13864 		palette = OS1_PALETTE;
13865 		break;
13866 	case 1:
13867 		palette = OS2_PALETTE;
13868 		break;
13869 	default:
13870 		return false;
13871 	}
13872 	int contentOffset = RECOIL_Get32BigEndian(content, 66) == 0 ? 78 : 134;
13873 	int width = content[contentOffset + 4] << 8 | content[contentOffset + 5];
13874 	int height = content[contentOffset + 6] << 8 | content[contentOffset + 7];
13875 	int bitplanes = content[contentOffset + 8] << 8 | content[contentOffset + 9];
13876 	switch (bitplanes) {
13877 	case 2:
13878 		break;
13879 	case 3:
13880 		if (palette == OS1_PALETTE)
13881 			return false;
13882 		break;
13883 	default:
13884 		return false;
13885 	}
13886 	int bytesPerLine = (width + 15) >> 4 << 1;
13887 	int bitplaneLength = height * bytesPerLine;
13888 	contentOffset += 20;
13889 	return contentLength >= contentOffset + bitplanes * bitplaneLength && RECOIL_DecodeAmigaPlanar(self, content, contentOffset, width, height, bitplanes, palette);
13890 }
13891 
RECOIL_DecodeAbkSprite(RECOIL * self,uint8_t const * content,int contentLength)13892 static bool RECOIL_DecodeAbkSprite(RECOIL *self, uint8_t const *content, int contentLength)
13893 {
13894 	if (content[10] != 0)
13895 		return false;
13896 	int bitplanes = content[11];
13897 	if (bitplanes == 0 || bitplanes > 5)
13898 		return false;
13899 	int width = content[6] << 8 | content[7];
13900 	int height = content[8] << 8 | content[9];
13901 	int bitplaneLength = width * height << 1;
13902 	int paletteOffset = 16 + bitplanes * bitplaneLength;
13903 	if (paletteOffset + 64 > contentLength)
13904 		return false;
13905 	RECOIL_SetOcsPalette(self, content, paletteOffset, 32);
13906 	return RECOIL_DecodeAmigaPlanar(self, content, 16, width << 4, height, bitplanes, self->contentPalette);
13907 }
13908 
RECOIL_DecodeAbk(RECOIL * self,uint8_t const * content,int contentLength)13909 static bool RECOIL_DecodeAbk(RECOIL *self, uint8_t const *content, int contentLength)
13910 {
13911 	if (contentLength < 82 || content[0] != 65 || content[1] != 109)
13912 		return false;
13913 	switch (content[2]) {
13914 	case 83:
13915 		return content[3] == 112 && RECOIL_DecodeAbkSprite(self, content, contentLength);
13916 	case 73:
13917 		return content[3] == 99 && RECOIL_DecodeAbkSprite(self, content, contentLength);
13918 	case 66:
13919 		break;
13920 	default:
13921 		return false;
13922 	}
13923 	if (content[3] != 107 || contentLength < 135 || !RECOIL_IsStringAt(content, 12, "Pac.Pic") || content[110] != 6 || content[111] != 7 || content[112] != 25 || content[113] != 99 || content[124] != 0)
13924 		return false;
13925 	int width = content[118] << 8 | content[119];
13926 	int lumps = content[120] << 8 | content[121];
13927 	int lumpLines = content[122] << 8 | content[123];
13928 	int height = lumps * lumpLines;
13929 	int bitplanes = content[125];
13930 	if (bitplanes == 0 || bitplanes > 5 || !RECOIL_SetSize(self, width << 3, height, RECOILResolution_AMIGA1X1))
13931 		return false;
13932 	int rleOffset = 110 + RECOIL_Get32BigEndian(content, 126);
13933 	if (rleOffset < 0 || rleOffset >= contentLength)
13934 		return false;
13935 	int pointsOffset = 110 + RECOIL_Get32BigEndian(content, 130);
13936 	if (pointsOffset < 0)
13937 		return false;
13938 	uint8_t *unpacked = (uint8_t *) CiShared_Make(bitplanes * width * height, sizeof(uint8_t), NULL, NULL);
13939 	int picOffset = 135;
13940 	int pic = content[134];
13941 	int rleBits = content[rleOffset++] << 8 | 128;
13942 	int pointsBits = 0;
13943 	for (int bitplane = 0; bitplane < bitplanes; bitplane++) {
13944 		for (int lump = 0; lump < lumps; lump++) {
13945 			for (int x = 0; x < width; x++) {
13946 				for (int y = 0; y < lumpLines; y++) {
13947 					rleBits <<= 1;
13948 					if ((rleBits & 255) == 0) {
13949 						pointsBits <<= 1;
13950 						if ((pointsBits & 255) == 0) {
13951 							if (pointsOffset >= contentLength) {
13952 								CiShared_Release(unpacked);
13953 								return false;
13954 							}
13955 							pointsBits = content[pointsOffset++] << 1 | 1;
13956 						}
13957 						if ((pointsBits >> 8 & 1) != 0) {
13958 							if (rleOffset >= contentLength) {
13959 								CiShared_Release(unpacked);
13960 								return false;
13961 							}
13962 							rleBits = content[rleOffset++] << 1 | 1;
13963 						}
13964 						else {
13965 							rleBits >>= 8;
13966 						}
13967 					}
13968 					if ((rleBits >> 8 & 1) != 0) {
13969 						pic = content[picOffset++];
13970 					}
13971 					unpacked[((bitplane * lumps + lump) * lumpLines + y) * width + x] = (uint8_t) pic;
13972 				}
13973 			}
13974 		}
13975 	}
13976 	RECOIL_SetOcsPalette(self, content, 46, 32);
13977 	bool returnValue = RECOIL_DecodeAmigaPlanar(self, unpacked, 0, width << 3, height, bitplanes, self->contentPalette);
13978 	CiShared_Release(unpacked);
13979 	return returnValue;
13980 }
13981 
RECOIL_GetAmigaAspectRatio(int xRatio,int yRatio,RECOILResolution resolution)13982 static RECOILResolution RECOIL_GetAmigaAspectRatio(int xRatio, int yRatio, RECOILResolution resolution)
13983 {
13984 	if (xRatio <= 0 || yRatio <= 0)
13985 		return resolution;
13986 	if (xRatio > yRatio * 6)
13987 		return RECOILResolution_AMIGA8X1;
13988 	if (xRatio > yRatio * 3)
13989 		return RECOILResolution_AMIGA4X1;
13990 	if (xRatio * 2 > yRatio * 3)
13991 		return RECOILResolution_AMIGA2X1;
13992 	if (yRatio > xRatio * 3)
13993 		return RECOILResolution_AMIGA1X4;
13994 	if (yRatio * 2 > xRatio * 3)
13995 		return resolution == RECOILResolution_AMIGA1X1 ? RECOILResolution_AMIGA1X2 : RECOILResolution_ST1X2;
13996 	return resolution;
13997 }
13998 
RECOIL_GetCamgAspectRatio(int camg,RECOILResolution resolution)13999 static RECOILResolution RECOIL_GetCamgAspectRatio(int camg, RECOILResolution resolution)
14000 {
14001 	int log;
14002 	switch (camg & -61440) {
14003 	case 0:
14004 	case 69632:
14005 	case 135168:
14006 	case 462848:
14007 	case 790528:
14008 	case 856064:
14009 		camg &= 32812;
14010 		log = 0;
14011 		break;
14012 	case 266240:
14013 		return RECOILResolution_AMIGA1X1;
14014 	case 331776:
14015 	case 528384:
14016 	case 724992:
14017 	case 921600:
14018 		camg &= 32812;
14019 		log = -1;
14020 		break;
14021 	case 200704:
14022 	case 397312:
14023 		camg &= 32805;
14024 		log = -1;
14025 		break;
14026 	case 593920:
14027 	case 659456:
14028 		camg &= 33285;
14029 		log = 0;
14030 		break;
14031 	default:
14032 		return resolution;
14033 	}
14034 	switch (camg & 33312) {
14035 	case 0:
14036 		break;
14037 	case 32768:
14038 		log++;
14039 		break;
14040 	case 32800:
14041 		log += 2;
14042 		break;
14043 	case 512:
14044 		log--;
14045 		break;
14046 	default:
14047 		return resolution;
14048 	}
14049 	switch (camg & 13) {
14050 	case 0:
14051 		break;
14052 	case 4:
14053 		log--;
14054 		break;
14055 	case 5:
14056 		log -= 2;
14057 		break;
14058 	case 8:
14059 		log++;
14060 		break;
14061 	default:
14062 		return resolution;
14063 	}
14064 	switch (log) {
14065 	case 0:
14066 		return RECOILResolution_AMIGA1X1;
14067 	case -1:
14068 		return RECOILResolution_AMIGA2X1;
14069 	case -2:
14070 		return RECOILResolution_AMIGA4X1;
14071 	case -3:
14072 		return RECOILResolution_AMIGA8X1;
14073 	case 1:
14074 		return RECOILResolution_AMIGA1X2;
14075 	case 2:
14076 		return RECOILResolution_AMIGA1X4;
14077 	default:
14078 		return resolution;
14079 	}
14080 }
14081 
RECOIL_DecodeDeep(RECOIL * self,uint8_t const * content,int contentLength)14082 static bool RECOIL_DecodeDeep(RECOIL *self, uint8_t const *content, int contentLength)
14083 {
14084 	int width = 0;
14085 	int height = 0;
14086 	int compression = 0;
14087 	RECOILResolution resolution = RECOILResolution_AMIGA1X1;
14088 	DeepStream rle;
14089 	DeepStream_Construct(&rle);
14090 	rle.base.base.base.base.content = content;
14091 	int tvdcOffset = -1;
14092 	for (int contentOffset = 12; contentOffset < contentLength - 7;) {
14093 		int chunkLength = RECOIL_Get32BigEndian(content, contentOffset + 4);
14094 		int chunkEndOffset = contentOffset + 8 + chunkLength;
14095 		if (chunkEndOffset > contentLength || chunkEndOffset < contentOffset + 8)
14096 			break;
14097 		if (RECOIL_IsStringAt(content, contentOffset, "DGBL")) {
14098 			if (chunkLength < 8 || content[contentOffset + 12] != 0)
14099 				return false;
14100 			width = content[contentOffset + 8] << 8 | content[contentOffset + 9];
14101 			height = content[contentOffset + 10] << 8 | content[contentOffset + 11];
14102 			compression = content[contentOffset + 13];
14103 			resolution = RECOIL_GetAmigaAspectRatio(content[contentOffset + 14], content[contentOffset + 15], resolution);
14104 		}
14105 		else if (RECOIL_IsStringAt(content, contentOffset, "DPEL")) {
14106 			if (!DeepStream_SetDpel(&rle, contentOffset, chunkLength))
14107 				return false;
14108 		}
14109 		else if (RECOIL_IsStringAt(content, contentOffset, "DLOC")) {
14110 			if (chunkLength < 4)
14111 				return false;
14112 			width = content[contentOffset + 8] << 8 | content[contentOffset + 9];
14113 			height = content[contentOffset + 10] << 8 | content[contentOffset + 11];
14114 		}
14115 		else if (RECOIL_IsStringAt(content, contentOffset, "TVDC")) {
14116 			if (chunkLength != 32)
14117 				return false;
14118 			tvdcOffset = contentOffset + 8;
14119 		}
14120 		else if (RECOIL_IsStringAt(content, contentOffset, "DBOD")) {
14121 			if (chunkEndOffset + 8 < contentLength && RECOIL_IsStringAt(content, chunkEndOffset, "DBOD"))
14122 				return false;
14123 			if (rle.components <= 0 || !RECOIL_SetScaledSize(self, width, height, resolution))
14124 				return false;
14125 			rle.base.base.base.base.contentOffset = contentOffset + 8;
14126 			rle.base.base.base.base.contentLength = chunkEndOffset;
14127 			for (int y = 0; y < height; y++) {
14128 				if (compression == 5) {
14129 					if (tvdcOffset < 0 || !DeepStream_ReadDeltaLine(&rle, width, tvdcOffset))
14130 						return false;
14131 				}
14132 				for (int x = 0; x < width; x++) {
14133 					int rgb;
14134 					switch (compression) {
14135 					case 0:
14136 						rgb = ((const RleStreamVtbl *) rle.base.base.base.vtbl)->readValue(&rle.base.base);
14137 						break;
14138 					case 1:
14139 						rgb = RleStream_ReadRle(&rle.base.base);
14140 						break;
14141 					case 5:
14142 						rgb = rle.line[x];
14143 						break;
14144 					default:
14145 						return false;
14146 					}
14147 					if (rgb < 0)
14148 						return false;
14149 					RECOIL_SetScaledPixel(self, x, y, rgb);
14150 				}
14151 			}
14152 			return true;
14153 		}
14154 		contentOffset = (chunkEndOffset + 1) & -2;
14155 	}
14156 	return false;
14157 }
14158 
RECOIL_DecodeRgbn(RECOIL * self,uint8_t const * content,int contentOffset,int contentLength,int width,int height,bool rgb8)14159 static bool RECOIL_DecodeRgbn(RECOIL *self, uint8_t const *content, int contentOffset, int contentLength, int width, int height, bool rgb8)
14160 {
14161 	int rgb = 0;
14162 	int count = 0;
14163 	for (int y = 0; y < height; y++) {
14164 		for (int x = 0; x < width; x++) {
14165 			if (count == 0) {
14166 				if (rgb8) {
14167 					if (contentOffset > contentLength - 4)
14168 						return false;
14169 					rgb = RECOIL_GetR8G8B8Color(content, contentOffset);
14170 					count = content[contentOffset + 3] & 127;
14171 					contentOffset += 4;
14172 				}
14173 				else {
14174 					if (contentOffset > contentLength - 2)
14175 						return false;
14176 					rgb = content[contentOffset];
14177 					count = content[contentOffset + 1];
14178 					rgb = (((rgb & 240) << 4 | (rgb & 15)) << 8 | count >> 4) * 17;
14179 					count &= 7;
14180 					contentOffset += 2;
14181 				}
14182 				if (count == 0) {
14183 					if (contentOffset >= contentLength)
14184 						return false;
14185 					count = content[contentOffset++];
14186 					if (count == 0) {
14187 						if (contentOffset > contentLength - 2)
14188 							return false;
14189 						count = content[contentOffset] << 8 | content[contentOffset + 1];
14190 						contentOffset += 2;
14191 					}
14192 				}
14193 			}
14194 			RECOIL_SetScaledPixel(self, x, y, rgb);
14195 			count--;
14196 		}
14197 	}
14198 	return true;
14199 }
14200 
RECOIL_DecodeRast(RECOIL * self,uint8_t const * content,int contentOffset,int contentLength,uint8_t const * unpacked,int width,int height,int bitplanes)14201 static bool RECOIL_DecodeRast(RECOIL *self, uint8_t const *content, int contentOffset, int contentLength, uint8_t const *unpacked, int width, int height, int bitplanes)
14202 {
14203 	if (!RECOIL_SetSizeStOrFalcon(self, width, height, bitplanes, false))
14204 		return false;
14205 	RastPalette rast;
14206 	RastPalette_Construct(&rast);
14207 	rast.base.base.base.content = content;
14208 	rast.base.base.base.contentOffset = contentOffset + 8;
14209 	rast.base.base.base.contentLength = contentLength;
14210 	rast.colors = 1 << bitplanes;
14211 	RECOIL_DecodeScaledBitplanes(self, unpacked, 0, width, height, bitplanes, false, &rast.base);
14212 	return true;
14213 }
14214 
RECOIL_DecodeHam(RECOIL * self,uint8_t const * unpacked,int width,int height,int bitplanes,MultiPalette * multiPalette)14215 static void RECOIL_DecodeHam(RECOIL *self, uint8_t const *unpacked, int width, int height, int bitplanes, MultiPalette *multiPalette)
14216 {
14217 	int bytesPerLine = ((width + 15) >> 4 << 1) * bitplanes;
14218 	int holdBits = bitplanes > 6 ? 6 : 4;
14219 	for (int y = 0; y < height; y++) {
14220 		if (multiPalette != NULL)
14221 			((const MultiPaletteVtbl *) multiPalette->base.vtbl)->setLinePalette(multiPalette, self, y);
14222 		int rgb = self->contentPalette[0];
14223 		for (int x = 0; x < width; x++) {
14224 			int c = RECOIL_GetBitplaneWordsPixel(unpacked, y * bytesPerLine, x, bitplanes);
14225 			switch (c >> holdBits) {
14226 			case 0:
14227 				rgb = self->contentPalette[c];
14228 				break;
14229 			case 1:
14230 				c = c << (8 - holdBits) & 255;
14231 				c |= c >> holdBits;
14232 				rgb = (rgb & 16776960) | c;
14233 				break;
14234 			case 2:
14235 				c = c << (8 - holdBits) & 255;
14236 				c |= c >> holdBits;
14237 				rgb = (rgb & 65535) | c << 16;
14238 				break;
14239 			case 3:
14240 				c = c << (8 - holdBits) & 255;
14241 				c |= c >> holdBits;
14242 				rgb = (rgb & 16711935) | c << 8;
14243 				break;
14244 			default:
14245 				assert(false);
14246 			}
14247 			RECOIL_SetScaledPixel(self, x, y, rgb);
14248 		}
14249 	}
14250 }
14251 
RECOIL_GetHameNibble(const RECOIL * self,uint8_t const * content,int contentOffset,int x)14252 static int RECOIL_GetHameNibble(const RECOIL *self, uint8_t const *content, int contentOffset, int x)
14253 {
14254 	int c = RECOIL_GetStLowPixel(content, contentOffset, x);
14255 	int rgb = self->contentPalette[c];
14256 	return (rgb >> 20 & 8) | (rgb >> 13 & 4) | (rgb >> 6 & 2) | (rgb >> 4 & 1);
14257 }
14258 
RECOIL_GetHameByte(const RECOIL * self,uint8_t const * content,int contentOffset,int x)14259 static int RECOIL_GetHameByte(const RECOIL *self, uint8_t const *content, int contentOffset, int x)
14260 {
14261 	return RECOIL_GetHameNibble(self, content, contentOffset, x << 1) << 4 | RECOIL_GetHameNibble(self, content, contentOffset, (x << 1) + 1);
14262 }
14263 
RECOIL_IsHame(const RECOIL * self,uint8_t const * content,int contentOffset)14264 static bool RECOIL_IsHame(const RECOIL *self, uint8_t const *content, int contentOffset)
14265 {
14266 	for (int i = 0; i < 7; i++) {
14267 		static const uint8_t MAGIC[7] = { 162, 245, 132, 220, 109, 176, 127 };
14268 		if (RECOIL_GetHameByte(self, content, contentOffset, i) != MAGIC[i])
14269 			return false;
14270 	}
14271 	switch (RECOIL_GetHameByte(self, content, contentOffset, 7)) {
14272 	case 20:
14273 	case 24:
14274 		return true;
14275 	default:
14276 		return false;
14277 	}
14278 }
14279 
RECOIL_DecodeHame(RECOIL * self,uint8_t const * content,int width)14280 static void RECOIL_DecodeHame(RECOIL *self, uint8_t const *content, int width)
14281 {
14282 	int palette[512] = { 0 };
14283 	int paletteLength[2] = { 0 };
14284 	bool hame = false;
14285 	for (int y = 0; y < self->height; y++) {
14286 		int lineOffset = y * width;
14287 		int paletteOffset = self->resolution == RECOILResolution_AMIGA2X1 && (y & 1) != 0 ? 256 : 0;
14288 		if (RECOIL_IsHame(self, content, lineOffset)) {
14289 			paletteOffset += paletteLength[paletteOffset >> 8];
14290 			for (int c = 0; c < 64; c++) {
14291 				int offset = 8 + c * 3;
14292 				palette[paletteOffset + c] = RECOIL_GetHameByte(self, content, lineOffset, offset) << 16 | RECOIL_GetHameByte(self, content, lineOffset, offset + 1) << 8 | RECOIL_GetHameByte(self, content, lineOffset, offset + 2);
14293 			}
14294 			paletteLength[paletteOffset >> 8] = (paletteLength[paletteOffset >> 8] + 64) & 255;
14295 			hame = RECOIL_GetHameByte(self, content, lineOffset, 7) == 24;
14296 			for (int x = 0; x < self->width; x++)
14297 				self->pixels[y * self->width + x] = 0;
14298 		}
14299 		else {
14300 			int paletteBank = 0;
14301 			int rgb = 0;
14302 			for (int x = 0; x < width; x++) {
14303 				int c = RECOIL_GetHameByte(self, content, lineOffset, x);
14304 				if (hame) {
14305 					switch (c >> 6) {
14306 					case 0:
14307 						if (c < 60)
14308 							rgb = palette[paletteOffset + paletteBank + c];
14309 						else
14310 							paletteBank = (c - 60) << 6;
14311 						break;
14312 					case 1:
14313 						rgb = (c & 63) << 2 | (rgb & 16776960);
14314 						break;
14315 					case 2:
14316 						rgb = (c & 63) << 18 | (rgb & 65535);
14317 						break;
14318 					default:
14319 						rgb = (c & 63) << 10 | (rgb & 16711935);
14320 						break;
14321 					}
14322 				}
14323 				else
14324 					rgb = palette[paletteOffset + c];
14325 				RECOIL_SetScaledPixel(self, x, y, rgb);
14326 			}
14327 		}
14328 	}
14329 }
14330 
RECOIL_GetDctvValue(const RECOIL * self,uint8_t const * content,int contentOffset,int x,int bitplanes)14331 static int RECOIL_GetDctvValue(const RECOIL *self, uint8_t const *content, int contentOffset, int x, int bitplanes)
14332 {
14333 	int c = RECOIL_GetBitplaneWordsPixel(content, contentOffset, x, bitplanes);
14334 	int rgb = self->contentPalette[c];
14335 	return (rgb << 2 & 64) | (rgb >> 19 & 16) | (rgb >> 5 & 4) | (rgb >> 15 & 1);
14336 }
14337 
RECOIL_IsDctv(const RECOIL * self,uint8_t const * content,int contentOffset,int bitplanes)14338 static bool RECOIL_IsDctv(const RECOIL *self, uint8_t const *content, int contentOffset, int bitplanes)
14339 {
14340 	if (RECOIL_GetDctvValue(self, content, contentOffset, 0, bitplanes) >> 6 != 0)
14341 		return false;
14342 	int r = 125;
14343 	for (int x = 1; x < 256; x++) {
14344 		if (RECOIL_GetDctvValue(self, content, contentOffset, x, bitplanes) >> 6 == (r & 1))
14345 			return false;
14346 		if ((r & 1) != 0)
14347 			r ^= 390;
14348 		r >>= 1;
14349 	}
14350 	return true;
14351 }
14352 
RECOIL_ClampByte(int x)14353 static int RECOIL_ClampByte(int x)
14354 {
14355 	return x <= 0 ? 0 : x >= 255 ? 255 : x;
14356 }
14357 
RECOIL_DecodeDctv(RECOIL * self,uint8_t const * content,int width,int height,RECOILResolution resolution,int bitplanes)14358 static bool RECOIL_DecodeDctv(RECOIL *self, uint8_t const *content, int width, int height, RECOILResolution resolution, int bitplanes)
14359 {
14360 	if (!RECOIL_IsDctv(self, content, 0, bitplanes))
14361 		return false;
14362 	int interlace;
14363 	int bytesPerLine = ((width + 15) >> 4 << 1) * bitplanes;
14364 	if (resolution == RECOILResolution_AMIGA1X2) {
14365 		interlace = 0;
14366 		height--;
14367 	}
14368 	else {
14369 		if (!RECOIL_IsDctv(self, content, bytesPerLine, bitplanes))
14370 			return false;
14371 		interlace = 1;
14372 		height -= 2;
14373 	}
14374 	RECOIL_SetScaledSize(self, width, height, resolution);
14375 	int contentOffset = bytesPerLine << interlace;
14376 	int chroma[10000];
14377 	for (int y = 0; y < height; y++) {
14378 		int odd = y >> interlace & 1;
14379 		int rgb = 0;
14380 		int o = 0;
14381 		int p = 0;
14382 		for (int x = 0; x < width; x++) {
14383 			if ((x & 1) == odd) {
14384 				int n = x + 1 < width ? RECOIL_GetDctvValue(self, content, contentOffset, x, bitplanes) << 1 | RECOIL_GetDctvValue(self, content, contentOffset, x + 1, bitplanes) : 0;
14385 				int i = (o + n) >> 1;
14386 				i = i <= 64 ? 0 : i >= 224 ? 255 : (i - 64) * 8 / 5;
14387 				int u = n + p - (o << 1);
14388 				if (u < 0)
14389 					u += 3;
14390 				u >>= 2;
14391 				if (((x + 1) & 2) == 0)
14392 					u = -u;
14393 				int chromaOffset = (x & -2) | (y & interlace);
14394 				int v = y > interlace ? chroma[chromaOffset] : 0;
14395 				chroma[chromaOffset] = u;
14396 				if (odd == 0) {
14397 					u = v;
14398 					v = chroma[chromaOffset];
14399 				}
14400 				p = o;
14401 				o = n;
14402 				int r = i + v * 4655 / 2560;
14403 				int b = i + u * 8286 / 2560;
14404 				int g = i - (v * 2372 + u * 1616) / 2560;
14405 				rgb = RECOIL_ClampByte(r) << 16 | RECOIL_ClampByte(g) << 8 | RECOIL_ClampByte(b);
14406 			}
14407 			RECOIL_SetScaledPixel(self, x, y, rgb);
14408 		}
14409 		contentOffset += bytesPerLine;
14410 	}
14411 	return true;
14412 }
14413 
RECOIL_DecodeIffUnpacked(RECOIL * self,uint8_t const * unpacked,int width,int height,RECOILResolution resolution,int bitplanes,int colors,int camg,MultiPalette * multiPalette)14414 static bool RECOIL_DecodeIffUnpacked(RECOIL *self, uint8_t const *unpacked, int width, int height, RECOILResolution resolution, int bitplanes, int colors, int camg, MultiPalette *multiPalette)
14415 {
14416 	if (!RECOIL_SetScaledSize(self, width, height, resolution))
14417 		return false;
14418 	if (bitplanes <= 8) {
14419 		if (colors == 0) {
14420 			colors = 1 << bitplanes;
14421 			for (int c = 0; c < colors; c++)
14422 				self->contentPalette[c] = c * 255 / colors * 65793;
14423 		}
14424 		if ((camg & 2048) != 0 || (bitplanes == 6 && colors == 16)) {
14425 			RECOIL_DecodeHam(self, unpacked, width, height, bitplanes, multiPalette);
14426 		}
14427 		else if (width >= 400 && (resolution == RECOILResolution_AMIGA1X2 || resolution == RECOILResolution_AMIGA1X1) && bitplanes == 4 && multiPalette == NULL && RECOIL_IsHame(self, unpacked, 0)) {
14428 			if (resolution == RECOILResolution_AMIGA1X2)
14429 				RECOIL_SetSize(self, width >> 1, height, RECOILResolution_AMIGA1X1);
14430 			else
14431 				RECOIL_SetSize(self, width, height, RECOILResolution_AMIGA2X1);
14432 			RECOIL_DecodeHame(self, unpacked, width >> 1);
14433 		}
14434 		else if (width >= 256 && height >= 3 && (resolution == RECOILResolution_AMIGA1X2 || resolution == RECOILResolution_AMIGA1X1) && multiPalette == NULL && RECOIL_DecodeDctv(self, unpacked, width, height, resolution, bitplanes)) {
14435 		}
14436 		else {
14437 			RECOIL_DecodeScaledBitplanes(self, unpacked, 0, width, height, bitplanes, bitplanes == 6 && ((camg & 128) != 0 || colors == 32), multiPalette);
14438 		}
14439 	}
14440 	else {
14441 		int bytesPerBitplane = (width + 15) >> 4 << 1;
14442 		for (int y = 0; y < height; y++) {
14443 			for (int x = 0; x < width; x++) {
14444 				int offset = (y * bytesPerBitplane + (x >> 3 & -2)) * bitplanes + (x >> 3 & 1);
14445 				int c = RECOIL_GetBitplanePixel(unpacked, offset, x, 24, 2);
14446 				RECOIL_SetScaledPixel(self, x, y, (c & 255) << 16 | (c & 65280) | c >> 16);
14447 			}
14448 		}
14449 	}
14450 	return true;
14451 }
14452 
RECOIL_DecodeIff(RECOIL * self,uint8_t const * content,int contentLength,RECOILResolution resolution)14453 static bool RECOIL_DecodeIff(RECOIL *self, uint8_t const *content, int contentLength, RECOILResolution resolution)
14454 {
14455 	if (contentLength < 56 || !RECOIL_IsStringAt(content, 0, "FORM"))
14456 		return false;
14457 	if (RECOIL_IsStringAt(content, 8, "DEEP") || RECOIL_IsStringAt(content, 8, "TVPP"))
14458 		return RECOIL_DecodeDeep(self, content, contentLength);
14459 	int contentOffset = 8;
14460 	if (RECOIL_IsStringAt(content, 8, "DPSTDPAH") && RECOIL_Get32BigEndian(content, 16) == 24 && RECOIL_IsStringAt(content, 44, "FORM"))
14461 		contentOffset = 52;
14462 	else if (RECOIL_IsStringAt(content, 8, "ANIMFORM"))
14463 		contentOffset = 20;
14464 	IffType type;
14465 	if (RECOIL_IsStringAt(content, contentOffset, "ILBM"))
14466 		type = IffType_ILBM;
14467 	else if (RECOIL_IsStringAt(content, contentOffset, "PBM "))
14468 		type = IffType_PBM;
14469 	else if (RECOIL_IsStringAt(content, contentOffset, "ACBM"))
14470 		type = IffType_ACBM;
14471 	else if (RECOIL_IsStringAt(content, contentOffset, "RGB8"))
14472 		type = IffType_RGB8;
14473 	else if (RECOIL_IsStringAt(content, contentOffset, "RGBN"))
14474 		type = IffType_RGBN;
14475 	else
14476 		return false;
14477 	contentOffset += 4;
14478 	int width = 0;
14479 	int height = 0;
14480 	int bitplanes = 0;
14481 	bool hasMask = false;
14482 	int compression = 0;
14483 	bool ocsPalette = false;
14484 	int colors = 0;
14485 	int camg = 0;
14486 	CtblPalette ctbl;
14487 	CtblPalette_Construct(&ctbl);
14488 	ShamLacePalette sham;
14489 	ShamLacePalette_Construct(&sham);
14490 	PchgPalette pchg;
14491 	PchgPalette_Construct(&pchg);
14492 	MultiPalette *multiPalette = NULL;
14493 	while (contentOffset < contentLength - 7) {
14494 		int chunkLength = RECOIL_Get32BigEndian(content, contentOffset + 4);
14495 		int chunkEndOffset = contentOffset + 8 + chunkLength;
14496 		if (chunkEndOffset > contentLength || chunkEndOffset < contentOffset + 8) {
14497 			chunkEndOffset = contentLength;
14498 			chunkLength = contentLength - contentOffset - 8;
14499 		}
14500 		if (RECOIL_IsStringAt(content, contentOffset, "BMHD") && chunkLength >= 16) {
14501 			width = content[contentOffset + 8] << 8 | content[contentOffset + 9];
14502 			height = content[contentOffset + 10] << 8 | content[contentOffset + 11];
14503 			bitplanes = content[contentOffset + 16];
14504 			hasMask = content[contentOffset + 17] == 1;
14505 			compression = content[contentOffset + 18];
14506 			switch (type) {
14507 			case IffType_PBM:
14508 				if (bitplanes != 8 || compression > 1)
14509 					return false;
14510 				break;
14511 			case IffType_RGB8:
14512 				if (bitplanes != 25 || compression != 4)
14513 					return false;
14514 				break;
14515 			case IffType_RGBN:
14516 				if (bitplanes != 13 || compression != 4)
14517 					return false;
14518 				break;
14519 			default:
14520 				if (bitplanes == 0 || (bitplanes > 8 && bitplanes != 24 && bitplanes != 32) || compression > 2)
14521 					return false;
14522 				break;
14523 			}
14524 			int pixelsCount = width * height;
14525 			if (pixelsCount <= 0 || pixelsCount > 2854278)
14526 				return false;
14527 			ocsPalette = content[contentOffset + 19] != 128;
14528 			resolution = RECOIL_GetAmigaAspectRatio(content[contentOffset + 22], content[contentOffset + 23], resolution);
14529 		}
14530 		else if (RECOIL_IsStringAt(content, contentOffset, "CMAP")) {
14531 			colors = chunkLength / 3;
14532 			if (colors > 256)
14533 				return false;
14534 			if (colors > 32)
14535 				ocsPalette = false;
14536 			int c;
14537 			for (c = 0; c < colors; c++) {
14538 				self->contentPalette[c] = RECOIL_GetR8G8B8Color(content, contentOffset + 8 + c * 3);
14539 				if ((self->contentPalette[c] & 986895) != 0)
14540 					ocsPalette = false;
14541 			}
14542 			for (; c < 256; c++)
14543 				self->contentPalette[c] = 0;
14544 			if (ocsPalette) {
14545 				for (c = 0; c < colors; c++)
14546 					self->contentPalette[c] |= self->contentPalette[c] >> 4;
14547 			}
14548 		}
14549 		else if (RECOIL_IsStringAt(content, contentOffset, "CAMG") && chunkLength >= 4) {
14550 			camg = RECOIL_Get32BigEndian(content, contentOffset + 8);
14551 			resolution = RECOIL_GetCamgAspectRatio(camg, resolution);
14552 		}
14553 		else if ((RECOIL_IsStringAt(content, contentOffset, "CTBL") || RECOIL_IsStringAt(content, contentOffset, "BEAM")) && height > 0) {
14554 			ctbl.colors = (chunkLength >> 1) / height;
14555 			if (ctbl.colors <= 32) {
14556 				ctbl.base.base.base.content = content;
14557 				ctbl.base.base.base.contentOffset = contentOffset + 8;
14558 				multiPalette = &ctbl.base;
14559 			}
14560 		}
14561 		else if (RECOIL_IsStringAt(content, contentOffset, "SHAM") && chunkLength >= 2 && content[contentOffset + 8] == 0 && content[contentOffset + 9] == 0) {
14562 			if (chunkLength == 2 + (height << 5)) {
14563 				ctbl.base.base.base.content = content;
14564 				ctbl.base.base.base.contentOffset = contentOffset + 10;
14565 				ctbl.colors = 16;
14566 				multiPalette = &ctbl.base;
14567 			}
14568 			else if (chunkLength == 2 + (height >> 1 << 5)) {
14569 				sham.base.base.base.content = content;
14570 				sham.base.base.base.contentOffset = contentOffset + 10;
14571 				multiPalette = &sham.base;
14572 			}
14573 		}
14574 		else if (RECOIL_IsStringAt(content, contentOffset, "PCHG")) {
14575 			pchg.base.base.base.content = content;
14576 			pchg.base.base.base.contentOffset = contentOffset + 8;
14577 			pchg.base.base.base.contentLength = chunkEndOffset;
14578 			if (!PchgPalette_Init(&pchg))
14579 				return false;
14580 			multiPalette = &pchg.base;
14581 		}
14582 		else if (RECOIL_IsStringAt(content, contentOffset, "BODY")) {
14583 			if (width == 0)
14584 				return false;
14585 			if (compression == 4)
14586 				return RECOIL_SetScaledSize(self, width, height, resolution) && RECOIL_DecodeRgbn(self, content, contentOffset + 8, chunkEndOffset, width, height, type == IffType_RGB8);
14587 			int bytesPerLine = ((width + 15) >> 4 << 1) * bitplanes;
14588 			uint8_t *unpacked = NULL;
14589 			if (compression == 2) {
14590 				CiShared_Assign((void **) &unpacked, (uint8_t *) CiShared_Make(bytesPerLine * height, sizeof(uint8_t), NULL, NULL));
14591 				VdatStream rle;
14592 				VdatStream_Construct(&rle);
14593 				rle.base.base.base.base.base.content = content;
14594 				rle.base.base.base.base.base.contentOffset = contentOffset + 8;
14595 				for (int bitplane = 0; bitplane < bitplanes; bitplane++) {
14596 					if (rle.base.base.base.base.base.contentOffset + 14 > chunkEndOffset || !RECOIL_IsStringAt(content, rle.base.base.base.base.base.contentOffset, "VDAT")) {
14597 						CiShared_Release(unpacked);
14598 						return false;
14599 					}
14600 					int nextContentOffset = rle.base.base.base.base.base.contentOffset + 8 + RECOIL_Get32BigEndian(content, rle.base.base.base.base.base.contentOffset + 4);
14601 					if (nextContentOffset > chunkEndOffset) {
14602 						CiShared_Release(unpacked);
14603 						return false;
14604 					}
14605 					rle.base.valueOffset = rle.base.base.base.base.base.contentLength = rle.base.base.base.base.base.contentOffset + 8 + (content[rle.base.base.base.base.base.contentOffset + 8] << 8) + content[rle.base.base.base.base.base.contentOffset + 9];
14606 					rle.base.valueLength = nextContentOffset;
14607 					rle.base.base.base.base.base.contentOffset += 10;
14608 					for (int x = bitplane << 1; x < bytesPerLine; x += bitplanes << 1) {
14609 						int unpackedOffset = x;
14610 						for (int y = 0; y < height; y++) {
14611 							int b = RleStream_ReadRle(&rle.base.base.base);
14612 							if (b < 0) {
14613 								CiShared_Release(unpacked);
14614 								return false;
14615 							}
14616 							unpacked[unpackedOffset] = (uint8_t) (b >> 8);
14617 							unpacked[unpackedOffset + 1] = (uint8_t) b;
14618 							unpackedOffset += bytesPerLine;
14619 						}
14620 					}
14621 					rle.base.base.base.base.base.contentOffset = nextContentOffset;
14622 				}
14623 				resolution = resolution == RECOILResolution_AMIGA1X2 ? RECOILResolution_ST1X2 : RECOILResolution_ST1X1;
14624 			}
14625 			else {
14626 				PackBitsStream rle;
14627 				PackBitsStream_Construct(&rle);
14628 				rle.base.base.base.content = content;
14629 				rle.base.base.base.contentOffset = contentOffset + 8;
14630 				rle.base.base.base.contentLength = chunkEndOffset;
14631 				if (type == IffType_PBM) {
14632 					if (colors == 0 || !RECOIL_SetScaledSize(self, width, height, resolution)) {
14633 						CiShared_Release(unpacked);
14634 						return false;
14635 					}
14636 					for (int y = 0; y < height; y++) {
14637 						for (int x = 0; x < width; x++) {
14638 							int b = compression == 0 ? Stream_ReadByte(&rle.base.base.base) : RleStream_ReadRle(&rle.base);
14639 							if (b < 0) {
14640 								CiShared_Release(unpacked);
14641 								return false;
14642 							}
14643 							RECOIL_SetScaledPixel(self, x, y, self->contentPalette[b]);
14644 						}
14645 						if ((width & 1) != 0 && (compression == 0 ? Stream_ReadByte(&rle.base.base.base) : RleStream_ReadRle(&rle.base)) < 0) {
14646 							CiShared_Release(unpacked);
14647 							return false;
14648 						}
14649 					}
14650 					CiShared_Release(unpacked);
14651 					return true;
14652 				}
14653 				CiShared_Assign((void **) &unpacked, (uint8_t *) CiShared_Make(bytesPerLine * height, sizeof(uint8_t), NULL, NULL));
14654 				if (!PackBitsStream_UnpackBitplaneLines(&rle, unpacked, width, height, bitplanes, compression == 1, hasMask)) {
14655 					CiShared_Release(unpacked);
14656 					return false;
14657 				}
14658 			}
14659 			if (bitplanes <= 8 && chunkEndOffset < contentLength - 8) {
14660 				int nextChunkOffset = (chunkEndOffset + 1) & -2;
14661 				if (RECOIL_IsStringAt(content, nextChunkOffset, "RAST")) {
14662 					bool returnValue = RECOIL_DecodeRast(self, content, nextChunkOffset, contentLength, unpacked, width, height, bitplanes);
14663 					CiShared_Release(unpacked);
14664 					return returnValue;
14665 				}
14666 				if (RECOIL_IsStringAt(content, chunkEndOffset, "RAST")) {
14667 					bool returnValue = RECOIL_DecodeRast(self, content, chunkEndOffset, contentLength, unpacked, width, height, bitplanes);
14668 					CiShared_Release(unpacked);
14669 					return returnValue;
14670 				}
14671 			}
14672 			bool returnValue = RECOIL_DecodeIffUnpacked(self, unpacked, width, height, resolution, bitplanes, colors, camg, multiPalette);
14673 			CiShared_Release(unpacked);
14674 			return returnValue;
14675 		}
14676 		else if (RECOIL_IsStringAt(content, contentOffset, "ABIT")) {
14677 			if (width == 0 || chunkLength != ((width + 15) >> 4 << 1) * height * bitplanes)
14678 				return false;
14679 			contentOffset += 8;
14680 			uint8_t *unpacked = (uint8_t *) CiShared_Make(chunkLength, sizeof(uint8_t), NULL, NULL);
14681 			for (int bitplane = 0; bitplane < bitplanes; bitplane++) {
14682 				for (int unpackedOffset = bitplane << 1; unpackedOffset < chunkLength; unpackedOffset += bitplanes << 1) {
14683 					unpacked[unpackedOffset] = content[contentOffset++];
14684 					unpacked[unpackedOffset + 1] = content[contentOffset++];
14685 				}
14686 			}
14687 			bool returnValue = RECOIL_DecodeIffUnpacked(self, unpacked, width, height, resolution, bitplanes, colors, camg, multiPalette);
14688 			CiShared_Release(unpacked);
14689 			return returnValue;
14690 		}
14691 		contentOffset = (chunkEndOffset + 1) & -2;
14692 	}
14693 	return false;
14694 }
14695 
RECOIL_DecodeFlfFont(RECOIL * self,uint8_t const * content,int contentOffset,int contentLength,int columns,int rows,RECOILResolution resolution,int const * palette,int colors,int xMask,int cMask)14696 static bool RECOIL_DecodeFlfFont(RECOIL *self, uint8_t const *content, int contentOffset, int contentLength, int columns, int rows, RECOILResolution resolution, int const *palette, int colors, int xMask, int cMask)
14697 {
14698 	if (contentLength != contentOffset + columns * rows * 12)
14699 		return false;
14700 	int width = columns << 3;
14701 	int height = rows << 3;
14702 	RECOIL_SetSize(self, width, height, resolution);
14703 	for (int y = 0; y < height; y++) {
14704 		for (int x = 0; x < width; x++) {
14705 			int offset = contentOffset + ((y >> 3) * columns + (x >> 3)) * 12;
14706 			int c = content[offset + (y & 7)] >> (x & xMask) & cMask;
14707 			c = content[offset + 8 + c];
14708 			if (c >= colors)
14709 				return false;
14710 			self->pixels[y * width + x] = palette[c];
14711 		}
14712 	}
14713 	return true;
14714 }
14715 
RECOIL_DecodeFlf(RECOIL * self,uint8_t const * content,int contentLength)14716 static bool RECOIL_DecodeFlf(RECOIL *self, uint8_t const *content, int contentLength)
14717 {
14718 	if (contentLength < 20 || !RECOIL_IsStringAt(content, 0, "FLUFF64"))
14719 		return false;
14720 	switch (content[11]) {
14721 	case 1:
14722 		return RECOIL_DecodeFlfFont(self, content, 15, contentLength, 40, 25, RECOILResolution_C642X1, RECOIL_C64_PALETTE, 16, 6, 3);
14723 	case 4:
14724 	case 5:
14725 		return RECOIL_DecodeFlfFont(self, content, 18, contentLength, 40, 25, RECOILResolution_C642X1, RECOIL_C64_PALETTE, 16, 6, 3);
14726 	case 6:
14727 		return RECOIL_DecodeFlfFont(self, content, 18, contentLength, 40, 25, RECOILResolution_C641X1, RECOIL_C64_PALETTE, 16, 7, 1);
14728 	case 7:
14729 		;
14730 		int columns = content[15];
14731 		int rows = content[16];
14732 		int length = columns * rows;
14733 		return contentLength >= 45 + (length << 1) && RECOIL_DecodePetScreen(self, content, 29 + length, 29, 13, columns, rows);
14734 	case 9:
14735 		if (content[12] != 6)
14736 			return false;
14737 		static const int VIC20_PALETTE[8] = { 0, 16777215, 6829867, 7382194, 7290246, 5803331, 3483769, 12109679 };
14738 		return RECOIL_DecodeFlfFont(self, content, 20, contentLength, content[18], content[19], RECOILResolution_VIC202X1, VIC20_PALETTE, 8, 6, 3);
14739 	case 12:
14740 		if (contentLength < 64020)
14741 			return false;
14742 		int colors = content[64013];
14743 		if (contentLength != 64014 + colors * 3)
14744 			return false;
14745 		RECOIL_DecodeR8G8B8Colors(content, 64014, colors, self->contentPalette);
14746 		for (int c = colors; c < 256; c++)
14747 			self->contentPalette[c] = 0;
14748 		RECOIL_SetSize(self, 320, 200, RECOILResolution_AMIGA1X1);
14749 		RECOIL_DecodeBytes(self, content, 13);
14750 		return true;
14751 	default:
14752 		return false;
14753 	}
14754 }
14755 
RECOIL_SetAtari8Palette(RECOIL * self,uint8_t const * content)14756 void RECOIL_SetAtari8Palette(RECOIL *self, uint8_t const *content)
14757 {
14758 	if (content == NULL)
14759 		content = CiResource_altirrapal_pal;
14760 	RECOIL_DecodeR8G8B8Colors(content, 0, 256, self->atari8Palette);
14761 }
14762 
RECOIL_ParseAtari8ExecutableHeader(uint8_t const * content,int contentOffset)14763 static int RECOIL_ParseAtari8ExecutableHeader(uint8_t const *content, int contentOffset)
14764 {
14765 	if (content[contentOffset] != 255 || content[contentOffset + 1] != 255)
14766 		return -1;
14767 	int startAddress = content[contentOffset + 2] | content[contentOffset + 3] << 8;
14768 	int endAddress = content[contentOffset + 4] | content[contentOffset + 5] << 8;
14769 	return endAddress - startAddress + 1;
14770 }
14771 
RECOIL_GetAtari8ExecutableOffset(uint8_t const * content,int contentLength)14772 static int RECOIL_GetAtari8ExecutableOffset(uint8_t const *content, int contentLength)
14773 {
14774 	if (contentLength >= 7) {
14775 		int blockLength = RECOIL_ParseAtari8ExecutableHeader(content, 0);
14776 		if (blockLength > 0 && 6 + blockLength == contentLength)
14777 			return 6;
14778 	}
14779 	return 0;
14780 }
14781 
RECOIL_SetAtari8RawSize(RECOIL * self,uint8_t const * content,int contentLength,RECOILResolution resolution)14782 static bool RECOIL_SetAtari8RawSize(RECOIL *self, uint8_t const *content, int contentLength, RECOILResolution resolution)
14783 {
14784 	int contentOffset = RECOIL_GetAtari8ExecutableOffset(content, contentLength);
14785 	int height = (contentLength - contentOffset) / 40;
14786 	if (height == 0 || height > 240)
14787 		return false;
14788 	RECOIL_SetSize(self, 320, height, resolution);
14789 	return true;
14790 }
14791 
RECOIL_SetGtiaColor(RECOIL * self,int reg,int value)14792 static void RECOIL_SetGtiaColor(RECOIL *self, int reg, int value)
14793 {
14794 	value &= 254;
14795 	switch (reg) {
14796 	case 0:
14797 	case 1:
14798 	case 2:
14799 	case 3:
14800 		self->gtiaColors[reg] = (uint8_t) value;
14801 		break;
14802 	case 4:
14803 	case 5:
14804 	case 6:
14805 	case 7:
14806 		self->gtiaColors[8 + reg] = self->gtiaColors[reg] = (uint8_t) value;
14807 		break;
14808 	case 8:
14809 		self->gtiaColors[11] = self->gtiaColors[10] = self->gtiaColors[9] = self->gtiaColors[8] = (uint8_t) value;
14810 		break;
14811 	default:
14812 		assert(false);
14813 	}
14814 }
14815 
RECOIL_SetPM123PF0123Bak(RECOIL * self,uint8_t const * content,int contentOffset)14816 static void RECOIL_SetPM123PF0123Bak(RECOIL *self, uint8_t const *content, int contentOffset)
14817 {
14818 	for (int i = 0; i < 8; i++)
14819 		RECOIL_SetGtiaColor(self, 1 + i, content[contentOffset + i]);
14820 }
14821 
RECOIL_SetGtiaColors(RECOIL * self,uint8_t const * content,int contentOffset)14822 static void RECOIL_SetGtiaColors(RECOIL *self, uint8_t const *content, int contentOffset)
14823 {
14824 	self->gtiaColors[0] = (uint8_t) (content[contentOffset] & 254);
14825 	RECOIL_SetPM123PF0123Bak(self, content, contentOffset + 1);
14826 }
14827 
RECOIL_SetPF21(RECOIL * self,uint8_t const * content,int contentOffset)14828 static void RECOIL_SetPF21(RECOIL *self, uint8_t const *content, int contentOffset)
14829 {
14830 	self->gtiaColors[6] = (uint8_t) (content[contentOffset] & 254);
14831 	self->gtiaColors[5] = (uint8_t) (content[contentOffset + 1] & 254);
14832 }
14833 
RECOIL_SetXeOsDefaultColors(RECOIL * self)14834 static void RECOIL_SetXeOsDefaultColors(RECOIL *self)
14835 {
14836 	self->gtiaColors[8] = 0;
14837 	self->gtiaColors[4] = 40;
14838 	self->gtiaColors[5] = 202;
14839 	self->gtiaColors[6] = 148;
14840 }
14841 
RECOIL_SetGr15DefaultColors(RECOIL * self)14842 static void RECOIL_SetGr15DefaultColors(RECOIL *self)
14843 {
14844 	self->gtiaColors[8] = 0;
14845 	self->gtiaColors[4] = 4;
14846 	self->gtiaColors[5] = 8;
14847 	self->gtiaColors[6] = 12;
14848 }
14849 
RECOIL_SetBakPF012(RECOIL * self,uint8_t const * content,int contentOffset,int contentStride)14850 static void RECOIL_SetBakPF012(RECOIL *self, uint8_t const *content, int contentOffset, int contentStride)
14851 {
14852 	for (int i = 0; i < 4; i++)
14853 		self->gtiaColors[i == 0 ? 8 : 3 + i] = (uint8_t) (content[contentOffset + i * contentStride] & 254);
14854 }
14855 
RECOIL_SetBakPF0123(RECOIL * self,uint8_t const * content,int contentOffset)14856 static void RECOIL_SetBakPF0123(RECOIL *self, uint8_t const *content, int contentOffset)
14857 {
14858 	for (int i = 0; i < 5; i++)
14859 		self->gtiaColors[i == 0 ? 8 : 3 + i] = (uint8_t) (content[contentOffset + i] & 254);
14860 }
14861 
RECOIL_SetPF012Bak(RECOIL * self,uint8_t const * content,int contentOffset)14862 static void RECOIL_SetPF012Bak(RECOIL *self, uint8_t const *content, int contentOffset)
14863 {
14864 	for (int i = 0; i < 4; i++)
14865 		self->gtiaColors[i == 3 ? 8 : 4 + i] = (uint8_t) (content[contentOffset + i] & 254);
14866 }
14867 
RECOIL_SetPF0123Bak(RECOIL * self,uint8_t const * content,int contentOffset)14868 static void RECOIL_SetPF0123Bak(RECOIL *self, uint8_t const *content, int contentOffset)
14869 {
14870 	for (int i = 0; i < 5; i++)
14871 		self->gtiaColors[4 + i] = (uint8_t) (content[contentOffset + i] & 254);
14872 }
14873 
RECOIL_SetPF0123Even(RECOIL * self,uint8_t const * content,int contentOffset)14874 static void RECOIL_SetPF0123Even(RECOIL *self, uint8_t const *content, int contentOffset)
14875 {
14876 	for (int i = 0; i < 4; i++)
14877 		self->gtiaColors[4 + i] = (uint8_t) (content[contentOffset + i * 2] & 254);
14878 }
14879 
RECOIL_DecodeAtari8Gr8(const RECOIL * self,uint8_t const * content,int contentOffset,uint8_t * frame,int frameOffset,int height)14880 static void RECOIL_DecodeAtari8Gr8(const RECOIL *self, uint8_t const *content, int contentOffset, uint8_t *frame, int frameOffset, int height)
14881 {
14882 	uint8_t colors[2];
14883 	colors[0] = self->gtiaColors[6];
14884 	colors[1] = (uint8_t) ((self->gtiaColors[6] & 240) | (self->gtiaColors[5] & 14));
14885 	frameOffset -= self->leftSkip;
14886 	for (int y = 0; y < height; y++) {
14887 		int x;
14888 		for (x = self->leftSkip; x < self->width; x++) {
14889 			int c = content[contentOffset + (x >> 3)] >> (~x & 7) & 1;
14890 			frame[frameOffset + x] = colors[c];
14891 		}
14892 		for (; x < self->width + self->leftSkip; x++)
14893 			frame[frameOffset + x] = self->gtiaColors[8];
14894 		contentOffset += (self->width + 7) >> 3;
14895 		frameOffset += self->width;
14896 	}
14897 }
14898 
RECOIL_DecodeAtari8Gr15(const RECOIL * self,uint8_t const * content,int contentOffset,int contentStride,uint8_t * frame,int frameOffset,int frameStride,int height)14899 static void RECOIL_DecodeAtari8Gr15(const RECOIL *self, uint8_t const *content, int contentOffset, int contentStride, uint8_t *frame, int frameOffset, int frameStride, int height)
14900 {
14901 	for (int y = 0; y < height; y++) {
14902 		for (int x = 0; x < self->width; x++) {
14903 			int c = content[contentOffset + (x >> 3)] >> (~x & 6) & 3;
14904 			frame[frameOffset + x] = self->gtiaColors[c == 0 ? 8 : c + 3];
14905 		}
14906 		contentOffset += contentStride;
14907 		frameOffset += frameStride;
14908 	}
14909 }
14910 
RECOIL_DecodeAtari8Gr7(const RECOIL * self,uint8_t const * content,int contentOffset,uint8_t * frame,int frameOffset,int height)14911 static void RECOIL_DecodeAtari8Gr7(const RECOIL *self, uint8_t const *content, int contentOffset, uint8_t *frame, int frameOffset, int height)
14912 {
14913 	for (int y = 0; y < height; y++) {
14914 		for (int x = 0; x < self->width; x++) {
14915 			int c = content[contentOffset + (x >> 3)] >> (~x & 6) & 3;
14916 			frame[frameOffset + x + self->width] = frame[frameOffset + x] = self->gtiaColors[c == 0 ? 8 : c + 3];
14917 		}
14918 		contentOffset += self->width >> 3;
14919 		frameOffset += self->width << 1;
14920 	}
14921 }
14922 
RECOIL_DecodeAtari8Gr3(const RECOIL * self,uint8_t const * content,uint8_t * frame)14923 static void RECOIL_DecodeAtari8Gr3(const RECOIL *self, uint8_t const *content, uint8_t *frame)
14924 {
14925 	for (int y = 0; y < self->height; y++) {
14926 		for (int x = 0; x < self->width; x++) {
14927 			int c = content[(y >> 3) * (self->width >> 5) + (x >> 5)] >> (~(x >> 2) & 6) & 3;
14928 			frame[y * self->width + x] = self->gtiaColors[c == 0 ? 8 : c + 3];
14929 		}
14930 	}
14931 }
14932 
RECOIL_DecodeAtari8Gr9(const RECOIL * self,uint8_t const * content,int contentOffset,int contentStride,uint8_t * frame,int frameOffset,int frameStride,int width,int height)14933 static void RECOIL_DecodeAtari8Gr9(const RECOIL *self, uint8_t const *content, int contentOffset, int contentStride, uint8_t *frame, int frameOffset, int frameStride, int width, int height)
14934 {
14935 	for (int y = 0; y < height; y++) {
14936 		for (int x = 0; x < width; x++) {
14937 			int i = x + self->leftSkip;
14938 			int c = i < 0 || i >= width ? 0 : content[contentOffset + (i >> 3)] >> (~i & 4) & 15;
14939 			frame[frameOffset + x] = (uint8_t) (self->gtiaColors[8] | c);
14940 		}
14941 		contentOffset += contentStride;
14942 		frameOffset += frameStride;
14943 	}
14944 }
14945 
RECOIL_DecodeAtari8Gr11(const RECOIL * self,uint8_t const * content,int contentOffset,uint8_t * frame,int frameOffset,int frameStride,int height)14946 static void RECOIL_DecodeAtari8Gr11(const RECOIL *self, uint8_t const *content, int contentOffset, uint8_t *frame, int frameOffset, int frameStride, int height)
14947 {
14948 	frameOffset -= self->leftSkip;
14949 	for (int y = 0; y < height; y++) {
14950 		int x;
14951 		for (x = self->leftSkip; x < self->width; x++) {
14952 			int c = content[contentOffset + (x >> 3)] << (x & 4) & 240;
14953 			c = c == 0 ? self->gtiaColors[8] & 240 : self->gtiaColors[8] | c;
14954 			frame[frameOffset + x] = (uint8_t) c;
14955 		}
14956 		for (; x < self->width + self->leftSkip; x++)
14957 			frame[frameOffset + x] = (uint8_t) (self->gtiaColors[8] & 240);
14958 		contentOffset += self->width >> 3;
14959 		frameOffset += frameStride;
14960 	}
14961 }
14962 
RECOIL_DecodeAtari8Gr10(const RECOIL * self,uint8_t const * content,int contentOffset,uint8_t * frame,int frameOffset,int frameStride,int height)14963 static void RECOIL_DecodeAtari8Gr10(const RECOIL *self, uint8_t const *content, int contentOffset, uint8_t *frame, int frameOffset, int frameStride, int height)
14964 {
14965 	frameOffset += 2 - self->leftSkip;
14966 	for (int y = 0; y < height; y++) {
14967 		int x;
14968 		for (x = self->leftSkip - 2; x < 0; x++)
14969 			frame[frameOffset + x] = self->gtiaColors[0];
14970 		for (; x < self->width + self->leftSkip - 2; x++) {
14971 			int c = content[contentOffset + (x >> 3)] >> (~x & 4) & 15;
14972 			frame[frameOffset + x] = self->gtiaColors[c];
14973 		}
14974 		contentOffset += self->width >> 3;
14975 		frameOffset += frameStride;
14976 	}
14977 }
14978 
RECOIL_DecodeAtari8Gr11PalBlend(const RECOIL * self,uint8_t const * content,int contentOffset,int contentStride,uint8_t * frame,int y)14979 static void RECOIL_DecodeAtari8Gr11PalBlend(const RECOIL *self, uint8_t const *content, int contentOffset, int contentStride, uint8_t *frame, int y)
14980 {
14981 	for (; y < self->height; y += 2) {
14982 		int frameOffset = y * self->width - self->leftSkip;
14983 		int x;
14984 		for (x = self->leftSkip; x < self->width; x++) {
14985 			int c = content[contentOffset + (x >> 3)] << (x & 4) & 240;
14986 			int i = ((y == 0 ? 0 : frame[frameOffset - self->width + x] & 15) + (y == self->height - 1 ? 0 : frame[frameOffset + self->width + x] & 15)) >> 1;
14987 			frame[frameOffset + x] = (uint8_t) (c | i);
14988 			if (y < self->height - 1)
14989 				frame[frameOffset + self->width + x] = (uint8_t) (c | (frame[frameOffset + self->width + x] & 15));
14990 		}
14991 		for (; x < self->width + self->leftSkip; x++)
14992 			frame[frameOffset + x] = 0;
14993 		contentOffset += contentStride;
14994 	}
14995 }
14996 
RECOIL_ToAtari8Char(int ascii)14997 static int RECOIL_ToAtari8Char(int ascii)
14998 {
14999 	switch (ascii & 96) {
15000 	case 0:
15001 		return ascii + 64;
15002 	case 32:
15003 	case 64:
15004 		return ascii - 32;
15005 	default:
15006 		return ascii;
15007 	}
15008 }
15009 
RECOIL_DecodeAtari8Gr0Line(const RECOIL * self,uint8_t const * characters,int charactersOffset,uint8_t const * font,int fontOffset,uint8_t * frame,int frameOffset,int lines)15010 static void RECOIL_DecodeAtari8Gr0Line(const RECOIL *self, uint8_t const *characters, int charactersOffset, uint8_t const *font, int fontOffset, uint8_t *frame, int frameOffset, int lines)
15011 {
15012 	uint8_t colors[2];
15013 	colors[0] = self->gtiaColors[6];
15014 	colors[1] = (uint8_t) ((self->gtiaColors[6] & 240) | (self->gtiaColors[5] & 14));
15015 	for (int y = 0; y < lines; y++) {
15016 		for (int x = 0; x < self->width; x++) {
15017 			int ch = charactersOffset + (x >> 3);
15018 			if (characters != NULL)
15019 				ch = characters[ch];
15020 			int b = font[fontOffset + ((ch & 127) << 3) + (y & 7)];
15021 			if (lines == 10) {
15022 				switch (((ch & 96) + y) >> 1) {
15023 				case 4:
15024 				case 20:
15025 				case 36:
15026 				case 48:
15027 					b = 0;
15028 					break;
15029 				default:
15030 					break;
15031 				}
15032 			}
15033 			if (ch >= 128)
15034 				b ^= 255;
15035 			frame[frameOffset + x] = colors[b >> (~x & 7) & 1];
15036 		}
15037 		frameOffset += self->width;
15038 	}
15039 }
15040 
RECOIL_DecodeAtari8Gr0(RECOIL * self,uint8_t const * characters,int charactersStride,uint8_t const * font,int fontOffset,uint8_t * frame)15041 static void RECOIL_DecodeAtari8Gr0(RECOIL *self, uint8_t const *characters, int charactersStride, uint8_t const *font, int fontOffset, uint8_t *frame)
15042 {
15043 	self->gtiaColors[6] = 0;
15044 	self->gtiaColors[5] = 14;
15045 	for (int y = 0; y < self->height; y += 8)
15046 		RECOIL_DecodeAtari8Gr0Line(self, characters, (y >> 3) * charactersStride, font, fontOffset, frame, y * self->width, 8);
15047 }
15048 
RECOIL_DecodeAtari8Gr1Line(const RECOIL * self,uint8_t const * content,int charactersOffset,uint8_t const * font,int fontOffset,uint8_t * frame,int frameOffset,int doubleLine)15049 static void RECOIL_DecodeAtari8Gr1Line(const RECOIL *self, uint8_t const *content, int charactersOffset, uint8_t const *font, int fontOffset, uint8_t *frame, int frameOffset, int doubleLine)
15050 {
15051 	for (int y = 0; y < 8 << doubleLine; y++) {
15052 		for (int x = 0; x < self->width; x++) {
15053 			int ch = content[charactersOffset + (x >> 4)];
15054 			int b = font[fontOffset + ((ch & 63) << 3) + (y >> doubleLine)] >> (~(x >> 1) & 7) & 1;
15055 			frame[frameOffset + x] = self->gtiaColors[b == 0 ? 8 : 4 + (ch >> 6)];
15056 		}
15057 		frameOffset += self->width;
15058 	}
15059 }
15060 
RECOIL_DecodeAtari8Gr12Line(const RECOIL * self,uint8_t const * characters,int charactersOffset,uint8_t const * font,int fontOffset,uint8_t * frame,int frameOffset,int doubleLine)15061 static void RECOIL_DecodeAtari8Gr12Line(const RECOIL *self, uint8_t const *characters, int charactersOffset, uint8_t const *font, int fontOffset, uint8_t *frame, int frameOffset, int doubleLine)
15062 {
15063 	for (int y = 0; y < 8 << doubleLine; y++) {
15064 		for (int x = 0; x < self->width; x++) {
15065 			int ch = x >> 3;
15066 			if (characters != NULL)
15067 				ch = characters[charactersOffset + ch];
15068 			int c = font[fontOffset + ((ch & 127) << 3) + (y >> doubleLine)] >> (~x & 6) & 3;
15069 			int gr12Registers = ch >= 128 ? 30024 : 25928;
15070 			frame[frameOffset + x] = self->gtiaColors[gr12Registers >> (c << 2) & 15];
15071 		}
15072 		frameOffset += self->width;
15073 	}
15074 }
15075 
RECOIL_DecodeAtari8Player(const RECOIL * self,uint8_t const * content,int contentOffset,int color,uint8_t * frame,int frameOffset,int height,bool multi)15076 static void RECOIL_DecodeAtari8Player(const RECOIL *self, uint8_t const *content, int contentOffset, int color, uint8_t *frame, int frameOffset, int height, bool multi)
15077 {
15078 	color &= 254;
15079 	for (int y = 0; y < height; y++) {
15080 		int b = content[contentOffset + y];
15081 		for (int x = 0; x < 8; x++) {
15082 			int c = b >> (7 - x) & 1;
15083 			if (c != 0)
15084 				frame[frameOffset + x * 2 + 1] = frame[frameOffset + x * 2] = (uint8_t) (multi ? frame[frameOffset + x * 2] | color : color);
15085 		}
15086 		frameOffset += self->width;
15087 	}
15088 }
15089 
RECOIL_ApplyAtari8Palette(RECOIL * self,uint8_t const * frame)15090 static bool RECOIL_ApplyAtari8Palette(RECOIL *self, uint8_t const *frame)
15091 {
15092 	int pixelsLength = self->width * self->height;
15093 	for (int i = 0; i < pixelsLength; i++)
15094 		self->pixels[i] = self->atari8Palette[frame[i]];
15095 	return true;
15096 }
15097 
RECOIL_ApplyAtari8PaletteBlend(RECOIL * self,uint8_t const * frame1,uint8_t const * frame2)15098 static bool RECOIL_ApplyAtari8PaletteBlend(RECOIL *self, uint8_t const *frame1, uint8_t const *frame2)
15099 {
15100 	int pixelsLength = self->width * self->height;
15101 	self->frames = 2;
15102 	for (int i = 0; i < pixelsLength; i++) {
15103 		int rgb1 = self->atari8Palette[frame1[i]];
15104 		int rgb2 = self->atari8Palette[frame2[i]];
15105 		self->pixels[i] = (rgb1 & rgb2) + ((rgb1 ^ rgb2) >> 1 & 8355711);
15106 	}
15107 	return true;
15108 }
15109 
RECOIL_ApplyAtari8PaletteBlend3(RECOIL * self,uint8_t const * frame1,uint8_t const * frame2,uint8_t const * frame3)15110 static bool RECOIL_ApplyAtari8PaletteBlend3(RECOIL *self, uint8_t const *frame1, uint8_t const *frame2, uint8_t const *frame3)
15111 {
15112 	int pixelsLength = self->width * self->height;
15113 	self->frames = 3;
15114 	for (int i = 0; i < pixelsLength; i++) {
15115 		int rgb1 = self->atari8Palette[frame1[i]];
15116 		int rgb2 = self->atari8Palette[frame2[i]];
15117 		int rgb3 = self->atari8Palette[frame3[i]];
15118 		self->pixels[i] = ((rgb1 >> 16) + (rgb2 >> 16) + (rgb3 >> 16)) / 3 << 16 | ((rgb1 >> 8 & 255) + (rgb2 >> 8 & 255) + (rgb3 >> 8 & 255)) / 3 << 8 | ((rgb1 & 255) + (rgb2 & 255) + (rgb3 & 255)) / 3;
15119 	}
15120 	return true;
15121 }
15122 
RECOIL_DecodeGr8(RECOIL * self,uint8_t const * content,int contentLength)15123 static bool RECOIL_DecodeGr8(RECOIL *self, uint8_t const *content, int contentLength)
15124 {
15125 	if (!RECOIL_SetAtari8RawSize(self, content, contentLength, RECOILResolution_XE1X1))
15126 		return false;
15127 	int contentOffset = RECOIL_GetAtari8ExecutableOffset(content, contentLength);
15128 	if (contentLength == 7682) {
15129 		self->gtiaColors[6] = (uint8_t) (content[7680] & 14);
15130 		self->gtiaColors[5] = (uint8_t) (content[7681] & 14);
15131 	}
15132 	else {
15133 		self->gtiaColors[6] = 0;
15134 		self->gtiaColors[5] = 14;
15135 	}
15136 	uint8_t frame[76800];
15137 	RECOIL_DecodeAtari8Gr8(self, content, contentOffset, frame, 0, self->height);
15138 	return RECOIL_ApplyAtari8Palette(self, frame);
15139 }
15140 
RECOIL_DecodeDrg(RECOIL * self,uint8_t const * content,int contentLength)15141 static bool RECOIL_DecodeDrg(RECOIL *self, uint8_t const *content, int contentLength)
15142 {
15143 	return contentLength == 6400 && RECOIL_DecodeGr8(self, content, contentLength);
15144 }
15145 
RECOIL_DecodeGr8Raw(RECOIL * self,uint8_t const * content,int contentLength,int width,int height)15146 static bool RECOIL_DecodeGr8Raw(RECOIL *self, uint8_t const *content, int contentLength, int width, int height)
15147 {
15148 	RECOIL_SetSize(self, width, height, RECOILResolution_XE1X1);
15149 	self->contentPalette[0] = self->atari8Palette[0];
15150 	self->contentPalette[1] = self->atari8Palette[14];
15151 	return RECOIL_DecodeMono(self, content, 0, contentLength, false);
15152 }
15153 
RECOIL_DecodeGhg(RECOIL * self,uint8_t const * content,int contentLength)15154 static bool RECOIL_DecodeGhg(RECOIL *self, uint8_t const *content, int contentLength)
15155 {
15156 	if (contentLength < 4)
15157 		return false;
15158 	int width = content[0] | content[1] << 8;
15159 	int height = content[2];
15160 	if (width == 0 || width > 320 || height == 0 || height > 200 || contentLength != 3 + ((width + 7) >> 3) * height)
15161 		return false;
15162 	RECOIL_SetSize(self, width, height, RECOILResolution_XE1X1);
15163 	uint8_t frame[64000];
15164 	self->gtiaColors[6] = 12;
15165 	self->gtiaColors[5] = 2;
15166 	RECOIL_DecodeAtari8Gr8(self, content, 3, frame, 0, height);
15167 	return RECOIL_ApplyAtari8Palette(self, frame);
15168 }
15169 
RECOIL_DecodeCpr(RECOIL * self,uint8_t const * content,int contentLength)15170 static bool RECOIL_DecodeCpr(RECOIL *self, uint8_t const *content, int contentLength)
15171 {
15172 	if (contentLength < 2)
15173 		return false;
15174 	uint8_t unpacked[7680];
15175 	if (!XeKoalaStream_UnpackRaw(content[0], content, 1, contentLength, unpacked, 7680))
15176 		return false;
15177 	self->gtiaColors[6] = 12;
15178 	self->gtiaColors[5] = 0;
15179 	RECOIL_SetSize(self, 320, 192, RECOILResolution_XE1X1);
15180 	uint8_t frame[61440];
15181 	RECOIL_DecodeAtari8Gr8(self, unpacked, 0, frame, 0, 192);
15182 	return RECOIL_ApplyAtari8Palette(self, frame);
15183 }
15184 
RECOIL_DecodeSg3(RECOIL * self,uint8_t const * content,int contentLength)15185 static bool RECOIL_DecodeSg3(RECOIL *self, uint8_t const *content, int contentLength)
15186 {
15187 	if (contentLength != 240)
15188 		return false;
15189 	RECOIL_SetSize(self, 320, 192, RECOILResolution_XE8X8);
15190 	uint8_t frame[61440];
15191 	RECOIL_SetXeOsDefaultColors(self);
15192 	RECOIL_DecodeAtari8Gr3(self, content, frame);
15193 	return RECOIL_ApplyAtari8Palette(self, frame);
15194 }
15195 
RECOIL_DecodeGr3(RECOIL * self,uint8_t const * content,int contentLength)15196 static bool RECOIL_DecodeGr3(RECOIL *self, uint8_t const *content, int contentLength)
15197 {
15198 	if (contentLength != 244)
15199 		return false;
15200 	RECOIL_SetSize(self, 320, 192, RECOILResolution_XE8X8);
15201 	uint8_t frame[61440];
15202 	RECOIL_SetBakPF012(self, content, 240, 1);
15203 	RECOIL_DecodeAtari8Gr3(self, content, frame);
15204 	return RECOIL_ApplyAtari8Palette(self, frame);
15205 }
15206 
RECOIL_DecodeDit(RECOIL * self,uint8_t const * content,int contentLength)15207 static bool RECOIL_DecodeDit(RECOIL *self, uint8_t const *content, int contentLength)
15208 {
15209 	if (contentLength != 3845)
15210 		return false;
15211 	RECOIL_SetSize(self, 320, 192, RECOILResolution_XE2X2);
15212 	uint8_t frame[61440];
15213 	RECOIL_SetPF0123Bak(self, content, 3840);
15214 	RECOIL_DecodeAtari8Gr7(self, content, 0, frame, 0, 96);
15215 	return RECOIL_ApplyAtari8Palette(self, frame);
15216 }
15217 
RECOIL_DecodeGr7(RECOIL * self,uint8_t const * content,int contentOffset,int contentSize)15218 static bool RECOIL_DecodeGr7(RECOIL *self, uint8_t const *content, int contentOffset, int contentSize)
15219 {
15220 	if (contentSize > 4804 || contentSize % 40 != 4)
15221 		return false;
15222 	int height = contentSize / 40;
15223 	RECOIL_SetSize(self, 320, height * 2, RECOILResolution_XE2X2);
15224 	uint8_t frame[76800];
15225 	RECOIL_SetBakPF012(self, content, contentOffset + contentSize - 4, 1);
15226 	RECOIL_DecodeAtari8Gr7(self, content, contentOffset, frame, 0, height);
15227 	return RECOIL_ApplyAtari8Palette(self, frame);
15228 }
15229 
RECOIL_DecodeRys(RECOIL * self,uint8_t const * content,int contentLength)15230 static bool RECOIL_DecodeRys(RECOIL *self, uint8_t const *content, int contentLength)
15231 {
15232 	if (contentLength != 3840)
15233 		return false;
15234 	RECOIL_SetSize(self, 320, 192, RECOILResolution_XE2X2);
15235 	uint8_t frame[61440];
15236 	RECOIL_SetXeOsDefaultColors(self);
15237 	RECOIL_DecodeAtari8Gr7(self, content, 0, frame, 0, 96);
15238 	return RECOIL_ApplyAtari8Palette(self, frame);
15239 }
15240 
RECOIL_DecodeBkg(RECOIL * self,uint8_t const * content,int contentLength)15241 static bool RECOIL_DecodeBkg(RECOIL *self, uint8_t const *content, int contentLength)
15242 {
15243 	return contentLength == 3856 && RECOIL_DecodeGr7(self, content, 0, 3844);
15244 }
15245 
RECOIL_DecodeAtari8Artist(RECOIL * self,uint8_t const * content,int contentLength)15246 static bool RECOIL_DecodeAtari8Artist(RECOIL *self, uint8_t const *content, int contentLength)
15247 {
15248 	if (contentLength != 3206 || content[0] != 7)
15249 		return false;
15250 	RECOIL_SetSize(self, 320, 160, RECOILResolution_XE2X2);
15251 	uint8_t frame[51200];
15252 	RECOIL_SetPF0123Bak(self, content, 1);
15253 	RECOIL_DecodeAtari8Gr7(self, content, 6, frame, 0, 80);
15254 	return RECOIL_ApplyAtari8Palette(self, frame);
15255 }
15256 
RECOIL_DecodeGr9(RECOIL * self,uint8_t const * content,int contentLength)15257 static bool RECOIL_DecodeGr9(RECOIL *self, uint8_t const *content, int contentLength)
15258 {
15259 	if (!RECOIL_SetAtari8RawSize(self, content, contentLength, RECOILResolution_XE4X1))
15260 		return false;
15261 	self->gtiaColors[8] = 0;
15262 	int contentOffset = RECOIL_GetAtari8ExecutableOffset(content, contentLength);
15263 	uint8_t frame[76800];
15264 	RECOIL_DecodeAtari8Gr9(self, content, contentOffset, 40, frame, 0, 320, 320, self->height);
15265 	return RECOIL_ApplyAtari8Palette(self, frame);
15266 }
15267 
RECOIL_DecodeRap(RECOIL * self,uint8_t const * content,int contentLength)15268 static bool RECOIL_DecodeRap(RECOIL *self, uint8_t const *content, int contentLength)
15269 {
15270 	if (contentLength != 7681)
15271 		return false;
15272 	self->gtiaColors[8] = (uint8_t) (content[7680] & 254);
15273 	RECOIL_SetSize(self, 320, 192, RECOILResolution_XE4X1);
15274 	uint8_t frame[61440];
15275 	RECOIL_DecodeAtari8Gr9(self, content, 0, 40, frame, 0, 320, 320, 192);
15276 	return RECOIL_ApplyAtari8Palette(self, frame);
15277 }
15278 
RECOIL_DecodeTxe(RECOIL * self,uint8_t const * content,int contentLength)15279 static bool RECOIL_DecodeTxe(RECOIL *self, uint8_t const *content, int contentLength)
15280 {
15281 	if (contentLength != 3840)
15282 		return false;
15283 	RECOIL_SetSize(self, 320, 192, RECOILResolution_XE4X2);
15284 	uint8_t frame[61440];
15285 	self->gtiaColors[8] = 0;
15286 	RECOIL_DecodeAtari8Gr9(self, content, 0, 40, frame, 320, 640, 320, 96);
15287 	RECOIL_DecodeAtari8Gr9(self, content, 0, 40, frame, 0, 640, 320, 96);
15288 	return RECOIL_ApplyAtari8Palette(self, frame);
15289 }
15290 
RECOIL_DecodeGr9x4(RECOIL * self,uint8_t const * content,int contentOffset,int width,int height)15291 static bool RECOIL_DecodeGr9x4(RECOIL *self, uint8_t const *content, int contentOffset, int width, int height)
15292 {
15293 	if (!RECOIL_SetSize(self, width, height, RECOILResolution_XE4X4))
15294 		return false;
15295 	uint8_t *frame = (uint8_t *) CiShared_Make(width * height, sizeof(uint8_t), NULL, NULL);
15296 	self->gtiaColors[8] = 0;
15297 	for (int y = 0; y < 4; y++)
15298 		RECOIL_DecodeAtari8Gr9(self, content, contentOffset, width >> 3, frame, y * width, width << 2, width, height >> 2);
15299 	RECOIL_ApplyAtari8Palette(self, frame);
15300 	CiShared_Release(frame);
15301 	return true;
15302 }
15303 
RECOIL_DecodeGr9p(RECOIL * self,uint8_t const * content,int contentLength)15304 static bool RECOIL_DecodeGr9p(RECOIL *self, uint8_t const *content, int contentLength)
15305 {
15306 	return contentLength == 2400 && RECOIL_DecodeGr9x4(self, content, 0, 320, 240);
15307 }
15308 
RECOIL_DecodeFge(RECOIL * self,uint8_t const * content,int contentLength)15309 static bool RECOIL_DecodeFge(RECOIL *self, uint8_t const *content, int contentLength)
15310 {
15311 	return contentLength == 1286 && RECOIL_DecodeGr9x4(self, content, 6, 256, 160);
15312 }
15313 
RECOIL_Decode16x16x16(RECOIL * self,uint8_t const * content,int contentOffset,int colbak)15314 static bool RECOIL_Decode16x16x16(RECOIL *self, uint8_t const *content, int contentOffset, int colbak)
15315 {
15316 	RECOIL_SetSize(self, 64, 64, RECOILResolution_XE4X4);
15317 	for (int y = 0; y < 64; y++) {
15318 		for (int x = 0; x < 64; x++) {
15319 			int c = content[contentOffset + ((y & -4) << 2) + (x >> 2)];
15320 			if (c > 15)
15321 				return false;
15322 			self->pixels[(y << 6) + x] = self->atari8Palette[colbak | c];
15323 		}
15324 	}
15325 	return true;
15326 }
15327 
RECOIL_DecodeTx0(RECOIL * self,uint8_t const * content,int contentLength)15328 static bool RECOIL_DecodeTx0(RECOIL *self, uint8_t const *content, int contentLength)
15329 {
15330 	return contentLength == 257 && RECOIL_Decode16x16x16(self, content, 0, content[256] & 254);
15331 }
15332 
RECOIL_DecodeTxs(RECOIL * self,uint8_t const * content,int contentLength)15333 static bool RECOIL_DecodeTxs(RECOIL *self, uint8_t const *content, int contentLength)
15334 {
15335 	return contentLength == 262 && content[0] == 255 && content[1] == 255 && content[2] == 0 && content[3] == 6 && content[4] == 255 && content[5] == 6 && RECOIL_Decode16x16x16(self, content, 6, 0);
15336 }
15337 
RECOIL_DecodeA4r(RECOIL * self,uint8_t const * content,int contentLength)15338 static bool RECOIL_DecodeA4r(RECOIL *self, uint8_t const *content, int contentLength)
15339 {
15340 	A4rStream a4r;
15341 	A4rStream_Construct(&a4r);
15342 	a4r.base.content = content;
15343 	a4r.base.contentOffset = 0;
15344 	a4r.base.contentLength = contentLength;
15345 	if (!A4rStream_UnpackA4r(&a4r))
15346 		return false;
15347 	RECOIL_SetSize(self, 320, 256, RECOILResolution_XE4X1);
15348 	uint8_t frame[81920];
15349 	self->gtiaColors[8] = 0;
15350 	RECOIL_DecodeAtari8Gr9(self, a4r.unpacked, 512, 40, frame, 0, 320, 320, 256);
15351 	return RECOIL_ApplyAtari8Palette(self, frame);
15352 }
15353 
RECOIL_DecodeG11(RECOIL * self,uint8_t const * content,int contentLength)15354 static bool RECOIL_DecodeG11(RECOIL *self, uint8_t const *content, int contentLength)
15355 {
15356 	if (!RECOIL_SetAtari8RawSize(self, content, contentLength, RECOILResolution_XE4X1))
15357 		return false;
15358 	self->gtiaColors[8] = 6;
15359 	int contentOffset = RECOIL_GetAtari8ExecutableOffset(content, contentLength);
15360 	uint8_t frame[76800];
15361 	RECOIL_DecodeAtari8Gr11(self, content, contentOffset, frame, 0, 320, self->height);
15362 	return RECOIL_ApplyAtari8Palette(self, frame);
15363 }
15364 
RECOIL_DecodeG10(RECOIL * self,uint8_t const * content,int contentLength)15365 static bool RECOIL_DecodeG10(RECOIL *self, uint8_t const *content, int contentLength)
15366 {
15367 	if (!RECOIL_SetAtari8RawSize(self, content, contentLength, RECOILResolution_XE4X1))
15368 		return false;
15369 	int contentOffset = RECOIL_GetAtari8ExecutableOffset(content, contentLength);
15370 	if ((contentLength - contentOffset) % 40 != 9)
15371 		return false;
15372 	self->leftSkip = 2;
15373 	RECOIL_SetGtiaColors(self, content, contentLength - 9);
15374 	uint8_t frame[76800];
15375 	RECOIL_DecodeAtari8Gr10(self, content, contentOffset, frame, 0, 320, self->height);
15376 	return RECOIL_ApplyAtari8Palette(self, frame);
15377 }
15378 
RECOIL_DecodeG09(RECOIL * self,uint8_t const * content,int contentLength)15379 static bool RECOIL_DecodeG09(RECOIL *self, uint8_t const *content, int contentLength)
15380 {
15381 	switch (contentLength) {
15382 	case 7680:
15383 		return RECOIL_DecodeGr9(self, content, contentLength);
15384 	case 15360:
15385 		break;
15386 	default:
15387 		return false;
15388 	}
15389 	RECOIL_SetSize(self, 640, 192, RECOILResolution_XE4X1);
15390 	self->gtiaColors[8] = 0;
15391 	uint8_t frame[122880];
15392 	RECOIL_DecodeAtari8Gr9(self, content, 0, 40, frame, 0, 640, 320, 192);
15393 	RECOIL_DecodeAtari8Gr9(self, content, 7680, 40, frame, 320, 640, 320, 192);
15394 	return RECOIL_ApplyAtari8Palette(self, frame);
15395 }
15396 
RECOIL_DecodeSkp(RECOIL * self,uint8_t const * content,int contentLength)15397 static bool RECOIL_DecodeSkp(RECOIL *self, uint8_t const *content, int contentLength)
15398 {
15399 	if (contentLength != 7680)
15400 		return false;
15401 	self->gtiaColors[8] = 38;
15402 	self->gtiaColors[4] = 40;
15403 	self->gtiaColors[5] = 0;
15404 	self->gtiaColors[6] = 12;
15405 	RECOIL_SetSize(self, 320, 192, RECOILResolution_XE2X1);
15406 	uint8_t frame[61440];
15407 	RECOIL_DecodeAtari8Gr15(self, content, 0, 40, frame, 0, 320, 192);
15408 	return RECOIL_ApplyAtari8Palette(self, frame);
15409 }
15410 
RECOIL_DecodeKss(RECOIL * self,uint8_t const * content,int contentLength)15411 static bool RECOIL_DecodeKss(RECOIL *self, uint8_t const *content, int contentLength)
15412 {
15413 	if (contentLength != 6404)
15414 		return false;
15415 	RECOIL_SetSize(self, 320, 160, RECOILResolution_XE2X1);
15416 	uint8_t frame[51200];
15417 	RECOIL_SetBakPF012(self, content, 6400, 1);
15418 	RECOIL_DecodeAtari8Gr15(self, content, 0, 40, frame, 0, 320, 160);
15419 	return RECOIL_ApplyAtari8Palette(self, frame);
15420 }
15421 
RECOIL_DecodeMic(RECOIL * self,const char * filename,uint8_t const * content,int contentLength)15422 static bool RECOIL_DecodeMic(RECOIL *self, const char *filename, uint8_t const *content, int contentLength)
15423 {
15424 	if (contentLength == 15872) {
15425 		contentLength = 7680;
15426 		RECOIL_SetPF012Bak(self, content, 7680);
15427 	}
15428 	else {
15429 		switch (contentLength % 40) {
15430 		case 0:
15431 		case 3:
15432 			RECOIL_SetGr15DefaultColors(self);
15433 			break;
15434 		case 4:
15435 			RECOIL_SetBakPF012(self, content, contentLength - 4, 1);
15436 			break;
15437 		case 5:
15438 			RECOIL_SetPF012Bak(self, content, contentLength - 5);
15439 			break;
15440 		default:
15441 			return false;
15442 		}
15443 	}
15444 	int height = contentLength / 40;
15445 	if (height == 0 || height > 240)
15446 		return false;
15447 	RECOIL_SetSize(self, 320, height, RECOILResolution_XE2X1);
15448 	uint8_t frame[76800];
15449 	if (height == 240) {
15450 		uint8_t col[1281];
15451 		switch (RECOIL_ReadCompanionFile(self, filename, "COL", "col", col, 1281)) {
15452 		case 1024:
15453 		case 1280:
15454 			for (int y = 0; y < 240; y++) {
15455 				RECOIL_SetBakPF012(self, col, y, 256);
15456 				RECOIL_DecodeAtari8Gr15(self, content, y * 40, 40, frame, y * 320, 320, 1);
15457 			}
15458 			return RECOIL_ApplyAtari8Palette(self, frame);
15459 		default:
15460 			break;
15461 		}
15462 	}
15463 	RECOIL_DecodeAtari8Gr15(self, content, 0, 40, frame, 0, 320, height);
15464 	return RECOIL_ApplyAtari8Palette(self, frame);
15465 }
15466 
RECOIL_DecodeHpm(RECOIL * self,uint8_t const * content,int contentLength)15467 static bool RECOIL_DecodeHpm(RECOIL *self, uint8_t const *content, int contentLength)
15468 {
15469 	uint8_t unpacked[7684];
15470 	HpmStream rle;
15471 	HpmStream_Construct(&rle);
15472 	rle.base.base.base.content = content;
15473 	rle.base.base.base.contentOffset = 0;
15474 	rle.base.base.base.contentLength = contentLength;
15475 	if (!RleStream_Unpack(&rle.base, unpacked, 0, 1, 7680))
15476 		return false;
15477 	switch (Stream_ReadByte(&rle.base.base.base)) {
15478 	case 52:
15479 	case 53:
15480 		unpacked[7680] = 0;
15481 		unpacked[7681] = 52;
15482 		unpacked[7682] = (uint8_t) (contentLength == 3494 ? 56 : 200);
15483 		unpacked[7683] = (uint8_t) (contentLength == 3494 ? 60 : 124);
15484 		break;
15485 	case 81:
15486 		unpacked[7680] = 164;
15487 		unpacked[7681] = 81;
15488 		unpacked[7682] = 185;
15489 		unpacked[7683] = 124;
15490 		break;
15491 	case 228:
15492 		unpacked[7680] = 0;
15493 		unpacked[7681] = 228;
15494 		unpacked[7682] = 200;
15495 		unpacked[7683] = 190;
15496 		break;
15497 	case 4:
15498 		unpacked[7680] = 6;
15499 		unpacked[7681] = 4;
15500 		unpacked[7682] = 0;
15501 		unpacked[7683] = 10;
15502 		break;
15503 	case 48:
15504 		unpacked[7680] = 14;
15505 		unpacked[7681] = 48;
15506 		unpacked[7682] = 199;
15507 		unpacked[7683] = 123;
15508 		break;
15509 	case 116:
15510 		unpacked[7680] = 0;
15511 		unpacked[7681] = 116;
15512 		unpacked[7682] = 88;
15513 		unpacked[7683] = 126;
15514 		break;
15515 	default:
15516 		unpacked[7680] = 0;
15517 		unpacked[7681] = 4;
15518 		unpacked[7682] = 8;
15519 		unpacked[7683] = 12;
15520 		break;
15521 	}
15522 	return RECOIL_DecodeMic(self, NULL, unpacked, 7684);
15523 }
15524 
RECOIL_DecodeCpi(RECOIL * self,uint8_t const * content,int contentLength)15525 static bool RECOIL_DecodeCpi(RECOIL *self, uint8_t const *content, int contentLength)
15526 {
15527 	uint8_t unpacked[7936];
15528 	CpiStream rle;
15529 	CpiStream_Construct(&rle);
15530 	rle.base.base.base.content = content;
15531 	rle.base.base.base.contentOffset = 0;
15532 	rle.base.base.base.contentLength = contentLength;
15533 	if (!RleStream_Unpack(&rle.base, unpacked, 0, 1, 7936))
15534 		return false;
15535 	RECOIL_SetSize(self, 320, 192, RECOILResolution_XE2X1);
15536 	uint8_t frame[61440];
15537 	self->gtiaColors[8] = 0;
15538 	self->gtiaColors[4] = 12;
15539 	self->gtiaColors[5] = 8;
15540 	self->gtiaColors[6] = 4;
15541 	RECOIL_DecodeAtari8Gr15(self, unpacked, 0, 40, frame, 0, 320, 192);
15542 	return RECOIL_ApplyAtari8Palette(self, frame);
15543 }
15544 
RECOIL_DecodeWnd(RECOIL * self,uint8_t const * content,int contentLength)15545 static bool RECOIL_DecodeWnd(RECOIL *self, uint8_t const *content, int contentLength)
15546 {
15547 	if (contentLength != 3072)
15548 		return false;
15549 	int width = content[0] + 1;
15550 	int contentStride = (width + 3) >> 2;
15551 	int height = content[1];
15552 	if (contentStride > 40 || height == 0 || height > 192 || contentStride * height > 3070)
15553 		return false;
15554 	RECOIL_SetSize(self, width << 1, height, RECOILResolution_XE2X1);
15555 	uint8_t frame[61440];
15556 	self->gtiaColors[8] = 0;
15557 	self->gtiaColors[4] = 70;
15558 	self->gtiaColors[5] = 136;
15559 	self->gtiaColors[6] = 14;
15560 	RECOIL_DecodeAtari8Gr15(self, content, 2, contentStride, frame, 0, width << 1, height);
15561 	return RECOIL_ApplyAtari8Palette(self, frame);
15562 }
15563 
RECOIL_DecodeAt800Players(const RECOIL * self,uint8_t const * content,uint8_t * frame)15564 static void RECOIL_DecodeAt800Players(const RECOIL *self, uint8_t const *content, uint8_t *frame)
15565 {
15566 	for (int i = 0; i < 4; i++)
15567 		RECOIL_DecodeAtari8Player(self, content, 4 + i * 240, content[i], frame, i * 10 * 2, 240, false);
15568 }
15569 
RECOIL_DecodeAt800Missiles(const RECOIL * self,uint8_t const * content,int contentOffset,uint8_t * frame,int frameOffset)15570 static void RECOIL_DecodeAt800Missiles(const RECOIL *self, uint8_t const *content, int contentOffset, uint8_t *frame, int frameOffset)
15571 {
15572 	for (int y = 0; y < 240; y++) {
15573 		for (int i = 0; i < 4; i++) {
15574 			int b = content[contentOffset + y] >> (i << 1);
15575 			int offset = frameOffset + i * 4 * 2;
15576 			frame[offset + 1] = frame[offset] = (uint8_t) ((b & 2) == 0 ? 0 : content[i]);
15577 			frame[offset + 3] = frame[offset + 2] = (uint8_t) ((b & 1) == 0 ? 0 : content[i]);
15578 		}
15579 		frameOffset += self->width;
15580 	}
15581 }
15582 
RECOIL_DecodePla(RECOIL * self,uint8_t const * content,int contentLength)15583 static bool RECOIL_DecodePla(RECOIL *self, uint8_t const *content, int contentLength)
15584 {
15585 	if (contentLength != 241)
15586 		return false;
15587 	RECOIL_SetSize(self, 16, 240, RECOILResolution_XE2X1);
15588 	uint8_t frame[3840] = { 0 };
15589 	RECOIL_DecodeAtari8Player(self, content, 1, content[0], frame, 0, 240, false);
15590 	return RECOIL_ApplyAtari8Palette(self, frame);
15591 }
15592 
RECOIL_DecodeMis(RECOIL * self,uint8_t const * content,int contentLength)15593 static bool RECOIL_DecodeMis(RECOIL *self, uint8_t const *content, int contentLength)
15594 {
15595 	if (contentLength != 61 && contentLength != 241)
15596 		return false;
15597 	RECOIL_SetSize(self, 4, 240, RECOILResolution_XE2X1);
15598 	uint8_t frame[960];
15599 	for (int y = 0; y < 240; y++) {
15600 		int b = content[1 + (y >> 2)] >> ((~y & 3) << 1);
15601 		frame[y * 4 + 1] = frame[y * 4] = (uint8_t) ((b & 2) == 0 ? 0 : content[0]);
15602 		frame[y * 4 + 3] = frame[y * 4 + 2] = (uint8_t) ((b & 1) == 0 ? 0 : content[0]);
15603 	}
15604 	return RECOIL_ApplyAtari8Palette(self, frame);
15605 }
15606 
RECOIL_Decode4pl(RECOIL * self,uint8_t const * content,int contentLength)15607 static bool RECOIL_Decode4pl(RECOIL *self, uint8_t const *content, int contentLength)
15608 {
15609 	if (contentLength != 964)
15610 		return false;
15611 	RECOIL_SetSize(self, 80, 240, RECOILResolution_XE2X1);
15612 	uint8_t frame[19200] = { 0 };
15613 	RECOIL_DecodeAt800Players(self, content, frame);
15614 	return RECOIL_ApplyAtari8Palette(self, frame);
15615 }
15616 
RECOIL_Decode4mi(RECOIL * self,uint8_t const * content,int contentLength)15617 static bool RECOIL_Decode4mi(RECOIL *self, uint8_t const *content, int contentLength)
15618 {
15619 	if (contentLength != 244)
15620 		return false;
15621 	RECOIL_SetSize(self, 32, 240, RECOILResolution_XE2X1);
15622 	uint8_t frame[7680] = { 0 };
15623 	RECOIL_DecodeAt800Missiles(self, content, 4, frame, 0);
15624 	return RECOIL_ApplyAtari8Palette(self, frame);
15625 }
15626 
RECOIL_Decode4pm(RECOIL * self,uint8_t const * content,int contentLength)15627 static bool RECOIL_Decode4pm(RECOIL *self, uint8_t const *content, int contentLength)
15628 {
15629 	if (contentLength != 1204)
15630 		return false;
15631 	RECOIL_SetSize(self, 112, 240, RECOILResolution_XE2X1);
15632 	uint8_t frame[26880] = { 0 };
15633 	RECOIL_DecodeAt800Players(self, content, frame);
15634 	RECOIL_DecodeAt800Missiles(self, content, 964, frame, 80);
15635 	return RECOIL_ApplyAtari8Palette(self, frame);
15636 }
15637 
RECOIL_DecodeAtari8Spr(RECOIL * self,uint8_t const * content,int contentLength)15638 static bool RECOIL_DecodeAtari8Spr(RECOIL *self, uint8_t const *content, int contentLength)
15639 {
15640 	if (contentLength < 3 || contentLength > 42)
15641 		return false;
15642 	int height = content[0];
15643 	if (2 + height != contentLength)
15644 		return false;
15645 	RECOIL_SetSize(self, 16, height, RECOILResolution_XE2X1);
15646 	uint8_t frame[640] = { 0 };
15647 	RECOIL_DecodeAtari8Player(self, content, 2, content[1], frame, 0, height, false);
15648 	return RECOIL_ApplyAtari8Palette(self, frame);
15649 }
15650 
RECOIL_DecodeMsl(RECOIL * self,uint8_t const * content,int contentLength)15651 static bool RECOIL_DecodeMsl(RECOIL *self, uint8_t const *content, int contentLength)
15652 {
15653 	if (contentLength < 3 || contentLength > 36)
15654 		return false;
15655 	int height = content[0];
15656 	if (2 + height != contentLength)
15657 		return false;
15658 	RECOIL_SetSize(self, 4, height, RECOILResolution_XE2X1);
15659 	uint8_t frame[136];
15660 	for (int y = 0; y < height; y++) {
15661 		int b = content[2 + y];
15662 		if (b > 3)
15663 			return false;
15664 		frame[y * 4 + 1] = frame[y * 4] = (uint8_t) ((b & 2) == 0 ? 0 : content[1]);
15665 		frame[y * 4 + 3] = frame[y * 4 + 2] = (uint8_t) ((b & 1) == 0 ? 0 : content[1]);
15666 	}
15667 	return RECOIL_ApplyAtari8Palette(self, frame);
15668 }
15669 
RECOIL_DecodeMpl(RECOIL * self,uint8_t const * content,int contentLength)15670 static bool RECOIL_DecodeMpl(RECOIL *self, uint8_t const *content, int contentLength)
15671 {
15672 	if (contentLength < 13 || contentLength > 169)
15673 		return false;
15674 	int height = content[0];
15675 	if (9 + (height << 2) != contentLength)
15676 		return false;
15677 	int minX = 255;
15678 	int maxX = 0;
15679 	for (int i = 1; i < 5; i++) {
15680 		int x = content[i];
15681 		if (minX > x)
15682 			minX = x;
15683 		if (maxX < x)
15684 			maxX = x;
15685 	}
15686 	if (maxX + 8 > 56)
15687 		return false;
15688 	RECOIL_SetSize(self, (maxX + 8 - minX) << 1, height, RECOILResolution_XE2X1);
15689 	uint8_t frame[4480] = { 0 };
15690 	for (int i = 3; i >= 0; i--)
15691 		RECOIL_DecodeAtari8Player(self, content, 9 + i * height, content[5 + i], frame, (content[1 + i] - minX) << 1, height, false);
15692 	return RECOIL_ApplyAtari8Palette(self, frame);
15693 }
15694 
RECOIL_DecodeLdm(RECOIL * self,uint8_t const * content,int contentLength)15695 static bool RECOIL_DecodeLdm(RECOIL *self, uint8_t const *content, int contentLength)
15696 {
15697 	if (contentLength < 281)
15698 		return false;
15699 	for (int i = 0; i < 21; i++)
15700 		if (content[i] != "Ludek Maker data file"[i] + 128)
15701 			return false;
15702 	int shapes = content[24] - content[23];
15703 	if (shapes <= 0 || shapes > 100 || contentLength < 281 + shapes * 120)
15704 		return false;
15705 	int rows = (shapes + 7) >> 3;
15706 	if (rows == 1)
15707 		RECOIL_SetSize(self, shapes * 40, 30, RECOILResolution_XE2X1);
15708 	else
15709 		RECOIL_SetSize(self, 320, rows * 32 - 2, RECOILResolution_XE2X1);
15710 	uint8_t frame[132480] = { 0 };
15711 	for (int shape = 0; shape < shapes; shape++) {
15712 		int contentOffset = 281 + shape * 120;
15713 		int frameOffset = (shape >> 3) * 32 * 320 + (shape & 7) * 40;
15714 		RECOIL_DecodeAtari8Player(self, content, contentOffset, content[21], frame, frameOffset, 30, true);
15715 		RECOIL_DecodeAtari8Player(self, content, contentOffset + 30, content[22], frame, frameOffset, 30, true);
15716 		RECOIL_DecodeAtari8Player(self, content, contentOffset + 60, content[21], frame, frameOffset + 16, 30, true);
15717 		RECOIL_DecodeAtari8Player(self, content, contentOffset + 90, content[22], frame, frameOffset + 16, 30, true);
15718 	}
15719 	return RECOIL_ApplyAtari8Palette(self, frame);
15720 }
15721 
RECOIL_DecodePmd(RECOIL * self,uint8_t const * content,int contentLength)15722 static bool RECOIL_DecodePmd(RECOIL *self, uint8_t const *content, int contentLength)
15723 {
15724 	if (contentLength < 12 || content[0] != 240 || content[1] != 237 || content[2] != 228)
15725 		return false;
15726 	int sprites = content[7];
15727 	int shapes = content[8] * content[9];
15728 	int totalShapes = sprites * shapes;
15729 	int height = content[10];
15730 	if (sprites == 0 || sprites > 4 || shapes == 0 || shapes > 160 || height == 0 || height > 48 || 11 + totalShapes * height != contentLength)
15731 		return false;
15732 	if (true)
15733 		totalShapes >>= 1;
15734 	int rows = (totalShapes + 15) >> 4;
15735 	if (rows == 1)
15736 		RECOIL_SetSize(self, totalShapes * 20, height, RECOILResolution_XE2X1);
15737 	else {
15738 		int totalHeight = rows * (height + 2) - 2;
15739 		if (totalHeight > 560)
15740 			return false;
15741 		RECOIL_SetSize(self, 320, totalHeight, RECOILResolution_XE2X1);
15742 	}
15743 	uint8_t frame[179200] = { 0 };
15744 	for (int shape = 0; shape < totalShapes; shape++) {
15745 		int frameOffset = (shape >> 4) * (height + 2) * 320 + (shape & 15) * 20;
15746 		if (true) {
15747 			int spritePair = shape / shapes;
15748 			int contentOffset = 11 + (spritePair * shapes + shape) * height;
15749 			RECOIL_DecodeAtari8Player(self, content, contentOffset, content[3 + spritePair * 2], frame, frameOffset, height, true);
15750 			RECOIL_DecodeAtari8Player(self, content, contentOffset + shapes * height, content[4 + spritePair * 2], frame, frameOffset, height, true);
15751 		}
15752 		else
15753 			RECOIL_DecodeAtari8Player(self, content, 11 + shape * height, content[3 + shape / shapes], frame, frameOffset, height, false);
15754 	}
15755 	return RECOIL_ApplyAtari8Palette(self, frame);
15756 }
15757 
RECOIL_DecodeApl(RECOIL * self,uint8_t const * content,int contentLength)15758 static bool RECOIL_DecodeApl(RECOIL *self, uint8_t const *content, int contentLength)
15759 {
15760 	if (contentLength != 1677 || content[0] != 154 || content[1] != 248 || content[2] != 57 || content[3] != 33)
15761 		return false;
15762 	int frames = content[4];
15763 	int height = content[5];
15764 	int gap = content[6];
15765 	if (frames == 0 || frames > 16 || height == 0 || height > 48 || gap > 8)
15766 		return false;
15767 	int frameWidth = (8 + gap + 2) << 1;
15768 	RECOIL_SetSize(self, frames * frameWidth, height, RECOILResolution_XE2X1);
15769 	uint8_t frame[27648] = { 0 };
15770 	for (int f = 0; f < frames; f++) {
15771 		RECOIL_DecodeAtari8Player(self, content, 42 + f * 48, content[7 + f], frame, f * frameWidth, height, true);
15772 		RECOIL_DecodeAtari8Player(self, content, 858 + f * 48, content[24 + f], frame, f * frameWidth + gap * 2, height, true);
15773 	}
15774 	return RECOIL_ApplyAtari8Palette(self, frame);
15775 }
15776 
RECOIL_DecodeAtari8Hr(RECOIL * self,uint8_t const * content,int contentLength)15777 static bool RECOIL_DecodeAtari8Hr(RECOIL *self, uint8_t const *content, int contentLength)
15778 {
15779 	if (contentLength != 16384)
15780 		return false;
15781 	RECOIL_SetSize(self, 256, 239, RECOILResolution_XE1X1);
15782 	self->gtiaColors[6] = 0;
15783 	self->gtiaColors[5] = 14;
15784 	uint8_t frame1[61184];
15785 	RECOIL_DecodeAtari8Gr8(self, content, 0, frame1, 0, 239);
15786 	uint8_t frame2[61184];
15787 	RECOIL_DecodeAtari8Gr8(self, content, 8192, frame2, 0, 239);
15788 	return RECOIL_ApplyAtari8PaletteBlend(self, frame1, frame2);
15789 }
15790 
RECOIL_DecodeMcppVariable(RECOIL * self,uint8_t const * content,int bitmapOffset,int colorsOffset,int width,int height)15791 static bool RECOIL_DecodeMcppVariable(RECOIL *self, uint8_t const *content, int bitmapOffset, int colorsOffset, int width, int height)
15792 {
15793 	if (!RECOIL_SetSize(self, width, height, RECOILResolution_XE2X2))
15794 		return false;
15795 	uint8_t *frame = (uint8_t *) CiShared_Make(width * height, sizeof(uint8_t), NULL, NULL);
15796 	RECOIL_SetPF012Bak(self, content, colorsOffset);
15797 	RECOIL_DecodeAtari8Gr15(self, content, bitmapOffset, width >> 3, frame, 0, width << 1, height >> 1);
15798 	RECOIL_SetPF012Bak(self, content, colorsOffset + 4);
15799 	RECOIL_DecodeAtari8Gr15(self, content, bitmapOffset + (width * height >> 4), width >> 3, frame, width, width << 1, height >> 1);
15800 	RECOIL_ApplyAtari8Palette(self, frame);
15801 	CiShared_Release(frame);
15802 	return true;
15803 }
15804 
RECOIL_DecodeMcpp(RECOIL * self,uint8_t const * content,int contentLength)15805 static bool RECOIL_DecodeMcpp(RECOIL *self, uint8_t const *content, int contentLength)
15806 {
15807 	return contentLength == 8008 && RECOIL_DecodeMcppVariable(self, content, 0, 8000, 320, 200);
15808 }
15809 
RECOIL_DecodeIld(RECOIL * self,uint8_t const * content,int contentLength)15810 static bool RECOIL_DecodeIld(RECOIL *self, uint8_t const *content, int contentLength)
15811 {
15812 	if (contentLength != 8195)
15813 		return false;
15814 	RECOIL_SetSize(self, 256, 128, RECOILResolution_XE2X1);
15815 	self->gtiaColors[8] = 0;
15816 	self->gtiaColors[4] = 6;
15817 	self->gtiaColors[5] = 2;
15818 	self->gtiaColors[6] = 10;
15819 	uint8_t frame1[32768];
15820 	RECOIL_DecodeAtari8Gr15(self, content, 0, 32, frame1, 0, 256, 128);
15821 	uint8_t frame2[32768];
15822 	RECOIL_DecodeAtari8Gr15(self, content, 4096, 32, frame2, 0, 256, 128);
15823 	return RECOIL_ApplyAtari8PaletteBlend(self, frame1, frame2);
15824 }
15825 
RECOIL_DecodeInp(RECOIL * self,uint8_t const * content,int contentLength)15826 static bool RECOIL_DecodeInp(RECOIL *self, uint8_t const *content, int contentLength)
15827 {
15828 	if (contentLength < 16004)
15829 		return false;
15830 	RECOIL_SetSize(self, 320, 200, RECOILResolution_XE2X1);
15831 	RECOIL_SetBakPF012(self, content, 16000, 1);
15832 	uint8_t frame1[64000];
15833 	RECOIL_DecodeAtari8Gr15(self, content, 0, 40, frame1, 0, 320, 200);
15834 	uint8_t frame2[64000];
15835 	RECOIL_DecodeAtari8Gr15(self, content, 8000, 40, frame2, 0, 320, 200);
15836 	return RECOIL_ApplyAtari8PaletteBlend(self, frame1, frame2);
15837 }
15838 
RECOIL_DecodeIge(RECOIL * self,uint8_t const * content,int contentLength)15839 static bool RECOIL_DecodeIge(RECOIL *self, uint8_t const *content, int contentLength)
15840 {
15841 	if (contentLength != 6160 || content[0] != 255 || content[1] != 255 || content[2] != 246 || content[3] != 163 || content[4] != 255 || content[5] != 187 || content[6] != 255 || content[7] != 95)
15842 		return false;
15843 	RECOIL_SetSize(self, 256, 96, RECOILResolution_XE2X1);
15844 	uint8_t frame1[24576];
15845 	RECOIL_SetBakPF012(self, content, 8, 1);
15846 	RECOIL_DecodeAtari8Gr15(self, content, 16, 32, frame1, 0, 256, 96);
15847 	uint8_t frame2[24576];
15848 	RECOIL_SetBakPF012(self, content, 12, 1);
15849 	RECOIL_DecodeAtari8Gr15(self, content, 3088, 32, frame2, 0, 256, 96);
15850 	return RECOIL_ApplyAtari8PaletteBlend(self, frame1, frame2);
15851 }
15852 
RECOIL_DecodeInt(RECOIL * self,uint8_t const * content,int contentLength)15853 static bool RECOIL_DecodeInt(RECOIL *self, uint8_t const *content, int contentLength)
15854 {
15855 	if (contentLength < 18 || !RECOIL_IsStringAt(content, 0, "INT95a") || content[8] != 15 || content[9] != 43)
15856 		return false;
15857 	int contentStride = content[6];
15858 	int height = content[7];
15859 	if (contentStride == 0 || contentStride > 320 || height == 0 || height > 239 || 18 + contentStride * height * 2 != contentLength)
15860 		return false;
15861 	int width = contentStride << 3;
15862 	RECOIL_SetSize(self, width, height, RECOILResolution_XE2X1);
15863 	uint8_t frame1[76480];
15864 	RECOIL_SetBakPF012(self, content, 10, 1);
15865 	RECOIL_DecodeAtari8Gr15(self, content, 18, contentStride, frame1, 0, width, height);
15866 	uint8_t frame2[76480];
15867 	RECOIL_SetBakPF012(self, content, 14, 1);
15868 	RECOIL_DecodeAtari8Gr15(self, content, 18 + contentStride * height, contentStride, frame2, 0, width, height);
15869 	return RECOIL_ApplyAtari8PaletteBlend(self, frame1, frame2);
15870 }
15871 
RECOIL_DecodeIst(RECOIL * self,uint8_t const * content,int contentLength)15872 static bool RECOIL_DecodeIst(RECOIL *self, uint8_t const *content, int contentLength)
15873 {
15874 	if (contentLength != 17184)
15875 		return false;
15876 	RECOIL_SetSize(self, 320, 200, RECOILResolution_XE2X1);
15877 	uint8_t frame1[64000];
15878 	uint8_t frame2[64000];
15879 	for (int y = 0; y < 200; y++) {
15880 		RECOIL_SetBakPF012(self, content, 16384 + y, 200);
15881 		RECOIL_DecodeAtari8Gr15(self, content, 16 + y * 40, 0, frame1, y * 320, 320, 1);
15882 		RECOIL_DecodeAtari8Gr15(self, content, 8208 + y * 40, 0, frame2, y * 320, 320, 1);
15883 	}
15884 	return RECOIL_ApplyAtari8PaletteBlend(self, frame1, frame2);
15885 }
15886 
RECOIL_DecodeGr15Blend(RECOIL * self,uint8_t const * content,int bitmapOffset,int colorsOffset,int height)15887 static bool RECOIL_DecodeGr15Blend(RECOIL *self, uint8_t const *content, int bitmapOffset, int colorsOffset, int height)
15888 {
15889 	RECOIL_SetSize(self, 320, height, RECOILResolution_XE2X1);
15890 	uint8_t frame1[64000];
15891 	RECOIL_SetPF012Bak(self, content, colorsOffset);
15892 	RECOIL_DecodeAtari8Gr15(self, content, bitmapOffset, 80, frame1, 0, 640, height >> 1);
15893 	RECOIL_SetPF012Bak(self, content, colorsOffset + 4);
15894 	RECOIL_DecodeAtari8Gr15(self, content, bitmapOffset + 40, 80, frame1, 320, 640, height >> 1);
15895 	uint8_t frame2[64000];
15896 	RECOIL_DecodeAtari8Gr15(self, content, bitmapOffset + height * 40, 80, frame2, 0, 640, height >> 1);
15897 	RECOIL_SetPF012Bak(self, content, colorsOffset);
15898 	RECOIL_DecodeAtari8Gr15(self, content, bitmapOffset + height * 40 + 40, 80, frame2, 320, 640, height >> 1);
15899 	return RECOIL_ApplyAtari8PaletteBlend(self, frame1, frame2);
15900 }
15901 
RECOIL_DecodeMcp(RECOIL * self,uint8_t const * content,int contentLength)15902 static bool RECOIL_DecodeMcp(RECOIL *self, uint8_t const *content, int contentLength)
15903 {
15904 	return contentLength == 16008 && RECOIL_DecodeGr15Blend(self, content, 0, 16000, 200);
15905 }
15906 
RECOIL_DecodeAtari8Raw(RECOIL * self,uint8_t const * content,int contentLength)15907 static bool RECOIL_DecodeAtari8Raw(RECOIL *self, uint8_t const *content, int contentLength)
15908 {
15909 	return contentLength == 15372 && RECOIL_IsStringAt(content, 0, "XLPB") && RECOIL_DecodeGr15Blend(self, content, 4, 15364, 192);
15910 }
15911 
RECOIL_DecodeXlp(RECOIL * self,uint8_t const * content,int contentLength)15912 static bool RECOIL_DecodeXlp(RECOIL *self, uint8_t const *content, int contentLength)
15913 {
15914 	XlpStream rle;
15915 	XlpStream_Construct(&rle);
15916 	rle.base.base.base.content = content;
15917 	rle.base.base.base.contentLength = contentLength;
15918 	uint8_t unpacked[16000];
15919 	int height;
15920 	int colorsOffset;
15921 	if (contentLength >= 10 && RECOIL_IsStringAt(content, 0, "XLPC")) {
15922 		memset(unpacked, 0, sizeof(unpacked));
15923 		rle.base.base.base.contentOffset = 8;
15924 		RleStream_UnpackColumns(&rle.base, unpacked, 0, 40, 15360);
15925 		height = 192;
15926 		colorsOffset = 4;
15927 	}
15928 	else {
15929 		rle.base.base.base.contentOffset = 4;
15930 		if (RleStream_UnpackColumns(&rle.base, unpacked, 0, 40, 16000))
15931 			height = 200;
15932 		else {
15933 			rle.base.base.base.contentOffset = 4;
15934 			if (RleStream_UnpackColumns(&rle.base, unpacked, 0, 40, 15360))
15935 				height = 192;
15936 			else
15937 				return false;
15938 		}
15939 		colorsOffset = 0;
15940 	}
15941 	RECOIL_SetSize(self, 320, height, RECOILResolution_XE2X1);
15942 	RECOIL_SetPF012Bak(self, content, colorsOffset);
15943 	uint8_t frame1[64000];
15944 	RECOIL_DecodeAtari8Gr15(self, unpacked, 0, 40, frame1, 0, 320, height);
15945 	uint8_t frame2[64000];
15946 	RECOIL_DecodeAtari8Gr15(self, unpacked, height * 40, 40, frame2, 0, 320, height);
15947 	return RECOIL_ApplyAtari8PaletteBlend(self, frame1, frame2);
15948 }
15949 
RECOIL_DecodeAtari8Max(RECOIL * self,uint8_t const * content,int contentLength)15950 static bool RECOIL_DecodeAtari8Max(RECOIL *self, uint8_t const *content, int contentLength)
15951 {
15952 	if (contentLength < 1732 || !RECOIL_IsStringAt(content, 0, "XLPM"))
15953 		return false;
15954 	XlpStream rle;
15955 	XlpStream_Construct(&rle);
15956 	rle.base.base.base.content = content;
15957 	rle.base.base.base.contentOffset = 1732;
15958 	rle.base.base.base.contentLength = contentLength;
15959 	uint8_t unpacked[15360];
15960 	if (!RleStream_UnpackColumns(&rle.base, unpacked, 0, 40, 15360))
15961 		return false;
15962 	RECOIL_SetSize(self, 320, 192, RECOILResolution_XE2X1);
15963 	uint8_t frame1[61440];
15964 	uint8_t frame2[61440];
15965 	for (int y = 0; y < 192; y++) {
15966 		RECOIL_SetBakPF012(self, content, 772 + y, 192);
15967 		RECOIL_DecodeAtari8Gr15(self, unpacked, y * 40, 40, frame1, y * 320, 320, 1);
15968 		RECOIL_SetBakPF012(self, content, 4 + y, 192);
15969 		RECOIL_DecodeAtari8Gr15(self, unpacked, 7680 + y * 40, 40, frame2, y * 320, 320, 1);
15970 	}
15971 	return RECOIL_ApplyAtari8PaletteBlend(self, frame1, frame2);
15972 }
15973 
RECOIL_DecodeHr2(RECOIL * self,uint8_t const * content,int contentLength)15974 static bool RECOIL_DecodeHr2(RECOIL *self, uint8_t const *content, int contentLength)
15975 {
15976 	if (contentLength != 16006)
15977 		return false;
15978 	RECOIL_SetSize(self, 320, 200, RECOILResolution_XE1X1);
15979 	uint8_t frame1[64000];
15980 	RECOIL_SetPF21(self, content, 16000);
15981 	RECOIL_DecodeAtari8Gr8(self, content, 0, frame1, 0, 200);
15982 	uint8_t frame2[64000];
15983 	RECOIL_SetBakPF012(self, content, 16002, 1);
15984 	RECOIL_DecodeAtari8Gr15(self, content, 8000, 40, frame2, 0, 320, 200);
15985 	return RECOIL_ApplyAtari8PaletteBlend(self, frame1, frame2);
15986 }
15987 
RECOIL_DecodeLum(RECOIL * self,const char * filename,uint8_t const * content,int contentLength)15988 static bool RECOIL_DecodeLum(RECOIL *self, const char *filename, uint8_t const *content, int contentLength)
15989 {
15990 	if (contentLength != 4766)
15991 		return false;
15992 	RECOIL_SetSize(self, 320, 238, RECOILResolution_XE4X2);
15993 	uint8_t frame[76160];
15994 	self->gtiaColors[8] = 0;
15995 	RECOIL_DecodeAtari8Gr9(self, content, 6, 40, frame, 320, 640, 320, 119);
15996 	uint8_t col[4767];
15997 	if (RECOIL_ReadCompanionFile(self, filename, "COL", "col", col, 4767) == 4766) {
15998 		RECOIL_DecodeAtari8Gr11PalBlend(self, col, 6, 40, frame, 0);
15999 	}
16000 	else {
16001 		RECOIL_DecodeAtari8Gr9(self, content, 6, 40, frame, 0, 640, 320, 119);
16002 	}
16003 	return RECOIL_ApplyAtari8Palette(self, frame);
16004 }
16005 
RECOIL_DecodeApc(RECOIL * self,uint8_t const * content,int contentLength)16006 static bool RECOIL_DecodeApc(RECOIL *self, uint8_t const *content, int contentLength)
16007 {
16008 	if (contentLength != 7680 && contentLength != 7720)
16009 		return false;
16010 	RECOIL_SetSize(self, 320, 192, RECOILResolution_XE4X2);
16011 	uint8_t frame[61440];
16012 	self->gtiaColors[8] = 0;
16013 	RECOIL_DecodeAtari8Gr9(self, content, 40, 80, frame, 320, 640, 320, 96);
16014 	RECOIL_DecodeAtari8Gr11PalBlend(self, content, 0, 80, frame, 0);
16015 	return RECOIL_ApplyAtari8Palette(self, frame);
16016 }
16017 
RECOIL_Decode256(RECOIL * self,uint8_t const * content,int contentLength)16018 static bool RECOIL_Decode256(RECOIL *self, uint8_t const *content, int contentLength)
16019 {
16020 	if (contentLength != 7680 && contentLength != 7684)
16021 		return false;
16022 	RECOIL_SetSize(self, 320, 192, RECOILResolution_XE4X2);
16023 	uint8_t frame[61440];
16024 	self->gtiaColors[8] = 0;
16025 	RECOIL_DecodeAtari8Gr9(self, content, 3840, 40, frame, 320, 640, 320, 96);
16026 	RECOIL_DecodeAtari8Gr11PalBlend(self, content, 0, 40, frame, 0);
16027 	return RECOIL_ApplyAtari8Palette(self, frame);
16028 }
16029 
RECOIL_DecodeAp3(RECOIL * self,uint8_t const * content,int contentLength)16030 static bool RECOIL_DecodeAp3(RECOIL *self, uint8_t const *content, int contentLength)
16031 {
16032 	int gr11Offset;
16033 	switch (contentLength) {
16034 	case 15360:
16035 	case 15362:
16036 		gr11Offset = 7680;
16037 		break;
16038 	case 15872:
16039 		gr11Offset = 8192;
16040 		break;
16041 	default:
16042 		return false;
16043 	}
16044 	RECOIL_SetSize(self, 320, 192, RECOILResolution_XE4X1);
16045 	self->gtiaColors[8] = 0;
16046 	uint8_t frame1[61440];
16047 	RECOIL_DecodeAtari8Gr9(self, content, 0, 80, frame1, 0, 640, 320, 96);
16048 	RECOIL_DecodeAtari8Gr11PalBlend(self, content, gr11Offset + 40, 80, frame1, 1);
16049 	uint8_t frame2[61440];
16050 	RECOIL_DecodeAtari8Gr9(self, content, 40, 80, frame2, 320, 640, 320, 96);
16051 	RECOIL_DecodeAtari8Gr11PalBlend(self, content, gr11Offset, 80, frame2, 0);
16052 	return RECOIL_ApplyAtari8PaletteBlend(self, frame1, frame2);
16053 }
16054 
RECOIL_DecodeBgp(RECOIL * self,uint8_t const * content,int contentLength)16055 static bool RECOIL_DecodeBgp(RECOIL *self, uint8_t const *content, int contentLength)
16056 {
16057 	if (contentLength < 19163 || !RECOIL_IsStringAt(content, 0, "BUGBITER_APAC239I_PICTURE_V1.0") || content[30] != 255 || content[31] != 80 || content[32] != 239)
16058 		return false;
16059 	int textLength = content[37] + (content[38] << 8);
16060 	if (contentLength != 19163 + textLength || content[39 + textLength] != 88 || content[40 + textLength] != 37 || content[9601 + textLength] != 88 || content[9602 + textLength] != 37)
16061 		return false;
16062 	RECOIL_SetSize(self, 320, 239, RECOILResolution_XE4X1);
16063 	self->gtiaColors[8] = 0;
16064 	uint8_t frame1[76480];
16065 	RECOIL_DecodeAtari8Gr9(self, content, 41 + textLength, 80, frame1, 0, 640, 320, 120);
16066 	RECOIL_DecodeAtari8Gr11PalBlend(self, content, 9643 + textLength, 80, frame1, 1);
16067 	uint8_t frame2[76480];
16068 	RECOIL_DecodeAtari8Gr9(self, content, 81 + textLength, 80, frame2, 320, 640, 320, 119);
16069 	RECOIL_DecodeAtari8Gr11PalBlend(self, content, 9603 + textLength, 80, frame2, 0);
16070 	return RECOIL_ApplyAtari8PaletteBlend(self, frame1, frame2);
16071 }
16072 
RECOIL_DecodeHip(RECOIL * self,uint8_t const * content,int contentLength)16073 static bool RECOIL_DecodeHip(RECOIL *self, uint8_t const *content, int contentLength)
16074 {
16075 	if (contentLength < 80)
16076 		return false;
16077 	static const uint8_t GR10_COLORS[9] = { 0, 0, 2, 4, 6, 8, 10, 12, 14 };
16078 	uint8_t frame1[76800];
16079 	uint8_t frame2[76800];
16080 	int frameLength = RECOIL_ParseAtari8ExecutableHeader(content, 0);
16081 	if (frameLength > 0 && frameLength % 40 == 0 && 12 + frameLength * 2 == contentLength && RECOIL_ParseAtari8ExecutableHeader(content, 6 + frameLength) == frameLength) {
16082 		int height = frameLength / 40;
16083 		if (height > 240)
16084 			return false;
16085 		RECOIL_SetSize(self, 320, height, RECOILResolution_XE2X1);
16086 		self->leftSkip = 1;
16087 		RECOIL_SetGtiaColors(self, GR10_COLORS, 0);
16088 		RECOIL_DecodeAtari8Gr10(self, content, 6, frame1, 0, 320, height);
16089 		self->gtiaColors[8] = 0;
16090 		RECOIL_DecodeAtari8Gr9(self, content, 12 + frameLength, 40, frame2, 0, 320, 320, height);
16091 	}
16092 	else {
16093 		int height = contentLength / 80;
16094 		if (height > 240)
16095 			return false;
16096 		RECOIL_SetSize(self, 320, height, RECOILResolution_XE2X1);
16097 		self->leftSkip = 1;
16098 		self->gtiaColors[8] = 0;
16099 		RECOIL_DecodeAtari8Gr9(self, content, 0, 40, frame1, 0, 320, 320, height);
16100 		if (contentLength % 80 == 9)
16101 			RECOIL_SetGtiaColors(self, content, contentLength - 9);
16102 		else
16103 			RECOIL_SetGtiaColors(self, GR10_COLORS, 0);
16104 		RECOIL_DecodeAtari8Gr10(self, content, height * 40, frame2, 0, 320, height);
16105 	}
16106 	return RECOIL_ApplyAtari8PaletteBlend(self, frame1, frame2);
16107 }
16108 
RECOIL_DecodeG9s(RECOIL * self,uint8_t const * content,int contentLength)16109 static bool RECOIL_DecodeG9s(RECOIL *self, uint8_t const *content, int contentLength)
16110 {
16111 	uint8_t unpacked[7680];
16112 	SfdnStream s;
16113 	SfdnStream_Construct(&s);
16114 	s.base.base.content = content;
16115 	s.base.base.contentLength = contentLength;
16116 	return SfdnStream_Unpack(&s, unpacked, 7680) && RECOIL_DecodeGr9(self, unpacked, 7680);
16117 }
16118 
RECOIL_DecodeIns(RECOIL * self,uint8_t const * content,int contentLength)16119 static bool RECOIL_DecodeIns(RECOIL *self, uint8_t const *content, int contentLength)
16120 {
16121 	uint8_t unpacked[16004];
16122 	SfdnStream s;
16123 	SfdnStream_Construct(&s);
16124 	s.base.base.content = content;
16125 	s.base.base.contentLength = contentLength;
16126 	return SfdnStream_Unpack(&s, unpacked, 16004) && RECOIL_DecodeInp(self, unpacked, 16004);
16127 }
16128 
RECOIL_DecodePls(RECOIL * self,uint8_t const * content,int contentLength)16129 static bool RECOIL_DecodePls(RECOIL *self, uint8_t const *content, int contentLength)
16130 {
16131 	uint8_t unpacked[7680];
16132 	SfdnStream s;
16133 	SfdnStream_Construct(&s);
16134 	s.base.base.content = content;
16135 	s.base.base.contentLength = contentLength;
16136 	return SfdnStream_Unpack(&s, unpacked, 7680) && RECOIL_DecodeApc(self, unpacked, 7680);
16137 }
16138 
RECOIL_DecodeAps(RECOIL * self,uint8_t const * content,int contentLength)16139 static bool RECOIL_DecodeAps(RECOIL *self, uint8_t const *content, int contentLength)
16140 {
16141 	uint8_t unpacked[7720];
16142 	SfdnStream s;
16143 	SfdnStream_Construct(&s);
16144 	s.base.base.content = content;
16145 	s.base.base.contentLength = contentLength;
16146 	return SfdnStream_Unpack(&s, unpacked, 7720) && RECOIL_DecodeApc(self, unpacked, 7720);
16147 }
16148 
RECOIL_DecodeIls(RECOIL * self,uint8_t const * content,int contentLength)16149 static bool RECOIL_DecodeIls(RECOIL *self, uint8_t const *content, int contentLength)
16150 {
16151 	uint8_t unpacked[15360];
16152 	SfdnStream s;
16153 	SfdnStream_Construct(&s);
16154 	s.base.base.content = content;
16155 	s.base.base.contentLength = contentLength;
16156 	return SfdnStream_Unpack(&s, unpacked, 15360) && RECOIL_DecodeAp3(self, unpacked, 15360);
16157 }
16158 
RECOIL_DecodeApp(RECOIL * self,uint8_t const * content,int contentLength)16159 static bool RECOIL_DecodeApp(RECOIL *self, uint8_t const *content, int contentLength)
16160 {
16161 	uint8_t unpacked[15872];
16162 	SfdnStream s;
16163 	SfdnStream_Construct(&s);
16164 	s.base.base.content = content;
16165 	s.base.base.contentLength = contentLength;
16166 	return SfdnStream_Unpack(&s, unpacked, 15872) && RECOIL_DecodeAp3(self, unpacked, 15872);
16167 }
16168 
RECOIL_DecodeHps(RECOIL * self,uint8_t const * content,int contentLength)16169 static bool RECOIL_DecodeHps(RECOIL *self, uint8_t const *content, int contentLength)
16170 {
16171 	uint8_t unpacked[16009];
16172 	SfdnStream s;
16173 	SfdnStream_Construct(&s);
16174 	s.base.base.content = content;
16175 	s.base.base.contentLength = contentLength;
16176 	return SfdnStream_Unpack(&s, unpacked, 16009) && RECOIL_DecodeHip(self, unpacked, 16009);
16177 }
16178 
RECOIL_DecodeTip(RECOIL * self,uint8_t const * content,int contentLength)16179 static bool RECOIL_DecodeTip(RECOIL *self, uint8_t const *content, int contentLength)
16180 {
16181 	if (contentLength < 129 || content[0] != 84 || content[1] != 73 || content[2] != 80 || content[3] != 1 || content[4] != 0)
16182 		return false;
16183 	int width = content[5];
16184 	int height = content[6];
16185 	if (width > 160 || (width & 3) != 0 || height > 119)
16186 		return false;
16187 	int contentStride = width >> 2;
16188 	int frameLength = content[7] | content[8] << 8;
16189 	if (frameLength != contentStride * height || contentLength != 9 + 3 * frameLength)
16190 		return false;
16191 	RECOIL_SetSize(self, width << 1, height << 1, RECOILResolution_XE2X2);
16192 	self->leftSkip = 1;
16193 	static const uint8_t COLORS[9] = { 0, 2, 4, 6, 8, 10, 12, 14, 0 };
16194 	RECOIL_SetGtiaColors(self, COLORS, 0);
16195 	uint8_t frame1[76160];
16196 	RECOIL_DecodeAtari8Gr9(self, content, 9, contentStride, frame1, width << 1, width << 2, width << 1, height);
16197 	RECOIL_DecodeAtari8Gr11PalBlend(self, content, 9 + 2 * frameLength, contentStride, frame1, 0);
16198 	uint8_t frame2[76160];
16199 	RECOIL_DecodeAtari8Gr10(self, content, 9 + frameLength, frame2, width << 1, width << 2, height);
16200 	RECOIL_DecodeAtari8Gr11PalBlend(self, content, 9 + 2 * frameLength, contentStride, frame2, 0);
16201 	return RECOIL_ApplyAtari8PaletteBlend(self, frame1, frame2);
16202 }
16203 
RECOIL_DecodeCin(RECOIL * self,uint8_t const * content,int contentLength)16204 static bool RECOIL_DecodeCin(RECOIL *self, uint8_t const *content, int contentLength)
16205 {
16206 	int height;
16207 	switch (contentLength) {
16208 	case 15360:
16209 		RECOIL_SetGr15DefaultColors(self);
16210 		height = 192;
16211 		break;
16212 	case 16004:
16213 		RECOIL_SetBakPF012(self, content, 16000, 1);
16214 		height = 200;
16215 		break;
16216 	case 16384:
16217 		height = 192;
16218 		break;
16219 	default:
16220 		return false;
16221 	}
16222 	RECOIL_SetSize(self, 320, height, RECOILResolution_XE2X1);
16223 	uint8_t frame1[64000];
16224 	uint8_t frame2[64000];
16225 	for (int y = 0; y < height; y++) {
16226 		if (contentLength == 16384)
16227 			RECOIL_SetBakPF012(self, content, 15360 + y, 256);
16228 		RECOIL_DecodeAtari8Gr15(self, content, y * 40, 40, (y & 1) == 0 ? frame1 : frame2, y * 320, 320, 1);
16229 	}
16230 	RECOIL_DecodeAtari8Gr11PalBlend(self, content, 40 * height + 40, 80, frame1, 1);
16231 	RECOIL_DecodeAtari8Gr11PalBlend(self, content, 40 * height, 80, frame2, 0);
16232 	return RECOIL_ApplyAtari8PaletteBlend(self, frame1, frame2);
16233 }
16234 
RECOIL_DecodeCci(RECOIL * self,uint8_t const * content,int contentLength)16235 static bool RECOIL_DecodeCci(RECOIL *self, uint8_t const *content, int contentLength)
16236 {
16237 	if (contentLength < 24 || !RECOIL_IsStringAt(content, 0, "CIN 1.2 "))
16238 		return false;
16239 	CciStream rle;
16240 	CciStream_Construct(&rle);
16241 	rle.base.base.base.content = content;
16242 	rle.base.base.base.contentOffset = 8;
16243 	rle.base.base.base.contentLength = contentLength;
16244 	uint8_t unpacked[16384];
16245 	if (!CciStream_UnpackGr15(&rle, unpacked, 0) || !CciStream_UnpackGr15(&rle, unpacked, 40))
16246 		return false;
16247 	rle.base.base.base.contentOffset += 4;
16248 	rle.base.repeatCount = 0;
16249 	if (!RleStream_UnpackColumns(&rle.base, unpacked, 7680, 40, 15360))
16250 		return false;
16251 	rle.base.base.base.contentOffset += 4;
16252 	rle.base.repeatCount = 0;
16253 	return RleStream_Unpack(&rle.base, unpacked, 15360, 1, 16384) && RECOIL_DecodeCin(self, unpacked, 16384);
16254 }
16255 
RECOIL_DecodeAgs(RECOIL * self,uint8_t const * content,int contentLength)16256 static bool RECOIL_DecodeAgs(RECOIL *self, uint8_t const *content, int contentLength)
16257 {
16258 	if (contentLength < 17 || content[0] != 65 || content[1] != 71 || content[2] != 83)
16259 		return false;
16260 	int width = content[4];
16261 	int height = content[5] | content[6] << 8;
16262 	if (contentLength != 16 + (width * height << 1))
16263 		return false;
16264 	switch (content[3]) {
16265 	case 11:
16266 		return RECOIL_DecodeMcppVariable(self, content, 16, 7, width << 3, height << 1);
16267 	case 19:
16268 		return RECOIL_DecodeGr9x4(self, content, 16, width << 3, height << 2);
16269 	default:
16270 		return false;
16271 	}
16272 }
16273 
RECOIL_UnpackRip(const RECOIL * self,uint8_t const * content,int contentOffset,int contentLength,uint8_t * unpacked,int unpackedLength)16274 static bool RECOIL_UnpackRip(const RECOIL *self, uint8_t const *content, int contentOffset, int contentLength, uint8_t *unpacked, int unpackedLength)
16275 {
16276 	if (contentOffset + 304 > contentLength || !RECOIL_IsStringAt(content, contentOffset, "PCK"))
16277 		return false;
16278 	FanoTree lengthTree;
16279 	FanoTree_Create(&lengthTree, content, contentOffset + 16, 64);
16280 	FanoTree distanceTree;
16281 	FanoTree_Create(&distanceTree, content, contentOffset + 16 + 32, 256);
16282 	FanoTree literalTree;
16283 	FanoTree_Create(&literalTree, content, contentOffset + 16 + 32 + 128, 256);
16284 	BitStream bitStream;
16285 	BitStream_Construct(&bitStream);
16286 	bitStream.base.content = content;
16287 	bitStream.base.contentOffset = contentOffset + 16 + 288;
16288 	bitStream.base.contentLength = contentLength;
16289 	for (int unpackedOffset = 0; unpackedOffset < unpackedLength;) {
16290 		switch (bitStream.vtbl->readBit(&bitStream)) {
16291 		case 0:
16292 			;
16293 			int literal = FanoTree_ReadCode(&literalTree, &bitStream);
16294 			if (literal < 0)
16295 				return false;
16296 			unpacked[unpackedOffset++] = (uint8_t) literal;
16297 			break;
16298 		case 1:
16299 			;
16300 			int distance = FanoTree_ReadCode(&distanceTree, &bitStream);
16301 			if (distance < 0)
16302 				return false;
16303 			distance += 2;
16304 			int count = FanoTree_ReadCode(&lengthTree, &bitStream);
16305 			if (count < 0)
16306 				return false;
16307 			count += 2;
16308 			if (count > unpackedLength - unpackedOffset)
16309 				count = unpackedLength - unpackedOffset;
16310 			if (!RECOIL_CopyPrevious(unpacked, unpackedOffset, distance, count))
16311 				return false;
16312 			unpackedOffset += count;
16313 			if (unpackedOffset >= unpackedLength)
16314 				return true;
16315 			break;
16316 		default:
16317 			return false;
16318 		}
16319 	}
16320 	return true;
16321 }
16322 
RECOIL_DecodeRip(RECOIL * self,uint8_t const * content,int contentLength)16323 static bool RECOIL_DecodeRip(RECOIL *self, uint8_t const *content, int contentLength)
16324 {
16325 	if (contentLength < 34 || content[0] != 82 || content[1] != 73 || content[2] != 80 || content[18] != 84 || content[19] != 58)
16326 		return false;
16327 	int headerLength = content[11] | content[12] << 8;
16328 	int contentStride = content[13];
16329 	int height = content[15];
16330 	int textLength = content[17];
16331 	if (headerLength >= contentLength || contentStride == 0 || contentStride > 80 || (contentStride & 1) != 0 || height == 0 || height > 239 || 33 + textLength >= contentLength || content[20 + textLength] != 9 || !RECOIL_IsStringAt(content, 21 + textLength, "CM:"))
16332 		return false;
16333 	if (content[7] < 16)
16334 		contentStride >>= 1;
16335 	int unpackedLength = contentStride * height;
16336 	if (content[7] == 48)
16337 		unpackedLength += (height + 1) >> 1 << 3;
16338 	uint8_t unpacked[20076] = { 0 };
16339 	switch (content[9]) {
16340 	case 0:
16341 		if (headerLength + unpackedLength > contentLength)
16342 			return false;
16343 		memcpy(unpacked, content + headerLength, unpackedLength);
16344 		break;
16345 	case 1:
16346 		RECOIL_UnpackRip(self, content, headerLength, contentLength, unpacked, unpackedLength);
16347 		break;
16348 	default:
16349 		return false;
16350 	}
16351 	RECOIL_SetGtiaColors(self, content, 24 + textLength);
16352 	contentStride = content[13] >> 1;
16353 	int width = contentStride << 3;
16354 	uint8_t frame1[76480];
16355 	uint8_t frame2[76480];
16356 	switch (content[7]) {
16357 	case 14:
16358 		RECOIL_SetSize(self, width, height, RECOILResolution_XE2X1);
16359 		RECOIL_DecodeAtari8Gr15(self, unpacked, 0, contentStride, frame1, 0, width, height);
16360 		return RECOIL_ApplyAtari8Palette(self, frame1);
16361 	case 15:
16362 		RECOIL_SetSize(self, width, height, RECOILResolution_XE1X1);
16363 		RECOIL_DecodeAtari8Gr8(self, unpacked, 0, frame1, 0, height);
16364 		return RECOIL_ApplyAtari8Palette(self, frame1);
16365 	case 79:
16366 		RECOIL_SetSize(self, width, height, RECOILResolution_XE4X1);
16367 		RECOIL_DecodeAtari8Gr9(self, unpacked, 0, contentStride, frame1, 0, width, width, height);
16368 		return RECOIL_ApplyAtari8Palette(self, frame1);
16369 	case 143:
16370 		RECOIL_SetSize(self, width, height, RECOILResolution_XE4X1);
16371 		self->leftSkip = 2;
16372 		RECOIL_DecodeAtari8Gr10(self, unpacked, 0, frame1, 0, width, height);
16373 		return RECOIL_ApplyAtari8Palette(self, frame1);
16374 	case 207:
16375 		RECOIL_SetSize(self, width, height, RECOILResolution_XE4X1);
16376 		RECOIL_DecodeAtari8Gr11(self, content, 0, frame1, 0, width, height);
16377 		return RECOIL_ApplyAtari8Palette(self, frame1);
16378 	case 30:
16379 		RECOIL_SetSize(self, width, height, RECOILResolution_XE2X1);
16380 		RECOIL_DecodeAtari8Gr15(self, unpacked, 0, contentStride, frame1, 0, width, height);
16381 		RECOIL_DecodeAtari8Gr15(self, unpacked, height * contentStride, contentStride, frame2, 0, width, height);
16382 		return RECOIL_ApplyAtari8PaletteBlend(self, frame1, frame2);
16383 	case 16:
16384 		RECOIL_SetSize(self, width, height, RECOILResolution_XE2X1);
16385 		RECOIL_SetBakPF012(self, content, 28 + textLength, 1);
16386 		RECOIL_DecodeAtari8Gr15(self, unpacked, 0, contentStride << 1, frame1, 0, width << 1, height >> 1);
16387 		RECOIL_SetBakPF012(self, content, 24 + textLength, 1);
16388 		RECOIL_DecodeAtari8Gr15(self, unpacked, contentStride, contentStride << 1, frame1, width, width << 1, height >> 1);
16389 		RECOIL_DecodeAtari8Gr15(self, unpacked, height * contentStride, contentStride << 1, frame2, 0, width << 1, height >> 1);
16390 		RECOIL_SetBakPF012(self, content, 28 + textLength, 1);
16391 		RECOIL_DecodeAtari8Gr15(self, unpacked, (height + 1) * contentStride, contentStride << 1, frame2, width, width << 1, height >> 1);
16392 		return RECOIL_ApplyAtari8PaletteBlend(self, frame1, frame2);
16393 	case 32:
16394 		RECOIL_SetSize(self, width, height, RECOILResolution_XE2X1);
16395 		self->leftSkip = 1;
16396 		RECOIL_DecodeAtari8Gr10(self, unpacked, 0, frame1, 0, width, height);
16397 		self->gtiaColors[8] = 0;
16398 		RECOIL_DecodeAtari8Gr9(self, unpacked, height * contentStride, contentStride, frame2, 0, width, width, height);
16399 		return RECOIL_ApplyAtari8PaletteBlend(self, frame1, frame2);
16400 	case 48:
16401 		RECOIL_SetSize(self, width, height, RECOILResolution_XE2X1);
16402 		self->leftSkip = 1;
16403 		self->gtiaColors[0] = 0;
16404 		int colorsOffset = height * contentStride << 1;
16405 		for (int y = 0; y < height; y += 2) {
16406 			RECOIL_SetPM123PF0123Bak(self, unpacked, colorsOffset + (y << 2));
16407 			RECOIL_DecodeAtari8Gr10(self, unpacked, y * contentStride, frame1, y * width, width, y + 1 < height ? 2 : 1);
16408 		}
16409 		self->gtiaColors[8] = 0;
16410 		RECOIL_DecodeAtari8Gr9(self, unpacked, height * contentStride, contentStride, frame2, 0, width, width, height);
16411 		return RECOIL_ApplyAtari8PaletteBlend(self, frame1, frame2);
16412 	default:
16413 		return false;
16414 	}
16415 }
16416 
RECOIL_DecodeVzi(RECOIL * self,uint8_t const * content,int contentLength)16417 static bool RECOIL_DecodeVzi(RECOIL *self, uint8_t const *content, int contentLength)
16418 {
16419 	if (contentLength != 16000)
16420 		return false;
16421 	RECOIL_SetSize(self, 320, 200, RECOILResolution_XE2X1);
16422 	uint8_t frame1[64000];
16423 	self->leftSkip = -1;
16424 	RECOIL_DecodeAtari8Gr9(self, content, 0, 40, frame1, 0, 320, 320, 200);
16425 	self->leftSkip = 1;
16426 	uint8_t frame2[64000];
16427 	RECOIL_DecodeAtari8Gr9(self, content, 8000, 40, frame2, 0, 320, 320, 200);
16428 	return RECOIL_ApplyAtari8PaletteBlend(self, frame1, frame2);
16429 }
16430 
RECOIL_DecodeRm(RECOIL * self,uint8_t const * content,int contentLength,int mode,RECOILResolution resolution)16431 static bool RECOIL_DecodeRm(RECOIL *self, uint8_t const *content, int contentLength, int mode, RECOILResolution resolution)
16432 {
16433 	uint8_t unpacked[7680];
16434 	int colorsOffset;
16435 	int dliOffset;
16436 	if (XeKoalaStream_UnpackWrapped(content, contentLength - 464, unpacked, mode == 0 ? 3840 : 7680)) {
16437 		colorsOffset = contentLength - 464;
16438 		dliOffset = contentLength - 384;
16439 	}
16440 	else if (contentLength == 8192) {
16441 		memcpy(unpacked, content, 7680);
16442 		colorsOffset = 7680;
16443 		dliOffset = 7808;
16444 	}
16445 	else
16446 		return false;
16447 	bool dliPresent[192] = { false };
16448 	for (int i = 0; i < 128; i++) {
16449 		int y = content[dliOffset + i];
16450 		switch (y) {
16451 		case 0:
16452 			break;
16453 		case 1:
16454 		case 2:
16455 		case 4:
16456 		case 5:
16457 			return false;
16458 		default:
16459 			if (mode == 0) {
16460 				if (y >= 101)
16461 					return false;
16462 				if (y == 3)
16463 					y = 0;
16464 				else
16465 					y -= 5;
16466 			}
16467 			else {
16468 				if (y == 100 || y == 101 || y >= 198)
16469 					return false;
16470 				if (y == 3)
16471 					y = 1;
16472 				else if (y < 100)
16473 					y -= 4;
16474 				else
16475 					y -= 6;
16476 			}
16477 			dliPresent[y] = true;
16478 			break;
16479 		}
16480 	}
16481 	RECOIL_SetSize(self, 320, 192, resolution);
16482 	if (mode == 2)
16483 		self->leftSkip = 2;
16484 	if (mode == 1)
16485 		self->gtiaColors[8] = (uint8_t) (content[colorsOffset + 8] & 240);
16486 	else
16487 		RECOIL_SetGtiaColors(self, content, colorsOffset);
16488 	int height = mode == 0 ? 96 : 192;
16489 	uint8_t frame[61440];
16490 	for (int y = 0; y < height; y++) {
16491 		switch (mode) {
16492 		case 0:
16493 			RECOIL_DecodeAtari8Gr7(self, unpacked, y * 40, frame, y * 640, 1);
16494 			break;
16495 		case 1:
16496 			RECOIL_DecodeAtari8Gr9(self, unpacked, y * 40, 40, frame, y * 320, 320, 320, 1);
16497 			break;
16498 		case 2:
16499 			RECOIL_DecodeAtari8Gr10(self, unpacked, y * 40, frame, y * 320, 320, 1);
16500 			break;
16501 		case 3:
16502 			RECOIL_DecodeAtari8Gr11(self, unpacked, y * 40, frame, y * 320, 320, 1);
16503 			break;
16504 		case 4:
16505 			RECOIL_DecodeAtari8Gr15(self, unpacked, y * 40, 40, frame, y * 320, 320, 1);
16506 			break;
16507 		default:
16508 			assert(false);
16509 		}
16510 		if (dliPresent[y]) {
16511 			int vcount = mode == 0 ? 16 + y : 16 + ((y - 1) >> 1);
16512 			int reg = content[dliOffset + 128 + vcount];
16513 			if (reg < 9)
16514 				RECOIL_SetGtiaColor(self, reg, content[dliOffset + 256 + vcount]);
16515 			else if (reg != 128)
16516 				return false;
16517 		}
16518 	}
16519 	return RECOIL_ApplyAtari8Palette(self, frame);
16520 }
16521 
RECOIL_DecodeAgp(RECOIL * self,uint8_t const * content,int contentLength)16522 static bool RECOIL_DecodeAgp(RECOIL *self, uint8_t const *content, int contentLength)
16523 {
16524 	if (contentLength != 7690)
16525 		return false;
16526 	RECOIL_SetGtiaColors(self, content, 1);
16527 	uint8_t frame[61440];
16528 	switch (content[0]) {
16529 	case 8:
16530 		RECOIL_SetSize(self, 320, 192, RECOILResolution_XE1X1);
16531 		RECOIL_DecodeAtari8Gr8(self, content, 10, frame, 0, 192);
16532 		break;
16533 	case 9:
16534 		RECOIL_SetSize(self, 320, 192, RECOILResolution_XE4X1);
16535 		RECOIL_DecodeAtari8Gr9(self, content, 10, 40, frame, 0, 320, 320, 192);
16536 		break;
16537 	case 10:
16538 		RECOIL_SetSize(self, 320, 192, RECOILResolution_XE4X1);
16539 		self->leftSkip = 2;
16540 		RECOIL_DecodeAtari8Gr10(self, content, 10, frame, 0, 320, 192);
16541 		break;
16542 	case 11:
16543 		RECOIL_SetSize(self, 320, 192, RECOILResolution_XE4X1);
16544 		RECOIL_DecodeAtari8Gr11(self, content, 10, frame, 0, 320, 192);
16545 		break;
16546 	case 15:
16547 		RECOIL_SetSize(self, 320, 192, RECOILResolution_XE2X1);
16548 		RECOIL_DecodeAtari8Gr15(self, content, 10, 40, frame, 0, 320, 192);
16549 		break;
16550 	default:
16551 		return false;
16552 	}
16553 	return RECOIL_ApplyAtari8Palette(self, frame);
16554 }
16555 
RECOIL_DecodeShc(RECOIL * self,uint8_t const * content,int contentLength)16556 static bool RECOIL_DecodeShc(RECOIL *self, uint8_t const *content, int contentLength)
16557 {
16558 	if (contentLength != 17920)
16559 		return false;
16560 	RECOIL_SetSize(self, 320, 192, RECOILResolution_XE1X1);
16561 	uint8_t frame1[61440];
16562 	uint8_t frame2[61440];
16563 	int col1 = 15360;
16564 	int col2 = 16640;
16565 	for (int y = 0; y < 192; y++) {
16566 		for (int x = 0; x < 320; x++) {
16567 			int i = 320 * y + x;
16568 			int bit = ~x & 7;
16569 			switch (x) {
16570 			case 94:
16571 			case 166:
16572 			case 214:
16573 			case 262:
16574 			case 306:
16575 				col1++;
16576 				break;
16577 			case 46:
16578 			case 142:
16579 			case 190:
16580 			case 238:
16581 			case 286:
16582 				col2++;
16583 				break;
16584 			default:
16585 				break;
16586 			}
16587 			frame1[i] = (uint8_t) (content[col1] & ((content[i >> 3] >> bit & 1) != 0 ? 240 : 254));
16588 			frame2[i] = (uint8_t) (content[col2] & ((content[7680 + (i >> 3)] >> bit & 1) != 0 ? 240 : 254));
16589 		}
16590 		col1++;
16591 		col2++;
16592 	}
16593 	return RECOIL_ApplyAtari8PaletteBlend(self, frame1, frame2);
16594 }
16595 
RECOIL_DecodeMgp(RECOIL * self,uint8_t const * content,int contentLength)16596 static bool RECOIL_DecodeMgp(RECOIL *self, uint8_t const *content, int contentLength)
16597 {
16598 	if (contentLength != 3845)
16599 		return false;
16600 	RECOIL_SetSize(self, 320, 192, RECOILResolution_XE2X2);
16601 	uint8_t frame[61440];
16602 	RECOIL_SetPF0123Bak(self, content, 0);
16603 	int rainbow = content[5];
16604 	uint8_t bitmap[3840];
16605 	memcpy(bitmap, content + 6, 3839);
16606 	bitmap[3839] = 0;
16607 	for (int y = 0; y < 96; y++) {
16608 		if (rainbow < 4) {
16609 			self->gtiaColors[rainbow == 0 ? 8 : 3 + rainbow] = (uint8_t) ((16 + y) & 254);
16610 		}
16611 		RECOIL_DecodeAtari8Gr7(self, bitmap, y * 40, frame, y * 640, 1);
16612 	}
16613 	return RECOIL_ApplyAtari8Palette(self, frame);
16614 }
16615 
RECOIL_DecodeGad(RECOIL * self,uint8_t const * content,int contentLength)16616 static bool RECOIL_DecodeGad(RECOIL *self, uint8_t const *content, int contentLength)
16617 {
16618 	if (contentLength != 4325)
16619 		return false;
16620 	RECOIL_SetSize(self, 320, 192, RECOILResolution_XE2X2);
16621 	uint8_t frame[61440];
16622 	RECOIL_SetPF0123Bak(self, content, 0);
16623 	for (int y = 0; y < 96; y++) {
16624 		RECOIL_DecodeAtari8Gr7(self, content, 5 + y * 40, frame, y * 640, 1);
16625 		if (content[3845 + y] < 128) {
16626 			for (int i = 0; i < 4; i++)
16627 				self->gtiaColors[i == 3 ? 8 : 4 + i] = (uint8_t) (content[3941 + i * 96 + y] & 254);
16628 		}
16629 	}
16630 	return RECOIL_ApplyAtari8Palette(self, frame);
16631 }
16632 
RECOIL_DecodeFwa(RECOIL * self,uint8_t const * content,int contentLength)16633 static bool RECOIL_DecodeFwa(RECOIL *self, uint8_t const *content, int contentLength)
16634 {
16635 	if (contentLength < 7960 || content[0] != 254 || content[1] != 254 || content[6] != 112 || content[7] != 112 || content[8] != 112 || content[11] != 80 || content[115] != 96 || content[205] != 65 || 7960 + content[7958] + (content[7959] << 8) != contentLength)
16636 		return false;
16637 	RECOIL_SetSize(self, 320, 192, RECOILResolution_XE2X1);
16638 	uint8_t frame[61440];
16639 	RECOIL_SetBakPF012(self, content, 2, 1);
16640 	int dlOffset = 9;
16641 	int dliOffset = 7960;
16642 	for (int y = 0; y < 192; y++) {
16643 		RECOIL_DecodeAtari8Gr15(self, content, 262 + 40 * y + (y >= 102 ? 16 : 0), 40, frame, y * 320, 320, 1);
16644 		int dlInstr = content[dlOffset];
16645 		if (dlOffset == 9 || dlOffset == 113) {
16646 			if ((dlInstr & 127) != 78 || content[dlOffset + 1] != 0)
16647 				return false;
16648 			dlOffset += 3;
16649 		}
16650 		else {
16651 			if ((dlInstr & 127) != 14)
16652 				return false;
16653 			dlOffset++;
16654 		}
16655 		if (dlInstr >= 128) {
16656 			if (dliOffset + 14 > contentLength || content[dliOffset] != 72 || content[dliOffset + 1] != 138 || content[dliOffset + 2] != 72 || content[dliOffset + 3] != 169 || content[dliOffset + 5] != 141 || content[dliOffset + 6] != 10 || content[dliOffset + 7] != 212)
16657 				return false;
16658 			int a = content[dliOffset + 4];
16659 			dliOffset += 8;
16660 			while (content[dliOffset] != 32) {
16661 				switch (content[dliOffset]) {
16662 				case 169:
16663 					a = content[dliOffset + 1];
16664 					dliOffset += 2;
16665 					break;
16666 				case 141:
16667 					if (content[dliOffset + 2] != 208)
16668 						return false;
16669 					int lo = content[dliOffset + 1];
16670 					switch (lo) {
16671 					case 22:
16672 					case 23:
16673 					case 24:
16674 					case 26:
16675 						self->gtiaColors[lo - 18] = (uint8_t) (a & 254);
16676 						break;
16677 					default:
16678 						return false;
16679 					}
16680 					dliOffset += 3;
16681 					break;
16682 				default:
16683 					return false;
16684 				}
16685 				if (dliOffset + 3 > contentLength)
16686 					return false;
16687 			}
16688 			if (content[dliOffset + 1] != 202 || content[dliOffset + 2] != 6)
16689 				return false;
16690 			dliOffset += 3;
16691 		}
16692 	}
16693 	return RECOIL_ApplyAtari8Palette(self, frame);
16694 }
16695 
RECOIL_DecodeAtari8Font(RECOIL * self,uint8_t const * characters,uint8_t const * font,int fontOffset)16696 static bool RECOIL_DecodeAtari8Font(RECOIL *self, uint8_t const *characters, uint8_t const *font, int fontOffset)
16697 {
16698 	RECOIL_SetSize(self, 256, 32, RECOILResolution_XE1X1);
16699 	uint8_t frame[8192];
16700 	RECOIL_DecodeAtari8Gr0(self, characters, 32, font, fontOffset, frame);
16701 	return RECOIL_ApplyAtari8Palette(self, frame);
16702 }
16703 
RECOIL_DecodeAtari8Fnt(RECOIL * self,uint8_t const * content,int contentLength)16704 static bool RECOIL_DecodeAtari8Fnt(RECOIL *self, uint8_t const *content, int contentLength)
16705 {
16706 	int contentOffset;
16707 	switch (contentLength) {
16708 	case 1024:
16709 	case 1025:
16710 	case 1026:
16711 		contentOffset = 0;
16712 		break;
16713 	case 1030:
16714 		if (RECOIL_ParseAtari8ExecutableHeader(content, 0) != 1024)
16715 			return false;
16716 		contentOffset = 6;
16717 		break;
16718 	default:
16719 		return false;
16720 	}
16721 	return RECOIL_DecodeAtari8Font(self, NULL, content, contentOffset);
16722 }
16723 
RECOIL_DecodeF80(RECOIL * self,uint8_t const * content,int contentLength)16724 static bool RECOIL_DecodeF80(RECOIL *self, uint8_t const *content, int contentLength)
16725 {
16726 	if (contentLength != 512)
16727 		return false;
16728 	RECOIL_SetSize(self, 128, 32, RECOILResolution_XE1X1);
16729 	uint8_t frame[4096];
16730 	RECOIL_DecodeAtari8Gr0(self, NULL, 16, content, 0, frame);
16731 	return RECOIL_ApplyAtari8Palette(self, frame);
16732 }
16733 
RECOIL_DecodeSxs(RECOIL * self,uint8_t const * content,int contentLength)16734 static bool RECOIL_DecodeSxs(RECOIL *self, uint8_t const *content, int contentLength)
16735 {
16736 	if (contentLength != 1030 || RECOIL_ParseAtari8ExecutableHeader(content, 0) != 1024)
16737 		return false;
16738 	uint8_t characters[128];
16739 	for (int i = 0; i < 128; i++)
16740 		characters[i] = (uint8_t) ((i & 65) | (i >> 4 & 2) | (i & 30) << 1);
16741 	return RECOIL_DecodeAtari8Font(self, characters, content, 6);
16742 }
16743 
RECOIL_DecodeFn2(RECOIL * self,uint8_t const * content,int contentLength)16744 static bool RECOIL_DecodeFn2(RECOIL *self, uint8_t const *content, int contentLength)
16745 {
16746 	if (contentLength != 2048)
16747 		return false;
16748 	RECOIL_SetSize(self, 256, 64, RECOILResolution_XE1X1);
16749 	self->gtiaColors[6] = 0;
16750 	self->gtiaColors[5] = 14;
16751 	uint8_t frame[16384];
16752 	for (int y = 0; y < 64; y += 8)
16753 		RECOIL_DecodeAtari8Gr0Line(self, NULL, y >> 4 << 5, content, (y & 8) << 7, frame, y << 8, 8);
16754 	return RECOIL_ApplyAtari8Palette(self, frame);
16755 }
16756 
RECOIL_DecodeNlq(RECOIL * self,uint8_t const * content,int contentLength)16757 static bool RECOIL_DecodeNlq(RECOIL *self, uint8_t const *content, int contentLength)
16758 {
16759 	if (contentLength < 379 || !RECOIL_IsStringAt(content, 0, "DAISY-DOT NLQ FONT") || content[18] != 155)
16760 		return false;
16761 	RECOIL_SetSize(self, 320, 96, RECOILResolution_XE1X1);
16762 	uint8_t frame[30720] = { 0 };
16763 	int contentOffset = 19;
16764 	for (int i = 0; i < 91; i++) {
16765 		if (contentOffset >= contentLength)
16766 			return false;
16767 		int width = content[contentOffset];
16768 		if (width == 0 || width > 19)
16769 			return false;
16770 		int nextContentOffset = contentOffset + (width + 1) * 2;
16771 		if (nextContentOffset > contentLength || content[nextContentOffset - 1] != 155)
16772 			return false;
16773 		int c = i < 64 ? i : i < 90 ? i + 1 : 92;
16774 		for (int y = 0; y < 16; y++) {
16775 			for (int x = 0; x < width; x++) {
16776 				int b = content[contentOffset + 1 + (y & 1) * width + x] >> (7 - (y >> 1)) & 1;
16777 				frame[((c & 240) | y) * 320 + (c & 15) * 20 + x] = (uint8_t) (b == 0 ? 0 : 14);
16778 			}
16779 		}
16780 		contentOffset = nextContentOffset;
16781 	}
16782 	return RECOIL_ApplyAtari8Palette(self, frame);
16783 }
16784 
RECOIL_DecodeGr1(RECOIL * self,uint8_t const * content,int contentLength,int doubleHeight)16785 static bool RECOIL_DecodeGr1(RECOIL *self, uint8_t const *content, int contentLength, int doubleHeight)
16786 {
16787 	if (contentLength != 480 >> doubleHeight)
16788 		return false;
16789 	RECOIL_SetSize(self, 320, 192, doubleHeight == 0 ? RECOILResolution_XE2X1 : RECOILResolution_XE2X2);
16790 	uint8_t frame[61440];
16791 	RECOIL_SetXeOsDefaultColors(self);
16792 	uint8_t const *font = CiResource_atari8_fnt;
16793 	for (int offset = 0; offset < contentLength; offset += 20)
16794 		RECOIL_DecodeAtari8Gr1Line(self, content, offset, font, 0, frame, offset << (7 + doubleHeight), doubleHeight);
16795 	return RECOIL_ApplyAtari8Palette(self, frame);
16796 }
16797 
RECOIL_DecodeAcs(RECOIL * self,uint8_t const * content,int contentLength)16798 static bool RECOIL_DecodeAcs(RECOIL *self, uint8_t const *content, int contentLength)
16799 {
16800 	if (contentLength != 1028)
16801 		return false;
16802 	RECOIL_SetBakPF012(self, content, 0, 1);
16803 	RECOIL_SetSize(self, 128, 64, RECOILResolution_XE2X1);
16804 	uint8_t frame[8192];
16805 	for (int y = 0; y < 8; y++)
16806 		RECOIL_DecodeAtari8Gr12Line(self, NULL, 0, content, 4 + (y << 7), frame, y << 10, 0);
16807 	return RECOIL_ApplyAtari8Palette(self, frame);
16808 }
16809 
RECOIL_DecodeJgp(RECOIL * self,uint8_t const * content,int contentLength)16810 static bool RECOIL_DecodeJgp(RECOIL *self, uint8_t const *content, int contentLength)
16811 {
16812 	if (contentLength != 2054 || RECOIL_ParseAtari8ExecutableHeader(content, 0) != 2048)
16813 		return false;
16814 	RECOIL_SetGr15DefaultColors(self);
16815 	RECOIL_SetSize(self, 256, 64, RECOILResolution_XE2X1);
16816 	uint8_t frame[16384];
16817 	for (int y = 0; y < 8; y++)
16818 		RECOIL_DecodeAtari8Gr12Line(self, NULL, 0, content, 6 + ((y & 6) << 7) + ((y & 1) << 10), frame, y << 11, 0);
16819 	return RECOIL_ApplyAtari8Palette(self, frame);
16820 }
16821 
RECOIL_DecodeLeo(RECOIL * self,uint8_t const * content,int contentLength)16822 static bool RECOIL_DecodeLeo(RECOIL *self, uint8_t const *content, int contentLength)
16823 {
16824 	if (contentLength != 2580)
16825 		return false;
16826 	RECOIL_SetSize(self, 256, 64, RECOILResolution_XE2X1);
16827 	uint8_t frame[16384];
16828 	uint8_t characters[32];
16829 	RECOIL_SetPF0123Bak(self, content, 2560);
16830 	for (int y = 0; y < 8; y++) {
16831 		for (int x = 0; x < 32; x++)
16832 			characters[x] = content[2048 + ((x & 1) << 7) + ((y & 1) << 6) + ((y & 6) << 3) + (x >> 1)];
16833 		RECOIL_DecodeAtari8Gr12Line(self, characters, 0, content, (y & 1) << 10, frame, y << 11, 0);
16834 	}
16835 	return RECOIL_ApplyAtari8Palette(self, frame);
16836 }
16837 
RECOIL_DecodeSif(RECOIL * self,uint8_t const * content,int contentLength)16838 static bool RECOIL_DecodeSif(RECOIL *self, uint8_t const *content, int contentLength)
16839 {
16840 	if (contentLength != 2048)
16841 		return false;
16842 	RECOIL_SetSize(self, 256, 32, RECOILResolution_XE2X1);
16843 	self->gtiaColors[4] = 76;
16844 	self->gtiaColors[5] = 204;
16845 	self->gtiaColors[6] = 140;
16846 	self->gtiaColors[8] = 0;
16847 	uint8_t frame1[8192];
16848 	uint8_t frame2[8192];
16849 	for (int y = 0; y < 4; y++) {
16850 		RECOIL_DecodeAtari8Gr12Line(self, NULL, 0, content, y << 8, frame1, y << 11, 0);
16851 		RECOIL_DecodeAtari8Gr12Line(self, NULL, 0, content, 1024 + (y << 8), frame2, y << 11, 0);
16852 	}
16853 	return RECOIL_ApplyAtari8PaletteBlend(self, frame1, frame2);
16854 }
16855 
RECOIL_DecodeDlm(RECOIL * self,uint8_t const * content,int contentLength)16856 static bool RECOIL_DecodeDlm(RECOIL *self, uint8_t const *content, int contentLength)
16857 {
16858 	if (contentLength != 256)
16859 		return false;
16860 	uint8_t characters[176];
16861 	for (int y = 0; y < 16; y++)
16862 		for (int x = 0; x < 11; x++)
16863 			characters[y * 11 + x] = (uint8_t) RECOIL_ToAtari8Char(content[y * 16 + 5 + x]);
16864 	RECOIL_SetSize(self, 88, 128, RECOILResolution_XE1X1);
16865 	uint8_t frame[11264];
16866 	RECOIL_DecodeAtari8Gr0(self, characters, 11, CiResource_atari8_fnt, 0, frame);
16867 	return RECOIL_ApplyAtari8Palette(self, frame);
16868 }
16869 
RECOIL_DecodeAtari8Gr0Screen(RECOIL * self,uint8_t const * content,uint8_t const * font)16870 static void RECOIL_DecodeAtari8Gr0Screen(RECOIL *self, uint8_t const *content, uint8_t const *font)
16871 {
16872 	RECOIL_SetSize(self, 320, 192, RECOILResolution_XE1X1);
16873 	uint8_t frame[61440];
16874 	RECOIL_DecodeAtari8Gr0(self, content, 40, font, 0, frame);
16875 	RECOIL_ApplyAtari8Palette(self, frame);
16876 }
16877 
RECOIL_DecodeGr0(RECOIL * self,uint8_t const * content,int contentLength)16878 static bool RECOIL_DecodeGr0(RECOIL *self, uint8_t const *content, int contentLength)
16879 {
16880 	if (contentLength != 960)
16881 		return false;
16882 	RECOIL_DecodeAtari8Gr0Screen(self, content, CiResource_atari8_fnt);
16883 	return true;
16884 }
16885 
RECOIL_DecodeSge(RECOIL * self,uint8_t const * content,int contentLength)16886 static bool RECOIL_DecodeSge(RECOIL *self, uint8_t const *content, int contentLength)
16887 {
16888 	if (contentLength != 960)
16889 		return false;
16890 	uint8_t font[1024];
16891 	memcpy(font, CiResource_atari8_fnt, 1024);
16892 	for (int i = 0; i < 4; i++) {
16893 		font[1004 + i] = font[728 + i] = 15;
16894 		font[1000 + i] = font[732 + i] = 240;
16895 	}
16896 	RECOIL_DecodeAtari8Gr0Screen(self, content, font);
16897 	return true;
16898 }
16899 
RECOIL_DecodeAsciiArtEditor(RECOIL * self,uint8_t const * content,int contentLength)16900 static bool RECOIL_DecodeAsciiArtEditor(RECOIL *self, uint8_t const *content, int contentLength)
16901 {
16902 	if (contentLength <= 0 || content[contentLength - 1] != 155)
16903 		return false;
16904 	uint8_t characters[1536];
16905 	int columns = 1;
16906 	int x = 0;
16907 	int y = 0;
16908 	for (int contentOffset = 0; contentOffset < contentLength; contentOffset++) {
16909 		int ch = content[contentOffset];
16910 		if (y >= 24)
16911 			return false;
16912 		if (ch == 155) {
16913 			if (columns < x)
16914 				columns = x;
16915 			while (x < 64)
16916 				characters[y * 64 + x++] = 0;
16917 			x = 0;
16918 			y++;
16919 		}
16920 		else {
16921 			if (x >= 64)
16922 				return false;
16923 			characters[y * 64 + x++] = (uint8_t) RECOIL_ToAtari8Char(ch);
16924 		}
16925 	}
16926 	RECOIL_SetSize(self, columns << 3, y << 3, RECOILResolution_XE1X1);
16927 	uint8_t frame[98304];
16928 	RECOIL_DecodeAtari8Gr0(self, characters, 64, CiResource_atari8_fnt, 0, frame);
16929 	return RECOIL_ApplyAtari8Palette(self, frame);
16930 }
16931 
RECOIL_DecodeAll(RECOIL * self,uint8_t const * content,int contentLength)16932 static bool RECOIL_DecodeAll(RECOIL *self, uint8_t const *content, int contentLength)
16933 {
16934 	if ((contentLength & 1023) != 989)
16935 		return false;
16936 	RECOIL_SetPF0123Bak(self, content, contentLength - 5);
16937 	RECOIL_SetSize(self, 320, 192, RECOILResolution_XE2X1);
16938 	uint8_t frame[61440];
16939 	for (int y = 0; y < 24; y++) {
16940 		int fontOffset = 24 + (content[y] << 10);
16941 		if (fontOffset >= contentLength - 965)
16942 			return false;
16943 		RECOIL_DecodeAtari8Gr12Line(self, content, contentLength - 965 + y * 40, content, fontOffset, frame, y * 2560, 0);
16944 	}
16945 	return RECOIL_ApplyAtari8Palette(self, frame);
16946 }
16947 
RECOIL_DecodeKpr(RECOIL * self,uint8_t const * content,int contentLength)16948 static bool RECOIL_DecodeKpr(RECOIL *self, uint8_t const *content, int contentLength)
16949 {
16950 	if (contentLength < 11 || RECOIL_GetAtari8ExecutableOffset(content, contentLength) != 6)
16951 		return false;
16952 	int frames = content[8];
16953 	int cols = content[9];
16954 	int rows = content[10];
16955 	int tiles = frames * cols * rows;
16956 	if (contentLength < 11 + tiles || !RECOIL_SetSize(self, frames * cols << 3, rows << 3, RECOILResolution_XE2X1))
16957 		return false;
16958 	int pixelsOffset = 0;
16959 	for (int y = 0; y < rows << 3; y++) {
16960 		for (int f = 0; f < frames; f++) {
16961 			for (int x = 0; x < cols << 3; x++) {
16962 				int c = content[11 + (f * rows + (y >> 3)) * cols + (x >> 3)];
16963 				c = 11 + tiles + (c << 3) + (y & 7);
16964 				if (c >= contentLength)
16965 					return false;
16966 				c = content[c] >> (~x & 6) & 3;
16967 				self->pixels[pixelsOffset++] = self->atari8Palette[c << 2];
16968 			}
16969 		}
16970 	}
16971 	return true;
16972 }
16973 
RECOIL_DecodeEnvisionCommon(RECOIL * self,uint8_t const * content,int mode,int columns,int rows,int charactersOffset,int const * fontId2Offset)16974 static bool RECOIL_DecodeEnvisionCommon(RECOIL *self, uint8_t const *content, int mode, int columns, int rows, int charactersOffset, int const *fontId2Offset)
16975 {
16976 	int charWidth;
16977 	int charHeight;
16978 	RECOILResolution resolution;
16979 	switch (mode) {
16980 	case 2:
16981 		charWidth = 8;
16982 		charHeight = 8;
16983 		resolution = RECOILResolution_XE1X1;
16984 		break;
16985 	case 3:
16986 		charWidth = 8;
16987 		charHeight = 10;
16988 		resolution = RECOILResolution_XE1X1;
16989 		break;
16990 	case 4:
16991 		charWidth = 8;
16992 		charHeight = 8;
16993 		resolution = RECOILResolution_XE2X1;
16994 		break;
16995 	case 5:
16996 		charWidth = 8;
16997 		charHeight = 16;
16998 		resolution = RECOILResolution_XE2X2;
16999 		break;
17000 	case 6:
17001 		charWidth = 16;
17002 		charHeight = 8;
17003 		resolution = RECOILResolution_XE2X1;
17004 		break;
17005 	case 7:
17006 		charWidth = 16;
17007 		charHeight = 16;
17008 		resolution = RECOILResolution_XE2X2;
17009 		break;
17010 	default:
17011 		return false;
17012 	}
17013 	if (!RECOIL_SetSize(self, columns * charWidth, rows * charHeight, resolution))
17014 		return false;
17015 	uint8_t *frame = (uint8_t *) CiShared_Make(self->width * self->height, sizeof(uint8_t), NULL, NULL);
17016 	for (int row = 0; row < rows; row++) {
17017 		int fontOffset;
17018 		if (fontId2Offset != NULL) {
17019 			fontOffset = fontId2Offset[content[8 + columns * rows + 256 + row]];
17020 			if (fontOffset == 0) {
17021 				CiShared_Release(frame);
17022 				return false;
17023 			}
17024 		}
17025 		else {
17026 			fontOffset = 10 + columns * rows;
17027 		}
17028 		int frameOffset = row * charHeight * self->width;
17029 		switch (mode >> 1) {
17030 		case 1:
17031 			RECOIL_DecodeAtari8Gr0Line(self, content, charactersOffset, content, fontOffset, frame, frameOffset, charHeight);
17032 			break;
17033 		case 2:
17034 			RECOIL_DecodeAtari8Gr12Line(self, content, charactersOffset, content, fontOffset, frame, frameOffset, mode & 1);
17035 			break;
17036 		case 3:
17037 			RECOIL_DecodeAtari8Gr1Line(self, content, charactersOffset, content, fontOffset, frame, frameOffset, mode & 1);
17038 			break;
17039 		default:
17040 			assert(false);
17041 		}
17042 		charactersOffset += columns;
17043 	}
17044 	RECOIL_ApplyAtari8Palette(self, frame);
17045 	CiShared_Release(frame);
17046 	return true;
17047 }
17048 
RECOIL_DecodeEnvision(RECOIL * self,uint8_t const * content,int contentLength)17049 static bool RECOIL_DecodeEnvision(RECOIL *self, uint8_t const *content, int contentLength)
17050 {
17051 	if (contentLength < 1505)
17052 		return false;
17053 	int columns = content[1] + 1;
17054 	int rows = content[2] + 1;
17055 	if (rows > 204)
17056 		return false;
17057 	int fontOffset = 8 + columns * rows + 463;
17058 	if (contentLength < fontOffset || contentLength != fontOffset + content[fontOffset - 1] * 1033)
17059 		return false;
17060 	int fontId2Offset[256] = { 0 };
17061 	for (; fontOffset < contentLength; fontOffset += 1033)
17062 		fontId2Offset[content[fontOffset]] = fontOffset + 1 + 8;
17063 	RECOIL_SetPF0123Bak(self, content, 3);
17064 	return RECOIL_DecodeEnvisionCommon(self, content, content[0] & 127, columns, rows, 8, fontId2Offset);
17065 }
17066 
RECOIL_DecodeEnvisionPC(RECOIL * self,uint8_t const * content,int contentLength)17067 static bool RECOIL_DecodeEnvisionPC(RECOIL *self, uint8_t const *content, int contentLength)
17068 {
17069 	if (contentLength < 1035 || content[2] >= 128)
17070 		return false;
17071 	int columns = content[1] | content[2] << 8;
17072 	int rows = content[3] | content[4] << 8;
17073 	int contentOffset = 10 + columns * rows + 1024;
17074 	while (contentOffset < contentLength) {
17075 		switch (content[contentOffset++]) {
17076 		case 0:
17077 			break;
17078 		case 1:
17079 			if (contentOffset + 6 >= contentLength || content[contentOffset + 1] >= 5 || content[contentOffset + 3] >= 5 || content[contentOffset + 5] >= 5)
17080 				return false;
17081 			contentOffset += (content[contentOffset] + (content[contentOffset + 1] << 8)) * (content[contentOffset + 2] + (content[contentOffset + 3] << 8)) * (content[contentOffset + 4] + (content[contentOffset + 5] << 8) + 1);
17082 			break;
17083 		case 2:
17084 			contentOffset += columns * rows;
17085 			break;
17086 		case 3:
17087 			contentOffset += 1027;
17088 			break;
17089 		default:
17090 			return false;
17091 		}
17092 	}
17093 	if (contentOffset > contentLength)
17094 		return false;
17095 	RECOIL_SetBakPF0123(self, content, 5);
17096 	return RECOIL_DecodeEnvisionCommon(self, content, content[0], columns, rows, 10, NULL);
17097 }
17098 
RECOIL_DecodeMcs(RECOIL * self,uint8_t const * content,int contentLength)17099 static bool RECOIL_DecodeMcs(RECOIL *self, uint8_t const *content, int contentLength)
17100 {
17101 	if (contentLength != 10185)
17102 		return false;
17103 	RECOIL_SetSize(self, 320, 192, RECOILResolution_XE2X1);
17104 	uint8_t frame[61440];
17105 	for (int y = 0; y < 192; y++) {
17106 		int fontOffset = 9 + (y / 24 << 10);
17107 		for (int x = 0; x < 320; x++) {
17108 			int ch = content[8201 + (y >> 3) * 40 + (x >> 3)];
17109 			int c;
17110 			switch (content[fontOffset + ((ch & 127) << 3) + (y & 7)] >> (~x & 6) & 3) {
17111 			case 0:
17112 				c = x / 80;
17113 				int pmgBit = (x >> 3) % 10;
17114 				int pmgOffset;
17115 				if (pmgBit < 8) {
17116 					pmgBit = 7 - pmgBit;
17117 					pmgOffset = 9305 + (c << 7);
17118 				}
17119 				else {
17120 					pmgBit = c << 1 | (pmgBit ^ 9);
17121 					pmgOffset = 9177;
17122 				}
17123 				if ((content[pmgOffset + (y >> 1)] >> pmgBit & 1) == 0)
17124 					c = 8;
17125 				break;
17126 			case 1:
17127 				c = 4;
17128 				break;
17129 			case 2:
17130 				c = 5;
17131 				break;
17132 			default:
17133 				c = 6 + (ch >> 7);
17134 				break;
17135 			}
17136 			frame[y * 320 + x] = (uint8_t) (content[c] & 254);
17137 		}
17138 	}
17139 	return RECOIL_ApplyAtari8Palette(self, frame);
17140 }
17141 
RECOIL_Gr12GtiaNibbleToGr8(int nibble,int ch,bool gtia10)17142 static int RECOIL_Gr12GtiaNibbleToGr8(int nibble, int ch, bool gtia10)
17143 {
17144 	switch (nibble) {
17145 	case 0:
17146 	case 1:
17147 	case 4:
17148 	case 5:
17149 		return 0;
17150 	case 2:
17151 	case 6:
17152 		return 1;
17153 	case 3:
17154 	case 7:
17155 		return (ch & 128) == 0 ? 2 : 3;
17156 	case 8:
17157 		return gtia10 ? 8 : 4;
17158 	case 9:
17159 		return 4;
17160 	case 10:
17161 		return 5;
17162 	case 11:
17163 		return (ch & 128) == 0 ? 6 : 7;
17164 	case 12:
17165 		return gtia10 || (ch & 128) == 0 ? 8 : 12;
17166 	case 13:
17167 		return (ch & 128) == 0 ? 8 : 12;
17168 	case 14:
17169 		return (ch & 128) == 0 ? 9 : 13;
17170 	case 15:
17171 		return (ch & 128) == 0 ? 10 : 15;
17172 	default:
17173 		return 0;
17174 	}
17175 }
17176 
RECOIL_Gr12GtiaByteToGr8(int b,int ch,bool gtia10)17177 static int RECOIL_Gr12GtiaByteToGr8(int b, int ch, bool gtia10)
17178 {
17179 	return RECOIL_Gr12GtiaNibbleToGr8(b >> 4, ch, gtia10) << 4 | RECOIL_Gr12GtiaNibbleToGr8(b & 15, ch, gtia10);
17180 }
17181 
RECOIL_DecodeIceFrame(const RECOIL * self,uint8_t const * content,int charactersOffset,int fontOffset,uint8_t * frame,IceFrameMode mode)17182 static void RECOIL_DecodeIceFrame(const RECOIL *self, uint8_t const *content, int charactersOffset, int fontOffset, uint8_t *frame, IceFrameMode mode)
17183 {
17184 	int doubleLine;
17185 	switch (mode) {
17186 	case IceFrameMode_GR13_GTIA9:
17187 	case IceFrameMode_GR13_GTIA10:
17188 	case IceFrameMode_GR13_GTIA11:
17189 		doubleLine = 1;
17190 		break;
17191 	default:
17192 		doubleLine = 0;
17193 		break;
17194 	}
17195 	int frameOffset = 0;
17196 	uint8_t bitmap[40];
17197 	for (int y = 0; y < self->height; y++) {
17198 		for (int col = 0; col < self->width >> 3; col++) {
17199 			int ch;
17200 			switch (charactersOffset) {
17201 			case -1:
17202 				;
17203 				static const uint8_t ROW2CHAR1[16] = { 64, 0, 32, 96, 192, 128, 160, 224, 64, 0, 32, 96, 192, 128, 160, 224 };
17204 				ch = ROW2CHAR1[y >> (3 + doubleLine)] + col;
17205 				break;
17206 			case -2:
17207 				;
17208 				static const uint8_t ROW2CHAR2[16] = { 64, 0, 32, 96, 192, 128, 160, 224, 192, 128, 160, 224, 64, 0, 32, 96 };
17209 				ch = ROW2CHAR2[y >> (3 + doubleLine)] + col;
17210 				break;
17211 			default:
17212 				ch = (y / 24 << 8) + content[charactersOffset + (y >> 3) * 40 + col];
17213 				break;
17214 			}
17215 			int b = content[fontOffset + ((ch & -129) << 3) + (y >> doubleLine & 7)];
17216 			switch (mode) {
17217 			case IceFrameMode_GR0:
17218 			case IceFrameMode_GR0_GTIA9:
17219 			case IceFrameMode_GR0_GTIA10:
17220 			case IceFrameMode_GR0_GTIA11:
17221 				if (charactersOffset < 0 && (ch & 128) != 0)
17222 					b ^= 255;
17223 				bitmap[col] = (uint8_t) b;
17224 				break;
17225 			case IceFrameMode_GR12:
17226 				for (int x = col == 0 ? self->leftSkip : 0; x < 8; x++) {
17227 					int c = b >> (~x & 6) & 3;
17228 					int gr12Registers = (ch & 128) == 0 ? 25928 : 30024;
17229 					frame[frameOffset + (col << 3) + x - self->leftSkip] = self->gtiaColors[gr12Registers >> (c << 2) & 15];
17230 				}
17231 				break;
17232 			case IceFrameMode_GR12_GTIA9:
17233 			case IceFrameMode_GR12_GTIA11:
17234 			case IceFrameMode_GR13_GTIA9:
17235 			case IceFrameMode_GR13_GTIA11:
17236 				bitmap[col] = (uint8_t) RECOIL_Gr12GtiaByteToGr8(b, ch, false);
17237 				break;
17238 			case IceFrameMode_GR12_GTIA10:
17239 			case IceFrameMode_GR13_GTIA10:
17240 				bitmap[col] = (uint8_t) RECOIL_Gr12GtiaByteToGr8(b, ch, true);
17241 				break;
17242 			}
17243 		}
17244 		switch (mode) {
17245 		case IceFrameMode_GR0:
17246 			RECOIL_DecodeAtari8Gr8(self, bitmap, 0, frame, frameOffset, 1);
17247 			break;
17248 		case IceFrameMode_GR12:
17249 			for (int x = self->width; x < self->width + self->leftSkip; x++)
17250 				frame[frameOffset + x] = self->gtiaColors[8];
17251 			break;
17252 		case IceFrameMode_GR0_GTIA9:
17253 		case IceFrameMode_GR12_GTIA9:
17254 		case IceFrameMode_GR13_GTIA9:
17255 			RECOIL_DecodeAtari8Gr9(self, bitmap, 0, 0, frame, frameOffset, 0, self->width, 1);
17256 			break;
17257 		case IceFrameMode_GR0_GTIA10:
17258 		case IceFrameMode_GR12_GTIA10:
17259 		case IceFrameMode_GR13_GTIA10:
17260 			RECOIL_DecodeAtari8Gr10(self, bitmap, 0, frame, frameOffset, 0, 1);
17261 			break;
17262 		case IceFrameMode_GR0_GTIA11:
17263 		case IceFrameMode_GR12_GTIA11:
17264 		case IceFrameMode_GR13_GTIA11:
17265 			RECOIL_DecodeAtari8Gr11(self, bitmap, 0, frame, frameOffset, 0, 1);
17266 			break;
17267 		}
17268 		frameOffset += self->width;
17269 	}
17270 }
17271 
RECOIL_VerifyIce(RECOIL * self,uint8_t const * content,int contentLength,bool font,int fontLength,int imageLength,RECOILResolution resolution)17272 static bool RECOIL_VerifyIce(RECOIL *self, uint8_t const *content, int contentLength, bool font, int fontLength, int imageLength, RECOILResolution resolution)
17273 {
17274 	if (font) {
17275 		if (contentLength != fontLength)
17276 			return false;
17277 		RECOIL_SetSize(self, 256, 128, resolution);
17278 	}
17279 	else {
17280 		if (contentLength != imageLength || content[0] != 1)
17281 			return false;
17282 		RECOIL_SetSize(self, 320, 192, resolution);
17283 	}
17284 	return true;
17285 }
17286 
RECOIL_DecodeIce20Frame(const RECOIL * self,uint8_t const * content,bool second,int fontOffset,uint8_t * frame,int mode)17287 static void RECOIL_DecodeIce20Frame(const RECOIL *self, uint8_t const *content, bool second, int fontOffset, uint8_t *frame, int mode)
17288 {
17289 	uint8_t bitmap[32];
17290 	for (int y = 0; y < 288; y++) {
17291 		int row = y >> 5;
17292 		int c = (second ? row / 3 : row % 3) + 1;
17293 		for (int col = 0; col < 32; col++) {
17294 			int ch = ((y & 24) << 1) + (col >> 1);
17295 			int b = content[fontOffset + (ch << 3) + (y & 7)];
17296 			b = (col & 1) == 0 ? b >> 4 : b & 15;
17297 			b = ((b & 8) << 3 | (b & 4) << 2 | (b & 2) << 1 | (b & 1)) * c;
17298 			if (mode == 10) {
17299 				if ((b & 112) == 64)
17300 					b = 128 + (b & 15);
17301 				if ((b & 7) == 4)
17302 					b = (b & 240) + 8;
17303 			}
17304 			bitmap[col] = (uint8_t) b;
17305 		}
17306 		switch (mode) {
17307 		case 9:
17308 			RECOIL_DecodeAtari8Gr9(self, bitmap, 0, 0, frame, y << 8, 0, 256, 1);
17309 			break;
17310 		case 10:
17311 			RECOIL_DecodeAtari8Gr10(self, bitmap, 0, frame, y << 8, 0, 1);
17312 			break;
17313 		case 11:
17314 			RECOIL_DecodeAtari8Gr11(self, bitmap, 0, frame, y << 8, 0, 1);
17315 			break;
17316 		default:
17317 			assert(false);
17318 		}
17319 	}
17320 }
17321 
RECOIL_DecodeAtari8Ice(RECOIL * self,uint8_t const * content,int contentLength,bool font,int mode)17322 static bool RECOIL_DecodeAtari8Ice(RECOIL *self, uint8_t const *content, int contentLength, bool font, int mode)
17323 {
17324 	uint8_t frame1[73728];
17325 	uint8_t frame2[73728];
17326 	switch (mode) {
17327 	case 0:
17328 		if (contentLength != 2053)
17329 			return false;
17330 		RECOIL_SetSize(self, 256, 128, RECOILResolution_XE1X1);
17331 		self->gtiaColors[5] = (uint8_t) (content[1] & 254);
17332 		self->gtiaColors[6] = (uint8_t) (content[3] & 254);
17333 		RECOIL_DecodeIceFrame(self, content, -1, 5, frame1, IceFrameMode_GR0);
17334 		self->gtiaColors[5] = (uint8_t) (content[2] & 254);
17335 		self->gtiaColors[6] = (uint8_t) (content[4] & 254);
17336 		RECOIL_DecodeIceFrame(self, content, -2, 1029, frame2, IceFrameMode_GR0);
17337 		break;
17338 	case 1:
17339 		if (!RECOIL_VerifyIce(self, content, contentLength, font, 2054, 18310, RECOILResolution_XE2X1))
17340 			return false;
17341 		RECOIL_SetBakPF0123(self, content, 1);
17342 		RECOIL_DecodeIceFrame(self, content, font ? -1 : 16390, 6, frame1, IceFrameMode_GR12);
17343 		RECOIL_DecodeIceFrame(self, content, font ? -2 : 17350, 1030, frame2, IceFrameMode_GR12);
17344 		break;
17345 	case 2:
17346 		if (!RECOIL_VerifyIce(self, content, contentLength, font, 2058, 18314, RECOILResolution_XE2X1))
17347 			return false;
17348 		self->gtiaColors[8] = (uint8_t) (content[1] & 254);
17349 		RECOIL_SetPF0123Even(self, content, 2);
17350 		RECOIL_DecodeIceFrame(self, content, font ? -1 : 16394, 10, frame1, IceFrameMode_GR12);
17351 		RECOIL_SetPF0123Even(self, content, 3);
17352 		RECOIL_DecodeIceFrame(self, content, font ? -2 : 17354, 1034, frame2, IceFrameMode_GR12);
17353 		break;
17354 	case 3:
17355 		if (font) {
17356 			if (contentLength != 2055)
17357 				return false;
17358 			RECOIL_SetSize(self, 256, 128, RECOILResolution_XE1X1);
17359 		}
17360 		else {
17361 			if (contentLength != 17351 || content[0] != 3)
17362 				return false;
17363 			RECOIL_SetSize(self, 320, 192, RECOILResolution_XE1X1);
17364 		}
17365 		RECOIL_SetPF21(self, content, 1);
17366 		RECOIL_DecodeIceFrame(self, content, font ? -1 : 16391, 7, frame1, IceFrameMode_GR0);
17367 		RECOIL_SetBakPF0123(self, content, 2);
17368 		self->gtiaColors[8] = (uint8_t) (content[1] & 254);
17369 		RECOIL_DecodeIceFrame(self, content, font ? -2 : 16391, 1031, frame2, IceFrameMode_GR12);
17370 		break;
17371 	case 4:
17372 		if (contentLength != 2058)
17373 			return false;
17374 		RECOIL_SetSize(self, 256, 128, RECOILResolution_XE4X1);
17375 		self->leftSkip = 2;
17376 		RECOIL_SetGtiaColors(self, content, 1);
17377 		RECOIL_DecodeIceFrame(self, content, -1, 10, frame1, IceFrameMode_GR0_GTIA10);
17378 		RECOIL_DecodeIceFrame(self, content, -2, 1034, frame2, IceFrameMode_GR0_GTIA10);
17379 		break;
17380 	case 5:
17381 		if (contentLength != 2065 && contentLength != 2066)
17382 			return false;
17383 		RECOIL_SetSize(self, 256, 128, RECOILResolution_XE4X1);
17384 		self->leftSkip = 2;
17385 		self->gtiaColors[0] = (uint8_t) (content[1] & 254);
17386 		for (int i = 0; i < 8; i++)
17387 			RECOIL_SetGtiaColor(self, i + 1, content[2 + i * 2]);
17388 		if (contentLength == 2065) {
17389 			RECOIL_DecodeIceFrame(self, content, -1, 17, frame1, IceFrameMode_GR0_GTIA10);
17390 			for (int i = 0; i < 7; i++)
17391 				RECOIL_SetGtiaColor(self, i + 1, content[3 + i * 2]);
17392 			RECOIL_DecodeIceFrame(self, content, -2, 1041, frame2, IceFrameMode_GR0_GTIA10);
17393 		}
17394 		else {
17395 			RECOIL_DecodeIceFrame(self, content, -1, 18, frame1, IceFrameMode_GR0_GTIA10);
17396 			for (int i = 0; i < 8; i++)
17397 				RECOIL_SetGtiaColor(self, i + 1, content[3 + i * 2]);
17398 			RECOIL_DecodeIceFrame(self, content, -2, 1042, frame2, IceFrameMode_GR0_GTIA10);
17399 		}
17400 		break;
17401 	case 6:
17402 		if (contentLength != 2051)
17403 			return false;
17404 		RECOIL_SetSize(self, 256, 128, RECOILResolution_XE4X1);
17405 		self->gtiaColors[8] = (uint8_t) (content[1] & 254);
17406 		RECOIL_DecodeIceFrame(self, content, -1, 3, frame1, IceFrameMode_GR0_GTIA9);
17407 		self->gtiaColors[8] = (uint8_t) (content[2] & 254);
17408 		RECOIL_DecodeIceFrame(self, content, -2, 1027, frame2, IceFrameMode_GR0_GTIA9);
17409 		break;
17410 	case 7:
17411 		if (contentLength != 2051)
17412 			return false;
17413 		RECOIL_SetSize(self, 256, 128, RECOILResolution_XE4X1);
17414 		self->gtiaColors[8] = (uint8_t) (content[1] & 254);
17415 		RECOIL_DecodeIceFrame(self, content, -1, 3, frame1, IceFrameMode_GR0_GTIA11);
17416 		self->gtiaColors[8] = (uint8_t) (content[2] & 254);
17417 		RECOIL_DecodeIceFrame(self, content, -2, 1027, frame2, IceFrameMode_GR0_GTIA11);
17418 		break;
17419 	case 8:
17420 		if (contentLength != 2058)
17421 			return false;
17422 		RECOIL_SetSize(self, 256, 128, RECOILResolution_XE2X1);
17423 		self->leftSkip = 1;
17424 		self->gtiaColors[8] = (uint8_t) (content[1] & 254);
17425 		RECOIL_DecodeIceFrame(self, content, -1, 10, frame1, IceFrameMode_GR0_GTIA9);
17426 		RECOIL_SetGtiaColors(self, content, 1);
17427 		RECOIL_DecodeIceFrame(self, content, -2, 1034, frame2, IceFrameMode_GR0_GTIA10);
17428 		break;
17429 	case 9:
17430 		if (contentLength != 2058)
17431 			return false;
17432 		RECOIL_SetSize(self, 256, 128, RECOILResolution_XE2X1);
17433 		self->leftSkip = 1;
17434 		self->gtiaColors[8] = (uint8_t) (content[1] & 254);
17435 		RECOIL_DecodeIceFrame(self, content, -1, 10, frame1, IceFrameMode_GR0_GTIA11);
17436 		self->gtiaColors[0] = 0;
17437 		RECOIL_SetPM123PF0123Bak(self, content, 2);
17438 		RECOIL_DecodeIceFrame(self, content, -2, 1034, frame2, IceFrameMode_GR0_GTIA10);
17439 		break;
17440 	case 10:
17441 		if (contentLength != 2051)
17442 			return false;
17443 		RECOIL_SetSize(self, 256, 128, RECOILResolution_XE4X1);
17444 		self->gtiaColors[8] = (uint8_t) (content[1] & 254);
17445 		RECOIL_DecodeIceFrame(self, content, -1, 3, frame1, IceFrameMode_GR0_GTIA9);
17446 		self->gtiaColors[8] = (uint8_t) (content[2] & 254);
17447 		RECOIL_DecodeIceFrame(self, content, -2, 1027, frame2, IceFrameMode_GR0_GTIA11);
17448 		break;
17449 	case 11:
17450 		if (contentLength != 2051)
17451 			return false;
17452 		RECOIL_SetSize(self, 256, 128, RECOILResolution_XE1X1);
17453 		self->gtiaColors[6] = 0;
17454 		self->gtiaColors[5] = (uint8_t) (content[2] & 254);
17455 		RECOIL_DecodeIceFrame(self, content, -1, 3, frame1, IceFrameMode_GR0);
17456 		self->gtiaColors[8] = (uint8_t) (content[1] & 254);
17457 		RECOIL_DecodeIceFrame(self, content, -2, 1027, frame2, IceFrameMode_GR0_GTIA11);
17458 		break;
17459 	case 12:
17460 		if (contentLength != 2051)
17461 			return false;
17462 		RECOIL_SetSize(self, 256, 128, RECOILResolution_XE1X1);
17463 		RECOIL_SetPF21(self, content, 1);
17464 		RECOIL_DecodeIceFrame(self, content, -1, 3, frame1, IceFrameMode_GR0);
17465 		self->gtiaColors[8] = (uint8_t) (content[1] & 254);
17466 		RECOIL_DecodeIceFrame(self, content, -2, 1027, frame2, IceFrameMode_GR0_GTIA9);
17467 		break;
17468 	case 13:
17469 		if (contentLength != 2059)
17470 			return false;
17471 		RECOIL_SetSize(self, 256, 128, RECOILResolution_XE1X1);
17472 		RECOIL_SetPF21(self, content, 1);
17473 		self->gtiaColors[8] = (uint8_t) (content[1] & 254);
17474 		RECOIL_DecodeIceFrame(self, content, -1, 11, frame1, IceFrameMode_GR0);
17475 		self->leftSkip = 2;
17476 		self->gtiaColors[0] = (uint8_t) (content[1] & 254);
17477 		RECOIL_SetPM123PF0123Bak(self, content, 3);
17478 		RECOIL_DecodeIceFrame(self, content, -2, 1035, frame2, IceFrameMode_GR0_GTIA10);
17479 		break;
17480 	case 14:
17481 		if (contentLength != 2054)
17482 			return false;
17483 		RECOIL_SetSize(self, 256, 128, RECOILResolution_XE2X1);
17484 		RECOIL_SetBakPF0123(self, content, 1);
17485 		RECOIL_DecodeIceFrame(self, content, -2, 1030, frame2, IceFrameMode_GR12_GTIA11);
17486 		self->gtiaColors[8] = 0;
17487 		RECOIL_DecodeIceFrame(self, content, -1, 6, frame1, IceFrameMode_GR12);
17488 		break;
17489 	case 15:
17490 		if (contentLength != 2054)
17491 			return false;
17492 		RECOIL_SetSize(self, 256, 128, RECOILResolution_XE2X1);
17493 		RECOIL_SetBakPF0123(self, content, 1);
17494 		RECOIL_DecodeIceFrame(self, content, -1, 6, frame1, IceFrameMode_GR12);
17495 		RECOIL_DecodeIceFrame(self, content, -2, 1030, frame2, IceFrameMode_GR12_GTIA9);
17496 		break;
17497 	case 16:
17498 		if (contentLength != 2058)
17499 			return false;
17500 		RECOIL_SetSize(self, 256, 128, RECOILResolution_XE2X1);
17501 		self->leftSkip = 2;
17502 		RECOIL_SetGtiaColors(self, content, 1);
17503 		RECOIL_DecodeIceFrame(self, content, -2, 1034, frame2, IceFrameMode_GR12_GTIA10);
17504 		self->leftSkip = 0;
17505 		self->gtiaColors[8] = (uint8_t) (content[1] & 254);
17506 		RECOIL_DecodeIceFrame(self, content, -1, 10, frame1, IceFrameMode_GR12);
17507 		break;
17508 	case 17:
17509 		if (!RECOIL_VerifyIce(self, content, contentLength, font, 2054, 17350, RECOILResolution_XE2X1))
17510 			return false;
17511 		RECOIL_SetBakPF0123(self, content, 1);
17512 		RECOIL_DecodeIceFrame(self, content, font ? -2 : 16390, 1030, frame2, IceFrameMode_GR0_GTIA11);
17513 		self->gtiaColors[8] = 0;
17514 		RECOIL_DecodeIceFrame(self, content, font ? -1 : 16390, 6, frame1, IceFrameMode_GR12);
17515 		break;
17516 	case 18:
17517 		if (!RECOIL_VerifyIce(self, content, contentLength, font, 2054, 17350, RECOILResolution_XE2X1))
17518 			return false;
17519 		RECOIL_SetBakPF0123(self, content, 1);
17520 		RECOIL_DecodeIceFrame(self, content, font ? -1 : 16390, 6, frame1, IceFrameMode_GR12);
17521 		RECOIL_DecodeIceFrame(self, content, font ? -2 : 16390, 1030, frame2, IceFrameMode_GR0_GTIA9);
17522 		break;
17523 	case 19:
17524 		if (!RECOIL_VerifyIce(self, content, contentLength, font, 2058, 17354, RECOILResolution_XE2X1))
17525 			return false;
17526 		RECOIL_SetPF0123Bak(self, content, 5);
17527 		self->gtiaColors[8] = (uint8_t) (content[1] & 254);
17528 		RECOIL_DecodeIceFrame(self, content, font ? -1 : 16394, 10, frame1, IceFrameMode_GR12);
17529 		self->leftSkip = 2;
17530 		RECOIL_SetGtiaColors(self, content, 1);
17531 		RECOIL_DecodeIceFrame(self, content, font ? -2 : 16394, 1034, frame2, IceFrameMode_GR0_GTIA10);
17532 		break;
17533 	case 22:
17534 		if (contentLength != 2058)
17535 			return false;
17536 		RECOIL_SetSize(self, 256, 256, RECOILResolution_XE4X2);
17537 		self->leftSkip = 2;
17538 		RECOIL_SetGtiaColors(self, content, 1);
17539 		RECOIL_DecodeIceFrame(self, content, -1, 10, frame1, IceFrameMode_GR13_GTIA10);
17540 		RECOIL_DecodeIceFrame(self, content, -2, 1034, frame2, IceFrameMode_GR13_GTIA10);
17541 		break;
17542 	case 23:
17543 		if (contentLength != 2065)
17544 			return false;
17545 		RECOIL_SetSize(self, 256, 256, RECOILResolution_XE4X2);
17546 		self->leftSkip = 2;
17547 		self->gtiaColors[0] = (uint8_t) (content[1] & 254);
17548 		for (int i = 0; i < 8; i++)
17549 			RECOIL_SetGtiaColor(self, i + 1, content[2 + i * 2]);
17550 		RECOIL_DecodeIceFrame(self, content, -1, 17, frame1, IceFrameMode_GR13_GTIA10);
17551 		for (int i = 0; i < 7; i++)
17552 			RECOIL_SetGtiaColor(self, i + 1, content[3 + i * 2]);
17553 		RECOIL_DecodeIceFrame(self, content, -2, 1041, frame2, IceFrameMode_GR13_GTIA10);
17554 		break;
17555 	case 24:
17556 		if (contentLength != 2051)
17557 			return false;
17558 		RECOIL_SetSize(self, 256, 256, RECOILResolution_XE4X2);
17559 		self->gtiaColors[8] = (uint8_t) (content[1] & 254);
17560 		RECOIL_DecodeIceFrame(self, content, -1, 3, frame1, IceFrameMode_GR13_GTIA9);
17561 		self->gtiaColors[8] = (uint8_t) (content[2] & 254);
17562 		RECOIL_DecodeIceFrame(self, content, -2, 1027, frame2, IceFrameMode_GR13_GTIA9);
17563 		break;
17564 	case 25:
17565 		if (contentLength != 2051)
17566 			return false;
17567 		RECOIL_SetSize(self, 256, 256, RECOILResolution_XE4X2);
17568 		self->gtiaColors[8] = (uint8_t) (content[1] & 254);
17569 		RECOIL_DecodeIceFrame(self, content, -1, 3, frame1, IceFrameMode_GR13_GTIA11);
17570 		self->gtiaColors[8] = (uint8_t) (content[2] & 254);
17571 		RECOIL_DecodeIceFrame(self, content, -2, 1027, frame2, IceFrameMode_GR13_GTIA11);
17572 		break;
17573 	case 26:
17574 		if (contentLength != 2058)
17575 			return false;
17576 		RECOIL_SetSize(self, 256, 256, RECOILResolution_XE2X2);
17577 		self->leftSkip = 1;
17578 		self->gtiaColors[8] = (uint8_t) (content[1] & 254);
17579 		RECOIL_DecodeIceFrame(self, content, -1, 10, frame1, IceFrameMode_GR13_GTIA9);
17580 		RECOIL_SetGtiaColors(self, content, 1);
17581 		RECOIL_DecodeIceFrame(self, content, -2, 1034, frame2, IceFrameMode_GR13_GTIA10);
17582 		break;
17583 	case 27:
17584 		if (contentLength != 2058)
17585 			return false;
17586 		RECOIL_SetSize(self, 256, 256, RECOILResolution_XE2X2);
17587 		self->leftSkip = 1;
17588 		self->gtiaColors[8] = (uint8_t) (content[1] & 254);
17589 		RECOIL_DecodeIceFrame(self, content, -1, 10, frame1, IceFrameMode_GR13_GTIA11);
17590 		self->gtiaColors[0] = 0;
17591 		RECOIL_SetPM123PF0123Bak(self, content, 2);
17592 		RECOIL_DecodeIceFrame(self, content, -2, 1034, frame2, IceFrameMode_GR13_GTIA10);
17593 		break;
17594 	case 28:
17595 		if (contentLength != 2051)
17596 			return false;
17597 		RECOIL_SetSize(self, 256, 256, RECOILResolution_XE4X2);
17598 		self->gtiaColors[8] = (uint8_t) (content[1] & 254);
17599 		RECOIL_DecodeIceFrame(self, content, -1, 3, frame1, IceFrameMode_GR13_GTIA9);
17600 		self->gtiaColors[8] = (uint8_t) (content[2] & 254);
17601 		RECOIL_DecodeIceFrame(self, content, -2, 1027, frame2, IceFrameMode_GR13_GTIA11);
17602 		break;
17603 	case 31:
17604 		if (contentLength != 1032)
17605 			return false;
17606 		RECOIL_SetSize(self, 256, 288, RECOILResolution_XE4X1);
17607 		self->leftSkip = 2;
17608 		static const uint8_t ICE20_GTIA11_COLORS[7] = { 0, 1, 2, 3, 5, 7, 8 };
17609 		for (int i = 0; i < 7; i++)
17610 			RECOIL_SetGtiaColor(self, ICE20_GTIA11_COLORS[i], content[1 + i]);
17611 		RECOIL_DecodeIce20Frame(self, content, false, 8, frame1, 10);
17612 		RECOIL_DecodeIce20Frame(self, content, true, 520, frame2, 10);
17613 		break;
17614 	case 32:
17615 		if (contentLength != 1038)
17616 			return false;
17617 		RECOIL_SetSize(self, 256, 288, RECOILResolution_XE4X1);
17618 		self->leftSkip = 2;
17619 		self->gtiaColors[0] = (uint8_t) (content[1] & 254);
17620 		for (int i = 1; i < 7; i++)
17621 			RECOIL_SetGtiaColor(self, ICE20_GTIA11_COLORS[i], content[i * 2]);
17622 		RECOIL_DecodeIce20Frame(self, content, false, 14, frame1, 10);
17623 		for (int i = 1; i < 7; i++)
17624 			RECOIL_SetGtiaColor(self, ICE20_GTIA11_COLORS[i], content[1 + i * 2]);
17625 		RECOIL_DecodeIce20Frame(self, content, true, 526, frame2, 10);
17626 		break;
17627 	case 33:
17628 		if (contentLength != 1027)
17629 			return false;
17630 		RECOIL_SetSize(self, 256, 288, RECOILResolution_XE4X1);
17631 		self->gtiaColors[8] = (uint8_t) (content[1] & 254);
17632 		RECOIL_DecodeIce20Frame(self, content, false, 3, frame1, 9);
17633 		self->gtiaColors[8] = (uint8_t) (content[2] & 254);
17634 		RECOIL_DecodeIce20Frame(self, content, true, 515, frame2, 9);
17635 		break;
17636 	case 34:
17637 		if (contentLength != 1027)
17638 			return false;
17639 		RECOIL_SetSize(self, 256, 288, RECOILResolution_XE4X1);
17640 		self->gtiaColors[8] = (uint8_t) (content[1] & 254);
17641 		RECOIL_DecodeIce20Frame(self, content, false, 3, frame1, 11);
17642 		self->gtiaColors[8] = (uint8_t) (content[2] & 254);
17643 		RECOIL_DecodeIce20Frame(self, content, true, 515, frame2, 11);
17644 		break;
17645 	case 35:
17646 		if (contentLength != 1032)
17647 			return false;
17648 		RECOIL_SetSize(self, 256, 288, RECOILResolution_XE2X1);
17649 		self->leftSkip = 1;
17650 		self->gtiaColors[8] = (uint8_t) (content[1] & 254);
17651 		RECOIL_DecodeIce20Frame(self, content, false, 8, frame1, 9);
17652 		for (int i = 0; i < 7; i++)
17653 			RECOIL_SetGtiaColor(self, ICE20_GTIA11_COLORS[i], content[1 + i]);
17654 		RECOIL_DecodeIce20Frame(self, content, true, 520, frame2, 10);
17655 		break;
17656 	case 36:
17657 		if (contentLength != 1032)
17658 			return false;
17659 		RECOIL_SetSize(self, 256, 288, RECOILResolution_XE2X1);
17660 		self->leftSkip = 1;
17661 		self->gtiaColors[8] = (uint8_t) (content[1] & 254);
17662 		RECOIL_DecodeIce20Frame(self, content, false, 8, frame1, 11);
17663 		self->gtiaColors[0] = 0;
17664 		for (int i = 1; i < 7; i++)
17665 			RECOIL_SetGtiaColor(self, ICE20_GTIA11_COLORS[i], content[1 + i]);
17666 		RECOIL_DecodeIce20Frame(self, content, true, 520, frame2, 10);
17667 		break;
17668 	case 37:
17669 		if (contentLength != 1027)
17670 			return false;
17671 		RECOIL_SetSize(self, 256, 288, RECOILResolution_XE4X1);
17672 		self->gtiaColors[8] = (uint8_t) (content[1] & 254);
17673 		RECOIL_DecodeIce20Frame(self, content, false, 3, frame1, 9);
17674 		self->gtiaColors[8] = (uint8_t) (content[2] & 254);
17675 		RECOIL_DecodeIce20Frame(self, content, true, 515, frame2, 11);
17676 		break;
17677 	default:
17678 		return false;
17679 	}
17680 	return RECOIL_ApplyAtari8PaletteBlend(self, frame1, frame2);
17681 }
17682 
RECOIL_DecodeIp2(RECOIL * self,uint8_t const * content,int contentLength)17683 static bool RECOIL_DecodeIp2(RECOIL *self, uint8_t const *content, int contentLength)
17684 {
17685 	if (contentLength != 17358 || content[0] != 1)
17686 		return false;
17687 	RECOIL_SetSize(self, 320, 192, RECOILResolution_XE2X1);
17688 	self->gtiaColors[8] = (uint8_t) (content[1] & 254);
17689 	self->gtiaColors[4] = (uint8_t) (content[5] & 254);
17690 	self->gtiaColors[5] = (uint8_t) (content[7] & 254);
17691 	self->gtiaColors[6] = (uint8_t) (content[9] & 254);
17692 	self->gtiaColors[7] = (uint8_t) (content[11] & 254);
17693 	uint8_t frame1[61440];
17694 	RECOIL_DecodeIceFrame(self, content, 16398, 14, frame1, IceFrameMode_GR12);
17695 	self->leftSkip = 2;
17696 	for (int i = 0; i < 4; i++) {
17697 		self->gtiaColors[i] = (uint8_t) (content[1 + i] & 254);
17698 		RECOIL_SetGtiaColor(self, 4 + i, content[6 + i * 2]);
17699 	}
17700 	RECOIL_SetGtiaColor(self, 8, content[13]);
17701 	uint8_t frame2[61440];
17702 	RECOIL_DecodeIceFrame(self, content, 16398, 1038, frame2, IceFrameMode_GR0_GTIA10);
17703 	return RECOIL_ApplyAtari8PaletteBlend(self, frame1, frame2);
17704 }
17705 
RECOIL_DecodeAtari8RgbScreen(RECOIL * self,uint8_t const * screens,int screensOffset,int color,uint8_t * frame)17706 static void RECOIL_DecodeAtari8RgbScreen(RECOIL *self, uint8_t const *screens, int screensOffset, int color, uint8_t *frame)
17707 {
17708 	if (self->resolution == RECOILResolution_XE4X1) {
17709 		self->gtiaColors[8] = (uint8_t) color;
17710 		RECOIL_DecodeAtari8Gr9(self, screens, screensOffset, 40, frame, 0, self->width, self->width, self->height);
17711 	}
17712 	else {
17713 		self->gtiaColors[8] = 0;
17714 		self->gtiaColors[4] = (uint8_t) (color | 4);
17715 		self->gtiaColors[5] = (uint8_t) (color | 10);
17716 		self->gtiaColors[6] = (uint8_t) (color | 14);
17717 		RECOIL_DecodeAtari8Gr15(self, screens, screensOffset, 40, frame, 0, self->width, self->height);
17718 	}
17719 }
17720 
RECOIL_DecodeAtari8Rgb(RECOIL * self,uint8_t const * content,int contentLength)17721 static bool RECOIL_DecodeAtari8Rgb(RECOIL *self, uint8_t const *content, int contentLength)
17722 {
17723 	if (contentLength < 9 || !RECOIL_IsStringAt(content, 0, "RGB1"))
17724 		return false;
17725 	int titleLength = content[4];
17726 	if (contentLength < 9 + titleLength)
17727 		return false;
17728 	int width = content[6 + titleLength];
17729 	int height = content[7 + titleLength];
17730 	if (width == 0 || (width & 1) != 0 || width > 80 || height == 0 || height > 192 || content[8 + titleLength] != 1)
17731 		return false;
17732 	switch (content[5 + titleLength]) {
17733 	case 9:
17734 		RECOIL_SetSize(self, width << 2, height, RECOILResolution_XE4X1);
17735 		break;
17736 	case 15:
17737 		RECOIL_SetSize(self, width << 2, height, RECOILResolution_XE2X1);
17738 		break;
17739 	default:
17740 		return false;
17741 	}
17742 	int leftRgbs[192];
17743 	uint8_t screens[23040];
17744 	RgbStream rle;
17745 	RgbStream_Construct(&rle);
17746 	rle.base.base.base.content = content;
17747 	rle.base.base.base.contentOffset = 9 + titleLength;
17748 	rle.base.base.base.contentLength = contentLength;
17749 	for (int x = 0; x < width; x++) {
17750 		for (int y = 0; y < height; y++) {
17751 			int rgb = RleStream_ReadRle(&rle.base);
17752 			if (rgb < 0)
17753 				return false;
17754 			if ((x & 1) == 0)
17755 				leftRgbs[y] = rgb;
17756 			else {
17757 				int leftRgb = leftRgbs[y];
17758 				int screenOffset = y * 40 + (x >> 1);
17759 				screens[screenOffset] = (uint8_t) ((leftRgb >> 4 & 240) | rgb >> 8);
17760 				screens[7680 + screenOffset] = (uint8_t) ((leftRgb & 240) | (rgb >> 4 & 15));
17761 				screens[15360 + screenOffset] = (uint8_t) ((leftRgb << 4 & 240) | (rgb & 15));
17762 			}
17763 		}
17764 	}
17765 	uint8_t frame1[61440];
17766 	RECOIL_DecodeAtari8RgbScreen(self, screens, 0, 48, frame1);
17767 	uint8_t frame2[61440];
17768 	RECOIL_DecodeAtari8RgbScreen(self, screens, 7680, 192, frame2);
17769 	uint8_t frame3[61440];
17770 	RECOIL_DecodeAtari8RgbScreen(self, screens, 15360, 112, frame3);
17771 	return RECOIL_ApplyAtari8PaletteBlend3(self, frame1, frame2, frame3);
17772 }
17773 
RECOIL_DrawBlazingPaddlesVector(const RECOIL * self,uint8_t const * content,int contentLength,uint8_t * frame,int frameOffset,int index,int startAddress)17774 static bool RECOIL_DrawBlazingPaddlesVector(const RECOIL *self, uint8_t const *content, int contentLength, uint8_t *frame, int frameOffset, int index, int startAddress)
17775 {
17776 	if (index * 2 + 1 >= contentLength)
17777 		return false;
17778 	int contentOffset = content[index * 2] + (content[index * 2 + 1] << 8) - startAddress;
17779 	if (contentOffset < 0)
17780 		return false;
17781 	while (contentOffset < contentLength) {
17782 		int control = content[contentOffset++];
17783 		if (control == 8)
17784 			return true;
17785 		for (; control >= 0; control -= 16) {
17786 			if ((control & 4) == 0)
17787 				frame[frameOffset + 1] = frame[frameOffset] = 14;
17788 			switch (control & 3) {
17789 			case 0:
17790 				frameOffset += 2;
17791 				break;
17792 			case 1:
17793 				frameOffset -= 2;
17794 				break;
17795 			case 2:
17796 				frameOffset -= self->width;
17797 				break;
17798 			case 3:
17799 				frameOffset += self->width;
17800 				break;
17801 			default:
17802 				assert(false);
17803 			}
17804 		}
17805 	}
17806 	return false;
17807 }
17808 
RECOIL_DecodeBlazingPaddlesVectors(RECOIL * self,uint8_t const * content,int contentLength,int startAddress)17809 static bool RECOIL_DecodeBlazingPaddlesVectors(RECOIL *self, uint8_t const *content, int contentLength, int startAddress)
17810 {
17811 	int x = 0;
17812 	int y = 0;
17813 	int i;
17814 	int lineI = 0;
17815 	int lineTop = 0;
17816 	int lineBottom = 0;
17817 	int xs[256];
17818 	int ys[256];
17819 	int width = 0;
17820 	BlazingPaddlesBoundingBox box;
17821 	for (i = 0; i < 256; i++) {
17822 		if (!BlazingPaddlesBoundingBox_Calculate(&box, content, contentLength, i, startAddress))
17823 			break;
17824 		int shapeWidth = box.right - box.left + 2;
17825 		if (x + shapeWidth > 160) {
17826 			y -= lineTop;
17827 			while (lineI < i)
17828 				ys[lineI++] = y;
17829 			if (width < x)
17830 				width = x;
17831 			x = 0;
17832 			y += lineBottom + 2;
17833 			lineTop = box.top;
17834 			lineBottom = box.bottom;
17835 		}
17836 		xs[i] = x - box.left;
17837 		x += shapeWidth;
17838 		if (lineTop > box.top)
17839 			lineTop = box.top;
17840 		if (lineBottom < box.bottom)
17841 			lineBottom = box.bottom;
17842 	}
17843 	y -= lineTop;
17844 	while (lineI < i)
17845 		ys[lineI++] = y;
17846 	if (width < x)
17847 		width = x;
17848 	y += lineBottom + 1;
17849 	if (i == 0 || y > 240)
17850 		return false;
17851 	RECOIL_SetSize(self, width << 1, y, RECOILResolution_XE2X1);
17852 	uint8_t frame[76800] = { 0 };
17853 	for (i = 0; i < 256; i++) {
17854 		if (!RECOIL_DrawBlazingPaddlesVector(self, content, contentLength, frame, (ys[i] * width + xs[i]) * 2, i, startAddress))
17855 			break;
17856 	}
17857 	return RECOIL_ApplyAtari8Palette(self, frame);
17858 }
17859 
RECOIL_DecodeChr(RECOIL * self,uint8_t const * content,int contentLength)17860 static bool RECOIL_DecodeChr(RECOIL *self, uint8_t const *content, int contentLength)
17861 {
17862 	return contentLength == 3072 && RECOIL_DecodeBlazingPaddlesVectors(self, content, contentLength, 28672);
17863 }
17864 
RECOIL_DecodeShp(RECOIL * self,uint8_t const * content,int contentLength)17865 static bool RECOIL_DecodeShp(RECOIL *self, uint8_t const *content, int contentLength)
17866 {
17867 	switch (contentLength) {
17868 	case 1024:
17869 		return RECOIL_DecodeBlazingPaddlesVectors(self, content, contentLength, 31744);
17870 	case 4384:
17871 		return RECOIL_DecodeGr7(self, content, 528, 3844);
17872 	default:
17873 		return false;
17874 	}
17875 }
17876 
RECOIL_DrawSpcChar(uint8_t * pixels,int x1,int y1,int ch)17877 static void RECOIL_DrawSpcChar(uint8_t *pixels, int x1, int y1, int ch)
17878 {
17879 	if (ch < 32 || ch > 95)
17880 		return;
17881 	uint8_t const *font = CiResource_atari8_fnt;
17882 	int fontOffset = (ch - 32) << 3;
17883 	for (int y = 0; y < 8 && y1 + y < 192; y++) {
17884 		for (int x = 0; x < 4 && x1 + x < 160; x++)
17885 			pixels[(y1 + y) * 160 + x1 + x] = (uint8_t) (font[fontOffset + y] >> (6 - x * 2) & 3);
17886 	}
17887 }
17888 
RECOIL_DrawSpcLine(uint8_t * pixels,int x1,int y1,int x2,int y2,int color)17889 static void RECOIL_DrawSpcLine(uint8_t *pixels, int x1, int y1, int x2, int y2, int color)
17890 {
17891 	int dx = x2 - x1;
17892 	int dy = y2 - y1;
17893 	if (dx < 0)
17894 		dx = -dx;
17895 	if (dy < 0)
17896 		dy = -dy;
17897 	if (dx >= dy) {
17898 		int e = dx;
17899 		if (x2 < x1) {
17900 			int ty = y1;
17901 			x1 = x2;
17902 			x2 += dx;
17903 			y1 = y2;
17904 			y2 = ty;
17905 		}
17906 		for (; x1 <= x2; x1++) {
17907 			if (x1 < 160 && y1 < 192)
17908 				pixels[160 * y1 + x1] = (uint8_t) color;
17909 			e -= dy * 2;
17910 			if (e < 0) {
17911 				e += dx * 2;
17912 				y1 += y1 < y2 ? 1 : -1;
17913 			}
17914 		}
17915 	}
17916 	else {
17917 		int e = dy;
17918 		if (y2 < y1) {
17919 			int tx = x1;
17920 			x1 = x2;
17921 			x2 = tx;
17922 			y1 = y2;
17923 			y2 += dy;
17924 		}
17925 		for (; y1 <= y2; y1++) {
17926 			if (x1 < 160 && y1 < 192)
17927 				pixels[160 * y1 + x1] = (uint8_t) color;
17928 			e -= dx * 2;
17929 			if (e < 0) {
17930 				e += dy * 2;
17931 				x1 += x1 < x2 ? 1 : -1;
17932 			}
17933 		}
17934 	}
17935 }
17936 
RECOIL_PlotSpcPattern(uint8_t * pixels,int x,int y,int pattern)17937 static void RECOIL_PlotSpcPattern(uint8_t *pixels, int x, int y, int pattern)
17938 {
17939 	pixels[y * 160 + x] = (uint8_t) (pattern >> ((~y & 1) * 8 + (~x & 3) * 2) & 3);
17940 }
17941 
RECOIL_DrawSpcBrush(uint8_t * pixels,int x1,int y1,int brush,int pattern)17942 static void RECOIL_DrawSpcBrush(uint8_t *pixels, int x1, int y1, int brush, int pattern)
17943 {
17944 	static const uint8_t BRUSHES[128] = { 0, 0, 0, 0, 0, 0, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0,
17945 		0, 0, 0, 0, 0, 48, 48, 48, 48, 0, 0, 0, 0, 0, 0, 0,
17946 		0, 0, 0, 0, 16, 56, 56, 56, 56, 16, 0, 0, 0, 0, 0, 0,
17947 		0, 0, 16, 56, 56, 124, 124, 124, 124, 56, 56, 16, 0, 0, 0, 0,
17948 		0, 24, 24, 60, 60, 126, 126, 126, 126, 60, 60, 24, 24, 0, 0, 0,
17949 		16, 56, 124, 124, 124, 254, 254, 254, 254, 124, 124, 124, 56, 16, 0, 0,
17950 		0, 0, 16, 40, 40, 80, 60, 120, 20, 40, 40, 16, 0, 0, 0, 0,
17951 		16, 40, 84, 40, 84, 186, 124, 124, 186, 84, 40, 84, 40, 16, 0, 0 };
17952 	for (int y = 0; y < 16 && y1 + y < 192; y++) {
17953 		int brushShape = BRUSHES[brush * 16 + y];
17954 		for (int x = 0; x < 8 && x1 + x < 160; x++) {
17955 			if ((brushShape >> (7 - x) & 1) != 0)
17956 				RECOIL_PlotSpcPattern(pixels, x, y, pattern);
17957 		}
17958 	}
17959 }
17960 
RECOIL_FillSpc(uint8_t * pixels,int x,int y,int pattern)17961 static bool RECOIL_FillSpc(uint8_t *pixels, int x, int y, int pattern)
17962 {
17963 	if (x >= 160 || y >= 192)
17964 		return false;
17965 	while (y >= 0 && pixels[y * 160 + x] == 0)
17966 		y--;
17967 	while (++y < 192 && pixels[y * 160 + x] == 0) {
17968 		do
17969 			x--;
17970 		while (x >= 0 && pixels[y * 160 + x] == 0);
17971 		int x1 = x;
17972 		while (x < 159) {
17973 			if (pixels[y * 160 + ++x] != 0)
17974 				break;
17975 			RECOIL_PlotSpcPattern(pixels, x, y, pattern);
17976 		}
17977 		x = x1 + ((x - x1 + 1) >> 1);
17978 	}
17979 	return true;
17980 }
17981 
RECOIL_DecodeAtari8Spc(RECOIL * self,uint8_t const * content,int contentLength)17982 static bool RECOIL_DecodeAtari8Spc(RECOIL *self, uint8_t const *content, int contentLength)
17983 {
17984 	if (contentLength < 3 || contentLength != content[0] + (content[1] << 8) + 3 || content[contentLength - 1] != 0)
17985 		return false;
17986 	uint8_t pixels[30720] = { 0 };
17987 	int lineColors[96] = { 0 };
17988 	int textX = 0;
17989 	int textY = 0;
17990 	int lineX = 0;
17991 	int lineY = 0;
17992 	int brush = 0;
17993 	int pattern = 8840;
17994 	int lineColor = 3;
17995 	int x;
17996 	int y;
17997 	for (int contentOffset = 2; content[contentOffset] != 0;) {
17998 		switch (content[contentOffset]) {
17999 		case 16:
18000 			if (contentOffset + 3 >= contentLength)
18001 				return false;
18002 			textX = content[contentOffset + 1];
18003 			textY = content[contentOffset + 2];
18004 			contentOffset += 3;
18005 			break;
18006 		case 32:
18007 		case 33:
18008 		case 34:
18009 		case 35:
18010 			if (contentOffset + 1 >= contentLength)
18011 				return false;
18012 			lineColor = content[contentOffset] & 3;
18013 			contentOffset++;
18014 			break;
18015 		case 48:
18016 		case 80:
18017 			if (contentOffset + 2 >= contentLength)
18018 				return false;
18019 			RECOIL_DrawSpcChar(pixels, textX, textY, content[contentOffset + 1]);
18020 			textX += 4;
18021 			contentOffset += 2;
18022 			break;
18023 		case 64:
18024 		case 65:
18025 		case 66:
18026 		case 67:
18027 		case 68:
18028 		case 69:
18029 		case 70:
18030 		case 71:
18031 			if (contentOffset + 1 >= contentLength)
18032 				return false;
18033 			brush = content[contentOffset] & 7;
18034 			contentOffset++;
18035 			break;
18036 		case 96:
18037 			if (contentOffset + 2 >= contentLength)
18038 				return false;
18039 			pattern = content[contentOffset + 1];
18040 			static const int PATTERNS[71] = { 0, 21845, 43690, 65535, 4420, 8840, 13260, 26265, 30685, 48110, 5457, 10914, 16371, 16388, 27302, 32759,
18041 				32776, 38233, 49147, 49164, 54621, 60078, 21896, 8908, 13124, 17561, 17629, 30617, 35054, 34918, 39406, 52343,
18042 				52411, 56763, 7089, 5465, 5469, 38237, 16392, 16396, 32780, 27308, 10926, 27298, 32763, 16379, 49143, 21892,
18043 				8900, 13128, 17553, 17617, 30609, 35042, 34914, 39393, 52339, 52403, 56755, 21900, 8904, 13132, 17565, 17625,
18044 				30621, 35046, 34926, 39397, 52347, 52407, 56759 };
18045 			if (pattern >= 71)
18046 				return false;
18047 			pattern = PATTERNS[pattern];
18048 			contentOffset += 2;
18049 			break;
18050 		case 112:
18051 			if (contentOffset + 7 >= contentLength)
18052 				return false;
18053 			for (y = content[contentOffset + 1]; y <= content[contentOffset + 2]; y++) {
18054 				if (y >= 96)
18055 					return false;
18056 				lineColors[y] = contentOffset + 3;
18057 			}
18058 			contentOffset += 7;
18059 			break;
18060 		case 128:
18061 			if (contentOffset + 3 >= contentLength)
18062 				return false;
18063 			lineX = content[contentOffset + 1];
18064 			lineY = content[contentOffset + 2];
18065 			contentOffset += 3;
18066 			break;
18067 		case 160:
18068 			if (contentOffset + 3 >= contentLength)
18069 				return false;
18070 			x = content[contentOffset + 1];
18071 			y = content[contentOffset + 2];
18072 			RECOIL_DrawSpcLine(pixels, lineX, lineY, x, y, lineColor);
18073 			lineX = x;
18074 			lineY = y;
18075 			contentOffset += 3;
18076 			break;
18077 		case 192:
18078 			if (contentOffset + 3 >= contentLength)
18079 				return false;
18080 			RECOIL_DrawSpcBrush(pixels, content[contentOffset + 1], content[contentOffset + 2], brush, pattern);
18081 			contentOffset += 3;
18082 			break;
18083 		case 224:
18084 			if (contentOffset + 3 >= contentLength)
18085 				return false;
18086 			if (!RECOIL_FillSpc(pixels, content[contentOffset + 1], content[contentOffset + 2], pattern))
18087 				return false;
18088 			contentOffset += 3;
18089 			break;
18090 		default:
18091 			return false;
18092 		}
18093 	}
18094 	RECOIL_SetSize(self, 320, 192, RECOILResolution_XE2X1);
18095 	uint8_t frame[61440];
18096 	for (y = 0; y < 192; y++) {
18097 		static const uint8_t DEFAULT_COLORS[4] = { 0, 21, 149, 54 };
18098 		int colorsOffset = lineColors[y >> 1];
18099 		uint8_t const *colors = colorsOffset == 0 ? DEFAULT_COLORS : content;
18100 		for (x = 0; x < 160; x++) {
18101 			int offset = y * 320 + x * 2;
18102 			frame[offset + 1] = frame[offset] = (uint8_t) (colors[colorsOffset + pixels[y * 160 + x]] & 254);
18103 		}
18104 	}
18105 	return RECOIL_ApplyAtari8Palette(self, frame);
18106 }
18107 
RECOIL_DecodeHcm(RECOIL * self,uint8_t const * content,int contentLength)18108 static bool RECOIL_DecodeHcm(RECOIL *self, uint8_t const *content, int contentLength)
18109 {
18110 	if (contentLength != 8208 || !RECOIL_IsStringAt(content, 0, "HCMA8") || content[5] != 1)
18111 		return false;
18112 	HcmRenderer gtia;
18113 	HcmRenderer_Construct(&gtia);
18114 	int leftSprite;
18115 	switch (content[6]) {
18116 	case 0:
18117 		leftSprite = 2;
18118 		gtia.base.prior = 0;
18119 		break;
18120 	case 2:
18121 		leftSprite = 1;
18122 		gtia.base.prior = 36;
18123 		break;
18124 	default:
18125 		return false;
18126 	}
18127 	gtia.base.playerHpos[3] = gtia.base.playerHpos[3 - leftSprite] = 104;
18128 	gtia.base.missileHpos[leftSprite] = gtia.base.missileHpos[0] = 136;
18129 	gtia.base.missileHpos[3] = gtia.base.missileHpos[3 - leftSprite] = 144;
18130 	for (int i = 0; i < 4; i++)
18131 		gtia.base.missileSize[i] = gtia.base.playerSize[i] = 4;
18132 	gtia.base.colors[8] = (uint8_t) (content[7] & 254);
18133 	gtia.base.colors[3 - leftSprite] = gtia.base.colors[0] = (uint8_t) (content[8] & 254);
18134 	gtia.base.colors[3] = gtia.base.colors[leftSprite] = (uint8_t) (content[9] & 254);
18135 	gtia.base.colors[4] = (uint8_t) (content[10] & 254);
18136 	gtia.base.colors[5] = (uint8_t) (content[11] & 254);
18137 	gtia.base.colors[6] = (uint8_t) (content[12] & 254);
18138 	gtia.base.content = content;
18139 	gtia.base.playfieldColumns = 32;
18140 	RECOIL_SetSize(self, 256, 192, RECOILResolution_XE2X1);
18141 	uint8_t frame[49152];
18142 	for (int y = 0; y < 192; y++) {
18143 		gtia.base.playerHpos[leftSprite] = gtia.base.playerHpos[0] = 72;
18144 		GtiaRenderer_ProcessSpriteDma(&gtia.base, content, 816 + y);
18145 		GtiaRenderer_StartLine(&gtia.base, 64);
18146 		GtiaRenderer_DrawSpan(&gtia.base, y, 64, 128, AnticMode_FOUR_COLOR, frame, 256);
18147 		gtia.base.playerHpos[leftSprite] = gtia.base.playerHpos[0] = 152;
18148 		gtia.base.playerGraphics[0] = content[48 + y];
18149 		gtia.base.playerGraphics[leftSprite] = content[304 + y];
18150 		GtiaRenderer_DrawSpan(&gtia.base, y, 128, 192, AnticMode_FOUR_COLOR, frame, 256);
18151 	}
18152 	return RECOIL_ApplyAtari8Palette(self, frame);
18153 }
18154 
RECOIL_DecodeGed(RECOIL * self,uint8_t const * content,int contentLength)18155 static bool RECOIL_DecodeGed(RECOIL *self, uint8_t const *content, int contentLength)
18156 {
18157 	if (contentLength != 11302 || content[0] != 255 || content[1] != 255 || content[2] != 48 || content[3] != 83 || content[4] != 79 || content[5] != 127)
18158 		return false;
18159 	int cycle = content[3300];
18160 	if (cycle > 7)
18161 		return false;
18162 	GedRenderer gtia;
18163 	GedRenderer_Construct(&gtia);
18164 	GtiaRenderer_SetSpriteSizes(gtia.base.missileSize, content[3291]);
18165 	gtia.base.colors[7] = (uint8_t) (content[3293] & 254);
18166 	gtia.base.colors[8] = (uint8_t) (content[3294] & 254);
18167 	int prior = content[3292];
18168 	gtia.base.prior = prior;
18169 	for (int i = 0; i < 4; i++) {
18170 		GtiaRenderer_SetPlayerSize(&gtia.base, i, content[3290] >> ((3 - i) << 1));
18171 		gtia.base.playerHpos[i] = (uint8_t) (48 + content[3295 + i]);
18172 		gtia.base.missileHpos[i] = (uint8_t) ((prior & 16) == 0 ? gtia.base.playerHpos[i] + (gtia.base.playerSize[i] << 3) : i == 0 ? 48 + content[3299] : gtia.base.missileHpos[i - 1] + (gtia.base.missileSize[i - 1] << 1));
18173 		gtia.base.colors[i] = (uint8_t) (content[3286 + i] & 254);
18174 	}
18175 	gtia.base.content = content;
18176 	gtia.base.playfieldColumns = 40;
18177 	RECOIL_SetSize(self, 320, 200, RECOILResolution_XE2X1);
18178 	uint8_t frame[64000];
18179 	for (int y = 0; y < 200; y++) {
18180 		GtiaRenderer_ProcessSpriteDma(&gtia.base, content, 2034 + y);
18181 		GtiaRenderer_Poke(&gtia.base, content[206 + y] & 31, content[6 + y]);
18182 		gtia.base.colors[4] = (uint8_t) (content[406 + y] & 254);
18183 		gtia.base.colors[5] = (uint8_t) (content[606 + y] & 254);
18184 		gtia.base.colors[6] = (uint8_t) (content[806 + y] & 254);
18185 		GtiaRenderer_StartLine(&gtia.base, 48);
18186 		int hpos = GtiaRenderer_DrawSpan(&gtia.base, y, 48, 63 + (cycle << 3), AnticMode_FOUR_COLOR, frame, 320);
18187 		gtia.base.colors[4] = (uint8_t) (content[1006 + y] & 254);
18188 		hpos = GtiaRenderer_DrawSpan(&gtia.base, y, hpos, cycle < 4 ? hpos + 32 : 107 + (cycle << 2), AnticMode_FOUR_COLOR, frame, 320);
18189 		gtia.base.colors[5] = (uint8_t) (content[1206 + y] & 254);
18190 		hpos = GtiaRenderer_DrawSpan(&gtia.base, y, hpos, 123 + (cycle << 2), AnticMode_FOUR_COLOR, frame, 320);
18191 		gtia.base.colors[6] = (uint8_t) (content[1406 + y] & 254);
18192 		hpos = GtiaRenderer_DrawSpan(&gtia.base, y, hpos, hpos + 24, AnticMode_FOUR_COLOR, frame, 320);
18193 		gtia.base.colors[4] = (uint8_t) (content[1606 + y] & 254);
18194 		hpos = GtiaRenderer_DrawSpan(&gtia.base, y, hpos, hpos + 24, AnticMode_FOUR_COLOR, frame, 320);
18195 		gtia.base.colors[5] = (uint8_t) (content[1806 + y] & 254);
18196 		GtiaRenderer_DrawSpan(&gtia.base, y, hpos, 208, AnticMode_FOUR_COLOR, frame, 320);
18197 	}
18198 	return RECOIL_ApplyAtari8Palette(self, frame);
18199 }
18200 
RECOIL_DecodePgr(RECOIL * self,uint8_t const * content,int contentLength)18201 static bool RECOIL_DecodePgr(RECOIL *self, uint8_t const *content, int contentLength)
18202 {
18203 	if (contentLength < 1776 || 6 + RECOIL_ParseAtari8ExecutableHeader(content, 0) != contentLength || content[2] != 6 || content[3] != 130 || !RECOIL_IsStringAt(content, 8, "PowerGFX"))
18204 		return false;
18205 	PgrRenderer gtia;
18206 	PgrRenderer_Construct(&gtia);
18207 	for (int i = 0; i < 14; i++) {
18208 		GtiaRenderer_Poke(&gtia.base, i, content[504 + i]);
18209 		GtiaRenderer_Poke(&gtia.base, 14 + i, content[760 + i]);
18210 	}
18211 	gtia.base.content = content;
18212 	int dmaCtl = content[774];
18213 	switch (dmaCtl & 243) {
18214 	case 49:
18215 		gtia.base.playfieldColumns = 32;
18216 		break;
18217 	case 50:
18218 		gtia.base.playfieldColumns = 40;
18219 		break;
18220 	default:
18221 		return false;
18222 	}
18223 	int dlOffset = 16;
18224 	int rasterOffset = content[6] + (content[7] << 8) - 33280;
18225 	if (rasterOffset < 1536)
18226 		return false;
18227 	gtia.screenOffset = -1;
18228 	int a = 0;
18229 	uint8_t frame[80640];
18230 	RECOILResolution resolution = RECOILResolution_XE4X1;
18231 	for (int y = 0; y < 240; y++) {
18232 		int hpos = -11;
18233 		int dlOp = content[dlOffset++];
18234 		switch (dlOp) {
18235 		case 0:
18236 		case 14:
18237 		case 15:
18238 			break;
18239 		case 65:
18240 			dlOffset--;
18241 			break;
18242 		case 78:
18243 		case 79:
18244 			hpos += 4;
18245 			gtia.screenOffset = content[dlOffset] + (content[dlOffset + 1] << 8) - 33280;
18246 			dlOffset += 2;
18247 			break;
18248 		default:
18249 			return false;
18250 		}
18251 		AnticMode anticMode;
18252 		switch (dlOp & 15) {
18253 		case 14:
18254 			anticMode = AnticMode_FOUR_COLOR;
18255 			if (resolution == RECOILResolution_XE4X1 && gtia.base.prior < 64)
18256 				resolution = RECOILResolution_XE2X1;
18257 			break;
18258 		case 15:
18259 			anticMode = AnticMode_HI_RES;
18260 			if (gtia.base.prior < 64)
18261 				resolution = RECOILResolution_XE1X1;
18262 			break;
18263 		default:
18264 			anticMode = AnticMode_BLANK;
18265 			break;
18266 		}
18267 		if (anticMode != AnticMode_BLANK && (gtia.screenOffset < 1536 || gtia.screenOffset + 40 > contentLength))
18268 			return false;
18269 		GtiaRenderer_StartLine(&gtia.base, 44);
18270 		if ((dmaCtl & 12) != 0) {
18271 			hpos += 2;
18272 			if ((dmaCtl & 4) != 0)
18273 				gtia.base.missileGraphics = content[264 + y];
18274 			if ((dmaCtl & 8) != 0) {
18275 				hpos += 8;
18276 				for (int i = 0; i < 4; i++)
18277 					gtia.base.playerGraphics[i] = content[520 + (i << 8) + y];
18278 			}
18279 		}
18280 		for (int cpuCycles = 1;;) {
18281 			if (rasterOffset >= contentLength)
18282 				return false;
18283 			int rasterOp = content[rasterOffset++];
18284 			if ((rasterOp & 32) != 0) {
18285 				if (rasterOffset >= contentLength)
18286 					return false;
18287 				cpuCycles += 2;
18288 				a = content[rasterOffset++];
18289 			}
18290 			int addr = rasterOp & 31;
18291 			if (addr <= 27) {
18292 				int untilHpos = hpos;
18293 				for (;;) {
18294 					untilHpos += 2;
18295 					int x = (untilHpos - 118) >> 1;
18296 					if ((x & 1) != 0 ? anticMode != AnticMode_BLANK && x >= -gtia.base.playfieldColumns && x < gtia.base.playfieldColumns : x >= -36 && x < 0 && (x & 2) != 0) {
18297 					}
18298 					else if (--cpuCycles == 0)
18299 						break;
18300 				}
18301 				GtiaRenderer_DrawSpan(&gtia.base, y, hpos >= 44 ? hpos : 44, untilHpos < 212 ? untilHpos : 212, anticMode, frame, 336);
18302 				hpos = untilHpos;
18303 				GtiaRenderer_Poke(&gtia.base, addr, a);
18304 				if (rasterOp >= 128)
18305 					break;
18306 				cpuCycles = 4;
18307 			}
18308 			else {
18309 				int nops = (rasterOp >> 6 & 3) | (rasterOp & 3) << 2;
18310 				if (nops == 0)
18311 					break;
18312 				cpuCycles += nops << 1;
18313 			}
18314 		}
18315 		GtiaRenderer_DrawSpan(&gtia.base, y, hpos >= 44 ? hpos : 44, 212, anticMode, frame, 336);
18316 		if (anticMode != AnticMode_BLANK)
18317 			gtia.screenOffset += gtia.base.playfieldColumns;
18318 	}
18319 	RECOIL_SetSize(self, 336, 240, resolution);
18320 	return RECOIL_ApplyAtari8Palette(self, frame);
18321 }
18322 
RECOIL_HasG2fRaster(uint8_t const * content,int contentOffset,int count,int hitClr)18323 static bool RECOIL_HasG2fRaster(uint8_t const *content, int contentOffset, int count, int hitClr)
18324 {
18325 	do {
18326 		switch (content[contentOffset]) {
18327 		case 0:
18328 		case 1:
18329 		case 2:
18330 		case 3:
18331 		case 65:
18332 		case 66:
18333 		case 67:
18334 		case 97:
18335 		case 98:
18336 		case 99:
18337 			break;
18338 		case 129:
18339 		case 130:
18340 		case 131:
18341 			if (content[contentOffset + 1] != hitClr)
18342 				return true;
18343 			break;
18344 		default:
18345 			return true;
18346 		}
18347 		contentOffset += 2;
18348 	}
18349 	while (--count > 0);
18350 	return false;
18351 }
18352 
RECOIL_DecodeMch(RECOIL * self,uint8_t const * content,int contentLength)18353 static bool RECOIL_DecodeMch(RECOIL *self, uint8_t const *content, int contentLength)
18354 {
18355 	int columns;
18356 	switch (contentLength) {
18357 	case 9840:
18358 	case 28673:
18359 		columns = 32;
18360 		break;
18361 	case 12000:
18362 	case 30833:
18363 		columns = 40;
18364 		break;
18365 	case 14160:
18366 	case 32993:
18367 		columns = 48;
18368 		break;
18369 	default:
18370 		return false;
18371 	}
18372 	int bitmapLength = columns * 270;
18373 	bool sprites = contentLength > bitmapLength + 1200;
18374 	AnticMode anticMode;
18375 	switch (content[0] & 3) {
18376 	case 0:
18377 		if (sprites && RECOIL_HasG2fRaster(content, bitmapLength + 6080, 6960, 30))
18378 			return false;
18379 		anticMode = AnticMode_FIVE_COLOR;
18380 		break;
18381 	case 1:
18382 		anticMode = AnticMode_FIVE_COLOR;
18383 		break;
18384 	case 2:
18385 		if (sprites && RECOIL_HasG2fRaster(content, bitmapLength + 6080, 6960, 30))
18386 			return false;
18387 		anticMode = AnticMode_FOUR_COLOR;
18388 		break;
18389 	default:
18390 		return false;
18391 	}
18392 	RECOILResolution resolution;
18393 	int gtiaMode = 0;
18394 	switch (content[0] & 60) {
18395 	case 0:
18396 		anticMode = AnticMode_HI_RES;
18397 		resolution = RECOILResolution_XE1X1;
18398 		break;
18399 	case 4:
18400 		resolution = RECOILResolution_XE2X1;
18401 		break;
18402 	case 8:
18403 		anticMode = AnticMode_HI_RES;
18404 		resolution = RECOILResolution_XE4X1;
18405 		gtiaMode = 64;
18406 		break;
18407 	case 24:
18408 		anticMode = AnticMode_HI_RES;
18409 		resolution = RECOILResolution_XE4X1;
18410 		gtiaMode = 128;
18411 		break;
18412 	case 40:
18413 		anticMode = AnticMode_HI_RES;
18414 		resolution = RECOILResolution_XE4X1;
18415 		gtiaMode = 192;
18416 		break;
18417 	default:
18418 		return false;
18419 	}
18420 	RECOIL_SetSize(self, 336, 240, resolution);
18421 	uint8_t frame[80640];
18422 	MchRenderer gtia;
18423 	MchRenderer_Construct(&gtia);
18424 	memset(gtia.base.playerHpos, 0, sizeof(gtia.base.playerHpos));
18425 	memset(gtia.base.missileHpos, 0, sizeof(gtia.base.missileHpos));
18426 	memset(gtia.base.colors, 0, sizeof(gtia.base.colors));
18427 	gtia.base.prior = gtiaMode;
18428 	gtia.base.content = content;
18429 	gtia.base.playfieldColumns = columns;
18430 	gtia.dliPlus = false;
18431 	for (int i = 0; i < bitmapLength; i += 9) {
18432 		if ((content[i] & 64) != 0) {
18433 			gtia.dliPlus = true;
18434 			break;
18435 		}
18436 	}
18437 	for (int y = 0; y < 240; y++) {
18438 		int colorsOffset = bitmapLength + y;
18439 		GtiaRenderer_SetG2fColors(&gtia.base, colorsOffset, 240, sprites ? 9 : 5, gtiaMode);
18440 		if (sprites) {
18441 			for (int i = 0; i < 4; i++) {
18442 				gtia.base.playerHpos[i] = content[colorsOffset + (9 + i) * 240];
18443 				gtia.base.missileHpos[i] = content[colorsOffset + (13 + i) * 240];
18444 			}
18445 			GtiaRenderer_SetSpriteSizes(gtia.base.playerSize, content[colorsOffset + 4080]);
18446 			GtiaRenderer_SetSpriteSizes(gtia.base.missileSize, content[colorsOffset + 4320]);
18447 			gtia.base.prior = gtiaMode | content[colorsOffset + 4560];
18448 			GtiaRenderer_ProcessSpriteDma(&gtia.base, content, colorsOffset + 4800);
18449 		}
18450 		GtiaRenderer_StartLine(&gtia.base, 44);
18451 		GtiaRenderer_DrawSpan(&gtia.base, y, 44, 212, anticMode, frame, 336);
18452 	}
18453 	return RECOIL_ApplyAtari8Palette(self, frame);
18454 }
18455 
RECOIL_G2fHasRaster(uint8_t const * content,int contentOffset)18456 static bool RECOIL_G2fHasRaster(uint8_t const *content, int contentOffset)
18457 {
18458 	return RECOIL_HasG2fRaster(content, contentOffset, 2880, content[0] < 128 ? 22 : 30);
18459 }
18460 
RECOIL_DecodeG2fUnpacked(RECOIL * self,uint8_t const * content,int contentLength)18461 static bool RECOIL_DecodeG2fUnpacked(RECOIL *self, uint8_t const *content, int contentLength)
18462 {
18463 	if (contentLength < 155711)
18464 		return false;
18465 	int columns = content[0] & 127;
18466 	switch (columns) {
18467 	case 32:
18468 	case 40:
18469 	case 48:
18470 		break;
18471 	default:
18472 		return false;
18473 	}
18474 	int fontsOffset = 3 + 30 * columns;
18475 	int fontNumberOffset = fontsOffset + (((content[2] & 127) + 1) << 10);
18476 	if (contentLength < fontNumberOffset + 153724)
18477 		return false;
18478 	bool charMode;
18479 	int vbxeOffset = fontNumberOffset + 155231;
18480 	int inverse2Offset = -1;
18481 	switch (content[fontNumberOffset + 147679] & 127) {
18482 	case 1:
18483 		if (RECOIL_G2fHasRaster(content, fontNumberOffset + 147934))
18484 			return false;
18485 		charMode = true;
18486 		break;
18487 	case 2:
18488 		charMode = true;
18489 		break;
18490 	case 3:
18491 		if (RECOIL_G2fHasRaster(content, fontNumberOffset + 147934))
18492 			return false;
18493 		charMode = false;
18494 		break;
18495 	case 66:
18496 		charMode = true;
18497 		inverse2Offset = vbxeOffset + 138244;
18498 		if (contentLength < inverse2Offset + 30 * columns)
18499 			return false;
18500 		break;
18501 	default:
18502 		return false;
18503 	}
18504 	if (contentLength < vbxeOffset + 138243)
18505 		vbxeOffset = -1;
18506 	else {
18507 		switch (content[vbxeOffset]) {
18508 		case 0:
18509 			vbxeOffset = -1;
18510 			break;
18511 		case 1:
18512 			if (content[vbxeOffset + 1] != 8 || content[vbxeOffset + 2] == 0)
18513 				return false;
18514 			break;
18515 		default:
18516 			return false;
18517 		}
18518 	}
18519 	uint8_t frame[80640];
18520 	RECOILResolution resolution = RECOILResolution_XE4X1;
18521 	G2fRenderer gtia;
18522 	G2fRenderer_Construct(&gtia);
18523 	gtia.base.content = content;
18524 	gtia.base.playfieldColumns = columns;
18525 	gtia.inverse2Offset = inverse2Offset;
18526 	gtia.vbxeOffset = vbxeOffset;
18527 	for (int y = 0; y < 240; y++) {
18528 		int row = y >> 3;
18529 		gtia.fontOffset = fontsOffset + ((content[fontNumberOffset + row] & 127) << 10);
18530 		if (gtia.fontOffset >= fontNumberOffset)
18531 			return false;
18532 		int spriteOffset = fontNumberOffset + 2334 + (y << 1);
18533 		int prior = content[spriteOffset + 1] >> 4 & 7;
18534 		static const uint8_t PRIORS[5] = { 4, 2, 1, 8, 0 };
18535 		if (prior >= 5)
18536 			return false;
18537 		prior = PRIORS[prior] | (content[spriteOffset + 1025] & 48);
18538 		AnticMode anticMode;
18539 		switch (content[fontNumberOffset + 153694 + row]) {
18540 		case 1:
18541 			resolution = RECOILResolution_XE1X1;
18542 			anticMode = AnticMode_HI_RES;
18543 			break;
18544 		case 2:
18545 			if (resolution == RECOILResolution_XE4X1)
18546 				resolution = RECOILResolution_XE2X1;
18547 			anticMode = charMode ? AnticMode_FIVE_COLOR : AnticMode_FOUR_COLOR;
18548 			break;
18549 		case 4:
18550 			;
18551 			static const uint8_t GTIA_MODES[8] = { 64, 64, 64, 64, 64, 128, 192, 64 };
18552 			prior |= GTIA_MODES[content[1] & 7];
18553 			anticMode = AnticMode_HI_RES;
18554 			break;
18555 		case 255:
18556 			anticMode = AnticMode_BLANK;
18557 			break;
18558 		default:
18559 			return false;
18560 		}
18561 		int colorsOffset = fontNumberOffset + 30 + y;
18562 		GtiaRenderer_SetG2fColors(&gtia.base, colorsOffset, 256, 9, prior);
18563 		int missileGraphics = 0;
18564 		for (int i = 0; i < 4; i++) {
18565 			if (!G2fRenderer_SetSprite(gtia.base.playerHpos, gtia.base.playerSize, i, content, spriteOffset) || !G2fRenderer_SetSprite(gtia.base.missileHpos, gtia.base.missileSize, i, content, spriteOffset + 512))
18566 				return false;
18567 			gtia.base.playerGraphics[i] = content[colorsOffset + 6400 + (i << 9)];
18568 			missileGraphics |= content[colorsOffset + 6656 + (i << 9)] >> 6 << (i << 1);
18569 		}
18570 		gtia.base.missileGraphics = missileGraphics;
18571 		gtia.base.prior = prior;
18572 		GtiaRenderer_StartLine(&gtia.base, 44);
18573 		GtiaRenderer_DrawSpan(&gtia.base, y, 44, 212, anticMode, frame, 336);
18574 	}
18575 	RECOIL_SetSize(self, 336, 240, resolution);
18576 	return RECOIL_ApplyAtari8Palette(self, frame);
18577 }
18578 
RECOIL_DecodeG2f(RECOIL * self,uint8_t const * content,int contentLength)18579 static bool RECOIL_DecodeG2f(RECOIL *self, uint8_t const *content, int contentLength)
18580 {
18581 	if (contentLength < 11)
18582 		return false;
18583 	if (RECOIL_IsStringAt(content, 0, "G2FZLIB")) {
18584 		uint8_t *unpacked = (uint8_t *) CiShared_Make(327078, sizeof(uint8_t), NULL, NULL);
18585 		InflateStream stream;
18586 		stream.base.content = content;
18587 		stream.base.contentOffset = 7;
18588 		stream.base.contentLength = contentLength;
18589 		contentLength = InflateStream_Uncompress(&stream, unpacked, 327078);
18590 		bool returnValue = RECOIL_DecodeG2fUnpacked(self, unpacked, contentLength);
18591 		CiShared_Release(unpacked);
18592 		return returnValue;
18593 	}
18594 	return RECOIL_DecodeG2fUnpacked(self, content, contentLength);
18595 }
18596 
RECOIL_DecodeDap(RECOIL * self,uint8_t const * content,int contentLength)18597 static bool RECOIL_DecodeDap(RECOIL *self, uint8_t const *content, int contentLength)
18598 {
18599 	if (contentLength != 77568)
18600 		return false;
18601 	RECOIL_SetSize(self, 320, 240, RECOILResolution_XE1X1);
18602 	for (int i = 0; i < 256; i++)
18603 		self->contentPalette[i] = content[76800 + i] << 16 | content[77056 + i] << 8 | content[77312 + i];
18604 	RECOIL_DecodeBytes(self, content, 0);
18605 	return true;
18606 }
18607 
RECOIL_DecodeHs2(RECOIL * self,uint8_t const * content,int contentLength)18608 static bool RECOIL_DecodeHs2(RECOIL *self, uint8_t const *content, int contentLength)
18609 {
18610 	if (contentLength % 105 != 0)
18611 		return false;
18612 	return RECOIL_SetSize(self, 840, contentLength / 105, RECOILResolution_PC1X1) && RECOIL_DecodeBlackAndWhite(self, content, 0, contentLength, false, 0);
18613 }
18614 
RECOIL_DecodeImage72Fnt(RECOIL * self,uint8_t const * content,int contentLength)18615 static bool RECOIL_DecodeImage72Fnt(RECOIL *self, uint8_t const *content, int contentLength)
18616 {
18617 	if (contentLength < 4 || content[0] != 0 || content[1] != 8)
18618 		return false;
18619 	int fontHeight = content[2];
18620 	if (contentLength != 3 + (fontHeight << 8))
18621 		return false;
18622 	RECOIL_SetSize(self, 256, fontHeight << 3, RECOILResolution_PC1X1);
18623 	RECOIL_DecodeBlackAndWhiteFont(self, content, 3, contentLength, fontHeight);
18624 	return true;
18625 }
18626 
RECOIL_DecodeMsp(RECOIL * self,uint8_t const * content,int contentLength)18627 static bool RECOIL_DecodeMsp(RECOIL *self, uint8_t const *content, int contentLength)
18628 {
18629 	if (contentLength < 32)
18630 		return false;
18631 	int width = content[4] | content[5] << 8;
18632 	int height = content[6] | content[7] << 8;
18633 	if (RECOIL_IsStringAt(content, 0, "DanM"))
18634 		return RECOIL_SetSize(self, width, height, RECOILResolution_PC1X1) && RECOIL_DecodeBlackAndWhite(self, content, 32, contentLength, false, 0);
18635 	if (RECOIL_IsStringAt(content, 0, "LinS") && RECOIL_SetSize(self, width, height, RECOILResolution_PC1X1)) {
18636 		MspStream rle;
18637 		MspStream_Construct(&rle);
18638 		rle.base.base.base.content = content;
18639 		rle.base.base.base.contentOffset = 32 + (height << 1);
18640 		rle.base.base.base.contentLength = contentLength;
18641 		return RECOIL_DecodeRleBlackAndWhite(self, &rle.base, 0);
18642 	}
18643 	return false;
18644 }
18645 
RECOIL_DecodeAwbmPalette(RECOIL * self,uint8_t const * content,int contentLength,int paletteOffset,int colors)18646 static bool RECOIL_DecodeAwbmPalette(RECOIL *self, uint8_t const *content, int contentLength, int paletteOffset, int colors)
18647 {
18648 	if (contentLength < paletteOffset + 4 + colors * 3 || !RECOIL_IsStringAt(content, paletteOffset, "RGB "))
18649 		return false;
18650 	for (int i = 0; i < colors; i++) {
18651 		int rgb = RECOIL_GetR8G8B8Color(content, paletteOffset + 4 + i * 3);
18652 		self->contentPalette[i] = (rgb & 4144959) << 2 | (rgb >> 4 & 197379);
18653 	}
18654 	return true;
18655 }
18656 
RECOIL_DecodeAwbm(RECOIL * self,uint8_t const * content,int contentLength)18657 static bool RECOIL_DecodeAwbm(RECOIL *self, uint8_t const *content, int contentLength)
18658 {
18659 	int width = content[4] | content[5] << 8;
18660 	int height = content[6] | content[7] << 8;
18661 	int planeStride = (width + 7) >> 3;
18662 	bool colors256;
18663 	if (RECOIL_DecodeAwbmPalette(self, content, contentLength, 8 + width * height, 256))
18664 		colors256 = true;
18665 	else if (RECOIL_DecodeAwbmPalette(self, content, contentLength, 8 + (height * planeStride << 2), 16))
18666 		colors256 = false;
18667 	else
18668 		return false;
18669 	if (!RECOIL_SetSize(self, width, height, RECOILResolution_PC1X1))
18670 		return false;
18671 	for (int y = 0; y < height; y++) {
18672 		for (int x = 0; x < width; x++) {
18673 			int c;
18674 			if (colors256)
18675 				c = content[8 + y * width + x];
18676 			else {
18677 				int offset = 8 + (y * planeStride << 2) + (x >> 3);
18678 				c = 0;
18679 				for (int bit = 0; bit < 4; bit++) {
18680 					c |= (content[offset] >> (~x & 7) & 1) << bit;
18681 					offset += planeStride;
18682 				}
18683 			}
18684 			self->pixels[y * width + x] = self->contentPalette[c];
18685 		}
18686 	}
18687 	return true;
18688 }
18689 
RECOIL_DecodeEpa(RECOIL * self,uint8_t const * content,int contentLength)18690 static bool RECOIL_DecodeEpa(RECOIL *self, uint8_t const *content, int contentLength)
18691 {
18692 	if (contentLength < 17)
18693 		return false;
18694 	if (RECOIL_IsStringAt(content, 0, "AWBM"))
18695 		return RECOIL_DecodeAwbm(self, content, contentLength);
18696 	int columns = content[0];
18697 	int rows = content[1];
18698 	if (columns > 80 || rows > 25 || contentLength != 2 + columns * rows * 15 + 70)
18699 		return false;
18700 	int width = columns * 8;
18701 	int height = rows * 14;
18702 	RECOIL_SetSize(self, width, height, RECOILResolution_PC1X1);
18703 	int bitmapOffset = 2 + columns * rows;
18704 	for (int y = 0; y < height; y++) {
18705 		for (int x = 0; x < width; x++) {
18706 			int ch = y / 14 * columns + (x >> 3);
18707 			int attribute = content[2 + ch];
18708 			int b = content[bitmapOffset + ch * 14 + y % 14] >> (~x & 7) & 1;
18709 			static const int PALETTE[16] = { 0, 170, 43520, 43690, 11141120, 11141290, 11162880, 11184810, 5592405, 5592575, 5635925, 5636095, 16733525, 16733695, 16777045, 16777215 };
18710 			self->pixels[y * width + x] = PALETTE[b == 0 ? attribute >> 4 : attribute & 15];
18711 		}
18712 	}
18713 	return true;
18714 }
18715 
RECOIL_DecodeElectronika(RECOIL * self,uint8_t const * content)18716 static bool RECOIL_DecodeElectronika(RECOIL *self, uint8_t const *content)
18717 {
18718 	RECOIL_SetSize(self, 256, 256, RECOILResolution_ELECTRONIKA1X1);
18719 	for (int i = 0; i < 65536; i++) {
18720 		static const int PALETTE[4] = { 0, 255, 65280, 16711680 };
18721 		self->pixels[i] = PALETTE[content[i >> 2] >> ((i & 3) << 1) & 3];
18722 	}
18723 	return true;
18724 }
18725 
RECOIL_DecodePic(RECOIL * self,uint8_t const * content,int contentLength)18726 static bool RECOIL_DecodePic(RECOIL *self, uint8_t const *content, int contentLength)
18727 {
18728 	if (RECOIL_DecodePsion3Pic(self, content, contentLength) || RECOIL_DecodeX68KPic(self, content, contentLength))
18729 		return true;
18730 	uint8_t unpacked[7680];
18731 	if (XeKoalaStream_UnpackWrapped(content, contentLength, unpacked, 7680)) {
18732 		RECOIL_SetSize(self, 320, 192, RECOILResolution_XE2X1);
18733 		RECOIL_SetPF0123Bak(self, content, 13);
18734 		uint8_t frame[61440];
18735 		RECOIL_DecodeAtari8Gr15(self, unpacked, 0, 40, frame, 0, 320, 192);
18736 		return RECOIL_ApplyAtari8Palette(self, frame);
18737 	}
18738 	switch (contentLength) {
18739 	case 4325:
18740 		return RECOIL_DecodeGad(self, content, contentLength);
18741 	case 7680:
18742 		return RECOIL_DecodeGr8(self, content, contentLength);
18743 	case 7681:
18744 	case 7682:
18745 	case 7683:
18746 	case 7684:
18747 	case 7685:
18748 		return RECOIL_DecodeMic(self, NULL, content, contentLength);
18749 	case 16384:
18750 		return RECOIL_DecodeElectronika(self, content);
18751 	case 32000:
18752 		return RECOIL_DecodeDoo(self, content, contentLength);
18753 	case 32768:
18754 		return RECOIL_DecodeAppleIIShr(self, content, contentLength);
18755 	default:
18756 		return RECOIL_DecodeStPi(self, content, contentLength) || RECOIL_DecodeSc8(self, NULL, content, contentLength);
18757 	}
18758 }
18759 
RECOIL_DecodeScr(RECOIL * self,const char * filename,uint8_t const * content,int contentLength)18760 static bool RECOIL_DecodeScr(RECOIL *self, const char *filename, uint8_t const *content, int contentLength)
18761 {
18762 	switch (contentLength) {
18763 	case 960:
18764 		return RECOIL_DecodeGr0(self, content, contentLength);
18765 	case 1002:
18766 		return RECOIL_DecodeScrCol(self, filename, content, contentLength);
18767 	case 6144:
18768 		RECOIL_SetZx(self, RECOILResolution_SPECTRUM1X1);
18769 		RECOIL_DecodeZx(self, content, 0, -1, -3, 0);
18770 		return true;
18771 	case 6912:
18772 	case 6913:
18773 		RECOIL_SetZx(self, RECOILResolution_SPECTRUM1X1);
18774 		RECOIL_DecodeZx(self, content, 0, 6144, 3, 0);
18775 		return true;
18776 	case 6976:
18777 		RECOIL_SetUlaPlus(self, content, 6912);
18778 		RECOIL_DecodeZx(self, content, 0, 6144, 3, 0);
18779 		return true;
18780 	case 12288:
18781 		RECOIL_SetZx(self, RECOILResolution_TIMEX1X1);
18782 		RECOIL_DecodeZx(self, content, 0, 6144, -1, 0);
18783 		return true;
18784 	case 12289:
18785 		RECOIL_SetSize(self, 512, 384, RECOILResolution_TIMEX1X2);
18786 		RECOIL_DecodeTimexHires(self, content, 0, 0);
18787 		return true;
18788 	case 12352:
18789 		RECOIL_SetUlaPlus(self, content, 12288);
18790 		RECOIL_DecodeZx(self, content, 0, 6144, -1, 0);
18791 		return true;
18792 	case 32768:
18793 		return RECOIL_DecodeAppleIIShr(self, content, contentLength);
18794 	default:
18795 		return RECOIL_DecodeAmstradScr(self, filename, content, contentLength);
18796 	}
18797 }
18798 
RECOIL_GetPackedExt(const char * filename)18799 static int RECOIL_GetPackedExt(const char *filename)
18800 {
18801 	int ext = 0;
18802 	for (int i = (int) strlen(filename); --i >= 0;) {
18803 		int c = filename[i];
18804 		if (c == 46)
18805 			return ext | 538976288;
18806 		if (c <= 32 || c > 122 || ext >= 16777216)
18807 			return 0;
18808 		ext = (ext << 8) + c;
18809 	}
18810 	return 0;
18811 }
18812 
RECOIL_IsOurFile(const char * filename)18813 bool RECOIL_IsOurFile(const char *filename)
18814 {
18815 	switch (RECOIL_GetPackedExt(filename)) {
18816 	case 540423474:
18817 	case 538976307:
18818 	case 825242163:
18819 	case 544498228:
18820 	case 543780148:
18821 	case 543977524:
18822 	case 544043060:
18823 	case 543372342:
18824 	case 538976353:
18825 	case 544355425:
18826 	case 540292705:
18827 	case 543648119:
18828 	case 544432481:
18829 	case 543715433:
18830 	case 543908449:
18831 	case 544432993:
18832 	case 543975009:
18833 	case 544237409:
18834 	case 544434017:
18835 	case 543976545:
18836 	case 543780193:
18837 	case 540176481:
18838 	case 540242017:
18839 	case 544632929:
18840 	case 543778660:
18841 	case 544237412:
18842 	case 543388517:
18843 	case 543386729:
18844 	case 544045680:
18845 	case 543256673:
18846 	case 543387745:
18847 	case 544042096:
18848 	case 543977569:
18849 	case 544239713:
18850 	case 544436321:
18851 	case 544502369:
18852 	case 544371809:
18853 	case 544679522:
18854 	case 544702306:
18855 	case 540041826:
18856 	case 540107362:
18857 	case 540172898:
18858 	case 540303970:
18859 	case 540369506:
18860 	case 543646306:
18861 	case 1768711778:
18862 	case 540632930:
18863 	case 1937076834:
18864 	case 538996841:
18865 	case 1952672112:
18866 	case 540618855:
18867 	case 544237410:
18868 	case 543648610:
18869 	case 540109922:
18870 	case 540175458:
18871 	case 540240994:
18872 	case 543452258:
18873 	case 543976802:
18874 	case 544567906:
18875 	case 543388514:
18876 	case 878931298:
18877 	case 544240482:
18878 	case 540107107:
18879 	case 540172643:
18880 	case 540238179:
18881 	case 543777635:
18882 	case 544564323:
18883 	case 540108131:
18884 	case 540173667:
18885 	case 540239203:
18886 	case 543974755:
18887 	case 539256931:
18888 	case 540305507:
18889 	case 540436579:
18890 	case 540567651:
18891 	case 543516771:
18892 	case 544368739:
18893 	case 544434275:
18894 	case 544106851:
18895 	case 543517795:
18896 	case 544238691:
18897 	case 540372323:
18898 	case 544238947:
18899 	case 540242019:
18900 	case 543780963:
18901 	case 544370787:
18902 	case 544501859:
18903 	case 543650403:
18904 	case 544044131:
18905 	case 544503139:
18906 	case 543651683:
18907 	case 540303716:
18908 	case 544235876:
18909 	case 540107620:
18910 	case 538993764:
18911 	case 543974756:
18912 	case 540108644:
18913 	case 1919379556:
18914 	case 544368740:
18915 	case 544106852:
18916 	case 544500068:
18917 	case 544042084:
18918 	case 543977316:
18919 	case 543451510:
18920 	case 544173924:
18921 	case 543715428:
18922 	case 543650404:
18923 	case 543978084:
18924 	case 544238692:
18925 	case 544895588:
18926 	case 544240228:
18927 	case 540112228:
18928 	case 544175460:
18929 	case 540177764:
18930 	case 543777637:
18931 	case 544236389:
18932 	case 543256677:
18933 	case 544043877:
18934 	case 543259237:
18935 	case 540031078:
18936 	case 543777382:
18937 	case 544236390:
18938 	case 544501862:
18939 	case 540173414:
18940 	case 1768711782:
18941 	case 543516518:
18942 	case 543583334:
18943 	case 543779942:
18944 	case 540175974:
18945 	case 544501350:
18946 	case 540176486:
18947 	case 544370790:
18948 	case 543388774:
18949 	case 543978854:
18950 	case 544109926:
18951 	case 543258470:
18952 	case 538976359:
18953 	case 540029287:
18954 	case 540094823:
18955 	case 543568487:
18956 	case 543308135:
18957 	case 544422247:
18958 	case 543450739:
18959 	case 543450471:
18960 	case 543319655:
18961 	case 538994535:
18962 	case 543647847:
18963 	case 540372071:
18964 	case 540437607:
18965 	case 540503143:
18966 	case 540568679:
18967 	case 543255655:
18968 	case 543386727:
18969 	case 544435303:
18970 	case 543453031:
18971 	case 540045927:
18972 	case 543388513:
18973 	case 540111463:
18974 	case 540176999:
18975 	case 540242535:
18976 	case 540504679:
18977 	case 540570215:
18978 	case 540635751:
18979 	case 1882813031:
18980 	case 544240231:
18981 	case 538997607:
18982 	case 1936157033:
18983 	case 543896115:
18984 	case 544109927:
18985 	case 544039784:
18986 	case 543450472:
18987 	case 543385192:
18988 	case 543319912:
18989 	case 544368488:
18990 	case 544041320:
18991 	case 544237928:
18992 	case 544369000:
18993 	case 544039528:
18994 	case 543780968:
18995 	case 543713639:
18996 	case 544434022:
18997 	case 544108397:
18998 	case 543449959:
18999 	case 543583336:
19000 	case 544369768:
19001 	case 543387752:
19002 	case 544043112:
19003 	case 544436328:
19004 	case 538997352:
19005 	case 540177000:
19006 	case 543777640:
19007 	case 543650408:
19008 	case 544043624:
19009 	case 544436840:
19010 	case 540177256:
19011 	case 540238441:
19012 	case 543777385:
19013 	case 540107625:
19014 	case 540173161:
19015 	case 540238697:
19016 	case 543515497:
19017 	case 544105321:
19018 	case 543581801:
19019 	case 1835164513:
19020 	case 1835099490:
19021 	case 544498532:
19022 	case 1987339108:
19023 	case 1885693284:
19024 	case 538997348:
19025 	case 544039272:
19026 	case 913138024:
19027 	case 946692456:
19028 	case 544039532:
19029 	case 1835166825:
19030 	case 538996845:
19031 	case 945973106:
19032 	case 1851942770:
19033 	case 1835100275:
19034 	case 543975017:
19035 	case 543516521:
19036 	case 543516777:
19037 	case 544041321:
19038 	case 543452265:
19039 	case 544435305:
19040 	case 543649129:
19041 	case 1735223668:
19042 	case 1735223672:
19043 	case 544107881:
19044 	case 1868983913:
19045 	case 543649385:
19046 	case 544239209:
19047 	case 544435817:
19048 	case 544501353:
19049 	case 540176489:
19050 	case 543387753:
19051 	case 544501865:
19052 	case 540177001:
19053 	case 543650409:
19054 	case 544043881:
19055 	case 544502633:
19056 	case 544237418:
19057 	case 538995306:
19058 	case 544761451:
19059 	case 543451499:
19060 	case 543255659:
19061 	case 543256427:
19062 	case 543648103:
19063 	case 544043122:
19064 	case 544370795:
19065 	case 544437099:
19066 	case 544040044:
19067 	case 544171372:
19068 	case 540242028:
19069 	case 543912044:
19070 	case 543912045:
19071 	case 543912040:
19072 	case 544044396:
19073 	case 543383917:
19074 	case 1735683696:
19075 	case 543646061:
19076 	case 543779693:
19077 	case 544235885:
19078 	case 544760173:
19079 	case 543646317:
19080 	case 538993517:
19081 	case 543712109:
19082 	case 543777645:
19083 	case 544236397:
19084 	case 1886413677:
19085 	case 544433005:
19086 	case 540108653:
19087 	case 540174189:
19088 	case 540305261:
19089 	case 540567405:
19090 	case 544237421:
19091 	case 543385965:
19092 	case 543648109:
19093 	case 543975789:
19094 	case 544434541:
19095 	case 540109933:
19096 	case 543517805:
19097 	case 544500845:
19098 	case 543977581:
19099 	case 544239725:
19100 	case 543978349:
19101 	case 544240493:
19102 	case 544372077:
19103 	case 540113005:
19104 	case 544171374:
19105 	case 540241006:
19106 	case 544304238:
19107 	case 543783022:
19108 	case 544236399:
19109 	case 538976368:
19110 	case 540094832:
19111 	case 543372144:
19112 	case 540095600:
19113 	case 543584871:
19114 	case 543765616:
19115 	case 540292720:
19116 	case 540238192:
19117 	case 543383920:
19118 	case 544760432:
19119 	case 540107632:
19120 	case 540173168:
19121 	case 540238704:
19122 	case 543777648:
19123 	case 544433008:
19124 	case 544498544:
19125 	case 544499056:
19126 	case 540108656:
19127 	case 540174192:
19128 	case 540239728:
19129 	case 543385456:
19130 	case 543582064:
19131 	case 544368496:
19132 	case 538995056:
19133 	case 540109168:
19134 	case 540174704:
19135 	case 540240240:
19136 	case 540371312:
19137 	case 540436848:
19138 	case 543716723:
19139 	case 540305776:
19140 	case 540502384:
19141 	case 540633456:
19142 	case 543385968:
19143 	case 544762224:
19144 	case 540306544:
19145 	case 543255664:
19146 	case 544435312:
19147 	case 543452528:
19148 	case 543649136:
19149 	case 544501360:
19150 	case 538996848:
19151 	case 543715440:
19152 	case 544239728:
19153 	case 543388528:
19154 	case 538981489:
19155 	case 543646066:
19156 	case 544235890:
19157 	case 544694642:
19158 	case 543319922:
19159 	case 543713138:
19160 	case 544237938:
19161 	case 543517810:
19162 	case 540044658:
19163 	case 540110194:
19164 	case 540175730:
19165 	case 540241266:
19166 	case 540306802:
19167 	case 538996850:
19168 	case 543717234:
19169 	case 543979378:
19170 	case 544438642:
19171 	case 544366963:
19172 	case 540044387:
19173 	case 540109923:
19174 	case 540175459:
19175 	case 540043120:
19176 	case 540042099:
19177 	case 540107635:
19178 	case 540173171:
19179 	case 540238707:
19180 	case 540304243:
19181 	case 540369779:
19182 	case 540370279:
19183 	case 540435315:
19184 	case 540500851:
19185 	case 540501351:
19186 	case 540566387:
19187 	case 540566887:
19188 	case 540570227:
19189 	case 543253363:
19190 	case 543384435:
19191 	case 540042355:
19192 	case 540107891:
19193 	case 540173427:
19194 	case 544436851:
19195 	case 543910521:
19196 	case 544367475:
19197 	case 879977331:
19198 	case 540308339:
19199 	case 540239731:
19200 	case 543516531:
19201 	case 544761715:
19202 	case 540239987:
19203 	case 808464947:
19204 	case 543385715:
19205 	case 544237683:
19206 	case 544368755:
19207 	case 543582579:
19208 	case 544238451:
19209 	case 543387763:
19210 	case 543453299:
19211 	case 544370803:
19212 	case 544436339:
19213 	case 544567411:
19214 	case 544764019:
19215 	case 540373619:
19216 	case 540439155:
19217 	case 540504691:
19218 	case 543781491:
19219 	case 544502387:
19220 	case 543322995:
19221 	case 543978611:
19222 	case 544240755:
19223 	case 543651955:
19224 	case 544438387:
19225 	case 544236404:
19226 	case 540108660:
19227 	case 544041332:
19228 	case 544237940:
19229 	case 540110452:
19230 	case 540175988:
19231 	case 540241524:
19232 	case 540307060:
19233 	case 540372596:
19234 	case 540438132:
19235 	case 544829044:
19236 	case 543780980:
19237 	case 543519348:
19238 	case 544240244:
19239 	case 544567924:
19240 	case 540047476:
19241 	case 543520884:
19242 	case 544438388:
19243 	case 544039542:
19244 	case 538996066:
19245 	case 543385974:
19246 	case 543783542:
19247 	case 544106871:
19248 	case 543452791:
19249 	case 543254392:
19250 	case 544238712:
19251 	case 544041338:
19252 	case 540110970:
19253 	case 544241786:
19254 		return true;
19255 	default:
19256 		return false;
19257 	}
19258 }
19259 
RECOIL_Decode(RECOIL * self,const char * filename,uint8_t const * content,int contentLength)19260 bool RECOIL_Decode(RECOIL *self, const char *filename, uint8_t const *content, int contentLength)
19261 {
19262 	switch (RECOIL_GetPackedExt(filename)) {
19263 	case 540423474:
19264 		return RECOIL_DecodeIff(self, content, contentLength, RECOILResolution_AMIGA1X1) || RECOIL_Decode256(self, content, contentLength);
19265 	case 538976307:
19266 		return RECOIL_Decode3(self, content, contentLength);
19267 	case 825242163:
19268 		return RECOIL_Decode3201(self, content, contentLength);
19269 	case 544498228:
19270 		return RECOIL_Decode4bt(self, content, contentLength);
19271 	case 543780148:
19272 		return RECOIL_Decode4mi(self, content, contentLength);
19273 	case 543977524:
19274 		return RECOIL_Decode4pl(self, content, contentLength);
19275 	case 544043060:
19276 		return RECOIL_Decode4pm(self, content, contentLength);
19277 	case 543372342:
19278 		return RECOIL_Decode64c(self, content, contentLength);
19279 	case 538976353:
19280 		return RECOIL_DecodeA(self, content, contentLength);
19281 	case 544355425:
19282 		return RECOIL_DecodeA4r(self, content, contentLength);
19283 	case 540292705:
19284 	case 543648119:
19285 		return contentLength == 10242 && RECOIL_DecodeC64Multicolor(self, 320, content, 2, 8194, 9218, content[10241]);
19286 	case 544432481:
19287 	case 543715433:
19288 		return RECOIL_DecodeIph(self, content, contentLength);
19289 	case 543908449:
19290 		return RECOIL_DecodeAbk(self, content, contentLength);
19291 	case 544432993:
19292 		return RECOIL_DecodeAcs(self, content, contentLength);
19293 	case 543975009:
19294 		return RECOIL_DecodeAfl(self, content, contentLength);
19295 	case 544237409:
19296 		return RECOIL_DecodeAgp(self, content, contentLength);
19297 	case 544434017:
19298 		return RECOIL_DecodeAgs(self, content, contentLength);
19299 	case 543976545:
19300 		return RECOIL_DecodeAll(self, content, contentLength);
19301 	case 543780193:
19302 		return RECOIL_DecodeAmi(self, content, contentLength);
19303 	case 540176481:
19304 		return RECOIL_Decode256(self, content, contentLength);
19305 	case 540242017:
19306 	case 544632929:
19307 	case 543778660:
19308 	case 544237412:
19309 	case 543388517:
19310 	case 543386729:
19311 	case 544045680:
19312 		return RECOIL_DecodeAp3(self, content, contentLength);
19313 	case 543256673:
19314 	case 543387745:
19315 	case 544042096:
19316 		return RECOIL_DecodeApc(self, content, contentLength);
19317 	case 543977569:
19318 		return RECOIL_DecodeApl(self, content, contentLength);
19319 	case 544239713:
19320 		return RECOIL_DecodeApp(self, content, contentLength);
19321 	case 544436321:
19322 		return RECOIL_DecodeAps(self, content, contentLength);
19323 	case 544502369:
19324 		return RECOIL_DecodeIph(self, content, contentLength) || RECOIL_DecodeArtDirector(self, content, contentLength) || RECOIL_DecodeGfaArtist(self, content, contentLength) || RECOIL_DecodePaletteMaster(self, content, contentLength) || RECOIL_DecodeAtari8Artist(self, content, contentLength) || RECOIL_DecodeAsciiArtEditor(self, content, contentLength);
19325 	case 544371809:
19326 		return RECOIL_DecodeAtr(self, content, contentLength);
19327 	case 544679522:
19328 	case 544702306:
19329 		return RECOIL_DecodeBw(self, content, contentLength);
19330 	case 540041826:
19331 		return RECOIL_DecodeBb0(self, content, contentLength, RECOIL_BBC_PALETTE1_BIT);
19332 	case 540107362:
19333 		return RECOIL_DecodeBb1(self, content, contentLength, RECOIL_BBC_PALETTE2_BIT);
19334 	case 540172898:
19335 		return RECOIL_DecodeBb2(self, content, contentLength, RECOIL_BBC_PALETTE);
19336 	case 540303970:
19337 		return RECOIL_DecodeBb4(self, content, contentLength, RECOIL_BBC_PALETTE1_BIT);
19338 	case 540369506:
19339 		return RECOIL_DecodeBb5(self, content, contentLength, RECOIL_BBC_PALETTE2_BIT);
19340 	case 543646306:
19341 		return RECOIL_DecodeBbg(self, content, contentLength);
19342 	case 1768711778:
19343 		return RECOIL_DecodeBfli(self, content, contentLength);
19344 	case 540632930:
19345 	case 540618855:
19346 		return RECOIL_DecodeG09(self, content, contentLength);
19347 	case 544237410:
19348 		return RECOIL_DecodeBgp(self, content, contentLength);
19349 	case 543648610:
19350 		return RECOIL_DecodeBkg(self, content, contentLength);
19351 	case 1937076834:
19352 	case 538996841:
19353 	case 1952672112:
19354 		return RECOIL_DecodeBrus(self, content, contentLength);
19355 	case 540109922:
19356 	case 540175458:
19357 	case 540240994:
19358 		return RECOIL_DecodeIff(self, content, contentLength, RECOILResolution_ST1X1);
19359 	case 543452258:
19360 		return RECOIL_DecodeBld(self, content, contentLength);
19361 	case 543976802:
19362 		return RECOIL_DecodeBml(self, content, contentLength);
19363 	case 544567906:
19364 		return RECOIL_DecodeBru(self, content, contentLength);
19365 	case 543388514:
19366 	case 878931298:
19367 		return RECOIL_DecodeBsc(self, content, contentLength);
19368 	case 544240482:
19369 		return RECOIL_DecodeBsp(self, content, contentLength);
19370 	case 540107107:
19371 	case 540172643:
19372 	case 540238179:
19373 		return RECOIL_DecodeCa(self, content, contentLength);
19374 	case 543777635:
19375 		return RECOIL_DecodeCci(self, content, contentLength);
19376 	case 544564323:
19377 		return contentLength == 10277 && RECOIL_DecodeC64Multicolor(self, 320, content, 275, 8275, 9275, content[10275]);
19378 	case 540108131:
19379 	case 540173667:
19380 	case 540239203:
19381 		return RECOIL_DecodeCe(self, content, contentLength);
19382 	case 543974755:
19383 		return RECOIL_DecodeCel(self, content, contentLength);
19384 	case 539256931:
19385 		return RECOIL_DecodeChrd(self, content, contentLength);
19386 	case 540305507:
19387 	case 540436579:
19388 	case 540567651:
19389 		return RECOIL_DecodeCh8(self, content, contentLength);
19390 	case 543516771:
19391 		return contentLength == 20482 && RECOIL_DecodeC64Multicolor(self, 320, content, 2, 16898, 18434, content[20479]);
19392 	case 544368739:
19393 		return RECOIL_DecodeChr(self, content, contentLength);
19394 	case 544434275:
19395 		return RECOIL_DecodeChs(self, content, contentLength);
19396 	case 544106851:
19397 		return RECOIL_DecodeCin(self, content, contentLength);
19398 	case 543517795:
19399 		return RECOIL_DecodeCle(self, content, contentLength);
19400 	case 544238691:
19401 		return RECOIL_DecodeClp(self, content, contentLength);
19402 	case 540372323:
19403 		return RECOIL_DecodeCm5(self, filename, content, contentLength);
19404 	case 544238947:
19405 		return RECOIL_DecodeCmp(self, content, contentLength);
19406 	case 540242019:
19407 		return RECOIL_DecodeCp3(self, content, contentLength);
19408 	case 543780963:
19409 		return RECOIL_DecodeCpi(self, content, contentLength);
19410 	case 544370787:
19411 		return RECOIL_DecodeCpr(self, content, contentLength);
19412 	case 544501859:
19413 		return RECOIL_DecodeCpt(self, filename, content, contentLength);
19414 	case 543650403:
19415 		return RECOIL_DecodeCrg(self, content, contentLength);
19416 	case 544044131:
19417 		return RECOIL_DecodeCtm(self, content, contentLength);
19418 	case 544503139:
19419 		return RECOIL_DecodeGr8Raw(self, content, contentLength, 96, 99);
19420 	case 543651683:
19421 		return contentLength == 10007 && RECOIL_DecodeC64Multicolor(self, 320, content, 2, 8002, 9002, content[10003]);
19422 	case 540303716:
19423 		return RECOIL_DecodeDa4(self, content, contentLength);
19424 	case 544235876:
19425 		return RECOIL_DecodeDap(self, content, contentLength);
19426 	case 540107620:
19427 		return RECOIL_DecodeDc1(self, content, contentLength);
19428 	case 538993764:
19429 		return RECOIL_DecodeDd(self, content, contentLength);
19430 	case 543974756:
19431 		return RECOIL_DecodeDel(self, content, contentLength);
19432 	case 540108644:
19433 		return RECOIL_DecodeDg1(self, content, contentLength);
19434 	case 1919379556:
19435 		return RECOIL_DecodeAppleIIDhr(self, content, contentLength);
19436 	case 544368740:
19437 		return RECOIL_DecodeIff(self, content, contentLength, RECOILResolution_AMIGA1X1) || RECOIL_DecodeAppleIIDhr(self, content, contentLength);
19438 	case 544106852:
19439 		return RECOIL_DecodeAtari8Ice(self, content, contentLength, false, 3);
19440 	case 544500068:
19441 		return RECOIL_DecodeDit(self, content, contentLength);
19442 	case 544042084:
19443 		return RECOIL_DecodeDlm(self, content, contentLength);
19444 	case 543977316:
19445 	case 543451510:
19446 		return RECOIL_DecodeDol(self, content, contentLength);
19447 	case 544173924:
19448 		return RECOIL_DecodeDoo(self, content, contentLength);
19449 	case 543715428:
19450 		return RECOIL_DecodeDph(self, content, contentLength);
19451 	case 543650404:
19452 		return RECOIL_DecodeDrg(self, content, contentLength);
19453 	case 543978084:
19454 	case 544238692:
19455 		return RECOIL_DecodeDrl(self, content, contentLength);
19456 	case 544895588:
19457 	case 544240228:
19458 		return RECOIL_DecodeDrz(self, content, contentLength);
19459 	case 540112228:
19460 	case 544175460:
19461 		return RECOIL_DecodeDuo(self, content, contentLength);
19462 	case 540177764:
19463 		return RECOIL_DecodeDu2(self, content, contentLength);
19464 	case 543777637:
19465 		return RECOIL_DecodeEci(self, content, contentLength);
19466 	case 544236389:
19467 		return RECOIL_DecodeEcp(self, content, contentLength);
19468 	case 543256677:
19469 		return RECOIL_DecodeEpa(self, content, contentLength);
19470 	case 544043877:
19471 		return RECOIL_DecodeEsm(self, content, contentLength);
19472 	case 543259237:
19473 		return RECOIL_DecodeEza(self, content, contentLength);
19474 	case 540031078:
19475 		return RECOIL_DecodeF80(self, content, contentLength);
19476 	case 543777382:
19477 		return RECOIL_DecodeFbi(self, content, contentLength);
19478 	case 544236390:
19479 	case 544501862:
19480 		return contentLength == 10004 && RECOIL_DecodeC64Multicolor(self, 320, content, 2, 8002, 9002, content[10002]);
19481 	case 540173414:
19482 		return RECOIL_DecodeFli(self, content, contentLength);
19483 	case 1768711782:
19484 		return RECOIL_DecodeFfli(self, content, contentLength);
19485 	case 543516518:
19486 		return RECOIL_DecodeFge(self, content, contentLength);
19487 	case 543583334:
19488 		return RECOIL_DecodeFlf(self, content, contentLength);
19489 	case 543779942:
19490 		return RECOIL_DecodeFli(self, content, contentLength) || RECOIL_DecodeBml(self, content, contentLength);
19491 	case 540175974:
19492 		return RECOIL_DecodeFn2(self, content, contentLength);
19493 	case 544501350:
19494 		return RECOIL_DecodePct(self, content, contentLength) || RECOIL_DecodeGdosFnt(self, content, contentLength) || RECOIL_DecodeAtari8Fnt(self, content, contentLength) || RECOIL_DecodeStFnt(self, content, contentLength) || RECOIL_DecodeAmstradFnt(self, content, contentLength) || RECOIL_DecodeImage72Fnt(self, content, contentLength);
19495 	case 540176486:
19496 		return RECOIL_DecodeC64Fun(self, content, contentLength);
19497 	case 544370790:
19498 		return RECOIL_DecodeFpr(self, content, contentLength);
19499 	case 543388774:
19500 		return RECOIL_DecodeFtc(self, content, contentLength);
19501 	case 543978854:
19502 		return RECOIL_DecodeFul(self, content, contentLength);
19503 	case 544109926:
19504 		return RECOIL_DecodeC64Fun(self, content, contentLength) || RECOIL_DecodeFalconFun(self, content, contentLength);
19505 	case 543258470:
19506 		return RECOIL_DecodeFwa(self, content, contentLength);
19507 	case 538976359:
19508 		return RECOIL_DecodeG(self, content, contentLength);
19509 	case 540029287:
19510 		return RECOIL_DecodeG10(self, content, contentLength);
19511 	case 540094823:
19512 		return RECOIL_DecodeG11(self, content, contentLength);
19513 	case 543568487:
19514 		return RECOIL_DecodeG2f(self, content, contentLength);
19515 	case 543308135:
19516 		return RECOIL_DecodeG9b(self, content, contentLength);
19517 	case 544422247:
19518 	case 543450739:
19519 		return RECOIL_DecodeG9s(self, content, contentLength);
19520 	case 543450471:
19521 		return RECOIL_DecodeGed(self, content, contentLength);
19522 	case 543319655:
19523 		return RECOIL_DecodeGfb(self, content, contentLength);
19524 	case 538994535:
19525 		return RECOIL_DecodeGg(self, content, contentLength);
19526 	case 543647847:
19527 		return RECOIL_DecodeGhg(self, content, contentLength);
19528 	case 540372071:
19529 		return RECOIL_DecodeGl5(self, filename, content, contentLength);
19530 	case 540437607:
19531 		return RECOIL_DecodeGl6(self, filename, content, contentLength);
19532 	case 540503143:
19533 		return RECOIL_DecodeGl7(self, filename, content, contentLength);
19534 	case 540568679:
19535 		return RECOIL_DecodeGl8(self, content, contentLength);
19536 	case 543255655:
19537 		return RECOIL_DecodeGlYjk(self, filename, content, contentLength);
19538 	case 543386727:
19539 	case 544435303:
19540 		return RECOIL_DecodeGlYjk(self, NULL, content, contentLength);
19541 	case 543453031:
19542 		return RECOIL_DecodeGod(self, content, contentLength);
19543 	case 540045927:
19544 	case 543388513:
19545 		return RECOIL_DecodeGr0(self, content, contentLength);
19546 	case 540111463:
19547 		return RECOIL_DecodeGr1(self, content, contentLength, 0);
19548 	case 540176999:
19549 		return RECOIL_DecodeGr1(self, content, contentLength, 1);
19550 	case 540242535:
19551 		return RECOIL_DecodeGr3(self, content, contentLength);
19552 	case 540504679:
19553 		return RECOIL_DecodeGr7(self, content, 0, contentLength);
19554 	case 540570215:
19555 		return RECOIL_DecodeGr8(self, content, contentLength);
19556 	case 540635751:
19557 		return RECOIL_DecodeGr9(self, content, contentLength);
19558 	case 1882813031:
19559 		return RECOIL_DecodeGr9p(self, content, contentLength);
19560 	case 544240231:
19561 		return RECOIL_DecodeSc2(self, content, contentLength);
19562 	case 538997607:
19563 	case 1936157033:
19564 	case 543896115:
19565 		return RECOIL_DecodeApfShr(self, content, contentLength);
19566 	case 544109927:
19567 		return RECOIL_DecodeGun(self, content, contentLength);
19568 	case 544039784:
19569 		return RECOIL_DecodeHcm(self, content, contentLength);
19570 	case 543450472:
19571 		return RECOIL_DecodeHed(self, content, contentLength);
19572 	case 543385192:
19573 		return RECOIL_DecodeHfc(self, content, contentLength);
19574 	case 543319912:
19575 		return RECOIL_DecodeHgb(self, content, contentLength);
19576 	case 544368488:
19577 		return RECOIL_DecodeHgr(self, content, contentLength);
19578 	case 544041320:
19579 		return RECOIL_DecodeHim(self, content, contentLength);
19580 	case 544237928:
19581 		return RECOIL_DecodeHip(self, content, contentLength);
19582 	case 544369000:
19583 		return RECOIL_DecodeFalconHir(self, content, contentLength) || RECOIL_DecodeC64Hir(self, content, contentLength) || RECOIL_DecodeHrs(self, content, contentLength);
19584 	case 544039528:
19585 	case 543780968:
19586 	case 543713639:
19587 	case 544434022:
19588 	case 544108397:
19589 	case 543449959:
19590 		return RECOIL_DecodeC64Hir(self, content, contentLength);
19591 	case 543583336:
19592 		return RECOIL_DecodeHlf(self, content, contentLength);
19593 	case 544369768:
19594 		return RECOIL_DecodeHlr(self, content, contentLength);
19595 	case 543387752:
19596 		return RECOIL_DecodeIph(self, content, contentLength);
19597 	case 544043112:
19598 		return RECOIL_DecodeHpm(self, content, contentLength);
19599 	case 544436328:
19600 		return RECOIL_DecodeHps(self, content, contentLength);
19601 	case 538997352:
19602 		return RECOIL_DecodeTrsHr(self, content, contentLength) || RECOIL_DecodeAtari8Hr(self, content, contentLength);
19603 	case 540177000:
19604 	case 543777640:
19605 		return RECOIL_DecodeHr2(self, content, contentLength);
19606 	case 543650408:
19607 		return RECOIL_DecodeHrg(self, content, contentLength);
19608 	case 544043624:
19609 		return RECOIL_DecodeHrm(self, content, contentLength);
19610 	case 544436840:
19611 		return RECOIL_DecodeHrs(self, content, contentLength);
19612 	case 540177256:
19613 		return RECOIL_DecodeHs2(self, content, contentLength);
19614 	case 540238441:
19615 	case 543777385:
19616 		return RECOIL_DecodeIbi(self, content, contentLength);
19617 	case 540107625:
19618 	case 540173161:
19619 	case 540238697:
19620 		return RECOIL_DecodeIc(self, content, contentLength);
19621 	case 543515497:
19622 		return contentLength > 1024 && RECOIL_DecodeAtari8Ice(self, content, contentLength, true, content[0]);
19623 	case 544105321:
19624 		return RECOIL_DecodeStIcn(self, content, contentLength) || RECOIL_DecodePsion3Pic(self, content, contentLength) || RECOIL_DecodeAtari8Ice(self, content, contentLength, false, 17);
19625 	case 543581801:
19626 	case 1835164513:
19627 	case 1835099490:
19628 	case 544498532:
19629 	case 1987339108:
19630 	case 1885693284:
19631 	case 538997348:
19632 	case 544039272:
19633 	case 913138024:
19634 	case 946692456:
19635 	case 544039532:
19636 	case 1835166825:
19637 	case 538996845:
19638 	case 945973106:
19639 	case 1851942770:
19640 	case 1835100275:
19641 		return RECOIL_DecodeIff(self, content, contentLength, RECOILResolution_AMIGA1X1);
19642 	case 543975017:
19643 		return RECOIL_DecodeGun(self, content, contentLength) || RECOIL_DecodeZxIfl(self, content, contentLength);
19644 	case 543516521:
19645 		return RECOIL_DecodeIge(self, content, contentLength);
19646 	case 543516777:
19647 		return RECOIL_DecodeIhe(self, content, contentLength);
19648 	case 544041321:
19649 		return RECOIL_DecodeIim(self, content, contentLength);
19650 	case 543452265:
19651 		return RECOIL_DecodeIld(self, content, contentLength);
19652 	case 544435305:
19653 		return RECOIL_DecodeIls(self, content, contentLength);
19654 	case 543649129:
19655 		return RECOIL_DecodeStImg(self, content, contentLength) || RECOIL_DecodeZxImg(self, content, contentLength) || RECOIL_DecodeArtMaster88(self, content, contentLength) || RECOIL_DecodeDaVinci(self, content, contentLength);
19656 	case 1735223668:
19657 	case 1735223672:
19658 		return RECOIL_DecodeStImg(self, content, contentLength);
19659 	case 544107881:
19660 		return RECOIL_DecodeAtari8Ice(self, content, contentLength, false, 18);
19661 	case 1868983913:
19662 		return RECOIL_DecodeInfo(self, content, contentLength);
19663 	case 543649385:
19664 	case 544239209:
19665 		return RECOIL_DecodeInp(self, content, contentLength);
19666 	case 544435817:
19667 		return RECOIL_DecodeIns(self, content, contentLength);
19668 	case 544501353:
19669 		return RECOIL_DecodeInt(self, content, contentLength) || RECOIL_DecodeInp(self, content, contentLength);
19670 	case 540176489:
19671 		return RECOIL_DecodeIp2(self, content, contentLength);
19672 	case 543387753:
19673 		return RECOIL_DecodeAtari8Ice(self, content, contentLength, false, 19);
19674 	case 544501865:
19675 		return contentLength == 10003 && RECOIL_DecodeC64Multicolor(self, 320, content, 2, 8002, 9002, content[10002]);
19676 	case 540177001:
19677 		return RECOIL_DecodeAtari8Ice(self, content, contentLength, false, 2);
19678 	case 543650409:
19679 		return RECOIL_DecodeAtari8Ice(self, content, contentLength, false, 1);
19680 	case 544043881:
19681 		return contentLength == 10218 && RECOIL_DecodeC64Multicolor(self, 320, content, 1026, 9218, 2, content[9217]);
19682 	case 544502633:
19683 		return RECOIL_DecodeIst(self, content, contentLength);
19684 	case 544237418:
19685 		return RECOIL_DecodeJgp(self, content, contentLength);
19686 	case 538995306:
19687 		return RECOIL_DecodeJj(self, content, contentLength);
19688 	case 544761451:
19689 		return RECOIL_DecodeGr8Raw(self, content, contentLength, 56, 60);
19690 	case 543451499:
19691 		return RECOIL_DecodeKid(self, content, contentLength);
19692 	case 543255659:
19693 	case 543256427:
19694 	case 543648103:
19695 	case 544043122:
19696 		return RECOIL_DecodeKoa(self, content, contentLength);
19697 	case 544370795:
19698 		return RECOIL_DecodeKpr(self, content, contentLength);
19699 	case 544437099:
19700 		return RECOIL_DecodeKss(self, content, contentLength);
19701 	case 544040044:
19702 		return RECOIL_DecodeLdm(self, content, contentLength);
19703 	case 544171372:
19704 		return RECOIL_DecodeLeo(self, content, contentLength);
19705 	case 540242028:
19706 		return RECOIL_DecodeLp3(self, content, contentLength);
19707 	case 543912044:
19708 		return RECOIL_DecodeDaliCompressed(self, content, contentLength, 0);
19709 	case 543912045:
19710 		return RECOIL_DecodeDaliCompressed(self, content, contentLength, 1);
19711 	case 543912040:
19712 		return RECOIL_DecodeDaliCompressed(self, content, contentLength, 2);
19713 	case 544044396:
19714 		return RECOIL_DecodeLum(self, filename, content, contentLength);
19715 	case 543383917:
19716 	case 1735683696:
19717 		return RECOIL_DecodeMac(self, content, contentLength);
19718 	case 543646061:
19719 	case 543779693:
19720 		return RECOIL_DecodeMag(self, content, contentLength);
19721 	case 544235885:
19722 		return RECOIL_DecodeEnvision(self, content, contentLength) || RECOIL_DecodeEnvisionPC(self, content, contentLength);
19723 	case 544760173:
19724 		return RECOIL_DecodeMag(self, content, contentLength) || RECOIL_DecodeAtari8Max(self, content, contentLength) || RECOIL_DecodeCocoMax(self, content, contentLength);
19725 	case 543646317:
19726 		return RECOIL_DecodeGr8Raw(self, content, contentLength, 512, 256);
19727 	case 538993517:
19728 		return RECOIL_DecodeMcMlt(self, content, contentLength, -1);
19729 	case 543712109:
19730 		return RECOIL_DecodeMch(self, content, contentLength);
19731 	case 543777645:
19732 		return RECOIL_DecodeMci(self, content, contentLength);
19733 	case 544236397:
19734 		return RECOIL_DecodeMcp(self, content, contentLength);
19735 	case 1886413677:
19736 		return RECOIL_DecodeMcpp(self, content, contentLength);
19737 	case 544433005:
19738 		return RECOIL_DecodeMcs(self, content, contentLength);
19739 	case 540108653:
19740 	case 540174189:
19741 	case 540305261:
19742 	case 540567405:
19743 		return RECOIL_DecodeMg(self, content, contentLength);
19744 	case 544237421:
19745 		return RECOIL_DecodeMgp(self, content, contentLength);
19746 	case 543385965:
19747 		return RECOIL_DecodeMic(self, filename, content, contentLength);
19748 	case 543648109:
19749 		return RECOIL_DecodeMig(self, content, contentLength);
19750 	case 543975789:
19751 		return contentLength == 10022 && RECOIL_DecodeC64Multicolor(self, 320, content, 2022, 22, 1022, 0);
19752 	case 544434541:
19753 		return RECOIL_DecodeMis(self, content, contentLength);
19754 	case 540109933:
19755 		return RECOIL_DecodeMl1(self, content, contentLength);
19756 	case 543517805:
19757 		return RECOIL_DecodeMle(self, content, contentLength);
19758 	case 544500845:
19759 		return RECOIL_DecodeMcMlt(self, content, contentLength, 0);
19760 	case 543977581:
19761 		return RECOIL_DecodeMpl(self, content, contentLength);
19762 	case 544239725:
19763 		return RECOIL_DecodeMpp(self, content, contentLength);
19764 	case 543978349:
19765 		return RECOIL_DecodeMsl(self, content, contentLength);
19766 	case 544240493:
19767 		return RECOIL_DecodeMsp(self, content, contentLength);
19768 	case 544372077:
19769 		return RECOIL_DecodeMur(self, filename, content, contentLength);
19770 	case 540113005:
19771 		return RECOIL_DecodeMx1(self, content, contentLength);
19772 	case 544171374:
19773 		return RECOIL_DecodeNeo(self, filename, content, contentLength) || RECOIL_DecodeIff(self, content, contentLength, RECOILResolution_STE1X1);
19774 	case 540241006:
19775 		return RECOIL_DecodeNl3(self, content, contentLength);
19776 	case 544304238:
19777 		return RECOIL_DecodeNlq(self, content, contentLength);
19778 	case 543783022:
19779 		return RECOIL_DecodeNxi(self, content, contentLength);
19780 	case 544236399:
19781 		return RECOIL_DecodeOcp(self, content, contentLength);
19782 	case 538976368:
19783 		return RECOIL_DecodeP(self, content, contentLength);
19784 	case 540094832:
19785 		return RECOIL_DecodeP11(self, content, contentLength);
19786 	case 543372144:
19787 		return RECOIL_DecodeP3c(self, content, contentLength);
19788 	case 540095600:
19789 	case 543584871:
19790 		return RECOIL_DecodeCocoMax(self, content, contentLength);
19791 	case 543765616:
19792 		return RECOIL_DecodeP4i(self, content, contentLength);
19793 	case 540292720:
19794 		return contentLength == 10050 && RECOIL_DecodeC64Multicolor(self, 320, content, 2050, 1026, 2, content[2049]);
19795 	case 540238192:
19796 		return RECOIL_DecodeStPpp(self, content, contentLength);
19797 	case 543383920:
19798 		return RECOIL_DecodePac(self, content, contentLength);
19799 	case 544760432:
19800 		return RECOIL_DecodePbx(self, content, contentLength);
19801 	case 540107632:
19802 	case 540173168:
19803 	case 540238704:
19804 		return RECOIL_DecodePc(self, content, contentLength);
19805 	case 543777648:
19806 		return RECOIL_DecodePci(self, content, contentLength);
19807 	case 544433008:
19808 		return RECOIL_DecodePcs(self, content, contentLength);
19809 	case 544498544:
19810 		return RECOIL_DecodePct(self, content, contentLength);
19811 	case 544499056:
19812 		return RECOIL_DecodePet(self, content, contentLength);
19813 	case 540108656:
19814 	case 540174192:
19815 		return RECOIL_DecodeSc(self, content, contentLength) || RECOIL_DecodeGraphicsProcessor(self, content, contentLength);
19816 	case 540239728:
19817 		return RECOIL_DecodeGraphicsProcessor(self, content, contentLength);
19818 	case 543385456:
19819 		return RECOIL_DecodePgc(self, content, contentLength);
19820 	case 543582064:
19821 		return RECOIL_DecodePgf(self, content, contentLength);
19822 	case 544368496:
19823 		return RECOIL_DecodePgr(self, content, contentLength);
19824 	case 538995056:
19825 		return RECOIL_DecodePi(self, content, contentLength) || (contentLength == 10242 && RECOIL_DecodeC64Multicolor(self, 320, content, 2, 8194, 9218, content[8066]));
19826 	case 540109168:
19827 	case 540174704:
19828 	case 540240240:
19829 	case 540371312:
19830 	case 540436848:
19831 	case 543716723:
19832 		return RECOIL_DecodeStPi(self, content, contentLength);
19833 	case 540305776:
19834 		return RECOIL_DecodeFuckpaint(self, content, contentLength) || RECOIL_DecodeStPi(self, content, contentLength);
19835 	case 540502384:
19836 	case 540633456:
19837 		return RECOIL_DecodeFuckpaint(self, content, contentLength);
19838 	case 543385968:
19839 		return RECOIL_DecodePic(self, content, contentLength);
19840 	case 544762224:
19841 		return RECOIL_DecodeFalconPix(self, content, contentLength) || RECOIL_DecodeCocoMax(self, content, contentLength);
19842 	case 540306544:
19843 		return RECOIL_DecodePl4(self, content, contentLength);
19844 	case 543255664:
19845 		return RECOIL_DecodePla(self, content, contentLength);
19846 	case 544435312:
19847 		return RECOIL_DecodePls(self, content, contentLength);
19848 	case 543452528:
19849 		return RECOIL_DecodePmd(self, content, contentLength);
19850 	case 543649136:
19851 		return RECOIL_DecodePmg(self, content, contentLength);
19852 	case 544501360:
19853 		return RECOIL_DecodeFalconPnt(self, content, contentLength) || RECOIL_DecodeApfShr(self, content, contentLength) || RECOIL_DecodeMac(self, content, contentLength) || RECOIL_DecodeAppleIIShr(self, content, contentLength) || RECOIL_DecodePaintworks(self, content, contentLength);
19854 	case 538996848:
19855 		return RECOIL_DecodePp(self, content, contentLength);
19856 	case 543715440:
19857 		return RECOIL_DecodePph(self, filename, content, contentLength);
19858 	case 544239728:
19859 		return RECOIL_DecodeStPpp(self, content, contentLength) || RECOIL_DecodePp(self, content, contentLength);
19860 	case 543388528:
19861 		return RECOIL_DecodePsc(self, content, contentLength);
19862 	case 538981489:
19863 		return RECOIL_DecodeQ4(self, content, contentLength);
19864 	case 543646066:
19865 		return RECOIL_DecodeRag(self, content, contentLength);
19866 	case 544235890:
19867 		return RECOIL_DecodeRap(self, content, contentLength);
19868 	case 544694642:
19869 		return RECOIL_DecodeZx81Raw(self, content, contentLength) || RECOIL_DecodeAtari8Raw(self, content, contentLength) || RECOIL_DecodeRw(self, content, contentLength);
19870 	case 543319922:
19871 		return RECOIL_DecodeStRgb(self, content, contentLength) || RECOIL_DecodeAtari8Rgb(self, content, contentLength) || RECOIL_DecodeZxRgb(self, content, contentLength);
19872 	case 543713138:
19873 		return RECOIL_DecodeRgh(self, content, contentLength);
19874 	case 544237938:
19875 		return RECOIL_DecodeRip(self, content, contentLength);
19876 	case 543517810:
19877 		return RECOIL_DecodeRle(self, content, contentLength);
19878 	case 540044658:
19879 		return RECOIL_DecodeRm(self, content, contentLength, 0, RECOILResolution_XE2X2);
19880 	case 540110194:
19881 		return RECOIL_DecodeRm(self, content, contentLength, 1, RECOILResolution_XE4X1);
19882 	case 540175730:
19883 		return RECOIL_DecodeRm(self, content, contentLength, 2, RECOILResolution_XE4X1);
19884 	case 540241266:
19885 		return RECOIL_DecodeRm(self, content, contentLength, 3, RECOILResolution_XE4X1);
19886 	case 540306802:
19887 		return RECOIL_DecodeRm(self, content, contentLength, 4, RECOILResolution_XE2X1);
19888 	case 538996850:
19889 		return contentLength == 10242 && RECOIL_DecodeC64Multicolor(self, 320, content, 1026, 2, 9218, 0);
19890 	case 543717234:
19891 	case 543979378:
19892 		return RECOIL_DecodeRw(self, content, contentLength);
19893 	case 544438642:
19894 		return RECOIL_DecodeRys(self, content, contentLength);
19895 	case 544366963:
19896 		return contentLength == 10219 && RECOIL_DecodeC64Multicolor(self, 320, content, 1026, 2, 9218, content[1010]);
19897 	case 540044387:
19898 	case 540109923:
19899 	case 540175459:
19900 	case 540043120:
19901 	case 540042099:
19902 	case 540107635:
19903 		return RECOIL_DecodeSc(self, content, contentLength);
19904 	case 540173171:
19905 		return RECOIL_DecodeSc(self, content, contentLength) || RECOIL_DecodeSc2(self, content, contentLength);
19906 	case 540238707:
19907 		return RECOIL_DecodeSc3(self, content, contentLength);
19908 	case 540304243:
19909 		return RECOIL_DecodeSc4(self, content, contentLength);
19910 	case 540369779:
19911 	case 540370279:
19912 		return RECOIL_DecodeSc5(self, filename, content, contentLength);
19913 	case 540435315:
19914 		return RECOIL_DecodeSc6(self, filename, content, contentLength);
19915 	case 540500851:
19916 	case 540501351:
19917 		return RECOIL_DecodeSc7(self, filename, content, contentLength);
19918 	case 540566387:
19919 	case 540566887:
19920 	case 540570227:
19921 		return RECOIL_DecodeSc8(self, filename, content, contentLength);
19922 	case 543253363:
19923 		return RECOIL_DecodeSca(self, filename, content, contentLength);
19924 	case 543384435:
19925 	case 544436851:
19926 	case 543910521:
19927 		return RECOIL_DecodeScc(self, filename, content, contentLength);
19928 	case 544367475:
19929 		return RECOIL_DecodeScr(self, filename, content, contentLength);
19930 	case 879977331:
19931 	case 540308339:
19932 		return RECOIL_DecodeScs4(self, content, contentLength);
19933 	case 540042355:
19934 		return RECOIL_DecodeSd(self, content, contentLength, 0);
19935 	case 540107891:
19936 		return RECOIL_DecodeSd(self, content, contentLength, 1);
19937 	case 540173427:
19938 		return RECOIL_DecodeSd(self, content, contentLength, 2);
19939 	case 540239731:
19940 		return RECOIL_DecodeSg3(self, content, contentLength);
19941 	case 543516531:
19942 		return RECOIL_DecodeSge(self, content, contentLength);
19943 	case 544761715:
19944 		return RECOIL_DecodeSgx(self, content, contentLength);
19945 	case 540239987:
19946 	case 808464947:
19947 		return RECOIL_DecodeApfShr(self, content, contentLength) || RECOIL_Decode3201(self, content, contentLength) || RECOIL_DecodeSh3(self, content, contentLength) || RECOIL_DecodeAppleIIShr(self, content, contentLength);
19948 	case 543385715:
19949 		return RECOIL_DecodeShc(self, content, contentLength);
19950 	case 544237683:
19951 		return RECOIL_DecodeShp(self, content, contentLength);
19952 	case 544368755:
19953 		return RECOIL_DecodeApfShr(self, content, contentLength) || RECOIL_DecodeAppleIIShr(self, content, contentLength) || RECOIL_DecodeSh3(self, content, contentLength) || RECOIL_DecodeTrsShr(self, content, contentLength);
19954 	case 543582579:
19955 		return RECOIL_DecodeSif(self, content, contentLength);
19956 	case 544238451:
19957 		return RECOIL_DecodeSkp(self, content, contentLength);
19958 	case 543387763:
19959 		return RECOIL_DecodeStSpc(self, content, contentLength) || RECOIL_DecodeAtari8Spc(self, content, contentLength);
19960 	case 543453299:
19961 		return RECOIL_DecodeSpd(self, content, contentLength);
19962 	case 544370803:
19963 		return RECOIL_DecodeAppleSpr(self, content, contentLength) || RECOIL_DecodeAtari8Spr(self, content, contentLength);
19964 	case 544436339:
19965 		return RECOIL_DecodeSps(self, content, contentLength);
19966 	case 544567411:
19967 		return RECOIL_DecodeSpu(self, content, contentLength);
19968 	case 544764019:
19969 		return RECOIL_DecodeSpx(self, content, contentLength);
19970 	case 540373619:
19971 		return RECOIL_DecodeSr5(self, filename, content, contentLength);
19972 	case 540439155:
19973 		return RECOIL_DecodeSr6(self, filename, content, contentLength);
19974 	case 540504691:
19975 		return RECOIL_DecodeSr7(self, filename, content, contentLength);
19976 	case 543781491:
19977 		return RECOIL_DecodeSri(self, filename, content, contentLength);
19978 	case 544502387:
19979 		return RECOIL_DecodeSrt(self, content, contentLength);
19980 	case 543322995:
19981 		return RECOIL_DecodeSsb(self, content, contentLength);
19982 	case 543978611:
19983 		return RECOIL_DecodeStl(self, content, contentLength);
19984 	case 544240755:
19985 		return RECOIL_DecodeGl6(self, NULL, content, contentLength);
19986 	case 543651955:
19987 		return RECOIL_DecodeSxg(self, content, contentLength);
19988 	case 544438387:
19989 		return RECOIL_DecodeSxs(self, content, contentLength);
19990 	case 544236404:
19991 		return RECOIL_DecodeTcp(self, content, contentLength);
19992 	case 540108660:
19993 		return RECOIL_DecodeTg1(self, content, contentLength);
19994 	case 544041332:
19995 		return RECOIL_DecodeTim(self, content, contentLength);
19996 	case 544237940:
19997 		return RECOIL_DecodeTip(self, content, contentLength);
19998 	case 540110452:
19999 	case 540175988:
20000 	case 540241524:
20001 	case 540307060:
20002 	case 540372596:
20003 	case 540438132:
20004 	case 544829044:
20005 		return RECOIL_DecodeTny(self, content, contentLength);
20006 	case 543780980:
20007 		return RECOIL_DecodeFalconPnt(self, content, contentLength);
20008 	case 543519348:
20009 		return RECOIL_DecodeTre(self, content, contentLength);
20010 	case 544240244:
20011 		return RECOIL_DecodeTrp(self, content, contentLength);
20012 	case 544567924:
20013 		return RECOIL_DecodeTru(self, content, contentLength);
20014 	case 540047476:
20015 		return RECOIL_DecodeTx0(self, content, contentLength);
20016 	case 543520884:
20017 		return RECOIL_DecodeTxe(self, content, contentLength);
20018 	case 544438388:
20019 		return RECOIL_DecodeTxs(self, content, contentLength);
20020 	case 544039542:
20021 	case 538996066:
20022 		return RECOIL_DecodeVbm(self, content, contentLength);
20023 	case 543385974:
20024 		return RECOIL_DecodeVic(self, content, contentLength);
20025 	case 543783542:
20026 		return RECOIL_DecodeVzi(self, content, contentLength);
20027 	case 544106871:
20028 		return RECOIL_DecodeWin(self, filename, content, contentLength);
20029 	case 543452791:
20030 		return RECOIL_DecodeWnd(self, content, contentLength);
20031 	case 543254392:
20032 		return RECOIL_DecodeXga(self, content, contentLength);
20033 	case 544238712:
20034 		return RECOIL_DecodeXlp(self, content, contentLength);
20035 	case 544041338:
20036 		return RECOIL_DecodeZim(self, content, contentLength);
20037 	case 540110970:
20038 		return RECOIL_DecodeZp1(self, content, contentLength);
20039 	case 544241786:
20040 		return RECOIL_DecodeZxp(self, content, contentLength);
20041 	default:
20042 		return false;
20043 	}
20044 }
20045 
RECOIL_CalculatePalette(RECOIL * self)20046 static void RECOIL_CalculatePalette(RECOIL *self)
20047 {
20048 	memset(self->colorInUse, 0, sizeof(self->colorInUse));
20049 	self->colors = 0;
20050 	memset(self->palette, 0, sizeof(self->palette));
20051 	int pixelsCount = self->width * self->height;
20052 	for (int pixelsOffset = 0; pixelsOffset < pixelsCount; pixelsOffset++) {
20053 		int rgb = self->pixels[pixelsOffset];
20054 		int i = rgb >> 3;
20055 		int mask = 1 << (rgb & 7);
20056 		if ((self->colorInUse[i] & mask) == 0) {
20057 			self->colorInUse[i] |= mask;
20058 			if (self->colors < 256)
20059 				self->palette[self->colors] = rgb;
20060 			self->colors++;
20061 		}
20062 	}
20063 }
20064 
RECOIL_GetColors(RECOIL * self)20065 int RECOIL_GetColors(RECOIL *self)
20066 {
20067 	if (self->colors == -1)
20068 		RECOIL_CalculatePalette(self);
20069 	return self->colors;
20070 }
20071 
RECOIL_SortPalette(RECOIL * self,int start,int end)20072 static void RECOIL_SortPalette(RECOIL *self, int start, int end)
20073 {
20074 	while (start + 1 < end) {
20075 		int left = start + 1;
20076 		int right = end;
20077 		int pivot = self->palette[start];
20078 		int rgb;
20079 		while (left < right) {
20080 			rgb = self->palette[left];
20081 			if (rgb <= pivot)
20082 				left++;
20083 			else {
20084 				self->palette[left] = self->palette[--right];
20085 				self->palette[right] = rgb;
20086 			}
20087 		}
20088 		rgb = self->palette[--left];
20089 		self->palette[left] = self->palette[start];
20090 		self->palette[start] = rgb;
20091 		RECOIL_SortPalette(self, start, left);
20092 		start = right;
20093 	}
20094 }
20095 
RECOIL_FindInSortedPalette(const RECOIL * self,int rgb)20096 static int RECOIL_FindInSortedPalette(const RECOIL *self, int rgb)
20097 {
20098 	int left = 0;
20099 	int right = self->colors;
20100 	while (left < right) {
20101 		int index = (left + right) >> 1;
20102 		int paletteRgb = self->palette[index];
20103 		if (rgb == paletteRgb)
20104 			return index;
20105 		if (rgb < paletteRgb)
20106 			right = index;
20107 		else
20108 			left = index + 1;
20109 	}
20110 	return 0;
20111 }
20112 
RECOIL_ToPalette(RECOIL * self,uint8_t * indexes)20113 int const *RECOIL_ToPalette(RECOIL *self, uint8_t *indexes)
20114 {
20115 	if (self->colors == -1)
20116 		RECOIL_CalculatePalette(self);
20117 	if (self->colors > 256)
20118 		return NULL;
20119 	RECOIL_SortPalette(self, 0, self->colors);
20120 	int pixelsCount = self->width * self->height;
20121 	for (int i = 0; i < pixelsCount; i++)
20122 		indexes[i] = (uint8_t) RECOIL_FindInSortedPalette(self, self->pixels[i]);
20123 	return self->palette;
20124 }
20125