aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugene Sandulenko2008-06-01 11:43:20 +0000
committerEugene Sandulenko2008-06-01 11:43:20 +0000
commitcc74ec5c39a233c05ad9e8b3eba96649ceb8490b (patch)
tree56771c0bac722f669e5ae535a5672edff698babc
parenta81e10da49a1418326f324227d6daa06aed346cc (diff)
downloadscummvm-rg350-cc74ec5c39a233c05ad9e8b3eba96649ceb8490b.tar.gz
scummvm-rg350-cc74ec5c39a233c05ad9e8b3eba96649ceb8490b.tar.bz2
scummvm-rg350-cc74ec5c39a233c05ad9e8b3eba96649ceb8490b.zip
Unarj code based on unarj 2.62. Used by Drascula engine
svn-id: r32460
-rw-r--r--common/module.mk1
-rw-r--r--common/unarj.cpp666
-rw-r--r--common/unarj.h179
3 files changed, 846 insertions, 0 deletions
diff --git a/common/module.mk b/common/module.mk
index a7c0f4eb90..c3f2a38c3f 100644
--- a/common/module.mk
+++ b/common/module.mk
@@ -14,6 +14,7 @@ MODULE_OBJS := \
stream.o \
util.o \
system.o \
+ unarj.o \
unzip.o \
zlib.o
diff --git a/common/unarj.cpp b/common/unarj.cpp
new file mode 100644
index 0000000000..c8e48dce2c
--- /dev/null
+++ b/common/unarj.cpp
@@ -0,0 +1,666 @@
+/* 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$
+ *
+ */
+
+// Heavily based on Unarj 2.65
+
+/* UNARJ.C, UNARJ, R JUNG, 06/05/02
+ * Main Extractor routine
+ * Copyright (c) 1991-2002 by ARJ Software, Inc. All rights reserved.
+ *
+ * This code may be freely used in programs that are NOT ARJ archivers
+ * (both compress and extract ARJ archives).
+ *
+ * If you wish to distribute a modified version of this program, you
+ * MUST indicate that it is a modified version both in the program and
+ * source code.
+ *
+ * We are holding the copyright on the source code, so please do not
+ * delete our name from the program files or from the documentation.
+ *
+ * We wish to give credit to Haruhiko Okumura for providing the
+ * basic ideas for ARJ and UNARJ in his program AR. Please note
+ * that UNARJ is significantly different from AR from an archive
+ * structural point of view.
+ *
+ */
+
+#include "common/scummsys.h"
+#include "common/util.h"
+#include "common/unarj.h"
+
+namespace Common {
+
+static uint32 CRCtable[256];
+
+static void InitCRC(void) {
+ const uint32 poly = 0xEDB88320;
+ int i, j;
+ uint32 n;
+
+ for (i = 0; i < 256; i++) {
+ n = i;
+ for (j = 0; j < 8; j++)
+ n = (n & 1) ? ((n >> 1) ^ poly) : (n >> 1);
+ CRCtable[i] = n;
+ }
+}
+
+static uint32 GetCRC(byte *data, int len) {
+ uint32 CRC = 0xFFFFFFFF;
+ int i;
+ for (i = 0; i < len; i++)
+ CRC = (CRC >> 8) ^ CRCtable[(CRC ^ data[i]) & 0xFF];
+ return CRC ^ 0xFFFFFFFF;
+}
+
+ArjFile::ArjFile() {
+ InitCRC();
+}
+
+ArjFile::~ArjFile() {
+ close();
+
+ for (uint i = 0; i < _headers.size(); i++)
+ delete _headers[i];
+
+ _headers.clear();
+}
+
+void ArjFile::registerArchive(const String &filename) {
+ int32 first_hdr_pos;
+ ArjHeader *header;
+
+ if (!_currArchive.open(filename))
+ return;
+
+ first_hdr_pos = findHeader();
+
+ if (first_hdr_pos < 0) {
+ warning("ArjFile::registerArchive(): Could not find a valid header");
+ return;
+ }
+
+ _currArchive.seek(first_hdr_pos, SEEK_SET);
+ if (readHeader() == NULL)
+ return;
+
+ while ((header = readHeader()) != NULL) {
+ _headers.push_back(header);
+
+ _currArchive.seek(header->compSize, SEEK_CUR);
+
+ _fileMap[header->filename] = _headers.size() - 1;
+ _archMap[header->filename] = filename;
+ }
+
+ _currArchive.close();
+
+ debug(0, "ArjFile::registerArchive(%s): Located %d files", filename.c_str(), _headers.size());
+}
+
+int32 ArjFile::findHeader(void) {
+ long arcpos, lastpos;
+ int c;
+ byte header[HEADERSIZE_MAX];
+ uint32 crc;
+ uint16 headersize;
+
+ arcpos = _currArchive.pos();
+ _currArchive.seek(0L, SEEK_END);
+ lastpos = _currArchive.pos() - 2;
+ if (lastpos > MAXSFX)
+ lastpos = MAXSFX;
+
+ for ( ; arcpos < lastpos; arcpos++) {
+ _currArchive.seek(arcpos, SEEK_SET);
+ c = _currArchive.readByte();
+ while (arcpos < lastpos) {
+ if (c != HEADER_ID_LO) // low order first
+ c = _currArchive.readByte();
+ else if ((c = _currArchive.readByte()) == HEADER_ID_HI)
+ break;
+ arcpos++;
+ }
+ if (arcpos >= lastpos)
+ break;
+ if ((headersize = _currArchive.readUint16LE()) <= HEADERSIZE_MAX) {
+ _currArchive.read(header, headersize);
+ crc = GetCRC(header, headersize);
+ if (crc == _currArchive.readUint32LE()) {
+ _currArchive.seek(arcpos, SEEK_SET);
+ return arcpos;
+ }
+ }
+ }
+ return -1; // could not find a valid header
+}
+
+ArjHeader *ArjFile::readHeader() {
+ ArjHeader header;
+ ArjHeader *head;
+ byte headData[HEADERSIZE_MAX];
+
+ header.id = _currArchive.readUint16LE();
+ if (header.id != HEADER_ID) {
+ warning("ArjFile::readHeader(): Bad header ID (%x)", header.id);
+
+ return NULL;
+ }
+
+ header.headerSize = _currArchive.readUint16LE();
+ if (header.headerSize == 0)
+ return NULL; // end of archive
+ if (header.headerSize > HEADERSIZE_MAX) {
+ warning("ArjFile::readHeader(): Bad header");
+
+ return NULL;
+ }
+
+ int rSize = _currArchive.read(headData, header.headerSize);
+
+ MemoryReadStream readS(headData, rSize);
+
+ header.headerCrc = _currArchive.readUint32LE();
+ if (GetCRC(headData, header.headerSize) != header.headerCrc) {
+ warning("ArjFile::readHeader(): Bad header CRC");
+ return NULL;
+ }
+
+ header.firstHdrSize = readS.readByte();
+ header.nbr = readS.readByte();
+ header.xNbr = readS.readByte();
+ header.hostOs = readS.readByte();
+ header.flags = readS.readByte();
+ header.method = readS.readByte();
+ header.fileType = readS.readByte();
+ (void)readS.readByte();
+ header.timeStamp = readS.readUint32LE();
+ header.compSize = readS.readSint32LE();
+ header.origSize = readS.readSint32LE();
+ header.fileCRC = readS.readUint32LE();
+ header.entryPos = readS.readUint16LE();
+ header.fileMode = readS.readUint16LE();
+ header.hostData = readS.readUint16LE();
+
+ if (header.origSize < 0 || header.compSize < 0) {
+ warning("ArjFile::readHeader(): Wrong file size");
+ return NULL;
+ }
+
+ strncpy(header.filename, (const char *)&headData[header.firstHdrSize], FNAME_MAX);
+
+ strncpy(header.comment, (const char *)&headData[header.firstHdrSize + strlen(header.filename) + 1], COMMENT_MAX);
+
+ /* if extheadersize == 0 then no CRC */
+ /* otherwise read extheader data and read 4 bytes for CRC */
+
+ while ((header.extHeaderSize = _currArchive.readUint16LE()) != 0)
+ _currArchive.seek((long)(header.extHeaderSize + 4), SEEK_CUR);
+
+ header.pos = _currArchive.pos();
+
+ head = new ArjHeader(header);
+
+ return head;
+}
+
+
+bool ArjFile::open(const Common::String &filename, AccessMode mode) {
+ _isOpen = false;
+
+ if (!_fileMap.contains(filename))
+ return false;
+
+ _isOpen = true;
+
+ ArjHeader *hdr = _headers[_fileMap[filename]];
+
+ _compsize = hdr->compSize;
+ _origsize = hdr->origSize;
+
+ _uncompressedData = (byte *)malloc(_origsize);
+ _outstream = new MemoryWriteStream(_uncompressedData, _origsize);
+
+ _currArchive.open(_archMap[filename]);
+ _currArchive.seek(hdr->pos, SEEK_SET);
+
+ if (hdr->method == 0) // store
+ _currArchive.read(_uncompressedData, _origsize);
+ else if (hdr->method == 1 || hdr->method == 2 || hdr->method == 3)
+ decode();
+ else if (hdr->method == 4)
+ decode_f();
+
+ _currArchive.close();
+ delete _outstream;
+ _outstream = NULL;
+
+ _uncompressed = new MemoryReadStream(_uncompressedData, _origsize);
+
+ return true;
+}
+
+void ArjFile::close() {
+ _isOpen = false;
+
+ delete _uncompressed;
+ _uncompressed = NULL;
+
+ free(_uncompressedData);
+ _uncompressedData = NULL;
+}
+
+uint32 ArjFile::read(void *dataPtr, uint32 dataSize) {
+ return _uncompressed->read(dataPtr, dataSize);
+}
+
+bool ArjFile::eos() {
+ return _uncompressed->eos();
+}
+
+uint32 ArjFile::pos() {
+ return _uncompressed->pos();
+}
+
+uint32 ArjFile::size() {
+ return _uncompressed->size();
+}
+
+void ArjFile::seek(int32 offset, int whence) {
+ _uncompressed->seek(offset, whence);
+}
+
+void ArjFile::init_getbits() {
+ _bitbuf = 0;
+ _subbitbuf = 0;
+ _bitcount = 0;
+ fillbuf(2 * CHAR_BIT);
+}
+
+void ArjFile::fillbuf(int n) { // Shift bitbuf n bits left, read n bits
+ _bitbuf = (_bitbuf << n) & 0xFFFF; /* lose the first n bits */
+ while (n > _bitcount) {
+ _bitbuf |= _subbitbuf << (n -= _bitcount);
+ if (_compsize != 0) {
+ _compsize--;
+ _subbitbuf = _currArchive.readByte();
+ } else
+ _subbitbuf = 0;
+ _bitcount = CHAR_BIT;
+ }
+ _bitbuf |= _subbitbuf >> (_bitcount -= n);
+}
+
+uint16 ArjFile::getbits(int n) {
+ uint16 x;
+
+ x = _bitbuf >> (2 * CHAR_BIT - n);
+ fillbuf(n);
+ return x;
+}
+
+
+
+/* Huffman decode routines */
+
+void ArjFile::make_table(int nchar, byte *bitlen, int tablebits, uint16 *table, int tablesize) {
+ 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; (int)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) (1 << 16))
+ error("ArjFile::make_table(): bad file data");
+
+ jutbits = 16 - tablebits;
+ for (i = 1; (int)i <= tablebits; i++) {
+ start[i] >>= jutbits;
+ weight[i] = 1 << (tablebits - i);
+ }
+ while (i <= 16) {
+ weight[i] = 1 << (16 - i);
+ i++;
+ }
+
+ i = start[tablebits + 1] >> jutbits;
+ if (i != (uint16) (1 << 16)) {
+ k = 1 << tablebits;
+ while (i != k)
+ table[i++] = 0;
+ }
+
+ avail = nchar;
+ mask = 1 << (15 - tablebits);
+ for (ch = 0; (int)ch < nchar; ch++) {
+ if ((len = bitlen[ch]) == 0)
+ continue;
+ k = start[len];
+ nextcode = k + weight[len];
+ if ((int)len <= tablebits) {
+ if (nextcode > (uint)tablesize)
+ error("ArjFile::make_table(): bad file data");
+ for (i = start[len]; i < nextcode; i++)
+ table[i] = ch;
+ } else {
+ 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;
+ }
+}
+
+void ArjFile::read_pt_len(int nn, int nbit, int i_special) {
+ int i, n;
+ int16 c;
+ uint16 mask;
+
+ n = getbits(nbit);
+ if (n == 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 < n) {
+ c = _bitbuf >> (13);
+ if (c == 7) {
+ mask = 1 << (12);
+ while (mask & _bitbuf) {
+ mask >>= 1;
+ c++;
+ }
+ }
+ fillbuf((c < 7) ? 3 : (int)(c - 3));
+ _pt_len[i++] = (byte)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, PTABLESIZE); // replaced sizeof
+ }
+}
+
+void ArjFile::read_c_len() {
+ int16 i, c, n;
+ uint16 mask;
+
+ n = getbits(CBIT);
+ if (n == 0) {
+ c = getbits(CBIT);
+ for (i = 0; i < NC; i++)
+ _c_len[i] = 0;
+ for (i = 0; i < CTABLESIZE; i++)
+ _c_table[i] = c;
+ } else {
+ i = 0;
+ while (i < n) {
+ c = _pt_table[_bitbuf >> (8)];
+ if (c >= NT) {
+ mask = 1 << (7);
+ do {
+ if (_bitbuf & mask)
+ c = _right[c];
+ else
+ c = _left[c];
+ mask >>= 1;
+ } while (c >= NT);
+ }
+ fillbuf((int)(_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++] = (byte)(c - 2);
+ }
+ while (i < NC)
+ _c_len[i++] = 0;
+ make_table(NC, _c_len, 12, _c_table, CTABLESIZE); // replaced sizeof
+ }
+}
+
+uint16 ArjFile::decode_c() {
+ uint16 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 >> 4];
+ if (j >= NC) {
+ mask = 1 << (3);
+ do {
+ if (_bitbuf & mask)
+ j = _right[j];
+ else
+ j = _left[j];
+ mask >>= 1;
+ } while (j >= NC);
+ }
+ fillbuf((int)(_c_len[j]));
+ return j;
+}
+
+uint16 ArjFile::decode_p() {
+ uint16 j, mask;
+
+ j = _pt_table[_bitbuf >> (8)];
+ if (j >= NP) {
+ mask = 1 << (7);
+ do {
+ if (_bitbuf & mask)
+ j = _right[j];
+ else
+ j = _left[j];
+ mask >>= 1;
+ } while (j >= NP);
+ }
+ fillbuf((int)(_pt_len[j]));
+ if (j != 0) {
+ j--;
+ j = (1 << j) + getbits((int)j);
+ }
+ return j;
+}
+
+void ArjFile::decode_start() {
+ _blocksize = 0;
+ init_getbits();
+}
+
+void ArjFile::decode() {
+ int16 i;
+ int16 j;
+ int16 c;
+ int16 r;
+ int32 count;
+
+ decode_start();
+ count = 0;
+ r = 0;
+
+ while (count < _origsize) {
+ if ((c = decode_c()) <= UCHAR_MAX) {
+ _text[r] = (byte) c;
+ count++;
+ if (++r >= DDICSIZ) {
+ r = 0;
+ _outstream->write(_text, DDICSIZ);
+ }
+ } else {
+ j = c - (UCHAR_MAX + 1 - THRESHOLD);
+ count += j;
+ i = decode_p();
+ if ((i = r - i - 1) < 0)
+ i += DDICSIZ;
+ if (r > i && r < DDICSIZ - MAXMATCH - 1) {
+ while (--j >= 0)
+ _text[r++] = _text[i++];
+ } else {
+ while (--j >= 0) {
+ _text[r] = _text[i];
+ if (++r >= DDICSIZ) {
+ r = 0;
+ _outstream->write(_text, DDICSIZ);
+ }
+ if (++i >= DDICSIZ)
+ i = 0;
+ }
+ }
+ }
+ }
+ if (r != 0)
+ _outstream->write(_text, r);
+}
+
+/* Macros */
+
+#define BFIL {_getbuf|=_bitbuf>>_getlen;fillbuf(CODE_BIT-_getlen);_getlen=CODE_BIT;}
+#define GETBIT(c) {if(_getlen<=0)BFIL c=(_getbuf&0x8000)!=0;_getbuf<<=1;_getlen--;}
+#define BPUL(l) {_getbuf<<=l;_getlen-=l;}
+#define GETBITS(c,l) {if(_getlen<l)BFIL c=(uint16)_getbuf>>(CODE_BIT-l);BPUL(l)}
+
+int16 ArjFile::decode_ptr() {
+ int16 c;
+ int16 width;
+ int16 plus;
+ int16 pwr;
+
+ plus = 0;
+ pwr = 1 << (STRTP);
+ for (width = (STRTP); width < (STOPP); width++) {
+ GETBIT(c);
+ if (c == 0)
+ break;
+ plus += pwr;
+ pwr <<= 1;
+ }
+ if (width != 0)
+ GETBITS(c, width);
+ c += plus;
+ return c;
+}
+
+int16 ArjFile::decode_len() {
+ int16 c;
+ int16 width;
+ int16 plus;
+ int16 pwr;
+
+ plus = 0;
+ pwr = 1 << (STRTL);
+ for (width = (STRTL); width < (STOPL); width++) {
+ GETBIT(c);
+ if (c == 0)
+ break;
+ plus += pwr;
+ pwr <<= 1;
+ }
+ if (width != 0)
+ GETBITS(c, width);
+ c += plus;
+ return c;
+}
+
+void ArjFile::decode_f() {
+ int16 i;
+ int16 j;
+ int16 c;
+ int16 r;
+ int16 pos1;
+ int32 count;
+
+ init_getbits();
+ _getlen = _getbuf = 0;
+ count = 0;
+ r = 0;
+
+ while (count < _origsize) {
+ c = decode_len();
+ if (c == 0) {
+ GETBITS(c, CHAR_BIT);
+ _text[r] = (byte)c;
+ count++;
+ if (++r >= DDICSIZ) {
+ r = 0;
+ _outstream->write(_text, DDICSIZ);
+ }
+ } else {
+ j = c - 1 + THRESHOLD;
+ count += j;
+ pos1 = decode_ptr();
+ if ((i = r - pos1 - 1) < 0)
+ i += DDICSIZ;
+ while (j-- > 0) {
+ _text[r] = _text[i];
+ if (++r >= DDICSIZ) {
+ r = 0;
+ _outstream->write(_text, DDICSIZ);
+ }
+ if (++i >= DDICSIZ)
+ i = 0;
+ }
+ }
+ }
+ if (r != 0)
+ _outstream->write(_text, r);
+}
+
+
+} // End of namespace Common
diff --git a/common/unarj.h b/common/unarj.h
new file mode 100644
index 0000000000..63c6ca582d
--- /dev/null
+++ b/common/unarj.h
@@ -0,0 +1,179 @@
+/* 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$
+ *
+ */
+
+#ifndef COMMON_UNARJ_H
+#define COMMON_UNARJ_H
+
+#include "common/file.h"
+#include "common/hash-str.h"
+
+namespace Common {
+
+#define HEADER_ID 0xEA60
+#define HEADER_ID_HI 0xEA
+#define HEADER_ID_LO 0x60
+#define FIRST_HDR_SIZE 30
+#define FIRST_HDR_SIZE_V 34
+#define COMMENT_MAX 2048
+#define FNAME_MAX 512
+#define HEADERSIZE_MAX (FIRST_HDR_SIZE + 10 + FNAME_MAX + COMMENT_MAX)
+#define CRC_MASK 0xFFFFFFFFL
+#define MAXSFX 25000L
+
+#define CODE_BIT 16
+#define CHAR_BIT 8
+#define UCHAR_MAX 255
+#define THRESHOLD 3
+#define DDICSIZ 26624
+#define MAXDICBIT 16
+#define MATCHBIT 8
+#define MAXMATCH 256
+#define NC (UCHAR_MAX + MAXMATCH + 2 - THRESHOLD)
+#define NP (MAXDICBIT + 1)
+#define CBIT 9
+#define NT (CODE_BIT + 3)
+#define PBIT 5
+#define TBIT 5
+
+#if NT > NP
+#define NPT NT
+#else
+#define NPT NP
+#endif
+
+#define CTABLESIZE 4096
+#define PTABLESIZE 256
+
+#define STRTP 9
+#define STOPP 13
+
+#define STRTL 0
+#define STOPL 7
+
+struct ArjHeader {
+ int32 pos;
+ uint16 id;
+ uint16 headerSize;
+ //
+ byte firstHdrSize;
+ byte nbr;
+ byte xNbr;
+ byte hostOs;
+ byte flags;
+ byte method;
+ byte fileType;
+ byte pad;
+ uint32 timeStamp;
+ int32 compSize;
+ int32 origSize;
+ uint32 fileCRC;
+ uint16 entryPos;
+ uint16 fileMode;
+ uint16 hostData;
+ char filename[FNAME_MAX];
+ char comment[COMMENT_MAX];
+ uint16 extHeaderSize;
+
+ uint32 headerCrc;
+};
+
+typedef HashMap<String, int, IgnoreCase_Hash, IgnoreCase_EqualTo> ArjFilesMap;
+
+class ArjFile : public File {
+public:
+ ArjFile();
+ ~ArjFile();
+
+ void registerArchive(const String &filename);
+
+ bool open(const Common::String &filename, AccessMode mode = kFileReadMode);
+ void close();
+
+ uint32 read(void *dataPtr, uint32 dataSize);
+ bool eos();
+ uint32 pos();
+ uint32 size();
+ void seek(int32 offset, int whence = SEEK_SET);
+ bool isOpen() { return _isOpen; }
+
+private:
+ File _currArchive;
+ Array<ArjHeader *> _headers;
+ ArjFilesMap _fileMap;
+ StringMap _archMap;
+ ReadStream *_stream;
+ byte *_uncompressedData;
+ MemoryWriteStream *_outstream;
+ MemoryReadStream *_uncompressed;
+
+ bool _isOpen;
+
+ int32 findHeader(void);
+ ArjHeader *readHeader();
+
+ void decode();
+ void decode_f();
+
+ uint16 _bitbuf;
+ int32 _compsize;
+ int32 _origsize;
+ byte _subbitbuf;
+ int _bitcount;
+
+ void init_getbits();
+ void fillbuf(int n);
+ uint16 getbits(int n);
+
+
+ void make_table(int nchar, byte *bitlen, int tablebits, uint16 *table, int tablesize);
+ void read_pt_len(int nn, int nbit, int i_special);
+ void read_c_len(void);
+ uint16 decode_c(void);
+ uint16 decode_p(void);
+ void decode_start(void);
+ int16 decode_ptr(void);
+ int16 decode_len(void);
+
+private:
+ byte _text[DDICSIZ];
+
+ int16 _getlen;
+ int16 _getbuf;
+
+ uint16 _left[2 * NC - 1];
+ uint16 _right[2 * NC - 1];
+ byte _c_len[NC];
+ byte _pt_len[NPT];
+
+ uint16 _c_table[CTABLESIZE];
+ uint16 _pt_table[PTABLESIZE];
+ uint16 _blocksize;
+
+
+};
+
+} // End of namespace Common
+
+#endif