Exemplo n.º 1
0
bool Resource::readTableFile(const GameVersion *gameVersion) {
	Common::File tableFile;
	tableFile.open(_tableFilename);
	if (tableFile.isOpen() && tableFile.readUint32BE() == 'QTBL') {
		if (tableFile.readUint32BE() != CURRENT_TBL_VERSION)
			warning("Incorrect version of queen.tbl, please update it");
		tableFile.seek(gameVersion->tableOffset);
		readTableEntries(&tableFile);
		return true;
	}
	return false;
}
Exemplo n.º 2
0
void ExtractCine::unpackFile(Common::File &file) {
	char fileName[15];

	unsigned int entryCount = file.readUint16BE(); // How many entries?
	unsigned int entrySize = file.readUint16BE(); // How many bytes per entry?
	assert(entrySize == 0x1e);
	while (entryCount--) {
		file.read_throwsOnError(fileName, 14);
		fileName[14] = '\0';

		Common::Filename outPath(_outputPath);
		outPath.setFullName(fileName);

		uint32 offset = file.readUint32BE();
		unsigned int packedSize = file.readUint32BE();
		unsigned int unpackedSize = file.readUint32BE();
		// Skip one
		file.readUint32BE();
		unsigned int savedPos = file.pos();

		print("unpacking '%s' ... ", outPath.getFullName().c_str());

		Common::File fpOut(outPath, "wb");

		file.seek(offset, SEEK_SET);
		assert(unpackedSize >= packedSize);
		uint8 *data = (uint8 *)calloc(unpackedSize, 1);
		uint8 *packedData = (uint8 *)calloc(packedSize, 1);
		assert(data);
		assert(packedData);
		file.read_throwsOnError(packedData, packedSize);
		bool status = true;
		if (packedSize != unpackedSize) {
			CineUnpacker cineUnpacker;
			status = cineUnpacker.unpack(packedData, packedSize, data, unpackedSize);
		} else {
			memcpy(data, packedData, packedSize);
		}
		free(packedData);
		fpOut.write(data, unpackedSize);
		free(data);

		if (!status) {
			print("CRC ERROR");
		} else {
			print("ok");
		}
		print(", packedSize %u unpackedSize %u", packedSize, unpackedSize);
		file.seek(savedPos, SEEK_SET);
	}
}
Exemplo n.º 3
0
void SoundHE::setupHEMusicFile() {
	int i, total_size;
	Common::File musicFile;
	Common::String buf(_vm->generateFilename(-4));

	if (musicFile.open(buf) == true) {
		musicFile.seek(4, SEEK_SET);
		total_size = musicFile.readUint32BE();
		musicFile.seek(16, SEEK_SET);
		_heMusicTracks = musicFile.readUint32LE();
		debug(5, "Total music tracks %d", _heMusicTracks);

		int musicStart = (_vm->_game.heversion >= 80) ? 56 : 20;
		musicFile.seek(musicStart, SEEK_SET);

		_heMusic = (HEMusic *)malloc((_heMusicTracks + 1) * sizeof(HEMusic));
		for (i = 0; i < _heMusicTracks; i++) {
			_heMusic[i].id = musicFile.readUint32LE();
			_heMusic[i].offset = musicFile.readUint32LE();
			_heMusic[i].size = musicFile.readUint32LE();

			if (_vm->_game.heversion >= 80) {
				musicFile.seek(+9, SEEK_CUR);
			} else {
				musicFile.seek(+13, SEEK_CUR);
			}
		}

		musicFile.close();
	}
}
Exemplo n.º 4
0
/**
 * Opens a file and loads a sound effect.
 *
 * @param fileName         Sfx filename
 *
 * @returns                True is everything is OK, False otherwise
 */
bool FPSfx::loadFile(const char *fileName) {
	if (!_soundSupported)
		return true;

	SoundCodecs codec = FPCODEC_UNKNOWN;

	Common::File file;
	if (file.open(fileName))
		codec = FPCODEC_ADPCM;
	else if (file.open(setExtension(fileName, ".MP3")))
		codec = FPCODEC_MP3;
	else if (file.open(setExtension(fileName, ".OGG")))
		codec = FPCODEC_OGG;
	else if (file.open(setExtension(fileName, ".FLA")))
		codec = FPCODEC_FLAC;
	else {
		warning("FPSfx::LoadFile(): Cannot open sfx file!");
		return false;
	}

	Common::SeekableReadStream *buffer;
	switch (codec) {
	case FPCODEC_ADPCM: {
		if (file.readUint32BE() != MKTAG('A', 'D', 'P', 0x10)) {
			warning("FPSfx::LoadFile(): Invalid ADP header!");
			return false;
		}

		uint32 rate = file.readUint32LE();
		uint32 channels = file.readUint32LE();

		buffer = file.readStream(file.size() - file.pos());
		_rewindableStream = Audio::makeADPCMStream(buffer, DisposeAfterUse::YES, 0, Audio::kADPCMDVI, rate, channels);
		}
		break;
	case FPCODEC_MP3:
#ifdef USE_MAD
		buffer = file.readStream(file.size());
		_rewindableStream = Audio::makeMP3Stream(buffer, DisposeAfterUse::YES);
#endif
		break;
	case FPCODEC_OGG:
#ifdef USE_VORBIS
		buffer = file.readStream(file.size());
		_rewindableStream = Audio::makeVorbisStream(buffer, DisposeAfterUse::YES);
#endif
		break;
	case FPCODEC_FLAC:
		buffer = file.readStream(file.size());
#ifdef USE_FLAC
		_rewindableStream = Audio::makeFLACStream(buffer, DisposeAfterUse::YES);
#endif
		break;
	default:
		return false;
	}

	_fileLoaded = true;
	return true;
}
Exemplo n.º 5
0
ZorkCursor::ZorkCursor(const Common::String &fileName)
    : _width(0),
      _height(0),
      _hotspotX(0),
      _hotspotY(0) {
    Common::File file;
    if (!file.open(fileName))
        return;

    uint32 magic = file.readUint32BE();
    if (magic != MKTAG('Z', 'C', 'R', '1')) {
        warning("%s is not a Zork Cursor file", fileName.c_str());
        return;
    }

    _hotspotX = file.readUint16LE();
    _hotspotY = file.readUint16LE();
    _width = file.readUint16LE();
    _height = file.readUint16LE();

    uint dataSize = _width * _height * sizeof(uint16);
    _surface.create(_width, _height, Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0));
    uint32 bytesRead = file.read(_surface.getPixels(), dataSize);
    assert(bytesRead == dataSize);

    // Convert to RGB 565
    _surface.convertToInPlace(Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0));
}
Exemplo n.º 6
0
void Sound::loadVoiceFile(const GameSpecificSettings *gss) {
	// Game versions which use separate voice files
	if (_vm->getGameType() == GType_FF || _vm->getGameId() == GID_SIMON1CD32)
		return;


	char filename[16];
	Common::File *file = new Common::File();

	if (!_hasVoiceFile) {
		_voice = makeCompressedSound(_mixer, file, gss->speech_filename);
		_hasVoiceFile = (_voice != 0);
	}
	if (!_hasVoiceFile && _vm->getGameType() == GType_SIMON2) {
		// for simon2 mac/amiga, only read index file
		file->open("voices.idx");
		if (file->isOpen() == true) {
			int end = file->size();
			_filenums = (uint16 *)malloc((end / 6 + 1) * 2);
			_offsets = (uint32 *)malloc((end / 6 + 1) * 4);

			for (int i = 1; i <= end / 6; i++) {
				_filenums[i] = file->readUint16BE();
				_offsets[i] = file->readUint32BE();
			}
			_hasVoiceFile = true;
		}
	}
	if (!_hasVoiceFile) {
		sprintf(filename, "%s.wav", gss->speech_filename);
		file->open(filename);
		if (file->isOpen()) {
			_hasVoiceFile = true;
			_voice = new WavSound(_mixer, file);
		}
	}

	const bool dataIsUnsigned = true;

	if (!_hasVoiceFile) {
		sprintf(filename, "%s.voc", gss->speech_filename);
		file->open(filename);
		if (file->isOpen()) {
			_hasVoiceFile = true;
			_voice = new VocSound(_mixer, file, dataIsUnsigned);
		}
	}
	if (!_hasVoiceFile) {
		sprintf(filename, "%s", gss->speech_filename);
		file->open(filename);
		if (file->isOpen()) {
			_hasVoiceFile = true;
			if (_vm->getGameType() == GType_PP)
				_voice = new WavSound(_mixer, file);
			else
				_voice = new VocSound(_mixer, file, dataIsUnsigned);
		}
	}
}
Exemplo n.º 7
0
bool ScummDebugger::Cmd_ImportRes(int argc, const char** argv) {
	Common::File file;
	uint32 size;
	int resnum;

	if (argc != 4) {
		DebugPrintf("Syntax: importres <restype> <filename> <resnum>\n");
		return true;
	}

	resnum = atoi(argv[3]);
	// FIXME add bounds check

	if (!strncmp(argv[1], "scr", 3)) {
		file.open(argv[2], Common::File::kFileReadMode);
		if (file.isOpen() == false) {
			DebugPrintf("Could not open file %s\n", argv[2]);
			return true;
		}
		if (_vm->_game.features & GF_SMALL_HEADER) {
			size = file.readUint16LE();
			file.seek(-2, SEEK_CUR);
		} else if (_vm->_game.features & GF_SMALL_HEADER) {
			if (_vm->_game.version == 4)
				file.seek(8, SEEK_CUR);
			size = file.readUint32LE();
			file.readUint16LE();
			file.seek(-6, SEEK_CUR);
		} else {
			file.readUint32BE();
			size = file.readUint32BE();
			file.seek(-8, SEEK_CUR);
		}

		file.read(_vm->res.createResource(rtScript, resnum, size), size);

	} else
		DebugPrintf("Unknown importres type '%s'\n", argv[1]);
	return true;
}
Exemplo n.º 8
0
Audio::AudioStream *RawSound::makeAudioStream(uint sound) {
	if (_offsets == NULL)
		return NULL;

	Common::File *file = new Common::File();
	if (!file->open(_filename)) {
		warning("RawSound::makeAudioStream: Could not open file \"%s\"", _filename.c_str());
		return NULL;
	}

	file->seek(_offsets[sound], SEEK_SET);
	uint size = file->readUint32BE();
	return Audio::makeRawStream(new Common::SeekableSubReadStream(file, _offsets[sound] + 4, _offsets[sound] + 4 + size, DisposeAfterUse::YES), 22050, _flags, DisposeAfterUse::YES);
}
Exemplo n.º 9
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();
}
Exemplo n.º 10
0
Common::File *Resource::openDataFile(const Common::String fileName, uint32 fileHeader) {
	Common::File *dataFile = new Common::File();
	dataFile->open(translateFileName(fileName));
	if (!dataFile->isOpen())
		error("openDataFile: Couldn't open %s (%s)", translateFileName(fileName).c_str(), fileName.c_str());

	if (fileHeader > 0) {
		uint32 headerTag = dataFile->readUint32BE();
		if (headerTag != fileHeader) {
			dataFile->close();
			error("openDataFile: Unexpected header in %s (%s) - expected: %d, got: %d", translateFileName(fileName).c_str(), fileName.c_str(), fileHeader, headerTag);
		}
	}

	return dataFile;
}
Exemplo n.º 11
0
void Sound::loadVoiceFile(const GameSpecificSettings *gss) {
	// Game versions which use separate voice files
	if (_hasVoiceFile || _vm->getGameType() == GType_FF || _vm->getGameId() == GID_SIMON1CD32)
		return;

	_voice = makeSound(_mixer, gss->speech_filename);
	_hasVoiceFile = (_voice != 0);

	if (_hasVoiceFile)
		return;

	if (_vm->getGameType() == GType_SIMON2) {
		// for simon2 mac/amiga, only read index file
		Common::File file;
		if (file.open("voices.idx")) {
			int end = file.size();
			_filenums = (uint16 *)malloc((end / 6 + 1) * 2);
			_offsets = (uint32 *)malloc((end / 6 + 1 + 1) * 4);

			for (int i = 1; i <= end / 6; i++) {
				_filenums[i] = file.readUint16BE();
				_offsets[i] = file.readUint32BE();
			}
			// We need to add a terminator entry otherwise we get an out of
			// bounds read when the offset table is accessed in
			// BaseSound::getSoundStream.
			_offsets[end / 6 + 1] = 0;

			_hasVoiceFile = true;
			return;
		}
	}

	const bool dataIsUnsigned = true;

	if (Common::File::exists(gss->speech_filename)) {
		_hasVoiceFile = true;
		if (_vm->getGameType() == GType_PP)
			_voice = new WavSound(_mixer, gss->speech_filename);
		else
			_voice = new VocSound(_mixer, gss->speech_filename, dataIsUnsigned);
	}
}
Exemplo n.º 12
0
Font::Font(Common::String filename) {
	const uint32 headerFont = MKTAG('T', 'F', 'F', '\0');
	Common::File stream;

	stream.open(filename);

	uint32 header = stream.readUint32BE();

	if (header != headerFont)
		error("Invalid resource - %s", filename.c_str());

	stream.skip(4);	// total memory
	_count = stream.readUint16LE();
	_first = stream.readUint16LE();
	_last = stream.readUint16LE();
	_width = stream.readUint16LE();
	_height = stream.readUint16LE();

	_fontSurface.create(_width * _count, _height, ::Graphics::PixelFormat::createFormatCLUT8());

	byte cur;
	int bitIndex = 7;
	byte *p;

	cur = stream.readByte();

	for (uint n = 0; n < _count; n++) {
		for (uint y = 0; y < _height; y++) {
			p = (byte *)_fontSurface.getBasePtr(n * _width, y);

			for (uint x = n * _width; x < n * _width + _width; x++) {
				*p++ = (cur & (1 << bitIndex)) ? 0 : 0xFF;

				bitIndex--;
				if (bitIndex < 0) {
					bitIndex = 7;
					cur = stream.readByte();
				}
			}
		}
	}
}
Exemplo n.º 13
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;
}
Exemplo n.º 14
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;
}
Exemplo n.º 15
0
bool AGOSEngine::loadVGASoundFile(uint16 id, uint8 type) {
	Common::File in;
	char filename[15];
	byte *dst;
	uint32 srcSize, dstSize;

	if (getPlatform() == Common::kPlatformAmiga || getPlatform() == Common::kPlatformAtariST) {
		if (getGameType() == GType_ELVIRA1 && (getFeatures() & GF_DEMO) &&
			getPlatform() == Common::kPlatformAmiga) {
			sprintf(filename, "%c%d.out", 48 + id, type);
		} else if (getGameType() == GType_ELVIRA1 || getGameType() == GType_ELVIRA2) {
			sprintf(filename, "%.2d%d.out", id, type);
		} else if (getGameType() == GType_PN) {
			sprintf(filename, "%c%d.in", id + 48, type);
		} else {
			sprintf(filename, "%.3d%d.out", id, type);
		}
	} else {
		if (getGameType() == GType_ELVIRA1) {
			if (elvira1_soundTable[id] == 0)
				return false;

			sprintf(filename, "%.2d.SND", elvira1_soundTable[id]);
		} else if (getGameType() == GType_ELVIRA2 || getGameType() == GType_WW) {
			sprintf(filename, "%.2d%d.VGA", id, type);
		} else if (getGameType() == GType_PN) {
			sprintf(filename, "%c%d.out", id + 48, type);
		} else {
			sprintf(filename, "%.3d%d.VGA", id, type);
		}
	}

	in.open(filename);
	if (in.isOpen() == false || in.size() == 0) {
		return false;
	}

	dstSize = srcSize = in.size();
	if (getGameType() == GType_PN && (getFeatures() & GF_CRUNCHED)) {
		Common::Stack<uint32> data;
		byte *dataOut = 0;
		int dataOutSize = 0;

		for (uint i = 0; i < srcSize / 4; ++i)
			data.push(in.readUint32BE());

		decompressPN(data, dataOut, dataOutSize);
		dst = allocBlock (dataOutSize);
		memcpy(dst, dataOut, dataOutSize);
		delete[] dataOut;
	} else if (getGameType() == GType_ELVIRA1 && getFeatures() & GF_DEMO) {
		byte *srcBuffer = (byte *)malloc(srcSize);
		if (in.read(srcBuffer, srcSize) != srcSize)
			error("loadVGASoundFile: Read failed");

		dstSize = READ_BE_UINT32(srcBuffer + srcSize - 4);
		dst = allocBlock (dstSize);
		decrunchFile(srcBuffer, dst, srcSize);
		free(srcBuffer);
	} else {
		dst = allocBlock(dstSize);
		if (in.read(dst, dstSize) != dstSize)
			error("loadVGASoundFile: Read failed");
	}
	in.close();

	return true;
}
Exemplo n.º 16
0
void RenderManager::readImageToSurface(const Common::String &fileName, Graphics::Surface &destination) {
	Common::File file;

	if (!file.open(fileName)) {
		warning("Could not open file %s", fileName.c_str());
		return;
	}

	// Read the magic number
	// Some files are true TGA, while others are TGZ
	uint32 fileType = file.readUint32BE();

	uint32 imageWidth;
	uint32 imageHeight;
	Graphics::TGADecoder tga;
	uint16 *buffer;
	bool isTransposed = _renderTable.getRenderState() == RenderTable::PANORAMA;
	// All ZVision images are in RGB 555
	Graphics::PixelFormat pixelFormat555 = Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0);
	destination.format = pixelFormat555;

	bool isTGZ;

	// Check for TGZ files
	if (fileType == MKTAG('T', 'G', 'Z', '\0')) {
		isTGZ = true;

		// TGZ files have a header and then Bitmap data that is compressed with LZSS
		uint32 decompressedSize = file.readSint32LE();
		imageWidth = file.readSint32LE();
		imageHeight = file.readSint32LE();

		LzssReadStream lzssStream(&file);
		buffer = (uint16 *)(new uint16[decompressedSize]);
		lzssStream.read(buffer, decompressedSize);
	} else {
		isTGZ = false;

		// Reset the cursor
		file.seek(0);

		// Decode
		if (!tga.loadStream(file)) {
			warning("Error while reading TGA image");
			return;
		}

		Graphics::Surface tgaSurface = *(tga.getSurface());
		imageWidth = tgaSurface.w;
		imageHeight = tgaSurface.h;

		buffer = (uint16 *)tgaSurface.getPixels();
	}

	// Flip the width and height if transposed
	if (isTransposed) {
		uint16 temp = imageHeight;
		imageHeight = imageWidth;
		imageWidth = temp;
	}

	// If the destination internal buffer is the same size as what we're copying into it,
	// there is no need to free() and re-create
	if (imageWidth != destination.w || imageHeight != destination.h) {
		destination.create(imageWidth, imageHeight, pixelFormat555);
	}

	// If transposed, 'un-transpose' the data while copying it to the destination
	// Otherwise, just do a simple copy
	if (isTransposed) {
		uint16 *dest = (uint16 *)destination.getPixels();

		for (uint32 y = 0; y < imageHeight; ++y) {
			uint32 columnIndex = y * imageWidth;

			for (uint32 x = 0; x < imageWidth; ++x) {
				dest[columnIndex + x] = buffer[x * imageHeight + y];
			}
		}
	} else {
		memcpy(destination.getPixels(), buffer, imageWidth * imageHeight * _pixelFormat.bytesPerPixel);
	}

	// Cleanup
	if (isTGZ) {
		delete[] buffer;
	} else {
		tga.destroy();
	}

	// Convert in place to RGB 565 from RGB 555
	destination.convertToInPlace(_pixelFormat);
}
Exemplo n.º 17
0
/**
 * Plays the specified MIDI sequence through the sound driver.
 * @param dwFileOffset		File offset of MIDI sequence data
 * @param bLoop				Whether to loop the sequence
 */
bool PlayMidiSequence(uint32 dwFileOffset, bool bLoop) {
	g_currentMidi = dwFileOffset;
	g_currentLoop = bLoop;

	bool mute = false;
	if (ConfMan.hasKey("mute"))
		mute = ConfMan.getBool("mute");

	SetMidiVolume(mute ? 0 : _vm->_config->_musicVolume);

	// the index and length of the last tune loaded
	uint32 dwSeqLen = 0;	// length of the sequence

	// Support for external music from the music enhancement project
	if (_vm->getFeatures() & GF_ENHANCED_AUDIO_SUPPORT) {
		int trackNumber = GetTrackNumber(dwFileOffset);
		// Track 8 has been removed in the German CD re-release "Neon Edition"
		if ((_vm->getFeatures() & GF_ALT_MIDI) && trackNumber >= 8)
			trackNumber++;

		int track = 0;
		if (trackNumber >= 0) {
			if (_vm->getFeatures() & GF_SCNFILES)
				track = enhancedAudioSCNVersion[trackNumber];
			else
				track = enhancedAudioGRAVersion[trackNumber];

			if (track > 0) {
				StopMidi();

				// StopMidi resets these fields, so set them again
				g_currentMidi = dwFileOffset;
				g_currentLoop = bLoop;

				// try to play track, but don't fall back to a true CD
				g_system->getAudioCDManager()->play(track, bLoop ? -1 : 1, 0, 0, true);

				// Check if an enhanced audio track is being played.
				// If it is, stop here and don't load a MIDI track
				if (g_system->getAudioCDManager()->isPlaying()) {
					return true;
				}
			}
		} else {
			warning("Unknown MIDI offset %d", dwFileOffset);
		}
	}

	if (dwFileOffset == 0)
		return true;

	Common::File midiStream;

	// open MIDI sequence file in binary mode
	if (!midiStream.open(MIDI_FILE))
		error(CANNOT_FIND_FILE, MIDI_FILE);

	// move to correct position in the file
	midiStream.seek(dwFileOffset, SEEK_SET);

	if (TinselV1Mac) {
		// The Macintosh version of DW1 uses raw PCM for music
		dwSeqLen = midiStream.readUint32BE();
		_vm->_sound->playDW1MacMusic(midiStream, dwSeqLen);
	} else {
		dwSeqLen = midiStream.readUint32LE();

		// make sure buffer is large enough for this sequence
		assert(dwSeqLen > 0 && dwSeqLen <= g_midiBuffer.size);

		// stop any currently playing tune
		_vm->_midiMusic->stop();

		// read the sequence. This needs to be read again before playSEQ() is
		// called even if the music is restarting, as playSEQ() reads the file
		// name off the buffer itself. However, that function adds SMF headers
		// to the buffer, thus if it's read again, the SMF headers will be read
		// and the filename will always be 'MThd'.
		if (midiStream.read(g_midiBuffer.pDat, dwSeqLen) != dwSeqLen)
			error(FILE_IS_CORRUPT, MIDI_FILE);

		// WORKAROUND for bug #2820054 "DW1: No intro music at first start on Wii",
		// which actually affects all ports, since it's specific to the GRA version.
		//
		// The GRA version does not seem to set the channel volume at all for the first
		// intro track, thus we need to do that here. We only initialize the channels
		// used in that sequence. And we are using 127 as default channel volume.
		//
		// Only in the GRA version dwFileOffset can be "38888", just to be sure, we
		// check for the SCN files feature flag not being set though.
		if (_vm->getGameID() == GID_DW1 && dwFileOffset == 38888 && !(_vm->getFeatures() & GF_SCNFILES)) {
			_vm->_midiMusic->send(0x7F07B0 |  3);
			_vm->_midiMusic->send(0x7F07B0 |  5);
			_vm->_midiMusic->send(0x7F07B0 |  8);
			_vm->_midiMusic->send(0x7F07B0 | 10);
			_vm->_midiMusic->send(0x7F07B0 | 13);
		}

		_vm->_midiMusic->playMIDI(dwSeqLen, bLoop);
	}

	midiStream.close();

	return true;
}
Exemplo n.º 18
0
/**
 * Opens and inits all MIDI sequence files.
 */
void OpenMidiFiles() {
	Common::File midiStream;

	if (TinselV0) {
		// The early demo version of DW1 doesn't have MIDI
	} else if (TinselV2) {
		// DW2 uses a different music mechanism
	} else if (TinselV1Mac) {
		// open MIDI sequence file in binary mode
		if (!midiStream.open(MIDI_FILE))
			error(CANNOT_FIND_FILE, MIDI_FILE);

		uint32 curTrack = 1;
		uint32 songLength = 0;
		int32 fileSize = midiStream.size();

		// Init
		for (int i = 0; i < ARRAYSIZE(g_midiOffsets); i++)
			g_midiOffsets[i] = 0;

		midiStream.skip(4);	// skip file header

		while (!midiStream.eos() && !midiStream.err() && midiStream.pos() != fileSize) {
			assert(curTrack < ARRAYSIZE(g_midiOffsets));
			g_midiOffsets[curTrack] = midiStream.pos();
			//debug("%d: %d", curTrack, g_midiOffsets[curTrack]);

			songLength = midiStream.readUint32BE();
			midiStream.skip(songLength);

			curTrack++;
		}

		midiStream.close();
	} else {
		if (g_midiBuffer.pDat)
			// already allocated
			return;

		// open MIDI sequence file in binary mode
		if (!midiStream.open(MIDI_FILE))
			error(CANNOT_FIND_FILE, MIDI_FILE);

		// get length of the largest sequence
		g_midiBuffer.size = midiStream.readUint32LE();
		if (midiStream.eos() || midiStream.err())
			error(FILE_IS_CORRUPT, MIDI_FILE);

		if (g_midiBuffer.size) {
			// allocate a buffer big enough for the largest MIDI sequence
			if ((g_midiBuffer.pDat = (uint8 *)malloc(g_midiBuffer.size)) != NULL) {
				// clear out the buffer
				memset(g_midiBuffer.pDat, 0, g_midiBuffer.size);
			}
		}

		// Now scan through the contents of the MIDI file to find the offset
		// of each individual track, in order to create a mapping from MIDI
		// offset to track number, for the enhanced MIDI soundtrack.
		// The first song is always at position 4. The subsequent ones are
		// calculated dynamically.
		uint32 curOffset = 4;
		uint32 curTrack = 0;
		uint32 songLength = 0;

		// Init
		for (int i = 0; i < ARRAYSIZE(g_midiOffsets); i++)
			g_midiOffsets[i] = 0;

		while (!midiStream.eos() && !midiStream.err()) {
			if (curOffset + (4 * curTrack) >= (uint32)midiStream.size())
				break;

			assert(curTrack < ARRAYSIZE(g_midiOffsets));
			g_midiOffsets[curTrack] = curOffset + (4 * curTrack);
			//debug("%d: %d", curTrack, midiOffsets[curTrack]);

			songLength = midiStream.readUint32LE();
			curOffset += songLength;
			midiStream.skip(songLength);

			curTrack++;
		}

		midiStream.close();
	}
}
Exemplo n.º 19
0
void MidiMusicPlayer::playSEQ(uint32 size, bool loop) {
	// MIDI.DAT holds the file names in DW1 PSX
	Common::String baseName((char *)g_midiBuffer.pDat, size);
	Common::String seqName = baseName + ".SEQ";

	// TODO: Load the instrument bank (<baseName>.VB and <baseName>.VH)

	Common::File seqFile;
	if (!seqFile.open(seqName))
		error("Failed to open SEQ file '%s'", seqName.c_str());

	if (seqFile.readUint32LE() != MKTAG('S', 'E', 'Q', 'p'))
		error("Failed to find SEQp tag");

	// Make sure we don't have a SEP file (with multiple SEQ's inside)
	if (seqFile.readUint32BE() != 1)
		error("Can only play SEQ files, not SEP");

	uint16 ppqn = seqFile.readUint16BE();
	uint32 tempo = seqFile.readUint16BE() << 8;
	tempo |= seqFile.readByte();
	/* uint16 beat = */ seqFile.readUint16BE();

	// SEQ is directly based on SMF and we'll use that to our advantage here
	// and convert to SMF and then use the SMF MidiParser.

	// Calculate the SMF size we'll need
	uint32 dataSize = seqFile.size() - 15;
	uint32 actualSize = dataSize + 7 + 22;

	// Resize the buffer if necessary
	if (g_midiBuffer.size < actualSize) {
		g_midiBuffer.pDat = (byte *)realloc(g_midiBuffer.pDat, actualSize);
		assert(g_midiBuffer.pDat);
	}

	// Now construct the header
	WRITE_BE_UINT32(g_midiBuffer.pDat, MKTAG('M', 'T', 'h', 'd'));
	WRITE_BE_UINT32(g_midiBuffer.pDat + 4, 6); // header size
	WRITE_BE_UINT16(g_midiBuffer.pDat + 8, 0); // type 0
	WRITE_BE_UINT16(g_midiBuffer.pDat + 10, 1); // one track
	WRITE_BE_UINT16(g_midiBuffer.pDat + 12, ppqn);
	WRITE_BE_UINT32(g_midiBuffer.pDat + 14, MKTAG('M', 'T', 'r', 'k'));
	WRITE_BE_UINT32(g_midiBuffer.pDat + 18, dataSize + 7); // SEQ data size + tempo change event size

	// Add in a fake tempo change event
	WRITE_BE_UINT32(g_midiBuffer.pDat + 22, 0x00FF5103); // no delta, meta event, tempo change, param size = 3
	WRITE_BE_UINT16(g_midiBuffer.pDat + 26, tempo >> 8);
	g_midiBuffer.pDat[28] = tempo & 0xFF;

	// Now copy in the rest of the events
	seqFile.read(g_midiBuffer.pDat + 29, dataSize);
	seqFile.close();

	MidiParser *parser = MidiParser::createParser_SMF();
	if (parser->loadMusic(g_midiBuffer.pDat, actualSize)) {
		parser->setTrack(0);
		parser->setMidiDriver(this);
		parser->setTimerRate(getBaseTempo());
		parser->property(MidiParser::mpCenterPitchWheelOnUnload, 1);
		parser->property(MidiParser::mpSendSustainOffOnNotesOff, 1);

		_parser = parser;

		_isLooping = loop;
		_isPlaying = true;
	} else {
		delete parser;
	}
}
Exemplo n.º 20
0
void RenderManager::readImageToSurface(const Common::String &fileName, Graphics::Surface &destination, bool transposed) {
	Common::File file;

	if (!_engine->getSearchManager()->openFile(file, fileName)) {
		warning("Could not open file %s", fileName.c_str());
		return;
	}

	// Read the magic number
	// Some files are true TGA, while others are TGZ
	uint32 fileType = file.readUint32BE();

	uint32 imageWidth;
	uint32 imageHeight;
	Image::TGADecoder tga;
	uint16 *buffer;
	// All ZVision images are in RGB 555
	destination.format = _engine->_resourcePixelFormat;

	bool isTGZ;

	// Check for TGZ files
	if (fileType == MKTAG('T', 'G', 'Z', '\0')) {
		isTGZ = true;

		// TGZ files have a header and then Bitmap data that is compressed with LZSS
		uint32 decompressedSize = file.readSint32LE() / 2;
		imageWidth = file.readSint32LE();
		imageHeight = file.readSint32LE();

		LzssReadStream lzssStream(&file);
		buffer = (uint16 *)(new uint16[decompressedSize]);
		lzssStream.read(buffer, 2 * decompressedSize);
#ifndef SCUMM_LITTLE_ENDIAN
		for (uint32 i = 0; i < decompressedSize; ++i)
			buffer[i] = FROM_LE_16(buffer[i]);
#endif
	} else {
		isTGZ = false;

		// Reset the cursor
		file.seek(0);

		// Decode
		if (!tga.loadStream(file)) {
			warning("Error while reading TGA image");
			return;
		}

		Graphics::Surface tgaSurface = *(tga.getSurface());
		imageWidth = tgaSurface.w;
		imageHeight = tgaSurface.h;

		buffer = (uint16 *)tgaSurface.getPixels();
	}

	// Flip the width and height if transposed
	if (transposed) {
		uint16 temp = imageHeight;
		imageHeight = imageWidth;
		imageWidth = temp;
	}

	// If the destination internal buffer is the same size as what we're copying into it,
	// there is no need to free() and re-create
	if (imageWidth != destination.w || imageHeight != destination.h) {
		destination.create(imageWidth, imageHeight, _engine->_resourcePixelFormat);
	}

	// If transposed, 'un-transpose' the data while copying it to the destination
	// Otherwise, just do a simple copy
	if (transposed) {
		uint16 *dest = (uint16 *)destination.getPixels();

		for (uint32 y = 0; y < imageHeight; ++y) {
			uint32 columnIndex = y * imageWidth;

			for (uint32 x = 0; x < imageWidth; ++x) {
				dest[columnIndex + x] = buffer[x * imageHeight + y];
			}
		}
	} else {
		memcpy(destination.getPixels(), buffer, imageWidth * imageHeight * destination.format.bytesPerPixel);
	}

	// Cleanup
	if (isTGZ) {
		delete[] buffer;
	} else {
		tga.destroy();
	}
}
Exemplo n.º 21
0
void readElement(Common::File &file, Saga::ResourceData &element) {
	element.id = file.readUint32BE();
	element.offset = file.readUint32LE();
	element.size = file.readUint32LE();
	debug(3, "Entry: id %u, offset %u, size %u", element.id, (uint)element.offset, (uint)element.size);
}