aboutsummaryrefslogtreecommitdiff
path: root/engines/lure/disk.cpp
blob: e996ff6eccd024260accdb85b1f4a40d07148bb6 (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
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2005-2006 The ScummVM project
 *
 * 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.
 *
 * $URL$
 * $Id$
 *
 */

#include "common/stdafx.h"
#include "common/file.h"
#include "common/util.h"
#include "common/scummsys.h"

#include "lure/disk.h"
#include "lure/luredefs.h"

namespace Lure {

static Disk *int_disk = NULL;

Disk &Disk::getReference() {
	return *int_disk;
}

Disk::Disk(const Common::String &gameDataPath) {
	_gameDataPath = gameDataPath;
	_fileNum = 0xff;
	_fileHandle = NULL;
	int_disk = this;
}

Disk::~Disk() {
	if (_fileHandle) delete _fileHandle;
	int_disk = NULL;
}

uint8 Disk::indexOf(uint16 id, bool suppressError) {
	// Make sure the correct file is open - the upper two bits of the Id give the file number. Note
	// that an extra check is done for the upper byte of the Id being 0x3f, which is the Id range
	// I use for lure.dat resources, which are resources extracted from the lure.exe executable
	uint8 entryFileNum = ((id>>8) == 0x3f) ? 0 : ((id >> 14) & 3) + 1;
	openFile(entryFileNum);

	// Find the correct entry in the list based on the Id
	for (int entryIndex=0; entryIndex<NUM_ENTRIES_IN_HEADER; ++entryIndex) {
		if (_entries[entryIndex].id == HEADER_ENTRY_UNUSED_ID) break;
		else if (_entries[entryIndex].id == id) return entryIndex;
	}
	
	if (suppressError) return 0xff;
	error("Could not find entry Id #%d in file %sdisk%d.vga", id, _gameDataPath.c_str(), _fileNum);
}

void Disk::openFile(uint8 fileNum) {
	// Validate that the file number is correct
	if (fileNum > 4)
		error("Invalid file number specified - %d", fileNum);

	// Only load up the new file if the current file number has changed
	if (fileNum == _fileNum) return;
	
	// Delete any existing open file handle
	if (_fileNum != 0xff) delete _fileHandle;		
	_fileNum = fileNum;
	
	// Open up the the new file
	_fileHandle = new Common::File();

	char sFilename[10];
	if (_fileNum == 0) 
		strcpy(sFilename, SUPPORT_FILENAME);
	else
		sprintf(sFilename, "disk%d.vga", _fileNum);

	_fileHandle->open(sFilename);
	if (!_fileHandle->isOpen())
		error("Could not open %s%s", _gameDataPath.c_str(), sFilename);

	// Validate the header
	char buffer[7];
	uint32 bytesRead;

	bytesRead = _fileHandle->read(buffer, 6);
	buffer[6] = '\0';
	if (strcmp(buffer, HEADER_IDENT_STRING) != 0)
		error("The file %s%s was not a valid VGA file", _gameDataPath.c_str(), sFilename);

	uint16 fileFileNum = _fileHandle->readUint16BE();
	if (fileFileNum != _fileNum)
		error("The file %s%s was not the correct file number", _gameDataPath.c_str(), sFilename);

	// Read in the header entries
	uint32 headerSize = sizeof(FileEntry) * NUM_ENTRIES_IN_HEADER;
	if (_fileHandle->read(_entries, headerSize) != headerSize)
		error("The file %s%s had a corrupted header", _gameDataPath.c_str(), sFilename);

#ifdef SCUMM_BIG_ENDIAN
	// Process the read in header list to convert to big endian
	for (int i = 0; i < NUM_ENTRIES_IN_HEADER; ++i) {
		_entries[i].id = FROM_LE_16(_entries[i].id);
		_entries[i].size = FROM_LE_16(_entries[i].size);
		_entries[i].offset = FROM_LE_16(_entries[i].offset);
	}
#endif
}

uint32 Disk::getEntrySize(uint16 id) {
	// Get the index of the resource, if necessary opening the correct file
	uint8 index = indexOf(id);

	// Calculate the offset and size of the entry
	uint32 size = (uint32) _entries[index].size;
	if (_entries[index].sizeExtension) size += 0x10000;

	return size;
}

MemoryBlock *Disk::getEntry(uint16 id)
{
	// Get the index of the resource, if necessary opening the correct file
	uint8 index = indexOf(id);
		
	// Calculate the offset and size of the entry
	uint32 size = (uint32) _entries[index].size;
	if (_entries[index].sizeExtension) size += 0x10000;
	uint32 offset = (uint32) _entries[index].offset * 0x20;

	MemoryBlock *result = Memory::allocate(size);
	_fileHandle->seek(offset, SEEK_SET);
	_fileHandle->read(result->data(), size);
	return result;
}

bool Disk::exists(uint16 id) {
	// Get the index of the resource, if necessary opening the correct file
	uint8 index = indexOf(id, true);
	return (index != 0xff);
}

uint8 Disk::numEntries() {
	if (_fileNum == 0)
		error("No file is currently open");

	// Figure out how many entries there are by count until an unused entry is found
	for (byte entryIndex = 0; entryIndex < NUM_ENTRIES_IN_HEADER; ++entryIndex)
		if (_entries[entryIndex].id == HEADER_ENTRY_UNUSED_ID) return entryIndex;
	
	return NUM_ENTRIES_IN_HEADER;
}

FileEntry *Disk::getIndex(uint8 entryIndex) {
	if (_fileNum == 0)
		error("No file is currently open");
	if ((entryIndex >= NUM_ENTRIES_IN_HEADER) || (_entries[entryIndex].id == HEADER_ENTRY_UNUSED_ID))
		error("There is no entry at the specified index");

	return &_entries[entryIndex];
}

} // end of namespace Lure