PageRenderTime 48ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/engines/kyra/resource_intern.cpp

http://github.com/scummvm/scummvm
C++ | 1351 lines | 1038 code | 272 blank | 41 comment | 232 complexity | 24569c7f39d38fda214699017d088d02 MD5 | raw file
Possible License(s): GPL-3.0, LGPL-2.1, GPL-2.0
  1. /* ScummVM - Graphic Adventure Engine
  2. *
  3. * ScummVM is the legal property of its developers, whose names
  4. * are too numerous to list here. Please refer to the COPYRIGHT
  5. * file distributed with this source distribution.
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License
  9. * as published by the Free Software Foundation; either version 2
  10. * of the License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  20. *
  21. */
  22. #include "kyra/resource_intern.h"
  23. #include "kyra/resource.h"
  24. #include "common/endian.h"
  25. #include "common/memstream.h"
  26. #include "common/substream.h"
  27. namespace Kyra {
  28. // Implementation of various Archive subclasses
  29. // -> PlainArchive implementation
  30. PlainArchive::PlainArchive(Common::ArchiveMemberPtr file)
  31. : _file(file), _files() {
  32. }
  33. bool PlainArchive::hasFile(const Common::String &name) const {
  34. return (_files.find(name) != _files.end());
  35. }
  36. int PlainArchive::listMembers(Common::ArchiveMemberList &list) const {
  37. int count = 0;
  38. for (FileMap::const_iterator i = _files.begin(); i != _files.end(); ++i) {
  39. list.push_back(Common::ArchiveMemberList::value_type(new Common::GenericArchiveMember(i->_key, this)));
  40. ++count;
  41. }
  42. return count;
  43. }
  44. const Common::ArchiveMemberPtr PlainArchive::getMember(const Common::String &name) const {
  45. if (!hasFile(name))
  46. return Common::ArchiveMemberPtr();
  47. return Common::ArchiveMemberPtr(new Common::GenericArchiveMember(name, this));
  48. }
  49. Common::SeekableReadStream *PlainArchive::createReadStreamForMember(const Common::String &name) const {
  50. FileMap::const_iterator fDesc = _files.find(name);
  51. if (fDesc == _files.end())
  52. return 0;
  53. Common::SeekableReadStream *parent = _file->createReadStream();
  54. if (!parent)
  55. return 0;
  56. return new Common::SeekableSubReadStream(parent, fDesc->_value.offset, fDesc->_value.offset + fDesc->_value.size, DisposeAfterUse::YES);
  57. }
  58. void PlainArchive::addFileEntry(const Common::String &name, const Entry entry) {
  59. _files[name] = entry;
  60. }
  61. PlainArchive::Entry PlainArchive::getFileEntry(const Common::String &name) const {
  62. FileMap::const_iterator fDesc = _files.find(name);
  63. if (fDesc == _files.end())
  64. return Entry();
  65. return fDesc->_value;
  66. }
  67. // -> TlkArchive implementation
  68. TlkArchive::TlkArchive(Common::ArchiveMemberPtr file, uint16 entryCount, const uint32 *fileEntries)
  69. : _file(file), _entryCount(entryCount), _fileEntries(fileEntries) {
  70. }
  71. TlkArchive::~TlkArchive() {
  72. delete[] _fileEntries;
  73. }
  74. bool TlkArchive::hasFile(const Common::String &name) const {
  75. return (findFile(name) != 0);
  76. }
  77. int TlkArchive::listMembers(Common::ArchiveMemberList &list) const {
  78. uint count = 0;
  79. for (; count < _entryCount; ++count) {
  80. const Common::String name = Common::String::format("%08u.AUD", _fileEntries[count * 2 + 0]);
  81. list.push_back(Common::ArchiveMemberList::value_type(new Common::GenericArchiveMember(name, this)));
  82. }
  83. return count;
  84. }
  85. const Common::ArchiveMemberPtr TlkArchive::getMember(const Common::String &name) const {
  86. if (!hasFile(name))
  87. return Common::ArchiveMemberPtr();
  88. return Common::ArchiveMemberPtr(new Common::GenericArchiveMember(name, this));
  89. }
  90. Common::SeekableReadStream *TlkArchive::createReadStreamForMember(const Common::String &name) const {
  91. const uint32 *fileDesc = findFile(name);
  92. if (!fileDesc)
  93. return 0;
  94. Common::SeekableReadStream *parent = _file->createReadStream();
  95. if (!parent)
  96. return 0;
  97. parent->seek(fileDesc[1], SEEK_SET);
  98. const uint32 size = parent->readUint32LE();
  99. const uint32 fileStart = fileDesc[1] + 4;
  100. return new Common::SeekableSubReadStream(parent, fileStart, fileStart + size, DisposeAfterUse::YES);
  101. }
  102. const uint32 *TlkArchive::findFile(const Common::String &name) const {
  103. Common::String uppercaseName = name;
  104. uppercaseName.toUppercase();
  105. if (!uppercaseName.hasSuffix(".AUD"))
  106. return 0;
  107. uint32 id;
  108. if (sscanf(uppercaseName.c_str(), "%08u.AUD", &id) != 1)
  109. return 0;
  110. // Binary search for the file entry
  111. int leftIndex = 0;
  112. int rightIndex = _entryCount - 1;
  113. while (leftIndex <= rightIndex) {
  114. int mid = (leftIndex + rightIndex) / 2;
  115. const uint32 key = _fileEntries[mid * 2];
  116. if (key == id) {
  117. // Found
  118. return &_fileEntries[mid * 2];
  119. } else if (key > id) {
  120. // Take the left sub-tree
  121. rightIndex = mid - 1;
  122. } else {
  123. // Take the right sub-tree
  124. leftIndex = mid + 1;
  125. }
  126. }
  127. return 0;
  128. }
  129. // -> CachedArchive implementation
  130. CachedArchive::CachedArchive(const FileInputList &files)
  131. : _files() {
  132. for (FileInputList::const_iterator i = files.begin(); i != files.end(); ++i) {
  133. Entry entry;
  134. entry.data = i->data;
  135. entry.size = i->size;
  136. Common::String name = i->name;
  137. name.toLowercase();
  138. _files[name] = entry;
  139. }
  140. }
  141. CachedArchive::~CachedArchive() {
  142. for (FileMap::iterator i = _files.begin(); i != _files.end(); ++i)
  143. delete[] i->_value.data;
  144. _files.clear();
  145. }
  146. bool CachedArchive::hasFile(const Common::String &name) const {
  147. return (_files.find(name) != _files.end());
  148. }
  149. int CachedArchive::listMembers(Common::ArchiveMemberList &list) const {
  150. int count = 0;
  151. for (FileMap::const_iterator i = _files.begin(); i != _files.end(); ++i) {
  152. list.push_back(Common::ArchiveMemberList::value_type(new Common::GenericArchiveMember(i->_key, this)));
  153. ++count;
  154. }
  155. return count;
  156. }
  157. const Common::ArchiveMemberPtr CachedArchive::getMember(const Common::String &name) const {
  158. if (!hasFile(name))
  159. return Common::ArchiveMemberPtr();
  160. return Common::ArchiveMemberPtr(new Common::GenericArchiveMember(name, this));
  161. }
  162. Common::SeekableReadStream *CachedArchive::createReadStreamForMember(const Common::String &name) const {
  163. FileMap::const_iterator fDesc = _files.find(name);
  164. if (fDesc == _files.end())
  165. return 0;
  166. return new Common::MemoryReadStream(fDesc->_value.data, fDesc->_value.size, DisposeAfterUse::NO);
  167. }
  168. // ResFileLoader implementations
  169. // -> ResLoaderPak implementation
  170. bool ResLoaderPak::checkFilename(Common::String filename) const {
  171. filename.toUppercase();
  172. return (filename.hasSuffix(".PAK") || filename.hasSuffix(".APK") || filename.hasSuffix(".VRM") || filename.hasSuffix(".CMP") || filename.hasSuffix(".TLK") || filename.equalsIgnoreCase(StaticResource::staticDataFilename()));
  173. }
  174. namespace {
  175. Common::String readString(Common::SeekableReadStream &stream) {
  176. Common::String result;
  177. char c = 0;
  178. while ((c = stream.readByte()) != 0)
  179. result += c;
  180. return result;
  181. }
  182. } // end of anonymous namespace
  183. bool ResLoaderPak::isLoadable(const Common::String &filename, Common::SeekableReadStream &stream) const {
  184. int32 filesize = stream.size();
  185. if (filesize < 0)
  186. return false;
  187. int32 offset = 0;
  188. bool switchEndian = false;
  189. bool firstFile = true;
  190. offset = stream.readUint32LE();
  191. if (offset > filesize || offset < 0) {
  192. switchEndian = true;
  193. offset = SWAP_BYTES_32(offset);
  194. }
  195. int32 firstOffset = offset;
  196. Common::String file;
  197. while (!stream.eos()) {
  198. // The start offset of a file should never be in the filelist
  199. if (offset < stream.pos() || offset > filesize || offset < 0)
  200. return false;
  201. file = readString(stream);
  202. if (stream.eos())
  203. return false;
  204. // Quit now if we encounter an empty string
  205. if (file.empty()) {
  206. if (firstFile)
  207. return false;
  208. else
  209. break;
  210. }
  211. firstFile = false;
  212. offset = switchEndian ? stream.readUint32BE() : stream.readUint32LE();
  213. if (!offset || offset == filesize || firstOffset == stream.pos())
  214. break;
  215. }
  216. return true;
  217. }
  218. Common::Archive *ResLoaderPak::load(Common::ArchiveMemberPtr memberFile, Common::SeekableReadStream &stream) const {
  219. int32 filesize = stream.size();
  220. if (filesize < 0)
  221. return 0;
  222. Common::ScopedPtr<PlainArchive> result(new PlainArchive(memberFile));
  223. if (!result)
  224. return 0;
  225. int32 startoffset = 0, endoffset = 0;
  226. bool switchEndian = false;
  227. bool firstFile = true;
  228. startoffset = stream.readUint32LE();
  229. int32 firstOffset = startoffset;
  230. if (startoffset > filesize || startoffset < 0) {
  231. switchEndian = true;
  232. startoffset = SWAP_BYTES_32(startoffset);
  233. }
  234. Common::String file;
  235. while (!stream.eos()) {
  236. // The start offset of a file should never be in the filelist
  237. if (startoffset < stream.pos() || startoffset > filesize || startoffset < 0) {
  238. warning("PAK file '%s' is corrupted", memberFile->getDisplayName().c_str());
  239. return 0;
  240. }
  241. file = readString(stream);
  242. if (stream.eos()) {
  243. warning("PAK file '%s' is corrupted", memberFile->getDisplayName().c_str());
  244. return 0;
  245. }
  246. // Quit now if we encounter an empty string
  247. if (file.empty()) {
  248. if (firstFile) {
  249. warning("PAK file '%s' is corrupted", memberFile->getDisplayName().c_str());
  250. return 0;
  251. } else {
  252. break;
  253. }
  254. }
  255. firstFile = false;
  256. endoffset = switchEndian ? stream.readUint32BE() : stream.readUint32LE();
  257. if (endoffset < 0 && stream.pos() != firstOffset) {
  258. warning("PAK file '%s' is corrupted", memberFile->getDisplayName().c_str());
  259. return 0;
  260. }
  261. if (!endoffset || stream.pos() == firstOffset)
  262. endoffset = filesize;
  263. if (startoffset != endoffset)
  264. result->addFileEntry(file, PlainArchive::Entry(startoffset, endoffset - startoffset));
  265. if (endoffset == filesize)
  266. break;
  267. startoffset = endoffset;
  268. }
  269. PlainArchive::Entry linklistFile = result->getFileEntry("LINKLIST");
  270. if (linklistFile.size != 0) {
  271. stream.seek(linklistFile.offset, SEEK_SET);
  272. const uint32 magic = stream.readUint32BE();
  273. if (magic != MKTAG('S', 'C', 'V', 'M'))
  274. error("LINKLIST file does not contain 'SCVM' header");
  275. const uint32 links = stream.readUint32BE();
  276. for (uint32 i = 0; i < links; ++i) {
  277. const Common::String linksTo = readString(stream);
  278. const uint32 sources = stream.readUint32BE();
  279. PlainArchive::Entry destination = result->getFileEntry(linksTo);
  280. if (destination.size == 0)
  281. error("PAK file link destination '%s' not found", linksTo.c_str());
  282. for (uint32 j = 0; j < sources; ++j) {
  283. const Common::String dest = readString(stream);
  284. result->addFileEntry(dest, destination);
  285. }
  286. }
  287. }
  288. return result.release();
  289. }
  290. // -> ResLoaderInsMalcolm implementation
  291. bool ResLoaderInsMalcolm::checkFilename(Common::String filename) const {
  292. filename.toUppercase();
  293. if (!filename.hasSuffix(".001"))
  294. return false;
  295. return true;
  296. }
  297. bool ResLoaderInsMalcolm::isLoadable(const Common::String &filename, Common::SeekableReadStream &stream) const {
  298. stream.seek(3, SEEK_SET);
  299. int32 size = stream.readUint32LE();
  300. if (size + 7 > stream.size())
  301. return false;
  302. stream.seek(size + 5, SEEK_SET);
  303. uint8 buffer[2];
  304. stream.read(&buffer, 2);
  305. return (buffer[0] == 0x0D && buffer[1] == 0x0A);
  306. }
  307. Common::Archive *ResLoaderInsMalcolm::load(Common::ArchiveMemberPtr memberFile, Common::SeekableReadStream &stream) const {
  308. Common::List<Common::String> filenames;
  309. Common::ScopedPtr<PlainArchive> result(new PlainArchive(memberFile));
  310. if (!result)
  311. return 0;
  312. // thanks to eriktorbjorn for this code (a bit modified though)
  313. stream.seek(3, SEEK_SET);
  314. // first file is the index table
  315. uint32 size = stream.readUint32LE();
  316. Common::String temp;
  317. for (uint32 i = 0; i < size; ++i) {
  318. byte c = stream.readByte();
  319. if (c == '\\') {
  320. temp.clear();
  321. } else if (c == 0x0D) {
  322. // line endings are CRLF
  323. c = stream.readByte();
  324. assert(c == 0x0A);
  325. ++i;
  326. filenames.push_back(temp);
  327. } else {
  328. temp += (char)c;
  329. }
  330. }
  331. stream.seek(3, SEEK_SET);
  332. for (Common::List<Common::String>::iterator file = filenames.begin(); file != filenames.end(); ++file) {
  333. const uint32 fileSize = stream.readUint32LE();
  334. const uint32 fileOffset = stream.pos();
  335. result->addFileEntry(*file, PlainArchive::Entry(fileOffset, fileSize));
  336. stream.seek(fileSize, SEEK_CUR);
  337. }
  338. return result.release();
  339. }
  340. bool ResLoaderTlk::checkFilename(Common::String filename) const {
  341. filename.toUppercase();
  342. return (filename.hasSuffix(".TLK"));
  343. }
  344. bool ResLoaderTlk::isLoadable(const Common::String &filename, Common::SeekableReadStream &stream) const {
  345. uint16 entries = stream.readUint16LE();
  346. int32 entryTableSize = (entries * 8);
  347. if (entryTableSize + 2 > stream.size())
  348. return false;
  349. int32 offset = 0;
  350. for (uint i = 0; i < entries; ++i) {
  351. stream.readUint32LE();
  352. offset = stream.readUint32LE();
  353. if (offset > stream.size())
  354. return false;
  355. }
  356. return true;
  357. }
  358. Common::Archive *ResLoaderTlk::load(Common::ArchiveMemberPtr file, Common::SeekableReadStream &stream) const {
  359. const uint16 entryCount = stream.readUint16LE();
  360. uint32 *fileEntries = new uint32[entryCount * 2];
  361. assert(fileEntries);
  362. stream.read(fileEntries, sizeof(uint32) * entryCount * 2);
  363. for (uint i = 0; i < entryCount; ++i) {
  364. fileEntries[i * 2 + 0] = READ_LE_UINT32(&fileEntries[i * 2 + 0]);
  365. fileEntries[i * 2 + 1] = READ_LE_UINT32(&fileEntries[i * 2 + 1]);
  366. }
  367. return new TlkArchive(file, entryCount, fileEntries);
  368. }
  369. // InstallerLoader implementation
  370. class FileExpanderSource {
  371. public:
  372. FileExpanderSource(const uint8 *data, int dataSize) : _dataPtr(data), _endofBuffer(data + dataSize), _bitsLeft(8), _key(0), _index(0) {}
  373. ~FileExpanderSource() {}
  374. void advSrcRefresh();
  375. void advSrcBitsBy1();
  376. void advSrcBitsByIndex(uint8 newIndex);
  377. uint8 getKeyLower() const { return _key & 0xFF; }
  378. void setIndex(uint8 index) { _index = index; }
  379. uint16 getKeyMasked(uint8 newIndex);
  380. uint16 keyMaskedAlign(uint16 val);
  381. void copyBytes(uint8 *& dst);
  382. private:
  383. const uint8 *_dataPtr;
  384. const uint8 *_endofBuffer;
  385. uint16 _key;
  386. int8 _bitsLeft;
  387. uint8 _index;
  388. };
  389. void FileExpanderSource::advSrcBitsBy1() {
  390. _key >>= 1;
  391. if (!--_bitsLeft) {
  392. if (_dataPtr < _endofBuffer)
  393. _key = ((*_dataPtr++) << 8) | (_key & 0xFF);
  394. _bitsLeft = 8;
  395. }
  396. }
  397. void FileExpanderSource::advSrcBitsByIndex(uint8 newIndex) {
  398. _index = newIndex;
  399. _bitsLeft -= _index;
  400. if (_bitsLeft <= 0) {
  401. _key >>= (_index + _bitsLeft);
  402. _index = -_bitsLeft;
  403. _bitsLeft = 8 - _index;
  404. if (_dataPtr < _endofBuffer)
  405. _key = (*_dataPtr++ << 8) | (_key & 0xFF);
  406. }
  407. _key >>= _index;
  408. }
  409. uint16 FileExpanderSource::getKeyMasked(uint8 newIndex) {
  410. static const uint8 mskTable[] = { 0x0F, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF };
  411. _index = newIndex;
  412. uint16 res = 0;
  413. if (_index > 8) {
  414. newIndex = _index - 8;
  415. res = (_key & 0xFF) & mskTable[8];
  416. advSrcBitsByIndex(8);
  417. _index = newIndex;
  418. res |= (((_key & 0xFF) & mskTable[_index]) << 8);
  419. advSrcBitsByIndex(_index);
  420. } else {
  421. res = (_key & 0xFF) & mskTable[_index];
  422. advSrcBitsByIndex(_index);
  423. }
  424. return res;
  425. }
  426. void FileExpanderSource::copyBytes(uint8 *& dst) {
  427. advSrcBitsByIndex(_bitsLeft);
  428. uint16 r = (READ_LE_UINT16(_dataPtr) ^ _key) + 1;
  429. _dataPtr += 2;
  430. if (r)
  431. error("decompression failure");
  432. memcpy(dst, _dataPtr, _key);
  433. _dataPtr += _key;
  434. dst += _key;
  435. }
  436. uint16 FileExpanderSource::keyMaskedAlign(uint16 val) {
  437. val -= 0x101;
  438. _index = (val & 0xFF) >> 2;
  439. int16 b = ((_bitsLeft << 8) | _index) - 1;
  440. _bitsLeft = b >> 8;
  441. _index = b & 0xFF;
  442. uint16 res = (((val & 3) + 4) << _index) + 0x101;
  443. return res + getKeyMasked(_index);
  444. }
  445. void FileExpanderSource::advSrcRefresh() {
  446. _key = READ_LE_UINT16(_dataPtr);
  447. if (_dataPtr < _endofBuffer - 1)
  448. _dataPtr += 2;
  449. _bitsLeft = 8;
  450. }
  451. class FileExpander {
  452. public:
  453. FileExpander();
  454. ~FileExpander();
  455. bool process(uint8 *dst, const uint8 *src, uint32 outsize, uint32 insize);
  456. private:
  457. void generateTables(uint8 srcIndex, uint8 dstIndex, uint8 dstIndex2, int cnt);
  458. uint8 calcCmdAndIndex(const uint8 *tbl, int16 &para);
  459. FileExpanderSource *_src;
  460. uint8 *_tables[9];
  461. uint16 *_tables16[3];
  462. };
  463. FileExpander::FileExpander() : _src(0) {
  464. _tables[0] = new uint8[3914];
  465. assert(_tables[0]);
  466. _tables[1] = _tables[0] + 320;
  467. _tables[2] = _tables[0] + 352;
  468. _tables[3] = _tables[0] + 864;
  469. _tables[4] = _tables[0] + 2016;
  470. _tables[5] = _tables[0] + 2528;
  471. _tables[6] = _tables[0] + 2656;
  472. _tables[7] = _tables[0] + 2736;
  473. _tables[8] = _tables[0] + 2756;
  474. _tables16[0] = (uint16 *)(_tables[0] + 3268);
  475. _tables16[1] = (uint16 *)(_tables[0] + 3302);
  476. _tables16[2] = (uint16 *)(_tables[0] + 3338);
  477. }
  478. FileExpander::~FileExpander() {
  479. delete _src;
  480. delete[] _tables[0];
  481. }
  482. bool FileExpander::process(uint8 *dst, const uint8 *src, uint32 outsize, uint32 compressedSize) {
  483. static const uint8 indexTable[] = {
  484. 0x10, 0x11, 0x12, 0x00, 0x08, 0x07, 0x09, 0x06, 0x0A,
  485. 0x05, 0x0B, 0x04, 0x0C, 0x03, 0x0D, 0x02, 0x0E, 0x01, 0x0F
  486. };
  487. memset(_tables[0], 0, 3914);
  488. uint8 *d = dst;
  489. uint16 tableSize0 = 0;
  490. uint16 tableSize1 = 0;
  491. bool needrefresh = true;
  492. bool postprocess = false;
  493. _src = new FileExpanderSource(src, compressedSize);
  494. while (d < dst + outsize) {
  495. if (needrefresh) {
  496. needrefresh = false;
  497. _src->advSrcRefresh();
  498. }
  499. _src->advSrcBitsBy1();
  500. int mode = _src->getKeyMasked(2) - 1;
  501. if (mode == 1) {
  502. tableSize0 = _src->getKeyMasked(5) + 257;
  503. tableSize1 = _src->getKeyMasked(5) + 1;
  504. memset(_tables[7], 0, 19);
  505. const uint8 *itbl = indexTable;
  506. int numbytes = _src->getKeyMasked(4) + 4;
  507. while (numbytes--)
  508. _tables[7][*itbl++] = _src->getKeyMasked(3);
  509. generateTables(7, 8, 255, 19);
  510. int cnt = tableSize0 + tableSize1;
  511. uint8 *tmp = _tables[0];
  512. while (cnt) {
  513. uint16 cmd = _src->getKeyLower();
  514. cmd = READ_LE_UINT16(&_tables[8][cmd << 1]);
  515. _src->advSrcBitsByIndex(_tables[7][cmd]);
  516. if (cmd < 16) {
  517. *tmp++ = cmd;
  518. cnt--;
  519. } else {
  520. uint8 tmpI = 0;
  521. if (cmd == 16) {
  522. cmd = _src->getKeyMasked(2) + 3;
  523. tmpI = *(tmp - 1);
  524. } else if (cmd == 17) {
  525. cmd = _src->getKeyMasked(3) + 3;
  526. } else {
  527. cmd = _src->getKeyMasked(7) + 11;
  528. }
  529. _src->setIndex(tmpI);
  530. memset(tmp, tmpI, cmd);
  531. tmp += cmd;
  532. cnt -= cmd;
  533. if (cnt < 0)
  534. error("decompression failure");
  535. }
  536. }
  537. memcpy(_tables[1], _tables[0] + tableSize0, tableSize1);
  538. generateTables(0, 2, 3, tableSize0);
  539. generateTables(1, 4, 5, tableSize1);
  540. postprocess = true;
  541. } else if (mode < 0) {
  542. _src->copyBytes(d);
  543. postprocess = false;
  544. needrefresh = true;
  545. } else if (mode == 0) {
  546. uint8 *d2 = _tables[0];
  547. memset(d2, 8, 144);
  548. memset(d2 + 144, 9, 112);
  549. memset(d2 + 256, 7, 24);
  550. memset(d2 + 280, 8, 8);
  551. d2 = _tables[1];
  552. memset(d2, 5, 32);
  553. tableSize0 = 288;
  554. tableSize1 = 32;
  555. generateTables(0, 2, 3, tableSize0);
  556. generateTables(1, 4, 5, tableSize1);
  557. postprocess = true;
  558. } else {
  559. error("decompression failure");
  560. }
  561. if (!postprocess)
  562. continue;
  563. int16 cmd = 0;
  564. do {
  565. cmd = ((int16 *)_tables[2])[_src->getKeyLower()];
  566. _src->advSrcBitsByIndex(cmd < 0 ? calcCmdAndIndex(_tables[3], cmd) : _tables[0][cmd]);
  567. if (cmd == 0x11D) {
  568. cmd = 0x200;
  569. } else if (cmd > 0x108) {
  570. cmd = _src->keyMaskedAlign(cmd);
  571. }
  572. if (!(cmd >> 8)) {
  573. *d++ = cmd & 0xFF;
  574. } else if (cmd != 0x100) {
  575. cmd -= 0xFE;
  576. int16 offset = ((int16 *)_tables[4])[_src->getKeyLower()];
  577. _src->advSrcBitsByIndex(offset < 0 ? calcCmdAndIndex(_tables[5], offset) : _tables[1][offset]);
  578. if ((offset & 0xFF) >= 4) {
  579. uint8 newIndex = ((offset & 0xFF) >> 1) - 1;
  580. offset = (((offset & 1) + 2) << newIndex);
  581. offset += _src->getKeyMasked(newIndex);
  582. }
  583. uint8 *s2 = d - 1 - offset;
  584. if (s2 >= dst) {
  585. while (cmd--)
  586. *d++ = *s2++;
  587. } else {
  588. uint32 pos = dst - s2;
  589. s2 += (d - dst);
  590. if (pos < (uint32) cmd) {
  591. cmd -= pos;
  592. while (pos--)
  593. *d++ = *s2++;
  594. s2 = dst;
  595. }
  596. while (cmd--)
  597. *d++ = *s2++;
  598. }
  599. }
  600. } while (cmd != 0x100);
  601. }
  602. delete _src;
  603. _src = 0;
  604. return true;
  605. }
  606. void FileExpander::generateTables(uint8 srcIndex, uint8 dstIndex, uint8 dstIndex2, int cnt) {
  607. uint8 *tbl1 = _tables[srcIndex];
  608. uint8 *tbl2 = _tables[dstIndex];
  609. uint8 *tbl3 = dstIndex2 == 0xFF ? 0 : _tables[dstIndex2];
  610. if (!cnt)
  611. return;
  612. const uint8 *s = tbl1;
  613. memset(_tables16[0], 0, 32);
  614. for (int i = 0; i < cnt; i++)
  615. _tables16[0][(*s++)]++;
  616. _tables16[1][1] = 0;
  617. for (uint16 i = 1, r = 0; i < 16; i++) {
  618. r = (r + _tables16[0][i]) << 1;
  619. _tables16[1][i + 1] = r;
  620. }
  621. if (_tables16[1][16]) {
  622. uint16 r = 0;
  623. for (uint16 i = 1; i < 16; i++)
  624. r += _tables16[0][i];
  625. if (r > 1)
  626. error("decompression failure");
  627. }
  628. s = tbl1;
  629. uint16 *d = _tables16[2];
  630. for (int i = 0; i < cnt; i++) {
  631. uint16 t = *s++;
  632. if (t) {
  633. _tables16[1][t]++;
  634. t = _tables16[1][t] - 1;
  635. }
  636. *d++ = t;
  637. }
  638. s = tbl1;
  639. d = _tables16[2];
  640. for (int i = 0; i < cnt; i++) {
  641. int8 t = ((int8)(*s++)) - 1;
  642. if (t > 0) {
  643. uint16 v1 = *d;
  644. uint16 v2 = 0;
  645. do {
  646. v2 = (v2 << 1) | (v1 & 1);
  647. v1 >>= 1;
  648. } while (--t && v1);
  649. t++;
  650. uint8 c1 = (v1 & 1);
  651. while (t--) {
  652. uint8 c2 = v2 >> 15;
  653. v2 = (v2 << 1) | c1;
  654. c1 = c2;
  655. };
  656. *d++ = v2;
  657. } else {
  658. d++;
  659. }
  660. }
  661. memset(tbl2, 0, 512);
  662. cnt--;
  663. s = tbl1 + cnt;
  664. d = &_tables16[2][cnt];
  665. uint16 *bt = (uint16 *)tbl3;
  666. uint16 inc = 0;
  667. uint16 cnt2 = 0;
  668. do {
  669. uint8 t = *s--;
  670. uint16 *s2 = (uint16 *)tbl2;
  671. if (t && t < 9) {
  672. inc = 1 << t;
  673. uint16 o = *d;
  674. do {
  675. s2[o] = cnt;
  676. o += inc;
  677. } while (!(o & 0xF00));
  678. } else if (t > 8) {
  679. if (!bt)
  680. error("decompression failure");
  681. t -= 8;
  682. uint8 shiftCnt = 1;
  683. uint8 v = (*d) >> 8;
  684. s2 = &((uint16 *)tbl2)[*d & 0xFF];
  685. do {
  686. if (!*s2) {
  687. *s2 = (uint16)(~cnt2);
  688. *(uint32 *)&bt[cnt2] = 0;
  689. cnt2 += 2;
  690. }
  691. s2 = &bt[(uint16)(~*s2)];
  692. if (v & shiftCnt)
  693. s2++;
  694. shiftCnt <<= 1;
  695. } while (--t);
  696. *s2 = cnt;
  697. }
  698. d--;
  699. } while (--cnt >= 0);
  700. }
  701. uint8 FileExpander::calcCmdAndIndex(const uint8 *tbl, int16 &para) {
  702. const uint16 *t = (const uint16 *)tbl;
  703. _src->advSrcBitsByIndex(8);
  704. uint8 newIndex = 0;
  705. uint16 v = _src->getKeyLower();
  706. do {
  707. newIndex++;
  708. para = t[((~para) & 0xFFFE) | (v & 1)];
  709. v >>= 1;
  710. } while (para < 0);
  711. return newIndex;
  712. }
  713. namespace {
  714. struct InsArchive {
  715. Common::String filename;
  716. uint32 firstFile;
  717. uint32 startOffset;
  718. uint32 lastFile;
  719. uint32 endOffset;
  720. uint32 totalSize;
  721. };
  722. } // end of anonymouse namespace
  723. class CmpVocDecoder {
  724. public:
  725. CmpVocDecoder();
  726. ~CmpVocDecoder();
  727. uint8 *process(uint8 *src, uint32 insize, uint32 *outsize, bool disposeInput = true);
  728. private:
  729. void decodeHelper(int p);
  730. int32 *_vtbl;
  731. int32 *_tbl1, *_p1, *_tbl2, *_p2, *_tbl3, *_p3, *_tbl4, *_p4, *_floatArray, *_stTbl;
  732. uint8 *_sndArray;
  733. };
  734. Common::Archive *InstallerLoader::load(Resource *owner, const Common::String &filename, const Common::String &extension, const uint8 containerOffset) {
  735. uint32 pos = 0;
  736. uint32 bytesleft = 0;
  737. bool startFile = true;
  738. Common::String filenameBase = filename;
  739. Common::String filenameTemp;
  740. char filenameExt[4];
  741. if (filenameBase.lastChar() != '.')
  742. filenameBase += '.';
  743. InsArchive newArchive;
  744. Common::List<InsArchive> archives;
  745. Common::SeekableReadStream *tmpFile = 0;
  746. for (int8 currentFile = 1; currentFile; currentFile++) {
  747. sprintf(filenameExt, extension.c_str(), currentFile);
  748. filenameTemp = filenameBase + Common::String(filenameExt);
  749. if (!(tmpFile = owner->createReadStream(filenameTemp))) {
  750. debug(3, "couldn't open file '%s'\n", filenameTemp.c_str());
  751. break;
  752. }
  753. tmpFile->seek(pos, SEEK_SET);
  754. uint8 fileId = tmpFile->readByte();
  755. pos++;
  756. uint32 size = tmpFile->size() - 1;
  757. if (startFile) {
  758. size -= 4;
  759. if (fileId == currentFile) {
  760. size -= containerOffset;
  761. pos += containerOffset;
  762. tmpFile->seek(containerOffset, SEEK_CUR);
  763. } else {
  764. size = size + 1 - pos;
  765. }
  766. newArchive.filename = filenameBase;
  767. bytesleft = newArchive.totalSize = tmpFile->readUint32LE();
  768. pos += 4;
  769. newArchive.firstFile = currentFile;
  770. newArchive.startOffset = pos;
  771. startFile = false;
  772. }
  773. uint32 cs = MIN(size, bytesleft);
  774. bytesleft -= cs;
  775. delete tmpFile;
  776. tmpFile = 0;
  777. pos += cs;
  778. if (cs == size) {
  779. if (!bytesleft) {
  780. newArchive.lastFile = currentFile;
  781. newArchive.endOffset = --pos;
  782. archives.push_back(newArchive);
  783. currentFile = -1;
  784. } else {
  785. pos = 0;
  786. }
  787. } else {
  788. startFile = true;
  789. bytesleft = size - cs;
  790. newArchive.lastFile = currentFile--;
  791. newArchive.endOffset = --pos;
  792. archives.push_back(newArchive);
  793. }
  794. }
  795. FileExpander exp;
  796. CmpVocDecoder cvdec;
  797. CachedArchive::InputEntry newEntry;
  798. uint32 insize = 0;
  799. uint32 outsize = 0;
  800. uint8 *inbuffer = 0;
  801. uint8 *outbuffer = 0;
  802. uint32 inPart1 = 0;
  803. uint32 inPart2 = 0;
  804. uint8 compressionType = 0;
  805. Common::String entryStr;
  806. CachedArchive::FileInputList fileList;
  807. pos = 0;
  808. const uint32 kExecSize = 0x0BBA;
  809. const uint32 kHeaderSize = 30;
  810. const uint32 kHeaderSize2 = 46;
  811. for (Common::List<InsArchive>::iterator a = archives.begin(); a != archives.end(); ++a) {
  812. startFile = true;
  813. for (uint32 i = a->firstFile; i != (a->lastFile + 1); i++) {
  814. sprintf(filenameExt, extension.c_str(), i);
  815. filenameTemp = a->filename + Common::String(filenameExt);
  816. if (!(tmpFile = owner->createReadStream(filenameTemp))) {
  817. debug(3, "couldn't open file '%s'\n", filenameTemp.c_str());
  818. break;
  819. }
  820. uint32 size = (i == a->lastFile) ? a->endOffset : tmpFile->size();
  821. if (startFile) {
  822. startFile = false;
  823. pos = a->startOffset + kExecSize;
  824. if (pos > size) {
  825. pos -= size;
  826. delete tmpFile;
  827. tmpFile = 0;
  828. continue;
  829. }
  830. } else {
  831. if (inPart2) {
  832. tmpFile->seek(1, SEEK_SET);
  833. tmpFile->read(inbuffer + inPart1, inPart2);
  834. inPart2 = 0;
  835. if (compressionType > 0)
  836. exp.process(outbuffer, inbuffer, outsize, insize);
  837. else
  838. memcpy(outbuffer, inbuffer, outsize);
  839. delete[] inbuffer;
  840. inbuffer = 0;
  841. newEntry.data = outbuffer;
  842. newEntry.size = outsize;
  843. newEntry.name = entryStr;
  844. entryStr.toUppercase();
  845. if (entryStr.hasSuffix(".CMP")) {
  846. entryStr.deleteLastChar();
  847. entryStr.deleteLastChar();
  848. entryStr.deleteLastChar();
  849. entryStr += "PAK";
  850. newEntry.data = cvdec.process(outbuffer, outsize, &outsize);
  851. newEntry.size = outsize;
  852. newEntry.name = entryStr;
  853. }
  854. fileList.push_back(newEntry);
  855. }
  856. pos++;
  857. }
  858. while (pos < size) {
  859. uint8 hdr[43];
  860. uint32 m = 0;
  861. tmpFile->seek(pos, SEEK_SET);
  862. if (pos + 42 > size) {
  863. m = size - pos;
  864. uint32 b = 42 - m;
  865. if (m >= 4) {
  866. uint32 id = tmpFile->readUint32LE();
  867. if (id == 0x06054B50) {
  868. startFile = true;
  869. break;
  870. } else {
  871. tmpFile->seek(pos, SEEK_SET);
  872. }
  873. }
  874. sprintf(filenameExt, extension.c_str(), i + 1);
  875. filenameTemp = a->filename + Common::String(filenameExt);
  876. Common::SeekableReadStream *tmpFile2 = owner->createReadStream(filenameTemp);
  877. tmpFile->read(hdr, m);
  878. tmpFile2->read(hdr + m, b);
  879. delete tmpFile2;
  880. } else {
  881. tmpFile->read(hdr, 42);
  882. }
  883. uint32 id = READ_LE_UINT32(hdr);
  884. if (id == 0x04034B50) {
  885. compressionType = hdr[8];
  886. insize = READ_LE_UINT32(hdr + 18);
  887. outsize = READ_LE_UINT32(hdr + 22);
  888. uint16 filestrlen = READ_LE_UINT16(hdr + 26);
  889. *(hdr + 30 + filestrlen) = 0;
  890. entryStr = Common::String((const char *)(hdr + 30));
  891. pos += (kHeaderSize + filestrlen - m);
  892. tmpFile->seek(pos, SEEK_SET);
  893. outbuffer = new uint8[outsize];
  894. if (!outbuffer)
  895. error("Out of memory: Can't uncompress installer files");
  896. if (!inbuffer) {
  897. inbuffer = new uint8[insize];
  898. if (!inbuffer)
  899. error("Out of memory: Can't uncompress installer files");
  900. }
  901. if ((pos + insize) > size) {
  902. // this is for files that are split between two archive files
  903. inPart1 = size - pos;
  904. inPart2 = insize - inPart1;
  905. tmpFile->read(inbuffer, inPart1);
  906. } else {
  907. tmpFile->read(inbuffer, insize);
  908. inPart2 = 0;
  909. if (compressionType > 0)
  910. exp.process(outbuffer, inbuffer, outsize, insize);
  911. else
  912. memcpy(outbuffer, inbuffer, outsize);
  913. delete[] inbuffer;
  914. inbuffer = 0;
  915. newEntry.data = outbuffer;
  916. newEntry.size = outsize;
  917. newEntry.name = entryStr;
  918. entryStr.toUppercase();
  919. if (entryStr.hasSuffix(".CMP")) {
  920. entryStr.deleteLastChar();
  921. entryStr.deleteLastChar();
  922. entryStr.deleteLastChar();
  923. entryStr += "PAK";
  924. newEntry.data = cvdec.process(outbuffer, outsize, &outsize);
  925. newEntry.size = outsize;
  926. newEntry.name = entryStr;
  927. }
  928. fileList.push_back(newEntry);
  929. }
  930. pos += insize;
  931. if (pos > size) {
  932. pos -= size;
  933. break;
  934. }
  935. } else {
  936. uint32 filestrlen = READ_LE_UINT32(hdr + 28);
  937. pos += (kHeaderSize2 + filestrlen - m);
  938. }
  939. }
  940. delete tmpFile;
  941. tmpFile = 0;
  942. }
  943. }
  944. archives.clear();
  945. return new CachedArchive(fileList);
  946. }
  947. CmpVocDecoder::CmpVocDecoder() {
  948. _tbl1 = new int32[4000];
  949. _p1 = _tbl1 + 2000;
  950. _tbl2 = new int32[4000];
  951. _p2 = _tbl2 + 2000;
  952. _tbl3 = new int32[4000];
  953. _p3 = _tbl3 + 2000;
  954. _tbl4 = new int32[4000];
  955. _p4 = _tbl4 + 2000;
  956. _vtbl = new int32[8193];
  957. _floatArray = new int32[8193];
  958. _sndArray = new uint8[8192];
  959. _stTbl = new int32[256];
  960. assert(_tbl1);
  961. assert(_tbl2);
  962. assert(_tbl3);
  963. assert(_tbl4);
  964. assert(_vtbl);
  965. assert(_floatArray);
  966. assert(_sndArray);
  967. assert(_stTbl);
  968. for (int32 i = -2000; i < 2000; i++) {
  969. int32 x = i + 2000;
  970. _tbl1[x] = (int32)(0.4829629131445341 * (double)i * 256.0);
  971. _tbl2[x] = (int32)(0.8365163037378079 * (double)i * 256.0);
  972. _tbl3[x] = (int32)(0.2241438680420134 * (double)i * 256.0);
  973. _tbl4[x] = (int32)(-0.1294095225512604 * (double)i * 256.0);
  974. }
  975. }
  976. CmpVocDecoder::~CmpVocDecoder() {
  977. delete[] _stTbl;
  978. delete[] _sndArray;
  979. delete[] _floatArray;
  980. delete[] _vtbl;
  981. delete[] _tbl1;
  982. delete[] _tbl2;
  983. delete[] _tbl3;
  984. delete[] _tbl4;
  985. }
  986. uint8 *CmpVocDecoder::process(uint8 *src, uint32 insize, uint32 *outsize, bool disposeInput) {
  987. *outsize = 0;
  988. uint8 *outTemp = new uint8[insize];
  989. uint8 *inPosH = src;
  990. uint8 *outPosH = outTemp;
  991. uint8 *outPosD = outTemp + READ_LE_UINT32(src);
  992. uint8 *end = outPosD;
  993. while (outPosH < end) {
  994. uint8 *spos = inPosH;
  995. uint32 offset = READ_LE_UINT32(inPosH);
  996. inPosH += 4;
  997. char *name = (char *)inPosH;
  998. inPosH += strlen(name) + 1;
  999. if (!name[0]) {
  1000. *outsize = outPosD - outTemp;
  1001. WRITE_LE_UINT32(outPosH, *outsize);
  1002. memset(outPosH + 4, 0, 5);
  1003. break;
  1004. }
  1005. uint32 fileSize = READ_LE_UINT32(inPosH) - offset;
  1006. int headerEntryLen = inPosH - spos;
  1007. if (scumm_stricmp(name + strlen(name) - 4, ".voc")) {
  1008. memcpy(outPosH, spos, headerEntryLen);
  1009. WRITE_LE_UINT32(outPosH, outPosD - outTemp);
  1010. outPosH += headerEntryLen;
  1011. memcpy(outPosD, src + offset, fileSize);
  1012. outPosD += fileSize;
  1013. continue;
  1014. }
  1015. uint8 *vocPtr = src + offset;
  1016. uint32 vocLen = (vocPtr[27] | (vocPtr[28] << 8) | (vocPtr[29] << 16)) - 2;
  1017. uint8 *vocOutEnd = outPosD + vocLen + 32;
  1018. uint8 *vocInEnd = src + offset + fileSize;
  1019. memcpy(outPosD, vocPtr, 32);
  1020. uint8 *dst = outPosD + 32;
  1021. vocPtr += 32;
  1022. float t = 0.0f;
  1023. while (dst < vocOutEnd) {
  1024. memcpy(&t, vocPtr, 4);
  1025. vocPtr += 4;
  1026. uint32 readSize = MIN<uint32>(8192, vocInEnd - vocPtr);
  1027. memcpy(_sndArray, vocPtr, readSize);
  1028. vocPtr += readSize;
  1029. for (int i = -128; i < 128; i++)
  1030. _stTbl[i + 128] = (int32)((float)i / t + 0.5f);
  1031. int8 *ps = (int8 *)_sndArray;
  1032. for (int i = 0; i < 8192; i++)
  1033. _floatArray[i + 1] = _stTbl[128 + *ps++];
  1034. for (int i = 4; i <= 8192; i <<= 1)
  1035. decodeHelper(i);
  1036. for (int i = 1; i <= 8192; i++) {
  1037. int32 v = CLIP<int32>(_floatArray[i] + 128, 0, 255);
  1038. _sndArray[i - 1] = v;
  1039. }
  1040. uint32 numBytesOut = MIN<uint32>(vocOutEnd - dst, 8192);
  1041. memcpy(dst, _sndArray, numBytesOut);
  1042. dst += numBytesOut;
  1043. }
  1044. *dst++ = 0;
  1045. memcpy(outPosH, spos, headerEntryLen);
  1046. WRITE_LE_UINT32(outPosH, outPosD - outTemp);
  1047. outPosH += headerEntryLen;
  1048. outPosD += (vocLen + 33);
  1049. }
  1050. if (disposeInput)
  1051. delete[] src;
  1052. uint8 *outFinal = new uint8[*outsize];
  1053. memcpy(outFinal, outTemp, *outsize);
  1054. delete[] outTemp;
  1055. return outFinal;
  1056. }
  1057. void CmpVocDecoder::decodeHelper(int p1) {
  1058. int p2 = p1 >> 1;
  1059. int p3 = p2 + 1;
  1060. int16 fi1 = _floatArray[1];
  1061. int16 fi2 = _floatArray[p2];
  1062. int16 fi3 = _floatArray[p3];
  1063. int16 fi4 = _floatArray[p1];
  1064. _vtbl[1] = (*(_p3 + fi2) + *(_p2 + fi4) + *(_p1 + fi1) + *(_p4 + fi3)) >> 8;
  1065. _vtbl[2] = (*(_p4 + fi2) - *(_p1 + fi4) + *(_p2 + fi1) - *(_p3 + fi3)) >> 8;
  1066. int d = 3;
  1067. int s = 1;
  1068. while (s < p2) {
  1069. fi2 = _floatArray[s];
  1070. fi1 = _floatArray[s + 1];
  1071. fi4 = _floatArray[s + p2];
  1072. fi3 = _floatArray[s + p3];
  1073. _vtbl[d++] = (*(_p3 + fi2) + *(_p2 + fi4) + *(_p1 + fi1) + *(_p4 + fi3)) >> 8;
  1074. _vtbl[d++] = (*(_p4 + fi2) - *(_p1 + fi4) + *(_p2 + fi1) - *(_p3 + fi3)) >> 8;
  1075. s++;
  1076. }
  1077. memcpy(&_floatArray[1], &_vtbl[1], p1 * sizeof(int32));
  1078. }
  1079. } // End of namespace Kyra