File: extract_fascination_cd.cpp

package info (click to toggle)
scummvm-tools 2.9.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 6,940 kB
  • sloc: cpp: 76,819; python: 6,550; sh: 4,661; perl: 1,530; ansic: 646; makefile: 360
file content (134 lines) | stat: -rw-r--r-- 4,234 bytes parent folder | download | duplicates (2)
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
/* ScummVM Tools
 *
 * ScummVM Tools 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 3 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, see <http://www.gnu.org/licenses/>.
 *
 */

/* a tool for extracting .stk archives from a mode1/2048 Fascination CD image */

#include "common/endian.h"
#include "common/file.h"
#include "common/util.h"

#include "extract_fascination_cd.h"


enum {
	STK_HEADER_ENTRY_SIZE = 22
};

struct STKFile {
	const char *stkFilename;
	const char *firstEntryName;
	bool  extracted;
} static stkFile[] = {
	{ "intro.stk", "INTRO1.TOT", false },
	{ "disk1.stk", "DOUCHE.TOT", false },
	{ "disk2.stk", "PLANQUE.TOT", false },
	{ "disk3.stk", "MELANGE.TOT", false },
};


ExtractFascinationCD::ExtractFascinationCD(const std::string &name) : Tool(name, TOOLTYPE_EXTRACTION) {
	ToolInput input;
	input.format = "*.iso";
	_inputPaths.push_back(input);

	_shorthelp = "Extract data files from a Fascination ISO.";
	_helptext = "Usage: " + _name + " [-o outputdir] <infile>\n" + _shorthelp + "\n";
}

void ExtractFascinationCD::execute(void) {
	if (_outputPath.empty())
		_outputPath.setFullPath("./");

	// Open ISO file
	Common::File file(_inputPaths[0].path, "rb");
	assert(file.isOpen());
	uint32 fileSize = file.size();

	// Sanity check the file size
	if (fileSize > (16 * 1024 * 1024)) {
		error("'%s' is too large to be a Fascination mode1/2048 ISO", _inputPaths[0].path.c_str());
	}

	if (fileSize < (8 * 1024 * 1024)) {
		error("'%s' is too small to be a Fascination mode1/2048 ISO", _inputPaths[0].path.c_str());
	}

	if (fileSize % 2048) {
		error("'%s' doesn't appear to be a mode1/2048 ISO", _inputPaths[0].path.c_str());
	}

	// Load ISO file to memory. (Should only be ~10MB, and this simplifies the code)
	byte *data = new byte[fileSize];
	file.read_noThrow(data, fileSize);
	file.close();
	
	print("Loaded '%s' (%d bytes)\n", _inputPaths[0].path.c_str(), fileSize);
	
	for (uint32 i = 0; i < ARRAYSIZE(stkFile); i++) {
		// initialize curPos to start of file
		byte *curPos = data;	
	
		while (curPos < data + fileSize) {
			// search for known first entry of STK files
			if (!memcmp(curPos, stkFile[i].firstEntryName, strlen(stkFile[i].firstEntryName))) {
				byte *stkFileStart = curPos - 2;	// the actual STK start is 2 bytes prior
				uint16 numStkEntries = READ_LE_UINT16(stkFileStart); // read number of entries in STK file
				assert(numStkEntries > 0 && numStkEntries < 0xFF);
				
				// Determine length of file by adding offset and size of the last entry
				const uint32 lastEntrySize = READ_LE_UINT32(curPos + ((numStkEntries - 1) * STK_HEADER_ENTRY_SIZE) + 13);
				const uint32 lastEntryOffset = READ_LE_UINT32(curPos + ((numStkEntries - 1) * STK_HEADER_ENTRY_SIZE) + 17);
				const uint32 stkEntrySize = lastEntryOffset + lastEntrySize;

				print("Found '%s' at %x (size: %d).  Extracting...\n", stkFile[i].stkFilename, curPos - data - 2, stkEntrySize);
				
				// write STK file
				Common::File output;
				_outputPath.setFullName(stkFile[i].stkFilename);
				output.open(_outputPath, "wb");
				assert(output.isOpen());
				output.write(stkFileStart, stkEntrySize);
				output.close();
				stkFile[i].extracted = true;

				curPos += stkEntrySize;
			}
		
			curPos++;
		}
	}
	
	for (int i = 0; i < ARRAYSIZE(stkFile); i++) {
		if (!stkFile[i].extracted)
			error("A problem occurred: '%s' has NOT been extracted", stkFile[i].stkFilename);
	}

	delete[] data;
}


#ifdef STANDALONE_MAIN
int main(int argc, char *argv[]) {
	ExtractFascinationCD fe(argv[0]);
	return fe.run(argc, argv);
}
#endif