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 
23 #include "common/substream.h"
24 #include "access/files.h"
25 #include "access/amazon/amazon_resources.h"
26 #include "access/martian/martian_resources.h"
27 #include "access/access.h"
28 
29 namespace Access {
30 
FileIdent()31 FileIdent::FileIdent() {
32 	_fileNum = -1;
33 	_subfile = 0;
34 }
35 
load(Common::SeekableReadStream & s)36 void FileIdent::load(Common::SeekableReadStream &s) {
37 	_fileNum = s.readSint16LE();
38 	_subfile = s.readUint16LE();
39 }
40 
41 /*------------------------------------------------------------------------*/
42 
CellIdent()43 CellIdent::	CellIdent() {
44 	_cell = 0;
45 }
46 
CellIdent(int cell,int fileNum,int subfile)47 CellIdent::CellIdent(int cell, int fileNum, int subfile) {
48 	_cell = cell;
49 	_fileNum = fileNum;
50 	_subfile = subfile;
51 }
52 
53 /*------------------------------------------------------------------------*/
54 
Resource()55 Resource::Resource() {
56 	_stream = nullptr;
57 	_size = 0;
58 	_data = nullptr;
59 }
60 
~Resource()61 Resource::~Resource() {
62 	delete[] _data;
63 	delete _stream;
64 }
65 
Resource(byte * p,int size)66 Resource::Resource(byte *p, int size) {
67 	_data = p;
68 	_size = size;
69 	_stream = new Common::MemoryReadStream(p, size);
70 }
71 
data()72 byte *Resource::data() {
73 	if (_data == nullptr) {
74 		_data = new byte[_size];
75 		int pos = _stream->pos();
76 		_stream->seek(0);
77 		_stream->read(_data, _size);
78 		_stream->seek(pos);
79 	}
80 
81 	return _data;
82 }
83 
84 /*------------------------------------------------------------------------*/
85 
FileManager(AccessEngine * vm)86 FileManager::FileManager(AccessEngine *vm) : _vm(vm) {
87 	_fileNumber = -1;
88 	_setPaletteFlag = true;
89 }
90 
~FileManager()91 FileManager::~FileManager() {
92 }
93 
loadFile(int fileNum,int subfile)94 Resource *FileManager::loadFile(int fileNum, int subfile) {
95 	Resource *res = new Resource();
96 	setAppended(res, fileNum);
97 	gotoAppended(res, subfile);
98 
99 	handleFile(res);
100 	return res;
101 }
102 
loadFile(const FileIdent & fileIdent)103 Resource *FileManager::loadFile(const FileIdent &fileIdent) {
104 	return loadFile(fileIdent._fileNum, fileIdent._subfile);
105 }
106 
loadFile(const Common::String & filename)107 Resource *FileManager::loadFile(const Common::String &filename) {
108 	Resource *res = new Resource();
109 
110 	// Open the file
111 	openFile(res, filename);
112 
113 	// Set up stream for the entire file
114 	res->_size = res->_file.size();
115 	res->_stream = res->_file.readStream(res->_size);
116 
117 	handleFile(res);
118 	return res;
119 }
120 
existFile(const Common::String & filename)121 bool FileManager::existFile(const Common::String &filename) {
122 	Common::File f;
123 	return f.exists(filename);
124 }
125 
openFile(Resource * res,const Common::String & filename)126 void FileManager::openFile(Resource *res, const Common::String &filename) {
127 	// Open up the file
128 	_fileNumber = -1;
129 	if (!res->_file.open(filename))
130 		error("Could not open file - %s", filename.c_str());
131 }
132 
loadScreen(Graphics::ManagedSurface * dest,int fileNum,int subfile)133 void FileManager::loadScreen(Graphics::ManagedSurface *dest, int fileNum, int subfile) {
134 	Resource *res = loadFile(fileNum, subfile);
135 	handleScreen(dest, res);
136 	delete res;
137 }
138 
handleScreen(Graphics::ManagedSurface * dest,Resource * res)139 void FileManager::handleScreen(Graphics::ManagedSurface *dest, Resource *res) {
140 	_vm->_screen->loadRawPalette(res->_stream);
141 	if (_setPaletteFlag)
142 		_vm->_screen->setPalette();
143 	_setPaletteFlag = true;
144 
145 	// The remainder of the file after the palette may be separately compressed,
146 	// so call handleFile to handle it if it is
147 	res->_size -= res->_stream->pos();
148 	handleFile(res);
149 
150 	Graphics::Surface destSurface = dest->getSubArea(Common::Rect(0, 0,
151 		_vm->_screen->w, _vm->_screen->h));
152 
153 	if (destSurface.w == destSurface.pitch) {
154 		res->_stream->read((byte *)destSurface.getPixels(), destSurface.w * destSurface.h);
155 	} else {
156 		for (int y = 0; y < destSurface.h; ++y) {
157 			byte *pDest = (byte *)destSurface.getBasePtr(0, y);
158 			res->_stream->read(pDest, destSurface.w);
159 		}
160 	}
161 }
162 
loadScreen(int fileNum,int subfile)163 void FileManager::loadScreen(int fileNum, int subfile) {
164 	loadScreen(_vm->_screen, fileNum, subfile);
165 }
166 
loadScreen(const Common::String & filename)167 void FileManager::loadScreen(const Common::String &filename) {
168 	Resource *res = loadFile(filename);
169 	handleScreen(_vm->_screen, res);
170 	delete res;
171 }
172 
handleFile(Resource * res)173 void FileManager::handleFile(Resource *res) {
174 	char header[3];
175 	res->_stream->read(&header[0], 3);
176 	res->_stream->seek(-3, SEEK_CUR);
177 
178 	bool isCompressed = !strncmp(header, "DBE", 3);
179 
180 	// If the data is compressed, uncompress it and replace the stream
181 	// in the resource with the decompressed one
182 	if (isCompressed) {
183 		// Read in the entire compressed data
184 		byte *src = new byte[res->_size];
185 		res->_stream->read(src, res->_size);
186 
187 		// Decompress the data
188 		res->_size = decompressDBE(src, &res->_data);
189 
190 		// Replace the default resource stream with a stream for the decompressed data
191 		delete res->_stream;
192 		res->_file.close();
193 		res->_stream = new Common::MemoryReadStream(res->_data, res->_size);
194 
195 		delete[] src;
196 	}
197 }
198 
setAppended(Resource * res,int fileNum)199 void FileManager::setAppended(Resource *res, int fileNum) {
200 	// Open the file for access
201 	if (!res->_file.open(_vm->_res->FILENAMES[fileNum]))
202 		error("Could not open file %s", _vm->_res->FILENAMES[fileNum].c_str());
203 
204 	// If a different file has been opened then previously, load its index
205 	if (_fileNumber != fileNum) {
206 		_fileNumber = fileNum;
207 
208 		// Read in the file index
209 		int count = res->_file.readUint16LE();
210 		assert(count <= 100);
211 		_fileIndex.resize(count);
212 		for (int i = 0; i < count; ++i)
213 			_fileIndex[i] = res->_file.readUint32LE();
214 	}
215 }
216 
gotoAppended(Resource * res,int subfile)217 void FileManager::gotoAppended(Resource *res, int subfile) {
218 	uint32 offset = _fileIndex[subfile];
219 	uint32 size = (subfile == (int)_fileIndex.size() - 1) ? res->_file.size() - offset :
220 		_fileIndex[subfile + 1] - offset;
221 
222 	res->_size = size;
223 	res->_stream = new Common::SeekableSubReadStream(&res->_file, offset, offset + size);
224 }
225 
226 } // End of namespace Access
227