Exemplo n.º 1
0
static void writePixel(Common::WriteStream &file, const byte *&data, PixelFormat format) {
	if (format == kPixelFormatRGB) {
		file.writeByte(data[2]);
		file.writeByte(data[1]);
		file.writeByte(data[0]);
		file.writeByte(0xFF);
		data += 3;
	} else if (format == kPixelFormatBGR) {
		file.writeByte(data[0]);
		file.writeByte(data[1]);
		file.writeByte(data[2]);
		file.writeByte(0xFF);
		data += 3;
	} else if (format == kPixelFormatRGBA) {
		file.writeByte(data[2]);
		file.writeByte(data[1]);
		file.writeByte(data[0]);
		file.writeByte(data[3]);
		data += 4;
	} else if (format == kPixelFormatBGRA) {
		file.writeByte(data[0]);
		file.writeByte(data[1]);
		file.writeByte(data[2]);
		file.writeByte(data[3]);
		data += 4;
	} else
		throw Common::Exception("Unsupported pixel format: %d", (int) format);

}
Exemplo n.º 2
0
void TwoDAFile::writeASCII(Common::WriteStream &out) const {
	// Write header

	out.writeString("2DA V2.0\n");
	if (!_defaultString.empty())
		out.writeString(Common::UString::format("DEFAULT: %s", _defaultString.c_str()));
	out.writeByte('\n');

	// Calculate column lengths

	std::vector<size_t> colLength;
	colLength.resize(_headers.size() + 1, 0);

	const Common::UString maxRow = Common::UString::format("%d", (int)_rows.size() - 1);
	colLength[0] = maxRow.size();

	for (size_t i = 0; i < _headers.size(); i++)
		colLength[i + 1] = _headers[i].size();

	for (size_t i = 0; i < _rows.size(); i++) {
		for (size_t j = 0; j < _rows[i]->_data.size(); j++) {
			const bool   needQuote = _rows[i]->_data[j].contains(' ');
			const size_t length    = needQuote ? _rows[i]->_data[j].size() + 2 : _rows[i]->_data[j].size();

			colLength[j + 1] = MAX<size_t>(colLength[j + 1], length);
		}
	}

	// Write column headers

	out.writeString(Common::UString::format("%-*s", (int)colLength[0], ""));

	for (size_t i = 0; i < _headers.size(); i++)
		out.writeString(Common::UString::format(" %-*s", (int)colLength[i + 1], _headers[i].c_str()));

	out.writeByte('\n');

	// Write array

	for (size_t i = 0; i < _rows.size(); i++) {
		out.writeString(Common::UString::format("%*u", (int)colLength[0], (uint)i));

		for (size_t j = 0; j < _rows[i]->_data.size(); j++) {
			const bool needQuote = _rows[i]->_data[j].contains(' ');

			Common::UString cellString;
			if (needQuote)
				cellString = Common::UString::format("\"%s\"", _rows[i]->_data[j].c_str());
			else
				cellString = _rows[i]->_data[j];

			out.writeString(Common::UString::format(" %-*s", (int)colLength[j + 1], cellString.c_str()));

		}

		out.writeByte('\n');
	}

	out.flush();
}
Exemplo n.º 3
0
bool saveThumbnail(Common::WriteStream &out, const Graphics::Surface &thumb) {
	if (thumb.format.bytesPerPixel != 2) {
		warning("trying to save thumbnail with bpp different than 2");
		return false;
	}

	ThumbnailHeader header;
	header.type = MKTAG('T','H','M','B');
	header.size = ThumbnailHeaderSize + thumb.w*thumb.h*thumb.format.bytesPerPixel;
	header.version = THMB_VERSION;
	header.width = thumb.w;
	header.height = thumb.h;
	header.bpp = thumb.format.bytesPerPixel;

	out.writeUint32BE(header.type);
	out.writeUint32BE(header.size);
	out.writeByte(header.version);
	out.writeUint16BE(header.width);
	out.writeUint16BE(header.height);
	out.writeByte(header.bpp);

	// TODO: for later this shouldn't be casted to uint16...
	uint16 *pixels = (uint16 *)thumb.pixels;
	for (uint16 p = 0; p < thumb.w*thumb.h; ++p, ++pixels)
		out.writeUint16BE(*pixels);

	return true;
}
Exemplo n.º 4
0
void TimerManager::saveDataToFile(Common::WriteStream &file) const {
	const uint32 saveTime = _isPaused ? _pauseStart : _system->getMillis();

	file.writeByte(count());
	for (CIterator pos = _timers.begin(); pos != _timers.end(); ++pos) {
		file.writeByte(pos->id);
		file.writeByte(pos->enabled);
		file.writeSint32BE(pos->countdown);
		file.writeSint32BE(pos->lastUpdate - saveTime);
	}
}
Exemplo n.º 5
0
/* Simple LZSS decompression.
 *
 * Code loosely based on DSDecmp by Barubary, released under the terms of the MIT license.
 *
 * See <https://github.com/gravgun/dsdecmp/blob/master/CSharp/DSDecmp/Formats/Nitro/LZ10.cs#L121>
 * and <https://code.google.com/p/dsdecmp/>.
 */
static void decompress10(Common::SeekableReadStream &small, Common::WriteStream &out, uint32 size) {
	byte   buffer[0x10000];
	uint32 bufferPos = 0;

	uint16 flags = 0xFF00;

	uint32 outSize = 0;
	while (outSize < size) {
		// Only our canaries left => Read flags for the next 8 blocks
		if (flags == 0xFF00)
			flags = (small.readByte() << 8) | 0x00FF;

		if (flags & 0x8000) {
			// Copy from buffer

			const byte data1 = small.readByte();
			const byte data2 = small.readByte();

			// Copy how many bytes from where (relative) in the buffer?
			const uint8  length = (data1 >> 4) + 3;
			const uint16 offset = (((data1 & 0x0F) << 8) | data2) + 1;

			// Direct offset. Add size of the buffer once, to protect from overroll
			uint32 copyOffset = bufferPos + sizeof(buffer) - offset;

			// Copy length bytes (and store each back into the buffer)
			for (uint8 i = 0; i < length; i++, copyOffset++) {
				if ((copyOffset % sizeof(buffer)) > outSize)
					throw Common::Exception("Tried to copy past the buffer");

				const byte data = buffer[copyOffset % sizeof(buffer)];

				out.writeByte(data);
				outSize++;

				buffer[bufferPos] = data;
				bufferPos = (bufferPos + 1) % sizeof(buffer);
			}

		} else {
			// Read literal byte

			const byte data = small.readByte();

			out.writeByte(data);
			outSize++;

			buffer[bufferPos] = data;
			bufferPos = (bufferPos + 1) % sizeof(buffer);
		}

		flags <<= 1;
	}
Exemplo n.º 6
0
void LocString::writeLocString(Common::WriteStream &stream, bool withNullTerminate) const {
	for (StringMap::const_iterator iter = _strings.begin(); iter != _strings.end() ; iter++) {
		stream.writeUint32LE((*iter).first);
		stream.writeUint32LE((*iter).second.size());
		stream.write((*iter).second.c_str(), (*iter).second.size());
		if (withNullTerminate)
			stream.writeByte(0);
	}
}
Exemplo n.º 7
0
bool LureEngine::saveGame(uint8 slotNumber, Common::String &caption) {
	Common::WriteStream *f = this->_saveFileMan->openForSaving(
		generateSaveName(slotNumber));
	if (f == NULL)
		return false;

	f->write("lure", 5);
	f->writeByte(getLanguage());
	f->writeByte(LURE_SAVEGAME_MINOR);
	f->writeString(caption);
	f->writeByte(0); // End of string terminator

	Resources::getReference().saveToStream(f);
	Game::getReference().saveToStream(f);
	Sound.saveToStream(f);
	Fights.saveToStream(f);
	Room::getReference().saveToStream(f);

	delete f;
	return true;
}
Exemplo n.º 8
0
bool SavePartInfo::write(Common::WriteStream &stream) const {
	if (!_header.write(stream))
		return false;

	stream.writeUint32LE(_gameID);
	stream.writeUint32LE(_gameVersion);
	stream.writeByte(_endian);
	stream.writeUint32LE(_varCount);
	stream.writeUint32LE(_descMaxLength);

	if (stream.write(_desc, _descMaxLength) != _descMaxLength)
		return false;

	return flushStream(stream);
}
Exemplo n.º 9
0
void TwoDAFile::writeCSV(Common::WriteStream &out) const {
	// Write column headers

	for (size_t i = 0; i < _headers.size(); i++) {
		const bool needQuote = _headers[i].contains(',');
		if (needQuote)
			out.writeByte('"');

		out.writeString(_headers[i]);

		if (needQuote)
			out.writeByte('"');

		if (i < (_headers.size() - 1))
			out.writeByte(',');
	}

	out.writeByte('\n');

	// Write array

	for (size_t i = 0; i < _rows.size(); i++) {
		for (size_t j = 0; j < _rows[i]->_data.size(); j++) {
			const bool needQuote = _rows[i]->_data[j].contains(',');

			if (needQuote)
				out.writeByte('"');

			if (_rows[i]->_data[j] != "****")
				out.writeString(_rows[i]->_data[j]);

			if (needQuote)
				out.writeByte('"');

			if (j < (_rows[i]->_data.size() - 1))
				out.writeByte(',');
		}

		out.writeByte('\n');
	}

	out.flush();
}
Exemplo n.º 10
0
Common::WriteStream *KyraEngine_v1::openSaveForWriting(const char *filename, const char *saveName, const Graphics::Surface *thumbnail) const {
	if (shouldQuit())
		return 0;

	Common::WriteStream *out = 0;
	if (!(out = _saveFileMan->openForSaving(filename))) {
		warning("Can't create file '%s', game not saved", filename);
		return 0;
	}

	// Savegame version
	out->writeUint32BE(MKTAG('W', 'W', 'S', 'V'));
	out->writeByte(_flags.gameID);
	out->writeUint32BE(CURRENT_SAVE_VERSION);
	out->write(saveName, strlen(saveName) + 1);
	if (_flags.isTalkie)
		out->writeUint32BE(GF_TALKIE);
	else if (_flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98)
		out->writeUint32BE(GF_FMTOWNS);
	else
		out->writeUint32BE(GF_FLOPPY);

	if (out->err()) {
		warning("Can't write file '%s'. (Disk full?)", filename);
		delete out;
		return 0;
	}

	Graphics::Surface *genThumbnail = 0;
	if (!thumbnail)
		thumbnail = genThumbnail = generateSaveThumbnail();

	if (thumbnail)
		Graphics::saveThumbnail(*out, *thumbnail);
	else
		Graphics::saveThumbnail(*out);

	if (genThumbnail) {
		genThumbnail->free();
		delete genThumbnail;
	}

	return out;
}
Exemplo n.º 11
0
bool SavePartSprite::write(Common::WriteStream &stream) const {
	if (!_header.write(stream))
		return false;

	// The sprite's dimensions
	stream.writeUint32LE(_width);
	stream.writeUint32LE(_height);
	stream.writeByte(_trueColor);

	// Sprite data
	if (stream.write(_dataSprite, _spriteSize) != _spriteSize)
		return false;

	// Palette data
	if (stream.write(_dataPalette, 768) != 768)
		return false;

	return flushStream(stream);
}
Exemplo n.º 12
0
reg_t kFileIOExists(EngineState *s, int argc, reg_t *argv) {
	Common::String name = s->_segMan->getString(argv[0]);

#ifdef ENABLE_SCI32
	// Cache the file existence result for the Phantasmagoria
	// save index file, as the game scripts keep checking for
	// its existence.
	if (name == PHANTASMAGORIA_SAVEGAME_INDEX && s->_virtualIndexFile)
		return TRUE_REG;
#endif

	bool exists = false;

	// Check for regular file
	exists = Common::File::exists(name);

	// Check for a savegame with the name
	Common::SaveFileManager *saveFileMan = g_sci->getSaveFileManager();
	if (!exists)
		exists = !saveFileMan->listSavefiles(name).empty();

	// Try searching for the file prepending "target-"
	const Common::String wrappedName = g_sci->wrapFilename(name);
	if (!exists) {
		exists = !saveFileMan->listSavefiles(wrappedName).empty();
	}

	// SCI2+ debug mode
	if (DebugMan.isDebugChannelEnabled(kDebugLevelDebugMode)) {
		if (!exists && name == "1.scr")		// PQ4
			exists = true;
		if (!exists && name == "18.scr")	// QFG4
			exists = true;
		if (!exists && name == "99.scr")	// GK1, KQ7
			exists = true;
		if (!exists && name == "classes")	// GK2, SQ6, LSL7
			exists = true;
	}

	// Special case for non-English versions of LSL5: The English version of
	// LSL5 calls kFileIO(), case K_FILEIO_OPEN for reading to check if
	// memory.drv exists (which is where the game's password is stored). If
	// it's not found, it calls kFileIO() again, case K_FILEIO_OPEN for
	// writing and creates a new file. Non-English versions call kFileIO(),
	// case K_FILEIO_FILE_EXISTS instead, and fail if memory.drv can't be
	// found. We create a default memory.drv file with no password, so that
	// the game can continue.
	if (!exists && name == "memory.drv") {
		// Create a new file, and write the bytes for the empty password
		// string inside
		byte defaultContent[] = { 0xE9, 0xE9, 0xEB, 0xE1, 0x0D, 0x0A, 0x31, 0x30, 0x30, 0x30 };
		Common::WriteStream *outFile = saveFileMan->openForSaving(wrappedName);
		for (int i = 0; i < 10; i++)
			outFile->writeByte(defaultContent[i]);
		outFile->finalize();
		exists = !outFile->err();	// check whether we managed to create the file.
		delete outFile;
	}

	// Special case for KQ6 Mac: The game checks for two video files to see
	// if they exist before it plays them. Since we support multiple naming
	// schemes for resource fork files, we also need to support that here in
	// case someone has a "HalfDome.bin" file, etc. 
	if (!exists && g_sci->getGameId() == GID_KQ6 && g_sci->getPlatform() == Common::kPlatformMacintosh &&
			(name == "HalfDome" || name == "Kq6Movie"))
		exists = Common::MacResManager::exists(name);

	debugC(kDebugLevelFile, "kFileIO(fileExists) %s -> %d", name.c_str(), exists);
	return make_reg(0, exists);
}
Exemplo n.º 13
0
void TwoDAFile::writeBinary(Common::WriteStream &out) const {
	const size_t columnCount = _headers.size();
	const size_t rowCount    = _rows.size();
	const size_t cellCount   = columnCount * rowCount;

	out.writeString("2DA V2.b\n");

	// Write the column headers

	for (std::vector<Common::UString>::const_iterator h = _headers.begin(); h != _headers.end(); ++h) {
		out.writeString(*h);
		out.writeByte('\t');
	}
	out.writeByte('\0');

	// Write the row indices

	out.writeUint32LE((uint32) rowCount);
	for (size_t i = 0; i < rowCount; i++) {
		out.writeString(Common::composeString(i));
		out.writeByte('\t');
	}

	/* Deduplicate cell data strings. Binary 2DA files don't store the
	 * data for each cell directly: instead, each cell contains an offset
	 * into a data array. This way, cells with the same data only need to
	 * to store this data once.
	 *
	 * The original binary 2DA files in KotOR/KotOR2 make extensive use
	 * of that, and we should do this as well.
	 *
	 * Basically, this involves going through each cell, and looking up
	 * if we already saved this particular piece of data. If not, save
	 * it, otherwise only remember the offset. There's no need to be
	 * particularly smart about it, so we're just doing it the naive
	 * O(n^2) way.
	 */

	std::vector<Common::UString> data;
	std::vector<size_t> offsets;

	data.reserve(cellCount);
	offsets.reserve(cellCount);

	size_t dataSize = 0;

	std::vector<size_t> cells;
	cells.reserve(cellCount);

	for (size_t i = 0; i < rowCount; i++) {
		assert(_rows[i]);

		for (size_t j = 0; j < columnCount; j++) {
			const Common::UString cell = _rows[i]->getString(j);

			// Do we already know about this cell data string?
			size_t foundCell = SIZE_MAX;
			for (size_t k = 0; k < data.size(); k++) {
				if (data[k] == cell) {
					foundCell = k;
					break;
				}
			}

			// If not, add it to the cell data array
			if (foundCell == SIZE_MAX) {
				foundCell = data.size();

				data.push_back(cell);
				offsets.push_back(dataSize);

				dataSize += data.back().size() + 1;

				if (dataSize > 65535)
					throw Common::Exception("TwoDAFile::writeBinary(): Cell data size overflow");
			}

			// Remember the offset to the cell data array
			cells.push_back(offsets[foundCell]);
		}
	}

	// Write cell data offsets
	for (std::vector<size_t>::const_iterator c = cells.begin(); c != cells.end(); ++c)
		out.writeUint16LE((uint16) *c);

	// Size of the all cell data strings
	out.writeUint16LE((uint16) dataSize);

	// Write cell data strings
	for (std::vector<Common::UString>::const_iterator d = data.begin(); d != data.end(); ++d) {
		out.writeString(*d);
		out.writeByte('\0');
	}
}