diff options
author | Jamieson Christian | 2003-09-29 04:15:24 +0000 |
---|---|---|
committer | Jamieson Christian | 2003-09-29 04:15:24 +0000 |
commit | 6a4c977a487228dec4e33fef0e699e51032330fd (patch) | |
tree | 7533e46c8771be76d4ee161febfd60e7587d9fbb /simon | |
parent | a48c8ff4c1d68f67459555f3f56a0398e66f144f (diff) | |
download | scummvm-rg350-6a4c977a487228dec4e33fef0e699e51032330fd.tar.gz scummvm-rg350-6a4c977a487228dec4e33fef0e699e51032330fd.tar.bz2 scummvm-rg350-6a4c977a487228dec4e33fef0e699e51032330fd.zip |
Added decruncher for Simon 1 disk version files.
Also thanks to Stuart Caie for the C conversion
of the decruncher algorithm.
svn-id: r10476
Diffstat (limited to 'simon')
-rw-r--r-- | simon/simon.cpp | 140 |
1 files changed, 126 insertions, 14 deletions
diff --git a/simon/simon.cpp b/simon/simon.cpp index 3c20709248..5949e586b0 100644 --- a/simon/simon.cpp +++ b/simon/simon.cpp @@ -4197,6 +4197,109 @@ void SimonEngine::talk_with_text(uint num_1, uint num_2, const char *string_ptr, } } +// Thanks to Stuart Caie for providing the original +// C conversion upon which this decruncher is based. + +#define SD_GETBIT(var) do { \ +if(!bits--){s-=4;if(s<src)return false;bb=READ_BE_UINT32(s);bits=31;}(var)=bb&1;bb>>=1; \ +}while(0) + +#define SD_GETBITS(var, nbits) do { \ +bc=(nbits);(var)=0;while(bc--){(var)<<=1;SD_GETBIT(bit);(var)|=bit;} \ +}while(0) + +#define SD_TYPE_LITERAL (0) +#define SD_TYPE_MATCH (1) + +static bool decrunch_file_amiga (byte *src, byte *dst, uint32 size) { + byte *s = src + size - 4; + uint32 destlen = READ_BE_UINT32 (s); + uint32 bb, x, y; + byte *d = dst + destlen; + byte bc, bit, bits, type; + + // Initialize bit buffer. + s -= 4; + bb = x = READ_BE_UINT32 (s); + bits = 0; + do { + x >>= 1; + bits++; + } while (x); + bits--; + + while (d > dst) { + SD_GETBIT(x); + if (x) { + SD_GETBITS(x,2); + switch (x) { + case 0: + type = SD_TYPE_MATCH; + x = 9; + y = 2; + break; + + case 1: + type = SD_TYPE_MATCH; + x = 10; + y = 3; + break; + + case 2: + type = SD_TYPE_MATCH; + x = 12; + SD_GETBITS(y,8); + break; + + default: + type = SD_TYPE_LITERAL; + x = 8; + y = 8; + } + } else { + SD_GETBIT(x); + if (x) { + type = SD_TYPE_MATCH; + x = 8; + y = 1; + } else { + type = SD_TYPE_LITERAL; + x = 3; + y = 0; + } + } + + if (type == SD_TYPE_LITERAL) { + SD_GETBITS(x,x); + y += x; + if ((int)(y + 1) > (d - dst)) + return false; // Overflow? + do { + SD_GETBITS(x,8); + *--d = x; + } while (y-- > 0); + } else { + if ((int)(y + 1) > (d - dst)) + return false; // Overflow? + SD_GETBITS(x,x); + if ((d + x) > (dst + destlen)) + return false; // Offset overflow? + do { + d--; + *d = d[x]; + } while (y-- > 0); + } + } + + // Successful decrunch. + return true; +} + +#undef SD_GETBIT +#undef SD_GETBITS +#undef SD_TYPE_LITERAL +#undef SD_TYPE_MATCH + void SimonEngine::read_vga_from_datfile_1(uint vga_id) { if (_game & GF_AMIGA || _game == GAME_SIMON1DEMO || _game == GAME_SIMON1DOS) { File in; @@ -4210,8 +4313,7 @@ void SimonEngine::read_vga_from_datfile_1(uint vga_id) { if (_game == GAME_SIMON1CD32) { sprintf(buf, "0%d.out", vga_id); } else if (_game == GAME_SIMON1AMIGA) { - // TODO Add support for decruncher - sprintf(buf, "0%d.pkd.out", vga_id); + sprintf(buf, "0%d.pkd", vga_id); } else { sprintf(buf, "0%d.VGA", vga_id); } @@ -4219,12 +4321,18 @@ void SimonEngine::read_vga_from_datfile_1(uint vga_id) { in.open(buf, _gameDataPath); if (in.isOpen() == false) error("read_vga_from_datfile_1: can't open %s", buf); - size = in.size(); - if (in.read(_vga_buffer_pointers[11].vgaFile2, size) != size) - error("read_vga_from_datfile_1: read failed"); - + if (_game == GAME_SIMON1AMIGA) { + byte *buffer = new byte[size]; + if (in.read(buffer, size) != size) + error("read_vga_from_datfile_1: read failed"); + decrunch_file_amiga (buffer, _vga_buffer_pointers[11].vgaFile2, size); + delete [] buffer; + } else { + if (in.read(_vga_buffer_pointers[11].vgaFile2, size) != size) + error("read_vga_from_datfile_1: read failed"); + } in.close(); } else { uint32 offs_a = _game_offsets_ptr[vga_id]; @@ -4244,8 +4352,7 @@ byte *SimonEngine::read_vga_from_datfile_2(uint id) { if (_game == GAME_SIMON1CD32) { sprintf(buf, "%.3d%d.out", id >> 1, (id & 1) + 1); } else if (_game == GAME_SIMON1AMIGA) { - // TODO Add support for decruncher - sprintf(buf, "%.3d%d.pkd.out", id >> 1, (id & 1) + 1); + sprintf(buf, "%.3d%d.pkd", id >> 1, (id & 1) + 1); } else { sprintf(buf, "%.3d%d.VGA", id >> 1, (id & 1) + 1); } @@ -4253,14 +4360,19 @@ byte *SimonEngine::read_vga_from_datfile_2(uint id) { in.open(buf, _gameDataPath); if (in.isOpen() == false) error("read_vga_from_datfile_2: can't open %s", buf); - size = in.size(); - dst = setup_vga_destination(size); - - if (in.read(dst, size) != size) - error("read_vga_from_datfile_2: read failed"); - + if (_game == GAME_SIMON1AMIGA) { + byte *buffer = new byte[size]; + if (in.read(buffer, size) != size) + error("read_vga_from_datfile_2: read failed"); + dst = setup_vga_destination (READ_BE_UINT32 (buffer + size - 4)); + decrunch_file_amiga (buffer, dst, size); + } else { + dst = setup_vga_destination(size); + if (in.read(dst, size) != size) + error("read_vga_from_datfile_2: read failed"); + } in.close(); return dst; |