bool MusBinOutput::WriteElementAttr( const MusElement *element ) { Write( &element->liaison , 1 ); Write( &element->dliai , 1 ); Write( &element->fliai , 1 ); Write( &element->lie_up , 1 ); Write( &element->rel , 1 ); Write( &element->drel , 1 ); Write( &element->frel , 1 ); Write( &element->oct , 1 ); Write( &element->dimin , 1 ); Write( &element->grp , 1 ); Write( &element->_shport , 1 ); Write( &element->ligat , 1 ); Write( &element->ElemInvisible , 1 ); Write( &element->pointInvisible , 1 ); Write( &element->existDebord , 1 ); Write( &element->fligat , 1 ); Write( &element->notschowgrp , 1 ); Write( &element->cone , 1 ); Write( &element->liaisonPointil , 1 ); Write( &element->reserve1 , 1 ); Write( &element->reserve2 , 1 ); Write( &element->ottava , 1 ); uint16 = wxUINT16_SWAP_ON_BE( element->durNum ); Write( &uint16, 2 ); uint16 = wxUINT16_SWAP_ON_BE( element->durDen ); Write( &uint16, 2 ); uint16 = wxUINT16_SWAP_ON_BE( element->offset ); Write( &uint16, 2 ); int32 = wxINT32_SWAP_ON_BE( element->xrel ); Write( &int32, 4 ); return true; }
bool MusBinInput::ReadElementAttr( MusElement *element ) { Read( &element->liaison , 1 ); Read( &element->dliai , 1 ); Read( &element->fliai , 1 ); Read( &element->lie_up , 1 ); Read( &element->rel , 1 ); Read( &element->drel , 1 ); Read( &element->frel , 1 ); Read( &element->oct , 1 ); Read( &element->dimin , 1 ); Read( &element->grp , 1 ); Read( &element->_shport , 1 ); Read( &element->ligat , 1 ); Read( &element->ElemInvisible , 1 ); Read( &element->pointInvisible , 1 ); Read( &element->existDebord , 1 ); Read( &element->fligat , 1 ); Read( &element->notschowgrp , 1 ); Read( &element->cone , 1 ); Read( &element->liaisonPointil , 1 ); Read( &element->reserve1 , 1 ); Read( &element->reserve2 , 1 ); Read( &element->ottava , 1 ); Read( &uint16, 2 ); element->durNum = wxUINT16_SWAP_ON_BE( uint16 ); Read( &uint16, 2 ); element->durDen = wxUINT16_SWAP_ON_BE( uint16 ); Read( &uint16, 2 ); element->offset = wxUINT16_SWAP_ON_BE( uint16 ); Read( &int32, 4 ); element->xrel = wxINT32_SWAP_ON_BE( int32 ); return true; }
void MyApp::DoByteOrderDemo(wxCommandEvent& WXUNUSED(event)) { wxTextCtrl& textCtrl = * GetTextCtrl(); textCtrl.Clear(); textCtrl << _T("\nTest byte order macros:\n\n"); #if wxBYTE_ORDER == wxLITTLE_ENDIAN textCtrl << _T("This is a little endian system.\n\n"); #else textCtrl << _T("This is a big endian system.\n\n"); #endif wxString text; wxInt32 var = 0xF1F2F3F4; text = wxEmptyString; text.Printf( _T("Value of wxInt32 is now: %#x.\n\n"), var ); textCtrl.WriteText( text ); text = wxEmptyString; text.Printf( _T("Value of swapped wxInt32 is: %#x.\n\n"), wxINT32_SWAP_ALWAYS( var ) ); textCtrl.WriteText( text ); text = wxEmptyString; text.Printf( _T("Value of wxInt32 swapped on little endian is: %#x.\n\n"), wxINT32_SWAP_ON_LE( var ) ); textCtrl.WriteText( text ); text = wxEmptyString; text.Printf( _T("Value of wxInt32 swapped on big endian is: %#x.\n\n"), wxINT32_SWAP_ON_BE( var ) ); textCtrl.WriteText( text ); }
/* RffArchive::isRffArchive * Checks if the given data is a valid Duke Nukem 3D grp archive *******************************************************************/ bool RffArchive::isRffArchive(MemChunk& mc) { // Check size if (mc.getSize() < 12) 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) return false; // Compute total size 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)); uint32_t totalsize = 12 + num_lumps * sizeof(RFFLump); uint32_t size = 0; for (uint32_t a = 0; a < num_lumps; ++a) { totalsize += lumps[a].Size; } // Check if total size is correct if (totalsize > mc.getSize()) return false; // If it's passed to here it's probably a grp file return true; }
bool MusBinOutput::WriteLyric( const MusElement *element ) { int32 = wxINT32_SWAP_ON_BE( (int)element->m_debord_str.Length() ); Write( &int32, 4 ); Write( element->m_debord_str.c_str(), (int)element->m_debord_str.Length() + 1 ); return true; }
/* GobArchive::isGobArchive * Checks if the file at [filename] is a valid Dark Forces gob archive *******************************************************************/ bool GobArchive::isGobArchive(string filename) { // Open file for reading wxFile file(filename); // Check it opened ok if (!file.IsOpened()) return false; // Check size if (file.Length() < 12) return false; // Read header char header[4]; file.Read(header, 4); // Check magic header if (header[0] != 'G' || header[1] != 'O' || header[2] != 'B' || header[3] != 0xA) return false; // Get directory offset uint32_t dir_offset = 0; file.Seek(4, wxFromStart); file.Read(&dir_offset, 4); dir_offset = wxINT32_SWAP_ON_BE(dir_offset); // Check size if ((unsigned)file.Length() < (dir_offset + 4)) return false; // Get number of lumps uint32_t num_lumps = 0; file.Seek(dir_offset, wxFromStart); file.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)file.Length() < (dir_offset + dir_size)) return false; // If it's passed to here it's probably a gob file return true; }
bool ResArchive::isResArchive(MemChunk& mc, size_t& dir_offset, size_t& num_lumps) { // Check size if (mc.getSize() < 12) return false; // Check for "Res!" header if (!(mc[0] == 'R' && mc[1] == 'e' && mc[2] == 's' && mc[3] == '!')) return false; // Get number of lumps and directory offset uint32_t offset_offset = 0; uint32_t rel_offset = 0; uint32_t dir_size = 0; mc.seek(4, SEEK_SET); mc.read(&dir_offset, 4); mc.read(&dir_size, 4); // Byteswap values for big endian if needed dir_size = wxINT32_SWAP_ON_BE(dir_size); dir_offset = wxINT32_SWAP_ON_BE(dir_offset); // A&A contains nested resource files. The offsets are then always relative to // the top-level file. This causes problem with the embedded archive system // used by SLADE3. The solution is to compute the offset offset. :) offset_offset = dir_offset - (mc.getSize() - dir_size); rel_offset = dir_offset - offset_offset; // Check directory offset and size are both decent if (dir_size % RESDIRENTRYSIZE || (rel_offset + dir_size) > mc.getSize()) return false; num_lumps = dir_size / RESDIRENTRYSIZE; // Reset MemChunk (just in case) mc.seek(0, SEEK_SET); // If it's passed to here it's probably a res file return true; }
/* ADatArchive::isADatArchive * Checks if the file at [filename] is a valid Anachronox dat archive *******************************************************************/ bool ADatArchive::isADatArchive(string filename) { // Open file for reading wxFile file(filename); // Check it opened ok if (!file.IsOpened() || file.Length() < 16) return false; // Read dat header char magic[4]; long dir_offset; long dir_size; long version; file.Seek(0, wxFromStart); file.Read(magic, 4); file.Read(&dir_offset, 4); file.Read(&dir_size, 4); file.Read(&version, 4); // Byteswap values for big endian if needed dir_size = wxINT32_SWAP_ON_BE(dir_size); dir_offset = wxINT32_SWAP_ON_BE(dir_offset); // Check version if (wxINT32_SWAP_ON_BE(version) != 9) return false; // Check header if (magic[0] != 'A' || magic[1] != 'D' || magic[2] != 'A' || magic[3] != 'T') return false; // Check directory is sane if (dir_offset < 16 || dir_offset + dir_size > file.Length()) return false; // That'll do return true; }
/* LfdArchive::isLfdArchive * Checks if the given data is a valid Dark Forces lfd archive *******************************************************************/ bool LfdArchive::isLfdArchive(MemChunk& mc) { // Check size if (mc.getSize() < 12) return false; // Check magic header if (mc[0] != 'R' || mc[1] != 'M' || mc[2] != 'A' || mc[3] != 'P') return false; // Get offset of first entry uint32_t dir_offset = 0; mc.seek(12, SEEK_SET); mc.read(&dir_offset, 4); dir_offset = wxINT32_SWAP_ON_BE(dir_offset) + 16; if (dir_offset % 16) return false; char type1[5]; char type2[5]; char name1[9]; char name2[9]; uint32_t len1; uint32_t len2; mc.read(type1, 4); type1[4] = 0; mc.read(name1, 8); name1[8] = 0; mc.read(&len1, 4); len1 = wxINT32_SWAP_ON_BE(len1); // Check size if ((unsigned)mc.getSize() < (dir_offset + 16 + len1)) return false; // Compare mc.seek(dir_offset, SEEK_SET); mc.read(type2, 4); type2[4] = 0; mc.read(name2, 8); name2[8] = 0; mc.read(&len2, 4); len2 = wxINT32_SWAP_ON_BE(len2); if (strcmp(type1, type2) || strcmp(name1, name2) || len1 != len2) return false; // If it's passed to here it's probably a lfd file return true; }
/* HogArchive::write * Writes the hog archive to a MemChunk * Returns true if successful, false otherwise *******************************************************************/ bool HogArchive::write(MemChunk& mc, bool update) { // Determine individual lump offsets uint32_t offset = 3; ArchiveEntry* entry = NULL; for (uint32_t l = 0; l < numEntries(); l++) { offset += 17; entry = getEntry(l); setEntryOffset(entry, offset); if (update) { entry->setState(0); entry->exProp("Offset") = (int)offset; } offset += entry->getSize(); } // Clear/init MemChunk mc.clear(); mc.seek(0, SEEK_SET); mc.reSize(offset); // Write the header char header[3] = { 'D', 'H', 'F' }; mc.write(header, 3); // Write the lumps for (uint32_t l = 0; l < numEntries(); l++) { entry = getEntry(l); mc.write(entry->getData(), entry->getSize()); } // Write the directory for (uint32_t l = 0; l < numEntries(); l++) { entry = getEntry(l); char name[13] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; long size = wxINT32_SWAP_ON_BE(entry->getSize()); for (size_t c = 0; c < entry->getName().length() && c < 13; c++) name[c] = entry->getName()[c]; mc.write(name, 13); mc.write(&size, 4); mc.write(entry->getData(), entry->getSize()); } return true; }
/* ResArchive::isResArchive * Checks if the file at [filename] is a valid A&A res archive *******************************************************************/ bool ResArchive::isResArchive(string filename) { // Open file for reading wxFile file(filename); // Check it opened ok if (!file.IsOpened()) return false; file.Seek(0, wxFromStart); // Read header char header[5]; file.Read(header, 4); header[4] = 0; // Check for "Res!" header if (!(header[0] == 'R' && header[1] == 'e' && header[2] == 's' && header[3] == '!')) return false; // Get number of lumps and directory offset uint32_t dir_offset = 0; uint32_t dir_size = 0; file.Read(&dir_offset, 4); file.Read(&dir_size, 4); // Byteswap values for big endian if needed dir_size = wxINT32_SWAP_ON_BE(dir_size); dir_offset = wxINT32_SWAP_ON_BE(dir_offset); // Check directory offset and size are both decent if (dir_size % RESDIRENTRYSIZE || (dir_offset + dir_size) > file.Length()) return false; // If it's passed to here it's probably a res file 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; }
/* ADatArchive::isADatArchive * Checks if the given data is a valid Anachronox dat archive *******************************************************************/ bool ADatArchive::isADatArchive(MemChunk& mc) { // Check it opened ok if (mc.getSize() < 16) return false; // Read dat header char magic[4]; long dir_offset; long dir_size; long version; mc.seek(0, SEEK_SET); mc.read(magic, 4); mc.read(&dir_offset, 4); mc.read(&dir_size, 4); mc.read(&version, 4); // Byteswap values for big endian if needed dir_size = wxINT32_SWAP_ON_BE(dir_size); dir_offset = wxINT32_SWAP_ON_BE(dir_offset); // Check version if (wxINT32_SWAP_ON_BE(version) != 9) return false; // Check header if (magic[0] != 'A' || magic[1] != 'D' || magic[2] != 'A' || magic[3] != 'T') return false; // Check directory is sane if (dir_offset < 16 || (unsigned)(dir_offset + dir_size) > mc.getSize()) return false; // That'll do return true; }
/* WadArchive::isWadArchive * Checks if the file at [filename] is a valid Doom wad archive *******************************************************************/ bool WadArchive::isWadArchive(string filename) { // Open file for reading wxFile file(filename); // Check it opened ok if (!file.IsOpened()) return false; // Read header char header[4]; file.Read(header, 4); // Check for IWAD/PWAD header if (!(header[1] == 'W' && header[2] == 'A' && header[3] == 'D' && (header[0] == 'P' || header[0] == 'I'))) return false; // Get number of lumps and directory offset uint32_t num_lumps = 0; uint32_t dir_offset = 0; file.Read(&num_lumps, 4); file.Read(&dir_offset, 4); // Byteswap values for big endian if needed num_lumps = wxINT32_SWAP_ON_BE(num_lumps); dir_offset = wxINT32_SWAP_ON_BE(dir_offset); // Check directory offset is decent if ((dir_offset + (num_lumps * 16)) > file.Length() || dir_offset < 12) return false; // If it's passed to here it's probably a wad file return true; }
bool CRemoteProtocolHandler::readUnlink(wxString& callsign, PROTOCOL& protocol, wxString& reflector) { if (m_type != RPHT_UNLINK) return false; callsign = wxString((char*)(m_inBuffer + 3U), wxConvLocal, LONG_CALLSIGN_LENGTH); wxInt32 temp; ::memcpy(&temp, m_inBuffer + 3U + LONG_CALLSIGN_LENGTH, sizeof(wxInt32)); protocol = PROTOCOL(wxINT32_SWAP_ON_BE(temp)); reflector = wxString((char*)(m_inBuffer + 3U + LONG_CALLSIGN_LENGTH + sizeof(wxInt32)), wxConvLocal, LONG_CALLSIGN_LENGTH); return true; }
// ----------------------------------------------------------------------------- // Checks if the file at [filename] is a valid DN3D grp archive // ----------------------------------------------------------------------------- bool GrpArchive::isGrpArchive(const string& filename) { // Open file for reading wxFile file(filename); // Check it opened ok if (!file.IsOpened()) return false; // Check size if (file.Length() < 16) return false; // Get number of lumps uint32_t num_lumps = 0; char ken_magic[13] = ""; file.Seek(0, wxFromStart); file.Read(ken_magic, 12); // "KenSilverman" file.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::From8BitData(ken_magic), "KenSilverman"))) return false; // Compute total size uint32_t totalsize = (1 + num_lumps) * 16; uint32_t size = 0; for (uint32_t a = 0; a < num_lumps; ++a) { file.Read(ken_magic, 12); file.Read(&size, 4); totalsize += size; } // Check if total size is correct if (totalsize > file.Length()) return false; // If it's passed to here it's probably a grp file return true; }
bool CRemoteProtocolHandler::readLink(wxString& callsign, RECONNECT& reconnect, wxString& reflector) { if (m_type != RPHT_LINK) return false; callsign = wxString((char*)(m_inBuffer + 3U), wxConvLocal, LONG_CALLSIGN_LENGTH); wxInt32 temp; ::memcpy(&temp, m_inBuffer + 3U + LONG_CALLSIGN_LENGTH, sizeof(wxInt32)); reconnect = RECONNECT(wxINT32_SWAP_ON_BE(temp)); reflector = wxString((char*)(m_inBuffer + 3U + LONG_CALLSIGN_LENGTH + sizeof(wxInt32)), wxConvLocal, LONG_CALLSIGN_LENGTH); if (reflector.IsSameAs(wxT(" "))) reflector.Clear(); return true; }
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; }
// ----------------------------------------------------------------------------- // Checks if the given data is a valid Duke Nukem 3D grp archive // ----------------------------------------------------------------------------- bool GrpArchive::isGrpArchive(MemChunk& mc) { // Check size if (mc.size() < 16) return false; // Get number of lumps 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::From8BitData(ken_magic), "KenSilverman"))) return false; // Compute total size uint32_t totalsize = (1 + num_lumps) * 16; uint32_t size = 0; for (uint32_t a = 0; a < num_lumps; ++a) { mc.read(ken_magic, 12); mc.read(&size, 4); totalsize += size; } // Check if total size is correct if (totalsize > mc.size()) return false; // If it's passed to here it's probably a grp file return true; }
bool MusBinInput::ReadSymbol( MusSymbol *symbol ) { ReadElementAttr( symbol ); Read( &symbol->flag , 1 ); we also need to convert LEIPZIG_METER_SYMB_CUT into METER_SYMB_CUT for IND_MES Read( &symbol->calte , 1 ); Read( &symbol->carStyle , 1 ); Read( &symbol->carOrient , 1 ); Read( &symbol->fonte , 1 ); Read( &symbol->s_lie_l , 1 ); Read( &symbol->point , 1 ); Read( &uint16, 2 ); symbol->code = wxUINT16_SWAP_ON_BE( uint16 ); Read( &uint16, 2 ); symbol->l_ptch = wxUINT16_SWAP_ON_BE( uint16 ); Read( &int32, 4 ); symbol->dec_y = wxINT32_SWAP_ON_BE( int32 ); if ( symbol->IsLyric() ) ReadLyric( symbol ); return true; }
/* HogArchive::isHogArchive * Checks if the file at [filename] is a valid Descent hog archive *******************************************************************/ bool HogArchive::isHogArchive(string filename) { // Open file for reading wxFile file(filename); // Check it opened ok if (!file.IsOpened()) return false; // Check size size_t size = file.Length(); if (size < 3) return false; // Check magic header char magic[3] = ""; file.Seek(0, wxFromStart); file.Read(magic, 3); if (magic[0] != 'D' || magic[1] != 'H' || magic[2] != 'F') return false; // Iterate through files to see if the size seems okay size_t offset = 3; while (offset < size) { // Enough room for the header? if (offset + 17 > size) return false; // Read entry size to compute next offset uint32_t lumpsize; file.Seek(offset + 13, wxFromStart); file.Read(&lumpsize, 4); offset += 17 + wxINT32_SWAP_ON_BE(lumpsize); } // We should end on at exactly the end of the file return (offset == size); }
bool MusBinOutput::WriteSymbol( const MusSymbol *symbol ) { Write( &symbol->TYPE, 1 ); WriteElementAttr( symbol ); Write( &symbol->flag , 1 ); Write( &symbol->calte , 1 ); Write( &symbol->carStyle , 1 ); Write( &symbol->carOrient , 1 ); Write( &symbol->fonte , 1 ); Write( &symbol->s_lie_l , 1 ); Write( &symbol->point , 1 ); uint16 = wxUINT16_SWAP_ON_BE( symbol->code ); Write( &uint16, 2 ); uint16 = wxUINT16_SWAP_ON_BE( symbol->l_ptch ); Write( &uint16, 2 ); int32 = wxINT32_SWAP_ON_BE( symbol->dec_y ); Write( &int32, 4 ); // if ( symbol->IsLyric() ) // To be fixed ?? if ( (symbol->flag == CHAINE) && (symbol->fonte == LYRIC) ) WriteLyric( symbol ); return true; }
inline static wxInt32 CacheReadInt32(wxInputStream *f) { wxInt32 x; f->Read(&x, sizeof(x)); return wxINT32_SWAP_ON_BE(x); }
inline static void CacheWriteInt32(wxOutputStream *f, wxInt32 value) { wxInt32 x = wxINT32_SWAP_ON_BE(value); f->Write(&x, sizeof(x)); }
/* 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; }
bool wxBMPHandler::DoLoadDib(wxImage * image, int width, int height, int bpp, int ncolors, int comp, wxFileOffset bmpOffset, wxInputStream& stream, bool verbose, bool IsBmp, bool hasPalette) { wxInt32 aDword, rmask = 0, gmask = 0, bmask = 0, amask = 0; int rshift = 0, gshift = 0, bshift = 0, ashift = 0; int rbits = 0, gbits = 0, bbits = 0; wxInt32 dbuf[4]; wxInt8 bbuf[4]; wxUint8 aByte; wxUint16 aWord; // allocate space for palette if needed: BMPPalette *cmap; if ( bpp < 16 ) { cmap = new BMPPalette[ncolors]; if ( !cmap ) { if (verbose) { wxLogError(_("BMP: Couldn't allocate memory.")); } return false; } } else // no palette { cmap = NULL; } wxON_BLOCK_EXIT1(&BMPPalette::Free, cmap); // destroy existing here instead of: image->Destroy(); image->Create(width, height); unsigned char *ptr = image->GetData(); if ( !ptr ) { if ( verbose ) { wxLogError( _("BMP: Couldn't allocate memory.") ); } return false; } unsigned char *alpha; if ( bpp == 32 ) { // tell the image to allocate an alpha buffer image->SetAlpha(); alpha = image->GetAlpha(); if ( !alpha ) { if ( verbose ) { wxLogError(_("BMP: Couldn't allocate memory.")); } return false; } } else // no alpha { alpha = NULL; } // Reading the palette, if it exists: if ( bpp < 16 && ncolors != 0 ) { unsigned char* r = new unsigned char[ncolors]; unsigned char* g = new unsigned char[ncolors]; unsigned char* b = new unsigned char[ncolors]; for (int j = 0; j < ncolors; j++) { if (hasPalette) { stream.Read(bbuf, 4); cmap[j].b = bbuf[0]; cmap[j].g = bbuf[1]; cmap[j].r = bbuf[2]; r[j] = cmap[j].r; g[j] = cmap[j].g; b[j] = cmap[j].b; } else { //used in reading .ico file mask r[j] = cmap[j].r = g[j] = cmap[j].g = b[j] = cmap[j].b = ( j ? 255 : 0 ); } } #if wxUSE_PALETTE // Set the palette for the wxImage image->SetPalette(wxPalette(ncolors, r, g, b)); #endif // wxUSE_PALETTE delete[] r; delete[] g; delete[] b; } else if ( bpp == 16 || bpp == 32 ) { if ( comp == BI_BITFIELDS ) { int bit; stream.Read(dbuf, 4 * 3); rmask = wxINT32_SWAP_ON_BE(dbuf[0]); gmask = wxINT32_SWAP_ON_BE(dbuf[1]); bmask = wxINT32_SWAP_ON_BE(dbuf[2]); // find shift amount (Least significant bit of mask) for (bit = bpp-1; bit>=0; bit--) { if (bmask & (1 << bit)) bshift = bit; if (gmask & (1 << bit)) gshift = bit; if (rmask & (1 << bit)) rshift = bit; } // Find number of bits in mask (MSB-LSB+1) for (bit = 0; bit < bpp; bit++) { if (bmask & (1 << bit)) bbits = bit-bshift+1; if (gmask & (1 << bit)) gbits = bit-gshift+1; if (rmask & (1 << bit)) rbits = bit-rshift+1; } } else if ( bpp == 16 ) { rmask = 0x7C00; gmask = 0x03E0; bmask = 0x001F; rshift = 10; gshift = 5; bshift = 0; rbits = 5; gbits = 5; bbits = 5; } else if ( bpp == 32 ) { rmask = 0x00FF0000; gmask = 0x0000FF00; bmask = 0x000000FF; amask = 0xFF000000; ashift = 24; rshift = 16; gshift = 8; bshift = 0; rbits = 8; gbits = 8; bbits = 8; } } /* * Reading the image data */ if ( IsBmp ) { // NOTE: seeking a positive amount in wxFromCurrent mode allows us to // load even non-seekable streams (see wxInputStream::SeekI docs)! const wxFileOffset pos = stream.TellI(); if (pos != wxInvalidOffset && bmpOffset > pos) if (stream.SeekI(bmpOffset - pos, wxFromCurrent) == wxInvalidOffset) return false; //else: icon, just carry on } unsigned char *data = ptr; /* set the whole image to the background color */ if ( bpp < 16 && (comp == BI_RLE4 || comp == BI_RLE8) ) { for (int i = 0; i < width * height; i++) { *ptr++ = cmap[0].r; *ptr++ = cmap[0].g; *ptr++ = cmap[0].b; } ptr = data; } int linesize = ((width * bpp + 31) / 32) * 4; /* BMPs are stored upside down */ for ( int line = (height - 1); line >= 0; line-- ) { int linepos = 0; for ( int column = 0; column < width ; ) { if ( bpp < 16 ) { linepos++; aByte = stream.GetC(); if ( bpp == 1 ) { for (int bit = 0; bit < 8 && column < width; bit++) { int index = ((aByte & (0x80 >> bit)) ? 1 : 0); ptr[poffset] = cmap[index].r; ptr[poffset + 1] = cmap[index].g; ptr[poffset + 2] = cmap[index].b; column++; } } else if ( bpp == 4 ) { if ( comp == BI_RLE4 ) { wxUint8 first; first = aByte; aByte = stream.GetC(); if ( first == 0 ) { if ( aByte == 0 ) { if ( column > 0 ) column = width; } else if ( aByte == 1 ) { column = width; line = -1; } else if ( aByte == 2 ) { aByte = stream.GetC(); column += aByte; linepos = column * bpp / 4; aByte = stream.GetC(); line -= aByte; // upside down } else { int absolute = aByte; wxUint8 nibble[2] ; int readBytes = 0 ; for (int k = 0; k < absolute; k++) { if ( !(k % 2 ) ) { ++readBytes ; aByte = stream.GetC(); nibble[0] = (wxUint8)( (aByte & 0xF0) >> 4 ) ; nibble[1] = (wxUint8)( aByte & 0x0F ) ; } ptr[poffset ] = cmap[nibble[k%2]].r; ptr[poffset + 1] = cmap[nibble[k%2]].g; ptr[poffset + 2] = cmap[nibble[k%2]].b; column++; if ( k % 2 ) linepos++; } if ( readBytes & 0x01 ) aByte = stream.GetC(); } } else { wxUint8 nibble[2] ; nibble[0] = (wxUint8)( (aByte & 0xF0) >> 4 ) ; nibble[1] = (wxUint8)( aByte & 0x0F ) ; for ( int l = 0; l < first && column < width; l++ ) { ptr[poffset ] = cmap[nibble[l%2]].r; ptr[poffset + 1] = cmap[nibble[l%2]].g; ptr[poffset + 2] = cmap[nibble[l%2]].b; column++; if ( l % 2 ) linepos++; } } }
/* TextureXList::writeTEXTUREXData * Writes the texture list in TEXTUREX format to [texturex], using * [patch_table] for patch information. Returns true on success, * false otherwise *******************************************************************/ bool TextureXList::writeTEXTUREXData(ArchiveEntry* texturex, PatchTable& patch_table) { // Check entry was given if (!texturex) return false; if (texturex->isLocked()) return false; wxLogMessage("Writing " + getTextureXFormatString() + " format TEXTUREx entry"); /* Total size of a TEXTUREx lump, in bytes: Header: 4 + (4 * numtextures) Textures: 22 * numtextures (normal format) 14 * numtextures (nameless format) 18 * numtextures (Strife 1.1 format) Patches: 10 * sum of patchcounts (normal and nameless formats) 6 * sum of patchcounts (Strife 1.1 format) */ size_t numpatchrefs = 0; size_t numtextures = textures.size(); for (size_t i = 0; i < numtextures; ++i) { numpatchrefs += textures[i]->nPatches(); } wxLogMessage("%i patch references in %i textures", numpatchrefs, numtextures); size_t datasize = 0; size_t headersize = 4 + (4 * numtextures); switch (txformat) { case TXF_NORMAL: datasize = 4 + (26 * numtextures) + (10 * numpatchrefs); break; case TXF_NAMELESS: datasize = 4 + (18 * numtextures) + (10 * numpatchrefs); break; case TXF_STRIFE11: datasize = 4 + (22 * numtextures) + ( 6 * numpatchrefs); break; // Some compilers insist on having default cases. default: return false; } MemChunk txdata(datasize); int32_t* offsets = new int32_t[numtextures]; int32_t foo = wxINT32_SWAP_ON_BE((signed) numtextures); // Write header txdata.seek(0, SEEK_SET); SAFEFUNC(txdata.write(&foo, 4)); // Go to beginning of texture definitions SAFEFUNC(txdata.seek(4 + (numtextures*4), SEEK_SET)); // Write texture entries for (size_t i = 0; i < numtextures; ++i) { // Get texture to write CTexture* tex = textures[i]; // Set offset offsets[i] = (signed)txdata.currentPos(); // Write texture entry switch (txformat) { case TXF_NORMAL: { // Create 'normal' doom format texture definition ftdef_t txdef; memset(txdef.name, 0, 8); // Set texture name to all 0's (to ensure compatibility with XWE) strncpy(txdef.name, CHR(tex->getName().Upper()), tex->getName().Len()); txdef.flags = 0; txdef.scale[0] = (tex->getScaleX()*8); txdef.scale[1] = (tex->getScaleY()*8); txdef.width = tex->getWidth(); txdef.height = tex->getHeight(); txdef.columndir[0] = 0; txdef.columndir[1] = 0; txdef.patchcount = tex->nPatches(); // Check for WorldPanning flag if (tex->world_panning) txdef.flags |= TX_WORLDPANNING; // Write texture definition SAFEFUNC(txdata.write(&txdef, 22)); break; } case TXF_NAMELESS: { // Create nameless texture definition nltdef_t txdef; txdef.flags = 0; txdef.scale[0] = (tex->getScaleX()*8); txdef.scale[1] = (tex->getScaleY()*8); txdef.width = tex->getWidth(); txdef.height = tex->getHeight(); txdef.columndir[0] = 0; txdef.columndir[1] = 0; txdef.patchcount = tex->nPatches(); // Write texture definition SAFEFUNC(txdata.write(&txdef, 8)); break; } case TXF_STRIFE11: { // Create strife format texture definition stdef_t txdef; memset(txdef.name, 0, 8); // Set texture name to all 0's (to ensure compatibility with XWE) strncpy(txdef.name, CHR(tex->getName().Upper()), tex->getName().Len()); txdef.flags = 0; txdef.scale[0] = (tex->getScaleX()*8); txdef.scale[1] = (tex->getScaleY()*8); txdef.width = tex->getWidth(); txdef.height = tex->getHeight(); txdef.patchcount = tex->nPatches(); // Check for WorldPanning flag if (tex->world_panning) txdef.flags |= TX_WORLDPANNING; // Write texture definition SAFEFUNC(txdata.write(&txdef, 18)); break; } default: return false; } // Write patch references for (size_t k = 0; k < tex->nPatches(); ++k) { // Get patch to write CTPatch* patch = tex->getPatch(k); // Create patch definition tx_patch_t pdef; pdef.left = patch->xOffset(); pdef.top = patch->yOffset(); // Check for 'invalid' patch if (patch->getName().StartsWith("INVPATCH")) { // Get raw patch index from name string number = patch->getName(); number.Replace("INVPATCH", ""); long index; number.ToLong(&index); pdef.patch = index; } else pdef.patch = patch_table.patchIndex(patch->getName()); // Note this will be -1 if the patch doesn't exist in the patch table. This should never happen with the texture editor, though. // Write common data SAFEFUNC(txdata.write(&pdef, 6)); // In non-Strife formats, there's some added rubbish if (txformat != TXF_STRIFE11) { foo = 0; SAFEFUNC(txdata.write(&foo, 4)); } } } // Write offsets SAFEFUNC(txdata.seek(4, SEEK_SET)); SAFEFUNC(txdata.write(offsets, 4*numtextures)); // Write data to the TEXTUREx entry texturex->importMemChunk(txdata); // Update entry type EntryType::detectEntryType(texturex); // Clean up delete[] offsets; 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; }