Example #1
0
/**
 * Reads boot file for program environment.  Fatal error if not there or
 * file checksum is bad.  De-crypts structure while checking checksum
 */
void FileManager::readBootFile() {
	debugC(1, kDebugFile, "readBootFile()");

	Common::File ofp;
	if (!ofp.open(getBootFilename())) {
		if (_vm->_gameVariant == kGameVariantH1Dos) {
			//TODO initialize properly _boot structure
			warning("readBootFile - Skipping as H1 Dos may be a freeware");
			memset(_vm->_boot.distrib, '\0', sizeof(_vm->_boot.distrib));
			_vm->_boot.registered = kRegFreeware;
			return;
		} else {
			error("Missing startup file '%s'", getBootFilename());
		}
	}

	if (ofp.size() < (int32)sizeof(_vm->_boot))
		error("Corrupted startup file");

	_vm->_boot.checksum = ofp.readByte();
	_vm->_boot.registered = ofp.readByte();
	ofp.read(_vm->_boot.pbswitch, sizeof(_vm->_boot.pbswitch));
	ofp.read(_vm->_boot.distrib, sizeof(_vm->_boot.distrib));
	_vm->_boot.exit_len = ofp.readUint16LE();

	byte *p = (byte *)&_vm->_boot;

	byte checksum = 0;
	for (uint32 i = 0; i < sizeof(_vm->_boot); i++) {
		checksum ^= p[i];
		p[i] ^= s_bootCyper[i % s_bootCyperLen];
	}
	ofp.close();

	if (checksum)
		error("Corrupted startup file");
}
Example #2
0
/**
 * Read sound (or music) file data.  Call with SILENCE to free-up
 * any allocated memory.  Also returns size of data
 */
sound_pt FileManager::getSound(const int16 sound, uint16 *size) {
	debugC(1, kDebugFile, "getSound(%d)", sound);

	// No more to do if SILENCE (called for cleanup purposes)
	if (sound == _vm->_soundSilence)
		return 0;

	// Open sounds file
	Common::File fp;                                // Handle to SOUND_FILE
	if (!fp.open(getSoundFilename())) {
		warning("Hugo Error: File not found %s", getSoundFilename());
		return 0;
	}

	if (!has_read_header) {
		if (fp.read(s_hdr, sizeof(s_hdr)) != sizeof(s_hdr))
			error("Wrong sound file format");
		has_read_header = true;
	}

	*size = s_hdr[sound].size;
	if (*size == 0)
		error("Wrong sound file format or missing sound %d", sound);

	// Allocate memory for sound or music, if possible
	sound_pt soundPtr = (byte *)malloc(s_hdr[sound].size); // Ptr to sound data
	assert(soundPtr);

	// Seek to data and read it
	fp.seek(s_hdr[sound].offset, SEEK_SET);
	if (fp.read(soundPtr, s_hdr[sound].size) != s_hdr[sound].size)
		error("Wrong sound file format");

	fp.close();

	return soundPtr;
}
Example #3
0
VideoHandle VideoManager::createVideoHandle(const Common::String &filename, uint16 x, uint16 y, bool loop, byte volume) {
	// First, check to see if that video is already playing
	for (uint32 i = 0; i < _videoStreams.size(); i++)
		if (_videoStreams[i].filename == filename)
			return i;

	// Otherwise, create a new entry
	VideoEntry entry;
	entry.clear();
	entry.video = new Video::QuickTimeDecoder();
	entry.x = x;
	entry.y = y;
	entry.filename = filename;
	entry.loop = loop;
	entry.enabled = true;

	Common::File *file = new Common::File();
	if (!file->open(filename)) {
		delete file;
		return NULL_VID_HANDLE;
	}

	entry->loadStream(file);
	entry->setVolume(volume);
	entry->start();

	// Search for any deleted videos so we can take a formerly used slot
	for (uint32 i = 0; i < _videoStreams.size(); i++)
		if (!_videoStreams[i].video) {
			_videoStreams[i] = entry;
			return i;
		}

	// Otherwise, just add it to the list
	_videoStreams.push_back(entry);
	return _videoStreams.size() - 1;
}
Example #4
0
Common::SeekableReadStream *SaveManager::getSlotFile(uint slot) {
	Common::SeekableReadStream *saveFile = g_system->getSavefileManager()->openForLoading(_engine->generateSaveFileName(slot));
	if (saveFile == NULL) {
		// Try to load standard save file
		Common::String filename;
		if (_engine->getGameId() == GID_GRANDINQUISITOR)
			filename = Common::String::format("inqsav%u.sav", slot);
		else if (_engine->getGameId() == GID_NEMESIS)
			filename = Common::String::format("nemsav%u.sav", slot);

		saveFile = _engine->getSearchManager()->openFile(filename);
		if (saveFile == NULL) {
			Common::File *tmpFile = new Common::File;
			if (!tmpFile->open(filename)) {
				delete tmpFile;
			} else {
				saveFile = tmpFile;
			}
		}

	}

	return saveFile;
}
Example #5
0
bool GfxPalette::loadClut(uint16 clutId) {
	// loadClut() will load a color lookup table from a clu file and set
	// the palette found in the file. This is to be used with Phantasmagoria 2.

	unloadClut();

	Common::String filename = Common::String::format("%d.clu", clutId);
	Common::File clut;

	if (!clut.open(filename) || clut.size() != 0x10000 + 236 * 3)
		return false;

	// Read in the lookup table
	// It maps each RGB565 color to a palette index
	_clutTable = new byte[0x10000];
	clut.read(_clutTable, 0x10000);

	Palette pal;
	memset(&pal, 0, sizeof(Palette));

	// Setup 1:1 mapping
	for (int i = 0; i < 256; i++)
		pal.mapping[i] = i;

	// Now load in the palette
	for (int i = 1; i <= 236; i++) {
		pal.colors[i].used = 1;
		pal.colors[i].r = clut.readByte();
		pal.colors[i].g = clut.readByte();
		pal.colors[i].b = clut.readByte();
	}

	set(&pal, true);
	setOnScreen();
	return true;
}
Example #6
0
// Will try to set amiga palette by using "spal" file. If not found, we return false
bool GfxPalette::setAmiga() {
	Common::File file;

	if (file.open("spal")) {
		for (int curColor = 0; curColor < 32; curColor++) {
			byte byte1 = file.readByte();
			byte byte2 = file.readByte();

			if (file.eos())
				error("Amiga palette file ends prematurely");

			_sysPalette.colors[curColor].used = 1;
			_sysPalette.colors[curColor].r = (byte1 & 0x0F) * 0x11;
			_sysPalette.colors[curColor].g = ((byte2 & 0xF0) >> 4) * 0x11;
			_sysPalette.colors[curColor].b = (byte2 & 0x0F) * 0x11;
		}

		// Directly set the palette, because setOnScreen() wont do a thing for amiga
		copySysPaletteToScreen();
		return true;
	}

	return false;
}
Example #7
0
bool MD5Check::advanceCheck(int *pos, int *total) {
	if (_iterator < 0) {
		return false;
	}

	const MD5Sum &sum = (*_files)[_iterator++];
	if (pos) {
		*pos = _iterator;
	}
	if (total) {
		*total = _files->size();
	}
	if ((uint32)_iterator == _files->size()) {
		_iterator = -1;
	}

	Common::File file;
	if (file.open(sum.filename)) {
		Common::String md5 = Common::computeStreamMD5AsString(file);
		if (!checkMD5(sum, md5.c_str())) {
			warning("'%s' may be corrupted. MD5: '%s'", sum.filename, md5.c_str());
			GUI::displayErrorDialog(Common::String::format("The game data file %s may be corrupted.\nIf you are sure it is "
									"not please provide the ResidualVM team the following code, along with the file name, the language and a "
									"description of your game version (i.e. dvd-box or jewelcase):\n%s", sum.filename, md5.c_str()).c_str());
			return false;
		}
	} else {
		warning("Could not open %s for checking", sum.filename);
		GUI::displayErrorDialog(Common::String::format("Could not open the file %s for checking.\nIt may be missing or "
								"you may not have the rights to open it.\nGo to http://wiki.residualvm.org/index.php/Datafiles to see a list "
								"of the needed files.", sum.filename).c_str());
		return false;
	}

	return true;
}
Example #8
0
void convertRawToWav(const Common::String &inputFile, ZVision *engine, const Common::String &outputFile) {
	Common::File file;
	if (!file.open(inputFile))
		return;

	Audio::AudioStream *audioStream = makeRawZorkStream(inputFile, engine);

	Common::DumpFile output;
	output.open(outputFile);

	output.writeUint32BE(MKTAG('R', 'I', 'F', 'F'));
	output.writeUint32LE(file.size() * 2 + 36);
	output.writeUint32BE(MKTAG('W', 'A', 'V', 'E'));
	output.writeUint32BE(MKTAG('f', 'm', 't', ' '));
	output.writeUint32LE(16);
	output.writeUint16LE(1);
	uint16 numChannels;
	if (audioStream->isStereo()) {
		numChannels = 2;
		output.writeUint16LE(2);
	} else {
		numChannels = 1;
		output.writeUint16LE(1);
	}
	output.writeUint32LE(audioStream->getRate());
	output.writeUint32LE(audioStream->getRate() * numChannels * 2);
	output.writeUint16LE(numChannels * 2);
	output.writeUint16LE(16);
	output.writeUint32BE(MKTAG('d', 'a', 't', 'a'));
	output.writeUint32LE(file.size() * 2);
	int16 *buffer = new int16[file.size()];
	audioStream->readBuffer(buffer, file.size());
	output.write(buffer, file.size() * 2);

	delete[] buffer;
}
Example #9
0
/**
 * Draw background animation
 * @remarks	Originally called 'show_one'
 */
void Background::draw(int16 destX, int16 destY, byte sprId) {
	assert(sprId < 40);

	if (_sprites[sprId]._x > kOnDisk) {
		if (destX < 0) {
			destX = _sprites[sprId]._x * 8;
			destY = _sprites[sprId]._y;
		}
		drawSprite(destX, destY, _sprites[sprId]);
	} else {
		Common::File f;
		if (!f.open(_filename)) // Filename was set in loadBackgroundSprites().
			return; // We skip because some rooms don't have sprites in the background.

		f.seek(_offsets[sprId]);

		SpriteType sprite;
		sprite._type = (PictureType)(f.readByte());
		sprite._x = f.readSint16LE();
		sprite._y = f.readSint16LE();
		sprite._width = f.readSint16LE();
		sprite._height = f.readSint16LE();
		sprite._size = f.readSint32LE();
		f.skip(2); // Natural and Memorize are used in Load()
		sprite._picture = _vm->_graphics->loadPictureRaw(f, sprite._width * 8, sprite._height + 1);

		if (destX < 0) {
			destX = sprite._x * 8;
			destY = sprite._y;
		}
		drawSprite(destX, destY, sprite);

		sprite._picture.free();
		f.close();
	}
}
Example #10
0
BaseSound::BaseSound(Audio::Mixer *mixer, const Common::String &filename, uint32 base, bool bigEndian)
	: _mixer(mixer), _filename(filename), _offsets(NULL) {

	uint res = 0;
	uint32 size;

	Common::File file;
	if (!file.open(_filename))
		error("BaseSound: Could not open file \"%s\"", filename.c_str());

	file.seek(base + sizeof(uint32), SEEK_SET);
	if (bigEndian)
		size = file.readUint32BE();
	else
		size = file.readUint32LE();

	// The Feeble Files uses set amount of voice offsets
	if (size == 0)
		size = 40000;

	res = size / sizeof(uint32);

	_offsets = (uint32 *)malloc(size + sizeof(uint32));
	_freeOffsets = true;

	file.seek(base, SEEK_SET);

	for (uint i = 0; i < res; i++) {
		if (bigEndian)
			_offsets[i] = base + file.readUint32BE();
		else
			_offsets[i] = base + file.readUint32LE();
	}

	_offsets[res] = file.size();
}
Example #11
0
void GameModule::load(const char *filename) {
	debug(0, "GameModule::load()");

	unload();

	Common::File fd;

	if (!fd.open(filename))
		error("GameModule::load() Could not open %s", filename);

	loadBgSprites(fd);
	loadCameraInits(fd);
	loadWalkRects(fd);
	loadSceneExits(fd);
	loadBgObjects(fd);
	loadAnimations(fd);
	loadSceneObjectDefs(fd);
	loadSceneObjectInits(fd);
	loadActions(fd);
	loadGuiSpriteIndices(fd);
	loadInventoryItemSpriteIndices(fd);
	loadInventoryItemInfos(fd);
	loadDialogItemSpriteIndices(fd);
	loadSceneSounds(fd);
	loadPreloadSounds(fd);

	fd.seek(0xC);
	_fieldC = fd.readUint32LE();

	fd.seek(0x1A8);
	_buttheadObjectIndex = fd.readUint32LE();

	fd.close();

	debug(0, "GameModule::load() OK");
}
Common::SeekableReadStream *InstallShieldCabinet::createReadStreamForMember(const Common::String &name) const {
	if (!_map.contains(name))
		return 0;

	const FileEntry &entry = _map[name];

	Common::File archiveFile;
	archiveFile.open(_installShieldFilename);
	archiveFile.seek(entry.offset);

	if (!(entry.flags & 0x04)) {
		// Not compressed
		return archiveFile.readStream(entry.uncompressedSize);
	}

#ifdef USE_ZLIB
	byte *src = (byte *)malloc(entry.compressedSize);
	byte *dst = (byte *)malloc(entry.uncompressedSize);

	archiveFile.read(src, entry.compressedSize);

	bool result = Common::inflateZlibHeaderless(dst, entry.uncompressedSize, src, entry.compressedSize);
	free(src);

	if (!result) {
		warning("failed to inflate CAB file '%s'", name.c_str());
		free(dst);
		return 0;
	}

	return new Common::MemoryReadStream(dst, entry.uncompressedSize, DisposeAfterUse::YES);
#else
	warning("zlib required to extract compressed CAB file '%s'", name.c_str());
	return 0;
#endif
}
Example #13
0
Common::SeekableReadStream *Resources::openFile(const Common::String &fileName) {
	debugC(1, kDebugResource, "openFile(%s)", fileName.c_str());

	// first try to find files outside of .pak
	// some patched files have not been included in package.
	if (Common::File::exists(fileName)) {
		Common::File *file = new Common::File();
		bool opened = file->open(fileName);
		if (!opened) {
			delete file;
			return 0;
		}
		return file;
	} else {
		for (uint32 i = 0; i < _pakFiles.size(); i++) {
			Common::SeekableReadStream *stream = 0;
			stream = _pakFiles[i]->createReadStream(fileName);
			if (stream)
				return stream;
		}

		return 0;
	}
}
Example #14
0
bool Font::loadFont(const Common::String &filename) {
    // Free previously loaded font (if any)
    freeFont();

    Common::File f;

    f.open(filename);
    if (f.isOpen()) {
        debugC(6, kDraciGeneralDebugLevel, "Opened font file %s",
               filename.c_str());
    } else {
        debugC(6, kDraciGeneralDebugLevel, "Error opening font file %s",
               filename.c_str());
        return false;
    }

    _maxCharWidth = f.readByte();
    _fontHeight = f.readByte();

    // Read in the widths of the glyphs
    _charWidths = new uint8[kCharNum];
    for (uint i = 0; i < kCharNum; ++i) {
        _charWidths[i] = f.readByte();
    }

    // Calculate size of font data
    uint fontDataSize = kCharNum * _maxCharWidth * _fontHeight;

    // Read in all glyphs
    _charData = new byte[fontDataSize];
    f.read(_charData, fontDataSize);

    debugC(5, kDraciGeneralDebugLevel, "Font %s loaded", filename.c_str());

    return true;
}
Example #15
0
bool SndRes::load(ResourceContext *context, uint32 resourceId, SoundBuffer &buffer, bool onlyHeader) {
	size_t soundResourceLength;
	bool result = false;
	GameSoundType resourceType = kSoundPCM;
	int rate = 0, size = 0;
	Common::File *file;

	if (resourceId == (uint32)-1) {
		return false;
	}

#ifdef ENABLE_IHNM
	//TODO: move to resource_res so we can use normal "getResourceData" and "getFile" methods
	if (_vm->getGameId() == GID_IHNM && _vm->isMacResources()) {
		char soundFileName[40];
		int dirIndex = resourceId / 64;

		if ((context->fileType() & GAME_VOICEFILE) != 0) {
			if (_voiceSerial == 0) {
				sprintf(soundFileName, "Voices/VoicesS/Voices%d/VoicesS%03x", dirIndex, resourceId);
			} else {
				sprintf(soundFileName, "Voices/Voices%d/Voices%d/Voices%d%03x", _voiceSerial, dirIndex, _voiceSerial, resourceId);
			}
		} else {
			sprintf(soundFileName, "SFX/SFX%d/SFX%03x", dirIndex, resourceId);
		}

		file = new Common::File();

		file->open(soundFileName);
		soundResourceLength = file->size();
	} else
#endif
	{
		ResourceData* resourceData = context->getResourceData(resourceId);
		file = context->getFile(resourceData);

		file->seek(resourceData->offset);
		soundResourceLength = resourceData->size;
	}

	Common::SeekableReadStream &readS = *file;
	bool uncompressedSound = false;

	if (soundResourceLength >= 8) {
		byte header[8];

		readS.read(&header, 8);
		readS.seek(readS.pos() - 8);

		if (!memcmp(header, "Creative", 8)) {
			resourceType = kSoundVOC;
		} else if (!memcmp(header, "RIFF", 4) != 0) {
			resourceType = kSoundWAV;
		} else if (!memcmp(header, "FORM", 4) != 0) {
			resourceType = kSoundAIFF;
		} else if (!memcmp(header, "ajkg", 4) != 0) {
			resourceType = kSoundShorten;
		}

		// If patch data exists for sound resource 4 (used in ITE intro), don't treat this sound as compressed
		// Patch data for this resource is in file p2_a.iaf or p2_a.voc
		if (_vm->getGameId() == GID_ITE && resourceId == 4 && context->getResourceData(resourceId)->patchData != NULL)
			uncompressedSound = true;

		// FIXME: Currently, the SFX.RES file in IHNM cannot be compressed
		if (_vm->getGameId() == GID_IHNM && (context->fileType() & GAME_SOUNDFILE))
			uncompressedSound = true;

		if (context->isCompressed() && !uncompressedSound) {
			if (header[0] == char(0)) {
				resourceType = kSoundMP3;
			} else if (header[0] == char(1)) {
				resourceType = kSoundOGG;
			} else if (header[0] == char(2)) {
				resourceType = kSoundFLAC;
			}
		}

	}

	// Default sound type is 16-bit signed PCM, used in ITE
	byte rawFlags = Audio::FLAG_16BITS;

	if (_vm->getGameId() == GID_ITE) {
		if (context->fileType() & GAME_MACBINARY) {
			// ITE Mac has sound in the Mac snd format
			resourceType = kSoundMacSND;
		} else if (_vm->getFeatures() & GF_8BIT_UNSIGNED_PCM) {	// older ITE demos
			rawFlags |= Audio::FLAG_UNSIGNED;
			rawFlags &= ~Audio::FLAG_16BITS;
		} else if (!uncompressedSound && !scumm_stricmp(context->fileName(), "voicesd.rsc")) {
			// Voice files in newer ITE demo versions are OKI ADPCM (VOX) encoded.
			resourceType = kSoundVOX;
		}
	}

	buffer.stream = 0;

	// Check for LE sounds
	if (!context->isBigEndian())
		rawFlags |= Audio::FLAG_LITTLE_ENDIAN;

	switch (resourceType) {
	case kSoundPCM: {
		// In ITE CD German, some voices are absent and contain just 5 zero bytes.
		// Round down to an even number when the audio is 16-bit so makeRawStream
		// will accept the data (needs to be an even size for 16-bit data).
		// See bug #1256701

		if ((soundResourceLength & 1) && (rawFlags & Audio::FLAG_16BITS))
			soundResourceLength &= ~1;

		Audio::SeekableAudioStream *audStream = Audio::makeRawStream(READ_STREAM(soundResourceLength), 22050, rawFlags);
		buffer.stream = audStream;
		buffer.streamLength = audStream->getLength();
		result = true;
		} break;
	case kSoundVOX:
		buffer.stream = Audio::makeADPCMStream(READ_STREAM(soundResourceLength), DisposeAfterUse::YES, soundResourceLength, Audio::kADPCMOki, 22050, 1);
		buffer.streamLength = Audio::Timestamp(0, soundResourceLength * 2, buffer.stream->getRate());
		result = true;
		break;
	case kSoundMacSND: {
		Audio::SeekableAudioStream *audStream = Audio::makeMacSndStream(READ_STREAM(soundResourceLength), DisposeAfterUse::YES);
		buffer.stream = audStream;
		buffer.streamLength = audStream->getLength();
		result = true;
		} break;
	case kSoundAIFF: {
		Audio::SeekableAudioStream *audStream = Audio::makeAIFFStream(READ_STREAM(soundResourceLength), DisposeAfterUse::YES);
		buffer.stream = audStream;
		buffer.streamLength = audStream->getLength();
		result = true;
		} break;
	case kSoundVOC: {
		Audio::SeekableAudioStream *audStream = Audio::makeVOCStream(READ_STREAM(soundResourceLength), Audio::FLAG_UNSIGNED, DisposeAfterUse::YES);
		buffer.stream = audStream;
		buffer.streamLength = audStream->getLength();
		result = true;
		} break;
	case kSoundWAV:
	case kSoundShorten:
		if (resourceType == kSoundWAV) {
			result = Audio::loadWAVFromStream(readS, size, rate, rawFlags);
#ifdef ENABLE_SAGA2
		} else if (resourceType == kSoundShorten) {
			result = loadShortenFromStream(readS, size, rate, rawFlags);
#endif
		}

		if (result) {
			Audio::SeekableAudioStream *audStream = Audio::makeRawStream(READ_STREAM(size), rate, rawFlags);
			buffer.stream = audStream;
			buffer.streamLength = audStream->getLength();
		}
		break;
	case kSoundMP3:
	case kSoundOGG:
	case kSoundFLAC: {
		readS.skip(9); // skip sfx header

		Audio::SeekableAudioStream *audStream = 0;
		Common::SeekableReadStream *memStream = READ_STREAM(soundResourceLength - 9);

		if (resourceType == kSoundMP3) {
#ifdef USE_MAD
			audStream = Audio::makeMP3Stream(memStream, DisposeAfterUse::YES);
#endif
		} else if (resourceType == kSoundOGG) {
#ifdef USE_VORBIS
			audStream = Audio::makeVorbisStream(memStream, DisposeAfterUse::YES);
#endif
		} else /* if (resourceType == kSoundFLAC) */ {
#ifdef USE_FLAC
			audStream = Audio::makeFLACStream(memStream, DisposeAfterUse::YES);
#endif
		}

		if (audStream) {
			buffer.stream = audStream;
			buffer.streamLength = audStream->getLength();
			result = true;
		} else {
			delete memStream;
		}

		} break;
	default:
		error("SndRes::load Unknown sound type");
	}

	if (_vm->getGameId() == GID_IHNM && _vm->isMacResources()) {
		delete file;
	}

	if (onlyHeader) {
		delete buffer.stream;
		buffer.stream = 0;
	}

	return result;
}
Example #16
0
void GhostRoom::loadPictures() {
	Common::File file;

	if (!file.open("spooky.avd"))
		error("AVALANCHE: GhostRoom: File not found: spooky.avd");

	file.seek(44);

	// Initializing ghost's array.
	for (int i = 0; i < 5; i++) {
		for (int j = 0; j < 2; j++) {
			for (int y = 0; y < 66; y++) {
				for (int x = 0; x < 26; x++)
					_ghost[i][j][y][x] = 0;
			}
		}
	}

	// Read in the pictures of the ghost.
	for (int i = 0; i < 5; i++) {
		ChunkBlock cb = readChunkBlock(file);
		for (int j = 0; j < 2; j++) {
			for (int y = 0; y <= cb._height; y++)
				file.read(_ghost[i][j][y], cb._width / 8);
		}
	}

	for (int i = 0; i < 2; i++)
		_eyes[i] = _vm->_graphics->ghostLoadPicture(file, dummyCoord);

	_exclamation = _vm->_graphics->ghostLoadPicture(file, dummyCoord);

	// Actually this function not just loads, but also draws the images, but they are part of the background
	// and they are need to be drawn only once.
	_vm->_graphics->ghostDrawBackgroundItems(file);

	for (int i = 0; i < 3; i++)
		_bat[i] = _vm->_graphics->ghostLoadPicture(file, dummyCoord);


	// Initializing glerk's array.
	for (int i = 0; i < 6; i++) {
		for (int j = 0; j < 4; j++) {
			for (int y = 0; y < 35; y++) {
				for (int x = 0; x < 9; x++)
					_glerk[i][j][y][x] = 0;
			}
		}
	}

	// Read in the pictures of the "glerk".
	for (int i = 0; i < 6; i++) {
		ChunkBlock cb = readChunkBlock(file);
		for (int j = 0; j < 4; j++) {
			for (int y = 0; y <= cb._height; y++)
				file.read(_glerk[i][j][y], cb._width / 8);
		}
	}

	for (int i = 0; i < 6; i++)
		_aargh[i] = _vm->_graphics->ghostLoadPicture(file, _aarghWhere[i]);

	for (int i = 0; i < 5; i++)
		_greenEyes[i] = _vm->_graphics->ghostLoadPicture(file, dummyCoord);

	for (int i = 0; i < 2; i++) {
		for (int j = 0; j < 6; j++)
			_greldet[j][i] = _vm->_graphics->ghostLoadPicture(file, dummyCoord);
	}

	file.close();
}
Example #17
0
bool FrotzMetaEngine::detectGames(const Common::FSList &fslist, DetectedGames &gameList) {
	const char *const EXTENSIONS[] = { ".z1", ".z2", ".z3", ".z4", ".z5", ".z6", ".z7", ".z8",
		".dat", ".zip", nullptr };

	// Loop through the files of the folder
	for (Common::FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) {
		// Check for a recognised filename
		if (file->isDirectory())
			continue;
		Common::String filename = file->getName();
		bool hasExt = Blorb::hasBlorbExt(filename), isBlorb = false;
		for (const char *const *ext = &EXTENSIONS[0]; *ext && !hasExt; ++ext)
			hasExt = filename.hasSuffixIgnoreCase(*ext);
		if (!hasExt)
			continue;

		// Open up the file and calculate the md5, and get the serial
		Common::File gameFile;
		if (!gameFile.open(*file))
			continue;
		Common::String md5 = Common::computeStreamMD5AsString(gameFile, 5000);
		size_t filesize = gameFile.size();
		char serial[9] = "";
		bool emptyBlorb = false;
		gameFile.seek(0);
		isBlorb = Blorb::isBlorb(gameFile, ID_ZCOD);

		if (!isBlorb) {
			if (Blorb::hasBlorbExt(filename)) {
				gameFile.close();
				continue;
			}
			gameFile.seek(18);
			strcpy(&serial[0], "\"");
			gameFile.read(&serial[1], 6);
			strcpy(&serial[7], "\"");
		} else {
			Blorb b(*file, INTERPRETER_FROTZ);
			Common::SeekableReadStream *f = b.createReadStreamForMember("game");
			emptyBlorb = f == nullptr;

			if (!emptyBlorb) {
				f->seek(18);
				strcpy(&serial[0], "\"");
				f->read(&serial[1], 6);
				strcpy(&serial[7], "\"");
				delete f;
			}
		}
		gameFile.close();

		// Check for known games. Note that there has been some variation in exact filesizes
		// for Infocom games due to padding at the end of files. So we match on md5s for the
		// first 5Kb, and only worry about filesize for more recent Blorb based Zcode games
		const FrotzGameDescription *p = FROTZ_GAMES;
		while (p->_gameId && p->_md5 && (md5 != p->_md5 ||
				(filesize != p->_filesize && isBlorb)))
			++p;

		DetectedGame gd;
		if (!p->_gameId) {
			// Generic .dat/.zip files don't get reported as matches unless they have a known md5
			if (filename.hasSuffixIgnoreCase(".dat") || filename.hasSuffixIgnoreCase(".zip") || emptyBlorb)
				continue;

			if (gDebugLevel > 0) {
				// Print an entry suitable for putting into the detection_tables.h, using the
				// name of the parent folder the game is in as the presumed game Id
				Common::String folderName = file->getParent().getName();
				if (folderName.hasSuffix("\\"))
					folderName.deleteLastChar();
				Common::String fname = filename;
				const char *dot = strchr(fname.c_str(), '.');
				if (dot)
					fname = Common::String(fname.c_str(), dot);

				debug("ENTRY0(\"%s\", %s, \"%s\", %u),",
					fname.c_str(), strlen(serial) ? serial : "nullptr", md5.c_str(), (uint)filesize);
			}
			const PlainGameDescriptor &desc = ZCODE_GAME_LIST[0];
			gd = DetectedGame(desc.gameId, desc.description, Common::UNK_LANG, Common::kPlatformUnknown);
		} else {
			GameDescriptor gameDesc = findGame(p->_gameId);
			gd = DetectedGame(p->_gameId, gameDesc._description, p->_language, Common::kPlatformUnknown, p->_extra);
			gd.setGUIOptions(p->_guiOptions);
		}

		gd.addExtraEntry("filename", filename);
		gameList.push_back(gd);
	}

	return !gameList.empty();
}
Example #18
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;
}
Example #19
0
void NDSFile::open(Common::File &file) const {
	if (!file.open(_fileName))
		throw Common::Exception(Common::kOpenError);
}
Example #20
0
    void loadKoreanStrings()
    {
        Common::File fp;
        char fname[128];
        
        strcpy(fname, "sub/");
        strcat(fname, _gameID);
        strcat(fname, ".dat");
        
        if(!fp.open(fname)) {
            warning("WARNING: Cannot load Korean V2 subtitle!, %s\n", fname);
            return;
//            strcpy(fname, "");
//            strcat(fname, _gameID);
//            strcat(fname, ".dat");
//                
//            if(!fp.open(fname)) {
//                warning("WARNING: Cannot load Korean V2 subtitle!, %s\n", fname);
//                return;
//            }
        }
        
        int k;
        char *buf = new char[1024];
        int len = 0;
        
        for(k = 0; !fp.eos(); k++) {
            FGETS(buf, 1023, fp);
            //printf("%d: <%s>\n", k+1, buf);
        }
        // 파일의 라인 수를 계산
        _numKLines = k;
        
        // memory size = file size
        k = fp.size();
        fp.seek(0, SEEK_SET);
        
        _KBuffer = new char *[_numKLines];
        //printf("_KBuffer size = %d\n", (int)k);
        _KBuffer[0] = new char[k];
        //printf("_KBuffer[0] = 0x%x\n", (int)_KBuffer[0]);
        
        for(int i = 0; i < _numKLines; i++) {
            FGETS(buf, 1023, fp);
            buf[1023] = 0;
            len = strlen(buf);
            //_KBuffer[i] = new char[strlen(buf) + 1]; //\0
            if (i > 0)
                _KBuffer[i] = _KBuffer[i-1] + strlen(_KBuffer[i-1])+1;
            if (len > 1000)
                warning("_KBuffer[%d]:%lx, len=%d\n", i, (long)_KBuffer[i], len);
            if(strlen(buf)) {
                strcpy(_KBuffer[i], buf);
                char *b = _KBuffer[i];
                if(b[strlen(b) - 1] == '\n' || b[strlen(b) - 1] == 0x0a || b[strlen(b) - 1] == 0x0d)
                    b[strlen(b) - 1] = 0;
                if(b[strlen(b) - 1] == '\n' || b[strlen(b) - 1] == 0x0a || b[strlen(b) - 1] == 0x0d)
                    b[strlen(b) - 1] = 0;
            } else
                _KBuffer[i][0] = 0;
        }
        fp.close();
        
        warning("Korean subtitle file loaded -- total %d lines, %ld bytes\n", _numKLines, _KBuffer[_numKLines-1]-_KBuffer[0]+len);
        
        delete[] buf;
        
        return;
    }
Example #21
0
/**
 * Loads and draws the chosen page of the help.
 * @remarks Originally called 'getme'
 */
void Help::switchPage(byte which) {
	// Help icons are 80x20.

	_highlightWas = 177; // Forget where the highlight was.

	Common::File file;

	if (!file.open("help.avd"))
		error("AVALANCHE: Help: File not found: help.avd");

	file.seek(which * 2);
	uint16 offset = file.readUint16LE();
	file.seek(offset);

	Common::String title = getLine(file);

	_vm->_graphics->drawFilledRectangle(Common::Rect(0, 0, 640, 200), kColorBlue);
	_vm->_graphics->drawFilledRectangle(Common::Rect(8, 40, 450, 200), kColorWhite);

	byte index = file.readByte();
	_vm->_graphics->helpDrawButton(-177, index);

	// Plot the title:
	_vm->_graphics->drawNormalText(title, _vm->_font, 8, 629 - 8 * title.size(), 26, kColorBlack);
	_vm->_graphics->drawNormalText(title, _vm->_font, 8, 630 - 8 * title.size(), 25, kColorCyan);

	_vm->_graphics->helpDrawBigText("help!", 549, 1, kColorBlack);
	_vm->_graphics->helpDrawBigText("help!", 550, 0, kColorCyan);

	byte y = 0;
	do {
		Common::String line = getLine(file);
		if (!line.empty()) {
			if (line.compareTo(Common::String('!')) == 0)  // End of the help text is signalled with a '!'.
				break;
			if (line[0] == '\\') {
				line.deleteChar(0);
				_vm->_graphics->drawNormalText(line, _vm->_font, 8, 16, 41 + y * 10, kColorRed);
			}
			else
				_vm->_graphics->drawNormalText(line, _vm->_font, 8, 16, 41 + y * 10, kColorBlack);
		}
		y++;
	} while (true);

	// We are now at the end of the text. Next we must read the icons:
	y = 0;
	_buttonNum = 0;
	while (!file.eos()) {
		int trigger = file.readByte();

		if (trigger == 177)
			break;
		switch (trigger) {
		case 254: // Escape
			trigger = 27;
			break;
		case 214: // PageUp
			trigger = 280;
			break;
		case 216: // PageDown
			trigger = 281;
			break;
		default: // A - Z
			// The characters are stored in the file in uppercase, but we need the lowercase versions for KeyCode:
			trigger = tolower(trigger);
			break;
		}

		_buttons[y]._trigger = Common::KeyCode(trigger);
		index = file.readByte();
		if (_buttons[y]._trigger != Common::KEYCODE_INVALID)
			_vm->_graphics->helpDrawButton(13 + (y + 1) * 27, index);
		_buttons[y]._whither = file.readByte(); // This is the position to jump to.

		Common::String text = "";
		switch (_buttons[y]._trigger) {
		case Common::KEYCODE_ESCAPE:
			text = Common::String("Esc");
			break;
		case Common::KEYCODE_PAGEUP:
			text = Common::String(24);
			break;
		case Common::KEYCODE_PAGEDOWN:
			text = Common::String(25);
			break;
		default:
			text = Common::String(toupper(_buttons[y]._trigger));
			break;
		}

		_vm->_graphics->helpDrawBigText(text, 589 - (text.size() * 8), 18 + (y + 1) * 27, kColorBlack);
		_vm->_graphics->helpDrawBigText(text, 590 - (text.size() * 8), 17 + (y + 1) * 27, kColorCyan);

		y++;
		_buttonNum++;
	}

	_vm->_graphics->refreshScreen();

	file.close();
}
Example #22
0
/**
 * Loads Hugo.dat file, which contains all the hardcoded data in the original executables
 */
bool HugoEngine::loadHugoDat() {
	Common::File in;
	in.open("hugo.dat");

	if (!in.isOpen()) {
		Common::String errorMessage = "You're missing the 'hugo.dat' file. Get it from the ScummVM website";
		GUIErrorMessage(errorMessage);
		warning("%s", errorMessage.c_str());
		return false;
	}

	// Read header
	char buf[4];
	in.read(buf, 4);

	if (memcmp(buf, "HUGO", 4)) {
		Common::String errorMessage = "File 'hugo.dat' is corrupt. Get it from the ScummVM website";
		GUIErrorMessage(errorMessage);
		return false;
	}

	int majVer = in.readByte();
	int minVer = in.readByte();

	if ((majVer != HUGO_DAT_VER_MAJ) || (minVer != HUGO_DAT_VER_MIN)) {
		Common::String errorMessage = Common::String::format("File 'hugo.dat' is wrong version. Expected %d.%d but got %d.%d. Get it from the ScummVM website", HUGO_DAT_VER_MAJ, HUGO_DAT_VER_MIN, majVer, minVer);
		GUIErrorMessage(errorMessage);
		return false;
	}

	_numVariant = in.readUint16BE();

	_screen->loadPalette(in);
	_screen->loadFontArr(in);
	_text->loadAllTexts(in);
	_intro->loadIntroData(in);
	_parser->loadArrayReqs(in);
	_parser->loadCatchallList(in);
	_parser->loadBackgroundObjects(in);
	_parser->loadCmdList(in);
	_mouse->loadHotspots(in);
	_inventory->loadInvent(in);
	_object->loadObjectUses(in);
	_object->loadObjectArr(in);
	_object->loadNumObj(in);
	_scheduler->loadPoints(in);
	_scheduler->loadScreenAct(in);
	_scheduler->loadActListArr(in);
	_scheduler->loadAlNewscrIndex(in);
	_hero = &_object->_objects[kHeroIndex];         // This always points to hero
	_screenPtr = &(_object->_objects[kHeroIndex]._screenIndex); // Current screen is hero's
	_heroImage = kHeroIndex;                        // Current in use hero image

	for (int varnt = 0; varnt < _numVariant; varnt++) {
		if (varnt == _gameVariant) {
			_tunesNbr     = in.readSByte();
			_soundSilence = in.readSByte();
			_soundTest    = in.readSByte();
		} else {
			in.readSByte();
			in.readSByte();
			in.readSByte();
		}
	}

	int numElem;

	//Read _defltTunes
	for (int varnt = 0; varnt < _numVariant; varnt++) {
		numElem = in.readUint16BE();
		if (varnt == _gameVariant) {
			_defltTunes = (int16 *)malloc(sizeof(int16) * numElem);
			for (int i = 0; i < numElem; i++)
				_defltTunes[i] = in.readSint16BE();
		} else {
			for (int i = 0; i < numElem; i++)
				in.readSint16BE();
		}
	}

	//Read _screenStates size
	for (int varnt = 0; varnt < _numVariant; varnt++) {
		numElem = in.readUint16BE();
		if (varnt == _gameVariant) {
			_numStates = numElem;
			_screenStates = (byte *)malloc(sizeof(byte) * numElem);
			memset(_screenStates, 0, sizeof(byte) * numElem);
		}
	}

	//Read look, take and drop special verbs indexes
	for (int varnt = 0; varnt < _numVariant; varnt++) {
		if (varnt == _gameVariant) {
			_look = in.readUint16BE();
			_take = in.readUint16BE();
			_drop = in.readUint16BE();
		} else {
			in.readUint16BE();
			in.readUint16BE();
			in.readUint16BE();
		}
	}

	_sound->loadIntroSong(in);
	_topMenu->loadBmpArr(in);

	return true;
}
Example #23
0
/**
 * Fallback detection scans the list of Discworld 2 targets to see if it can detect an installation
 * where the files haven't been renamed (i.e. don't have the '1' just before the extension)
 */
const ADGameDescription *TinselMetaEngine::fallbackDetect(const Common::FSList &fslist) const {
	Common::String extra;
	FileMap allFiles;
	SizeMD5Map filesSizeMD5;

	const ADGameFileDescription *fileDesc;
	const Tinsel::TinselGameDescription *g;

	if (fslist.empty())
		return NULL;

	// TODO: The following code is essentially a slightly modified copy of the
	// complete code of function detectGame() in engines/advancedDetector.cpp.
	// That quite some hefty and undesirable code duplication. Its only purpose
	// seems to be to treat filenames of the form "foo1.ext" as "foo.ext".
	// It would be nice to avoid this code duplication.

	// First we compose a hashmap of all files in fslist.
	for (Common::FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) {
		if (file->isDirectory()) {
			if (!scumm_stricmp(file->getName().c_str(), "dw2")) {
				// Probably Discworld 2 subfolder on CD, so add it's contents as well
				Common::FSList files;
				if (file->getChildren(files, Common::FSNode::kListAll)) {
					Common::FSList::const_iterator file2;
					for (file2 = files.begin(); file2 != files.end(); ++file2) {
						if (file2->isDirectory())
							continue;

						Common::String fname = file2->getName();
						allFiles[fname] = *file2;
					}
				}
			}
			continue;
		}

		Common::String tstr = file->getName();

		allFiles[tstr] = *file;	// Record the presence of this file
	}

	// Check which files are included in some dw2 ADGameDescription *and* present
	// in fslist without a '1' suffix character. Compute MD5s and file sizes for these files.
	for (g = &Tinsel::gameDescriptions[0]; g->desc.gameid != 0; ++g) {
		if (strcmp(g->desc.gameid, "dw2") != 0)
			continue;

		for (fileDesc = g->desc.filesDescriptions; fileDesc->fileName; fileDesc++) {
			// Get the next filename, stripping off any '1' suffix character
			char tempFilename[50];
			strcpy(tempFilename, fileDesc->fileName);
			char *pOne = strchr(tempFilename, '1');
			if (pOne) {
				do {
					*pOne = *(pOne + 1);
					pOne++;
				} while (*pOne);
			}

			Common::String fname(tempFilename);
			if (allFiles.contains(fname) && !filesSizeMD5.contains(fname)) {
				SizeMD5 tmp;
				Common::File testFile;

				if (testFile.open(allFiles[fname])) {
					tmp.size = (int32)testFile.size();
					tmp.md5 = computeStreamMD5AsString(testFile, detectionParams.md5Bytes);
				} else {
					tmp.size = -1;
				}

				filesSizeMD5[fname] = tmp;
			}
		}
	}

	ADGameDescList matched;
	int maxFilesMatched = 0;

	// MD5 based matching
	for (g = &Tinsel::gameDescriptions[0]; g->desc.gameid != 0; ++g) {
		if (strcmp(g->desc.gameid, "dw2") != 0)
			continue;

		bool fileMissing = false;

		if ((detectionParams.flags & kADFlagUseExtraAsHint) && !extra.empty() && g->desc.extra != extra)
			continue;

		bool allFilesPresent = true;

		// Try to match all files for this game
		for (fileDesc = g->desc.filesDescriptions; fileDesc->fileName; fileDesc++) {
			// Get the next filename, stripping off any '1' suffix character
			char tempFilename[50];
			strcpy(tempFilename, fileDesc->fileName);
			char *pOne = strchr(tempFilename, '1');
			if (pOne) {
				do {
					*pOne = *(pOne + 1);
					pOne++;
				} while (*pOne);
			}

			Common::String tstr(tempFilename);

			if (!filesSizeMD5.contains(tstr)) {
				fileMissing = true;
				allFilesPresent = false;
				break;
			}

			if (fileDesc->md5 != NULL && fileDesc->md5 != filesSizeMD5[tstr].md5) {
				fileMissing = true;
				break;
			}

			if (fileDesc->fileSize != -1 && fileDesc->fileSize != filesSizeMD5[tstr].size) {
				fileMissing = true;
				break;
			}
		}

		if (!fileMissing) {
			// Count the number of matching files. Then, only keep those
			// entries which match a maximal amount of files.
			int curFilesMatched = 0;
			for (fileDesc = g->desc.filesDescriptions; fileDesc->fileName; fileDesc++)
				curFilesMatched++;

			if (curFilesMatched > maxFilesMatched) {
				maxFilesMatched = curFilesMatched;

				matched.clear();	// Remove any prior, lower ranked matches.
				matched.push_back((const ADGameDescription *)g);
			} else if (curFilesMatched == maxFilesMatched) {
				matched.push_back((const ADGameDescription *)g);
			}
		}
	}

	// We didn't find a match
	if (matched.empty())
		return NULL;

	return *matched.begin();
}
Example #24
0
Common::ErrorCode Blorb::load() {
	// First, chew through the file and index the chunks
	Common::File f;
	if (!f.open(_filename) || f.size() < 12)
		return Common::kReadingFailed;

	if (f.readUint32BE() != ID_FORM)
		return Common::kReadingFailed;
	f.readUint32BE();
	if (f.readUint32BE() != ID_IFRS)
		return Common::kReadingFailed;
	if (f.readUint32BE() != ID_RIdx)
		return Common::kReadingFailed;

	f.readUint32BE();
	uint count = f.readUint32BE();

	// First read in the resource index
	for (uint idx = 0; idx < count; ++idx) {
		ChunkEntry ce;
		ce._type = f.readUint32BE();
		ce._number = f.readUint32BE();
		ce._offset = f.readUint32BE();

		_chunks.push_back(ce);
	}

	// Further iterate through the resources
	for (uint idx = 0; idx < _chunks.size(); ++idx) {
		ChunkEntry &ce = _chunks[idx];
		f.seek(ce._offset);
		ce._offset += 8;

		ce._id = f.readUint32BE();
		ce._size = f.readUint32BE();

		if (ce._type == ID_Pict) {
			ce._filename = Common::String::format("pic%u", ce._number);
			if (ce._id == ID_JPEG)
				ce._filename += ".jpg";
			else if (ce._id == ID_PNG)
				ce._filename += ".png";
			else if (ce._id == ID_Rect)
				ce._filename += ".rect";

		} else if (ce._type == ID_Snd) {
			ce._filename = Common::String::format("sound%u", ce._number);
			if (ce._id == ID_MIDI)
				ce._filename += ".midi";
			else if (ce._id == ID_MP3)
				ce._filename += ".mp3";
			else if (ce._id == ID_WAVE)
				ce._filename += ".wav";
			else if (ce._id == ID_AIFF || ce._id == ID_FORM)
				ce._filename += ".aiff";
			else if (ce._id == ID_OGG)
				ce._filename += ".ogg"; 
			else if (ce._id == ID_MOD)
				ce._filename += ".mod";

		} else if (ce._type == ID_Data) {
			ce._filename = Common::String::format("data%u", ce._number);

		} else if (ce._type == ID_Exec) {
			char buffer[5];
			WRITE_BE_UINT32(buffer, ce._id);
			buffer[4] = '\0';
			Common::String type(buffer);

			if (
				(_interpType == INTERPRETER_FROTZ && type == "ZCOD") ||
				(_interpType == INTERPRETER_GLULXE && type == "GLUL") ||
				(_interpType == INTERPRETER_TADS2 && type == "TAD2") ||
				(_interpType == INTERPRETER_TADS3 && type == "TAD3") ||
				(_interpType == INTERPRETER_HUGO && type == "HUGO")
			) {
				// Game executable
				ce._filename = "game";
			} else {
				ce._filename = type;
			}
		}
	}

	return Common::kNoError;
}
Example #25
0
bool PatchedFile::load(Common::SeekableReadStream *file, const Common::String &patchName) {
	uint8 md5_p[16], md5_f[16];
	uint32 zctrllen, zdatalen, zextralen;
	Common::File patch;

	_patchName = patchName;

	// Open the patch
	if (!patch.open(_patchName)) {
		error("Unable to open patchfile %s", _patchName.c_str());
		return false;
	}

	// Check for appropriate signature
	if (patch.readUint32BE() != MKTAG('P','A','T','R')) {
		error("%s patchfile is corrupted", _patchName.c_str());
		return false;
	}

	// Check the version number
	if (patch.readUint16LE() != _kVersionMajor || patch.readUint16LE() > _kVersionMinor) {
		error("%s has a wrong version number (must be major = %d, minor <= %d)", _patchName.c_str(), _kVersionMajor, _kVersionMinor);
		return false;
	}

	_flags = patch.readUint32LE();

	// Check if the file to patch match
	Common::computeStreamMD5(*file, md5_f, _kMd5size);
	file->seek(0, SEEK_SET);
	patch.read(md5_p, 16);
	if (memcmp(md5_p, md5_f, 16) != 0 || (uint32)file->size() != patch.readUint32LE()) {
		Debug::debug(Debug::Patchr,"%s targets a different file", _patchName.c_str());
		return false;
	}

	// Read lengths from header
	_newSize = patch.readUint32LE();
	zctrllen = patch.readUint32LE();
	zdatalen = patch.readUint32LE();
	zextralen = patch.readUint32LE();

	patch.close();

	// Opens ctrl, diff and extra substreams
	Common::File *tmp;
	tmp = new Common::File;
	tmp->open(_patchName);
	_ctrl = new Common::SeekableSubReadStream(tmp, _kHeaderSize, _kHeaderSize + zctrllen, DisposeAfterUse::YES);
	if (_flags & FLAG_COMPRESS_CTRL)
		_ctrl = Common::wrapCompressedReadStream(_ctrl);

	//ctrl stream sanity checks
	if (_ctrl->size() % (3 * sizeof(uint32)) != 0) {
		error("%s patchfile is corrupted", _patchName.c_str());
		return false;
	}

	instrLeft = _ctrl->size() / (3 * sizeof(uint32));

	tmp = new Common::File;
	tmp->open(_patchName);
	_diff = new Common::SeekableSubReadStream(tmp, _kHeaderSize + zctrllen, _kHeaderSize + zctrllen + zdatalen, DisposeAfterUse::YES);
	_diff = Common::wrapCompressedReadStream(_diff);

	if (_flags & FLAG_MIX_DIFF_EXTRA)
		_extra = _diff;
	else {
		tmp = new Common::File;
		tmp->open(_patchName);
		_extra = new Common::SeekableSubReadStream(tmp, _kHeaderSize + zctrllen + zdatalen, _kHeaderSize + zctrllen + zdatalen + zextralen, DisposeAfterUse::YES);
		_extra = Common::wrapCompressedReadStream(_extra);
	}

	_file = file;

	readNextInst();

	return true;
}
Example #26
0
void Screen::rollCredits() {
	uint32 loopingMusicId = _vm->_sound->getLoopingMusicId();

	// Prepare for the credits by fading down, stoping the music, etc.

	_vm->_mouse->setMouse(0);

	_vm->_sound->muteFx(true);
	_vm->_sound->muteSpeech(true);

	waitForFade();
	fadeDown();
	waitForFade();

	_vm->_mouse->closeMenuImmediately();

	// There are three files which I believe are involved in showing the
	// credits:
	//
	// credits.bmp  - The "Smacker" logo, stored as follows:
	//
	//     width     2 bytes, little endian
	//     height    2 bytes, little endian
	//     palette   3 * 256 bytes
	//     data      width * height bytes
	//
	//     Note that the maximum colour component in the palette is 0x3F.
	//     This is the same resolution as the _paletteMatch table. I doubt
	//     that this is a coincidence, but let's use the image palette
	//     directly anyway, just to be safe.
	//
	// credits.clu  - The credits text (credits.txt in PSX version)
	//
	//     This is simply a text file with CRLF line endings.
	//     '^' is not shown, but used to mark the center of the line.
	//     '@' is used as a placeholder for the "Smacker" logo. At least
	//     when it appears alone.
	//     Remaining lines are centered.
	//     The German version also contains character code 9 for no
	//     apparent reason. We ignore them.
	//
	// fonts.clu    - The credits font?
	//
	//     FIXME: At this time I don't know how to interpret fonts.clu. For
	//     now, let's just the standard speech font instead.

	SpriteInfo spriteInfo;
	Common::File f;
	int i;

	spriteInfo.isText = false;

	// Read the "Smacker" logo

	uint16 logoWidth = 0;
	uint16 logoHeight = 0;
	byte *logoData = NULL;
	byte palette[256 * 3];

	if (f.open("credits.bmp")) {
		logoWidth = f.readUint16LE();
		logoHeight = f.readUint16LE();

		for (i = 0; i < 256; i++) {
			palette[i * 3 + 0] = f.readByte() << 2;
			palette[i * 3 + 1] = f.readByte() << 2;
			palette[i * 3 + 2] = f.readByte() << 2;
		}

		logoData = (byte *)malloc(logoWidth * logoHeight);

		f.read(logoData, logoWidth * logoHeight);
		f.close();
	} else {
		warning("Can't find credits.bmp");
		memset(palette, 0, sizeof(palette));
		palette[14 * 3 + 0] = 252;
		palette[14 * 3 + 1] = 252;
		palette[14 * 3 + 2] = 252;
	}

	setPalette(0, 256, palette, RDPAL_INSTANT);

	// Read the credits text

	Common::Array<CreditsLine *> creditsLines;

	int lineCount = 0;
	int lineTop = 400;
	int paragraphStart = 0;
	bool hasCenterMark = false;

	if (Sword2Engine::isPsx()) {
		if (!f.open("credits.txt")) {
			warning("Can't find credits.txt");

			free(logoData);
			return;
		}
	} else {
		if (!f.open("credits.clu")) {
			warning("Can't find credits.clu");

			free(logoData);
			return;
		}
	}

	while (1) {
		char buffer[80];
		char *line = f.readLine(buffer, sizeof(buffer));

		if (line) {
			// Replace invalid character codes prevent the 'dud'
			// symbol from showing up in the credits.

			for (byte *ptr = (byte *)line; *ptr; ptr++) {
				switch (*ptr) {
				case 9:
					// The German credits contain these.
					// Convert them to spaces.
					*ptr = 32;
					break;
				case 10:
					// LF is treated as end of line.
					*ptr = 0;
					break;
				case 170:
					// The Spanish credits contain these.
					// Convert them to periods.
					*ptr = '.';
				default:
					break;
				}
			}
		}

		if (!line || *line == 0) {
			if (!hasCenterMark) {
				for (i = paragraphStart; i < lineCount; i++)
					creditsLines[i]->type = LINE_CENTER;
			}
			paragraphStart = lineCount;
			hasCenterMark = false;
			if (paragraphStart == lineCount)
				lineTop += CREDITS_LINE_SPACING;

			if (!line)
				break;

			continue;
		}

		char *center_mark = strchr(line, '^');

		if (center_mark) {
			// The current paragraph has at least one center mark.
			hasCenterMark = true;

			if (center_mark != line) {
				creditsLines.push_back(new CreditsLine);

				// The center mark is somewhere inside the
				// line. Split it into left and right side.
				*center_mark = 0;

				creditsLines[lineCount]->top = lineTop;
				creditsLines[lineCount]->height = CREDITS_FONT_HEIGHT;
				creditsLines[lineCount]->type = LINE_LEFT;
				creditsLines[lineCount]->str = strdup(line);

				lineCount++;
				*center_mark = '^';
			}

			line = center_mark;
		}

		creditsLines.push_back(new CreditsLine);

		creditsLines[lineCount]->top = lineTop;

		if (*line == '^') {
			creditsLines[lineCount]->type = LINE_RIGHT;
			line++;
		} else
			creditsLines[lineCount]->type = LINE_LEFT;

		if (strcmp(line, "@") == 0) {
			creditsLines[lineCount]->height = logoHeight;
			lineTop += logoHeight;
		} else {
			creditsLines[lineCount]->height = CREDITS_FONT_HEIGHT;
			lineTop += CREDITS_LINE_SPACING;
		}

		creditsLines[lineCount]->str = strdup(line);
		lineCount++;
	}

	f.close();

	// We could easily add some ScummVM stuff to the credits, if we wanted
	// to. On the other hand, anyone with the attention span to actually
	// read all the credits probably already knows. :-)

	// Start the music and roll the credits

	// The credits music (which can also be heard briefly in the "carib"
	// cutscene) is played once.

	_vm->_sound->streamCompMusic(309, false);

	clearScene();
	fadeUp(0);

	spriteInfo.scale = 0;
	spriteInfo.scaledWidth = 0;
	spriteInfo.scaledHeight = 0;
	spriteInfo.type = RDSPR_DISPLAYALIGN | RDSPR_NOCOMPRESSION | RDSPR_TRANS;
	spriteInfo.blend = 0;

	int startLine = 0;
	int scrollPos = 0;

	bool abortCredits = false;

	int scrollSteps = lineTop + CREDITS_FONT_HEIGHT;
	uint32 musicStart = getTick();

	// Ideally the music should last just a tiny bit longer than the
	// credits. Note that musicTimeRemaining() will return 0 if the music
	// is muted, so we need a sensible fallback for that case.

	uint32 musicLength = MAX((int32)(1000 * (_vm->_sound->musicTimeRemaining() - 3)), 25 * (int32)scrollSteps);

	while (scrollPos < scrollSteps && !_vm->shouldQuit()) {
		clearScene();

		for (i = startLine; i < lineCount; i++) {
			if (!creditsLines[i])
				continue;

			// Free any sprites that have scrolled off the screen

			if (creditsLines[i]->top + creditsLines[i]->height < scrollPos) {
				debug(2, "Freeing line %d: '%s'", i, creditsLines[i]->str);

				delete creditsLines[i];
				creditsLines[i] = NULL;

				startLine = i + 1;
			} else if (creditsLines[i]->top < scrollPos + 400) {
				if (!creditsLines[i]->sprite) {
					debug(2, "Creating line %d: '%s'", i, creditsLines[i]->str);
					creditsLines[i]->sprite = _vm->_fontRenderer->makeTextSprite((byte *)creditsLines[i]->str, 600, 14, _vm->_speechFontId, 0);
				}

				FrameHeader frame;

				frame.read(creditsLines[i]->sprite);

				spriteInfo.y = creditsLines[i]->top - scrollPos;
				spriteInfo.w = frame.width;
				spriteInfo.h = frame.height;
				spriteInfo.data = creditsLines[i]->sprite + FrameHeader::size();
				spriteInfo.isText = true;

				switch (creditsLines[i]->type) {
				case LINE_LEFT:
					spriteInfo.x = RENDERWIDE / 2 - 5 - frame.width;
					break;
				case LINE_RIGHT:
					spriteInfo.x = RENDERWIDE / 2 + 5;
					break;
				case LINE_CENTER:
					if (strcmp(creditsLines[i]->str, "@") == 0) {
						spriteInfo.data = logoData;
						spriteInfo.x = (RENDERWIDE - logoWidth) / 2;
						spriteInfo.w = logoWidth;
						spriteInfo.h = logoHeight;
					} else
						spriteInfo.x = (RENDERWIDE - frame.width) / 2;
					break;
				}

				if (spriteInfo.data)
					drawSprite(&spriteInfo);
			} else
				break;
		}

		updateDisplay();

		KeyboardEvent *ke = _vm->keyboardEvent();

		if (ke && ke->kbd.keycode == Common::KEYCODE_ESCAPE) {
			if (!abortCredits) {
				abortCredits = true;
				fadeDown();
			}
		}

		if (abortCredits && getFadeStatus() == RDFADE_BLACK)
			break;

		_vm->sleepUntil(musicStart + (musicLength * scrollPos) / scrollSteps + _pauseTicks);
		scrollPos++;
	}

	// We're done. Clean up and try to put everything back where it was
	// before the credits.

	for (i = 0; i < lineCount; i++) {
		delete creditsLines[i];
	}

	free(logoData);

	if (!abortCredits) {
		fadeDown();

		// The music should either have stopped or be about to stop, so
		// wait for it to really happen.

		while (_vm->_sound->musicTimeRemaining() && !_vm->shouldQuit()) {
			updateDisplay(false);
			_vm->_system->delayMillis(100);
		}
	}

	if (_vm->shouldQuit())
		return;

	waitForFade();

	_vm->_sound->muteFx(false);
	_vm->_sound->muteSpeech(false);

	if (loopingMusicId)
		_vm->_sound->streamCompMusic(loopingMusicId, true);
	else
		_vm->_sound->stopMusic(false);

	if (!_vm->_mouse->getMouseStatus() || _vm->_mouse->isChoosing())
		_vm->_mouse->setMouse(NORMAL_MOUSE_ID);

	if (_vm->_logic->readVar(DEAD))
		_vm->_mouse->buildSystemMenu();
}
Example #27
0
bool WinFont::loadFromFNT(const Common::String &fileName) {
	Common::File file;

	return file.open(fileName) && loadFromFNT(file);
}
Example #28
0
/**
 * Plays an animated cutscene.
 * @param id the id of the file
 */
bool MoviePlayer::load(uint32 id) {
	Common::File f;
	Common::String filename;

	if (_decoderType == kVideoDecoderDXA)
		_bgSoundStream = Audio::SeekableAudioStream::openStreamFile(sequenceList[id]);
	else
		_bgSoundStream = NULL;

	if (SwordEngine::_systemVars.showText) {
		filename = Common::String::format("%s.txt", sequenceList[id]);
		if (f.open(filename)) {
			Common::String line;
			int lineNo = 0;
			int lastEnd = -1;

			_movieTexts.clear();
			while (!f.eos() && !f.err()) {
				line = f.readLine();
				lineNo++;
				if (line.empty() || line[0] == '#') {
					continue;
				}

				const char *ptr = line.c_str();

				// TODO: Better error handling
				int startFrame = strtoul(ptr, const_cast<char **>(&ptr), 10);
				int endFrame = strtoul(ptr, const_cast<char **>(&ptr), 10);

				while (*ptr && Common::isSpace(*ptr))
					ptr++;

				if (startFrame > endFrame) {
					warning("%s:%d: startFrame (%d) > endFrame (%d)", filename.c_str(), lineNo, startFrame, endFrame);
					continue;
				}

				if (startFrame <= lastEnd) {
					warning("%s:%d startFrame (%d) <= lastEnd (%d)", filename.c_str(), lineNo, startFrame, lastEnd);
					continue;
				}
				
				int color = 0;
				if (*ptr == '@') {
					++ptr;
					color = strtoul(ptr, const_cast<char **>(&ptr), 10);
					while (*ptr && Common::isSpace(*ptr))
						ptr++;
				} 

				_movieTexts.push_back(MovieText(startFrame, endFrame, ptr, color));
				lastEnd = endFrame;
			}
			f.close();
		}
	}

	switch (_decoderType) {
	case kVideoDecoderDXA:
		filename = Common::String::format("%s.dxa", sequenceList[id]);
		break;
	case kVideoDecoderSMK:
		filename = Common::String::format("%s.smk", sequenceList[id]);
		break;
	case kVideoDecoderPSX:
		filename = Common::String::format("%s.str", (_vm->_systemVars.isDemo) ? sequenceList[id] : sequenceListPSX[id]);

		// Need to switch to true color
		initGraphics(g_system->getWidth(), g_system->getHeight(), true, 0);

		// Need to load here in case it fails in which case we'd need
		// to go back to paletted mode
		if (_decoder->loadFile(filename)) {
			return true;
		} else {
			initGraphics(g_system->getWidth(), g_system->getHeight(), true);
			return false;
		}
		break;
	}

	return _decoder->loadFile(filename.c_str());
}
Example #29
0
bool Sword2Engine::initStartMenu() {
	// Print out a list of all the start points available.
	// There should be a linc produced file called startup.txt.
	// This file should contain ascii numbers of all the resource game
	// objects that are screen managers.
	// We query each in turn and setup an array of start structures.
	// If the file doesn't exist then we say so and return a 0.

	Common::File fp;

	// ok, load in the master screen manager file

	_totalStartups = 0;
	_totalScreenManagers = 0;

	if (!fp.open("startup.inf")) {
		warning("Cannot open startup.inf - the debugger won't have a start menu");
		return false;
	}

	// The startup.inf file which contains a list of all the files. Now
	// extract the filenames

	int start_ids[MAX_starts];
	int lineno = 0;

	while (!fp.eos() && !fp.err()) {
		Common::String line = fp.readLine();

		// Skip empty lines or, more likely, the end of the stream.
		if (line.size() == 0)
			continue;

		char *errptr;
		int id;

		lineno++;
		id = strtol(line.c_str(), &errptr, 10);

		if (*errptr) {
			warning("startup.inf:%d: Invalid string '%s'", lineno, line.c_str());
			continue;
		}

		if (!_resman->checkValid(id)) {
			warning("startup.inf:%d: Invalid resource %d", lineno, id);
			continue;
		}

		if (_resman->fetchType(id) != SCREEN_MANAGER) {
			warning("startup.inf:%d: '%s' (%d) is not a screen manager", lineno, _resman->fetchName(id), id);
			continue;
		}

		start_ids[_totalScreenManagers] = id;

		if (++_totalScreenManagers >= MAX_starts) {
			warning("Too many entries in startup.inf");
			break;
		}
	}

	// An I/O error before EOS? That's bad, but this is not a vital file.
	if (fp.err() && !fp.eos())
		warning("I/O error while reading startup.inf");

	fp.close();

	// Using this method the Gode generated resource.inf must have #0d0a
	// on the last entry

	debug(1, "%d screen manager objects", _totalScreenManagers);

	// Open each object and make a query call. The object must fill in a
	// startup structure. It may fill in several if it wishes - for
	// instance a startup could be set for later in the game where
	// specific vars are set

	for (uint i = 0; i < _totalScreenManagers; i++) {
		_startRes = start_ids[i];

		debug(2, "Querying screen manager %d", _startRes);

		// Open each one and run through the interpreter. Script 0 is
		// the query request script. We have already made reasonably
		// sure the resource is ok.

		_logic->runResScript(_startRes, 0);
	}

	return 1;
}
Example #30
0
/**
 * Search file in Cat file
 */
byte *FileManager::searchCat(const Common::String &file, CatMode mode, bool &fileFoundFl) {
	byte *ptr = NULL;
	fileFoundFl = true;
	Common::File f;

	Common::String filename = file;
	Common::String secondaryFilename = "";
	filename.toUppercase();

	switch (mode) {
	case RES_INI:
		if (!f.exists("RES_INI.CAT")) {
			fileFoundFl = false;
			return NULL;
		}

		ptr = loadFile("RES_INI.CAT");
		secondaryFilename = "RES_INI.RES";
		break;

	case RES_REP:
		if (!f.exists("RES_REP.CAT")) {
			fileFoundFl = false;
			return NULL;
		}

		ptr = loadFile("RES_REP.CAT");
		secondaryFilename = "RES_REP.RES";
		break;

	case RES_LIN:
		if (!f.exists("RES_LIN.CAT")) {
			fileFoundFl = false;
			return NULL;
		}

		ptr = loadFile("RES_LIN.CAT");
		secondaryFilename = "RES_LIN.RES";
		break;

	case RES_PER:
		if (!f.exists("RES_PER.CAT")) {
			fileFoundFl = false;
			return NULL;
		}

		ptr = loadFile("RES_PER.CAT");
		secondaryFilename = "RES_PER.RES";
		break;

	case RES_PIC:
		if (!f.exists("PIC.CAT")) {
			fileFoundFl = false;
			return NULL;
		}

		ptr = loadFile("PIC.CAT");
		break;

	case RES_SAN:
		if (!f.exists("RES_SAN.CAT")) {
			fileFoundFl = false;
			return NULL;
		}

		ptr = loadFile("RES_SAN.CAT");
		break;

	case RES_SLI:
		if (!f.exists("RES_SLI.CAT")) {
			fileFoundFl = false;
			return NULL;
		}

		ptr = loadFile("RES_SLI.CAT");
		break;

	case RES_VOI: {
		Common::String tmpFilename;
		if (_vm->getPlatform() == Common::kPlatformOS2 || _vm->getPlatform() == Common::kPlatformBeOS)
			tmpFilename = "ENG_VOI.CAT";
		// Win95 and Linux versions uses another set of names
		else {
			switch (_vm->_globals->_language) {
			case LANG_EN:
				tmpFilename = "RES_VAN.CAT";
				break;
			case LANG_FR:
				tmpFilename = "RES_VFR.CAT";
				break;
			case LANG_SP:
				tmpFilename = "RES_VES.CAT";
				break;
			}
		}

		if (!f.exists(tmpFilename)) {
			fileFoundFl = false;
			return NULL;
		}

		ptr = loadFile(tmpFilename);
		break;
		}

	default:
		break;
	}

	// Scan for an entry in the catalogue
	byte *result;
	bool matchFlag = false;
	int offsetVal = 0;

	while (!matchFlag) {
		Common::String name = (const char *)ptr + offsetVal;

		if (name == filename) {
			// Found entry for file, so get it's details from the catalogue entry
			const byte *pData = ptr + offsetVal;
			_catalogPos = READ_LE_UINT32(pData + 15);
			_catalogSize = READ_LE_UINT32(pData + 19);
			matchFlag = true;
		}

		if (name == "FINIS") {
			_vm->_globals->freeMemory(ptr);
			fileFoundFl = false;
			return NULL;
		}

		offsetVal += 23;
	}

	_vm->_globals->freeMemory(ptr);

	if (secondaryFilename != "") {
		if (!f.open(secondaryFilename))
			error("CHARGE_FICHIER");

		f.seek(_catalogPos);

		byte *catData = _vm->_globals->allocMemory(_catalogSize);
		if (catData == g_PTRNUL)
			error("CHARGE_FICHIER");

		readStream(f, catData, _catalogSize);
		f.close();
		result = catData;
	} else {
		result = NULL;
	}

	return result;
}