aboutsummaryrefslogtreecommitdiff
path: root/engines/groovie/resource.cpp
blob: 75eba95240050defbaaa98ce1bb3aa0772f63e0a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
/* 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.
 *
 */

#include "common/archive.h"
#include "common/debug.h"
#include "common/file.h"
#include "common/macresman.h"
#include "common/substream.h"
#include "common/textconsole.h"

#include "groovie/resource.h"
#include "groovie/groovie.h"

namespace Groovie {

// ResMan

Common::SeekableReadStream *ResMan::open(uint32 fileRef) {
	// Get the information about the resource
	ResInfo resInfo;
	if (!getResInfo(fileRef, resInfo)) {
		return NULL;
	}

	// Do we know the name of the required GJD?
	if (resInfo.gjd >= _gjds.size()) {
		error("Groovie::Resource: Unknown GJD %d", resInfo.gjd);
		return NULL;
	}

	debugC(1, kDebugResource, "Groovie::Resource: Opening resource 0x%04X (%s, %d, %d)", fileRef, _gjds[resInfo.gjd].c_str(), resInfo.offset, resInfo.size);

	// Does it exist?
	if (!Common::File::exists(_gjds[resInfo.gjd])) {
		error("Groovie::Resource: %s not found", _gjds[resInfo.gjd].c_str());
		return NULL;
	}

	// Open the pack file
	Common::File *gjdFile = new Common::File();
	if (!gjdFile->open(_gjds[resInfo.gjd].c_str())) {
		delete gjdFile;
		error("Groovie::Resource: Couldn't open %s", _gjds[resInfo.gjd].c_str());
		return NULL;
	}

	// Save the used gjd file (except xmi and gamwav)
	if (resInfo.gjd < 19) {
		_lastGjd = resInfo.gjd;
	}

	// Returning the resource substream
	return new Common::SeekableSubReadStream(gjdFile, resInfo.offset, resInfo.offset + resInfo.size, DisposeAfterUse::YES);
}


// ResMan_t7g

static const char t7g_gjds[][0x15] = {"at", "b", "ch", "d", "dr", "fh", "ga", "hdisk", "htbd", "intro", "jhek", "k", "la", "li", "mb", "mc", "mu", "n", "p", "xmi", "gamwav"};

ResMan_t7g::ResMan_t7g(Common::MacResManager *macResFork) : _macResFork(macResFork) {
	for (int i = 0; i < 0x15; i++) {
		// Prepare the filename
		Common::String filename = t7g_gjds[i];
		filename += ".gjd";

		// Handle the special case of Mac's hdisk.gjd
		if (_macResFork && i == 7)
			filename = "T7GData";

		// Append it to the list of GJD files
		_gjds.push_back(filename);
	}
}

uint32 ResMan_t7g::getRef(Common::String name, Common::String scriptname) {
	// Get the name of the RL file
	Common::String rlFileName(t7g_gjds[_lastGjd]);
	rlFileName += ".rl";

	Common::SeekableReadStream *rlFile = 0;

	if (_macResFork) {
		// Open the RL file from the resource fork
		rlFile = _macResFork->getResource(rlFileName);
	} else {
		// Open the RL file
		rlFile = SearchMan.createReadStreamForMember(rlFileName);
	}

	if (!rlFile)
		error("Groovie::Resource: Couldn't open %s", rlFileName.c_str());

	uint32 resNum;
	bool found = false;
	for (resNum = 0; !found && !rlFile->err() && !rlFile->eos(); resNum++) {
		// Read the resource name
		char readname[12];
		rlFile->read(readname, 12);

		// Test whether it's the resource we're searching
		Common::String resname(readname, 12);
		if (resname.hasPrefix(name.c_str())) {
			debugC(2, kDebugResource, "Groovie::Resource: Resource %12s matches %s", readname, name.c_str());
			found = true;
		}

		// Skip the rest of resource information
		rlFile->read(readname, 8);
	}

	// Close the RL file
	delete rlFile;

	// Verify we really found the resource
	if (!found) {
		error("Groovie::Resource: Couldn't find resource %s in %s", name.c_str(), rlFileName.c_str());
		return (uint32)-1;
	}

	return (_lastGjd << 10) | (resNum - 1);
}

bool ResMan_t7g::getResInfo(uint32 fileRef, ResInfo &resInfo) {
	// Calculate the GJD and the resource number
	resInfo.gjd = fileRef >> 10;
	uint16 resNum = fileRef & 0x3FF;

	// Get the name of the RL file
	Common::String rlFileName(t7g_gjds[resInfo.gjd]);
	rlFileName += ".rl";

	Common::SeekableReadStream *rlFile = 0;

	if (_macResFork) {
		// Open the RL file from the resource fork
		rlFile = _macResFork->getResource(rlFileName);
	} else {
		// Open the RL file
		rlFile = SearchMan.createReadStreamForMember(rlFileName);
	}

	if (!rlFile)
		error("Groovie::Resource: Couldn't open %s", rlFileName.c_str());

	// Seek to the position of the desired resource
	rlFile->seek(resNum * 20);
	if (rlFile->eos()) {
		delete rlFile;
		error("Groovie::Resource: Invalid resource number: 0x%04X (%s)", resNum, rlFileName.c_str());
	}

	// Read the resource name
	char resname[13];
	rlFile->read(resname, 12);
	resname[12] = 0;
	debugC(2, kDebugResource, "Groovie::Resource: Resource name: %12s", resname);
	resInfo.filename = resname;

	// Read the resource information
	resInfo.offset = rlFile->readUint32LE();
	resInfo.size = rlFile->readUint32LE();

	// Close the resource RL file
	delete rlFile;

	return true;
}


// ResMan_v2

ResMan_v2::ResMan_v2() {
	Common::File indexfile;

	// Open the GJD index file
	if (!indexfile.open("gjd.gjd")) {
		error("Groovie::Resource: Couldn't open gjd.gjd");
		return;
	}

	Common::String line = indexfile.readLine();
	while (!indexfile.eos() && !line.empty()) {
		// Get the name before the space
		Common::String filename;
		for (const char *cur = line.c_str(); *cur != ' '; cur++) {
			filename += *cur;
		}

		// Append it to the list of GJD files
		if (!filename.empty()) {
			_gjds.push_back(filename);
		}

		// Read the next line
		line = indexfile.readLine();
	}

	// Close the GJD index file
	indexfile.close();
}

uint32 ResMan_v2::getRef(Common::String name, Common::String scriptname) {
	// Open the RL file
	Common::File rlFile;
	if (!rlFile.open("dir.rl")) {
		error("Groovie::Resource: Couldn't open dir.rl");
		return false;
	}

	uint32 resNum;
	bool found = false;
	for (resNum = 0; !found && !rlFile.err() && !rlFile.eos(); resNum++) {
		// Seek past metadata
		rlFile.seek(14, SEEK_CUR);

		// Read the resource name
		char readname[18];
		rlFile.read(readname, 18);

		// Test whether it's the resource we're searching
		Common::String resname(readname, 18);
		if (resname.hasPrefix(name.c_str())) {
			debugC(2, kDebugResource, "Groovie::Resource: Resource %18s matches %s", readname, name.c_str());
			found = true;
			break;
		}
	}

	// Close the RL file
	rlFile.close();

	// Verify we really found the resource
	if (!found) {
		error("Groovie::Resource: Couldn't find resource %s", name.c_str());
		return (uint32)-1;
	}

	return resNum;
}

bool ResMan_v2::getResInfo(uint32 fileRef, ResInfo &resInfo) {
	// Open the RL file
	Common::File rlFile;
	if (!rlFile.open("dir.rl")) {
		error("Groovie::Resource: Couldn't open dir.rl");
		return false;
	}

	// Seek to the position of the desired resource
	rlFile.seek(fileRef * 32);
	if (rlFile.eos()) {
		rlFile.close();
		error("Groovie::Resource: Invalid resource number: 0x%04X", fileRef);
		return false;
	}

	// Read the resource information
	rlFile.readUint32LE(); // Unknown
	resInfo.offset = rlFile.readUint32LE();
	resInfo.size = rlFile.readUint32LE();
	resInfo.gjd = rlFile.readUint16LE();

	// Read the resource name
	char resname[19];
	resname[18] = 0;
	rlFile.read(resname, 18);
	debugC(2, kDebugResource, "Groovie::Resource: Resource name: %18s", resname);
	resInfo.filename = resname;

	// 6 padding bytes? (it looks like they're always 0)

	// Close the resource RL file
	rlFile.close();

	return true;
}

} // End of Groovie namespace