// ----------------------------------------------------------------------------- // Writes Chasm bin archive to a MemChunk // Returns true if successful, false otherwise // ----------------------------------------------------------------------------- bool ChasmBinArchive::write(MemChunk& mc, bool update) { // Clear current data mc.clear(); // Get archive tree as a list vector<ArchiveEntry*> entries; getEntryTreeAsList(entries); // Check limit of entries count const uint16_t num_entries = static_cast<uint16_t>(entries.size()); if (num_entries > MAX_ENTRY_COUNT) { LOG_MESSAGE(1, "ChasmBinArchive::write: Bin archive can contain no more than %u entries", MAX_ENTRY_COUNT); Global::error = "Maximum number of entries exceeded for Chasm: The Rift bin archive"; return false; } // Init data size static const uint32_t HEADER_TOC_SIZE = HEADER_SIZE + ENTRY_SIZE * MAX_ENTRY_COUNT; mc.reSize(HEADER_TOC_SIZE, false); mc.fillData(0); // Write header const char magic[4] = { 'C', 'S', 'i', 'd' }; mc.seek(0, SEEK_SET); mc.write(magic, 4); mc.write(&num_entries, sizeof num_entries); // Write directory uint32_t offset = HEADER_TOC_SIZE; for (uint16_t i = 0; i < num_entries; ++i) { ArchiveEntry* const entry = entries[i]; // Update entry if (update) { entry->setState(0); entry->exProp("Offset") = static_cast<int>(offset); } // Check entry name string name = entry->getName(); uint8_t name_length = static_cast<uint8_t>(name.Length()); if (name_length > NAME_SIZE - 1) { LOG_MESSAGE(1, "Warning: Entry %s name is too long, it will be truncated", name); name.Truncate(NAME_SIZE - 1); name_length = static_cast<uint8_t>(NAME_SIZE - 1); } // Write entry name char name_data[NAME_SIZE] = {}; memcpy(name_data, &name_length, 1); memcpy(name_data + 1, CHR(name), name_length); mc.write(name_data, NAME_SIZE); // Write entry size const uint32_t size = entry->getSize(); mc.write(&size, sizeof size); // Write entry offset mc.write(&offset, sizeof offset); // Increment/update offset offset += size; } // Write entry data mc.reSize(offset); mc.seek(HEADER_TOC_SIZE, SEEK_SET); for (uint16_t i = 0; i < num_entries; ++i) { ArchiveEntry* const entry = entries[i]; mc.write(entry->getData(), entry->getSize()); } return true; }
/* GLTexture::loadImagePortion * Loads a portion of a SImage to the texture. Only used internally, * the portion must be 128x128 in size *******************************************************************/ bool GLTexture::loadImagePortion(SImage* image, rect_t rect, Palette8bit* pal, bool add) { // Check image was given if (!image) return false; // Check image is valid if (!image->isValid()) return false; // Check portion rect is valid if (rect.width() <= 0 || rect.height() <= 0) return false; // Get RGBA image data MemChunk rgba; image->getRGBAData(rgba, pal); // Init texture data MemChunk portion; portion.reSize(rect.width() * rect.height() * 4, false); portion.fillData(0); // Read portion of image if rect isn't completely outside the image if (!(rect.left() >= image->getWidth() || rect.right() < 0 || rect.top() >= image->getHeight() || rect.bottom() < 0)) { // Determine start of each row to read uint32_t row_start = 0; if (rect.left() > 0) row_start = rect.left(); // Determine width of each row to read uint32_t row_width = rect.right() - row_start; if (rect.right() >= image->getWidth()) row_width = image->getWidth() - row_start; // Determine difference between the left of the portion and the left of the image uint32_t skip = 0; if (rect.left() < 0) skip = (0 - rect.left()) * 4; // Create temp row buffer uint8_t* buf = new uint8_t[rect.width() * 4]; // Go through each row for (int32_t row = rect.top(); row < rect.bottom(); row++) { // Clear row buffer memset(buf, 0, rect.width() * 4); // Check that the current row is within the image if (row >= 0 && row < image->getHeight()) { // Seek to current row in image data rgba.seek((row * image->getWidth() + row_start) * 4, SEEK_SET); // Copy the row data rgba.read(buf + skip, row_width * 4); } // Write the row portion.write(buf, rect.width() * 4); } // Free buffer delete[] buf; } scale_x = scale_y = 1.0; // Generate texture from rgba data return loadData(portion.getData(), rect.width(), rect.height(), add); }