public void IdataCharacteristicsArePlausible()
        {
            var characteristics = SectionHeaders.First(sec => sec.NameString.StartsWith(".idata")).Characteristics;

            Assert.That(characteristics.HasFlag(SectionCharacteristics.MemRead), ".idata should be readable");
            Assert.That(characteristics.HasFlag(SectionCharacteristics.ContainsInitializedData), ".idata should contain initialized data");
        }
Exemple #2
0
        internal void Read(PeReader rdr)
        {
            rdr.SetPosition(0);
            if (t == PeFileType.Image)
            {
                dos = new DOSHeader(this);
                dos.Read(rdr);

                rdr.SetPosition(dos.PEHeaderOffset);
                sign = rdr.ReadBytes(4);

                pe = new PEHeader(this);
                pe.Read(rdr);

                op = new OptionalHeader(this);
                op.Read(rdr);

                sects = new SectionHeaders(this);
                sects.Read(rdr);

                certs = new CertificateDirectory(op.DataDirectories[DataDirectoryType.Certificate]);
                certs.Load(rdr, op.DataDirectories[DataDirectoryType.Certificate].Address.Value);
            }
            else if (t == PeFileType.Object)
            {
                pe = new PEHeader(this);
                pe.Read(rdr);

                sects = new SectionHeaders(this);
                sects.Read(rdr);
            }
        }
Exemple #3
0
        public static void WriteChunk(BBData data, SectionHeaders chunk, BBData inner)
        {
            var bb = data.Buffer;

            bb.Write((uint)chunk);

            Write(bb, inner);
        }
Exemple #4
0
        // http://msdn.microsoft.com/en-us/library/windows/desktop/ms680341(v=vs.85).aspx
        private void ParseImageSectionHeader()
        {
            var header = FromBinaryReader <IMAGE_SECTION_HEADER>(Reader);

            SectionHeaders.Add(header);
            LogStructure(header);
            Reader.BaseStream.Seek(-4, SeekOrigin.Current); // The f**k? Why is this needed?
        }
 /// <summary>
 /// Determines the image section the given relative virtual address (RVA) is located at.
 /// </summary>
 /// <param name="rva">The relative virtual address to check.</param>
 /// <returns>The section the <paramref name="rva"/> is located.</returns>
 public ImageSectionHeader GetSectionHeaderByRva(long rva)
 {
     return
         (SectionHeaders.FirstOrDefault(
              sectionHeader =>
              rva >= sectionHeader.VirtualAddress &&
              rva < sectionHeader.VirtualAddress + sectionHeader.VirtualSize));
 }
 /// <summary>
 /// Determines the image section the given absolute file offset is located at.
 /// </summary>
 /// <param name="fileOffset">The absolute file offset to check.</param>
 /// <returns>The section the <paramref name="fileOffset"/> is located.</returns>
 public ImageSectionHeader GetSectionHeaderByFileOffset(long fileOffset)
 {
     return
         (SectionHeaders.FirstOrDefault(
              sectionHeader =>
              fileOffset >= sectionHeader.PointerToRawData &&
              fileOffset < sectionHeader.PointerToRawData + sectionHeader.SizeOfRawData));
 }
Exemple #7
0
        public SectionHeader *GetChunk(SectionHeaders ident)
        {
            if (Chunks.ContainsKey(ident))
            {
                return((SectionHeader *)Chunks[ident]);
            }

            return(null);
        }
Exemple #8
0
        public ElfFile(MemoryStream stream)
        {
            //load main file header
            ElfHeader = new Elf32Ehdr((Elf32_Ehdr *)stream.Pointer);

            //load section headers
            var header = (Elf32_Shdr *)(stream.Pointer + ElfHeader.Shoff);

            for (int i = 0; i < ElfHeader.Shnum; i++)
            {
                var x = new Elf32Shdr(&header[i]);
                if (x.Type == SectionType.StringTable)
                {
                    _stringTables.Add(x.Offset);
                }
                SectionHeaders.Add(x);
            }

            //now we can load names into symbols and process sub data
            for (var index = 0; index < SectionHeaders.Count; index++)
            {
                var sectionHeader = SectionHeaders[index];
                sectionHeader.Name = ResolveName(sectionHeader, sectionHeader.NameOffset, stream);

                switch (sectionHeader.Type)
                {
                case SectionType.Relocation:
                    for (int i = 0; i < sectionHeader.Size / sectionHeader.Entsize; i++)
                    {
                        RelocationInformation.Add(new Elf32Rel(
                                                      (Elf32_Rel *)(stream.Pointer + sectionHeader.Offset + i * sectionHeader.Entsize))
                        {
                            Section = index
                        });
                    }

                    break;

                case SectionType.SymbolTable:
                    for (int i = 0; i < sectionHeader.Size / sectionHeader.Entsize; i++)
                    {
                        var x = new Elf32Sym(
                            (Elf32_Sym *)(stream.Pointer + sectionHeader.Offset + i * sectionHeader.Entsize));
                        x.Name = ResolveName(sectionHeader, x.NameOffset, stream);
                        Symbols.Add(x);
                    }

                    break;
                }
            }
        }
Exemple #9
0
        public IEnumerable <Section> GetSections(SectionHeaders header)
        {
            if (!HasSubSections)
            {
                yield break;
            }

            foreach (var section in SubSections)
            {
                if (section.Header == (uint)header)
                {
                    yield return(section);
                }
            }
        }
Exemple #10
0
        public static string ToChunkName(this SectionHeaders h)
        {
            sb.Clear();

            var u = (uint)h;

            var c3 = (char)((u & 0xFF000000) >> 24);
            var c2 = (char)((u & 0x00FF0000) >> 16);
            var c1 = (char)((u & 0x0000FF00) >> 8);
            var c0 = (char)((u & 0x000000FF));

            return(sb
                   .Append(c0).Append(c1).Append(c2).Append(c3)
                   .ToString());
        }
Exemple #11
0
        public Section GetSection(SectionHeaders header)
        {
            if (!HasSubSections)
            {
                return(null);
            }

            foreach (var section in SubSections)
            {
                if (section.Header == (uint)header)
                {
                    return(section);
                }
            }

            return(null);
        }
Exemple #12
0
 private bool ReadFromStream(BinaryReader r)
 {
     DosHeader = ReadDosHeader(r);
     if (DosHeader.e_magic != (int)ImageSignatureTypes.IMAGE_DOS_SIGNATURE)
     {
         r.Close();
         return(false);
     }
     r.BaseStream.Seek((long)DosHeader.e_lfanew, SeekOrigin.Begin);
     NTHeader = ReadNTHeader(r);
     if (NTHeader.Signature != (int)ImageSignatureTypes.IMAGE_NT_SIGNATURE)
     {
         r.Close();
         return(false);
     }
     {
         uint maxpointer = 0;
         uint exesize    = 0;
         for (int i = 0; i < NTHeader.FileHeader.NumberOfSections; ++i)
         {
             IMAGE_SECTION_HEADER data = new IMAGE_SECTION_HEADER();
             {
                 data.NameBytes            = r.ReadBytes(8);
                 data.PhysicalAddress      = r.ReadUInt32();
                 data.VirtualAddress       = r.ReadUInt32();
                 data.SizeOfRawData        = r.ReadUInt32();
                 data.PointerToRawData     = r.ReadUInt32();
                 data.PointerToRelocations = r.ReadUInt32();
                 data.PointerToLinenumbers = r.ReadUInt32();
                 data.NumberOfRelocations  = r.ReadUInt16();
                 data.NumberOfLinenumbers  = r.ReadUInt16();
                 data.Characteristics      = r.ReadUInt32();
             }
             if (data.PointerToRawData > maxpointer)
             {
                 maxpointer = data.PointerToRawData;
                 exesize    = data.PointerToRawData + data.SizeOfRawData;
             }
             SectionHeaders.Add(data);
         }
         this.FileSize = exesize;
     }
     return(true);
 }
        public void TextSectionIsReadableExecutableAndHasCode()
        {
            var textSections = SectionHeaders.Where(item => item.NameString == ".text\0\0\0").ToArray();

            if (textSections.Length < 1)
            {
                Assert.Inconclusive("Cannot run this test without .text section");
            }

            foreach (var sectionHeader in textSections)
            {
                Assert.That(
                    sectionHeader.Characteristics.HasFlag(SectionCharacteristics.ContainsCode),
                    ".text does not contain code (section flags)"
                    );
                Assert.That(sectionHeader.Characteristics.HasFlag(SectionCharacteristics.MemExecute), ".text is not executable (section flags)");
                Assert.That(sectionHeader.Characteristics.HasFlag(SectionCharacteristics.MemRead), ".text is not readable (section flags)");
            }
        }
Exemple #14
0
        public void Parse(BinaryReader reader)
        {
            DOSHeader = DOSHeader.Parse(reader);
            var dosStubSize = (int)(DOSHeader.CoffHeaderOffset - reader.BaseStream.Position);

            _dosStubBytes  = reader.ReadBytes(dosStubSize);
            COFFHeader     = COFFHeader.Parse(reader);
            PEHeaderOffset = (uint)reader.BaseStream.Position;
            PEHeader       = PEHeader.Parse(reader);

            for (var i = 0; i < COFFHeader.NumberOfSections; i++)
            {
                SectionHeaders.Add(PESectionHeader.Parse(reader));
            }

            var fillerSize = (int)(SectionHeaders[0].PointerToRawData - reader.BaseStream.Position);

            _filler = reader.ReadBytes(fillerSize);

            for (var i = 0; i < COFFHeader.NumberOfSections; i++)
            {
                var sectionBytes = reader.ReadBytes((int)SectionHeaders[i].SizeOfRawData);
                Sections.Add(sectionBytes);
            }

            var remainingByteCount = (int)(reader.BaseStream.Length - reader.BaseStream.Position);

            _remainingBytes = reader.ReadBytes(remainingByteCount);
            // file ends here

            // Parse Import Directory:
            var importDirectoryEntry = PEHeader.DataDirectories[(int)DataDirectoryName.Import];

            if (importDirectoryEntry.VirtualAddress > 0)
            {
                var importDirectoryFileOffset = GetOffsetFromRVA(importDirectoryEntry.VirtualAddress);
                reader.BaseStream.Seek(importDirectoryFileOffset, SeekOrigin.Begin);
                ImportDirectory = ImportDirectory.Parse(reader);
            }
        }
        public void CanParseHeaderAndEntries()
        {
            var relocRVA        = OptionalHeader.DataDirectories.BaseRelocationTable.VirtualAddress;
            var relocSection    = SectionHeaders.First(sec => sec.NameString.StartsWith(".reloc"));
            var startFileOffset = relocSection.PointerToRawData + relocRVA - relocSection.VirtualAddress;
            var reader          = new ArrayStructReaderWriter(TestFile)
            {
                Offset = startFileOffset
            };

            var blockHeader      = reader.Read <BaseRelocationBlockHeader>();
            var noEntries        = (blockHeader.BlockSize - 8) / 2;
            var firstBlockEntry  = reader.Read <BaseRelocationBlockEntry>();
            var secondBlockEntry = reader.Read <BaseRelocationBlockEntry>();

            Assert.AreEqual(0x19000, blockHeader.PageRVA);
            Assert.AreEqual(12, noEntries);
            Assert.AreEqual(0xA110, firstBlockEntry.Entry);
            Assert.AreEqual(0x110, firstBlockEntry.Offset);
            Assert.AreEqual(BaseRelocationType.ImageRelBasedDir64, firstBlockEntry.Type);
            Assert.AreEqual(0xA440, secondBlockEntry.Entry);
        }
Exemple #16
0
 private void ReadSections(int offset)
 {
     this.rva = new RVAManager();
     int len = this.pe1.NumberOfSections;
     this.sects = new SectionHeaders[len];
     for (int i = 0; i < len; i++)
     {
         sects[i] = new SectionHeaders();
         sects[i].ReadData(this.data, offset);
         offset += 40;
         this.rva.SetAddress(sects[i].PointerToRawData, sects[i].VirtualAddress);
         sects[i].AppendTitle(string.Format(" \"{0}\"", Util.EscapeText(Util.GetASCIIString(sects[i].Name))));
     }
 }
Exemple #17
0
        public SectionHeader *GetChunk(SectionHeaders ident)
        {
            switch (ident)
            {
            case SectionHeaders.Form:
                return((SectionHeader *)Form);

            case SectionHeaders.General:
                return((SectionHeader *)General);

            case SectionHeaders.Options:
                return((SectionHeader *)Options);

            case SectionHeaders.Extensions:
                return((SectionHeader *)Extensions);

            case SectionHeaders.AudioGroup:
                return((SectionHeader *)AudioGroup);

            case SectionHeaders.Shaders:
                return((SectionHeader *)Shaders);

            case SectionHeaders.Timelines:
                return((SectionHeader *)Timelines);

            case SectionHeaders.DataFiles:
                return((SectionHeader *)DataFiles);

            case SectionHeaders.GNAL_Unk:
                return((SectionHeader *)GNAL_Unk);

            case SectionHeaders.Sounds:
                return((SectionHeader *)Sounds);

            case SectionHeaders.Sprites:
                return((SectionHeader *)Sprites);

            case SectionHeaders.Backgrounds:
                return((SectionHeader *)Backgrounds);

            case SectionHeaders.Paths:
                return((SectionHeader *)Paths);

            case SectionHeaders.Scripts:
                return((SectionHeader *)Scripts);

            case SectionHeaders.Fonts:
                return((SectionHeader *)Fonts);

            case SectionHeaders.Objects:
                return((SectionHeader *)Objects);

            case SectionHeaders.Rooms:
                return((SectionHeader *)Rooms);

            case SectionHeaders.TexturePage:
                return((SectionHeader *)TexturePages);

            case SectionHeaders.Code:
                return((SectionHeader *)Code);

            case SectionHeaders.Strings:
                return((SectionHeader *)Strings);

            case SectionHeaders.Textures:
                return((SectionHeader *)Textures);

            case SectionHeaders.Audio:
                return((SectionHeader *)Audio);

            case SectionHeaders.Functions:
                return((SectionHeader *)Functions);

            case SectionHeaders.Variables:
                return((SectionHeader *)Variables);

            default:
                if (UnknownChunks.ContainsKey(ident))
                {
                    return((SectionHeader *)UnknownChunks[ident]);
                }

                return(null);
            }
        }
Exemple #18
0
        private void FileOpen(string file)
        {
            // Set status bar location for the file.
            tbStatusBarLocation.Text = file;

            // Parse the PE file
            if (!PeFile.IsPEFile(file))
            {
                ShowInvalidPeFileMsgBox();
                return;
            }

            _peFile = new PeFile(file);

            // Set all FileInfo fields.
            FileInfo.SetFileInfo(_peFile);

            // Set the DOS header fields
            DosNtHeader.SetDosHeader(_peFile);

            // Set the PE File fields
            DosNtHeader.SetNtHeader(_peFile);

            // Set the File header
            FileHeaderDebug.SetFileHeader(_peFile);

            // Set the Debug directory.
            FileHeaderDebug.SetDebug(_peFile);

            // Set the Optional header
            OptionalHeader.SetOptionalHeader(_peFile);

            // Set the imports.
            Imports.SetImports(_peFile);

            // Set the exports.
            Exports.SetExports(_peFile);

            // Set the resources.
            Resource.SetResources(_peFile);

            // Set the sections.
            SectionHeaders.SetSections(_peFile);

            // Set the Exception (only for x64)
            Exceptions.SetException(_peFile);

            // Set the Relocations.
            Relocation.SetRelocations(_peFile);

            // Set the Digital Signature information.
            Signature.SetDigSignature(_peFile);

            // Set the Bound Import directory.
            DebugBoundImport.SetBoundImport(_peFile);

            // Set the Delay Import descriptor.
            DebugBoundImport.SetDelayImport(_peFile);

            // Set the TLS directory.
            TlsDirectory.SetTlsDirectory(_peFile);

            // Set the Load Config Directory
            LoadConfig.SetLoadConfig(_peFile);

            // Set the Data Directory View
            DirectoryView.SetDirectoryView(_peFile);
        }
Exemple #19
0
 public uint GetPhysicalAddress(string sectionName)
 {
     return(SectionHeaders.First(i => i.NameString.Contains(sectionName)).PhysicalAddress);
 }
Exemple #20
0
 public uint GetPhysicalAddressEnd(string sectionName)
 {
     return(SectionHeaders.Where(i => i.NameString.Contains(sectionName)).Select(o => o.SizeOfRawData + o.PhysicalAddress).First());
 }
        public ImageSection GetSectionByName(string name)
        {
            var header = SectionHeaders.FirstOrDefault(x => x.Name == name);

            return(header != null ? header.Section : null);
        }
 public IEnumerable <ImageSection> GetSections()
 {
     return(SectionHeaders.Select(x => x.Section));
 }
Exemple #23
0
        internal GMFile(GMFileContent f)
        {
            Content = f;

            var orderList = new List <SectionHeaders>(f.HeaderOffsets.Length);

            foreach (long headerOffset in f.HeaderOffsets)
            {
                SectionHeaders tag = ((SectionHeader *)((byte *)f.Form + headerOffset))->Identity;
                if (tag != SectionHeaders.Form)
                {
                    orderList.Add(tag);
                }
            }
            ChunkOrder = orderList.ToArray();

            if (f.General != null)
            {
                General = SectionReader.GetGeneralInfo(f);
            }
            if (f.Options != null)
            {
                Options = SectionReader.GetOptionInfo(f);
            }
            if (f.Globals != null)
            {
                Globals = SectionReader.GetGlobalInfo(f);
            }

            Sound = MkLazyArr(f.Sounds, i => SectionReader.GetSoundInfo(f, i));

            if (f.TexturePages != null)
            {
                var toil = SectionReader.BuildTPAGOffsetIndexLUT(f);
                Sprites = MkLazyArr(f.Sprites, i => SectionReader.GetSpriteInfo(f, i, toil));
            }

            Backgrounds  = MkLazyArr(f.Backgrounds, i => SectionReader.GetBgInfo(f, i));
            Paths        = MkLazyArr(f.Paths, i => SectionReader.GetPathInfo(f, i));
            Scripts      = MkLazyArr(f.Scripts, i => SectionReader.GetScriptInfo(f, i));
            Fonts        = MkLazyArr(f.Fonts, i => SectionReader.GetFontInfo(f, i));
            Objects      = MkLazyArr(f.Objects, i => SectionReader.GetObjectInfo(f, i));
            Rooms        = MkLazyArr(f.Rooms, i => SectionReader.GetRoomInfo(f, i));
            TexturePages = MkLazyArr(f.TexturePages, i => SectionReader.GetTexPageInfo(f, i));
            Code         = MkLazyArr(f.Code, i => Disassembler.DisassembleCode(f, i));
            Strings      = MkLazyArr(f.Strings, i => SectionReader.GetStringInfo(f, i));
            Textures     = MkLazyArr(f.Textures, i => SectionReader.GetTextureInfo(f, i));
            Audio        = MkLazyArr(f.Audio, i => SectionReader.GetAudioInfo(f, i));
            AudioGroups  = MkLazyArr(f.AudioGroup, i => SectionReader.GetAudioGroupInfo(f, i));
            Extensions   = MkLazyArr(f.Extensions, i => SectionReader.GetExtensionInfo(f, i));
            Shaders      = MkLazyArr(f.Shaders, i => SectionReader.GetShaderInfo(f, i));
            Timelines    = MkLazyArr(f.Timelines, i => SectionReader.GetTimelineInfo(f, i));

            AudioSoundMap = new Dictionary <uint, uint>();
            if (f.Sounds != null)
            {
                for (uint i = 0; i < Sound.Length; i++)
                {
                    var s = Sound[i];

                    if ((s.IsEmbedded || s.IsCompressed) && s.AudioID != -1 && s.GroupID == 0)
                    {
                        AudioSoundMap[(uint)s.AudioID] = i;
                    }
                }
            }

            if (f.General == null)
            {
                return;
            }

            try
            {
                // TODO: do this in a better way
                var vars = General.IsOldBCVersion
                    ? SectionReader.GetRefDefs(f, f.Variables)
                    : SectionReader.GetRefDefsWithOthers(f, f.Variables);
                var fns = General.IsOldBCVersion
                    ? SectionReader.GetRefDefs(f, f.Functions)
                    : SectionReader.GetRefDefsWithLength(f, f.Functions);

                var varacc = Disassembler.GetReferenceTable(f, vars);
                var fnacc  = Disassembler.GetReferenceTable(f, fns);

                RefData = new RefData
                {
                    Variables     = vars,
                    Functions     = fns,
                    VarAccessors  = varacc,
                    FuncAccessors = fnacc
                };

                if (f.Functions->Entries.NameOffset * 12 < f.Functions->Header.Size)
                {
                    FunctionLocals = SectionReader.GetFunctionLocals(f, f.Functions);
                }
                if (f.Variables != null && !General.IsOldBCVersion)
                {
                    VariableExtra = new uint[]
                    {
                        ((uint *)&f.Variables->Entries)[0],
                        ((uint *)&f.Variables->Entries)[1],
                        ((uint *)&f.Variables->Entries)[2]
                    }
                }
                ;
            }
            catch (Exception e)
            {
                Console.Error.WriteLine("Warning: Can't figure out RefDef pairs. Exception:");
                Console.Error.WriteLine(e);
            }
        }
Exemple #24
0
        public WDC3Reader(Stream stream)
        {
            using (var reader = new BinaryReader(stream, Encoding.UTF8))
            {
                if (reader.BaseStream.Length < HeaderSize)
                {
                    throw new InvalidDataException("WDC3 file is corrupted!");
                }

                uint magic = reader.ReadUInt32();

                if (magic != WDC3FmtSig)
                {
                    throw new InvalidDataException("WDC3 file is corrupted!");
                }

                RecordsCount    = reader.ReadInt32();
                FieldsCount     = reader.ReadInt32();
                RecordSize      = reader.ReadInt32();
                StringTableSize = reader.ReadInt32();
                TableHash       = reader.ReadUInt32();
                LayoutHash      = reader.ReadUInt32();
                MinIndex        = reader.ReadInt32();
                MaxIndex        = reader.ReadInt32();
                Locale          = reader.ReadInt32();
                Flags           = (DB2Flags)reader.ReadUInt16();
                IdFieldIndex    = reader.ReadUInt16();
                int totalFieldsCount = reader.ReadInt32();
                PackedDataOffset  = reader.ReadInt32();     // Offset within the field where packed data starts
                lookupColumnCount = reader.ReadInt32();     // count of lookup columns
                field_info_size   = reader.ReadInt32();     // 24 * NumFields bytes, describes column bit packing, {ushort recordOffset, ushort size, uint additionalDataSize, uint compressionType, uint packedDataOffset or commonvalue, uint cellSize, uint cardinality}[NumFields], sizeof(DBC2CommonValue) == 8
                commonDataSize    = reader.ReadInt32();
                palletDataSize    = reader.ReadInt32();     // in bytes, sizeof(DBC2PalletValue) == 4
                SectionsCount     = reader.ReadInt32();

                if (SectionsCount == 0 || RecordsCount == 0)
                {
                    return;
                }

                //section headers
                SectionHeaders = reader.ReadArray <SectionHeaderWDC3>(SectionsCount).ToList();
                m_sections     = SectionHeaders.OfType <IEncryptableDatabaseSection>().ToList();

                // field meta data
                field_structure_data = reader.ReadArray <FieldMetaData>(FieldsCount);

                // column meta data
                ColumnMeta = reader.ReadArray <ColumnMetaData>(FieldsCount);

                // pallet data
                PalletData = new Value32[ColumnMeta.Length][];
                for (int i = 0; i < ColumnMeta.Length; i++)
                {
                    if (ColumnMeta[i].CompressionType == CompressionType.Pallet || ColumnMeta[i].CompressionType == CompressionType.PalletArray)
                    {
                        PalletData[i] = reader.ReadArray <Value32>((int)ColumnMeta[i].AdditionalDataSize / 4);
                    }
                }

                // common data
                CommonData = new Dictionary <int, Value32> [ColumnMeta.Length];
                for (int i = 0; i < ColumnMeta.Length; i++)
                {
                    if (ColumnMeta[i].CompressionType == CompressionType.Common)
                    {
                        var commonValues = new Dictionary <int, Value32>((int)ColumnMeta[i].AdditionalDataSize / 8);
                        CommonData[i] = commonValues;

                        for (int j = 0; j < ColumnMeta[i].AdditionalDataSize / 8; j++)
                        {
                            commonValues[reader.ReadInt32()] = reader.Read <Value32>();
                        }
                    }
                }

                //section_data
                int StringTableSizeCounter = 0, RecordCountCounter = 0;
                //foreach (var sectionheader in SectionHeaders)
                //{
                reader.BaseStream.Position = SectionHeaders[0].FileOffset;

                if (!Flags.HasFlagExt(DB2Flags.Sparse)) //'no offset map'
                {
                    // records data
                    RecordsData = reader.ReadBytes(SectionHeaders[0].NumRecords * RecordSize);

                    Array.Resize(ref RecordsData, RecordsData.Length + 8); // pad with extra zeros so we don't crash when reading

                    // string data
                    if (StringTable == null)
                    {
                        StringTable = new Dictionary <long, string>(SectionHeaders[0].StringTableSize / 0x20);
                    }

                    for (int i = 0; i < SectionHeaders[0].StringTableSize;)
                    {
                        long oldPos = reader.BaseStream.Position;
                        StringTable[i + StringTableSizeCounter] = reader.ReadCString();
                        i += (int)(reader.BaseStream.Position - oldPos);
                    }

                    StringTableSizeCounter += SectionHeaders[0].StringTableSize;
                }
                else //'Has offset map'
                {
                    // sparse data with inlined strings
                    RecordsData = reader.ReadBytes(SectionHeaders[0].OffsetRecordsEndOffset - SectionHeaders[0].FileOffset);

                    if (reader.BaseStream.Position != SectionHeaders[0].OffsetRecordsEndOffset)
                    {
                        throw new Exception("reader.BaseStream.Position != section.OffsetRecordsEndOffset");
                    }
                }

                // skip encrypted sections => has tact key + record data is zero filled
                if (SectionHeaders[0].TactKeyLookup != 0 && Array.TrueForAll(RecordsData, x => x == 0))
                {
                    RecordCountCounter += SectionHeaders[0].NumRecords;
                    return;
                }

                // id_list_data
                id_list_data = reader.ReadArray <int>(SectionHeaders[0].IndexDataSize / 4);

                // fix zero-filled index data
                if (id_list_data.Length > 0 && id_list_data.All(x => x == 0))
                {
                    id_list_data = Enumerable.Range(MinIndex + RecordCountCounter, SectionHeaders[0].NumRecords).ToArray();
                }

                // copy table entry data    , duplicate rows data
                if (SectionHeaders[0].CopyTableCount > 0)
                {
                    if (CopyData == null)
                    {
                        CopyData = new Dictionary <int, int>();
                    }

                    for (int i = 0; i < SectionHeaders[0].CopyTableCount; i++)
                    {
                        CopyData[reader.ReadInt32()] = reader.ReadInt32(); //id_of_new_row, id_of_copied_row
                    }
                }

                // offset map entry data
                if (SectionHeaders[0].OffsetMapIDCount > 0)
                {
                    // HACK unittestsparse is malformed and has sparseIndexData first
                    if (TableHash == 145293629)
                    {
                        reader.BaseStream.Position += 4 * SectionHeaders[0].OffsetMapIDCount;
                    }

                    offset_map_Entries = reader.ReadArray <offset_map_entry>(SectionHeaders[0].OffsetMapIDCount).ToList();
                }

                // reference/relationship data
                refData = new ReferenceData();
                if (SectionHeaders[0].ParentLookupDataSize > 0)
                {
                    refData.NumRecords = reader.ReadInt32();
                    refData.MinId      = reader.ReadInt32();
                    refData.MaxId      = reader.ReadInt32();

                    var entries = reader.ReadArray <ReferenceEntry>(refData.NumRecords);
                    for (int i = 0; i < entries.Length; i++)
                    {
                        refData.Entries[entries[i].Index] = entries[i].Id;
                    }
                }

                //offset_map_id_list
                if (SectionHeaders[0].OffsetMapIDCount > 0)
                {
                    int[] offset_map_id_listdata = reader.ReadArray <int>(SectionHeaders[0].OffsetMapIDCount);

                    if (SectionHeaders[0].IndexDataSize > 0 && id_list_data.Length != offset_map_id_listdata.Length)
                    {
                        throw new Exception("m_indexData.Length != sparseIndexData.Length");
                    }

                    id_list_data = offset_map_id_listdata;
                }

                //loop and add field data to create datarow
                int position = 0;
                for (int i = 0; i < SectionHeaders[0].NumRecords; i++)
                {
                    BitReader bitReader = new BitReader(RecordsData)
                    {
                        Position = 0
                    };

                    if (Flags.HasFlagExt(DB2Flags.Sparse))
                    {
                        bitReader.Position = position;
                        position          += offset_map_Entries[i].Size * 8;
                    }
                    else
                    {
                        bitReader.Offset = i * RecordSize;
                    }

                    refData.Entries.TryGetValue(i, out int refId);

                    IDBRow rec = new WDC3Row(this, bitReader, SectionHeaders[0].IndexDataSize != 0 ? id_list_data[i] : -1, refId, i + RecordCountCounter);
                    _Records.Add(_Records.Count, rec);
                }

                RecordCountCounter += SectionHeaders[0].NumRecords;
                //}

                long pos = reader.BaseStream.Position;
                long len = reader.BaseStream.Length;
                NoParseRecordsData = reader.ReadBytes((int)(len - pos));
            }
        }
 private string[] GetSectionNames() => SectionHeaders.Select(item => item.NameString).ToArray();
 public void LastSectionIsInFile()
 {
     Assert.GreaterOrEqual(TestFile.Length, SectionHeaders.Max(sec => sec.PointerToRawData + sec.SizeOfRawData));
 }