void CInArchive::ReadHashDigests(int numItems, CRecordVector<bool> &digestsDefined, CRecordVector<UInt32> &digests) { ReadBoolVector2(numItems, digestsDefined); digests.Clear(); digests.Reserve(numItems); for (int i = 0; i < numItems; i++) { UInt32 crc = 0; if (digestsDefined[i]) crc = ReadUInt32(); digests.Add(crc); } }
bool AtomSTTS::ReadData() { uint32_t entryCount; if (!ReadUInt32(entryCount)) { FATAL("Unable to read entry count"); return false; } for (uint32_t i = 0; i < entryCount; i++) { STTSEntry entry; if (!ReadUInt32(entry.count)) { FATAL("Unable to read count"); return false; } if (!ReadUInt32(entry.delta)) { FATAL("Unable to read delta"); return false; } ADD_VECTOR_END(_sttsEntries, entry); } return true; }
///////////////////////////////////////////////////////// // Parse the entries in IFD0. (Section 4.6.2) ///////////////////////////////////////////////////////// bool EXIFParser::ParseIFD0(Orientation& aOrientationOut) { uint16_t entryCount; if (!ReadUInt16(entryCount)) { return false; } for (uint16_t entry = 0 ; entry < entryCount ; ++entry) { // Read the fields of the entry. uint16_t tag; if (!ReadUInt16(tag)) { return false; } // Right now, we only care about orientation, so we immediately skip to the // next entry if we find anything else. if (tag != OrientationTag) { Advance(10); continue; } uint16_t type; if (!ReadUInt16(type)) { return false; } uint32_t count; if (!ReadUInt32(count)) { return false; } // We should have an orientation value here; go ahead and parse it. if (!ParseOrientation(type, count, aOrientationOut)) { return false; } // Since the orientation is all we care about, we're done. return true; } // We didn't find an orientation field in the IFD. That's OK; we assume the // default orientation in that case. aOrientationOut = Orientation(); return true; }
wxString CFileDataIO::ReadString(bool bOptUTF8, uint8 SizeLen, bool SafeRead) const { uint32 readLen; switch (SizeLen) { case sizeof(uint16): readLen = ReadUInt16(); break; case sizeof(uint32): readLen = ReadUInt32(); break; default: MULE_VALIDATE_PARAMS(false, wxT("Invalid SizeLen value in ReadString")); } if (SafeRead) { readLen = std::min<uint64>(readLen, GetLength() - GetPosition()); } return ReadOnlyString(bOptUTF8, readLen); }
bool CInArchive::ReadMarkerAndArchiveHeader(const UInt64 *searchHeaderSizeLimit) { if (!FindAndReadMarker(searchHeaderSizeLimit)) return false; Byte buf[NHeader::NArchive::kArchiveHeaderSize]; UInt32 processedSize; ReadBytes(buf, sizeof(buf), &processedSize); if (processedSize != sizeof(buf)) return false; m_CurData = buf; m_CurPos = 0; m_PosLimit = sizeof(buf); m_ArchiveHeader.CRC = ReadUInt16(); m_ArchiveHeader.Type = ReadByte(); m_ArchiveHeader.Flags = ReadUInt16(); m_ArchiveHeader.Size = ReadUInt16(); m_ArchiveHeader.Reserved1 = ReadUInt16(); m_ArchiveHeader.Reserved2 = ReadUInt32(); m_ArchiveHeader.EncryptVersion = 0; UInt32 crc = CRC_INIT_VAL; crc = CRC_UPDATE_BYTE(crc, m_ArchiveHeader.Type); crc = CrcUpdateUInt16(crc, m_ArchiveHeader.Flags); crc = CrcUpdateUInt16(crc, m_ArchiveHeader.Size); crc = CrcUpdateUInt16(crc, m_ArchiveHeader.Reserved1); crc = CrcUpdateUInt32(crc, m_ArchiveHeader.Reserved2); if (m_ArchiveHeader.IsThereEncryptVer() && m_ArchiveHeader.Size > NHeader::NArchive::kArchiveHeaderSize) { ReadBytes(&m_ArchiveHeader.EncryptVersion, 1, &processedSize); if (processedSize != 1) return false; crc = CRC_UPDATE_BYTE(crc, m_ArchiveHeader.EncryptVersion); } if(m_ArchiveHeader.CRC != (CRC_GET_DIGEST(crc) & 0xFFFF)) ThrowExceptionWithCode(CInArchiveException::kArchiveHeaderCRCError); if (m_ArchiveHeader.Type != NHeader::NBlockType::kArchiveHeader) return false; m_ArchiveCommentPosition = m_Position; m_SeekOnArchiveComment = true; return true; }
HRESULT CInArchive::TryReadCd(CObjectVector<CItemEx> &items, UInt64 cdOffset, UInt64 cdSize, CProgressVirt *progress) { items.Clear(); RINOK(Stream->Seek(cdOffset, STREAM_SEEK_SET, &m_Position)); if (m_Position != cdOffset) return S_FALSE; _inBuffer.Init(); _inBufMode = true; while (m_Position - cdOffset < cdSize) { if (ReadUInt32() != NSignature::kCentralFileHeader) return S_FALSE; CItemEx cdItem; RINOK(ReadCdItem(cdItem)); items.Add(cdItem); if (progress && items.Size() % 1 == 0) RINOK(progress->SetCompletedCD(items.Size())); } return (m_Position - cdOffset == cdSize) ? S_OK : S_FALSE; }
MR_UInt32 ClassicObjStream::ReadStringLength() { MR_UInt8 b; ReadUInt8(b); if (b < 0xff) return b; MR_UInt16 w; ReadUInt16(w); if (w == 0xfffe) { // Unicode (length follows). ASSERT(FALSE); throw std::exception(); } else if (w == 0xffff) { MR_UInt32 dw; ReadUInt32(dw); return dw; } else { return w; } }
///////////////////////////////////////////////////////// // Parse the TIFF header. (Section 4.5.2, Table 1) ///////////////////////////////////////////////////////// bool EXIFParser::ParseTIFFHeader(uint32_t& aIFD0OffsetOut) { // Determine byte order. if (MatchString("MM\0*", 4)) mByteOrder = ByteOrder::BigEndian; else if (MatchString("II*\0", 4)) mByteOrder = ByteOrder::LittleEndian; else return false; // Determine offset of the 0th IFD. (It shouldn't be greater than 64k, which // is the maximum size of the entry APP1 segment.) uint32_t ifd0Offset; if (!ReadUInt32(ifd0Offset) || ifd0Offset > 64 * 1024) return false; // The IFD offset is relative to the beginning of the TIFF header, which // begins after the EXIF header, so we need to increase the offset // appropriately. aIFD0OffsetOut = ifd0Offset + EXIFHeaderLength; return true; }
HRESULT CInArchive::ReadLocalItemAfterCdItem(CItemEx &item) { if (item.FromLocal) return S_OK; try { UInt64 offset = ArcInfo.Base + item.LocalHeaderPos; if (ArcInfo.Base < 0 && (Int64)offset < 0) return S_FALSE; RINOK(Seek(offset)); CItemEx localItem; if (ReadUInt32() != NSignature::kLocalFileHeader) return S_FALSE; ReadLocalItem(localItem); if (!AreItemsEqual(localItem, item)) return S_FALSE; item.LocalFullHeaderSize = localItem.LocalFullHeaderSize; item.LocalExtra = localItem.LocalExtra; item.FromLocal = true; } catch(...) { return S_FALSE; } return S_OK; }
HRESULT CInArchive::ReadLocals( CObjectVector<CItemEx> &items, CProgressVirt *progress) { items.Clear(); while (m_Signature == NSignature::kLocalFileHeader) { CItemEx item; item.LocalHeaderPos = m_Position - 4 - ArcInfo.MarkerPos; // we write ralative LocalHeaderPos here. Later we can correct it to real Base. try { ReadLocalItem(item); item.FromLocal = true; if (item.HasDescriptor()) ReadLocalItemDescriptor(item); else { RINOK(IncreaseRealPosition(item.PackSize)); } items.Add(item); m_Signature = ReadUInt32(); } catch (CUnexpectEnd &) { if (items.IsEmpty() || items.Size() == 1 && IsStrangeItem(items[0])) return S_FALSE; throw; } if (progress && items.Size() % 1 == 0) RINOK(progress->SetCompletedLocal(items.Size(), item.LocalHeaderPos)); } if (items.Size() == 1 && m_Signature != NSignature::kCentralFileHeader) if (IsStrangeItem(items[0])) return S_FALSE; return S_OK; }
HRESULT CInArchive::ReadHeader( DECL_EXTERNAL_CODECS_LOC_VARS CArchiveDatabaseEx &db #ifndef _NO_CRYPTO , ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined #endif ) { UInt64 type = ReadID(); if (type == NID::kArchiveProperties) { ReadArchiveProperties(db.ArchiveInfo); type = ReadID(); } CObjectVector<CByteBuffer> dataVector; if (type == NID::kAdditionalStreamsInfo) { HRESULT result = ReadAndDecodePackedStreams( EXTERNAL_CODECS_LOC_VARS db.ArchiveInfo.StartPositionAfterHeader, db.ArchiveInfo.DataStartPosition2, dataVector #ifndef _NO_CRYPTO , getTextPassword, passwordIsDefined #endif ); RINOK(result); db.ArchiveInfo.DataStartPosition2 += db.ArchiveInfo.StartPositionAfterHeader; type = ReadID(); } CRecordVector<UInt64> unpackSizes; CBoolVector digestsDefined; CRecordVector<UInt32> digests; if (type == NID::kMainStreamsInfo) { ReadStreamsInfo(&dataVector, db.ArchiveInfo.DataStartPosition, db.PackSizes, db.PackCRCsDefined, db.PackCRCs, db.Folders, db.NumUnpackStreamsVector, unpackSizes, digestsDefined, digests); db.ArchiveInfo.DataStartPosition += db.ArchiveInfo.StartPositionAfterHeader; type = ReadID(); } else { for (int i = 0; i < db.Folders.Size(); i++) { db.NumUnpackStreamsVector.Add(1); CFolder &folder = db.Folders[i]; unpackSizes.Add(folder.GetUnpackSize()); digestsDefined.Add(folder.UnpackCRCDefined); digests.Add(folder.UnpackCRC); } } db.Files.Clear(); if (type == NID::kEnd) return S_OK; if (type != NID::kFilesInfo) ThrowIncorrect(); CNum numFiles = ReadNum(); db.Files.Reserve(numFiles); CNum i; for (i = 0; i < numFiles; i++) db.Files.Add(CFileItem()); db.ArchiveInfo.FileInfoPopIDs.Add(NID::kSize); if (!db.PackSizes.IsEmpty()) db.ArchiveInfo.FileInfoPopIDs.Add(NID::kPackInfo); if (numFiles > 0 && !digests.IsEmpty()) db.ArchiveInfo.FileInfoPopIDs.Add(NID::kCRC); CBoolVector emptyStreamVector; BoolVector_Fill_False(emptyStreamVector, (int)numFiles); CBoolVector emptyFileVector; CBoolVector antiFileVector; CNum numEmptyStreams = 0; for (;;) { UInt64 type = ReadID(); if (type == NID::kEnd) break; UInt64 size = ReadNumber(); size_t ppp = _inByteBack->_pos; bool addPropIdToList = true; bool isKnownType = true; if (type > ((UInt32)1 << 30)) isKnownType = false; else switch((UInt32)type) { case NID::kName: { CStreamSwitch streamSwitch; streamSwitch.Set(this, &dataVector); for (int i = 0; i < db.Files.Size(); i++) _inByteBack->ReadString(db.Files[i].Name); break; } case NID::kWinAttributes: { CBoolVector boolVector; ReadBoolVector2(db.Files.Size(), boolVector); CStreamSwitch streamSwitch; streamSwitch.Set(this, &dataVector); for (i = 0; i < numFiles; i++) { CFileItem &file = db.Files[i]; file.AttribDefined = boolVector[i]; if (file.AttribDefined) file.Attrib = ReadUInt32(); } break; } case NID::kEmptyStream: { ReadBoolVector(numFiles, emptyStreamVector); for (i = 0; i < (CNum)emptyStreamVector.Size(); i++) if (emptyStreamVector[i]) numEmptyStreams++; BoolVector_Fill_False(emptyFileVector, numEmptyStreams); BoolVector_Fill_False(antiFileVector, numEmptyStreams); break; } case NID::kEmptyFile: ReadBoolVector(numEmptyStreams, emptyFileVector); break; case NID::kAnti: ReadBoolVector(numEmptyStreams, antiFileVector); break; case NID::kStartPos: ReadUInt64DefVector(dataVector, db.StartPos, (int)numFiles); break; case NID::kCTime: ReadUInt64DefVector(dataVector, db.CTime, (int)numFiles); break; case NID::kATime: ReadUInt64DefVector(dataVector, db.ATime, (int)numFiles); break; case NID::kMTime: ReadUInt64DefVector(dataVector, db.MTime, (int)numFiles); break; case NID::kDummy: { for (UInt64 j = 0; j < size; j++) if (ReadByte() != 0) ThrowIncorrect(); addPropIdToList = false; break; } default: addPropIdToList = isKnownType = false; } if (isKnownType) { if(addPropIdToList) db.ArchiveInfo.FileInfoPopIDs.Add(type); } else SkipData(size); bool checkRecordsSize = (db.ArchiveInfo.Version.Major > 0 || db.ArchiveInfo.Version.Minor > 2); if (checkRecordsSize && _inByteBack->_pos - ppp != size) ThrowIncorrect(); } CNum emptyFileIndex = 0; CNum sizeIndex = 0; CNum numAntiItems = 0; for (i = 0; i < numEmptyStreams; i++) if (antiFileVector[i]) numAntiItems++; for (i = 0; i < numFiles; i++) { CFileItem &file = db.Files[i]; bool isAnti; file.HasStream = !emptyStreamVector[i]; if (file.HasStream) { file.IsDir = false; isAnti = false; file.Size = unpackSizes[sizeIndex]; file.Crc = digests[sizeIndex]; file.CrcDefined = digestsDefined[sizeIndex]; sizeIndex++; } else { file.IsDir = !emptyFileVector[emptyFileIndex]; isAnti = antiFileVector[emptyFileIndex]; emptyFileIndex++; file.Size = 0; file.CrcDefined = false; } if (numAntiItems != 0) db.IsAnti.Add(isAnti); } return S_OK; }
bool AtomDATA::Read() { //1. Read the type if (!ReadUInt32(_type)) { FATAL("Unable to read type"); return false; } //2. Read unknown 4 bytes if (!ReadUInt32(_unknown)) { FATAL("Unable to read type"); return false; } switch (_type) { case 1: { //Single string if (!ReadString(_dataString, GetSize() - 8 - 8)) { FATAL("Unable to read string"); return false; } return true; } case 0: { //many uint16_t uint64_t count = (GetSize() - 8 - 8) / 2; for (uint64_t i = 0; i < count; i++) { uint16_t val; if (!ReadUInt16(val)) { FATAL("Unable to read value"); return false; } ADD_VECTOR_END(_dataUI16, val); } return true; } case 21: { //many uint8_t uint64_t count = GetSize() - 8 - 8; for (uint64_t i = 0; i < count; i++) { uint8_t val; if (!ReadUInt8(val)) { FATAL("Unable to read value"); return false; } ADD_VECTOR_END(_dataUI8, val); } return true; } case 14: case 15: { if (!ReadString(_dataImg, GetSize() - 8 - 8)) { FATAL("Unable to read data"); return false; } return true; } default: { FATAL("Type %u not yet implemented", _type); return false; } } }
HRESULT CInArchive::OpenHelp2(IInStream *inStream, CDatabase &database) { if (ReadUInt32() != 1) // version return S_FALSE; if (ReadUInt32() != 0x28) // Location of header section table return S_FALSE; UInt32 numHeaderSections = ReadUInt32(); const unsigned kNumHeaderSectionsMax = 5; if (numHeaderSections != kNumHeaderSectionsMax) return S_FALSE; IsArc = true; ReadUInt32(); // Len of post-header table Byte g[16]; ReadGUID(g); // {0A9007C1-4076-11D3-8789-0000F8105754} // header section table UInt64 sectionOffsets[kNumHeaderSectionsMax]; UInt64 sectionSizes[kNumHeaderSectionsMax]; UInt32 i; for (i = 0; i < numHeaderSections; i++) { sectionOffsets[i] = ReadUInt64(); sectionSizes[i] = ReadUInt64(); UInt64 end = sectionOffsets[i] + sectionSizes[i]; database.UpdatePhySize(end); } // Post-Header ReadUInt32(); // 2 ReadUInt32(); // 0x98: offset to CAOL from beginning of post-header) // ----- Directory information ReadUInt64(); // Chunk number of top-level AOLI chunk in directory, or -1 ReadUInt64(); // Chunk number of first AOLL chunk in directory ReadUInt64(); // Chunk number of last AOLL chunk in directory ReadUInt64(); // 0 (unknown) ReadUInt32(); // $2000 (Directory chunk size of directory) ReadUInt32(); // Quickref density for main directory, usually 2 ReadUInt32(); // 0 (unknown) ReadUInt32(); // Depth of main directory index tree // 1 there is no index, 2 if there is one level of AOLI chunks. ReadUInt64(); // 0 (unknown) UInt64 numDirEntries = ReadUInt64(); // Number of directory entries // ----- Directory Index Information ReadUInt64(); // -1 (unknown, probably chunk number of top-level AOLI in directory index) ReadUInt64(); // Chunk number of first AOLL chunk in directory index ReadUInt64(); // Chunk number of last AOLL chunk in directory index ReadUInt64(); // 0 (unknown) ReadUInt32(); // $200 (Directory chunk size of directory index) ReadUInt32(); // Quickref density for directory index, usually 2 ReadUInt32(); // 0 (unknown) ReadUInt32(); // Depth of directory index index tree. ReadUInt64(); // Possibly flags -- sometimes 1, sometimes 0. ReadUInt64(); // Number of directory index entries (same as number of AOLL // chunks in main directory) // (The obvious guess for the following two fields, which recur in a number // of places, is they are maximum sizes for the directory and directory index. // However, I have seen no direct evidence that this is the case.) ReadUInt32(); // $100000 (Same as field following chunk size in directory) ReadUInt32(); // $20000 (Same as field following chunk size in directory index) ReadUInt64(); // 0 (unknown) if (ReadUInt32() != kSignature_CAOL) return S_FALSE; if (ReadUInt32() != 2) // (Most likely a version number) return S_FALSE; UInt32 caolLength = ReadUInt32(); // $50 (Len of the CAOL section, which includes the ITSF section) if (caolLength >= 0x2C) { /* UInt32 c7 = */ ReadUInt16(); // Unknown. Remains the same when identical files are built. // Does not appear to be a checksum. Many files have // 'HH' (HTML Help?) here, indicating this may be a compiler ID // field. But at least one ITOL/ITLS compiler does not set this // field to a constant value. ReadUInt16(); // 0 (Unknown. Possibly part of 00A4 field) ReadUInt32(); // Unknown. Two values have been seen -- $43ED, and 0. ReadUInt32(); // $2000 (Directory chunk size of directory) ReadUInt32(); // $200 (Directory chunk size of directory index) ReadUInt32(); // $100000 (Same as field following chunk size in directory) ReadUInt32(); // $20000 (Same as field following chunk size in directory index) ReadUInt32(); // 0 (unknown) ReadUInt32(); // 0 (Unknown) if (caolLength == 0x2C) { // fprintf(stdout, "\n !!!NewFormat\n"); // fflush(stdout); database.ContentOffset = 0; // maybe we must add database.StartPosition here? database.NewFormat = true; } else if (caolLength == 0x50) { ReadUInt32(); // 0 (Unknown) if (ReadUInt32() != kSignature_ITSF) return S_FALSE; if (ReadUInt32() != 4) // $4 (Version number -- CHM uses 3) return S_FALSE; if (ReadUInt32() != 0x20) // $20 (length of ITSF) return S_FALSE; UInt32 unknown = ReadUInt32(); if (unknown != 0 && unknown != 1) // = 0 for some HxW files, 1 in other cases; return S_FALSE; database.ContentOffset = database.StartPosition + ReadUInt64(); /* UInt32 timeStamp = */ ReadUInt32(); // A timestamp of some sort. // Considered as a big-endian DWORD, it appears to contain // seconds (MSB) and fractional seconds (second byte). // The third and fourth bytes may contain even more fractional // bits. The 4 least significant bits in the last byte are constant. /* UInt32 lang = */ ReadUInt32(); // BE? } else return S_FALSE; } // Section 0 ReadChunk(inStream, database.StartPosition + sectionOffsets[0], sectionSizes[0]); if (sectionSizes[0] < 0x18) return S_FALSE; if (ReadUInt32() != 0x01FE) return S_FALSE; ReadUInt32(); // unknown: 0 UInt64 fileSize = ReadUInt64(); database.UpdatePhySize(fileSize); ReadUInt32(); // unknown: 0 ReadUInt32(); // unknown: 0 // Section 1: The Directory Listing ReadChunk(inStream, database.StartPosition + sectionOffsets[1], sectionSizes[1]); if (ReadUInt32() != kSignature_IFCM) return S_FALSE; if (ReadUInt32() != 1) // (probably a version number) return S_FALSE; UInt32 dirChunkSize = ReadUInt32(); // $2000 if (dirChunkSize < 64) return S_FALSE; ReadUInt32(); // $100000 (unknown) ReadUInt32(); // -1 (unknown) ReadUInt32(); // -1 (unknown) UInt32 numDirChunks = ReadUInt32(); ReadUInt32(); // 0 (unknown, probably high word of above) for (UInt32 ci = 0; ci < numDirChunks; ci++) { UInt64 chunkPos = _inBuffer.GetProcessedSize(); if (ReadUInt32() == kSignature_AOLL) { UInt32 quickrefLength = ReadUInt32(); // Len of quickref area at end of directory chunk if (quickrefLength > dirChunkSize || quickrefLength < 2) return S_FALSE; ReadUInt64(); // Directory chunk number // This must match physical position in file, that is // the chunk size times the chunk number must be the // offset from the end of the directory header. ReadUInt64(); // Chunk number of previous listing chunk when reading // directory in sequence (-1 if first listing chunk) ReadUInt64(); // Chunk number of next listing chunk when reading // directory in sequence (-1 if last listing chunk) ReadUInt64(); // Number of first listing entry in this chunk ReadUInt32(); // 1 (unknown -- other values have also been seen here) ReadUInt32(); // 0 (unknown) unsigned numItems = 0; for (;;) { UInt64 offset = _inBuffer.GetProcessedSize() - chunkPos; UInt32 offsetLimit = dirChunkSize - quickrefLength; if (offset > offsetLimit) return S_FALSE; if (offset == offsetLimit) break; if (database.NewFormat) { UInt16 nameLen = ReadUInt16(); if (nameLen == 0) return S_FALSE; UString name; ReadUString((unsigned)nameLen, name); AString s; ConvertUnicodeToUTF8(name, s); Byte b = ReadByte(); s.Add_Space(); PrintByte(b, s); s.Add_Space(); UInt64 len = ReadEncInt(); // then number of items ? // then length ? // then some data (binary encoding?) while (len-- != 0) { b = ReadByte(); PrintByte(b, s); } database.NewFormatString += s; database.NewFormatString += "\r\n"; } else { RINOK(ReadDirEntry(database)); } numItems++; } Skip(quickrefLength - 2); if (ReadUInt16() != numItems) return S_FALSE; if (numItems > numDirEntries) return S_FALSE; numDirEntries -= numItems; } else Skip(dirChunkSize - 4); } return numDirEntries == 0 ? S_OK : S_FALSE; }
HRESULT CInArchive::OpenChm(IInStream *inStream, CDatabase &database) { UInt32 headerSize = ReadUInt32(); if (headerSize != 0x60) return S_FALSE; database.PhySize = headerSize; UInt32 unknown1 = ReadUInt32(); if (unknown1 != 0 && unknown1 != 1) // it's 0 in one .sll file return S_FALSE; IsArc = true; /* UInt32 timeStamp = */ ReadUInt32(); // Considered as a big-endian DWORD, it appears to contain seconds (MSB) and // fractional seconds (second byte). // The third and fourth bytes may contain even more fractional bits. // The 4 least significant bits in the last byte are constant. /* UInt32 lang = */ ReadUInt32(); Byte g[16]; ReadGUID(g); // {7C01FD10-7BAA-11D0-9E0C-00A0-C922-E6EC} ReadGUID(g); // {7C01FD11-7BAA-11D0-9E0C-00A0-C922-E6EC} const unsigned kNumSections = 2; UInt64 sectionOffsets[kNumSections]; UInt64 sectionSizes[kNumSections]; unsigned i; for (i = 0; i < kNumSections; i++) { sectionOffsets[i] = ReadUInt64(); sectionSizes[i] = ReadUInt64(); UInt64 end = sectionOffsets[i] + sectionSizes[i]; database.UpdatePhySize(end); } // if (chmVersion == 3) database.ContentOffset = ReadUInt64(); /* else database.ContentOffset = database.StartPosition + 0x58 */ // Section 0 ReadChunk(inStream, sectionOffsets[0], sectionSizes[0]); if (sectionSizes[0] < 0x18) return S_FALSE; if (ReadUInt32() != 0x01FE) return S_FALSE; ReadUInt32(); // unknown: 0 UInt64 fileSize = ReadUInt64(); database.UpdatePhySize(fileSize); ReadUInt32(); // unknown: 0 ReadUInt32(); // unknown: 0 // Section 1: The Directory Listing ReadChunk(inStream, sectionOffsets[1], sectionSizes[1]); if (ReadUInt32() != kSignature_ITSP) return S_FALSE; if (ReadUInt32() != 1) // version return S_FALSE; /* UInt32 dirHeaderSize = */ ReadUInt32(); ReadUInt32(); // 0x0A (unknown) UInt32 dirChunkSize = ReadUInt32(); // $1000 if (dirChunkSize < 32) return S_FALSE; /* UInt32 density = */ ReadUInt32(); // "Density" of quickref section, usually 2. /* UInt32 depth = */ ReadUInt32(); // Depth of the index tree: 1 there is no index, // 2 if there is one level of PMGI chunks. /* UInt32 chunkNumber = */ ReadUInt32(); // Chunk number of root index chunk, -1 if there is none // (though at least one file has 0 despite there being no // index chunk, probably a bug.) /* UInt32 firstPmglChunkNumber = */ ReadUInt32(); // Chunk number of first PMGL (listing) chunk /* UInt32 lastPmglChunkNumber = */ ReadUInt32(); // Chunk number of last PMGL (listing) chunk ReadUInt32(); // -1 (unknown) UInt32 numDirChunks = ReadUInt32(); // Number of directory chunks (total) /* UInt32 windowsLangId = */ ReadUInt32(); ReadGUID(g); // {5D02926A-212E-11D0-9DF9-00A0C922E6EC} ReadUInt32(); // 0x54 (This is the length again) ReadUInt32(); // -1 (unknown) ReadUInt32(); // -1 (unknown) ReadUInt32(); // -1 (unknown) for (UInt32 ci = 0; ci < numDirChunks; ci++) { UInt64 chunkPos = _inBuffer.GetProcessedSize(); if (ReadUInt32() == kSignature_PMGL) { // The quickref area is written backwards from the end of the chunk. // One quickref entry exists for every n entries in the file, where n // is calculated as 1 + (1 << quickref density). So for density = 2, n = 5. UInt32 quickrefLength = ReadUInt32(); // Len of free space and/or quickref area at end of directory chunk if (quickrefLength > dirChunkSize || quickrefLength < 2) return S_FALSE; ReadUInt32(); // Always 0 ReadUInt32(); // Chunk number of previous listing chunk when reading // directory in sequence (-1 if this is the first listing chunk) ReadUInt32(); // Chunk number of next listing chunk when reading // directory in sequence (-1 if this is the last listing chunk) unsigned numItems = 0; for (;;) { UInt64 offset = _inBuffer.GetProcessedSize() - chunkPos; UInt32 offsetLimit = dirChunkSize - quickrefLength; if (offset > offsetLimit) return S_FALSE; if (offset == offsetLimit) break; RINOK(ReadDirEntry(database)); numItems++; } Skip(quickrefLength - 2); unsigned rrr = ReadUInt16(); if (rrr != numItems) { // Lazarus 9-26-2 chm contains 0 here. if (rrr != 0) return S_FALSE; } } else Skip(dirChunkSize - 4); } return S_OK; }
bool AtomMP4A::ReadData() { //qtff.pdf: General StructureofaSampleDescription (76/304) //TODO: there seems to be 2 kinds of DISTINCT mp4a atoms. If the size // of the atom is 0x0c (size+'mp4a'+4 zeros) we should ignore it for now... if (_size == 0x0c) { WARN("Another strange mp4a atom...."); return true; } //1. Skip reserved 6 bytes. Actually, slip the next 2, because the prev 4 //are already skipped by the versioned atom if (!SkipBytes(2)) { FATAL("Unable to skip 2 bytes"); return false; } if (!ReadUInt16(_dataReferenceIndex)) { FATAL("Unable to read count"); return false; } if (!ReadUInt16(_innerVersion)) { FATAL("Unable to read count"); return false; } if (!ReadUInt16(_revisionLevel)) { FATAL("Unable to read count"); return false; } if (!ReadUInt32(_vendor)) { FATAL("Unable to read count"); return false; } if (!ReadUInt16(_numberOfChannels)) { FATAL("Unable to read count"); return false; } if (!ReadUInt16(_sampleSizeInBits)) { FATAL("Unable to read count"); return false; } if (!ReadInt16(_compressionId)) { FATAL("Unable to read count"); return false; } if (!ReadUInt16(_packetSize)) { FATAL("Unable to read count"); return false; } if (!ReadUInt32(_sampleRate)) { FATAL("Unable to read count"); return false; } if (_innerVersion == 0) { return true; } if (!ReadUInt32(_samplesPerPacket)) { FATAL("Unable to read count"); return false; } if (!ReadUInt32(_bytesPerPacket)) { FATAL("Unable to read count"); return false; } if (!ReadUInt32(_bytesPerFrame)) { FATAL("Unable to read count"); return false; } if (!ReadUInt32(_bytesPerSample)) { FATAL("Unable to read count"); return false; } return true; }
CTag *CFileDataIO::ReadTag(bool bOptACP) const { CTag *retVal = NULL; wxString name; byte type = 0; try { type = ReadUInt8(); name = ReadString(false); switch (type) { // NOTE: This tag data type is accepted and stored only to give us the possibility to upgrade // the net in some months. // // And still.. it doesnt't work this way without breaking backward compatibility. To properly // do this without messing up the network the following would have to be done: // - those tag types have to be ignored by any client, otherwise those tags would also be sent (and // that's really the problem) // // - ignoring means, each client has to read and right throw away those tags, so those tags get // get never stored in any tag list which might be sent by that client to some other client. // // - all calling functions have to be changed to deal with the 'nr. of tags' attribute (which was // already parsed) correctly.. just ignoring those tags here is not enough, any taglists have to // be built with the knowledge that the 'nr. of tags' attribute may get decreased during the tag // reading.. // // If those new tags would just be stored and sent to remote clients, any malicious or just bugged // client could let send a lot of nodes "corrupted" packets... // case TAGTYPE_HASH16: { retVal = new CTagHash(name, ReadHash()); break; } case TAGTYPE_STRING: retVal = new CTagString(name, ReadString(bOptACP)); break; case TAGTYPE_UINT64: retVal = new CTagInt64(name, ReadUInt64()); break; case TAGTYPE_UINT32: retVal = new CTagInt32(name, ReadUInt32()); break; case TAGTYPE_UINT16: retVal = new CTagInt16(name, ReadUInt16()); break; case TAGTYPE_UINT8: retVal = new CTagInt8(name, ReadUInt8()); break; case TAGTYPE_FLOAT32: retVal = new CTagFloat(name, ReadFloat()); break; // NOTE: This tag data type is accepted and stored only to give us the possibility to upgrade // the net in some months. // // And still.. it doesnt't work this way without breaking backward compatibility case TAGTYPE_BSOB: { uint8 size = 0; CScopedArray<unsigned char> value(ReadBsob(&size)); retVal = new CTagBsob(name, value.get(), size); break; } default: throw wxString(CFormat(wxT("Invalid Kad tag type; type=0x%02x name=%s\n")) % type % name); } } catch(const CMuleException& e) { AddLogLineN(e.what()); delete retVal; throw; } catch(const wxString& e) { AddLogLineN(e); throw; } return retVal; }
bool CXBTFReader::Open(const std::string& path) { if (path.empty()) return false; m_path = path; #ifdef TARGET_WINDOWS std::wstring strPathW; g_charsetConverter.utf8ToW(CSpecialProtocol::TranslatePath(m_path), strPathW, false); m_file = _wfopen(strPathW.c_str(), L"rb"); #else m_file = fopen(m_path.c_str(), "rb"); #endif if (m_file == nullptr) return false; // read the magic word char magic[4]; if (!ReadString(m_file, magic, sizeof(magic))) return false; if (strncmp(XBTF_MAGIC.c_str(), magic, sizeof(magic)) != 0) return false; // read the version char version[1]; if (!ReadString(m_file, version, sizeof(version))) return false; if (strncmp(XBTF_VERSION.c_str(), version, sizeof(version)) != 0) return false; unsigned int nofFiles; if (!ReadUInt32(m_file, nofFiles)) return false; for (uint32_t i = 0; i < nofFiles; i++) { CXBTFFile xbtfFile; uint32_t u32; uint64_t u64; char path[CXBTFFile::MaximumPathLength]; memset(path, 0, sizeof(path)); if (!ReadString(m_file, path, sizeof(path))) return false; xbtfFile.SetPath(path); if (!ReadUInt32(m_file, u32)) return false; xbtfFile.SetLoop(u32); unsigned int nofFrames; if (!ReadUInt32(m_file, nofFrames)) return false; for (uint32_t j = 0; j < nofFrames; j++) { CXBTFFrame frame; if (!ReadUInt32(m_file, u32)) return false; frame.SetWidth(u32); if (!ReadUInt32(m_file, u32)) return false; frame.SetHeight(u32); if (!ReadUInt32(m_file, u32)) return false; frame.SetFormat(u32); if (!ReadUInt64(m_file, u64)) return false; frame.SetPackedSize(u64); if (!ReadUInt64(m_file, u64)) return false; frame.SetUnpackedSize(u64); if (!ReadUInt32(m_file, u32)) return false; frame.SetDuration(u32); if (!ReadUInt64(m_file, u64)) return false; frame.SetOffset(u64); xbtfFile.GetFrames().push_back(frame); } AddFile(xbtfFile); } // Sanity check uint64_t pos = static_cast<uint64_t>(ftell(m_file)); if (pos != GetHeaderSize()) return false; return true; }
float BinaryStream::ReadFloat() { float d; *(uint32_t*)(&d) = ReadUInt32(); return d; }
HRESULT CInArchive::GetNextItem(bool &filled, CItemEx &item) { filled = false; UInt32 processedSize; Byte startHeader[2]; RINOK(ReadBytes(startHeader, 2, processedSize)) if (processedSize == 0) return S_OK; if (processedSize == 1) return (startHeader[0] == 0) ? S_OK: S_FALSE; if (startHeader[0] == 0 && startHeader[1] == 0) return S_OK; Byte header[256]; const UInt32 kBasicPartSize = 22; RINOK(ReadBytes(header, kBasicPartSize, processedSize)); if (processedSize != kBasicPartSize) return (startHeader[0] == 0) ? S_OK: S_FALSE; const Byte *p = header; memmove(item.Method, p, kMethodIdSize); if (!item.IsValidMethod()) return S_OK; p += kMethodIdSize; p = ReadUInt32(p, item.PackSize); p = ReadUInt32(p, item.Size); p = ReadUInt32(p, item.ModifiedTime); item.Attributes = *p++; item.Level = *p++; if (item.Level > 2) return S_FALSE; UInt32 headerSize; if (item.Level < 2) { headerSize = startHeader[0]; if (headerSize < kBasicPartSize) return S_FALSE; UInt32 remain = headerSize - kBasicPartSize; RINOK(CheckReadBytes(header + kBasicPartSize, remain)); if (startHeader[1] != CalcSum(header, headerSize)) return S_FALSE; size_t nameLength = *p++; if ((p - header) + nameLength + 2 > headerSize) return S_FALSE; p = ReadString(p, nameLength, item.Name); } else headerSize = startHeader[0] | ((UInt32)startHeader[1] << 8); p = ReadUInt16(p, item.CRC); if (item.Level != 0) { if (item.Level == 2) { RINOK(CheckReadBytes(header + kBasicPartSize, 2)); } if ((size_t)(p - header) + 3 > headerSize) return S_FALSE; item.OsId = *p++; UInt16 nextSize; p = ReadUInt16(p, nextSize); while (nextSize != 0) { if (nextSize < 3) return S_FALSE; if (item.Level == 1) { if (item.PackSize < nextSize) return S_FALSE; item.PackSize -= nextSize; } CExtension ext; RINOK(CheckReadBytes(&ext.Type, 1)) nextSize -= 3; ext.Data.SetCapacity(nextSize); RINOK(CheckReadBytes((Byte *)ext.Data, nextSize)) item.Extensions.Add(ext); Byte hdr2[2]; RINOK(CheckReadBytes(hdr2, 2)); ReadUInt16(hdr2, nextSize); } } item.DataPosition = m_Position; filled = true; return S_OK; }
bool CInArchive::ReadExtra(unsigned extraSize, CExtraBlock &extraBlock, UInt64 &unpackSize, UInt64 &packSize, UInt64 &localHeaderOffset, UInt32 &diskStartNumber) { extraBlock.Clear(); UInt32 remain = extraSize; while (remain >= 4) { CExtraSubBlock subBlock; subBlock.ID = ReadUInt16(); unsigned dataSize = ReadUInt16(); remain -= 4; if (dataSize > remain) // it's bug { HeadersWarning = true; Skip(remain); return false; } if (subBlock.ID == NFileHeader::NExtraID::kZip64) { if (unpackSize == 0xFFFFFFFF) { if (dataSize < 8) { HeadersWarning = true; Skip(remain); return false; } unpackSize = ReadUInt64(); remain -= 8; dataSize -= 8; } if (packSize == 0xFFFFFFFF) { if (dataSize < 8) break; packSize = ReadUInt64(); remain -= 8; dataSize -= 8; } if (localHeaderOffset == 0xFFFFFFFF) { if (dataSize < 8) break; localHeaderOffset = ReadUInt64(); remain -= 8; dataSize -= 8; } if (diskStartNumber == 0xFFFF) { if (dataSize < 4) break; diskStartNumber = ReadUInt32(); remain -= 4; dataSize -= 4; } Skip(dataSize); } else { ReadBuffer(subBlock.Data, dataSize); extraBlock.SubBlocks.Add(subBlock); } remain -= dataSize; } if (remain != 0) { ExtraMinorError = true; // 7-Zip before 9.31 created incorrect WsAES Extra in folder's local headers. // so we don't return false, but just set warning flag // return false; } Skip(remain); return true; }
HRESULT CInArchive::ReadHeaders2(CObjectVector<CItemEx> &items, CProgressVirt *progress) { items.Clear(); // m_Signature must be kLocalFileHeader or kEcd // m_Position points to next byte after signature RINOK(Stream->Seek(m_Position, STREAM_SEEK_SET, NULL)); if (!_inBuffer.Create(1 << 15)) return E_OUTOFMEMORY; _inBuffer.SetStream(Stream); bool needReadCd = true; bool localsWereRead = false; if (m_Signature == NSignature::kEcd) { // It must be empty archive or backware archive // we don't support backware archive still const unsigned kBufSize = kEcdSize - 4; Byte buf[kBufSize]; SafeReadBytes(buf, kBufSize); CEcd ecd; ecd.Parse(buf); // if (ecd.cdSize != 0) // Do we need also to support the case where empty zip archive with PK00 uses cdOffset = 4 ?? if (!ecd.IsEmptyArc()) return S_FALSE; ArcInfo.Base = ArcInfo.MarkerPos; needReadCd = false; IsArc = true; // check it: we need more tests? RINOK(Stream->Seek(ArcInfo.MarkerPos2 + 4, STREAM_SEEK_SET, &m_Position)); } UInt64 cdSize = 0, cdRelatOffset = 0, cdAbsOffset = 0; HRESULT res = S_OK; if (needReadCd) { CItemEx firstItem; // try { try { if (!ReadLocalItem(firstItem)) return S_FALSE; } catch(CUnexpectEnd &) { return S_FALSE; } IsArc = true; res = ReadCd(items, cdRelatOffset, cdSize, progress); if (res == S_OK) m_Signature = ReadUInt32(); } // catch() { res = S_FALSE; } if (res != S_FALSE && res != S_OK) return res; if (res == S_OK && items.Size() == 0) res = S_FALSE; if (res == S_OK) { // we can't read local items here to keep _inBufMode state firstItem.LocalHeaderPos = ArcInfo.MarkerPos2 - ArcInfo.Base; int index = FindItem(items, firstItem.LocalHeaderPos); if (index == -1) res = S_FALSE; else if (!AreItemsEqual(firstItem, items[index])) res = S_FALSE; ArcInfo.CdWasRead = true; ArcInfo.FirstItemRelatOffset = items[0].LocalHeaderPos; } } CObjectVector<CItemEx> cdItems; bool needSetBase = false; unsigned numCdItems = items.Size(); if (res == S_FALSE) { // CD doesn't match firstItem so we clear items and read Locals. items.Clear(); localsWereRead = true; _inBufMode = false; ArcInfo.Base = ArcInfo.MarkerPos; RINOK(Stream->Seek(ArcInfo.MarkerPos2, STREAM_SEEK_SET, &m_Position)); m_Signature = ReadUInt32(); RINOK(ReadLocals(items, progress)); if (m_Signature != NSignature::kCentralFileHeader) { m_Position -= 4; NoCentralDir = true; HeadersError = true; return S_OK; } _inBufMode = true; _inBuffer.Init(); cdAbsOffset = m_Position - 4; for (;;) { CItemEx cdItem; RINOK(ReadCdItem(cdItem)); cdItems.Add(cdItem); if (progress && cdItems.Size() % 1 == 0) RINOK(progress->SetCompletedCD(items.Size())); m_Signature = ReadUInt32(); if (m_Signature != NSignature::kCentralFileHeader) break; } cdSize = (m_Position - 4) - cdAbsOffset; needSetBase = true; numCdItems = cdItems.Size(); if (!cdItems.IsEmpty()) { ArcInfo.CdWasRead = true; ArcInfo.FirstItemRelatOffset = cdItems[0].LocalHeaderPos; } } CEcd64 ecd64; bool isZip64 = false; UInt64 ecd64AbsOffset = m_Position - 4; if (m_Signature == NSignature::kEcd64) { IsZip64 = isZip64 = true; UInt64 recordSize = ReadUInt64(); const unsigned kBufSize = kEcd64_MainSize; Byte buf[kBufSize]; SafeReadBytes(buf, kBufSize); ecd64.Parse(buf); Skip64(recordSize - kEcd64_MainSize); m_Signature = ReadUInt32(); if (ecd64.thisDiskNumber != 0 || ecd64.startCDDiskNumber != 0) return E_NOTIMPL; if (needSetBase) { ArcInfo.Base = cdAbsOffset - ecd64.cdStartOffset; cdRelatOffset = ecd64.cdStartOffset; needSetBase = false; } if (ecd64.numEntriesInCDOnThisDisk != numCdItems || ecd64.numEntriesInCD != numCdItems || ecd64.cdSize != cdSize || (ecd64.cdStartOffset != cdRelatOffset && (!items.IsEmpty()))) return S_FALSE; } if (m_Signature == NSignature::kEcd64Locator) { if (!isZip64) return S_FALSE; /* UInt32 startEndCDDiskNumber = */ ReadUInt32(); UInt64 ecd64RelatOffset = ReadUInt64(); /* UInt32 numberOfDisks = */ ReadUInt32(); if (ecd64AbsOffset != ArcInfo.Base + ecd64RelatOffset) return S_FALSE; m_Signature = ReadUInt32(); } if (m_Signature != NSignature::kEcd) return S_FALSE; const unsigned kBufSize = kEcdSize - 4; Byte buf[kBufSize]; SafeReadBytes(buf, kBufSize); CEcd ecd; ecd.Parse(buf); COPY_ECD_ITEM_16(thisDiskNumber); COPY_ECD_ITEM_16(startCDDiskNumber); COPY_ECD_ITEM_16(numEntriesInCDOnThisDisk); COPY_ECD_ITEM_16(numEntriesInCD); COPY_ECD_ITEM_32(cdSize); COPY_ECD_ITEM_32(cdStartOffset); if (needSetBase) { ArcInfo.Base = cdAbsOffset - ecd64.cdStartOffset; cdRelatOffset = ecd64.cdStartOffset; needSetBase = false; } if (localsWereRead && (UInt64)ArcInfo.Base != ArcInfo.MarkerPos) { UInt64 delta = ArcInfo.MarkerPos - ArcInfo.Base; for (unsigned i = 0; i < items.Size(); i++) items[i].LocalHeaderPos += delta; } // ---------- merge Central Directory Items ---------- if (!cdItems.IsEmpty()) { for (unsigned i = 0; i < cdItems.Size(); i++) { const CItemEx &cdItem = cdItems[i]; int index = FindItem(items, cdItem.LocalHeaderPos); if (index == -1) { items.Add(cdItem); continue; } CItemEx &item = items[index]; if (item.Name != cdItem.Name // || item.Name.Len() != cdItem.Name.Len() || item.PackSize != cdItem.PackSize || item.Size != cdItem.Size // item.ExtractVersion != cdItem.ExtractVersion || !FlagsAreSame(item, cdItem) || item.Crc != cdItem.Crc) continue; // item.LocalHeaderPos = cdItem.LocalHeaderPos; // item.Name = cdItem.Name; item.MadeByVersion = cdItem.MadeByVersion; item.CentralExtra = cdItem.CentralExtra; item.InternalAttrib = cdItem.InternalAttrib; item.ExternalAttrib = cdItem.ExternalAttrib; item.Comment = cdItem.Comment; item.FromCentral = cdItem.FromCentral; } } if (ecd64.thisDiskNumber != 0 || ecd64.startCDDiskNumber != 0) return E_NOTIMPL; if (isZip64) { if (ecd64.numEntriesInCDOnThisDisk != items.Size()) HeadersError = true; } else { // old 7-zip could store 32-bit number of CD items to 16-bit field. if ((UInt16)ecd64.numEntriesInCDOnThisDisk != (UInt16)numCdItems || (UInt16)ecd64.numEntriesInCDOnThisDisk != (UInt16)items.Size()) HeadersError = true; } ReadBuffer(ArcInfo.Comment, ecd.commentSize); _inBufMode = false; _inBuffer.Free(); if ( (UInt16)ecd64.numEntriesInCD != ((UInt16)numCdItems) || (UInt32)ecd64.cdSize != (UInt32)cdSize || ((UInt32)(ecd64.cdStartOffset) != (UInt32)cdRelatOffset && (!items.IsEmpty()))) return S_FALSE; // printf("\nOpen OK"); return S_OK; }
bool AtomMVHD::ReadData() { if (_version == 1) { if (!ReadUInt64(_creationTime)) { FATAL("Unable to read creation time"); return false; } if (!ReadUInt64(_modificationTime)) { FATAL("Unable to read modification time"); return false; } } else { uint32_t temp; if (!ReadUInt32(temp)) { FATAL("Unable to read creation time"); return false; } _creationTime = temp; if (!ReadUInt32(temp)) { FATAL("Unable to read modification time"); return false; } _modificationTime = temp; } if (!ReadUInt32(_timeScale)) { FATAL("Unable to read time scale"); return false; } if (_version == 1) { if (!ReadUInt64(_duration)) { FATAL("Unable to read duration"); return false; } } else { uint32_t temp; if (!ReadUInt32(temp)) { FATAL("Unable to read duration"); return false; } _duration = temp; } if (!ReadUInt32(_preferredRate)) { FATAL("Unable to read preferred rate"); return false; } if (!ReadUInt16(_preferredVolume)) { FATAL("Unable to read preferred volume"); return false; } if (!ReadArray(_reserved, 10)) { FATAL("Unable to read reserved"); return false; } if (!ReadArray((uint8_t *) _matrixStructure, 36)) { FATAL("Unable to read matrix structure"); return false; } if (!ReadUInt32(_previewTime)) { FATAL("Unable to read preview time"); return false; } if (!ReadUInt32(_previewDuration)) { FATAL("Unable to read preview duration"); return false; } if (!ReadUInt32(_posterTime)) { FATAL("Unable to read poster time"); return false; } if (!ReadUInt32(_selectionTime)) { FATAL("Unable to read selection time"); return false; } if (!ReadUInt32(_selectionDuration)) { FATAL("Unable to read selection duration"); return false; } if (!ReadUInt32(_currentTime)) { FATAL("Unable to read current time"); return false; } if (!ReadUInt32(_nextTrakId)) { FATAL("Unable to read next track ID"); return false; } return true; }
HRESULT CInArchive::Open2(IInStream *stream, const UInt64 *searchHeaderSizeLimit, CDatabase &database) { database.Clear(); RINOK(stream->Seek(0, STREAM_SEEK_SET, &database.StartPosition)); RINOK(FindSignatureInStream(stream, NHeader::kMarker, NHeader::kMarkerSize, searchHeaderSizeLimit, database.StartPosition)); RINOK(stream->Seek(database.StartPosition + NHeader::kMarkerSize, STREAM_SEEK_SET, NULL)); if (!inBuffer.Create(1 << 17)) return E_OUTOFMEMORY; inBuffer.SetStream(stream); inBuffer.Init(); CInArchiveInfo &ai = database.ArchiveInfo; ai.Size = ReadUInt32(); if (ReadUInt32() != 0) return S_FALSE; ai.FileHeadersOffset = ReadUInt32(); if (ReadUInt32() != 0) return S_FALSE; ai.VersionMinor = ReadByte(); ai.VersionMajor = ReadByte(); ai.NumFolders = ReadUInt16(); ai.NumFiles = ReadUInt16(); ai.Flags = ReadUInt16(); if (ai.Flags > 7) return S_FALSE; ai.SetID = ReadUInt16(); ai.CabinetNumber = ReadUInt16(); if (ai.ReserveBlockPresent()) { ai.PerCabinetAreaSize = ReadUInt16(); ai.PerFolderAreaSize = ReadByte(); ai.PerDataBlockAreaSize = ReadByte(); Skip(ai.PerCabinetAreaSize); } { if (ai.IsTherePrev()) ReadOtherArchive(ai.PreviousArchive); if (ai.IsThereNext()) ReadOtherArchive(ai.NextArchive); } int i; for (i = 0; i < ai.NumFolders; i++) { CFolder folder; folder.DataStart = ReadUInt32(); folder.NumDataBlocks = ReadUInt16(); folder.CompressionTypeMajor = ReadByte(); folder.CompressionTypeMinor = ReadByte(); Skip(ai.PerFolderAreaSize); database.Folders.Add(folder); } RINOK(stream->Seek(database.StartPosition + ai.FileHeadersOffset, STREAM_SEEK_SET, NULL)); inBuffer.SetStream(stream); inBuffer.Init(); for (i = 0; i < ai.NumFiles; i++) { CItem item; item.Size = ReadUInt32(); item.Offset = ReadUInt32(); item.FolderIndex = ReadUInt16(); UInt16 pureDate = ReadUInt16(); UInt16 pureTime = ReadUInt16(); item.Time = ((UInt32(pureDate) << 16)) | pureTime; item.Attributes = ReadUInt16(); item.Name = SafeReadName(); int folderIndex = item.GetFolderIndex(database.Folders.Size()); if (folderIndex >= database.Folders.Size()) return S_FALSE; database.Items.Add(item); } return S_OK; }
int32_t BinaryReader::ReadInt32() { return (int32_t)ReadUInt32(); }
float BinaryReader::ReadSingle() { uint32_t value = ReadUInt32(); return *(float*)&value; }
int32_t ReadInt32() { return (int32_t)ReadUInt32(); }
int BinaryFP::ReadInt32() { return (int)ReadUInt32(); }
void FTextureManager::AddTexturesLump (const void *lumpdata, int lumpsize, int deflumpnum, int patcheslump, int firstdup, bool texture1) { FPatchLookup *patchlookup = NULL; int i; uint32_t numpatches; if (firstdup == 0) { firstdup = (int)Textures.Size(); } { auto pnames = Wads.OpenLumpReader(patcheslump); numpatches = pnames.ReadUInt32(); // Check whether the amount of names reported is correct. if ((signed)numpatches < 0) { Printf("Corrupt PNAMES lump found (negative amount of entries reported)\n"); return; } // Check whether the amount of names reported is correct. int lumplength = Wads.LumpLength(patcheslump); if (numpatches > uint32_t((lumplength-4)/8)) { Printf("PNAMES lump is shorter than required (%u entries reported but only %d bytes (%d entries) long\n", numpatches, lumplength, (lumplength-4)/8); // Truncate but continue reading. Who knows how many such lumps exist? numpatches = (lumplength-4)/8; } // Catalog the patches these textures use so we know which // textures they represent. patchlookup = new FPatchLookup[numpatches]; for (uint32_t i = 0; i < numpatches; ++i) { char pname[9]; pnames.Read(pname, 8); pname[8] = '\0'; patchlookup[i].Name = pname; } } bool isStrife = false; const uint32_t *maptex, *directory; uint32_t maxoff; int numtextures; uint32_t offset = 0; // Shut up, GCC! maptex = (const uint32_t *)lumpdata; numtextures = LittleLong(*maptex); maxoff = lumpsize; if (maxoff < uint32_t(numtextures+1)*4) { Printf ("Texture directory is too short\n"); delete[] patchlookup; return; } // Scan the texture lump to decide if it contains Doom or Strife textures for (i = 0, directory = maptex+1; i < numtextures; ++i) { offset = LittleLong(directory[i]); if (offset > maxoff) { Printf ("Bad texture directory\n"); delete[] patchlookup; return; } maptexture_t *tex = (maptexture_t *)((uint8_t *)maptex + offset); // There is bizzarely a Doom editing tool that writes to the // first two elements of columndirectory, so I can't check those. if (SAFESHORT(tex->patchcount) < 0 || tex->columndirectory[2] != 0 || tex->columndirectory[3] != 0) { isStrife = true; break; } } // Textures defined earlier in the lump take precedence over those defined later, // but later TEXTUREx lumps take precedence over earlier ones. for (i = 1, directory = maptex; i <= numtextures; ++i) { if (i == 1 && texture1) { // The very first texture is just a dummy. Copy its dimensions to texture 0. // It still needs to be created in case someone uses it by name. offset = LittleLong(directory[1]); const maptexture_t *tex = (const maptexture_t *)((const uint8_t *)maptex + offset); FDummyTexture *tex0 = static_cast<FDummyTexture *>(Textures[0].Texture); tex0->SetSize (SAFESHORT(tex->width), SAFESHORT(tex->height)); } offset = LittleLong(directory[i]); if (offset > maxoff) { Printf ("Bad texture directory\n"); delete[] patchlookup; return; } // If this texture was defined already in this lump, skip it // This could cause problems with animations that use the same name for intermediate // textures. Should I be worried? int j; for (j = (int)Textures.Size() - 1; j >= firstdup; --j) { if (strnicmp (Textures[j].Texture->Name, (const char *)maptex + offset, 8) == 0) break; } if (j + 1 == firstdup) { FMultiPatchTexture *tex = new FMultiPatchTexture ((const uint8_t *)maptex + offset, patchlookup, numpatches, isStrife, deflumpnum); if (i == 1 && texture1) { tex->UseType = ETextureType::FirstDefined; } TexMan.AddTexture (tex); StartScreen->Progress(); } } delete[] patchlookup; }
HRESULT CInArchive::Open2(IInStream *stream, const UInt64 *searchHeaderSizeLimit, CDatabase &database) { database.Clear(); RINOK(stream->Seek(0, STREAM_SEEK_SET, &database.StartPosition)); RINOK(FindSignatureInStream(stream, NHeader::kMarker, NHeader::kMarkerSize, searchHeaderSizeLimit, database.StartPosition)); RINOK(stream->Seek(database.StartPosition + NHeader::kMarkerSize, STREAM_SEEK_SET, NULL)); if (!inBuffer.Create(1 << 17)) return E_OUTOFMEMORY; inBuffer.SetStream(stream); inBuffer.Init(); CInArchiveInfo &archiveInfo = database.ArchiveInfo; archiveInfo.Size = ReadUInt32(); // size of this cabinet file in bytes if (ReadUInt32() != 0) return S_FALSE; archiveInfo.FileHeadersOffset = ReadUInt32(); // offset of the first CFFILE entry if (ReadUInt32() != 0) return S_FALSE; archiveInfo.VersionMinor = ReadByte(); // cabinet file format version, minor archiveInfo.VersionMajor = ReadByte(); // cabinet file format version, major archiveInfo.NumFolders = ReadUInt16(); // number of CFFOLDER entries in this cabinet archiveInfo.NumFiles = ReadUInt16(); // number of CFFILE entries in this cabinet archiveInfo.Flags = ReadUInt16(); if (archiveInfo.Flags > 7) return S_FALSE; archiveInfo.SetID = ReadUInt16(); // must be the same for all cabinets in a set archiveInfo.CabinetNumber = ReadUInt16(); // number of this cabinet file in a set if (archiveInfo.ReserveBlockPresent()) { archiveInfo.PerCabinetAreaSize = ReadUInt16(); // (optional) size of per-cabinet reserved area archiveInfo.PerFolderAreaSize = ReadByte(); // (optional) size of per-folder reserved area archiveInfo.PerDataBlockAreaSize = ReadByte(); // (optional) size of per-datablock reserved area Skeep(archiveInfo.PerCabinetAreaSize); } { if (archiveInfo.IsTherePrev()) ReadOtherArchive(archiveInfo.PreviousArchive); if (archiveInfo.IsThereNext()) ReadOtherArchive(archiveInfo.NextArchive); } int i; for(i = 0; i < archiveInfo.NumFolders; i++) { CFolder folder; folder.DataStart = ReadUInt32(); folder.NumDataBlocks = ReadUInt16(); folder.CompressionTypeMajor = ReadByte(); folder.CompressionTypeMinor = ReadByte(); Skeep(archiveInfo.PerFolderAreaSize); database.Folders.Add(folder); } RINOK(stream->Seek(database.StartPosition + archiveInfo.FileHeadersOffset, STREAM_SEEK_SET, NULL)); inBuffer.SetStream(stream); inBuffer.Init(); for(i = 0; i < archiveInfo.NumFiles; i++) { CItem item; item.Size = ReadUInt32(); item.Offset = ReadUInt32(); item.FolderIndex = ReadUInt16(); UInt16 pureDate = ReadUInt16(); UInt16 pureTime = ReadUInt16(); item.Time = ((UInt32(pureDate) << 16)) | pureTime; item.Attributes = ReadUInt16(); item.Name = SafeReadName(); int folderIndex = item.GetFolderIndex(database.Folders.Size()); if (folderIndex >= database.Folders.Size()) return S_FALSE; database.Items.Add(item); } return S_OK; }
// Reads the XNB file header (version number, size, etc.). uint32_t ContentReader::ReadHeader() { uint32_t startPosition = FilePosition(); // Magic number. uint8_t magic1 = ReadByte(); uint8_t magic2 = ReadByte(); uint8_t magic3 = ReadByte(); if (magic1 != 'X' || magic2 != 'N' || magic3 != 'B') { throw app_exception("Not an XNB file."); } // Target platform. uint8_t targetPlatform = ReadByte(); switch (targetPlatform) { case 'w': Log.WriteLine("Target platform: Windows"); break; case 'm': Log.WriteLine("Target platform: Windows Phone"); break; case 'x': Log.WriteLine("Target platform: Xbox 360"); break; default: Log.WriteLine("Unknown target platform %d", targetPlatform); break; } // Format version. uint8_t formatVersion = ReadByte(); if (formatVersion != 5) { Log.WriteLine("Warning: not an XNA Game Studio version 4.0 XNB file. Parsing may fail unexpectedly."); } // Flags. uint8_t flags = ReadByte(); if (flags & 1) { Log.WriteLine("Graphics profile: HiDef"); } else { Log.WriteLine("Graphics profile: Reach"); } bool isCompressed = (flags & 0x80) != 0; // File size. uint32_t sizeOnDisk = ReadUInt32(); if (startPosition + sizeOnDisk > FileSize()) { throw app_exception("XNB file has been truncated."); } if (isCompressed) { uint32_t decompressedSize = ReadUInt32(); uint32_t compressedSize = startPosition + sizeOnDisk - FilePosition(); Log.WriteLine("%d bytes of asset data are compressed into %d", decompressedSize, compressedSize); throw app_exception("Don't support reading the contents of compressed XNB files."); } return startPosition + sizeOnDisk; }