ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

lab.cpp

Go to the documentation of this file.
00001 /* ResidualVM - A 3D game interpreter
00002  *
00003  * ResidualVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the COPYRIGHT
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 #include "common/file.h"
00024 #include "common/substream.h"
00025 #include "common/memstream.h"
00026 
00027 #include "engines/grim/grim.h"
00028 #include "engines/grim/lab.h"
00029 
00030 namespace Grim {
00031 
00032 LabEntry::LabEntry(const Common::String &name, uint32 offset, uint32 len, Lab *parent) :
00033         _offset(offset), _len(len), _parent(parent), _name(name) {
00034     _name.toLowercase();
00035 }
00036 
00037 Common::SeekableReadStream *LabEntry::createReadStream() const {
00038     return _parent->createReadStreamForMember(_name);
00039 }
00040 
00041 Lab::Lab() {
00042     _stream = nullptr;
00043 }
00044 
00045 Lab::~Lab() {
00046     delete _stream;
00047 }
00048 
00049 bool Lab::open(const Common::String &filename, bool keepStream) {
00050     _labFileName = filename;
00051 
00052     bool result = true;
00053 
00054     Common::File *file = new Common::File();
00055     if (!file->open(filename) || file->readUint32BE() != MKTAG('L','A','B','N')) {
00056         result = false;
00057     } else {
00058         file->readUint32LE(); // version
00059 
00060         if (g_grim->getGameType() == GType_GRIM)
00061             parseGrimFileTable(file);
00062         else
00063             parseMonkey4FileTable(file);
00064     }
00065     if (result && keepStream) {
00066         file->seek(0, SEEK_SET);
00067         byte *data = static_cast<byte*>(malloc(sizeof(byte) * file->size()));
00068         file->read(data, file->size());
00069         _stream = new Common::MemoryReadStream(data, file->size(), DisposeAfterUse::YES);
00070     }
00071     delete file;
00072 
00073     return result;
00074 }
00075 
00076 void Lab::parseGrimFileTable(Common::File *file) {
00077     uint32 entryCount = file->readUint32LE();
00078     uint32 stringTableSize = file->readUint32LE();
00079 
00080     char *stringTable = new char[stringTableSize];
00081     file->seek(16 * (entryCount + 1));
00082     file->read(stringTable, stringTableSize);
00083     file->seek(16);
00084 
00085     int32 filesize = file->size();
00086 
00087     for (uint32 i = 0; i < entryCount; i++) {
00088         int fnameOffset = file->readUint32LE();
00089         int start = file->readUint32LE();
00090         int size = file->readUint32LE();
00091         file->readUint32LE();
00092 
00093         Common::String fname = stringTable + fnameOffset;
00094         fname.toLowercase();
00095 
00096         if (start + size > filesize)
00097             error("File \"%s\" past the end of lab \"%s\". Your game files may be corrupt.", fname.c_str(), _labFileName.c_str());
00098 
00099         LabEntry *entry = new LabEntry(fname, start, size, this);
00100         _entries[fname] = LabEntryPtr(entry);
00101     }
00102 
00103     delete[] stringTable;
00104 }
00105 
00106 void Lab::parseMonkey4FileTable(Common::File *file) {
00107     uint32 entryCount = file->readUint32LE();
00108     uint32 stringTableSize = file->readUint32LE();
00109     uint32 stringTableOffset = file->readUint32LE() - 0x13d0f;
00110 
00111     char *stringTable = new char[stringTableSize];
00112     file->seek(stringTableOffset);
00113     file->read(stringTable, stringTableSize);
00114     file->seek(20);
00115 
00116     int32 filesize = file->size();
00117 
00118     // Decrypt the string table
00119     for (uint32 i = 0; i < stringTableSize; i++)
00120         if (stringTable[i] != 0)
00121             stringTable[i] ^= 0x96;
00122 
00123     for (uint32 i = 0; i < entryCount; i++) {
00124         int fnameOffset = file->readUint32LE();
00125         int start = file->readUint32LE();
00126         int size = file->readUint32LE();
00127         file->readUint32LE();
00128 
00129         char *str = stringTable + fnameOffset;
00130         int len = strlen(str);
00131 
00132         for (int l = 0; l < len; ++l) {
00133             if (str[l] == '\\')
00134                 str[l] = '/';
00135         }
00136         Common::String fname = str;
00137         fname.toLowercase();
00138 
00139         if (start + size > filesize)
00140             error("File \"%s\" past the end of lab \"%s\". Your game files may be corrupt.", fname.c_str(), _labFileName.c_str());
00141 
00142         LabEntry *entry = new LabEntry(fname, start, size, this);
00143         _entries[fname] = LabEntryPtr(entry);
00144     }
00145 
00146     delete[] stringTable;
00147 }
00148 
00149 bool Lab::hasFile(const Common::String &filename) const {
00150     Common::String fname(filename);
00151     fname.toLowercase();
00152     return _entries.contains(fname);
00153 }
00154 
00155 int Lab::listMembers(Common::ArchiveMemberList &list) const {
00156     int count = 0;
00157 
00158     for (LabMap::const_iterator i = _entries.begin(); i != _entries.end(); ++i) {
00159         list.push_back(Common::ArchiveMemberList::value_type(i->_value));
00160         ++count;
00161     }
00162 
00163     return count;
00164 }
00165 
00166 const Common::ArchiveMemberPtr Lab::getMember(const Common::String &name) const {
00167     if (!hasFile(name))
00168         return Common::ArchiveMemberPtr();
00169 
00170     Common::String fname(name);
00171     fname.toLowercase();
00172     return _entries[fname];
00173 }
00174 
00175 Common::SeekableReadStream *Lab::createReadStreamForMember(const Common::String &filename) const {
00176     if (!hasFile(filename))
00177         return nullptr;
00178 
00179     Common::String fname(filename);
00180     fname.toLowercase();
00181     LabEntryPtr i = _entries[fname];
00182 
00183     if (!_stream) {
00184         Common::File *file = new Common::File();
00185         file->open(_labFileName);
00186         return new Common::SeekableSubReadStream(file, i->_offset, i->_offset + i->_len, DisposeAfterUse::YES);
00187     } else {
00188         byte *data = static_cast<byte*>(malloc(sizeof(byte) * i->_len));
00189         _stream->seek(i->_offset, SEEK_SET);
00190         _stream->read(data, i->_len);
00191         return new Common::MemoryReadStream(data, i->_len, DisposeAfterUse::YES);
00192     }
00193 }
00194 
00195 } // end of namespace Grim


Generated on Sat Oct 19 2019 05:01:03 for ResidualVM by doxygen 1.7.1
curved edge   curved edge