/* WadArchive::addEntry * Override of Archive::addEntry to force entry addition to the root * directory, update namespaces if needed and rename the entry if * necessary to be wad-friendly (8 characters max and no file * extension) *******************************************************************/ ArchiveEntry* WadArchive::addEntry(ArchiveEntry* entry, unsigned position, ArchiveTreeNode* dir, bool copy) { // Check entry if (!entry) return NULL; // Check if read-only if (isReadOnly()) return NULL; // Copy if necessary if (copy) entry = new ArchiveEntry(*entry); // Set new wad-friendly name string name = processEntryName(entry->getName()); entry->setName(name); // Do default entry addition (to root directory) Archive::addEntry(entry, position); // Update namespaces if necessary if (name.EndsWith("_START") || name.EndsWith("_END")) updateNamespaces(); return entry; }
void RObjectList::rCommandDone (RCommand *command) { RK_TRACE (OBJECTS); if (command->getFlags () == ROBJECTLIST_UPDATE_ENVIRONMENTS_COMMAND) { RK_ASSERT (command->getDataType () == RData::StructureVector); const RData::RDataStorage & data = command->structureVector (); RK_ASSERT (data.size () == 2); QStringList new_environments = data[0]->stringVector (); RK_ASSERT (new_environments.size () >= 2); updateEnvironments (new_environments, true); updateNamespaces (data[1]->stringVector ()); RKGlobals::rInterface ()->issueCommand (QString (), RCommand::App | RCommand::Sync | RCommand::EmptyCommand, QString (), this, ROBJECTLIST_UPDATE_COMPLETE_COMMAND, update_chain); } else if (command->getFlags () == ROBJECTLIST_UPDATE_COMPLETE_COMMAND) { RK_ASSERT (update_chain); RKGlobals::rInterface ()->closeChain (update_chain); update_chain = 0; RK_DEBUG (OBJECTS, DL_DEBUG, "object list update complete"); emit (updateComplete ()); } else { RK_ASSERT (false); } }
void RObjectList::updateFromR (RCommandChain *chain, const QStringList ¤t_searchpath, const QStringList ¤t_namespaces) { RK_TRACE (OBJECTS); // TODO: can this happen? when? if (update_chain) { // gee, looks like another update is still on the way. lets schedule one for later: update_timer->start (UPDATE_DELAY_INTERVAL); RK_DEBUG (OBJECTS, DL_DEBUG, "another object-list update is already running. Rescheduling a further update for later"); return; } emit (updateStarted ()); update_chain = RKGlobals::rInterface ()->startChain (chain); updateEnvironments (current_searchpath, false); updateNamespaces (current_namespaces); RKGlobals::rInterface ()->issueCommand (QString (), RCommand::App | RCommand::Sync | RCommand::EmptyCommand, QString (), this, ROBJECTLIST_UPDATE_COMPLETE_COMMAND, update_chain); }
/* DatArchive::moveEntry * Override of Archive::moveEntry to update namespaces if needed *******************************************************************/ bool DatArchive::moveEntry(ArchiveEntry* entry, unsigned position, ArchiveTreeNode* dir) { // Check entry if (!checkEntry(entry)) return false; // Do default move (force root dir) bool ok = Archive::moveEntry(entry, position, NULL); if (ok) { // Update namespaces if necessary if (entry->getName().Upper().Matches("START*") || entry->getName().Upper().Matches("END*")) updateNamespaces(); return true; } else return false; }
/* DatArchive::renameEntry * Override of Archive::renameEntry to update namespaces if needed *******************************************************************/ bool DatArchive::renameEntry(ArchiveEntry* entry, string name) { // Check entry if (!checkEntry(entry)) return false; // Do default rename bool ok = Archive::renameEntry(entry, name); if (ok) { // Update namespaces if necessary if (entry->getName().Upper().Matches("START*") || entry->getName().Upper().Matches("END*")) updateNamespaces(); return true; } else return false; }
/* WadArchive::renameEntry * Override of Archive::renameEntry to update namespaces if needed * and rename the entry if necessary to be wad-friendly (8 characters * max and no file extension) *******************************************************************/ bool WadArchive::renameEntry(ArchiveEntry* entry, string name) { // Check entry if (!checkEntry(entry)) return false; name = processEntryName(name); // Do default rename bool ok = Archive::renameEntry(entry, name); if (ok) { // Update namespaces if necessary if (entry->getName().Upper().Matches("*_START") || entry->getName().Upper().Matches("*_END")) updateNamespaces(); return true; } return false; }
/* DatArchive::swapEntries * Override of Archive::swapEntries to update namespaces if needed *******************************************************************/ bool DatArchive::swapEntries(ArchiveEntry* entry1, ArchiveEntry* entry2) { // Check entries if (!checkEntry(entry1) || !checkEntry(entry2)) return false; // Do default swap (force root dir) bool ok = Archive::swapEntries(entry1, entry2); if (ok) { // Update namespaces if needed if (entry1->getName().Upper().Matches("START*") || entry1->getName().Upper().Matches("END*") || entry2->getName().Upper().Matches("START*") || entry2->getName().Upper().Matches("END*")) updateNamespaces(); return true; } else return false; }
/* DatArchive::removeEntry * Override of Archive::removeEntry to update namespaces if needed *******************************************************************/ bool DatArchive::removeEntry(ArchiveEntry* entry, bool delete_entry) { // Check entry if (!checkEntry(entry)) return false; // Get entry name (for later) string name = entry->getName(); // Do default remove bool ok = Archive::removeEntry(entry, delete_entry); if (ok) { // Update namespaces if necessary if (name.Upper().Matches("START*") || name.Upper().Matches("END*")) updateNamespaces(); return true; } else return false; }
/* DatArchive::addEntry * Override of Archive::addEntry to force entry addition to the root * directory, and update namespaces if needed *******************************************************************/ ArchiveEntry* DatArchive::addEntry(ArchiveEntry* entry, unsigned position, ArchiveTreeNode* dir, bool copy) { // Check entry if (!entry) return NULL; // Check if read-only if (isReadOnly()) return NULL; // Copy if necessary if (copy) entry = new ArchiveEntry(*entry); // Do default entry addition (to root directory) Archive::addEntry(entry, position); // Update namespaces if necessary if (entry->getName().Upper().Matches("START*") || entry->getName().Upper().Matches("END*")) updateNamespaces(); return entry; }
/* 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; }