// ----------------------------------------------------------------------------- // Adds all available colour configuration names to [names] // ----------------------------------------------------------------------------- void ColourConfiguration::putConfigurationNames(vector<std::string>& names) { // TODO: search custom folder // Search resource pk3 auto res = App::archiveManager().programResourceArchive(); auto dir = res->dir("config/colours"); for (unsigned a = 0; a < dir->numEntries(); a++) names.emplace_back(dir->entryAt(a)->nameNoExt()); }
// important that it be big enough, not so important it's exact int OsConfigDb::calculateBufferSize() const { int n = numEntries(); size_t size = n * strlen(DB_LINE_FORMAT); for (int i = 0; i < n; i++) { DbEntry *pEntry = (DbEntry *)mDb.at(i); size += pEntry->key.length() + pEntry->value.length(); } return size; }
void CategoryTree::onContextMenu( wxTreeEvent& p_event ) { wxArrayTreeItemIds ids; this->GetSelections( ids ); if ( ids.Count( ) > 0 ) { // Start with counting the total amount of entries uint count = 0; const DatIndexEntry* firstEntry = nullptr; for ( uint i = 0; i < ids.Count( ); i++ ) { auto itemData = static_cast<const CategoryTreeItem*>( this->GetItemData( ids[i] ) ); if ( itemData->dataType( ) == CategoryTreeItem::DT_Entry ) { if ( !firstEntry ) { firstEntry = ( const DatIndexEntry* ) itemData->data( ); } count++; } else if ( itemData->dataType( ) == CategoryTreeItem::DT_Category ) { auto category = static_cast<const DatIndexCategory*>( itemData->data( ) ); count += category->numEntries( true ); if ( !firstEntry && category->numEntries( ) ) { firstEntry = category->entry( 0 ); } } } // Create the menu if ( count > 0 ) { wxMenu newMenu; if ( count == 1 ) { newMenu.Append( wxID_SAVE, wxString::Format( wxT( "Extract file %s..." ), firstEntry->name( ) ) ); newMenu.Append( wxID_SAVEAS, wxString::Format( wxT( "Extract file %s (raw)..." ), firstEntry->name( ) ) ); } else { newMenu.Append( wxID_SAVE, wxString::Format( wxT( "Extract %d files..." ), count ) ); newMenu.Append( wxID_SAVEAS, wxString::Format( wxT( "Extract %d files (raw)..." ), count ) ); } this->PopupMenu( &newMenu ); } } }
// ----------------------------------------------------------------------------- // Reads saved colour configuration [name] // ----------------------------------------------------------------------------- bool ColourConfiguration::readConfiguration(std::string_view name) { // TODO: search custom folder // Search resource pk3 auto res = App::archiveManager().programResourceArchive(); auto dir = res->dir("config/colours"); for (unsigned a = 0; a < dir->numEntries(); a++) { if (StrUtil::equalCI(dir->entryAt(a)->nameNoExt(), name)) return readConfiguration(dir->entryAt(a)->data()); } return false; }
void CategoryTree::onItemExpanding( wxTreeEvent& p_event ) { auto id = p_event.GetItem( ); auto itemData = static_cast<CategoryTreeItem*>( this->GetItemData( id ) ); // If this is not a category, skip it if ( itemData && itemData->dataType( ) != CategoryTreeItem::DT_Category ) { return; } // Give it the open folder icon instead this->SetItemImage( id, CategoryTreeImageList::IT_OpenFolder ); // Skip if the category isn't dirty if ( !itemData->isDirty( ) ) { return; } else { this->DeleteChildren( id ); } // Fetch the category info auto category = static_cast<const DatIndexCategory*>( itemData->data( ) ); if ( !category ) { return; } // Add all contained entries for ( uint i = 0; i < category->numEntries( ); i++ ) { auto entry = category->entry( i ); if ( !entry ) { continue; } //this->AddEntry(id, *entry); this->AppendItem( id, entry->name( ), this->getImageForEntry( *entry ), -1, new CategoryTreeItem( CategoryTreeItem::DT_Entry, entry ) ); } this->SortChildren( id ); // Add sub-categories last for ( uint i = 0; i < category->numSubCategories( ); i++ ) { auto subcategory = category->subCategory( i ); if ( !subcategory ) { continue; } this->ensureHasCategory( *subcategory, true ); } // Un-dirty! itemData->setDirty( false ); }
void OsConfigDb::storeToBuffer(char *buff) const { char *p = buff; int n = numEntries(); for (int i = 0; i < n; i++) { DbEntry *pEntry = (DbEntry *)mDb.at(i); removeChars(&pEntry->key, '\r'); removeChars(&pEntry->value, '\n'); sprintf(p, DB_LINE_FORMAT, (char *)pEntry->key.data(), (char *)pEntry->value.data()); p = buff + strlen(buff); } }
// Relative to rKey, return the key and value associated with // next (lexicographically ordered) key/value pair stored in the // database. If rKey is the empty string, key and value associated // with the first entry in the database will be returned. // Returns // OS_SUCCESS if there is a "next" entry // OS_NOT_FOUND if rKey is not found in the database and is not the // empty string // OS_NO_MORE_DATA if there is no "next" entry OsStatus OsConfigDb::getNext(const UtlString& rKey, UtlString& rNextKey, UtlString& rNextValue) const { OsReadLock lock(mRWMutex); UtlBoolean foundMatch; size_t nextIdx = 0; DbEntry lookupPair(rKey); DbEntry* pEntry; foundMatch = FALSE; if (rKey.compareTo("") == 0) { foundMatch = TRUE; // if the key is the empty string, then nextIdx = 0; // return the first entry in the database } else { size_t idx = mDb.index(&lookupPair); if (idx != UTL_NOT_FOUND) { foundMatch = TRUE; nextIdx = idx + 1; } } if (foundMatch && (((int)nextIdx) < numEntries())) { pEntry = (DbEntry *)mDb.at(nextIdx); rNextKey = pEntry->key; rNextValue = pEntry->value; return OS_SUCCESS; } rNextKey = ""; rNextValue = ""; if (!foundMatch) return OS_NOT_FOUND; else return OS_NO_MORE_DATA; }
std::string kyleAndKristinTrends::getNthPopular(unsigned int n){ if (!isSorted){ std::sort(sortingArr.begin(), sortingArr.end(), [this](const std::pair<std::string, unsigned int> i, std::pair<std::string, unsigned int> j) { isSorted = true; if (ints[i.second] == ints[j.second]){ return (i.first < j.first); } return (ints[i.second] > ints[j.second]); }); } if (n <= numEntries()){ return sortingArr[n].first; } //If they give bad input, return empty string. return ""; }
void Table::hashStats(ostream &out) const { out << "Number of hash buckets: " << hashSize << endl; out << "Number of entries: " << numEntries() << endl; int numBuckets = 0; int temp; int longestChain = 0; for(int i = 0; i < hashSize; i++){ if(hashTable[i] != NULL) { numBuckets++; temp = countNodes(hashTable[i]); if(temp > longestChain) { longestChain = temp; } } } out << "Number of non-empty buckets: " << numBuckets << endl; out << "Longest chain: " << longestChain << endl; }
// ----------------------------------------------------------------------------- // Loads all text language definitions from slade.pk3 // ----------------------------------------------------------------------------- bool TextLanguage::loadLanguages() { // Get slade resource archive auto res_archive = App::archiveManager().programResourceArchive(); // Read language definitions from resource archive if (res_archive) { // Get 'config/languages' directly auto dir = res_archive->dir("config/languages"); if (dir) { // Read all entries in this dir for (unsigned a = 0; a < dir->numEntries(); a++) readLanguageDefinition(dir->entryAt(a)->data(), dir->entryAt(a)->name()); } else Log::warning( 1, "Warning: 'config/languages' not found in slade.pk3, no builtin text language definitions loaded"); } return true; }
void TimeSeriesAggregate::setOutputCol(time_t startTime, int sliceNum, time_t width) { time_t targetTime = (isFirstVal_ ? startTime : startTime + width); time_t currTime = 0; // Find the last entry before our target time, if it exists. // Include the target time for first value, exclude it for // last value (in that case the target time already belongs // to the next time slice) while (currIx_+1 < numEntries() && ((isFirstVal_ && getTime(currIx_+1) <= targetTime) || (!isFirstVal_ && getTime(currIx_+1) < targetTime))) currIx_++; if (currIx_ >= 0) currTime = getTime(currIx_); if (isConstInterpol_) { // currIx_ points to the entry with the last known constant // value to use or currIx_ is -1 (no last known value exists) if (currIx_ < 0 || (useLong_ && lValues_[currIx_].isNull()) || (!useLong_ && dValues_[currIx_].isNull())) // produce a NULL value outTup_.setNull(outputColNum_); else if (useLong_) outTup_.setLong(outputColNum_, lValues_[currIx_].getVal()); else outTup_.setDouble(outputColNum_, dValues_[currIx_].getVal()); } // constant interpolation else { // linear interpolation, always uses a double value // currIx_ points to the last known value or is -1 (no last // known value exists). Now look for the next known value. NullableTimedValue<double> interpolatedVal; if (currIx_ >= 0 && currTime == targetTime) { // currIx_ and nextIx_ point to the one // entry describing the value, no interpolation needed interpolatedVal = dValues_[currIx_]; } else if (currIx_ < 0 || currIx_+1 >= numEntries()) { // produce a NULL value for these boundary cases where // we are missing an upper or lower entry to use for // interpolation interpolatedVal = NullableTimedValue<double>(true, targetTime, 0.0); } else { // currIx_ and the next entry should have time values // that form an interval we can use to interpolate interpolatedVal = dValues_[currIx_].interpolateLinear( targetTime, dValues_[currIx_+1]); } // now produce the value if (interpolatedVal.isNull()) outTup_.setNull(outputColNum_); else outTup_.setDouble(outputColNum_, interpolatedVal.getVal()); } // linear interpolation }
/* RffArchive::open * Reads grp format data from a MemChunk * Returns true if successful, false otherwise *******************************************************************/ bool RffArchive::open(MemChunk& mc) { // Check data was given if (!mc.hasData()) return false; // Read grp header uint8_t magic[4]; uint32_t version, dir_offset, num_lumps; mc.seek(0, SEEK_SET); mc.read(magic, 4); // Should be "RFF\x18" mc.read(&version, 4); // 0x01 0x03 \x00 \x00 mc.read(&dir_offset, 4); // Offset to directory mc.read(&num_lumps, 4); // No. of lumps in rff // Byteswap values for big endian if needed dir_offset = wxINT32_SWAP_ON_BE(dir_offset); num_lumps = wxINT32_SWAP_ON_BE(num_lumps); version = wxINT32_SWAP_ON_BE(version); // Check the header if (magic[0] != 'R' || magic[1] != 'F' || magic[2] != 'F' || magic[3] != 0x1A || version != 0x301) { wxLogMessage("RffArchive::openFile: File %s has invalid header", filename); Global::error = "Invalid rff header"; return false; } // Stop announcements (don't want to be announcing modification due to entries being added etc) setMuted(true); // Read the directory RFFLump* lumps = new RFFLump[num_lumps]; mc.seek(dir_offset, SEEK_SET); theSplashWindow->setProgressMessage("Reading rff archive data"); mc.read (lumps, num_lumps * sizeof(RFFLump)); BloodCrypt (lumps, dir_offset, num_lumps * sizeof(RFFLump)); 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[13] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; uint32_t offset = wxINT32_SWAP_ON_BE(lumps[d].FilePos); uint32_t size = wxINT32_SWAP_ON_BE(lumps[d].Size); // Reconstruct name int i, j = 0; for (i = 0; i < 8; ++i) { if (lumps[d].Name[i] == 0) break; name[i] = lumps[d].Name[i]; } for (name[i++] = '.'; j < 3; ++j) name[i+j] = lumps[d].Extension[j]; // If the lump data goes past the end of the file, // the rfffile is invalid if (offset + size > mc.getSize()) { wxLogMessage("RffArchive::open: rff archive is invalid or corrupt"); Global::error = "Archive is invalid and/or corrupt"; 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); // Is the entry encrypted? if (lumps[d].Flags & 0x10) nlump->setEncryption(ENC_BLOOD); // Add to entry list getRoot()->addEntry(nlump); } delete[] lumps; // 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)num_lumps))); // 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 the entry is encrypted, decrypt it if (entry->isEncrypted()) { uint8_t* cdata = new uint8_t[entry->getSize()]; memcpy(cdata, edata.getData(), entry->getSize()); int cryptlen = entry->getSize() < 256 ? entry->getSize() : 256; BloodCrypt(cdata, 0, cryptlen); edata.importMem(cdata, entry->getSize()); delete[] cdata; } // Import data 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); } // Detect maps (will detect map entry types) //theSplashWindow->setProgressMessage("Detecting maps"); //detectMaps(); // Setup variables setMuted(false); setModified(false); announce("opened"); theSplashWindow->setProgressMessage(""); return true; }
OsStatus OsConfigDb::updateFile(const char* filename) const { UtlString originalFileContents; long fileLength = OsFile::openAndRead(filename, originalFileContents); const char* unparsedBits = originalFileContents; int unparsedLength = originalFileContents.length(); // Loop through and try to preserve comments, space and order int lineStart = 0; int lineEnd = 0; UtlHashBag writtenNames; UtlString newFileContents; UtlString name; UtlString value; UtlString newValue; while(lineStart < unparsedLength) { lineEnd = UtlTokenizer::nextDelim(unparsedBits, lineStart, unparsedLength, "\n\r"); //printf("start: %d end: %d length: %d\n", lineStart, lineEnd, unparsedLength); UtlString oneLine(&unparsedBits[lineStart], lineEnd - lineStart); //printf("Line: <%s>\n", oneLine.data()); // If line contains a parameter if(parseLine(oneLine, mCapitalizeName, filename, name, value)) { //printf("name<%s> value<%s>\n", name.data(), value.data()); if(get(name, newValue) == OS_SUCCESS && !writtenNames.contains(&name)) { //printf("Wrote name<%s>\n", name.data()); // The parameter still exists in the configDb and we have not yet // written it out, write the potentially changed value newFileContents.appendFormat("%s : %s\n", name.data(), newValue.data()); // Save names/parameters written so that we can figure out what has not // been written out writtenNames.insert(new UtlString(name)); } // else the parameter was removed, do nothing } // The line was a comment or blank line, write it back out the same else { newFileContents.appendFormat("%s\n", oneLine.data()); } lineStart = lineEnd + 1; } int paramIndex; int paramCount = numEntries(); DbEntry* paramEntry; for (paramIndex = 0; paramIndex < paramCount; paramIndex++) { paramEntry = (DbEntry*) mDb.at(paramIndex); removeNewlineReturns(paramEntry->key); removeNewlineReturns(paramEntry->value); // We have not written the value yet if(!writtenNames.contains(&(paramEntry->key))) { newFileContents.appendFormat("%s : %s\n", paramEntry->key.data(), paramEntry->value.data()); writtenNames.insert(new UtlString(paramEntry->key)); } } fileLength = OsFile::openAndWrite(filename, newFileContents); writtenNames.destroyAll(); return(fileLength > 0 ? OS_SUCCESS : OS_INVALID_ARGUMENT); }
/* Wad2Archive::open * Reads wad format data from a MemChunk * Returns true if successful, false otherwise *******************************************************************/ bool Wad2Archive::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[0] != 'W' || wad_type[1] != 'A' || wad_type[2] != 'D' || (wad_type[3] != '2' && wad_type[3] != '3')) { wxLogMessage("Wad2Archive::open: Invalid header"); Global::error = "Invalid wad2 header"; return false; } if (wad_type[3] == '3') wad3 = true; // Stop announcements (don't want to be announcing modification due to entries being added etc) setMuted(true); // 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 wad2entry_t info; mc.read(&info, 32); // Byteswap values for big endian if needed info.offset = wxINT32_SWAP_ON_BE(info.offset); info.size = wxINT32_SWAP_ON_BE(info.size); info.dsize = wxINT32_SWAP_ON_BE(info.dsize); // If the lump data goes past the end of the file, // the wadfile is invalid if ((unsigned)(info.offset + info.dsize) > mc.getSize()) { wxLogMessage("Wad2Archive::open: Wad2 archive is invalid or corrupt"); Global::error = "Archive is invalid and/or corrupt"; setMuted(false); return false; } // Create & setup lump ArchiveEntry* nlump = new ArchiveEntry(wxString::FromAscii(info.name, 16), info.dsize); nlump->setLoaded(false); nlump->exProp("Offset") = (int)info.offset; nlump->exProp("W2Type") = info.type; nlump->exProp("W2Size") = (int)info.size; nlump->exProp("W2Comp") = !!(info.cmprs); nlump->setState(0); // Add to entry list getRoot()->addEntry(nlump); } // 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)num_lumps))); // 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, (int)entry->exProp("Offset"), entry->getSize()); 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); } // Detect maps (will detect map entry types) theSplashWindow->setProgressMessage("Detecting maps"); detectMaps(); // Setup variables setMuted(false); setModified(false); announce("opened"); theSplashWindow->setProgressMessage(""); return true; }
/* GobArchive::open * Reads gob format data from a MemChunk * Returns true if successful, false otherwise *******************************************************************/ bool GobArchive::open(MemChunk& mc) { // Check data was given if (!mc.hasData()) return false; // Check size if (mc.getSize() < 12) return false; // Check magic header if (mc[0] != 'G' || mc[1] != 'O' || mc[2] != 'B' || mc[3] != 0xA) return false; // Get directory offset uint32_t dir_offset = 0; mc.seek(4, SEEK_SET); mc.read(&dir_offset, 4); dir_offset = wxINT32_SWAP_ON_BE(dir_offset); // Check size if ((unsigned)mc.getSize() < (dir_offset + 4)) return false; // Get number of lumps uint32_t num_lumps = 0; mc.seek(dir_offset, SEEK_SET); mc.read(&num_lumps, 4); num_lumps = wxINT32_SWAP_ON_BE(num_lumps); // Compute directory size uint32_t dir_size = (num_lumps * 21) + 4; if ((unsigned)mc.getSize() < (dir_offset + dir_size)) return false; // Stop announcements (don't want to be announcing modification due to entries being added etc) setMuted(true); // Read the directory theSplashWindow->setProgressMessage("Reading gob 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 uint32_t offset = 0; uint32_t size = 0; char name[13] = ""; mc.read(&offset, 4); // Offset mc.read(&size, 4); // Size mc.read(name, 13); // Name name[12] = '\0'; // Byteswap values for big endian if needed size = wxINT32_SWAP_ON_BE(size); // If the lump data goes past the end of the file, // the gobfile is invalid if (offset + size > mc.getSize()) { wxLogMessage("GobArchive::open: gob archive is invalid or corrupt"); Global::error = "Archive is invalid and/or corrupt"; 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); // Add to entry list getRoot()->addEntry(nlump); } // 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)num_lumps))); // 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()); 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); } // Setup variables setMuted(false); setModified(false); announce("opened"); theSplashWindow->setProgressMessage(""); return true; }
/* LfdArchive::open * Reads lfd format data from a MemChunk * Returns true if successful, false otherwise *******************************************************************/ bool LfdArchive::open(MemChunk& mc) { // Check data was given if (!mc.hasData()) return false; // Check size if (mc.getSize() < 16) return false; // Check magic header if (mc[0] != 'R' || mc[1] != 'M' || mc[2] != 'A' || mc[3] != 'P') return false; // Get directory length uint32_t dir_len = 0; mc.seek(12, SEEK_SET); mc.read(&dir_len, 4); dir_len = wxINT32_SWAP_ON_BE(dir_len); // Check size if ((unsigned)mc.getSize() < (dir_len) || dir_len % 16) return false; // Guess number of lumps uint32_t num_lumps = dir_len / 16; // Stop announcements (don't want to be announcing modification due to entries being added etc) setMuted(true); // Read each entry theSplashWindow->setProgressMessage("Reading lfd archive data"); size_t offset = dir_len + 16; size_t size = mc.getSize(); for (uint32_t d = 0; offset < size; d++) { // Update splash window progress theSplashWindow->setProgress(((float)d / (float)num_lumps)); // Read lump info uint32_t length = 0; char type[5] = ""; char name[9] = ""; mc.read(type, 4); // Type mc.read(name, 8); // Name mc.read(&length, 4); // Size name[8] = '\0'; type[4] = 0; // Move past the header offset += 16; // Byteswap values for big endian if needed length = wxINT32_SWAP_ON_BE(length); // If the lump data goes past the end of the file, // the gobfile is invalid if (offset + length > size) { wxLogMessage("LfdArchive::open: lfd archive is invalid or corrupt"); Global::error = "Archive is invalid and/or corrupt"; setMuted(false); return false; } // Create & setup lump wxFileName fn(name); fn.SetExt(type); ArchiveEntry* nlump = new ArchiveEntry(fn.GetFullName(), length); nlump->setLoaded(false); nlump->exProp("Offset") = (int)offset; nlump->setState(0); // Add to entry list getRoot()->addEntry(nlump); // Move to next entry offset += length; mc.seek(offset, SEEK_SET); } if (num_lumps != numEntries()) wxLogMessage("Warning: computed %i lumps, but actually %i entries", num_lumps, numEntries()); // 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)num_lumps))); // 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()); 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); } // Setup variables setMuted(false); setModified(false); announce("opened"); theSplashWindow->setProgressMessage(""); return true; }
/* WadArchive::write * Writes the wad archive to a MemChunk * Returns true if successful, false otherwise *******************************************************************/ bool WadArchive::write(MemChunk& mc, bool update) { // Don't write if iwad if (iwad && iwad_lock) { Global::error = "IWAD saving disabled"; return false; } // Determine directory offset & individual lump offsets uint32_t dir_offset = 12; ArchiveEntry* entry = NULL; for (uint32_t l = 0; l < numEntries(); l++) { entry = getEntry(l); setEntryOffset(entry, dir_offset); dir_offset += entry->getSize(); } // Clear/init MemChunk mc.clear(); mc.seek(0, SEEK_SET); mc.reSize(dir_offset + numEntries() * 16); // Setup wad type char wad_type[4] = { 'P', 'W', 'A', 'D' }; if (iwad) wad_type[0] = 'I'; // 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 = getEntry(l); mc.write(entry->getData(), entry->getSize()); } // Write the directory for (uint32_t l = 0; l < num_lumps; l++) { entry = getEntry(l); char name[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; long offset = getEntryOffset(entry); long size = entry->getSize(); for (size_t c = 0; c < entry->getName().length() && c < 8; c++) name[c] = entry->getName()[c]; mc.write(&offset, 4); mc.write(&size, 4); mc.write(name, 8); if (update) { entry->setState(0); entry->exProp("Offset") = (int)offset; } } return true; }
/* WadArchive::findLast * Returns the last entry matching the search criteria in [options], * or NULL if no matching entry was found *******************************************************************/ ArchiveEntry* WadArchive::findLast(search_options_t& options) { // Init search variables ArchiveEntry* start = getEntry(numEntries()-1); ArchiveEntry* end = NULL; options.match_name = options.match_name.Lower(); // "graphics" namespace is the global namespace in a wad if (options.match_namespace == "graphics") options.match_namespace = ""; // "global" namespace has no name, by the way if (options.match_namespace == "global") options.match_namespace = ""; // Check for namespace to search if (!options.match_namespace.IsEmpty()) { // Find matching namespace bool ns_found = false; for (unsigned a = 0; a < namespaces.size(); a++) { if (namespaces[a].name == options.match_namespace) { start = namespaces[a].end->prevEntry(); end = namespaces[a].start; ns_found = true; break; } } // Return none if namespace not found if (!ns_found) return NULL; } // Begin search ArchiveEntry* entry = start; while (entry != end) { // Check type if (options.match_type) { if (entry->getType() == EntryType::unknownType()) { if (!options.match_type->isThisType(entry)) { entry = entry->prevEntry(); continue; } } else if (options.match_type != entry->getType()) { entry = entry->prevEntry(); continue; } } // Check name if (!options.match_name.IsEmpty()) { if (!options.match_name.Matches(entry->getName().Lower())) { entry = entry->prevEntry(); continue; } } // Entry passed all checks so far, so we found a match return entry; } // No match found return NULL; }
/* WadArchive::updateNamespaces * Updates the namespace list *******************************************************************/ void WadArchive::updateNamespaces() { // Clear current namespace info while (namespaces.size() > 0) namespaces.pop_back(); // Go through all entries for (unsigned a = 0; a < numEntries(); a++) { ArchiveEntry* entry = getRoot()->getEntry(a); // Check for namespace begin if (entry->getName().Matches("*_START")) { // Create new namespace wad_ns_pair_t ns(entry, NULL); string name = entry->getName(); ns.name = name.Left(name.Length() - 6).Lower(); ns.start_index = entryIndex(ns.start); // Convert some special cases (because technically PP_START->P_END is a valid namespace) if (ns.name == "pp") ns.name = "p"; if (ns.name == "ff") ns.name = "f"; if (ns.name == "ss") ns.name = "s"; if (ns.name == "tt") ns.name = "t"; // Add to namespace list namespaces.push_back(ns); } // Check for namespace end else if (entry->getName().Matches("?_END") || entry->getName().Matches("??_END")) { // Get namespace 'name' int len = entry->getName().Length() - 4; string ns_name = entry->getName().Left(len).Lower(); // Convert some special cases (because technically P_START->PP_END is a valid namespace) if (ns_name == "pp") ns_name = "p"; if (ns_name == "ff") ns_name = "f"; if (ns_name == "ss") ns_name = "s"; if (ns_name == "tt") ns_name = "t"; // Check if it's the end of an existing namespace // Remember entry is getEntry(a)? index is 'a' //size_t index = entryIndex(entry); bool found = false; for (unsigned b = 0; b < namespaces.size(); b++) { // Can't close a namespace that starts afterwards if (namespaces[b].start_index > a) break; // Can't close an already-closed namespace if (namespaces[b].end != NULL) continue; if (S_CMP(ns_name, namespaces[b].name)) { found = true; namespaces[b].end = entry; namespaces[b].end_index = a; break; } } // Flat hack: closing the flat namespace without opening it if (found == false && ns_name == "f") { wad_ns_pair_t ns(getRoot()->getEntry(0), entry); ns.start_index = 0; ns.end_index = a; ns.name = "f"; namespaces.push_back(ns); } } } // ROTT stuff. The first lump in the archive is always WALLSTRT, the last lump is either // LICENSE (darkwar.wad) or VENDOR (huntbgin.wad), with TABLES just before in both cases. // The shareware version has 2091 lumps, the complete version has about 50% more. if (numEntries() > 2090 && getRoot()->getEntry(0)->getName().Matches("WALLSTRT") && getRoot()->getEntry(numEntries()-2)->getName().Matches("TABLES")) { wad_ns_pair_t ns(getRoot()->getEntry(0), getRoot()->getEntry(numEntries()-1)); ns.name = "rott"; ns.start_index = 0; ns.end_index = entryIndex(ns.end); namespaces.push_back(ns); } // Check namespaces for (unsigned a = 0; a < namespaces.size(); a++) { wad_ns_pair_t& ns = namespaces[a]; // Check the namespace has an end if (!ns.end) { // If not, remove the namespace as it is invalid namespaces.erase(namespaces.begin() + a); a--; continue; } // Check namespace name for special cases for (int n = 0; n < n_special_namespaces; n++) { if (S_CMP(ns.name, special_namespaces[n].letter)) ns.name = special_namespaces[n].name; } ns.start_index = entryIndex(ns.start); ns.end_index = entryIndex(ns.end); // Testing //wxLogMessage("Namespace %s from %s (%d) to %s (%d)", ns.name, // ns.start->getName(), ns.start_index, ns.end->getName(), ns.end_index); } }
// Return TRUE if the Rsc database is empty. UtlBoolean UtlRscStore::isEmpty(void) const { return (numEntries() == 0); }
// ----------------------------------------------------------------------------- // Reads grp format data from a MemChunk // Returns true if successful, false otherwise // ----------------------------------------------------------------------------- bool GrpArchive::open(MemChunk& mc) { // Check data was given if (!mc.hasData()) return false; // Read grp header uint32_t num_lumps = 0; char ken_magic[13] = ""; mc.seek(0, SEEK_SET); mc.read(ken_magic, 12); // "KenSilverman" mc.read(&num_lumps, 4); // No. of lumps in grp // Byteswap values for big endian if needed num_lumps = wxINT32_SWAP_ON_BE(num_lumps); // Null-terminate the magic header ken_magic[12] = 0; // Check the header if (!(S_CMP(wxString::FromAscii(ken_magic), "KenSilverman"))) { Log::error(S_FMT("GrpArchive::openFile: File %s has invalid header", filename_)); Global::error = "Invalid grp header"; return false; } // Stop announcements (don't want to be announcing modification due to entries being added etc) setMuted(true); // The header takes as much space as a directory entry uint32_t entryoffset = 16 * (1 + num_lumps); // Read the directory UI::setSplashProgressMessage("Reading grp archive data"); for (uint32_t d = 0; d < num_lumps; d++) { // Update splash window progress UI::setSplashProgress(((float)d / (float)num_lumps)); // Read lump info char name[13] = ""; uint32_t offset = entryoffset; uint32_t size = 0; mc.read(name, 12); // Name mc.read(&size, 4); // Size name[12] = '\0'; // Byteswap values for big endian if needed size = wxINT32_SWAP_ON_BE(size); // Increase offset of next entry by this entry's size entryoffset += size; // If the lump data goes past the end of the file, // the grpfile is invalid if (offset + size > mc.size()) { Log::error("GrpArchive::open: grp archive is invalid or corrupt"); Global::error = "Archive is invalid and/or corrupt"; setMuted(false); return false; } // Create & setup lump auto nlump = std::make_shared<ArchiveEntry>(wxString::FromAscii(name), size); nlump->setLoaded(false); nlump->exProp("Offset") = (int)offset; nlump->setState(ArchiveEntry::State::Unmodified); // Add to entry list rootDir()->addEntry(nlump); } // Detect all entry types MemChunk edata; UI::setSplashProgressMessage("Detecting entry types"); for (size_t a = 0; a < numEntries(); a++) { // Update splash window progress UI::setSplashProgress((((float)a / (float)num_lumps))); // Get entry auto entry = entryAt(a); // Read entry data if it isn't zero-sized if (entry->size() > 0) { // Read the entry data mc.exportMemChunk(edata, getEntryOffset(entry), entry->size()); 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(ArchiveEntry::State::Unmodified); } // Setup variables setMuted(false); setModified(false); announce("opened"); UI::setSplashProgressMessage(""); return true; }
/* DatArchive::write * Writes the dat archive to a MemChunk * Returns true if successful, false otherwise *******************************************************************/ bool DatArchive::write(MemChunk& mc, bool update) { // Only two bytes are used for storing entry amount, // so abort for excessively large files: if (numEntries() > 65535) return false; // Determine directory offset, name offsets & individual lump offsets uint32_t dir_offset = 10; uint16_t name_offset = numEntries() * 12; uint32_t name_size = 0; string previousname = ""; uint16_t* nameoffsets = new uint16_t[numEntries()]; ArchiveEntry* entry = NULL; for (uint16_t l = 0; l < numEntries(); l++) { entry = getEntry(l); setEntryOffset(entry, dir_offset); dir_offset += entry->getSize(); // Does the entry has a name? string name = entry->getName(); if (l > 0 && previousname.length() > 0 && name.length() > previousname.length() && !previousname.compare(0, previousname.length(), name, 0, previousname.length()) && name.at(previousname.length()) == '+') { // This is a fake name name = ""; nameoffsets[l] = 0; } else { // This is a true name previousname = name; nameoffsets[l] = uint16_t(name_offset + name_size); name_size += name.length() + 1; } } // Clear/init MemChunk mc.clear(); mc.seek(0, SEEK_SET); mc.reSize(dir_offset + name_size + numEntries() * 12); // Write the header uint16_t num_lumps = wxINT16_SWAP_ON_BE(numEntries()); dir_offset = wxINT32_SWAP_ON_BE(dir_offset); uint32_t unknown = 0; mc.write(&num_lumps, 2); mc.write(&dir_offset, 4); mc.write(&unknown, 4); // Write the lumps for (uint16_t l = 0; l < numEntries(); l++) { entry = getEntry(l); mc.write(entry->getData(), entry->getSize()); } // Write the directory for (uint16_t l = 0; l < num_lumps; l++) { entry = getEntry(l); uint32_t offset = wxINT32_SWAP_ON_BE(getEntryOffset(entry)); uint32_t size = wxINT32_SWAP_ON_BE(entry->getSize()); uint16_t nameofs = wxINT16_SWAP_ON_BE(nameoffsets[l]); uint16_t flags = wxINT16_SWAP_ON_BE((entry->isEncrypted() == ENC_SCRLE0) ? 1 : 0); mc.write(&offset, 4); // Offset mc.write(&size, 4); // Size mc.write(&nameofs, 2); // Name offset mc.write(&flags, 2); // Flags if (update) { entry->setState(0); entry->exProp("Offset") = (int)wxINT32_SWAP_ON_BE(offset); } } // Write the names for (uint16_t l = 0; l < num_lumps; l++) { uint8_t zero = 0; entry = getEntry(l); if (nameoffsets[l]) { mc.write(CHR(entry->getName()), entry->getName().length()); mc.write(&zero, 1); } } // Clean-up delete[] nameoffsets; // Finished! return true; }
bool kvoctrainDoc::parseBody_e (XmlElement elem, XmlReader& xml) { grade_t grade, r_grade; int qcount, r_qcount; int bcount, r_bcount; QString remark; QString pronunce; time_t qdate, r_qdate; bool inquery; bool active; QString lang; QString textstr; QString exprtype; bool org_found = false; QString q_org, q_trans; QString query_id; kvoctrainExpr expr; int lesson; int width; QString type; QString faux_ami_f; QString faux_ami_t; QString synonym; QString example; QString antonym; QString usage; QString paraphrase; vector<Conjugation> conjug; Comparison comparison; MultipleChoice mc; if (!extract_KVT_E_attr (xml, elem, lesson, inquery, active, exprtype)) return false; if (lesson && lesson > (int) lesson_descr.size() ) { // description missing ? QString s; for (int i = lesson_descr.size(); i < lesson; i++) { s.setNum (i+1); s.insert (0, "#"); // invent descr according to number lesson_descr.push_back (s); } } if (! xml.readElement (elem) ) { errorKvtMl (xml.lineNumber(), i18n("I/O failure") ); return false; } if (elem.tag() == KV_EXPR && !elem.isEndTag() ) { errorKvtMl (xml.lineNumber(), i18n("disallowed occurrence of tag <%1>").arg(elem.tag())); return false; } unsigned int count = 0; org_found = false; while (elem.tag() != KV_EXPR) { // now want "original" and one or more "translations" // found original <o> if (elem.tag() == KV_ORG && !elem.isEndTag() ) { if (org_found) { errorKvtMl (xml.lineNumber(), i18n("repeated occurrence of tag <%1>").arg(elem.tag())); return false; } org_found = true; type = exprtype; if (!extract_O_T_attr ( xml, elem, lang, grade, r_grade, qcount, r_qcount, qdate, r_qdate, remark, bcount, r_bcount, query_id, pronunce, width, type, faux_ami_t, faux_ami_f, synonym, example, antonym, usage, paraphrase)) return false; if (vocabulary.size() == 0) { // only accept in first entry if (width >= 0) setSizeHint (count, width); if (query_id == KV_O) q_org = lang; if (query_id == KV_T) q_trans = lang; } if (langs.size() == 0) { // first entry if (lang.isEmpty()) // no definition in first entry lang = "original"; langs.push_back(lang); } else { if (lang != langs[0] && !lang.isEmpty()) { // different originals ? errorKvtMl (xml.lineNumber(), i18n("ambiguous definition of language code")); return false; } } count = 0; //======================================== // FIXME:: make loop for this if (! xml.readElement (elem) ) { errorKvtMl (xml.lineNumber(), i18n("I/O failure") ); return false; } if (elem.tag () == KV_CONJUG_GRP && !elem.isEndTag() ) { if (!loadConjugKvtMl (conjug, (QString) KV_CON_TYPE, elem, xml)) return false; if (! xml.readElement (elem) ) { errorKvtMl (xml.lineNumber(), i18n("I/O failure") ); return false; } } comparison.clear(); if (elem.tag () == KV_COMPARISON_GRP && !elem.isEndTag() ) { if (!loadComparison (comparison, elem, xml)) return false; if (! xml.readElement (elem) ) { errorKvtMl (xml.lineNumber(), i18n("I/O failure") ); return false; } } mc.clear(); if (elem.tag () == KV_MULTIPLECHOICE_GRP && !elem.isEndTag() ) { if (!loadMultipleChoice (mc, elem, xml)) return false; if (! xml.readElement (elem) ) { errorKvtMl (xml.lineNumber(), i18n("I/O failure") ); return false; } } if (elem.tag() == "#PCDATA") { // element data textstr = xml.getText(); if (! xml.readElement (elem) ) { errorKvtMl (xml.lineNumber(), i18n("I/O failure") ); return false; } if (elem.tag() != KV_ORG || !elem.isEndTag() ) { errorKvtMl (xml.lineNumber(), i18n("expected ending tag <%1>").arg(KV_ORG)); return false; } } else { if (elem.tag() != KV_ORG || !elem.isEndTag() ) { errorKvtMl (xml.lineNumber(), i18n("expected ending tag <%1>").arg(KV_ORG)); return false; } textstr = ""; } //======================================== expr = kvoctrainExpr (textstr); expr.setLesson (lesson); expr.setInQuery(inquery); expr.setActive(active); if (conjug.size() > 0) { expr.setConjugation(0, conjug[0]); conjug.clear(); } if (!comparison.isEmpty()) { expr.setComparison(0, comparison); comparison.clear(); } if (!mc.isEmpty()) { expr.setMultipleChoice(0, mc); mc.clear(); } if (!remark.isEmpty() ) expr.setRemark (0, remark); if (!pronunce.isEmpty() ) expr.setPronunce (0, pronunce); if (!type.isEmpty() ) expr.setType(0, type); if (!synonym.isEmpty() ) expr.setSynonym(0, synonym); if (!example.isEmpty() ) expr.setExample(0, example); if (!usage.isEmpty() ) expr.setUsageLabel(0, usage); if (!paraphrase.isEmpty() ) expr.setParaphrase(0, paraphrase); if (!antonym.isEmpty() ) expr.setAntonym(0, antonym); } // found translation <t> else if (elem.tag() == KV_TRANS && !elem.isEndTag() ) { if (!org_found) { // must be preceded by "original" errorKvtMl (xml.lineNumber(), i18n("starting tag <%1> is missing").arg(KV_ORG)); return false; } count++; type = exprtype; if (!extract_O_T_attr ( xml, elem, lang, grade, r_grade, qcount, r_qcount, qdate, r_qdate, remark, bcount, r_bcount, query_id, pronunce, width, type, faux_ami_f, faux_ami_t, synonym, example, antonym, usage, paraphrase)) return false; if (vocabulary.size() == 0) { // only accept in first entry if (width >= 0) setSizeHint (count, width); if (query_id == KV_O) q_org = lang; if (query_id == KV_T) q_trans = lang; } if (langs.size() <= count) { // new translation if (lang.isEmpty()) { // no definition in first entry ? lang.setNum (langs.size() ); lang.insert (0, "translation "); } langs.push_back(lang); } else { if (lang != langs[count] && !lang.isEmpty()) { // different language ? errorKvtMl (xml.lineNumber(), i18n("ambiguous definition of language code")); return false; } } //======================================== // FIXME:: make loop for this if (! xml.readElement (elem) ) { errorKvtMl (xml.lineNumber(), i18n("I/O failure") ); return false; } if (elem.tag () == KV_CONJUG_GRP && !elem.isEndTag() ) { if (!loadConjugKvtMl (conjug, (QString) KV_CON_TYPE, elem, xml)) return false; if (! xml.readElement (elem) ) { errorKvtMl (xml.lineNumber(), i18n("I/O failure") ); return false; } } comparison.clear(); if (elem.tag () == KV_COMPARISON_GRP && !elem.isEndTag() ) { if (!loadComparison (comparison, elem, xml)) return false; if (! xml.readElement (elem) ) { errorKvtMl (xml.lineNumber(), i18n("I/O failure") ); return false; } } mc.clear(); if (elem.tag () == KV_MULTIPLECHOICE_GRP && !elem.isEndTag() ) { if (!loadMultipleChoice (mc, elem, xml)) return false; if (! xml.readElement (elem) ) { errorKvtMl (xml.lineNumber(), i18n("I/O failure") ); return false; } } textstr = ""; if (elem.tag() == "#PCDATA") { // element data textstr = xml.getText(); if (! xml.readElement (elem) ) { errorKvtMl (xml.lineNumber(), i18n("I/O failure") ); return false; } if (elem.tag() != KV_TRANS || !elem.isEndTag() ) { errorKvtMl (xml.lineNumber(), i18n("expected ending tag <%1>").arg(KV_TRANS)); return false; } // expr ... } else { if (elem.tag() != KV_TRANS || !elem.isEndTag() ) { errorKvtMl (xml.lineNumber(), i18n("expected ending tag <%1>").arg(KV_TRANS)); return false; } textstr = ""; } //======================================== if (!org_found) { errorKvtMl (xml.lineNumber(), i18n("starting tag <%1> is missing").arg(KV_ORG)); return false; } /* if (qcount == 0) { grade = KV_NORM_GRADE; } if (r_qcount == 0) { r_grade = KV_NORM_GRADE; } */ expr.addTranslation (textstr, grade, r_grade); expr.setQueryCount (count, qcount, false); expr.setQueryCount (count, r_qcount, true); expr.setBadCount (count, bcount, false); expr.setBadCount (count, r_bcount, true); expr.setQueryDate (count, qdate, false); expr.setQueryDate (count, r_qdate, true); if (conjug.size() > 0) { expr.setConjugation(count, conjug[0]); conjug.clear(); } if (!comparison.isEmpty()) { expr.setComparison(count, comparison); comparison.clear(); } if (!mc.isEmpty()) { expr.setMultipleChoice(count, mc); mc.clear(); } if (!type.isEmpty() ) expr.setType (count, type); if (!remark.isEmpty() ) expr.setRemark (count, remark); if (!pronunce.isEmpty() ) expr.setPronunce (count, pronunce); if (!faux_ami_f.isEmpty() ) expr.setFauxAmi (count, faux_ami_f, false); if (!faux_ami_t.isEmpty() ) expr.setFauxAmi (count, faux_ami_t, true); if (!synonym.isEmpty() ) expr.setSynonym (count, synonym); if (!example.isEmpty() ) expr.setExample (count, example); if (!usage.isEmpty() ) expr.setUsageLabel (count, usage); if (!paraphrase.isEmpty() ) expr.setParaphrase (count, paraphrase); if (!antonym.isEmpty() ) expr.setAntonym (count, antonym); } else { if (elem.isEndTag() ) { errorKvtMl (xml.lineNumber(), i18n("unexpected ending tag <%1>" ).arg(elem.tag())); return false; } else { unknownElement (xml.lineNumber(), elem.tag()); return false; } } if (! xml.readElement (elem) ) { errorKvtMl (xml.lineNumber(), i18n("I/O failure") ); return false; } } if (numEntries() == 0) setQueryLang (q_org, q_trans); vocabulary.push_back (expr); return true; }
/* LfdArchive::write * 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 = NULL; for (uint32_t l = 0; l < numEntries(); l++) { entry = getEntry(l); total_size += 16; setEntryOffset(entry, total_size); if (update) { entry->setState(0); entry->exProp("Offset") = (int)total_size; } total_size += entry->getSize(); } // 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 = getEntry(l); for (int t = 0; t < 5; ++t) type[t] = 0; for (int n = 0; n < 9; ++n) name[n] = 0; size = wxINT32_SWAP_ON_BE(entry->getSize()); wxFileName fn(entry->getName()); 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 = getEntry(l); for (int t = 0; t < 5; ++t) type[t] = 0; for (int n = 0; n < 9; ++n) name[n] = 0; size = wxINT32_SWAP_ON_BE(entry->getSize()); wxFileName fn(entry->getName()); 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->getData(), entry->getSize()); } return true; }
// Return TRUE if the name database is empty UtlBoolean OsNameDb::isEmpty(void) { return (numEntries() == 0); }
/* 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; }
/* GZipArchive::write * Writes the gzip archive to a MemChunk * Returns true if successful, false otherwise *******************************************************************/ bool GZipArchive::write(MemChunk& mc, bool update) { // Clear current data mc.clear(); if (numEntries() == 1) { MemChunk stream; if (Compression::GZipDeflate(getEntry(0)->getMCData(), stream, 9)) { const uint8_t* data = stream.getData(); uint32_t working = 0; size_t size = stream.getSize(); if (size < 18) return false; // zlib will have given us a minimal header, so we make our own uint8_t header[4]; header[0] = GZIP_ID1; header[1] = GZIP_ID2; header[2] = GZIP_DEFLATE; header[3] = flags; mc.write(header, 4); // Update mtime if the file was modified if (getEntry(0)->getState()) { mtime = ::wxGetLocalTime(); } // Write mtime working = wxUINT32_SWAP_ON_BE(mtime); mc.write(&working, 4); // Write other stuff mc.write(&xfl, 1); mc.write(&os, 1); // Any extra content that may have been there if (flags & GZIP_FLG_FXTRA) { uint16_t xlen = wxUINT16_SWAP_ON_BE(xtra.getSize()); mc.write(&xlen, 2); mc.write(xtra.getData(), xtra.getSize()); } // File name, if not extrapolated from archive name if (flags & GZIP_FLG_FNAME) { mc.write(CHR(getEntry(0)->getName()), getEntry(0)->getName().length()); uint8_t zero = 0; mc.write(&zero, 1); // Terminate string } // Comment, if there were actually one if (flags & GZIP_FLG_FCMNT) { mc.write(CHR(comment), comment.length()); uint8_t zero = 0; mc.write(&zero, 1); // Terminate string } // And finally, the half CRC, which we recalculate if (flags & GZIP_FLG_FHCRC) { uint32_t fullcrc = Misc::crc(mc.getData(), mc.getSize()); uint16_t hcrc = (fullcrc & 0x0000FFFF); hcrc = wxUINT16_SWAP_ON_BE(hcrc); mc.write(&hcrc, 2); } // Now that the pleasantries are dispensed with, // let's get with the meat of the matter return mc.write(data + 10, size - 10); } } return false; }
// --------------------------------------------------------------------------- // Continue Scanning for more files // --------------------------------------------------------------------------- // TBool CMPXFolderScanner::DoScanL() { MPX_DEBUG1("CMPXFolderScanner::DoScanL <---"); TBool done (EFalse); TBool blocked ( EFalse ); // read successfully if ( iStatus == KErrNone || iStatus == KErrEof ) { TBuf<KMaxFileName> buffer; const TEntry* entry = NULL; TInt numEntries( iCurDirQueueEntry->iEntryArray.Count() ); // process the entry one by one while ( iCurDirQueueEntry->iPos < numEntries ) { entry = iCurDirQueueEntry->NextEntry(); buffer.Zero(); // Generates the full name of the entry buffer.Append( *iCurFullPath ); buffer.Append( entry->iName ); if ( entry->IsDir() ) // entry is a directory { buffer.Append( KTxtBackSlash ); blocked = iObserver.IsPathBlockedL( buffer ); if ( !blocked ) { CDirQueueEntry* newEntry = CDirQueueEntry::NewL( buffer ); TInt err = newEntry->iDir.Open( iFs, buffer, KEntryAttNormal | KEntryAttDir ); if ( err == KErrNone ) { CDirQueueEntry::PushL( iDirQueue, newEntry ); } else { delete newEntry; } } } else // entry is a file { TInt index = iObserver.IsMediaFileL( buffer ); if( KErrNotFound != index ) { iObserver.HandleFileAdditionL( buffer, index ); } } if ( iCurDirQueueEntry->iPos % KFileNumBreakCount == 0 ) { return done; } } } // this dir has other entries to read if ( iStatus == KErrNone ) { iCurDirQueueEntry->ResetPosition(); ReadDirEntry(); } // there is nothing to read or some error has occured during reading, // try to move to next dir else { CDirQueueEntry::PopAndDestroy( iDirQueue ); if ( iDirQueue.Count() || !SetupNextDriveToScanL() ) { iCurDirQueueEntry = iDirQueue[ 0 ]; iCurFullPath = iCurDirQueueEntry->iFullPath; ReadDirEntry(); } else // there is nothing to scan { done = ETrue; } } MPX_DEBUG1("CMPXFolderScanner::DoScanL --->"); return done; }
/* DatArchive::open * Reads wad format data from a MemChunk * Returns true if successful, false otherwise *******************************************************************/ bool DatArchive::open(MemChunk& mc) { // Check data was given if (!mc.hasData()) return false; const uint8_t* mcdata = mc.getData(); // Read dat header mc.seek(0, SEEK_SET); uint16_t num_lumps; uint32_t dir_offset, unknown; mc.read(&num_lumps, 2); // Size mc.read(&dir_offset, 4); // Directory offset mc.read(&unknown, 4); // Unknown value num_lumps = wxINT16_SWAP_ON_BE(num_lumps); dir_offset = wxINT32_SWAP_ON_BE(dir_offset); unknown = wxINT32_SWAP_ON_BE(unknown); string lastname(wxString::FromAscii("-noname-")); size_t namecount = 0; // Stop announcements (don't want to be announcing modification due to entries being added etc) setMuted(true); // Read the directory mc.seek(dir_offset, SEEK_SET); theSplashWindow->setProgressMessage("Reading dat 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 uint32_t offset = 0; uint32_t size = 0; uint16_t nameofs = 0; uint16_t flags = 0; mc.read(&offset, 4); // Offset mc.read(&size, 4); // Size mc.read(&nameofs, 2); // Name offset mc.read(&flags, 2); // Flags (only one: RLE encoded) // Byteswap values for big endian if needed offset = wxINT32_SWAP_ON_BE(offset); size = wxINT32_SWAP_ON_BE(size); nameofs = wxINT16_SWAP_ON_BE(nameofs); flags = wxINT16_SWAP_ON_BE(flags); // If the lump data goes past the directory, // the data file is invalid if (offset + size > mc.getSize()) { wxLogMessage("DatArchive::open: Dat archive is invalid or corrupt at entry %i", d); Global::error = "Archive is invalid and/or corrupt"; setMuted(false); return false; } string myname; if (nameofs != 0) { size_t len = 1; size_t start = nameofs+dir_offset; for (size_t i = start; mcdata[i] != 0; ++i) { ++len; } lastname = myname = wxString::FromAscii(mcdata+start, len); namecount = 0; } else { myname = S_FMT("%s+%d", lastname, ++namecount); } // Create & setup lump ArchiveEntry* nlump = new ArchiveEntry(myname, size); nlump->setLoaded(false); nlump->exProp("Offset") = (int)offset; nlump->setState(0); if (flags & 1) nlump->setEncryption(ENC_SCRLE0); // Check for markers if (!nlump->getName().Cmp("startflats")) flats[0] = d; if (!nlump->getName().Cmp("endflats")) flats[1] = d; if (!nlump->getName().Cmp("startsprites")) sprites[0] = d; if (!nlump->getName().Cmp("endmonsters")) sprites[1] = d; if (!nlump->getName().Cmp("startwalls")) walls[0] = d; if (!nlump->getName().Cmp("endwalls")) walls[1] = d; // Add to entry list getRoot()->addEntry(nlump); } // 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)num_lumps))); // 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()); entry->importMemChunk(edata); } // Detect entry type EntryType::detectEntryType(entry); // Set entry to unchanged entry->setState(0); } // Detect maps (will detect map entry types) //theSplashWindow->setProgressMessage("Detecting maps"); //detectMaps(); // Setup variables setMuted(false); setModified(false); announce("opened"); theSplashWindow->setProgressMessage(""); return true; }
/* HogArchive::open * Reads hog format data from a MemChunk * Returns true if successful, false otherwise *******************************************************************/ bool HogArchive::open(MemChunk& mc) { // Check data was given if (!mc.hasData()) return false; // Check size size_t archive_size = mc.getSize(); if (archive_size < 3) return false; // Check magic header (DHF for "Descent Hog File") if (mc[0] != 'D' || mc[1] != 'H' || mc[2] != 'F') return false; // Stop announcements (don't want to be announcing modification due to entries being added etc) setMuted(true); // Iterate through files to see if the size seems okay theSplashWindow->setProgressMessage("Reading hog archive data"); size_t iter_offset = 3; uint32_t num_lumps = 0; while (iter_offset < archive_size) { // Update splash window progress theSplashWindow->setProgress(((float)iter_offset / (float)archive_size)); // If the lump data goes past the end of the file, // the hogfile is invalid if (iter_offset + 17 > archive_size) { wxLogMessage("HogArchive::open: hog archive is invalid or corrupt"); Global::error = "Archive is invalid and/or corrupt"; setMuted(false); return false; } // Setup variables num_lumps++; size_t offset = iter_offset + 17; size_t size = READ_L32(mc, iter_offset + 13); char name[14] = ""; mc.seek(iter_offset, SEEK_SET); mc.read(name, 13); name[13] = 0; // Create & setup lump ArchiveEntry* nlump = new ArchiveEntry(wxString::FromAscii(name), size); nlump->setLoaded(false); nlump->exProp("Offset") = (int)offset; nlump->setState(0); // Add to entry list getRoot()->addEntry(nlump); // Update entry size to compute next offset iter_offset = offset + size; } // 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)num_lumps))); // 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()); 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); } // Setup variables setMuted(false); setModified(false); announce("opened"); theSplashWindow->setProgressMessage(""); return true; }