aboutsummaryrefslogtreecommitdiff
path: root/engines/made/redreader.cpp
diff options
context:
space:
mode:
authorBenjamin Haisch2008-04-23 08:08:37 +0000
committerBenjamin Haisch2008-04-23 08:08:37 +0000
commit6069dba988e9940b4d5285d6abc01b83967f8702 (patch)
tree3e70fa2ecffca571d1dde627a5f052653a44ae57 /engines/made/redreader.cpp
parent18ed600abea41fee47f92fa798f6fe49c5c37d25 (diff)
downloadscummvm-rg350-6069dba988e9940b4d5285d6abc01b83967f8702.tar.gz
scummvm-rg350-6069dba988e9940b4d5285d6abc01b83967f8702.tar.bz2
scummvm-rg350-6069dba988e9940b4d5285d6abc01b83967f8702.zip
Implemented direct loading of rtzcd.dat from the archive rtzcd.red, i.e. the game doesn't have to be installed first to get rtzcd.dat. Also added the respective detection entry.
svn-id: r31661
Diffstat (limited to 'engines/made/redreader.cpp')
-rw-r--r--engines/made/redreader.cpp422
1 files changed, 422 insertions, 0 deletions
diff --git a/engines/made/redreader.cpp b/engines/made/redreader.cpp
new file mode 100644
index 0000000000..96ed2a4c15
--- /dev/null
+++ b/engines/made/redreader.cpp
@@ -0,0 +1,422 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "made/redreader.h"
+
+namespace Made {
+
+
+Common::MemoryReadStream *RedReader::load(const char *redFilename, const char *filename) {
+
+ Common::File fd;
+ FileEntry fileEntry;
+
+ if (!fd.open(redFilename))
+ error("RedReader::RedReader() Could not open %s", redFilename);
+
+ if (!seekFile(fd, fileEntry, filename))
+ error("RedReader::RedReader() Could not find %s in archive %s", filename, redFilename);
+
+ byte *fileBuf = new byte[fileEntry.origSize];
+
+ LzhDecompressor lzhDec;
+ lzhDec.decompress(fd, fileBuf, fileEntry.compSize, fileEntry.origSize);
+
+ return new Common::MemoryReadStream(fileBuf, fileEntry.origSize, true);
+
+}
+
+Common::MemoryReadStream *RedReader::loadFromRed(const char *redFilename, const char *filename) {
+ RedReader redReader;
+ return redReader.load(redFilename, filename);
+}
+
+bool RedReader::seekFile(Common::File &fd, FileEntry &fileEntry, const char *filename) {
+ char arcFilename[13];
+ while (!fd.eof()) {
+ fd.skip(8); // skip unknown
+ fileEntry.compSize = fd.readUint32LE();
+ fileEntry.origSize = fd.readUint32LE();
+ fd.skip(10); // skip unknown
+ fd.read(arcFilename, 13);
+ fd.skip(2); // skip unknown
+ // Check if we have found the file
+ if (!scumm_stricmp(arcFilename, filename))
+ return true;
+ // Skip compressed data
+ fd.skip(fileEntry.compSize);
+ }
+ return false;
+}
+
+LzhDecompressor::LzhDecompressor() {
+}
+
+LzhDecompressor::~LzhDecompressor() {
+}
+
+int LzhDecompressor::decompress(Common::SeekableReadStream &source, byte *dest, uint32 sourceLen, uint32 destLen) {
+
+ int bufsize;
+ byte buffer[DICSIZ];
+
+ _source = &source;
+ _compSize = sourceLen;
+
+ count_len_depth = 0;
+
+ _blockPos = 0;
+
+ decode_start();
+ while (destLen > 0) {
+ bufsize = ((destLen > DICSIZ) ? DICSIZ : destLen);
+ decode(bufsize, buffer);
+ memcpy(dest, buffer, bufsize);
+ dest += bufsize;
+ destLen -= bufsize;
+ }
+
+ return 0;
+}
+
+byte LzhDecompressor::readByte() {
+ if (_blockPos == 0xFFE) {
+ _blockPos = 0;
+ _source->skip(2); // skip unknown value
+ }
+ byte temp = _source->readByte();
+ _blockPos++;
+ return temp;
+}
+
+void LzhDecompressor::fillbuf(int count) {
+ _bitbuf <<= count;
+ while (count > _bitcount) {
+ _bitbuf |= _subbitbuf << (count -= _bitcount);
+ if (_compSize != 0) {
+ _compSize--;
+ _subbitbuf = readByte();
+ } else _subbitbuf = 0;
+ _bitcount = 8;
+ }
+ _bitbuf |= _subbitbuf >> (_bitcount -= count);
+}
+
+uint LzhDecompressor::getbits(int count) {
+ uint x;
+ x = _bitbuf >> (BITBUFSIZ - count);
+ fillbuf(count);
+ return x;
+}
+
+void LzhDecompressor::init_getbits() {
+ _bitbuf = 0;
+ _subbitbuf = 0;
+ _bitcount = 0;
+ fillbuf(BITBUFSIZ);
+}
+
+void LzhDecompressor::decode_start() {
+ huf_decode_start();
+ decode_j = 0;
+}
+
+void LzhDecompressor::decode(uint count, byte buffer[]) {
+ uint r, c;
+ r = 0;
+ while (--decode_j >= 0) {
+ buffer[r] = buffer[decode_i];
+ decode_i = (decode_i + 1) & (DICSIZ - 1);
+ if (++r == count) return;
+ }
+ for ( ; ; ) {
+ c = decode_c();
+ if (c <= 255) {
+ buffer[r] = c;
+ if (++r == count) return;
+ } else {
+ decode_j = c - (255 + 1 - THRESHOLD);
+ decode_i = (r - decode_p() - 1) & (DICSIZ - 1);
+ while (--decode_j >= 0) {
+ buffer[r] = buffer[decode_i];
+ decode_i = (decode_i + 1) & (DICSIZ - 1);
+ if (++r == count) return;
+ }
+ }
+ }
+}
+
+void LzhDecompressor::read_pt_len(int nn, int nbit, int i_special) {
+ int i, c, v;
+ unsigned int mask;
+ v = getbits(nbit);
+ if (v == 0) {
+ c = getbits(nbit);
+ for (i = 0; i < nn; i++) _pt_len[i] = 0;
+ for (i = 0; i < 256; i++) _pt_table[i] = c;
+ } else {
+ i = 0;
+ while (i < v) {
+ c = _bitbuf >> (BITBUFSIZ - 3);
+ if (c == 7) {
+ mask = 1U << (BITBUFSIZ - 1 - 3);
+ while (mask & _bitbuf) { mask >>= 1; c++; }
+ }
+ fillbuf((c < 7) ? 3 : c - 3);
+ _pt_len[i++] = c;
+ if (i == i_special) {
+ c = getbits(2);
+ while (--c >= 0) _pt_len[i++] = 0;
+ }
+ }
+ while (i < nn) _pt_len[i++] = 0;
+ make_table(nn, _pt_len, 8, _pt_table);
+ }
+}
+
+void LzhDecompressor::read_c_len() {
+ uint i, v;
+ int c;
+ unsigned int mask;
+ v = getbits(CBIT);
+ if (v == 0) {
+ c = getbits(CBIT);
+ for (i = 0; i < NC; i++) _c_len[i] = 0;
+ for (i = 0; i < 4096; i++) _c_table[i] = c;
+ } else {
+ i = 0;
+ while (i < v) {
+ c = _pt_table[_bitbuf >> (BITBUFSIZ - 8)];
+ if (c >= NT) {
+ mask = 1U << (BITBUFSIZ - 1 - 8);
+ do {
+ if (_bitbuf & mask) c = _right[c];
+ else c = _left [c];
+ mask >>= 1;
+ } while (c >= NT);
+ }
+ fillbuf(_pt_len[c]);
+ if (c <= 2) {
+ if (c == 0) c = 1;
+ else if (c == 1) c = getbits(4) + 3;
+ else c = getbits(CBIT) + 20;
+ while (--c >= 0) _c_len[i++] = 0;
+ } else _c_len[i++] = c - 2;
+ }
+ while (i < NC) _c_len[i++] = 0;
+ make_table(NC, _c_len, 12, _c_table);
+ }
+}
+
+unsigned int LzhDecompressor::decode_c(void) {
+ uint j, mask;
+ if (_blocksize == 0) {
+ _blocksize = getbits(16);
+ read_pt_len(NT, TBIT, 3);
+ read_c_len();
+ read_pt_len(NP, PBIT, -1);
+ }
+ _blocksize--;
+ j = _c_table[_bitbuf >> (BITBUFSIZ - 12)];
+ if (j >= NC) {
+ mask = 1U << (BITBUFSIZ - 1 - 12);
+ do {
+ if (_bitbuf & mask) j = _right[j];
+ else j = _left [j];
+ mask >>= 1;
+ } while (j >= NC);
+ }
+ fillbuf(_c_len[j]);
+ return j;
+}
+
+unsigned int LzhDecompressor::decode_p() {
+ unsigned int j, mask;
+ j = _pt_table[_bitbuf >> (BITBUFSIZ - 8)];
+ if (j >= NP) {
+ mask = 1U << (BITBUFSIZ - 1 - 8);
+ do {
+ if (_bitbuf & mask) j = _right[j];
+ else j = _left [j];
+ mask >>= 1;
+ } while (j >= NP);
+ }
+ fillbuf(_pt_len[j]);
+ if (j != 0) j = (1U << (j - 1)) + getbits(j - 1);
+ return j;
+}
+
+void LzhDecompressor::huf_decode_start() {
+ init_getbits();
+ _blocksize = 0;
+}
+
+void LzhDecompressor::make_table(uint nchar, byte bitlen[], uint tablebits, uint16 table[]) {
+ uint16 count[17], weight[17], start[18], *p;
+ uint i, k, len, ch, jutbits, avail, nextcode, mask;
+ for (i = 1; i <= 16; i++) count[i] = 0;
+ for (i = 0; i < nchar; i++) count[bitlen[i]]++;
+ start[1] = 0;
+ for (i = 1; i <= 16; i++)
+ start[i + 1] = start[i] + (count[i] << (16 - i));
+ if (start[17] != (uint16)(1U << 16))
+ error("LzhDecompressor::make_table() Bad table\n");
+ jutbits = 16 - tablebits;
+ for (i = 1; i <= tablebits; i++) {
+ start[i] >>= jutbits;
+ weight[i] = 1U << (tablebits - i);
+ }
+ while (i <= 16) weight[i++] = 1U << (16 - i);
+ i = start[tablebits + 1] >> jutbits;
+ if (i != (uint16)(1U << 16)) {
+ k = 1U << tablebits;
+ while (i != k) table[i++] = 0;
+ }
+ avail = nchar;
+ mask = 1U << (15 - tablebits);
+ for (ch = 0; ch < nchar; ch++) {
+ if ((len = bitlen[ch]) == 0) continue;
+ nextcode = start[len] + weight[len];
+ if (len <= tablebits) {
+ for (i = start[len]; i < nextcode; i++) table[i] = ch;
+ } else {
+ k = start[len];
+ p = &table[k >> jutbits];
+ i = len - tablebits;
+ while (i != 0) {
+ if (*p == 0) {
+ _right[avail] = _left[avail] = 0;
+ *p = avail++;
+ }
+ if (k & mask) p = &_right[*p];
+ else p = &_left[*p];
+ k <<= 1; i--;
+ }
+ *p = ch;
+ }
+ start[len] = nextcode;
+ }
+}
+
+/* call with i = root */
+void LzhDecompressor::count_len(int i) {
+ if (i < tree_n)
+ len_cnt[(count_len_depth < 16) ? count_len_depth : 16]++;
+ else {
+ count_len_depth++;
+ count_len(_left [i]);
+ count_len(_right[i]);
+ count_len_depth--;
+ }
+}
+
+void LzhDecompressor::make_len(int root) {
+ int i, k;
+ uint cum;
+ for (i = 0; i <= 16; i++) len_cnt[i] = 0;
+ count_len(root);
+ cum = 0;
+ for (i = 16; i > 0; i--)
+ cum += len_cnt[i] << (16 - i);
+ while (cum != (1U << 16)) {
+ len_cnt[16]--;
+ for (i = 15; i > 0; i--) {
+ if (len_cnt[i] != 0) {
+ len_cnt[i]--;
+ len_cnt[i+1] += 2;
+ break;
+ }
+ }
+ cum--;
+ }
+ for (i = 16; i > 0; i--) {
+ k = len_cnt[i];
+ while (--k >= 0) len_table[*sortptr++] = i;
+ }
+}
+
+void LzhDecompressor::downheap(int i) {
+ int j, k;
+ k = heap[i];
+ while ((j = 2 * i) <= heapsize) {
+ if (j < heapsize && freq[heap[j]] > freq[heap[j + 1]])
+ j++;
+ if (freq[k] <= freq[heap[j]]) break;
+ heap[i] = heap[j]; i = j;
+ }
+ heap[i] = k;
+}
+
+void LzhDecompressor::make_code(int n, byte len[], uint16 code[]) {
+ int i;
+ uint16 start[18];
+ start[1] = 0;
+ for (i = 1; i <= 16; i++)
+ start[i + 1] = (start[i] + len_cnt[i]) << 1;
+ for (i = 0; i < n; i++) code[i] = start[len[i]]++;
+}
+
+/* make tree, calculate len[], return root */
+int LzhDecompressor::make_tree(int nparm, uint16 freqparm[], byte lenparm[], uint16 codeparm[]) {
+ int i, j, k, avail;
+
+ tree_n = nparm;
+ freq = freqparm;
+ len_table = lenparm;
+ avail = tree_n;
+ heapsize = 0;
+ heap[1] = 0;
+ for (i = 0; i < tree_n; i++) {
+ len_table[i] = 0;
+ if (freq[i]) heap[++heapsize] = i;
+ }
+ if (heapsize < 2) {
+ codeparm[heap[1]] = 0;
+ return heap[1];
+ }
+ for (i = heapsize / 2; i >= 1; i--)
+ downheap(i); /* make priority queue */
+ sortptr = codeparm;
+ do { /* while queue has at least two entries */
+ i = heap[1]; /* take out least-freq entry */
+ if (i < tree_n) *sortptr++ = i;
+ heap[1] = heap[heapsize--];
+ downheap(1);
+ j = heap[1]; /* next least-freq entry */
+ if (j < tree_n) *sortptr++ = j;
+ k = avail++; /* generate new node */
+ freq[k] = freq[i] + freq[j];
+ heap[1] = k;
+ downheap(1); /* put into queue */
+ _left[k] = i;
+ _right[k] = j;
+ } while (heapsize > 1);
+ sortptr = codeparm;
+ make_len(k);
+ make_code(nparm, lenparm, codeparm);
+ return k; /* return root */
+}
+
+}