/* DatArchive::isDatArchive * Checks if the given data is a valid Shadowcaster dat archive *******************************************************************/ bool DatArchive::isDatArchive(MemChunk& mc) { // Read dat header mc.seek(0, SEEK_SET); uint16_t num_lumps; uint32_t dir_offset, junk; mc.read(&num_lumps, 2); // Size mc.read(&dir_offset, 4); // Directory offset mc.read(&junk, 4); // Unknown value num_lumps = wxINT16_SWAP_ON_BE(num_lumps); dir_offset = wxINT32_SWAP_ON_BE(dir_offset); junk = wxINT32_SWAP_ON_BE(junk); if (dir_offset >= mc.getSize()) return false; // Read the directory mc.seek(dir_offset, SEEK_SET); // 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 // 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); // The first lump should have a name (subsequent lumps need not have one). // Also, sanity check the values. if (nameofs == 0 || nameofs >= mc.getSize() || offset + size >= mc.getSize()) { return false; } size_t len = 1; size_t start = nameofs+dir_offset; // Sanity checks again. Make sure there is actually a name. if (start > mc.getSize() || mc[start] < 33) return false; for (size_t i = start; (mc[i] != 0 && i < mc.getSize()); ++i, ++len) { // Names should not contain garbage characters if (mc[i] < 32 || mc[i] > 126) return false; } // Let's be reasonable here. While names aren't limited, if it's too long, it's suspicious. if (len > 60) return false; return true; }
bool MusBinInput::ReadFileHeader( MusFileHeader *header ) { Read( &int32, 4 ); m_flag = wxINT32_SWAP_ON_BE( int32 ); Read( &int32, 4 ); m_vmaj = wxINT32_SWAP_ON_BE( int32 ); Read( &int32, 4 ); m_vmin = wxINT32_SWAP_ON_BE( int32 ); Read( &int32, 4 ); m_vrev = wxINT32_SWAP_ON_BE( int32 ); Read( &uint16, 2 ); header->nbpage = wxUINT16_SWAP_ON_BE( uint16 ); // nbpage Read( &uint16, 2 ); header->nopage = wxUINT16_SWAP_ON_BE( uint16 ); // nopage Read( &uint16, 2 ); header->noligne = wxUINT16_SWAP_ON_BE( uint16 ); // noligne Read( &uint32, 4 ); header->xpos = wxUINT32_SWAP_ON_BE( uint32 ); // xpso Read( &header->param.orientation, 1 ); // param - orientation Read( &header->param.EpLignesPortee, 1 ); // param - epLignesPortee header->param.EpLignesPortee = 1; Read( &header->param.EpQueueNote, 1 ); // param - epQueueNotes header->param.EpQueueNote = 2; Read( &header->param.EpBarreMesure, 1 ); // param - epBarreMesure Read( &header->param.EpBarreValeur, 1 ); // param - epBarreValeur Read( &header->param.EpBlancBarreValeur, 1 ); // param - epBlancBarreValeur Read( &int32, 4 ); header->param.pageFormatHor = wxINT32_SWAP_ON_BE( int32 ); // param - pageFormatHor Read( &int32, 4 ); header->param.pageFormatVer = wxINT32_SWAP_ON_BE( int32 ); // param - pageFormatVer Read( &int16, 2 ); header->param.MargeSOMMET = wxINT16_SWAP_ON_BE( int16 ); // param - margeSommet Read( &int16, 2 ); header->param.MargeGAUCHEIMPAIRE = wxINT16_SWAP_ON_BE( int16 ); // param - margeGaucheImpaire Read( &int16, 2 ); header->param.MargeGAUCHEPAIRE = wxINT16_SWAP_ON_BE( int16 ); // param - margeGauchePaire Read( &header->param.rapportPorteesNum, 1 ); // rpPorteesNum Read( &header->param.rapportPorteesDen, 1 ); // rpPorteesDen Read( &header->param.rapportDiminNum, 1 ); // rpDiminNum Read( &header->param.rapportDiminDen, 1 ); // rpDiminDen Read( &header->param.hampesCorr, 1 ); // hampesCorr header->param.hampesCorr = 1; if ( AxFile::FormatVersion(m_vmaj, m_vmin, m_vrev) < AxFile::FormatVersion(1, 6, 1) ) return true; // following values where added in 1.6.1 // 1.6.1 Read( &int32, 4 ); header->param.notationMode = wxINT32_SWAP_ON_BE( int32 ); return true; }
bool MusBinInput::ReadPage( MusPage *page ) { int j; if ( !ReadSeparator() ) return false; Read( &int32, 4 ); page->npage = wxINT32_SWAP_ON_BE( int32 ); Read( &int16, 2 ); page->nbrePortees = wxINT16_SWAP_ON_BE( int16 ); Read( &page->noMasqueFixe, 1 ); Read( &page->noMasqueVar, 1 ); Read( &page->reserve, 1 ); Read( &page->defin, 1 ); Read( &int32, 4 ); page->indent = wxINT32_SWAP_ON_BE( int32 ); Read( &int32, 4 ); page->indentDroite = wxINT32_SWAP_ON_BE( int32 ); Read( &int32, 4 ); page->lrg_lign = wxINT32_SWAP_ON_BE( int32 ); for (j = 0; j < page->nbrePortees; j++) { MusStaff *staff = new MusStaff(); ReadStaff( staff ); staff->voix = (j % 2 == 0) ? 1 : 0; // add voices page->m_staves.Add( staff ); } return true; }
bool CDVDongleController::decodeOut(wxFloat32* audio, unsigned int length, unsigned int& ber) { wxASSERT(audio != NULL); wxASSERT(length == DSTAR_AUDIO_BLOCK_SIZE); ber = 0U; bool ambeFound = false; bool audioFound = false; for (;;) { unsigned char buffer[DVD_AUDIO_LENGTH_BYTES]; DVD_RESP_TYPE type = getResponse(buffer, DVD_AUDIO_LENGTH_BYTES); if (type == DVDRT_ERROR) return false; if (type == DVDRT_AMBE) { ber = ((buffer[14U] + buffer[15U] * 256U) * 100U) / 32767U; ambeFound = true; } else if (type == DVDRT_AUDIO) { wxInt16* q = (wxInt16*)buffer; for (unsigned int i = 0U; i < DSTAR_AUDIO_BLOCK_SIZE; i++) { wxInt16 word = wxINT16_SWAP_ON_BE(*q++); audio[i] = wxFloat32(word) / 32768.0F; } audioFound = true; } if (ambeFound && audioFound) return true; ::wxMilliSleep(5UL); } }
bool CDVAPController::setPower() { unsigned int count = 0U; unsigned int length; RESP_TYPE resp; do { unsigned char buffer[10U]; ::memcpy(buffer, DVAP_REQ_POWER, DVAP_REQ_POWER_LEN); wxInt16 power = wxINT16_SWAP_ON_BE(m_power); ::memcpy(buffer + 4U, &power, sizeof(wxInt16)); int ret = m_serial.write(buffer, DVAP_REQ_POWER_LEN); if (ret != int(DVAP_REQ_POWER_LEN)) { m_serial.close(); return false; } ::wxMilliSleep(50UL); resp = getResponse(m_buffer, length); if (resp != RT_POWER) { count++; if (count >= MAX_RESPONSES) { wxLogError(wxT("The DVAP is not responding to the power command")); return false; } } } while (resp != RT_POWER); return true; }
bool CDVAPController::setOffset() { unsigned char buffer[10U]; ::memcpy(buffer, DVAP_REQ_OFFSET, DVAP_REQ_OFFSET_LEN); wxInt16 offset = wxINT16_SWAP_ON_BE(m_offset); ::memcpy(buffer + 4U, &offset, sizeof(wxInt16)); int ret = m_serial.write(buffer, DVAP_REQ_OFFSET_LEN); if (ret != int(DVAP_REQ_OFFSET_LEN)) { m_serial.close(); return false; } unsigned int count = 0U; unsigned int length; RESP_TYPE resp; do { ::wxMilliSleep(5UL); resp = getResponse(m_buffer, length); if (resp != RT_OFFSET) { count++; if (count >= MAX_RESPONSES) { wxLogError(wxT("The DVAP is not responding to the offset command")); return false; } } } while (resp != RT_OFFSET); return true; }
bool MusBinOutput::WritePage( const MusPage *page ) { int j; if ( !WriteSeparator() ) return false; int32 = wxINT32_SWAP_ON_BE( page->npage ); Write( &int32, 4 ); int16 = wxINT16_SWAP_ON_BE( page->nbrePortees ); Write( &int16, 2 ); Write( &page->noMasqueFixe, 1 ); Write( &page->noMasqueVar, 1 ); Write( &page->reserve, 1 ); Write( &page->defin, 1 ); int32 = wxINT32_SWAP_ON_BE( page->indent ); Write( &int32, 4 ); int32 = wxINT32_SWAP_ON_BE( page->indentDroite ); Write( &int32, 4 ); int32 = wxINT32_SWAP_ON_BE( page->lrg_lign ); Write( &int32, 4 ); MusStaff *staff = NULL; for (j = 0; j < page->nbrePortees; j++) { staff = &page->m_staves[j]; WriteStaff( staff ); } return true; }
void CDVDongleController::encodeIn(const wxFloat32* audio, unsigned int length) { wxASSERT(audio != NULL); wxASSERT(length == DSTAR_AUDIO_BLOCK_SIZE); unsigned char buffer[DVD_HEADER_LEN + DVD_AUDIO_LENGTH_BYTES]; unsigned char* p = buffer; // First a dummy AMBE packet with parameter information in ::memcpy(p, DVD_AMBE_HEADER, DVD_HEADER_LEN); p += DVD_HEADER_LEN; ::memcpy(p, DVD_AMBE_ENC_DATA, DVD_AMBE_LENGTH_BYTES); m_controller->write(buffer, DVD_HEADER_LEN + DVD_AMBE_LENGTH_BYTES); // Then the Audio data to be encoded p = buffer; ::memcpy(p, DVD_AUDIO_HEADER, DVD_HEADER_LEN); p += DVD_HEADER_LEN; wxInt16* q = (wxInt16*)p; for (unsigned int i = 0; i < DSTAR_AUDIO_BLOCK_SIZE; i++) { wxInt16 word = wxInt16(audio[i] * 32767.0F); *q++ = wxINT16_SWAP_ON_BE(word); } m_controller->write(buffer, DVD_HEADER_LEN + DVD_AUDIO_LENGTH_BYTES); }
bool MusBinOutput::WriteFileHeader( const MusFileHeader *header ) { int32 = wxINT32_SWAP_ON_BE( m_flag ); Write( &int32, 4 ); int32 = wxINT32_SWAP_ON_BE( AxApp::s_version_major ); Write( &int32, 4 ); int32 = wxINT32_SWAP_ON_BE( AxApp::s_version_minor ); Write( &int32, 4 ); int32 = wxINT32_SWAP_ON_BE( AxApp::s_version_revision ); Write( &int32, 4 ); uint16 = wxUINT16_SWAP_ON_BE( header->nbpage ); // nbpage Write( &uint16, 2 ); uint16 = wxUINT16_SWAP_ON_BE( header->nopage ); // nopage Write( &uint16, 2 ); uint16 = wxUINT16_SWAP_ON_BE( header->noligne ); // noligne Write( &uint16, 2 ); uint32 = wxUINT32_SWAP_ON_BE( header->xpos ); // xpso Write( &uint32, 4 ); Write( &header->param.orientation, 1 ); // param - orientation Write( &header->param.EpLignesPortee, 1 ); // param - epLignesPortee Write( &header->param.EpQueueNote, 1 ); // param - epQueueNotes Write( &header->param.EpBarreMesure, 1 ); // param - epBarreMesure Write( &header->param.EpBarreValeur, 1 ); // param - epBarreValeur Write( &header->param.EpBlancBarreValeur, 1 ); // param - epBlancBarreValeur int32 = wxINT32_SWAP_ON_BE( header->param.pageFormatHor ); // param - pageFormatHor Write( &int32, 4 ); int32 = wxINT32_SWAP_ON_BE( header->param.pageFormatVer ); // param - pageFormatVer Write( &int32, 4 ); int16 = wxINT16_SWAP_ON_BE( header->param.MargeSOMMET ); // param - margeSommet Write( &int16, 2 ); int16 = wxINT16_SWAP_ON_BE( header->param.MargeGAUCHEIMPAIRE ); // param - margeGaucheImpaire Write( &int16, 2 ); int16 = wxINT16_SWAP_ON_BE( header->param.MargeGAUCHEPAIRE ); // param - margeGauchePaire Write( &int16, 2 ); Write( &header->param.rapportPorteesNum, 1 ); // rpPorteesNum Write( &header->param.rapportPorteesDen, 1 ); // rpPorteesDen Write( &header->param.rapportDiminNum, 1 ); // rpDiminNum Write( &header->param.rapportDiminDen, 1 ); // rpDiminDen Write( &header->param.hampesCorr, 1 ); // hampesCorr int32 = wxINT32_SWAP_ON_BE( header->param.notationMode ); // param - pageFormatVer Write( &int32, 4 ); return true; }
bool MusBinOutput::WritePagination( const MusPagination *pagination ) { int16 = wxINT16_SWAP_ON_BE( pagination->numeroInitial ); Write( &int16, 2 ); Write( &pagination->aussiPremierPage, 1 ); Write( &pagination->position, 1 ); Write( &pagination->numeroFonte, 1 ); Write( &pagination->carStyle, 1 ); Write( &pagination->taille, 1 ); Write( &pagination->offsetDuBord, 1 ); return true; }
bool MusBinInput::ReadPagination( MusPagination *pagination ) { Read( &int16, 2 ); pagination->numeroInitial = wxINT16_SWAP_ON_BE( int16 ); Read( &pagination->aussiPremierPage, 1 ); Read( &pagination->position, 1 ); Read( &pagination->numeroFonte, 1 ); Read( &pagination->carStyle, 1 ); Read( &pagination->taille, 1 ); Read( &pagination->offsetDuBord, 1 ); return true; }
// ----------------------------------------------------------------------------- // Reads in a doom-format TEXTUREx entry. // Returns true on success, false otherwise // ----------------------------------------------------------------------------- bool TextureXList::readTEXTUREXData(ArchiveEntry* texturex, const PatchTable& patch_table, bool add) { // Check entries were actually given if (!texturex) return false; // Clear current textures if needed if (!add) clear(); // Update palette MainEditor::setGlobalPaletteFromArchive(texturex->parent()); // Read TEXTUREx // Read header texturex->seek(0, SEEK_SET); // Number of textures int32_t n_tex = 0; if (!texturex->read(&n_tex, 4)) { Log::error("TEXTUREx entry is corrupt (can't read texture count)"); return false; } n_tex = wxINT32_SWAP_ON_BE(n_tex); // If it's an empty TEXTUREx entry, stop here if (n_tex == 0) return true; // Texture definition offsets vector<int32_t> offsets(n_tex); if (!texturex->read(offsets.data(), n_tex * 4)) { Log::error("TEXTUREx entry is corrupt (can't read first offset)"); return false; } // Read the first texture definition to try to identify the format if (!texturex->seek(wxINT32_SWAP_ON_BE(offsets[0]), SEEK_SET)) { Log::error("TEXTUREx entry is corrupt (can't read first definition)"); return false; } // Look at the name field. Is it present or not? char tempname[8]; if (!texturex->read(&tempname, 8)) { Log::error("TEXTUREx entry is corrupt (can't read first name)"); return false; } // Let's pretend it is and see what happens. txformat_ = Format::Normal; // Only the characters A-Z (uppercase), 0-9, and [ ] - _ should be used in texture names. for (uint8_t a = 0; a < 8; ++a) { if (a > 0 && tempname[a] == 0) // We found a null-terminator for the string, so we can assume it's okay. break; if (tempname[a] >= 'a' && tempname[a] <= 'z') { txformat_ = Format::Jaguar; // Log::info(1, "Jaguar texture"); break; } else if (!((tempname[a] >= 'A' && tempname[a] <= '[') || (tempname[a] >= '0' && tempname[a] <= '9') || tempname[a] == ']' || tempname[a] == '-' || tempname[a] == '_')) // We're out of character range, so this is probably not a texture name. { txformat_ = Format::Nameless; // Log::info(1, "Nameless texture"); break; } } // Now let's see if it is the abridged Strife format or not. if (txformat_ == Format::Normal) { // No need to test this again since it was already tested before. texturex->seek(offsets[0], SEEK_SET); FullTexDef temp; if (!texturex->read(&temp, 22)) { Log::error("TEXTUREx entry is corrupt (can't test definition)"); return false; } // Test condition adapted from ZDoom; apparently the first two bytes of columndir // may be set to garbage values by some editors and are therefore unreliable. if (wxINT16_SWAP_ON_BE(temp.patchcount <= 0) || (temp.columndir[1] != 0)) txformat_ = Format::Strife11; } // Read all texture definitions for (int32_t a = 0; a < n_tex; a++) { // Skip to texture definition if (!texturex->seek(offsets[a], SEEK_SET)) { Log::error("TEXTUREx entry is corrupt (can't find definition)"); return false; } // Read definition TexDef tdef; if (txformat_ == Format::Nameless) { NamelessTexDef nameless; // Auto-naming mechanism taken from DeuTex if (a > 99999) { Log::error("More than 100000 nameless textures"); return false; } char temp[9] = ""; sprintf(temp, "TEX%05d", a); memcpy(tdef.name, temp, 8); // Read texture info if (!texturex->read(&nameless, 8)) { Log::error("TEXTUREx entry is corrupt (can't read nameless definition #{})", a); return false; } // Copy data to permanent structure tdef.flags = nameless.flags; tdef.scale[0] = nameless.scale[0]; tdef.scale[1] = nameless.scale[1]; tdef.width = nameless.width; tdef.height = nameless.height; } else if (!texturex->read(&tdef, 16)) { Log::error("TEXTUREx entry is corrupt, (can't read texture definition #{})", a); return false; } // Skip unused if (txformat_ != Format::Strife11) { if (!texturex->seek(4, SEEK_CUR)) { Log::error("TEXTUREx entry is corrupt (can't skip dummy data past #{})", a); return false; } } // Create texture tdef.cleanupName(); auto tex = std::make_unique<CTexture>(); tex->name_ = StrUtil::viewFromChars(tdef.name, 8); tex->size_.x = wxINT16_SWAP_ON_BE(tdef.width); tex->size_.y = wxINT16_SWAP_ON_BE(tdef.height); tex->scale_.x = tdef.scale[0] / 8.0; tex->scale_.y = tdef.scale[1] / 8.0; // Set flags if (tdef.flags & Flags::WorldPanning) tex->world_panning_ = true; // Read patches int16_t n_patches = 0; if (!texturex->read(&n_patches, 2)) { Log::error("TEXTUREx entry is corrupt (can't read patchcount #{})", a); return false; } // Log::info(1, "Texture #{}: {} patch%s", a, n_patches, n_patches == 1 ? "" : "es"); for (uint16_t p = 0; p < n_patches; p++) { // Read patch definition Patch pdef; if (!texturex->read(&pdef, 6)) { Log::error("TEXTUREx entry is corrupt (can't read patch definition #{}:{})", a, p); Log::error("Lump size {}, offset {}", texturex->size(), texturex->currentPos()); return false; } // Skip unused if (txformat_ != Format::Strife11) { if (!texturex->seek(4, SEEK_CUR)) { Log::error("TEXTUREx entry is corrupt (can't skip dummy data past #{}:{})", a, p); return false; } } // Add it to the texture std::string patch; if (txformat_ == Format::Jaguar) { patch = StrUtil::upper(tex->name_); } else { patch = patch_table.patchName(pdef.patch); } if (patch.empty()) { // Log::info(1, "Warning: Texture %s contains patch %d which is invalid - may be incorrect PNAMES // entry", tex->getName(), pdef.patch); patch = fmt::format("INVPATCH{:04d}", pdef.patch); } tex->addPatch(patch, pdef.left, pdef.top); } // Add texture to list addTexture(std::move(tex)); } return true; }
/* 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; }
/* DatArchive::isDatArchive * Checks if the file at [filename] is a valid Shadowcaster dat archive *******************************************************************/ bool DatArchive::isDatArchive(string filename) { // Open file for reading wxFile file(filename); // Check it opened ok if (!file.IsOpened()) return false; // Read dat header file.Seek(0, wxFromStart); uint16_t num_lumps; uint32_t dir_offset, junk; file.Read(&num_lumps, 2); // Size file.Read(&dir_offset, 4); // Directory offset file.Read(&junk, 4); // Unknown value num_lumps = wxINT16_SWAP_ON_BE(num_lumps); dir_offset = wxINT32_SWAP_ON_BE(dir_offset); junk = wxINT32_SWAP_ON_BE(junk); if (dir_offset >= file.Length()) return false; // Read the directory file.Seek(dir_offset, wxFromStart); // Read lump info uint32_t offset = 0; uint32_t size = 0; uint16_t nameofs = 0; uint16_t flags = 0; file.Read(&offset, 4); // Offset file.Read(&size, 4); // Size file.Read(&nameofs, 2); // Name offset file.Read(&flags, 2); // Flags // 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); // The first lump should have a name (subsequent lumps need not have one). // Also, sanity check the values. if (nameofs == 0 || nameofs >= file.Length() || offset + size >= file.Length()) { return false; } string name; size_t len = 1; size_t start = nameofs+dir_offset; // Sanity checks again. Make sure there is actually a name. if (start > file.Length()) return false; uint8_t temp; file.Seek(start, wxFromStart); file.Read(&temp, 1); if (temp < 33) return false; for (size_t i = start; i < file.Length(); ++i, ++len) { file.Read(&temp, 1); // Found end of name if (temp == 0) break; // Names should not contain garbage characters if (temp < 32 || temp > 126) return false; } // Let's be reasonable here. While names aren't limited, if it's too long, it's suspicious. if (len > 60) return false; 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; }
/* TextureXList::readTEXTUREXData * Reads in a doom-format TEXTUREx entry. Returns true on success, * false otherwise *******************************************************************/ bool TextureXList::readTEXTUREXData(ArchiveEntry* texturex, PatchTable& patch_table, bool add) { // Check entries were actually given if (!texturex) return false; // Clear current textures if needed if (!add) clear(); // Update palette theMainWindow->getPaletteChooser()->setGlobalFromArchive(texturex->getParent()); // Read TEXTUREx // Read header texturex->seek(0, SEEK_SET); int32_t n_tex = 0; int32_t* offsets = NULL; // Number of textures if (!texturex->read(&n_tex, 4)) { wxLogMessage("Error: TEXTUREx entry is corrupt (can't read texture count)"); return false; } n_tex = wxINT32_SWAP_ON_BE(n_tex); // If it's an empty TEXTUREx entry, stop here if (n_tex == 0) return true; // Texture definition offsets offsets = new int32_t[n_tex]; if (!texturex->read(offsets, n_tex * 4)) { wxLogMessage("Error: TEXTUREx entry is corrupt (can't read first offset)"); return false; } // Read the first texture definition to try to identify the format if (!texturex->seek(wxINT32_SWAP_ON_BE(offsets[0]), SEEK_SET)) { wxLogMessage("Error: TEXTUREx entry is corrupt (can't read first definition)"); return false; } // Look at the name field. Is it present or not? char tempname[8]; if (!texturex->read(&tempname, 8)) { wxLogMessage("Error: TEXTUREx entry is corrupt (can't read first name)"); return false; } // Let's pretend it is and see what happens. txformat = TXF_NORMAL; // Only the characters A-Z (uppercase), 0-9, and [ ] - _ should be used in texture names. for (uint8_t a = 0; a < 8; ++a) { if (a > 0 && tempname[a] == 0) // We found a null-terminator for the string, so we can assume it's okay. break; if (tempname[a] >= 'a' && tempname[a] <= 'z') { txformat = TXF_JAGUAR; //wxLogMessage("Jaguar texture"); break; } else if (!((tempname[a] >= 'A' && tempname[a] <= '[') || (tempname[a] >= '0' && tempname[a] <= '9') || tempname[a] == ']' || tempname[a] == '-' || tempname[a] == '_')) // We're out of character range, so this is probably not a texture name. { txformat = TXF_NAMELESS; //wxLogMessage("Nameless texture"); break; } } // Now let's see if it is the abridged Strife format or not. if (txformat == TXF_NORMAL) { // No need to test this again since it was already tested before. texturex->seek(offsets[0], SEEK_SET); ftdef_t temp; if (!texturex->read(&temp, 22)) { wxLogMessage("Error: TEXTUREx entry is corrupt (can't test definition)"); return false; } // Test condition adapted from ZDoom; apparently the first two bytes of columndir // may be set to garbage values by some editors and are therefore unreliable. if (wxINT16_SWAP_ON_BE(temp.patchcount <= 0) || (temp.columndir[1] != 0)) txformat = TXF_STRIFE11; } // Read all texture definitions for (int32_t a = 0; a < n_tex; a++) { // Skip to texture definition if (!texturex->seek(offsets[a], SEEK_SET)) { wxLogMessage("Error: TEXTUREx entry is corrupt (can't find definition)"); return false; } // Read definition tdef_t tdef; if (txformat == TXF_NAMELESS) { nltdef_t nameless; // Auto-naming mechanism taken from DeuTex if (a > 99999) { wxLogMessage("Error: More than 100000 nameless textures"); return false; } char temp[9] = ""; sprintf (temp, "TEX%05d", a); memcpy(tdef.name, temp, 8); // Read texture info if (!texturex->read(&nameless, 8)) { wxLogMessage("Error: TEXTUREx entry is corrupt (can't read nameless definition #%d)", a); return false; } // Copy data to permanent structure tdef.flags = nameless.flags; tdef.scale[0] = nameless.scale[0]; tdef.scale[1] = nameless.scale[1]; tdef.width = nameless.width; tdef.height = nameless.height; } else if (!texturex->read(&tdef, 16)) { wxLogMessage("Error: TEXTUREx entry is corrupt, (can't read texture definition #%d)", a); return false; } // Skip unused if (txformat != TXF_STRIFE11) { if (!texturex->seek(4, SEEK_CUR)) { wxLogMessage("Error: TEXTUREx entry is corrupt (can't skip dummy data past #%d)", a); return false; } } // Create texture CTexture* tex = new CTexture(); tex->name = wxString::FromAscii(tdef.name, 8); tex->width = wxINT16_SWAP_ON_BE(tdef.width); tex->height = wxINT16_SWAP_ON_BE(tdef.height); tex->scale_x = tdef.scale[0]/8.0; tex->scale_y = tdef.scale[1]/8.0; // Set flags if (tdef.flags & TX_WORLDPANNING) tex->world_panning = true; // Read patches int16_t n_patches = 0; if (!texturex->read(&n_patches, 2)) { wxLogMessage("Error: TEXTUREx entry is corrupt (can't read patchcount #%d)", a); return false; } //wxLogMessage("Texture #%d: %d patch%s", a, n_patches, n_patches == 1 ? "" : "es"); for (uint16_t p = 0; p < n_patches; p++) { // Read patch definition tx_patch_t pdef; if (!texturex->read(&pdef, 6)) { wxLogMessage("Error: TEXTUREx entry is corrupt (can't read patch definition #%d:%d)", a, p); wxLogMessage("Lump size %d, offset %d", texturex->getSize(), texturex->currentPos()); return false; } // Skip unused if (txformat != TXF_STRIFE11) { if (!texturex->seek(4, SEEK_CUR)) { wxLogMessage("Error: TEXTUREx entry is corrupt (can't skip dummy data past #%d:%d)", a, p); return false; } } // Add it to the texture string patch; if (txformat == TXF_JAGUAR) { patch = tex->name.Upper(); } else { patch = patch_table.patchName(pdef.patch); } if (patch.IsEmpty()) { //wxLogMessage("Warning: Texture %s contains patch %d which is invalid - may be incorrect PNAMES entry", CHR(tex->getName()), pdef.patch); patch = S_FMT("INVPATCH%04d", pdef.patch); } tex->addPatch(patch, pdef.left, pdef.top); } // Add texture to list addTexture(tex); } // Clean up delete[] offsets; return true; }
/* EntryOperations::setGfxOffsets * Changes the offsets of the given gfx entry. Returns false if the * entry is invalid or not an offset-supported format, true otherwise *******************************************************************/ bool EntryOperations::setGfxOffsets(ArchiveEntry* entry, int x, int y) { if (entry == NULL || entry->getType() == NULL) return false; // Check entry type EntryType* type = entry->getType(); string entryformat = type->getFormat(); if (!(entryformat == "img_doom" || entryformat == "img_doom_arah" || entryformat == "img_doom_alpha" || entryformat == "img_doom_beta" || entryformat == "img_png")) { wxLogMessage("Entry \"%s\" is of type \"%s\" which does not support offsets", entry->getName(), entry->getType()->getName()); return false; } // Doom gfx format, normal and beta version. // Also arah format from alpha 0.2 because it uses the same header format. if (entryformat == "img_doom" || entryformat == "img_doom_beta" || entryformat == "image_doom_arah") { // Get patch header patch_header_t header; entry->seek(0, SEEK_SET); entry->read(&header, 8); // Apply new offsets header.left = wxINT16_SWAP_ON_BE((int16_t)x); header.top = wxINT16_SWAP_ON_BE((int16_t)y); // Write new header to entry entry->seek(0, SEEK_SET); entry->write(&header, 8); } // Doom alpha gfx format else if (entryformat == "img_doom_alpha") { // Get patch header entry->seek(0, SEEK_SET); oldpatch_header_t header; entry->read(&header, 4); // Apply new offsets header.left = (int8_t)x; header.top = (int8_t)y; // Write new header to entry entry->seek(0, SEEK_SET); entry->write(&header, 4); } // PNG format else if (entryformat == "img_png") { // Find existing grAb chunk const uint8_t* data = entry->getData(true); uint32_t grab_start = 0; for (uint32_t a = 0; a < entry->getSize(); a++) { // Check for 'grAb' header if (data[a] == 'g' && data[a + 1] == 'r' && data[a + 2] == 'A' && data[a + 3] == 'b') { grab_start = a - 4; break; } // Stop when we get to the 'IDAT' chunk if (data[a] == 'I' && data[a + 1] == 'D' && data[a + 2] == 'A' && data[a + 3] == 'T') break; } // Create new grAb chunk uint32_t csize = wxUINT32_SWAP_ON_LE(8); grab_chunk_t gc ={ { 'g', 'r', 'A', 'b' }, wxINT32_SWAP_ON_LE(x), wxINT32_SWAP_ON_LE(y) }; uint32_t dcrc = wxUINT32_SWAP_ON_LE(Misc::crc((uint8_t*)&gc, 12)); // Build new PNG from the original w/ the new grAb chunk MemChunk npng; uint32_t rest_start = 33; // Init new png data size if (grab_start == 0) npng.reSize(entry->getSize() + 20); else npng.reSize(entry->getSize()); // Write PNG header and IHDR chunk npng.write(data, 33); // If no existing grAb chunk was found, write new one here if (grab_start == 0) { npng.write(&csize, 4); npng.write(&gc, 12); npng.write(&dcrc, 4); } else { // Otherwise write any other data before the existing grAb chunk uint32_t to_write = grab_start - 33; npng.write(data + 33, to_write); rest_start = grab_start + 20; // And now write the new grAb chunk npng.write(&csize, 4); npng.write(&gc, 12); npng.write(&dcrc, 4); } // Write the rest of the PNG data uint32_t to_write = entry->getSize() - rest_start; npng.write(data + rest_start, to_write); // Load new png data to the entry entry->importMemChunk(npng); // Set its type back to png entry->setType(type); } else return false; return true; }
void Extract(bool bits16, bool sign, bool stereo, bool bigendian, bool offset, char *rawData, int dataSize, float *data1, float *data2, int *len1, int *len2) { int rawCount = 0; int dataCount1 = 0; int dataCount2 = 0; int i; *len1 = 0; *len2 = 0; if (offset && bits16) { /* Special case so as to not flip stereo channels during analysis */ if (stereo && !bigendian) { rawData += 3; dataSize -= 3; } else { rawData++; dataSize--; } } if (bits16) { if (sign && bigendian) while (rawCount + 1 < dataSize) { /* 16-bit signed BE */ data1[dataCount1] = (wxINT16_SWAP_ON_LE(*((signed short *) &rawData[rawCount]))) / 32768.0; dataCount1++; rawCount += 2; } if (!sign && bigendian) while (rawCount + 1 < dataSize) { /* 16-bit unsigned BE */ data1[dataCount1] = (wxUINT16_SWAP_ON_LE(*((unsigned short *) &rawData[rawCount]))) / 32768.0 - 1.0; dataCount1++; rawCount += 2; } if (sign && !bigendian) while (rawCount + 1 < dataSize) { /* 16-bit signed LE */ data1[dataCount1] = (wxINT16_SWAP_ON_BE(*((signed short *) &rawData[rawCount]))) / 32768.0; dataCount1++; rawCount += 2; } if (!sign && !bigendian) while (rawCount + 1 < dataSize) { /* 16-bit unsigned LE */ data1[dataCount1] = (wxUINT16_SWAP_ON_BE(*((unsigned short *) &rawData[rawCount]))) / 32768.0 - 1.0; dataCount1++; rawCount += 2; } } else { /* 8-bit */ if (sign) { while (rawCount < dataSize) { /* 8-bit signed */ data1[dataCount1++] = (*(signed char *) (&rawData[rawCount++])) / 128.0; } } else { while (rawCount < dataSize) { /* 8-bit unsigned */ data1[dataCount1++] = (*(unsigned char *) &rawData[rawCount++]) / 128.0 - 1.0; } } } if (stereo) { dataCount1 /= 2; for(i=0; i<dataCount1; i++) { data2[i] = data1[2*i+1]; data1[i] = data1[2*i]; } dataCount2 = dataCount1; } *len1 = dataCount1; *len2 = dataCount2; }
bool ExportCL(AudacityProject *project, bool stereo, wxString fName, bool selectionOnly, double t0, double t1) { int rate = int(project->GetRate() + 0.5); wxWindow *parent = project; TrackList *tracks = project->GetTracks(); wxString command = gPrefs->Read("/FileFormats/ExternalProgramExportCommand", "lame - '%f'"); command.Replace("%f", fName); /* establish parameters */ int channels = stereo ? 2 : 1; unsigned long totalSamples = (unsigned long)((t1 - t0) * rate + 0.5); unsigned long sampleBytes = totalSamples * channels * SAMPLE_SIZE(int16Sample); double timeStep = 10.0; // write in blocks of 10 secs /* fill up the wav header */ wav_header header; header.riffID[0] = 'R'; header.riffID[1] = 'I'; header.riffID[2] = 'F'; header.riffID[3] = 'F'; header.riffType[0] = 'W'; header.riffType[1] = 'A'; header.riffType[2] = 'V'; header.riffType[3] = 'E'; header.lenAfterRiff = sampleBytes + 32; header.fmtID[0] = 'f'; header.fmtID[1] = 'm'; header.fmtID[2] = 't'; header.fmtID[3] = ' '; header.formatChunkLen = 16; header.formatTag = 1; header.channels = channels; header.sampleRate = rate; header.bitsPerSample = SAMPLE_SIZE(int16Sample) * 8; header.blockAlign = header.bitsPerSample * header.channels; header.avgBytesPerSec = header.sampleRate * header.blockAlign; header.dataID[0] = 'd'; header.dataID[1] = 'a'; header.dataID[2] = 't'; header.dataID[3] = 'a'; header.dataLen = sampleBytes; FILE *pipe = popen(command.c_str(), "w"); /* write the header */ fwrite( &header, sizeof(wav_header), 1, pipe ); //sampleCount maxSamples = int (timeStep * rate + 0.5); wxProgressDialog *progress = NULL; wxYield(); wxStartTimer(); wxBusyCursor busy; bool cancelling = false; double t = t0; while (t < t1 && !cancelling) { double deltat = timeStep; if (t + deltat > t1) deltat = t1 - t; sampleCount numSamples = int (deltat * rate + 0.5); Mixer *mixer = new Mixer(channels, numSamples, true, rate, int16Sample); wxASSERT(mixer); mixer->Clear(); char *buffer = new char[numSamples * SAMPLE_SIZE(int16Sample) * channels]; wxASSERT(buffer); TrackListIterator iter(tracks); VTrack *tr = iter.First(); while (tr) { if (tr->GetKind() == VTrack::Wave) { if (tr->GetSelected() || !selectionOnly) { if (tr->GetChannel() == VTrack::MonoChannel) mixer->MixMono((WaveTrack *) tr, t, t + deltat); if (tr->GetChannel() == VTrack::LeftChannel) mixer->MixLeft((WaveTrack *) tr, t, t + deltat); if (tr->GetChannel() == VTrack::RightChannel) mixer->MixRight((WaveTrack *) tr, t, t + deltat); } } tr = iter.Next(); } samplePtr mixed = mixer->GetBuffer(); // Byte-swapping is neccesary on big-endian machines, since // WAV files are little-endian #if wxBYTE_ORDER == wxBIG_ENDIAN { short *buffer = (short*)mixed; for( int i = 0; i < numSamples; i++ ) buffer[i] = wxINT16_SWAP_ON_BE(buffer[i]); } #endif fwrite( mixed, numSamples * channels * SAMPLE_SIZE(int16Sample), 1, pipe ); t += deltat; if (!progress && wxGetElapsedTime(false) > 500) { wxString message; if (selectionOnly) message = "Exporting the selected audio using command-line encoder"; else message = "Exporting the entire project using command-line encoder"; progress = new wxProgressDialog("Export", message, 1000, parent, wxPD_CAN_ABORT | wxPD_REMAINING_TIME | wxPD_AUTO_HIDE); } if (progress) { cancelling = !progress->Update(int (((t - t0) * 1000) / (t1 - t0) + 0.5)); } delete mixer; delete[]buffer; } pclose( pipe ); if(progress) delete progress; return true; }
bool ExportCL(AudacityProject *project, bool stereo, wxString fName, bool selectionOnly, double t0, double t1, MixerSpec *mixerSpec) { int rate = int(project->GetRate() + 0.5); wxWindow *parent = project; TrackList *tracks = project->GetTracks(); wxString command = gPrefs->Read(wxT("/FileFormats/ExternalProgramExportCommand"), wxT("lame - '%f'")); command.Replace(wxT("%f"), fName); /* establish parameters */ int channels = stereo ? 2 : 1; unsigned long totalSamples = (unsigned long)((t1 - t0) * rate + 0.5); unsigned long sampleBytes = totalSamples * channels * SAMPLE_SIZE(int16Sample); /* fill up the wav header */ wav_header header; header.riffID[0] = 'R'; header.riffID[1] = 'I'; header.riffID[2] = 'F'; header.riffID[3] = 'F'; header.riffType[0] = 'W'; header.riffType[1] = 'A'; header.riffType[2] = 'V'; header.riffType[3] = 'E'; header.lenAfterRiff = sampleBytes + 32; header.fmtID[0] = 'f'; header.fmtID[1] = 'm'; header.fmtID[2] = 't'; header.fmtID[3] = ' '; header.formatChunkLen = 16; header.formatTag = 1; header.channels = channels; header.sampleRate = rate; header.bitsPerSample = SAMPLE_SIZE(int16Sample) * 8; header.blockAlign = header.bitsPerSample * header.channels; header.avgBytesPerSec = header.sampleRate * header.blockAlign; header.dataID[0] = 'd'; header.dataID[1] = 'a'; header.dataID[2] = 't'; header.dataID[3] = 'a'; header.dataLen = sampleBytes; FILE *pipe = popen(OSFILENAME(command), "w"); /* write the header */ fwrite( &header, sizeof(wav_header), 1, pipe ); sampleCount maxBlockLen = 44100 * 5; bool cancelling = false; int numWaveTracks; WaveTrack **waveTracks; tracks->GetWaveTracks(selectionOnly, &numWaveTracks, &waveTracks); Mixer *mixer = new Mixer(numWaveTracks, waveTracks, tracks->GetTimeTrack(), t0, t1, channels, maxBlockLen, true, rate, int16Sample, true, mixerSpec); GetActiveProject()->ProgressShow(_("Export"), selectionOnly ? _("Exporting the selected audio using command-line encoder") : _("Exporting the entire project using command-line encoder")); while(!cancelling) { sampleCount numSamples = mixer->Process(maxBlockLen); if (numSamples == 0) break; samplePtr mixed = mixer->GetBuffer(); char *buffer = new char[numSamples * SAMPLE_SIZE(int16Sample) * channels]; wxASSERT(buffer); // Byte-swapping is neccesary on big-endian machines, since // WAV files are little-endian #if wxBYTE_ORDER == wxBIG_ENDIAN { short *buffer = (short*)mixed; for( int i = 0; i < numSamples; i++ ) buffer[i] = wxINT16_SWAP_ON_BE(buffer[i]); } #endif fwrite( mixed, numSamples * channels * SAMPLE_SIZE(int16Sample), 1, pipe ); int progressvalue = int (1000 * ((mixer->MixGetCurrentTime()-t0) / (t1-t0))); cancelling = !GetActiveProject()->ProgressUpdate(progressvalue); delete[]buffer; } GetActiveProject()->ProgressHide(); delete mixer; pclose( pipe ); return true; }