Esempio n. 1
0
// -----------------------------------------------------------------------------
// Writes the wad archive to a MemChunk
// Returns true if successful, false otherwise
// -----------------------------------------------------------------------------
bool Wad2Archive::write(MemChunk& mc, bool update)
{
	// Determine directory offset & individual lump offsets
	uint32_t      dir_offset = 12;
	ArchiveEntry* entry      = nullptr;
	for (uint32_t l = 0; l < numEntries(); l++)
	{
		entry                   = entryAt(l);
		entry->exProp("Offset") = (int)dir_offset;
		dir_offset += entry->size();
	}

	// Clear/init MemChunk
	mc.clear();
	mc.seek(0, SEEK_SET);
	mc.reSize(dir_offset + numEntries() * 32);

	// Setup wad type
	char wad_type[4] = { 'W', 'A', 'D', '2' };
	if (wad3_)
		wad_type[3] = '3';

	// Write the header
	uint32_t num_lumps = numEntries();
	mc.write(wad_type, 4);
	mc.write(&num_lumps, 4);
	mc.write(&dir_offset, 4);

	// Write the lumps
	for (uint32_t l = 0; l < num_lumps; l++)
	{
		entry = entryAt(l);
		mc.write(entry->rawData(), entry->size());
	}

	// Write the directory
	for (uint32_t l = 0; l < num_lumps; l++)
	{
		entry = entryAt(l);

		// Setup directory entry
		Wad2Entry info;
		memset(info.name, 0, 16);
		memcpy(info.name, CHR(entry->name()), entry->name().Len());
		info.cmprs  = (bool)entry->exProp("W2Comp");
		info.dsize  = entry->size();
		info.size   = entry->size();
		info.offset = (int)entry->exProp("Offset");
		info.type   = (int)entry->exProp("W2Type");

		// Write it
		mc.write(&info, 32);

		if (update)
			entry->setState(ArchiveEntry::State::Unmodified);
	}

	return true;
}
Esempio n. 2
0
// -----------------------------------------------------------------------------
// Reads non-UDMF thing data
// -----------------------------------------------------------------------------
bool MapPreviewCanvas::readThings(ArchiveEntry* map_head, ArchiveEntry* map_end, MapFormat map_format)
{
	// Find THINGS entry
	ArchiveEntry* things = nullptr;
	while (map_head)
	{
		// Check entry type
		if (map_head->type() == EntryType::fromId("map_things"))
		{
			things = map_head;
			break;
		}

		// Exit loop if we've reached the end of the map entries
		if (map_head == map_end)
			break;
		else
			map_head = map_head->nextEntry();
	}

	// No things
	if (!things)
		return false;

	// Read things data
	if (map_format == MapFormat::Doom)
	{
		auto     thng_data = (DoomMapFormat::Thing*)things->rawData(true);
		unsigned nt        = things->size() / sizeof(DoomMapFormat::Thing);
		for (size_t a = 0; a < nt; a++)
			addThing(thng_data[a].x, thng_data[a].y);
	}
	else if (map_format == MapFormat::Doom64)
	{
		auto     thng_data = (Doom64MapFormat::Thing*)things->rawData(true);
		unsigned nt        = things->size() / sizeof(Doom64MapFormat::Thing);
		for (size_t a = 0; a < nt; a++)
			addThing(thng_data[a].x, thng_data[a].y);
	}
	else if (map_format == MapFormat::Hexen)
	{
		auto     thng_data = (HexenMapFormat::Thing*)things->rawData(true);
		unsigned nt        = things->size() / sizeof(HexenMapFormat::Thing);
		for (size_t a = 0; a < nt; a++)
			addThing(thng_data[a].x, thng_data[a].y);
	}

	return true;
}
Esempio n. 3
0
// -----------------------------------------------------------------------------
// Writes the grp archive to a MemChunk
// Returns true if successful, false otherwise
// -----------------------------------------------------------------------------
bool GrpArchive::write(MemChunk& mc, bool update)
{
	// Clear/init MemChunk
	mc.clear();
	mc.seek(0, SEEK_SET);
	mc.reSize((1 + numEntries()) * 16);
	ArchiveEntry* entry;

	// Write the header
	uint32_t num_lumps = numEntries();
	mc.write("KenSilverman", 12);
	mc.write(&num_lumps, 4);

	// Write the directory
	for (uint32_t l = 0; l < num_lumps; l++)
	{
		entry         = entryAt(l);
		char name[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
		long size     = entry->size();

		for (size_t c = 0; c < entry->name().length() && c < 12; c++)
			name[c] = entry->name()[c];

		mc.write(name, 12);
		mc.write(&size, 4);

		if (update)
		{
			long offset = getEntryOffset(entry);
			entry->setState(ArchiveEntry::State::Unmodified);
			entry->exProp("Offset") = (int)offset;
		}
	}

	// Write the lumps
	for (uint32_t l = 0; l < num_lumps; l++)
	{
		entry = entryAt(l);
		mc.write(entry->rawData(), entry->size());
	}

	return true;
}
Esempio n. 4
0
// -----------------------------------------------------------------------------
// Opens a map from a mapdesc_t
// -----------------------------------------------------------------------------
bool MapPreviewCanvas::openMap(Archive::MapDesc map)
{
	// All errors = invalid map
	Global::error = "Invalid map";

	// Check if this map is a pk3 map
	bool map_archive = false;
	if (map.archive)
	{
		map_archive = true;

		// Attempt to open entry as wad archive
		temp_archive_ = new WadArchive();
		if (!temp_archive_->open(map.head))
		{
			delete temp_archive_;
			return false;
		}

		// Detect maps
		auto maps = temp_archive_->detectMaps();

		// Set map if there are any in the archive
		if (!maps.empty())
			map = maps[0];
		else
			return false;
	}

	// Parse UDMF map
	if (map.format == MapFormat::UDMF)
	{
		ArchiveEntry* udmfdata = nullptr;
		for (auto mapentry = map.head; mapentry != map.end; mapentry = mapentry->nextEntry())
		{
			// Check entry type
			if (mapentry->type() == EntryType::fromId("udmf_textmap"))
			{
				udmfdata = mapentry;
				break;
			}
		}
		if (udmfdata == nullptr)
			return false;

		// Start parsing
		Tokenizer tz;
		tz.openMem(udmfdata->data(), map.head->name());

		// Get first token
		wxString token       = tz.getToken();
		size_t   vertcounter = 0, linecounter = 0, thingcounter = 0;
		while (!token.IsEmpty())
		{
			if (!token.CmpNoCase("namespace"))
			{
				//  skip till we reach the ';'
				do
				{
					token = tz.getToken();
				} while (token.Cmp(";"));
			}
			else if (!token.CmpNoCase("vertex"))
			{
				// Get X and Y properties
				bool   gotx = false;
				bool   goty = false;
				double x    = 0.;
				double y    = 0.;
				do
				{
					token = tz.getToken();
					if (!token.CmpNoCase("x") || !token.CmpNoCase("y"))
					{
						bool isx = !token.CmpNoCase("x");
						token    = tz.getToken();
						if (token.Cmp("="))
						{
							Log::error(wxString::Format("Bad syntax for vertex %i in UDMF map data", vertcounter));
							return false;
						}
						if (isx)
							x = tz.getDouble(), gotx = true;
						else
							y = tz.getDouble(), goty = true;
						// skip to end of declaration after each key
						do
						{
							token = tz.getToken();
						} while (token.Cmp(";"));
					}
				} while (token.Cmp("}"));
				if (gotx && goty)
					addVertex(x, y);
				else
				{
					Log::error(wxString::Format("Wrong vertex %i in UDMF map data", vertcounter));
					return false;
				}
				vertcounter++;
			}
			else if (!token.CmpNoCase("linedef"))
			{
				bool   special  = false;
				bool   twosided = false;
				bool   gotv1 = false, gotv2 = false;
				size_t v1 = 0, v2 = 0;
				do
				{
					token = tz.getToken();
					if (!token.CmpNoCase("v1") || !token.CmpNoCase("v2"))
					{
						bool isv1 = !token.CmpNoCase("v1");
						token     = tz.getToken();
						if (token.Cmp("="))
						{
							Log::error(wxString::Format("Bad syntax for linedef %i in UDMF map data", linecounter));
							return false;
						}
						if (isv1)
							v1 = tz.getInteger(), gotv1 = true;
						else
							v2 = tz.getInteger(), gotv2 = true;
						// skip to end of declaration after each key
						do
						{
							token = tz.getToken();
						} while (token.Cmp(";"));
					}
					else if (!token.CmpNoCase("special"))
					{
						special = true;
						// skip to end of declaration after each key
						do
						{
							token = tz.getToken();
						} while (token.Cmp(";"));
					}
					else if (!token.CmpNoCase("sideback"))
					{
						twosided = true;
						// skip to end of declaration after each key
						do
						{
							token = tz.getToken();
						} while (token.Cmp(";"));
					}
				} while (token.Cmp("}"));
				if (gotv1 && gotv2)
					addLine(v1, v2, twosided, special);
				else
				{
					Log::error(wxString::Format("Wrong line %i in UDMF map data", linecounter));
					return false;
				}
				linecounter++;
			}
			else if (S_CMPNOCASE(token, "thing"))
			{
				// Get X and Y properties
				bool   gotx = false;
				bool   goty = false;
				double x    = 0.;
				double y    = 0.;
				do
				{
					token = tz.getToken();
					if (!token.CmpNoCase("x") || !token.CmpNoCase("y"))
					{
						bool isx = !token.CmpNoCase("x");
						token    = tz.getToken();
						if (token.Cmp("="))
						{
							Log::error(wxString::Format("Bad syntax for thing %i in UDMF map data", vertcounter));
							return false;
						}
						if (isx)
							x = tz.getDouble(), gotx = true;
						else
							y = tz.getDouble(), goty = true;
						// skip to end of declaration after each key
						do
						{
							token = tz.getToken();
						} while (token.Cmp(";"));
					}
				} while (token.Cmp("}"));
				if (gotx && goty)
					addThing(x, y);
				else
				{
					Log::error(wxString::Format("Wrong thing %i in UDMF map data", vertcounter));
					return false;
				}
				vertcounter++;
			}
			else
			{
				// Check for side or sector definition (increase counts)
				if (S_CMPNOCASE(token, "sidedef"))
					n_sides_++;
				else if (S_CMPNOCASE(token, "sector"))
					n_sectors_++;

				// map preview ignores sidedefs, sectors, comments,
				// unknown fields, etc. so skip to end of block
				do
				{
					token = tz.getToken();
				} while (token.Cmp("}") && !token.empty());
			}
			// Iterate to next token
			token = tz.getToken();
		}
	}

	// Non-UDMF map
	if (map.format != MapFormat::UDMF)
	{
		// Read vertices (required)
		if (!readVertices(map.head, map.end, map.format))
			return false;

		// Read linedefs (required)
		if (!readLines(map.head, map.end, map.format))
			return false;

		// Read things
		if (map.format != MapFormat::UDMF)
			readThings(map.head, map.end, map.format);

		// Read sides & sectors (count only)
		ArchiveEntry* sidedefs = nullptr;
		ArchiveEntry* sectors  = nullptr;
		while (map.head)
		{
			// Check entry type
			if (map.head->type() == EntryType::fromId("map_sidedefs"))
				sidedefs = map.head;
			if (map.head->type() == EntryType::fromId("map_sectors"))
				sectors = map.head;

			// Exit loop if we've reached the end of the map entries
			if (map.head == map.end)
				break;
			else
				map.head = map.head->nextEntry();
		}
		if (sidedefs && sectors)
		{
			// Doom64 map
			if (map.format != MapFormat::Doom64)
			{
				n_sides_   = sidedefs->size() / 30;
				n_sectors_ = sectors->size() / 26;
			}

			// Doom/Hexen map
			else
			{
				n_sides_   = sidedefs->size() / 12;
				n_sectors_ = sectors->size() / 16;
			}
		}
	}

	// Clean up
	if (map_archive)
	{
		temp_archive_->close();
		delete temp_archive_;
		temp_archive_ = nullptr;
	}

	// Refresh map
	Refresh();

	return true;
}
Esempio n. 5
0
bool TarReader::readHeader(Ref<ArchiveEntry> *nextEntry)
{
    if (!data_) data_ = ByteArray::create(512);
    *nextEntry = ArchiveEntry::create();

    ByteArray *data = data_;
    ArchiveEntry *entry = *nextEntry;

    if (source_->readAll(data) < data->count()) return false;
    i_ += data->count();

    bool eoi = true;
    for (int i = 0; i < data->count(); ++i) {
        if (data->byteAt(i) != 0) {
            eoi = false;
            break;
        }
    }

    if (eoi) return false;

    bool ustarMagic = false;
    bool gnuMagic = false;

    bool readAgain = true;
    while (readAgain) {
        readAgain = false;

        String magic;
        data->scanString(&magic, "", 257, 263);
        ustarMagic = (magic == "ustar");
        gnuMagic   = (magic == "ustar ");

        unsigned checksum, probesum;
        data->scanNumber(&checksum, 8, 148, 156);
        entry->type_ = data->at(156);
        if (entry->path_ == "")     data->scanString(&entry->path_,     "", 0,   100);
        if (entry->linkPath_ == "") data->scanString(&entry->linkPath_, "", 157, 257);

        probesum = tarHeaderSum(data);
        if (checksum != probesum)
            throw BrokenArchive(i_ - data->count(), Format("Checksum mismatch (%% != %%), path = \"%%\"") << oct(checksum, 6) << oct(probesum, 6) << entry->path());

        if (gnuMagic) {
            while ((entry->type_ == 'K' || entry->type_ == 'L') /*&& entry->path_ == "././@LongLink"*/) {
                data->scanNumber(&entry->size_, 8, 124, 136);
                String longPath = source_->readAll(entry->size_);
                if (longPath->count() < entry->size_)
                    throw BrokenArchive(i_, "Expected GNU @LongLink data");
                i_ += entry->size_;
                if (entry->size() % 512 != 0) {
                    i_ += source_->skip(512 - entry->size() % 512);
                }
                if (longPath->byteAt(longPath->count() - 1) == 0)
                    longPath->truncate(longPath->count() - 1);
                if (entry->type_ == 'K') entry->linkPath_ = longPath;
                else if (entry->type_ == 'L') entry->path_ = longPath;
                if (source_->readAll(data) < data->count())
                    throw BrokenArchive(i_, "Expected GNU @LongLink header");
                i_ += data->count();
                entry->type_ = data->at(156);
                readAgain = true;
            }
        }
    }

    if (ustarMagic || gnuMagic) {
        String prefix;
        data->scanString(&entry->userName_,  "", 265, 297);
        data->scanString(&entry->groupName_, "", 297, 329);
        if (!gnuMagic) {
            data->scanString(&prefix,        "", 345, 500);
            if (prefix != "") entry->path_ = prefix + "/" + entry->path_;
        }
    }

    data->scanNumber(&entry->mode_,         8, 100, 108);
    data->scanNumber(&entry->userId_,       8, 108, 116);
    data->scanNumber(&entry->groupId_,      8, 116, 124);
    data->scanNumber(&entry->size_,         8, 124, 136);
    data->scanNumber(&entry->lastModified_, 8, 136, 148);

    if (entry->type() == 0 && entry->path()->count() > 0) {
        if (entry->path()->at(entry->path()->count() - 1) == '/')
            entry->type_ = ArchiveEntry::Directory;
    }

    entry->offset_ = i_;

    return true;
}
Esempio n. 6
0
// -----------------------------------------------------------------------------
// Writes the lfd archive to a MemChunk
// Returns true if successful, false otherwise
// -----------------------------------------------------------------------------
bool LfdArchive::write(MemChunk& mc, bool update)
{
	// Determine total size
	uint32_t      dir_size   = (numEntries() + 1) << 4;
	uint32_t      total_size = dir_size;
	ArchiveEntry* entry;
	for (uint32_t l = 0; l < numEntries(); l++)
	{
		entry = entryAt(l);
		total_size += 16;
		setEntryOffset(entry, total_size);
		if (update)
		{
			entry->setState(ArchiveEntry::State::Unmodified);
			entry->exProp("Offset") = (int)total_size;
		}
		total_size += entry->size();
	}

	// Clear/init MemChunk
	mc.clear();
	mc.seek(0, SEEK_SET);
	mc.reSize(total_size);

	// Variables
	char   type[5] = "RMAP";
	char   name[9] = "resource";
	size_t size    = wxINT32_SWAP_ON_BE(numEntries() << 4);


	// Write the resource map first
	mc.write(type, 4);
	mc.write(name, 8);
	mc.write(&size, 4);
	for (uint32_t l = 0; l < numEntries(); l++)
	{
		entry = entryAt(l);
		for (char& t : type)
			t = 0;
		for (char& n : name)
			n = 0;
		size = wxINT32_SWAP_ON_BE(entry->size());
		wxFileName fn(entry->name());

		for (size_t c = 0; c < fn.GetName().length() && c < 9; c++)
			name[c] = fn.GetName()[c];
		for (size_t c = 0; c < fn.GetExt().length() && c < 5; c++)
			type[c] = fn.GetExt()[c];

		mc.write(type, 4);
		mc.write(name, 8);
		mc.write(&size, 4);
	}

	// Write the lumps
	for (uint32_t l = 0; l < numEntries(); l++)
	{
		entry = entryAt(l);
		for (char& t : type)
			t = 0;
		for (char& n : name)
			n = 0;
		size = wxINT32_SWAP_ON_BE(entry->size());
		wxFileName fn(entry->name());

		for (size_t c = 0; c < fn.GetName().length() && c < 9; c++)
			name[c] = fn.GetName()[c];
		for (size_t c = 0; c < fn.GetExt().length() && c < 5; c++)
			type[c] = fn.GetExt()[c];

		mc.write(type, 4);
		mc.write(name, 8);
		mc.write(&size, 4);
		mc.write(entry->rawData(), entry->size());
	}

	return true;
}