bool AdvancedMetaEngine::getFileProperties(const Common::FSNode &parent, const FileMap &allFiles, const ADGameDescription &game, const Common::String fname, ADFileProperties &fileProps) const { // FIXME/TODO: We don't handle the case that a file is listed as a regular // file and as one with resource fork. if (game.flags & ADGF_MACRESFORK) { Common::MacResManager macResMan; if (!macResMan.open(parent, fname)) return false; fileProps.md5 = macResMan.computeResForkMD5AsString(_md5Bytes); fileProps.size = macResMan.getResForkDataSize(); if (fileProps.size != 0) return true; } if (!allFiles.contains(fname)) return false; Common::File testFile; if (!testFile.open(allFiles[fname])) return false; fileProps.size = (int32)testFile.size(); fileProps.md5 = Common::computeStreamMD5AsString(testFile, _md5Bytes); return true; }
bool Player_V3M::checkMusicAvailable() { Common::MacResManager resource; for (int i = 0; i < ARRAYSIZE(loomFileNames); i++) { if (resource.exists(loomFileNames[i])) { return true; } } GUI::MessageDialog dialog(_( "Could not find the 'Loom' Macintosh executable to read the\n" "instruments from. Music will be disabled."), _("OK")); dialog.runModal(); return false; }
void World::loadExternalSounds(Common::String fname) { Common::File in; in.open(fname); if (!in.isOpen()) { warning("Cannot load sound file <%s>", fname.c_str()); return; } in.close(); Common::MacResManager resMan; resMan.open(fname); Common::MacResIDArray resArray; Common::SeekableReadStream *res; Common::MacResIDArray::const_iterator iter; resArray = resMan.getResIDArray(MKTAG('A','S','N','D')); for (iter = resArray.begin(); iter != resArray.end(); ++iter) { res = resMan.getResource(MKTAG('A','S','N','D'), *iter); addSound(new Sound(resMan.getResName(MKTAG('A','S','N','D'), *iter), res)); } }
bool Player_V3M::loadMusic(const byte *ptr) { Common::MacResManager resource; bool found = false; for (int i = 0; i < ARRAYSIZE(loomFileNames); i++) { if (resource.open(loomFileNames[i])) { found = true; break; } } if (!found) { return false; } if (ptr[4] != 's' || ptr[5] != 'o') { // Like the original we ignore all sound resources which do not have // a 'so' tag in them. // See bug #3602239 ("Mac Loom crashes using opening spell on // gravestone") for a case where this is required. Loom Mac tries to // play resource 11 here. This resource is no Mac sound resource // though, it is a PC Speaker resource. A test with the original // interpreter also has shown that no sound is played while the // screen is shaking. debug(5, "Player_V3M::loadMusic: Skipping unknown music type %02X%02X", ptr[4], ptr[5]); resource.close(); return false; } uint i; for (i = 0; i < 5; i++) { int instrument = READ_BE_UINT16(ptr + 20 + 2 * i); int offset = READ_BE_UINT16(ptr + 30 + 2 * i); _channel[i]._looped = false; _channel[i]._length = READ_BE_UINT16(ptr + offset + 4) * 3; _channel[i]._data = ptr + offset + 6; _channel[i]._pos = 0; _channel[i]._pitchModifier = 0; _channel[i]._velocity = 0; _channel[i]._remaining = 0; _channel[i]._notesLeft = true; Common::SeekableReadStream *stream = resource.getResource(RES_SND, instrument); if (_channel[i].loadInstrument(stream)) { debug(6, "Player_V3M::loadMusic: Channel %d - Loaded Instrument %d (%s)", i, instrument, resource.getResName(RES_SND, instrument).c_str()); } else { resource.close(); return false; } } resource.close(); return true; }
static ADGameDescList detectGame(const Common::FSList &fslist, const ADParams ¶ms, Common::Language language, Common::Platform platform, const Common::String &extra) { FileMap allFiles; SizeMD5Map filesSizeMD5; const ADGameFileDescription *fileDesc; const ADGameDescription *g; const byte *descPtr; if (fslist.empty()) return ADGameDescList(); Common::FSNode parent = fslist.begin()->getParent(); debug(3, "Starting detection in dir '%s'", parent.getPath().c_str()); // First we compose a hashmap of all files in fslist. // Includes nifty stuff like removing trailing dots and ignoring case. composeFileHashMap(fslist, allFiles, (params.depth == 0 ? 1 : params.depth), params.directoryGlobs); // Check which files are included in some ADGameDescription *and* present // in fslist. Compute MD5s and file sizes for these files. for (descPtr = params.descs; ((const ADGameDescription *)descPtr)->gameid != 0; descPtr += params.descItemSize) { g = (const ADGameDescription *)descPtr; for (fileDesc = g->filesDescriptions; fileDesc->fileName; fileDesc++) { Common::String fname = fileDesc->fileName; SizeMD5 tmp; if (filesSizeMD5.contains(fname)) continue; // FIXME/TODO: We don't handle the case that a file is listed as a regular // file and as one with resource fork. if (g->flags & ADGF_MACRESFORK) { Common::MacResManager *macResMan = new Common::MacResManager(); if (macResMan->open(parent, fname)) { tmp.md5 = macResMan->computeResForkMD5AsString(params.md5Bytes); tmp.size = macResMan->getResForkDataSize(); debug(3, "> '%s': '%s'", fname.c_str(), tmp.md5.c_str()); filesSizeMD5[fname] = tmp; } delete macResMan; } else { if (allFiles.contains(fname)) { debug(3, "+ %s", fname.c_str()); Common::File testFile; if (testFile.open(allFiles[fname])) { tmp.size = (int32)testFile.size(); tmp.md5 = Common::computeStreamMD5AsString(testFile, params.md5Bytes); } else { tmp.size = -1; } debug(3, "> '%s': '%s'", fname.c_str(), tmp.md5.c_str()); filesSizeMD5[fname] = tmp; } } } } ADGameDescList matched; int maxFilesMatched = 0; bool gotAnyMatchesWithAllFiles = false; // MD5 based matching uint i; for (i = 0, descPtr = params.descs; ((const ADGameDescription *)descPtr)->gameid != 0; descPtr += params.descItemSize, ++i) { g = (const ADGameDescription *)descPtr; bool fileMissing = false; // Do not even bother to look at entries which do not have matching // language and platform (if specified). if ((language != Common::UNK_LANG && g->language != Common::UNK_LANG && g->language != language && !(language == Common::EN_ANY && (g->flags & ADGF_ADDENGLISH))) || (platform != Common::kPlatformUnknown && g->platform != Common::kPlatformUnknown && g->platform != platform)) { continue; } if ((params.flags & kADFlagUseExtraAsHint) && !extra.empty() && g->extra != extra) continue; bool allFilesPresent = true; int curFilesMatched = 0; // Try to match all files for this game for (fileDesc = g->filesDescriptions; fileDesc->fileName; fileDesc++) { Common::String tstr = fileDesc->fileName; if (!filesSizeMD5.contains(tstr)) { fileMissing = true; allFilesPresent = false; break; } if (fileDesc->md5 != NULL && fileDesc->md5 != filesSizeMD5[tstr].md5) { debug(3, "MD5 Mismatch. Skipping (%s) (%s)", fileDesc->md5, filesSizeMD5[tstr].md5.c_str()); fileMissing = true; break; } if (fileDesc->fileSize != -1 && fileDesc->fileSize != filesSizeMD5[tstr].size) { debug(3, "Size Mismatch. Skipping"); fileMissing = true; break; } debug(3, "Matched file: %s", tstr.c_str()); curFilesMatched++; } // We found at least one entry with all required files present. // That means that we got new variant of the game. // // Without this check we would have erroneous checksum display // where only located files will be enlisted. // // Potentially this could rule out variants where some particular file // is really missing, but the developers should better know about such // cases. if (allFilesPresent) gotAnyMatchesWithAllFiles = true; if (!fileMissing) { debug(2, "Found game: %s (%s %s/%s) (%d)", g->gameid, g->extra, getPlatformDescription(g->platform), getLanguageDescription(g->language), i); if (curFilesMatched > maxFilesMatched) { debug(2, " ... new best match, removing all previous candidates"); maxFilesMatched = curFilesMatched; matched.clear(); // Remove any prior, lower ranked matches. matched.push_back(g); } else if (curFilesMatched == maxFilesMatched) { matched.push_back(g); } else { debug(2, " ... skipped"); } } else { debug(5, "Skipping game: %s (%s %s/%s) (%d)", g->gameid, g->extra, getPlatformDescription(g->platform), getLanguageDescription(g->language), i); } } // We didn't find a match if (matched.empty()) { if (!filesSizeMD5.empty() && gotAnyMatchesWithAllFiles) { reportUnknown(parent, filesSizeMD5); } // Filename based fallback if (params.fileBasedFallback != 0) matched = detectGameFilebased(allFiles, params); } return matched; }
bool Player_V5M::loadMusic(const byte *ptr) { Common::MacResManager resource; bool found = false; uint i; for (i = 0; i < ARRAYSIZE(monkeyIslandFileNames); i++) { if (resource.open(monkeyIslandFileNames[i])) { found = true; break; } } if (!found) { return false; } ptr += 8; // TODO: Decipher the unknown bytes in the header. For now, skip 'em ptr += 28; Common::MacResIDArray idArray = resource.getResIDArray(RES_SND); // Load the three channels and their instruments for (i = 0; i < 3; i++) { assert(READ_BE_UINT32(ptr) == MKTAG('C', 'h', 'a', 'n')); uint32 len = READ_BE_UINT32(ptr + 4); uint32 instrument = READ_BE_UINT32(ptr + 8); _channel[i]._length = len - 20; _channel[i]._data = ptr + 12; _channel[i]._looped = (READ_BE_UINT32(ptr + len - 8) == MKTAG('L', 'o', 'o', 'p')); _channel[i]._pos = 0; _channel[i]._pitchModifier = 0; _channel[i]._velocity = 0; _channel[i]._remaining = 0; _channel[i]._notesLeft = true; for (uint j = 0; j < idArray.size(); j++) { Common::String name = resource.getResName(RES_SND, idArray[j]); if (instrument == READ_BE_UINT32(name.c_str())) { debug(6, "Player_V5M::loadMusic: Channel %d: Loading instrument '%s'", i, name.c_str()); Common::SeekableReadStream *stream = resource.getResource(RES_SND, idArray[j]); if (!_channel[i].loadInstrument(stream)) { resource.close(); return false; } break; } } ptr += len; } resource.close(); // The last note of each channel is just zeroes. We will adjust this // note so that all the channels end at the same time. uint32 samples[3]; uint32 maxSamples = 0; for (i = 0; i < 3; i++) { samples[i] = 0; for (uint j = 0; j < _channel[i]._length; j += 4) { samples[i] += durationToSamples(READ_BE_UINT16(&_channel[i]._data[j])); } if (samples[i] > maxSamples) { maxSamples = samples[i]; } } for (i = 0; i < 3; i++) { _lastNoteSamples[i] = maxSamples - samples[i]; } return true; }
void MacFontManager::loadFonts() { Common::Archive *dat; dat = Common::makeZipArchive("classicmacfonts.dat"); if (!dat) { warning("Could not find classicmacfonts.dat. Falling back to built-in fonts"); _builtInFonts = true; return; } Common::ArchiveMemberList list; dat->listMembers(list); for (Common::ArchiveMemberList::iterator it = list.begin(); it != list.end(); ++it) { Common::SeekableReadStream *stream = dat->createReadStreamForMember((*it)->getName()); Common::MacResManager *fontFile = new Common::MacResManager(); if (!fontFile->loadFromMacBinary(*stream)) continue; Common::MacResIDArray fonds = fontFile->getResIDArray(MKTAG('F','O','N','D')); if (fonds.size() > 0) { for (Common::Array<uint16>::iterator iterator = fonds.begin(); iterator != fonds.end(); ++iterator) { Common::SeekableReadStream *fond = fontFile->getResource(MKTAG('F', 'O', 'N', 'D'), *iterator); Common::String familyName = fontFile->getResName(MKTAG('F', 'O', 'N', 'D'), *iterator); Graphics::MacFontFamily *fontFamily = new MacFontFamily(); fontFamily->load(*fond); Common::Array<Graphics::MacFontFamily::AsscEntry> *assoc = fontFamily->getAssocTable(); for (uint i = 0; i < assoc->size(); i++) { debug("size: %d style: %d id: %d", (*assoc)[i]._fontSize, (*assoc)[i]._fontStyle, (*assoc)[i]._fontID); Common::SeekableReadStream *fontstream; MacFont *macfont; Graphics::MacFONTFont *font; fontstream = fontFile->getResource(MKTAG('N', 'F', 'N', 'T'), (*assoc)[i]._fontID); if (!fontstream) fontstream = fontFile->getResource(MKTAG('F', 'O', 'N', 'T'), (*assoc)[i]._fontID); if (!fontstream) { warning("Unknown FontId: %d", (*assoc)[i]._fontID); continue; } font = new Graphics::MacFONTFont; font->loadFont(*fontstream, fontFamily, (*assoc)[i]._fontSize, (*assoc)[i]._fontStyle); delete fontstream; Common::String fontName = Common::String::format("%s-%d-%d", familyName.c_str(), (*assoc)[i]._fontStyle, (*assoc)[i]._fontSize); macfont = new MacFont(_fontNames.getVal(familyName, kMacFontNonStandard), (*assoc)[i]._fontSize, (*assoc)[i]._fontStyle); FontMan.assignFontToName(fontName, font); macfont->setFont(font); _fontRegistry.setVal(fontName, macfont); debug(2, " %s", fontName.c_str()); } delete fond; } } delete fontFile; } _builtInFonts = false; delete dat; }
void Lingo::func_goto(Datum &frame, Datum &movie) { _vm->_playbackPaused = false; if (!_vm->getCurrentScore()) return; if (movie.type != VOID) { movie.toString(); Common::String movieFilename = convertPath(*movie.u.s); Common::String cleanedFilename; bool fileExists = false; if (_vm->getPlatform() == Common::kPlatformMacintosh) { Common::MacResManager resMan; for (const byte *p = (const byte *)movieFilename.c_str(); *p; p++) if (*p >= 0x20 && *p <= 0x7f) cleanedFilename += (char) *p; if (resMan.open(movieFilename)) { fileExists = true; cleanedFilename = movieFilename; } else if (!movieFilename.equals(cleanedFilename) && resMan.open(cleanedFilename)) { fileExists = true; } } else { Common::File file; cleanedFilename = movieFilename + ".MMM"; if (file.open(movieFilename)) { fileExists = true; cleanedFilename = movieFilename; } else if (!movieFilename.equals(cleanedFilename) && file.open(cleanedFilename)) { fileExists = true; } } if (!fileExists) { warning("Movie %s does not exist", movieFilename.c_str()); return; } _vm->_nextMovie.movie = cleanedFilename; _vm->getCurrentScore()->_stopPlay = true; _vm->_nextMovie.frameS.clear(); _vm->_nextMovie.frameI = -1; if (frame.type == VOID) return; if (frame.type == STRING) { _vm->_nextMovie.frameS = *frame.u.s; return; } frame.toInt(); _vm->_nextMovie.frameI = frame.u.i; return; } if (frame.type == VOID) return; _vm->_skipFrameAdvance = true; if (frame.type == STRING) { if (_vm->getCurrentScore()) _vm->getCurrentScore()->setStartToLabel(*frame.u.s); return; } frame.toInt(); if (_vm->getCurrentScore()) _vm->getCurrentScore()->setCurrentFrame(frame.u.i); }