Esempio n. 1
0
ArchiveType::Certainty ArchiveType_DAT_Sango::isInstance(stream::input_sptr psArchive) const
{
	stream::pos lenArchive = psArchive->size();

	// TESTED BY: fmt_dat_sango_isinstance_c01
	if (lenArchive < DAT_FAT_ENTRY_LEN) return DefinitelyNo; // too short

	uint32_t offEndFAT;
	psArchive->seekg(0, stream::start);
	psArchive >> u32le(offEndFAT);
	// TESTED BY: fmt_dat_sango_isinstance_c02
	if (offEndFAT > lenArchive) return DefinitelyNo;

	uint32_t offNext = 4; // in case of no files
	for (unsigned int offset = 4; offset < offEndFAT; offset += 4) {
		psArchive >> u32le(offNext);
		// TESTED BY: fmt_dat_sango_isinstance_c03
		if (offNext > lenArchive) return DefinitelyNo;
	}

	// Last offset must equal file size
	// TESTED BY: fmt_dat_sango_isinstance_c04
	if (offNext != lenArchive) return DefinitelyNo;

	// TESTED BY: fmt_dat_sango_isinstance_c00
	return DefinitelyYes;
}
Esempio n. 2
0
Archive_DAT_Sango::Archive_DAT_Sango(stream::inout_sptr psArchive)
	:	FATArchive(psArchive, DAT_FIRST_FILE_OFFSET, 0)
{
	psArchive->seekg(0, stream::end);
	this->lenArchive = psArchive->tellg();

	if (this->lenArchive < DAT_FAT_ENTRY_LEN) throw stream::error("file too short");

	uint32_t offEndFAT;
	psArchive->seekg(0, stream::start);
	psArchive >> u32le(offEndFAT);

	uint32_t offCur = offEndFAT, offNext;
	for (int i = 0; offCur < this->lenArchive; i++) {
		psArchive >> u32le(offNext);

		FATEntry *fatEntry = new FATEntry();
		EntryPtr ep(fatEntry);

		fatEntry->iIndex = i;
		fatEntry->iOffset = offCur;
		fatEntry->lenHeader = 0;
		fatEntry->type = FILETYPE_GENERIC;
		fatEntry->fAttr = 0;
		fatEntry->bValid = true;
		fatEntry->storedSize = offNext - offCur;
		fatEntry->realSize = fatEntry->storedSize;
		this->vcFAT.push_back(ep);
		if (i >= DAT_SAFETY_MAX_FILECOUNT) {
			throw stream::error("too many files or corrupted archive");
		}

		offCur = offNext;
	}
}
Esempio n. 3
0
Archive_DAT_LostVikings::Archive_DAT_LostVikings(std::unique_ptr<stream::inout> content)
	:	Archive_FAT(std::move(content), DAT_FIRST_FILE_OFFSET, 0)
{
	stream::pos lenArchive = this->content->size();
	if (lenArchive > 0) {
		this->content->seekg(0, stream::start);
		uint32_t offNext;
		*this->content
			>> u32le(offNext)
		;
		uint32_t numFiles = offNext / DAT_FAT_ENTRY_LEN;
		this->vcFAT.reserve(numFiles);
		for (unsigned int i = 0; i < numFiles; i++) {
			auto f = this->createNewFATEntry();

			f->iOffset = offNext;
			if (i == numFiles - 1) {
				offNext = lenArchive;
			} else {
				*this->content
					>> u32le(offNext)
				;
			}

			f->iIndex = i;
			f->lenHeader = 0;
			f->type = FILETYPE_GENERIC;
			f->fAttr = File::Attribute::Default;
			f->storedSize = offNext - f->iOffset;
			f->realSize = f->storedSize;
			f->bValid = true;
			this->vcFAT.push_back(std::move(f));
		}
	} // else empty archive
Esempio n. 4
0
void IFFWriter::end()
{
	stream::pos orig = this->iff.tellp();
	stream::pos start = this->chunk.back();
	this->chunk.pop_back();
	stream::len lenChunk = orig - (start + 8);

	switch (this->filetype) {
		case Filetype_RIFF_Unpadded:
		case Filetype_IFF_Unpadded:
			break;
		case Filetype_RIFF:
		case Filetype_IFF:
			if (orig % 2) {
				// Pad to even byte boundary
				this->iff.write("", 1);
				orig++;
			}
			break;
	}

	this->iff.seekp(start + 4, stream::start);
	switch (this->filetype) {
		case Filetype_RIFF_Unpadded:
		case Filetype_RIFF:
			this->iff << u32le(lenChunk);
			break;
		case Filetype_IFF_Unpadded:
		case Filetype_IFF:
			this->iff << u32be(lenChunk);
			break;
	}
	this->iff.seekp(orig, stream::start);
	return;
}
Esempio n. 5
0
FATArchive::FATEntry *Archive_DAT_Sango::preInsertFile(const FATEntry *idBeforeThis, FATEntry *pNewEntry)
{
	// TESTED BY: fmt_dat_sango_insert*

	// Set the format-specific variables
	pNewEntry->lenHeader = 0;

	// Because the new entry isn't in the vector yet we need to shift it manually
	pNewEntry->iOffset += DAT_FAT_ENTRY_LEN;

	// Update the last FAT entry (the one that points to EOF.)
	this->updateLastEntry(pNewEntry->storedSize + DAT_FAT_ENTRY_LEN);

	this->psArchive->seekp(DAT_FATENTRY_OFFSET(pNewEntry), stream::start);
	this->psArchive->insert(DAT_FAT_ENTRY_LEN);

	this->psArchive
		<< u32le(pNewEntry->iOffset);

	// Update the offsets now there's a new FAT entry taking up space.
	this->shiftFiles(
		NULL,
		(this->vcFAT.size() + 1) * DAT_FAT_ENTRY_LEN,
		DAT_FAT_ENTRY_LEN,
		0
	);

	return pNewEntry;
}
Esempio n. 6
0
void Archive_DAT_Sango::updateLastEntry(stream::delta lenDelta)
{
	this->lenArchive += lenDelta;
	this->psArchive->seekp(this->vcFAT.size() * DAT_FAT_ENTRY_LEN, stream::start);
	this->psArchive
		<< u32le(this->lenArchive);
	return;
}
Esempio n. 7
0
Tileset_Zone66::Tileset_Zone66(stream::inout_sptr data,
	PaletteTablePtr pal)
	:	Tileset_FAT(data, Z66_FIRST_TILE_OFFSET),
		pal(pal)
{
	stream::pos len = this->data->size();

	// We still have to perform sanity checks in case the user forced an
	// open even though it failed the signature check.
	if (len < Z66_FIRST_TILE_OFFSET) throw stream::error("file too short");

	this->data->seekg(0, stream::start);
	uint32_t numTiles;
	this->data >> u32le(numTiles);
	this->items.reserve(numTiles);
	if (numTiles > Z66_SAFETY_MAX_TILES) throw stream::error("too many tiles");

	if (numTiles > 0) {
		uint32_t firstOffset = (numTiles+1) * 4;
		uint32_t nextOffset;
		this->data >> u32le(nextOffset);
		nextOffset += firstOffset;
		for (unsigned int i = 0; i < numTiles; i++) {
			FATEntry *fat = new FATEntry();
			EntryPtr ep(fat);
			fat->valid = true;
			fat->attr = 0;
			fat->index = i;
			fat->offset = nextOffset;
			fat->lenHeader = 0;
			if (i + 1 == numTiles) {
				// Last entry ends at EOF
				nextOffset = len;
			} else {
				this->data >> u32le(nextOffset);
				nextOffset += firstOffset;
			}
			fat->size = nextOffset - fat->offset;
			this->items.push_back(ep);
		}
	}
Esempio n. 8
0
TilesetType_Zone66::Certainty TilesetType_Zone66::isInstance(
	stream::input_sptr psTileset) const
{
	stream::pos len = psTileset->size();
	// TESTED BY: tls_zone66_isinstance_c04
	if (len < Z66_FIRST_TILE_OFFSET) return DefinitelyNo; // too short

	psTileset->seekg(0, stream::start);
	uint32_t numFiles;
	psTileset >> u32le(numFiles);

	if ((numFiles == 0) && (len > 8)) return DefinitelyNo; // invalid empty file

	uint32_t offset, lastOffset = 0;
	for (unsigned int i = 0; i < numFiles; i++) {
		psTileset >> u32le(offset);

		// The first file always starts at offset 0.
		// TESTED BY: tls_zone66_isinstance_c01
		if ((i == 0) && (offset != 0)) return DefinitelyNo;

		// Make sure the offsets are increasing, otherwise we'd get a negative
		// file size (or the file has been tweaked to make opening difficult, but
		// then there's the -f option to gametls for that.)
		// TESTED BY: tls_zone66_isinstance_c02
		if (offset < lastOffset) return DefinitelyNo;

		// Make sure the tile is contained within the file
		// TESTED BY: tls_zone66_isinstance_c03
		if ((numFiles+1) * 4 + offset > len) return DefinitelyNo;

		lastOffset = offset;
	}

	// TESTED BY: tls_zone66_isinstance_c00
	return DefinitelyYes;
}
Esempio n. 9
0
TilesetPtr TilesetType_Zone66::create(stream::inout_sptr psTileset,
	SuppData& suppData) const
{
	psTileset->truncate(4);
	psTileset->seekp(0, stream::start);
	psTileset << u32le(0);

	PaletteTablePtr pal;
	// Only load the palette if one was given
	if (suppData.find(SuppItem::Palette) != suppData.end()) {
		ImagePtr palFile(new Palette_VGA(suppData[SuppItem::Palette], 6));
		pal = palFile->getPalette();
		pal->at(Z66_TRANSPARENT_COLOUR).alpha = 0;
	}
	return TilesetPtr(new Tileset_Zone66(psTileset, pal));
}
Esempio n. 10
0
void IFFReader::loadChunks(stream::len lenChunk)
{
	this->chunks.clear();
	while (lenChunk > 8) {
		lenChunk -= 8; // ID and chunk size fields
		Chunk c;
		c.start = this->iff.tellg() + 8;
		this->iff >> fixedLength(c.name, 4);
		switch (this->filetype) {
			case Filetype_RIFF_Unpadded:
			case Filetype_RIFF:
				this->iff >> u32le(c.len);
				break;
			case Filetype_IFF_Unpadded:
			case Filetype_IFF:
			default:
				this->iff >> u32be(c.len);
				break;
		}

		unsigned int pad;
		switch (this->filetype) {
			case Filetype_RIFF:
			case Filetype_IFF:
				pad = (c.len % 2) ? 1 : 0;
				break;
			case Filetype_RIFF_Unpadded:
			case Filetype_IFF_Unpadded:
			default:
				pad = 0;
				break;
		}

		stream::len lenPaddedSub = c.len + pad;
		if (lenChunk < c.len) c.len = lenChunk; // truncated
		if (lenChunk < lenPaddedSub) lenPaddedSub = lenChunk; // final pad truncated
		this->chunks.push_back(c);
		lenChunk -= lenPaddedSub;
		this->iff.seekg(lenPaddedSub, stream::cur);
	}
	return;
}
Esempio n. 11
0
void Archive_DAT_Sango::updateFileOffset(const FATEntry *pid, stream::delta offDelta)
{
	this->psArchive->seekp(DAT_FATENTRY_OFFSET(pid), stream::start);
	this->psArchive << u32le(pid->iOffset);
	return;
}