Beispiel #1
0
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;
}
Beispiel #2
0
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;
}
Beispiel #3
0
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));
	}
}
Beispiel #4
0
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;
}
Beispiel #5
0
static ADGameDescList detectGame(const Common::FSList &fslist, const ADParams &params, 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;
}
Beispiel #6
0
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;
}
Beispiel #7
0
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;
}
Beispiel #8
0
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);
}