00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include "common/scummsys.h"
00028 #include "common/archive.h"
00029 #include "common/debug.h"
00030 #include "common/unarj.h"
00031 #include "common/file.h"
00032 #include "common/hash-str.h"
00033 #include "common/memstream.h"
00034 #include "common/bufferedstream.h"
00035 #include "common/textconsole.h"
00036
00037 namespace Common {
00038
00039 #define ARJ_UCHAR_MAX 255
00040 #define ARJ_CHAR_BIT 8
00041
00042 #define ARJ_COMMENT_MAX 2048
00043 #define ARJ_FILENAME_MAX 512
00044
00045 #define ARJ_CODE_BIT 16
00046 #define ARJ_THRESHOLD 3
00047 #define ARJ_DICSIZ 26624
00048 #define ARJ_FDICSIZ ARJ_DICSIZ
00049 #define ARJ_MAXDICBIT 16
00050 #define ARJ_MAXMATCH 256
00051 #define ARJ_NC (ARJ_UCHAR_MAX + ARJ_MAXMATCH + 2 - ARJ_THRESHOLD)
00052 #define ARJ_NP (ARJ_MAXDICBIT + 1)
00053 #define ARJ_NT (ARJ_CODE_BIT + 3)
00054
00055 #if ARJ_NT > ARJ_NP
00056 #define ARJ_NPT ARJ_NT
00057 #else
00058 #define ARJ_NPT ARJ_NP
00059 #endif
00060
00061 #define ARJ_CTABLESIZE 4096
00062 #define ARJ_PTABLESIZE 256
00063
00064
00065 struct ArjHeader {
00066 int32 pos;
00067 uint16 id;
00068 uint16 headerSize;
00069
00070 byte firstHdrSize;
00071 byte nbr;
00072 byte xNbr;
00073 byte hostOs;
00074 byte flags;
00075 byte method;
00076 byte fileType;
00077 byte pad;
00078 uint32 timeStamp;
00079 int32 compSize;
00080 int32 origSize;
00081 uint32 fileCRC;
00082 uint16 entryPos;
00083 uint16 fileMode;
00084 uint16 hostData;
00085 char filename[ARJ_FILENAME_MAX];
00086 char comment[ARJ_COMMENT_MAX];
00087
00088 uint32 headerCrc;
00089 };
00090
00091 static int32 findHeader(SeekableReadStream &stream);
00092 static ArjHeader *readHeader(SeekableReadStream &stream);
00093
00094 class ArjDecoder {
00095 public:
00096 ArjDecoder(const ArjHeader *hdr) {
00097 _compsize = hdr->compSize;
00098 _compressed = nullptr;
00099 _outstream = nullptr;
00100 _bitbuf = 0;
00101 _bytebuf = 0;
00102 _bitcount = 0;
00103 _blocksize = 0;
00104 }
00105
00106 ~ArjDecoder() {
00107 delete _compressed;
00108 delete _outstream;
00109 }
00110
00111 void decode(int32 origsize);
00112 void decode_f(int32 origsize);
00113
00114 ReadStream *_compressed;
00115 MemoryWriteStream *_outstream;
00116
00117
00118 uint16 _bitbuf;
00119 uint16 _bytebuf;
00120 int32 _compsize;
00121 int _bitcount;
00122
00123 void init_getbits();
00124 void fillbuf(int n);
00125 uint16 getbits(int n);
00126
00127
00128 void make_table(int nchar, byte *bitlen, int tablebits, uint16 *table, int tablesize);
00129 void read_pt_len(int nn, int nbit, int i_special);
00130 void read_c_len(void);
00131 uint16 decode_c(void);
00132 uint16 decode_p(void);
00133 void decode_start(void);
00134 int16 decode_ptr(void);
00135 int16 decode_len(void);
00136
00137 private:
00138 byte _ntext[ARJ_FDICSIZ];
00139
00140 uint16 _left[2 * ARJ_NC - 1];
00141 uint16 _right[2 * ARJ_NC - 1];
00142 byte _c_len[ARJ_NC];
00143 byte _pt_len[ARJ_NPT];
00144
00145 uint16 _c_table[ARJ_CTABLESIZE];
00146 uint16 _pt_table[ARJ_PTABLESIZE];
00147 uint16 _blocksize;
00148 };
00149
00150 #define HEADER_ID 0xEA60
00151 #define HEADER_ID_HI 0xEA
00152 #define HEADER_ID_LO 0x60
00153
00154 #define FIRST_HDR_SIZE 30
00155 #define HEADERSIZE_MAX (FIRST_HDR_SIZE + 10 + ARJ_FILENAME_MAX + ARJ_COMMENT_MAX)
00156 #define CRC_MASK 0xFFFFFFFFL
00157 #define HSLIMIT_ARJ 524288L
00158
00159 #define CBIT 9
00160 #define PBIT 5
00161 #define TBIT 5
00162
00163
00164 class CRC32 {
00165 static uint32 _table[256];
00166 static bool _initialized;
00167
00168 private:
00169 static void init() {
00170 const uint32 poly = 0xEDB88320;
00171 int i, j;
00172 uint32 r;
00173
00174 for (i = 0; i < 256; i++) {
00175 r = i;
00176 for (j = 0; j < 8; j++)
00177 if (r & 1)
00178 r = (r >> 1) ^ poly;
00179 else
00180 r >>= 1;
00181 _table[i] = r;
00182 }
00183
00184 _initialized = true;
00185 }
00186
00187 public:
00188 static uint32 checksum(byte *data, int len) {
00189 if (!_initialized) {
00190 init();
00191 }
00192
00193 uint32 CRC = 0xFFFFFFFF;
00194 int i;
00195 for (i = 0; i < len; i++)
00196 CRC = (CRC >> 8) ^ _table[(CRC ^ data[i]) & 0xFF];
00197 return CRC ^ 0xFFFFFFFF;
00198 }
00199 };
00200
00201 bool CRC32::_initialized = false;
00202 uint32 CRC32::_table[256];
00203
00204
00205 int32 findHeader(SeekableReadStream &stream) {
00206 long end_pos, tmp_pos;
00207 int id;
00208 byte header[HEADERSIZE_MAX];
00209 uint32 crc;
00210 uint16 basic_hdr_size;
00211
00212 tmp_pos = stream.pos();
00213 stream.seek(0L, SEEK_END);
00214 end_pos = stream.pos() - 2;
00215 if (end_pos >= tmp_pos + HSLIMIT_ARJ)
00216 end_pos = tmp_pos + HSLIMIT_ARJ;
00217
00218 while (tmp_pos < end_pos) {
00219 stream.seek(tmp_pos, SEEK_SET);
00220 id = stream.readByte();
00221 while (tmp_pos < end_pos) {
00222 if (id == HEADER_ID_LO) {
00223 if ((id = stream.readByte()) == HEADER_ID_HI)
00224 break;
00225 } else
00226 id = stream.readByte();
00227 tmp_pos++;
00228 }
00229 if (tmp_pos >= end_pos)
00230 return -1;
00231 if ((basic_hdr_size = stream.readUint16LE()) <= HEADERSIZE_MAX) {
00232 stream.read(header, basic_hdr_size);
00233 crc = CRC32::checksum(header, basic_hdr_size);
00234 if (crc == stream.readUint32LE()) {
00235 stream.seek(tmp_pos, SEEK_SET);
00236 return tmp_pos;
00237 }
00238 }
00239 tmp_pos++;
00240 }
00241 return -1;
00242 }
00243
00244 ArjHeader *readHeader(SeekableReadStream &stream) {
00245 ArjHeader header;
00246 ArjHeader *head;
00247 byte headData[HEADERSIZE_MAX];
00248
00249
00250 header.id = stream.readUint16LE();
00251 if (header.id != HEADER_ID) {
00252 warning("ArjFile::readHeader(): Bad header ID (%x)", header.id);
00253
00254 return nullptr;
00255 }
00256
00257 header.headerSize = stream.readUint16LE();
00258 if (header.headerSize == 0)
00259 return nullptr;
00260 if (header.headerSize > HEADERSIZE_MAX) {
00261 warning("ArjFile::readHeader(): Bad header");
00262
00263 return nullptr;
00264 }
00265
00266 int rSize = stream.read(headData, header.headerSize);
00267
00268 MemoryReadStream readS(headData, rSize);
00269
00270 header.headerCrc = stream.readUint32LE();
00271 if (CRC32::checksum(headData, header.headerSize) != header.headerCrc) {
00272 warning("ArjFile::readHeader(): Bad header CRC");
00273 return nullptr;
00274 }
00275
00276 header.firstHdrSize = readS.readByte();
00277 header.nbr = readS.readByte();
00278 header.xNbr = readS.readByte();
00279 header.hostOs = readS.readByte();
00280 header.flags = readS.readByte();
00281 header.method = readS.readByte();
00282 header.fileType = readS.readByte();
00283 (void)readS.readByte();
00284 header.timeStamp = readS.readUint32LE();
00285 header.compSize = readS.readSint32LE();
00286 header.origSize = readS.readSint32LE();
00287 header.fileCRC = readS.readUint32LE();
00288 header.entryPos = readS.readUint16LE();
00289 header.fileMode = readS.readUint16LE();
00290 header.hostData = readS.readUint16LE();
00291
00292
00293 if (header.origSize < 0 || header.compSize < 0) {
00294 warning("ArjFile::readHeader(): Wrong file size");
00295 return nullptr;
00296 }
00297
00298 strlcpy(header.filename, (const char *)&headData[header.firstHdrSize], ARJ_FILENAME_MAX);
00299 strlcpy(header.comment, (const char *)&headData[header.firstHdrSize + strlen(header.filename) + 1], ARJ_COMMENT_MAX);
00300
00301
00302 uint16 extHeaderSize;
00303 while ((extHeaderSize = stream.readUint16LE()) != 0)
00304 stream.seek((long)(extHeaderSize + 4), SEEK_CUR);
00305
00306 header.pos = stream.pos();
00307
00308 head = new ArjHeader(header);
00309
00310 return head;
00311 }
00312
00313
00314 void ArjDecoder::init_getbits() {
00315 _bitbuf = 0;
00316 _bytebuf = 0;
00317 _bitcount = 0;
00318 fillbuf(ARJ_CHAR_BIT * 2);
00319 }
00320
00321
00322 void ArjDecoder::fillbuf(int n) {
00323 while (_bitcount < n) {
00324 _bitbuf = (_bitbuf << _bitcount) | (_bytebuf >> (8 - _bitcount));
00325 n -= _bitcount;
00326 if (_compsize > 0) {
00327 _compsize--;
00328 _bytebuf = _compressed->readByte();
00329 } else {
00330 _bytebuf = 0;
00331 }
00332 _bitcount = 8;
00333 }
00334 _bitcount -= n;
00335 _bitbuf = ( _bitbuf << n) | (_bytebuf >> (8-n));
00336 _bytebuf <<= n;
00337 }
00338
00339
00340 uint16 ArjDecoder::getbits(int n) {
00341 uint16 rc;
00342
00343 rc = _bitbuf >> (ARJ_CODE_BIT - n);
00344 fillbuf(n);
00345 return rc;
00346 }
00347
00348
00349
00350
00351
00352 void ArjDecoder::make_table(int nchar, byte *bitlen, int tablebits, uint16 *table, int tablesize) {
00353 uint16 count[17], weight[17], start[18];
00354 uint16 *p;
00355 uint i, k, len, ch, jutbits, avail, nextcode, mask;
00356
00357 for (i = 1; i <= 16; i++)
00358 count[i] = 0;
00359 for (i = 0; (int)i < nchar; i++)
00360 count[bitlen[i]]++;
00361
00362 start[1] = 0;
00363 for (i = 1; i <= 16; i++)
00364 start[i + 1] = start[i] + (count[i] << (16 - i));
00365 if (start[17] != (uint16) (1 << 16))
00366 error("ArjDecoder::make_table(): bad file data");
00367
00368 jutbits = 16 - tablebits;
00369 for (i = 1; (int)i <= tablebits; i++) {
00370 start[i] >>= jutbits;
00371 weight[i] = 1 << (tablebits - i);
00372 }
00373 while (i <= 16) {
00374 weight[i] = 1 << (16 - i);
00375 i++;
00376 }
00377
00378 i = start[tablebits + 1] >> jutbits;
00379 if (i != (uint16) (1 << 16)) {
00380 k = 1 << tablebits;
00381 while (i != k)
00382 table[i++] = 0;
00383 }
00384
00385 avail = nchar;
00386 mask = 1 << (15 - tablebits);
00387 for (ch = 0; (int)ch < nchar; ch++) {
00388 if ((len = bitlen[ch]) == 0)
00389 continue;
00390 k = start[len];
00391 nextcode = k + weight[len];
00392 if ((int)len <= tablebits) {
00393 if (nextcode > (uint)tablesize)
00394 error("ArjDecoder::make_table(): bad file data");
00395 for (i = start[len]; i < nextcode; i++)
00396 table[i] = ch;
00397 } else {
00398 p = &table[k >> jutbits];
00399 i = len - tablebits;
00400 while (i != 0) {
00401 if (*p == 0) {
00402 _right[avail] = _left[avail] = 0;
00403 *p = avail;
00404 avail++;
00405 }
00406 if (k & mask)
00407 p = &_right[*p];
00408 else
00409 p = &_left[*p];
00410 k <<= 1;
00411 i--;
00412 }
00413 *p = ch;
00414 }
00415 start[len] = nextcode;
00416 }
00417 }
00418
00419
00420 void ArjDecoder::read_pt_len(int nn, int nbit, int i_special) {
00421 int i, n;
00422 int16 c;
00423 uint16 mask;
00424
00425 n = getbits(nbit);
00426 if (n == 0) {
00427 c = getbits(nbit);
00428 for (i = 0; i < nn; i++)
00429 _pt_len[i] = 0;
00430 for (i = 0; i < 256; i++)
00431 _pt_table[i] = c;
00432 } else {
00433 i = 0;
00434 while (i < n) {
00435 c = _bitbuf >> 13;
00436 if (c == 7) {
00437 mask = 1 << 12;
00438 while (mask & _bitbuf) {
00439 mask >>= 1;
00440 c++;
00441 }
00442 }
00443 fillbuf((c < 7) ? 3 : (int)(c - 3));
00444 _pt_len[i++] = (byte)c;
00445 if (i == i_special) {
00446 c = getbits(2);
00447 while (--c >= 0)
00448 _pt_len[i++] = 0;
00449 }
00450 }
00451 while (i < nn)
00452 _pt_len[i++] = 0;
00453 make_table(nn, _pt_len, 8, _pt_table, ARJ_PTABLESIZE);
00454 }
00455 }
00456
00457
00458 void ArjDecoder::read_c_len() {
00459 int16 i, c, n;
00460 uint16 mask;
00461
00462 n = getbits(CBIT);
00463 if (n == 0) {
00464 c = getbits(CBIT);
00465 for (i = 0; i < ARJ_NC; i++)
00466 _c_len[i] = 0;
00467 for (i = 0; i < ARJ_CTABLESIZE; i++)
00468 _c_table[i] = c;
00469 } else {
00470 i = 0;
00471 while (i < n) {
00472 c = _pt_table[_bitbuf >> (8)];
00473 if (c >= ARJ_NT) {
00474 mask = 1 << 7;
00475 do {
00476 if (_bitbuf & mask)
00477 c = _right[c];
00478 else
00479 c = _left[c];
00480 mask >>= 1;
00481 } while (c >= ARJ_NT);
00482 }
00483 fillbuf((int)(_pt_len[c]));
00484 if (c <= 2) {
00485 if (c == 0)
00486 c = 1;
00487 else if (c == 1) {
00488 c = getbits(4);
00489 c += 3;
00490 } else {
00491 c = getbits(CBIT);
00492 c += 20;
00493 }
00494 while (--c >= 0)
00495 _c_len[i++] = 0;
00496 }
00497 else
00498 _c_len[i++] = (byte)(c - 2);
00499 }
00500 while (i < ARJ_NC)
00501 _c_len[i++] = 0;
00502 make_table(ARJ_NC, _c_len, 12, _c_table, ARJ_CTABLESIZE);
00503 }
00504 }
00505
00506
00507 uint16 ArjDecoder::decode_c() {
00508 uint16 j, mask;
00509
00510 if (_blocksize == 0) {
00511 _blocksize = getbits(ARJ_CODE_BIT);
00512 read_pt_len(ARJ_NT, TBIT, 3);
00513 read_c_len();
00514 read_pt_len(ARJ_NP, PBIT, -1);
00515 }
00516 _blocksize--;
00517 j = _c_table[_bitbuf >> 4];
00518 if (j >= ARJ_NC) {
00519 mask = 1 << 3;
00520 do {
00521 if (_bitbuf & mask)
00522 j = _right[j];
00523 else
00524 j = _left[j];
00525 mask >>= 1;
00526 } while (j >= ARJ_NC);
00527 }
00528 fillbuf((int)(_c_len[j]));
00529 return j;
00530 }
00531
00532
00533 uint16 ArjDecoder::decode_p() {
00534 uint16 j, mask;
00535
00536 j = _pt_table[_bitbuf >> 8];
00537 if (j >= ARJ_NP) {
00538 mask = 1 << 7;
00539 do {
00540 if (_bitbuf & mask)
00541 j = _right[j];
00542 else
00543 j = _left[j];
00544 mask >>= 1;
00545 } while (j >= ARJ_NP);
00546 }
00547 fillbuf((int)(_pt_len[j]));
00548 if (j != 0) {
00549 j--;
00550 j = (1 << j) + getbits((int)j);
00551 }
00552 return j;
00553 }
00554
00555
00556 void ArjDecoder::decode_start() {
00557 _blocksize = 0;
00558 init_getbits();
00559 }
00560
00561
00562 void ArjDecoder::decode(int32 origsize) {
00563 int16 i;
00564 int16 r;
00565 int16 c;
00566 int16 j;
00567 int32 count;
00568
00569 decode_start();
00570 count = origsize;
00571 r = 0;
00572
00573 while (count > 0) {
00574 if ((c = decode_c()) <= ARJ_UCHAR_MAX) {
00575 _ntext[r] = (byte) c;
00576 count--;
00577 if (++r >= ARJ_DICSIZ) {
00578 r = 0;
00579 _outstream->write(_ntext, ARJ_DICSIZ);
00580 }
00581 } else {
00582 j = c - (ARJ_UCHAR_MAX + 1 - ARJ_THRESHOLD);
00583 count -= j;
00584 i = r - decode_p() - 1;
00585 if (i < 0)
00586 i += ARJ_DICSIZ;
00587 if (r > i && r < ARJ_DICSIZ - ARJ_MAXMATCH - 1) {
00588 while (--j >= 0)
00589 _ntext[r++] = _ntext[i++];
00590 } else {
00591 while (--j >= 0) {
00592 _ntext[r] = _ntext[i];
00593 if (++r >= ARJ_DICSIZ) {
00594 r = 0;
00595 _outstream->write(_ntext, ARJ_DICSIZ);
00596 }
00597 if (++i >= ARJ_DICSIZ)
00598 i = 0;
00599 }
00600 }
00601 }
00602 }
00603 if (r > 0)
00604 _outstream->write(_ntext, r);
00605 }
00606
00607
00608 int16 ArjDecoder::decode_ptr() {
00609 int16 c = 0;
00610 int16 width;
00611 int16 plus;
00612 int16 pwr;
00613
00614 plus = 0;
00615 pwr = 1 << 9;
00616 for (width = 9; width < 13; width++) {
00617 c = getbits(1);
00618 if (c == 0)
00619 break;
00620 plus += pwr;
00621 pwr <<= 1;
00622 }
00623 if (width != 0)
00624 c = getbits(width);
00625 c += plus;
00626 return c;
00627 }
00628
00629
00630 int16 ArjDecoder::decode_len() {
00631 int16 c = 0;
00632 int16 width;
00633 int16 plus;
00634 int16 pwr;
00635
00636 plus = 0;
00637 pwr = 1;
00638 for (width = 0; width < 7; width++) {
00639 c = getbits(1);
00640 if (c == 0)
00641 break;
00642 plus += pwr;
00643 pwr <<= 1;
00644 }
00645 if (width != 0)
00646 c = getbits(width);
00647 c += plus;
00648 return c;
00649 }
00650
00651
00652 void ArjDecoder::decode_f(int32 origsize) {
00653 int16 i;
00654 int16 j;
00655 int16 c;
00656 int16 r;
00657 uint32 ncount;
00658
00659 init_getbits();
00660 ncount = 0;
00661 r = 0;
00662
00663 while (ncount < (uint32)origsize) {
00664 c = decode_len();
00665 if (c == 0) {
00666 ncount++;
00667 _ntext[r] = (byte)getbits(8);
00668 if (++r >= ARJ_FDICSIZ) {
00669 r = 0;
00670 _outstream->write(_ntext, ARJ_FDICSIZ);
00671 }
00672 } else {
00673 j = c - 1 + ARJ_THRESHOLD;
00674 ncount += j;
00675 if ((i = r - decode_ptr() - 1) < 0)
00676 i += ARJ_FDICSIZ;
00677 while (j-- > 0) {
00678 _ntext[r] = _ntext[i];
00679 if (++r >= ARJ_FDICSIZ) {
00680 r = 0;
00681 _outstream->write(_ntext, ARJ_FDICSIZ);
00682 }
00683 if (++i >= ARJ_FDICSIZ)
00684 i = 0;
00685 }
00686 }
00687 }
00688 if (r != 0)
00689 _outstream->write(_ntext, r);
00690 }
00691
00692 #pragma mark ArjArchive implementation
00693
00694 typedef HashMap<String, ArjHeader*, IgnoreCase_Hash, IgnoreCase_EqualTo> ArjHeadersMap;
00695
00696 class ArjArchive : public Archive {
00697 ArjHeadersMap _headers;
00698 String _arjFilename;
00699
00700 public:
00701 ArjArchive(const String &name);
00702 virtual ~ArjArchive();
00703
00704
00705 virtual bool hasFile(const String &name) const;
00706 virtual int listMembers(ArchiveMemberList &list) const;
00707 virtual const ArchiveMemberPtr getMember(const String &name) const;
00708 virtual SeekableReadStream *createReadStreamForMember(const String &name) const;
00709 };
00710
00711 ArjArchive::ArjArchive(const String &filename) : _arjFilename(filename) {
00712 File arjFile;
00713
00714 if (!arjFile.open(_arjFilename)) {
00715 warning("ArjArchive::ArjArchive(): Could not find the archive file");
00716 return;
00717 }
00718
00719 int32 firstHeaderOffset = findHeader(arjFile);
00720
00721 if (firstHeaderOffset < 0) {
00722 warning("ArjArchive::ArjArchive(): Could not find a valid header");
00723 return;
00724 }
00725
00726 ArjHeader *header = nullptr;
00727
00728 arjFile.seek(firstHeaderOffset, SEEK_SET);
00729 if ((header = readHeader(arjFile)) == nullptr)
00730 return;
00731 delete header;
00732
00733 while ((header = readHeader(arjFile)) != nullptr) {
00734 _headers[header->filename] = header;
00735 arjFile.seek(header->compSize, SEEK_CUR);
00736 }
00737
00738 debug(0, "ArjArchive::ArjArchive(%s): Located %d files", filename.c_str(), _headers.size());
00739 }
00740
00741 ArjArchive::~ArjArchive() {
00742 debug(0, "ArjArchive Destructor Called");
00743 ArjHeadersMap::iterator it = _headers.begin();
00744 for ( ; it != _headers.end(); ++it) {
00745 delete it->_value;
00746 }
00747 }
00748
00749 bool ArjArchive::hasFile(const String &name) const {
00750 return _headers.contains(name);
00751 }
00752
00753 int ArjArchive::listMembers(ArchiveMemberList &list) const {
00754 int matches = 0;
00755
00756 ArjHeadersMap::const_iterator it = _headers.begin();
00757 for ( ; it != _headers.end(); ++it) {
00758 list.push_back(ArchiveMemberList::value_type(new GenericArchiveMember(it->_value->filename, this)));
00759 matches++;
00760 }
00761
00762 return matches;
00763 }
00764
00765 const ArchiveMemberPtr ArjArchive::getMember(const String &name) const {
00766 if (!hasFile(name))
00767 return ArchiveMemberPtr();
00768
00769 return ArchiveMemberPtr(new GenericArchiveMember(name, this));
00770 }
00771
00772 SeekableReadStream *ArjArchive::createReadStreamForMember(const String &name) const {
00773 if (!_headers.contains(name)) {
00774 return nullptr;
00775 }
00776
00777 ArjHeader *hdr = _headers[name];
00778
00779 File archiveFile;
00780 archiveFile.open(_arjFilename);
00781 archiveFile.seek(hdr->pos, SEEK_SET);
00782
00783
00784
00785 byte *uncompressedData = (byte *)malloc(hdr->origSize);
00786 assert(uncompressedData);
00787
00788 if (hdr->method == 0) {
00789 int32 len = archiveFile.read(uncompressedData, hdr->origSize);
00790 assert(len == hdr->origSize);
00791 } else {
00792 ArjDecoder *decoder = new ArjDecoder(hdr);
00793
00794
00795
00796
00797
00798 decoder->_compressed = wrapBufferedReadStream(&archiveFile, 4096, DisposeAfterUse::NO);
00799 decoder->_outstream = new MemoryWriteStream(uncompressedData, hdr->origSize);
00800
00801 if (hdr->method == 1 || hdr->method == 2 || hdr->method == 3)
00802 decoder->decode(hdr->origSize);
00803 else if (hdr->method == 4)
00804 decoder->decode_f(hdr->origSize);
00805
00806 delete decoder;
00807 }
00808
00809 return new MemoryReadStream(uncompressedData, hdr->origSize, DisposeAfterUse::YES);
00810 }
00811
00812 Archive *makeArjArchive(const String &name) {
00813 return new ArjArchive(name);
00814 }
00815
00816 }