/* ArchiveEntry::ArchiveEntry * ArchiveEntry class copy constructor *******************************************************************/ ArchiveEntry::ArchiveEntry(ArchiveEntry& copy) { // Initialise (copy) attributes this->parent = NULL; this->name = copy.name; this->size = copy.size; this->data_loaded = true; this->state = 2; this->type = copy.type; this->locked = false; this->state_locked = false; this->reliability = copy.reliability; this->next = NULL; this->prev = NULL; this->encrypted = copy.encrypted; // Copy data data.importMem(copy.getData(true), copy.getSize()); // Copy extra properties copy.exProps().copyTo(ex_props); // Clear properties that shouldn't be copied ex_props.removeProperty("ZipIndex"); ex_props.removeProperty("Offset"); // Set entry state state = 2; state_locked = false; }
/* WadArchive::open * Reads wad format data from a MemChunk * Returns true if successful, false otherwise *******************************************************************/ bool WadArchive::open(MemChunk& mc) { // Check data was given if (!mc.hasData()) return false; // Read wad header uint32_t num_lumps = 0; uint32_t dir_offset = 0; char wad_type[4] = ""; mc.seek(0, SEEK_SET); mc.read(&wad_type, 4); // Wad type mc.read(&num_lumps, 4); // No. of lumps in wad mc.read(&dir_offset, 4); // Offset to directory // Byteswap values for big endian if needed num_lumps = wxINT32_SWAP_ON_BE(num_lumps); dir_offset = wxINT32_SWAP_ON_BE(dir_offset); // Check the header if (wad_type[1] != 'W' || wad_type[2] != 'A' || wad_type[3] != 'D') { wxLogMessage("WadArchive::openFile: File %s has invalid header", filename); Global::error = "Invalid wad header"; return false; } // Check for iwad if (wad_type[0] == 'I') iwad = true; // Stop announcements (don't want to be announcing modification due to entries being added etc) setMuted(true); vector<uint32_t> offsets; // Read the directory mc.seek(dir_offset, SEEK_SET); theSplashWindow->setProgressMessage("Reading wad archive data"); for (uint32_t d = 0; d < num_lumps; d++) { // Update splash window progress theSplashWindow->setProgress(((float)d / (float)num_lumps)); // Read lump info char name[9] = ""; uint32_t offset = 0; uint32_t size = 0; mc.read(&offset, 4); // Offset mc.read(&size, 4); // Size mc.read(name, 8); // Name name[8] = '\0'; // Byteswap values for big endian if needed offset = wxINT32_SWAP_ON_BE(offset); size = wxINT32_SWAP_ON_BE(size); // Check to catch stupid shit if (size > 0) { if (offset == 0) { LOG_MESSAGE(2, "No."); continue; } if (VECTOR_EXISTS(offsets, offset)) { LOG_MESSAGE(1, "Ignoring entry %d: %s, is a clone of a previous entry", d, name); continue; } offsets.push_back(offset); } // Hack to open Operation: Rheingold WAD files if (size == 0 && offset > mc.getSize()) offset = 0; // Is there a compression/encryption thing going on? bool jaguarencrypt = !!(name[0] & 0x80); // look at high bit name[0] = name[0] & 0x7F; // then strip it away // Look for encryption shenanigans size_t actualsize = size; if (jaguarencrypt) { if (d < num_lumps - 1) { size_t pos = mc.currentPos(); uint32_t nextoffset = 0; for (int i = 0; i + d < num_lumps; ++i) { mc.read(&nextoffset, 4); if (nextoffset != 0) break; mc.seek(12, SEEK_CUR); } nextoffset = wxINT32_SWAP_ON_BE(nextoffset); if (nextoffset == 0) nextoffset = dir_offset; mc.seek(pos, SEEK_SET); actualsize = nextoffset - offset; } else { if (offset > dir_offset) { actualsize = mc.getSize() - offset; } else { actualsize = dir_offset - offset; } } } // If the lump data goes past the end of the file, // the wadfile is invalid if (offset + actualsize > mc.getSize()) { wxLogMessage("WadArchive::open: Wad archive is invalid or corrupt"); Global::error = S_FMT("Archive is invalid and/or corrupt (lump %d: %s data goes past end of file)", d, name); setMuted(false); return false; } // Create & setup lump ArchiveEntry* nlump = new ArchiveEntry(wxString::FromAscii(name), size); nlump->setLoaded(false); nlump->exProp("Offset") = (int)offset; nlump->setState(0); if (jaguarencrypt) { nlump->setEncryption(ENC_JAGUAR); nlump->exProp("FullSize") = (int)size; } // Add to entry list getRoot()->addEntry(nlump); } // Detect namespaces (needs to be done before type detection as some types // rely on being within certain namespaces) updateNamespaces(); // Detect all entry types MemChunk edata; theSplashWindow->setProgressMessage("Detecting entry types"); for (size_t a = 0; a < numEntries(); a++) { // Update splash window progress theSplashWindow->setProgress((((float)a / (float)numEntries()))); // Get entry ArchiveEntry* entry = getEntry(a); // Read entry data if it isn't zero-sized if (entry->getSize() > 0) { // Read the entry data mc.exportMemChunk(edata, getEntryOffset(entry), entry->getSize()); if (entry->isEncrypted()) { if (entry->exProps().propertyExists("FullSize") && (unsigned)(int)(entry->exProp("FullSize")) > entry->getSize()) edata.reSize((int)(entry->exProp("FullSize")), true); if (!JaguarDecode(edata)) wxLogMessage("%i: %s (following %s), did not decode properly", a, entry->getName(), a>0?getEntry(a-1)->getName():"nothing"); } entry->importMemChunk(edata); } // Detect entry type EntryType::detectEntryType(entry); // Unload entry data if needed if (!archive_load_data) entry->unloadData(); // Set entry to unchanged entry->setState(0); } // Identify #included lumps (DECORATE, GLDEFS, etc.) detectIncludes(); // Detect maps (will detect map entry types) theSplashWindow->setProgressMessage("Detecting maps"); detectMaps(); // Setup variables setMuted(false); setModified(false); //if (iwad && iwad_lock) read_only = true; announce("opened"); theSplashWindow->setProgressMessage(""); return true; }