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
|
/* 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/>.
*
*/
/* Split one-big-file Macintosh game data into separate .00x files for ScummVM */
#include "extract_scumm_mac.h"
#include <algorithm>
ExtractScummMac::ExtractScummMac(const std::string &name) : Tool(name, TOOLTYPE_EXTRACTION) {
ToolInput input;
input.format = "*.*";
_inputPaths.push_back(input);
_shorthelp = "Extract data files from the single data file of later LucasArts Macintosh SCUMM games.";
_helptext =
"\nUsage: " + getName() + " [-o <output dir> = out/] <file>\n" +
_shorthelp + "\n";
}
InspectionMatch ExtractScummMac::inspectInput(const Common::Filename &filename) {
std::string name = filename.getFullName();
std::transform(name.begin(), name.end(), name.begin(), tolower);
std::string::size_type pos = name.find(" data");
if (pos == name.length() - 5) // True if the file name ends with " Data"
return IMATCH_PERFECT;
return IMATCH_AWFUL;
}
void ExtractScummMac::execute() {
Common::Filename inPath(_inputPaths[0].path);
Common::Filename outPath(_outputPath);
if (outPath.empty())
outPath.setFullPath("./");
Common::File ifp(inPath, "rb");
// Get the length of the data file to use for consistency checks
uint32 dataFileLength = ifp.size();
// Read offset and length to the file records
uint32 fileRecordOffset = ifp.readUint32BE();
uint32 fileRecordLength = ifp.readUint32BE();
// Do a quick check to make sure the offset and length are good
if (fileRecordOffset + fileRecordLength > dataFileLength)
error("File records out of bounds");
// Do a little consistancy check on fileRecordLength
if (fileRecordLength % 0x28)
error("File record length not multiple of 40");
// Extract the files
for (uint32 i = 0; i < fileRecordLength; i += 0x28) {
// read a file record
ifp.seek(fileRecordOffset + i, SEEK_SET);
uint32 fileOffset = ifp.readUint32BE();
uint32 fileLength = ifp.readUint32BE();
char fileName[0x21];
ifp.read_throwsOnError(fileName, 0x20);
fileName[0x20] = 0;
if (!fileName[0])
error("File has no name");
print("Extracting %s...", fileName);
// Consistency check. make sure the file data is in the file
if (fileOffset + fileLength > dataFileLength)
error("File out of bounds");
// Write a file
ifp.seek(fileOffset, SEEK_SET);
outPath.setFullName(fileName);
Common::File ofp(outPath, "wb");
byte *buf = new byte[fileLength];
ifp.read_throwsOnError(buf, fileLength);
ofp.write(buf, fileLength);
delete[] buf;
}
}
#ifdef STANDALONE_MAIN
int main(int argc, char *argv[]) {
return export_main(extract_scumm_mac)(argc, argv);
}
#endif
|