// ----------------------------------------------------------------------------- // Adds the directory structure starting from [start] to [list] // ----------------------------------------------------------------------------- void Archive::putEntryTreeAsList(vector<shared_ptr<ArchiveEntry>>& list, ArchiveTreeNode* start) { // If no start dir is specified, use the root dir if (!start) start = &dir_root_; // Add the directory entry to the list if it isn't the root dir if (start != &dir_root_) list.push_back(start->dir_entry_); // Add all entries to the list for (unsigned a = 0; a < start->numEntries(); a++) list.push_back(start->sharedEntryAt(a)); // Go through subdirectories and add them to the list for (unsigned a = 0; a < start->nChildren(); a++) putEntryTreeAsList(list, (ArchiveTreeNode*)start->child(a)); }
// ----------------------------------------------------------------------------- // Reads pod format data from a MemChunk // Returns true if successful, false otherwise // ----------------------------------------------------------------------------- bool PodArchive::open(MemChunk& mc) { // Check data was given if (!mc.hasData()) return false; // Read no. of files mc.seek(0, 0); uint32_t num_files; mc.read(&num_files, 4); // Read id mc.read(id_, 80); // Read directory vector<FileEntry> files(num_files); mc.read(files.data(), num_files * sizeof(FileEntry)); // Stop announcements (don't want to be announcing modification due to entries being added etc) setMuted(true); // Create entries UI::setSplashProgressMessage("Reading pod archive data"); for (unsigned a = 0; a < num_files; a++) { // Get the entry name as a wxFileName (so we can break it up) wxFileName fn(files[a].name); // Create entry auto new_entry = std::make_shared<ArchiveEntry>(fn.GetFullName(), files[a].size); new_entry->exProp("Offset") = files[a].offset; new_entry->setLoaded(false); // Add entry and directory to directory tree string path = fn.GetPath(false); auto ndir = createDir(path); ndir->addEntry(new_entry); new_entry->setState(ArchiveEntry::State::Unmodified); LOG_MESSAGE(5, "File size: %d, offset: %d, name: %s", files[a].size, files[a].offset, files[a].name); } // Detect entry types vector<ArchiveEntry*> all_entries; putEntryTreeAsList(all_entries); UI::setSplashProgressMessage("Detecting entry types"); for (unsigned a = 0; a < all_entries.size(); a++) { // Skip dir/marker if (all_entries[a]->size() == 0 || all_entries[a]->type() == EntryType::folderType()) { all_entries[a]->setState(ArchiveEntry::State::Unmodified); continue; } // Update splash window progress UI::setSplashProgress((float)a / (float)all_entries.size()); // Read data MemChunk edata; mc.exportMemChunk(edata, all_entries[a]->exProp("Offset").intValue(), all_entries[a]->size()); all_entries[a]->importMemChunk(edata); // Detect entry type EntryType::detectEntryType(all_entries[a]); // Unload entry data if needed if (!archive_load_data) all_entries[a]->unloadData(); // Set entry to unchanged all_entries[a]->setState(ArchiveEntry::State::Unmodified); LOG_MESSAGE(5, "entry %s size %d", CHR(all_entries[a]->name()), all_entries[a]->size()); } // Setup variables setMuted(false); setModified(false); announce("opened"); UI::setSplashProgressMessage(""); return true; }
// ----------------------------------------------------------------------------- // Writes the pod archive to a MemChunk // Returns true if successful, false otherwise // ----------------------------------------------------------------------------- bool PodArchive::write(MemChunk& mc, bool update) { // Get all entries vector<ArchiveEntry*> entries; putEntryTreeAsList(entries); // Process entries int ndirs = 0; uint32_t data_size = 0; for (auto& entry : entries) { if (entry->type() == EntryType::folderType()) ndirs++; else data_size += entry->size(); } // Init MemChunk mc.clear(); mc.reSize(4 + 80 + (entries.size() * 40) + data_size, false); LOG_MESSAGE(5, "MC size %d", mc.size()); // Write no. entries uint32_t n_entries = entries.size() - ndirs; LOG_MESSAGE(5, "n_entries %d", n_entries); mc.write(&n_entries, 4); // Write id LOG_MESSAGE(5, "id %s", id_); mc.write(id_, 80); // Write directory FileEntry fe; fe.offset = 4 + 80 + (n_entries * 40); for (auto& entry : entries) { if (entry->type() == EntryType::folderType()) continue; // Name memset(fe.name, 0, 32); string path = entry->path(true); path.Replace("/", "\\"); path = path.AfterFirst('\\'); // LOG_MESSAGE(2, path); memcpy(fe.name, CHR(path), path.Len()); // Size fe.size = entry->size(); // Write directory entry mc.write(fe.name, 32); mc.write(&fe.size, 4); mc.write(&fe.offset, 4); LOG_MESSAGE( 5, "entry %s: old=%d new=%d size=%d", fe.name, entry->exProp("Offset").intValue(), fe.offset, entry->size()); // Next offset fe.offset += fe.size; } // Write entry data for (auto& entry : entries) if (entry->type() != EntryType::folderType()) mc.write(entry->rawData(), entry->size()); return true; }