Exemple #1
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="filePath"></param>
        public void Open(string name, Stream s)
        {
            Name = name;
            using (BinaryReaderExt r = new BinaryReaderExt(s))
            {
                r.BigEndian = true;

                var headerLength = r.ReadInt32() + 0x10;
                var dataOff      = r.ReadInt32();
                var soundCount   = r.ReadInt32();
                StartIndex = r.ReadInt32();

                Sounds = new DSP[soundCount];

                for (int i = 0; i < soundCount; i++)
                {
                    var sound        = new DSP();
                    var ChannelCount = r.ReadInt32();
                    sound.Frequency = r.ReadInt32();

                    sound.Channels.Clear();
                    for (int j = 0; j < ChannelCount; j++)
                    {
                        var channel = new DSPChannel();

                        channel.LoopFlag = r.ReadInt16();
                        channel.Format   = r.ReadInt16();
                        var LoopStartOffset = r.ReadInt32();
                        var LoopEndOffset   = r.ReadInt32();
                        var CurrentAddress  = r.ReadInt32();
                        for (int k = 0; k < 0x10; k++)
                        {
                            channel.COEF[k] = r.ReadInt16();
                        }
                        channel.Gain = r.ReadInt16();
                        channel.InitialPredictorScale = r.ReadInt16();
                        channel.InitialSampleHistory1 = r.ReadInt16();
                        channel.InitialSampleHistory2 = r.ReadInt16();
                        channel.LoopPredictorScale    = r.ReadInt16();
                        channel.LoopSampleHistory1    = r.ReadInt16();
                        channel.LoopSampleHistory2    = r.ReadInt16();
                        r.ReadInt16(); //  padding

                        channel.NibbleCount = LoopEndOffset - CurrentAddress;
                        channel.LoopStart   = LoopStartOffset - CurrentAddress;

                        sound.Channels.Add(channel);

                        var DataOffset = headerLength + (int)Math.Ceiling(CurrentAddress / 2d) - 1;

                        channel.Data = r.GetSection((uint)DataOffset, (int)Math.Ceiling(channel.NibbleCount / 2d) + 1);
                    }

                    Sounds[i] = sound;
                }
            }
        }
Exemple #2
0
        /// <summary>
        /// Melee's sound format
        /// </summary>
        /// <param name="filePath"></param>
        private void OpenSSM(string filePath)
        {
            using (BinaryReaderExt r = new BinaryReaderExt(new FileStream(filePath, FileMode.Open)))
            {
                r.BigEndian = true;

                var headerLength = r.ReadInt32() + 0x10;
                var dataOff      = r.ReadInt32();
                var soundCount   = r.ReadInt32();
                Unknown = r.ReadInt32();

                for (int i = 0; i < soundCount; i++)
                {
                    var sound = new DSP();
                    sound.Index = i;
                    var ChannelCount = r.ReadInt32();
                    sound.Frequency = r.ReadInt32();

                    sound.Channels.Clear();
                    for (int j = 0; j < ChannelCount; j++)
                    {
                        var channel = new DSPChannel();

                        channel.LoopFlag = r.ReadInt16();
                        channel.Format   = r.ReadInt16();
                        var LoopStartOffset = r.ReadInt32();
                        var LoopEndOffset   = r.ReadInt32();
                        var CurrentAddress  = r.ReadInt32();
                        for (int k = 0; k < 0x10; k++)
                        {
                            channel.COEF[k] = r.ReadInt16();
                        }
                        channel.Gain = r.ReadInt16();
                        channel.InitialPredictorScale = r.ReadInt16();
                        channel.InitialSampleHistory1 = r.ReadInt16();
                        channel.InitialSampleHistory2 = r.ReadInt16();
                        channel.LoopPredictorScale    = r.ReadInt16();
                        channel.LoopSampleHistory1    = r.ReadInt16();
                        channel.LoopSampleHistory2    = r.ReadInt16();
                        r.ReadInt16(); //  padding

                        channel.NibbleCount = LoopEndOffset - CurrentAddress;
                        channel.LoopStart   = LoopStartOffset - CurrentAddress;

                        sound.Channels.Add(channel);

                        var DataOffset = headerLength + (int)Math.Ceiling(CurrentAddress / 2d) - 1;

                        channel.Data = r.GetSection((uint)DataOffset, (int)Math.Ceiling(channel.NibbleCount / 2d) + 1);
                    }

                    Sounds.Add(sound);
                }
            }
        }
Exemple #3
0
        /// <summary>
        ///
        /// </summary>
        public void LoadFromStream(Stream s)
        {
            using (BinaryReaderExt r = new BinaryReaderExt(s))
            {
                if (s.Length < 0x14)
                {
                    return;
                }

                if (new string(r.ReadChars(4)) != "SPKG")
                {
                    return;
                }

                GroupFlags = r.ReadUInt32();
                Flags      = r.ReadUInt32();

                var ssmSize = r.ReadInt32();
                ScriptBank         = new SEMBank();
                ScriptBank.Scripts = new SEMBankScript[r.ReadInt32()];

                for (int i = 0; i < ScriptBank.Scripts.Length; i++)
                {
                    ScriptBank.Scripts[i] = new SEMBankScript();
                    ScriptBank.Scripts[i].Decompile(r.GetSection(r.ReadUInt32(), r.ReadInt32()));
                }

                var name = r.ReadString(r.ReadByte());

                if (ssmSize == 0)
                {
                    SoundBank = null;
                }
                else
                {
                    SoundBank = new SSM();
                    using (MemoryStream ssmStream = new MemoryStream(r.ReadBytes(ssmSize)))
                        SoundBank.Open(name, ssmStream);
                }
            }
        }
        /// <summary>
        ///
        /// </summary>
        private void LoadFighterAnimationFiles()
        {
            var aFile = MainForm.Instance.FilePath.Replace(".dat", "AJ.dat");
            var cFile = MainForm.Instance.FilePath.Replace(".dat", "Nr.dat");

            // try to automatically locate files
            bool openFiles = true;

            if (File.Exists(aFile) && File.Exists(cFile))
            {
                var r = MessageBox.Show($"Load {System.IO.Path.GetFileName(aFile)} and {System.IO.Path.GetFileName(cFile)}", "Open Files", MessageBoxButtons.YesNoCancel);

                if (r == DialogResult.Cancel)
                {
                    return;
                }

                if (r == DialogResult.Yes)
                {
                    openFiles = false;
                }
            }

            // find files to open
            if (openFiles)
            {
                cFile = FileIO.OpenFile("Fighter Costume (Pl**Nr.dat)|*.dat");
                if (cFile == null)
                {
                    return;
                }
                aFile = FileIO.OpenFile("Fighter Animation (Pl**AJ.dat)|*.dat");
                if (aFile == null)
                {
                    return;
                }
            }

            // load model
            var modelFile = new HSDRawFile(cFile);

            if (modelFile.Roots.Count > 0 && modelFile.Roots[0].Data is HSD_JOBJ jobj)
            {
                JointManager.SetJOBJ(jobj);

                // load material animation if it exists
                if (modelFile.Roots.Count > 1 && modelFile.Roots[1].Data is HSD_MatAnimJoint matanim)
                {
                    JointManager.SetMatAnimJoint(matanim);
                    JointManager.EnableMaterialFrame = true;
                }
            }
            else
            {
                return;
            }

            // set model scale
            JointManager.ModelScale = ModelScale;

            // clear hidden dobjs
            JointManager.DOBJManager.HiddenDOBJs.Clear();

            // don't render bones by default
            JointManager._settings.RenderBones = false;

            // reset model visibility
            ResetModelVis();

            // load the model parts
            LoadModelParts();

            // populate animation dictionary
            AJFilePath = aFile;
            SymbolToAnimation.Clear();
            using (BinaryReaderExt r = new BinaryReaderExt(new FileStream(aFile, FileMode.Open)))
                foreach (var a in AllActions)
                {
                    if (a.Symbol != null && !SymbolToAnimation.ContainsKey(a.Symbol))
                    {
                        SymbolToAnimation.Add(a.Symbol, r.GetSection((uint)a.AnimOffset, a.AnimSize));
                    }
                }

            // enable preview box
            previewBox.Visible = true;

            // reselect action
            if (actionList.SelectedItem is Action action)
            {
                SelectAction(action);
            }
        }
        public static void Deconstruct(string plFilePath, string ajFilePath, string outputFolder)
        {
            var plfile = new HSDRawFile(plFilePath);

            var path = Path.GetDirectoryName(plFilePath) + "\\" + outputFolder + "\\";

            Directory.CreateDirectory(path);

            var data = plfile.Roots[0].Data as SBM_FighterData;

            if (data == null)
            {
                return;
            }

            var ajfile = new HSDRawFile(ajFilePath);

            foreach (var prop in data.GetType().GetProperties())
            {
                var val = prop.GetValue(data) as HSDAccessor;

                if (val == null)
                {
                    continue;
                }
                if (prop.PropertyType == typeof(SBM_CommonFighterAttributes))
                {
                    var attr = prop.GetValue(data) as SBM_CommonFighterAttributes;
                    using (StreamWriter w = new StreamWriter(new FileStream(path + prop.Name + ".ini", FileMode.Create)))
                    {
                        foreach (var v in attr.GetType().GetProperties())
                        {
                            if (v.Name.Equals("TrimmedSize"))
                            {
                                continue;
                            }
                            w.WriteLine($"{v.Name}={v.GetValue(attr)}");
                        }
                    }
                }
                else
                if (prop.Name.Equals("SubActionTable"))
                {
                    ScriptFile f = new ScriptFile();

                    f.Actions = new ActionGroup[val._s.Length / 0x18];

                    var ActionDecompiler = new ActionDecompiler();
                    HashSet <string> ExportedAnimations = new HashSet <string>();

                    for (int i = 0; i < f.Actions.Length; i++)
                    {
                        SBM_FighterAction subaction = new HSDRaw.Melee.Pl.SBM_FighterAction();
                        subaction._s = val._s.GetEmbeddedStruct(0x18 * i, 0x18);

                        if (!ExportedAnimations.Contains(subaction.Name) && subaction.Name != null && subaction.Name != "")
                        {
                            ExportedAnimations.Add(subaction.Name);
                            if (ajFilePath != null && File.Exists(ajFilePath))
                            {
                                using (BinaryReaderExt r = new BinaryReaderExt(new FileStream(ajFilePath, FileMode.Open)))
                                {
                                    var animdata = r.GetSection((uint)subaction.AnimationOffset, subaction.AnimationSize);
                                    File.WriteAllBytes(path + "Animations\\" + subaction.Name + ".dat", animdata);
                                }
                            }
                        }

                        ActionGroup g = new ActionGroup();
                        g.animation_name = subaction.Name;
                        g.flags          = (int)subaction.Flags;
                        g.script         = ActionDecompiler.Decompile("Func_" + i.ToString("X3"), subaction.SubAction);
                        //g.script =
                        g.off        = subaction.AnimationOffset;
                        g.size       = subaction.AnimationSize;
                        f.Actions[i] = g;

                        Console.WriteLine(i + " " + subaction.Name + " " + subaction._s.GetReference <HSDAccessor>(0x0C)._s.References.Count);
                    }

                    XmlSerializer writer = new XmlSerializer(typeof(ScriptFile));
                    using (var w = new XmlTextWriter(new FileStream(path + prop.Name + ".txt", FileMode.Create), Encoding.UTF8))
                    {
                        w.Formatting = Formatting.Indented;
                        writer.Serialize(w, f);
                    }
                }
                else
                {
                    HSDRootNode root = new HSDRootNode();

                    root.Name = prop.Name;

                    root.Data = val;

                    HSDRawFile file = new HSDRawFile();
                    file.Roots.Add(root);

                    file.Save(path + prop.Name + ".dat");

                    Console.WriteLine(prop.Name + " " + val._s.GetSubStructs().Count);
                }
            }
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="output"></param>
        /// <param name="name"></param>
        /// <param name="datas"></param>
        /// <param name="structToFunctionName"></param>
        private void DecompileGroup(StringBuilder output, string name, HSDStruct datas)
        {
            if (structToFunctionName.ContainsKey(datas))
            {
                return;
            }
            structToFunctionName.Add(datas, name);

            output.AppendLine(name);
            output.AppendLine("{");
            using (BinaryReaderExt r = new BinaryReaderExt(new MemoryStream(datas.GetData())))
            {
                byte flag = (byte)(r.ReadByte() >> 2);

                var cmd = ActionCommon.GetMeleeCMDAction(flag);

                while (flag != 0)
                {
                    r.BaseStream.Position -= 1;
                    var size    = cmd.ByteSize;
                    var command = r.GetSection(r.Position, size);
                    r.Skip((uint)size);

                    if (flag == 5 || flag == 7) //goto
                    {
                        var re = datas.GetReference <HSDAccessor>((int)r.BaseStream.Position - 4);
                        if (re != null)
                        {
                            if (!tempStructToName.ContainsKey(re._s))
                            {
                                if (structToFunctionName.ContainsKey(re._s))
                                {
                                    tempStructToName.Add(re._s, structToFunctionName[re._s]);
                                }
                                else
                                {
                                    tempStructToName.Add(re._s, name + "_" + ((int)r.BaseStream.Position - 4).ToString("X4"));
                                }
                            }
                            var funcname = tempStructToName[re._s];
                            output.AppendLine("\t" + (flag == 5 ? "Goto" : "Subroutine") + "(" + funcname + ");");
                        }
                    }
                    else
                    {
                        output.AppendLine("\t" + DecompileCommand(command));
                    }

                    if (r.BaseStream.Position >= r.BaseStream.Length)
                    {
                        break;
                    }

                    flag = (byte)(r.ReadByte() >> 2);
                    cmd  = ActionCommon.GetMeleeCMDAction(flag);
                }
            }
            output.AppendLine("}");

            foreach (var re in datas.References)
            {
                DecompileGroup(output, name + "_" + re.Key.ToString("X4"), re.Value);
            }
        }
Exemple #7
0
        private static void FromBRSTM(this DSP dsp, string filePath)
        {
            using (FileStream s = new FileStream(filePath, FileMode.Open))
                using (BinaryReaderExt r = new BinaryReaderExt(s))
                {
                    if (new string(r.ReadChars(4)) != "RSTM")
                    {
                        throw new NotSupportedException("File is not a valid BRSTM file");
                    }

                    r.BigEndian = true;
                    r.BigEndian = r.ReadUInt16() == 0xFEFF;

                    r.Skip(2); // 01 00 version
                    r.Skip(4); // filesize

                    r.Skip(2); // 00 40 - header length
                    r.Skip(2); // 00 02 - header version

                    var headOffset = r.ReadUInt32();
                    var headSize   = r.ReadUInt32();

                    var adpcOffset = r.ReadUInt32();
                    var adpcSize   = r.ReadUInt32();

                    var dataOffset = r.ReadUInt32();
                    var dataSize   = r.ReadUInt32();


                    // can skip adpc section when reading because it just contains sample history


                    // parse head section
                    // --------------------------------------------------------------
                    r.Position = headOffset;
                    if (new string(r.ReadChars(4)) != "HEAD")
                    {
                        throw new NotSupportedException("BRSTM does not have a valid HEAD");
                    }
                    r.Skip(4); // section size


                    r.Skip(4); // 01 00 00 00 marker
                    var chunk1Offset = r.ReadUInt32() + 8 + headOffset;

                    r.Skip(4); // 01 00 00 00 marker
                    var chunk2Offset = r.ReadUInt32() + 8 + headOffset;

                    r.Skip(4); // 01 00 00 00 marker
                    var chunk3Offset = r.ReadUInt32() + 8 + headOffset;


                    // --------------------------------------------------------------
                    r.Seek(chunk1Offset);
                    var codec        = (BRSTM_CODEC)r.ReadByte();
                    var loopFlag     = r.ReadByte();
                    var channelCount = r.ReadByte();
                    r.Skip(1); // padding

                    if (codec != BRSTM_CODEC.ADPCM_4bit)
                    {
                        throw new NotSupportedException("only 4bit ADPCM files currently supported");
                    }

                    var sampleRate = r.ReadUInt16();
                    r.Skip(2); // padding

                    dsp.Frequency = sampleRate;

                    var loopStart    = r.ReadUInt32();
                    var totalSamples = r.ReadUInt32();

                    var dataPointer = r.ReadUInt32(); // DATA offset
                    int blockCount  = r.ReadInt32();

                    var blockSize       = r.ReadUInt32();
                    var samplesPerBlock = r.ReadInt32();

                    var sizeOfFinalBlock    = r.ReadUInt32();
                    var samplesInFinalBlock = r.ReadInt32();

                    var sizeOfFinalBlockWithPadding = r.ReadUInt32();

                    var samplesPerEntry = r.ReadInt32();
                    var bytesPerEntry   = r.ReadInt32();

                    // --------------------------------------------------------------
                    r.Seek(chunk2Offset);
                    var numOfTracks   = r.ReadByte();
                    var trackDescType = r.ReadByte();
                    r.Skip(2); // padding

                    for (uint i = 0; i < numOfTracks; i++)
                    {
                        r.Seek(chunk1Offset + 4 + 8 * i);
                        r.Skip(1); // 01 padding
                        var descType = r.ReadByte();
                        r.Skip(2); // padding
                        var descOffset = r.ReadUInt32() + 8 + headOffset;

                        r.Seek(descOffset);
                        switch (descType)
                        {
                        case 0:
                        {
                            int channelsInTrack = r.ReadByte();
                            int leftChannelID   = r.ReadByte();
                            int rightChannelID  = r.ReadByte();
                            r.Skip(1);     // padding
                        }
                        break;

                        case 1:
                        {
                            var volume  = r.ReadByte();
                            var panning = r.ReadByte();
                            r.Skip(2);     // padding
                            r.Skip(4);     // padding
                            int channelsInTrack = r.ReadByte();
                            int leftChannelID   = r.ReadByte();
                            int rightChannelID  = r.ReadByte();
                            r.Skip(1);     // 01 padding
                        }
                        break;
                        }
                    }

                    // --------------------------------------------------------------
                    r.Seek(chunk3Offset);

                    var channelCountAgain = r.ReadByte();
                    r.Skip(3);

                    for (uint i = 0; i < channelCountAgain; i++)
                    {
                        r.Seek(chunk3Offset + 4 + 8 * i);

                        r.Skip(4); // 01000000 marker
                        var offset = r.ReadUInt32() + headOffset + 8;

                        r.Seek(offset);

                        // channel information
                        var channel = new DSPChannel();
                        dsp.Channels.Add(channel);
                        channel.LoopFlag  = loopFlag;
                        channel.LoopStart = (int)loopStart;

                        r.Skip(4); // 01000000 marker
                        r.Skip(4); // offset to coefficients (they follow directly after)

                        for (int k = 0; k < 0x10; k++)
                        {
                            channel.COEF[k] = r.ReadInt16();
                        }
                        channel.Gain = r.ReadInt16();
                        channel.InitialPredictorScale = r.ReadInt16();
                        channel.InitialSampleHistory1 = r.ReadInt16();
                        channel.InitialSampleHistory2 = r.ReadInt16();
                        channel.LoopPredictorScale    = r.ReadInt16();
                        channel.LoopSampleHistory1    = r.ReadInt16();
                        channel.LoopSampleHistory2    = r.ReadInt16();
                        r.Skip(2); // padding

                        // get channel data
                        using (MemoryStream channelStream = new MemoryStream())
                        {
                            for (uint j = 0; j < blockCount; j++)
                            {
                                var bs = blockSize;
                                var actualBlockSize = blockSize;

                                if (j == blockCount - 1)
                                {
                                    bs = sizeOfFinalBlockWithPadding;
                                    actualBlockSize = sizeOfFinalBlock;
                                }

                                channelStream.Write(r.GetSection(dataPointer + j * (blockSize * channelCountAgain) + bs * i, (int)actualBlockSize), 0, (int)actualBlockSize);
                            }

                            channel.Data        = channelStream.ToArray();
                            channel.NibbleCount = channel.Data.Length * 2;
                        }
                    }


                    dsp.LoopPoint = TimeSpan.FromMilliseconds(loopStart / (double)sampleRate * 1000).ToString();
                }
        }
Exemple #8
0
 /// <summary>
 ///
 /// </summary>
 /// <param name="offset"></param>
 /// <param name="size"></param>
 /// <returns></returns>
 public byte[] GetSection(uint doloffset, int size)
 {
     return(r.GetSection(doloffset, size));
 }
Exemple #9
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="elfFile"></param>
        public RelocELF(byte[] elfFile)
        {
            using (MemoryStream mstream = new MemoryStream(elfFile))
                using (BinaryReaderExt r = new BinaryReaderExt(mstream))
                {
                    // Parse Header

                    if (!(r.ReadByte() == 0x7F && r.ReadByte() == 0x45 && r.ReadByte() == 0x4C && r.ReadByte() == 0x46))
                    {
                        throw new InvalidDataException("Not a valid ELF file");
                    }

                    byte bitType = r.ReadByte(); // 1 - 32, 2 - 64
                    if (bitType != 1)
                    {
                        throw new NotSupportedException("Only 32 bit ELF files are currently supported");
                    }

                    r.BigEndian = r.ReadByte() == 2;

                    // I only care about the sections
                    r.Seek(0x20);
                    var sectionOffset = r.ReadUInt32();
                    r.Seek(0x2E);
                    var sectionHeaderSize  = r.ReadUInt16();
                    var numOfSections      = r.ReadInt16();
                    var StringSectionIndex = r.ReadUInt16();

                    List <SectionData> DataSections = new List <SectionData>();

                    // Parse Sections
                    var Sections = new ELFSection[numOfSections];
                    for (uint i = 0; i < numOfSections; i++)
                    {
                        r.Seek(sectionOffset + sectionHeaderSize * i);

                        Sections[i] = new ELFSection()
                        {
                            sh_name      = r.ReadUInt32(),
                            sh_type      = (SectionType)r.ReadInt32(),
                            sh_flags     = r.ReadUInt32(),
                            sh_addr      = r.ReadUInt32(),
                            sh_offset    = r.ReadUInt32(),
                            sh_size      = r.ReadUInt32(),
                            sh_link      = r.ReadUInt32(),
                            sh_info      = r.ReadUInt32(),
                            sh_addralign = r.ReadUInt32(),
                            sh_entsize   = r.ReadUInt32()
                        };

                        DataSections.Add(new SectionData());
                    }

                    // Parse Symbols
                    var symbolSection = Array.Find(Sections, e => r.ReadString((int)(Sections[StringSectionIndex].sh_offset + e.sh_name), -1) == ".symtab");

                    var Symbols = new ELFSymbol[symbolSection.sh_size / 0x10];
                    for (uint i = 0; i < Symbols.Length; i++)
                    {
                        r.Seek(symbolSection.sh_offset + 0x10 * i);

                        Symbols[i] = new ELFSymbol()
                        {
                            st_name  = r.ReadUInt32(),
                            st_value = r.ReadUInt32(),
                            st_size  = r.ReadUInt32(),
                            st_info  = r.ReadByte(),
                            st_other = r.ReadByte(),
                            st_shndx = r.ReadInt16()
                        };

                        SymbolSections.Add(new SymbolData());
                    }

                    // Grab Relocation Data

                    for (int i = 0; i < Sections.Length; i++)
                    {
                        var section = Sections[i];

                        var data = DataSections[i];
                        data.Name = r.ReadString((int)(Sections[StringSectionIndex].sh_offset + Sections[i].sh_name), -1);

                        data.Data = r.GetSection(section.sh_offset, (int)section.sh_size);

                        if (section.sh_type == SectionType.SHT_RELA || section.sh_type == SectionType.SHT_REL)
                        {
                            var relocs = ParseRelocationSection(r, section);

                            foreach (var v in relocs)
                            {
                                DataSections[(int)section.sh_info].Relocations.Add(new RelocData()
                                {
                                    Offset      = v.r_offset,
                                    AddEnd      = v.r_addend,
                                    Symbol      = SymbolSections[(int)v.R_SYM],
                                    Type        = (RelocType)v.R_TYP,
                                    SymbolIndex = v.R_SYM
                                });
                            }
                        }
                    }

                    var symbolStringSection = Sections[symbolSection.sh_link];

                    // rip out symbol data

                    for (int i = 0; i < Symbols.Length; i++)
                    {
                        var sym = Symbols[i];

                        var section = sym.st_shndx >= 0 ? DataSections[sym.st_shndx] : null;

                        byte[]           symbolData  = new byte[sym.st_size];
                        List <RelocData> relocations = new List <RelocData>();

                        if (section != null)
                        {
                            SymbolSections[i].SectionName = section.Name;

                            if (Sections[sym.st_shndx].sh_type == SectionType.SHT_NOBITS)
                            {
                                symbolData = new byte[section.Data.Length];
#if DEBUG
                                // Console.WriteLine($"{section.Name} {(Sections[sym.st_shndx].sh_offset + sym.st_value).ToString("X")} {sym.st_size} {sym.st_value} {symbolData.Length} {Sections[sym.st_shndx].sh_type}");
#endif
                            }
                            else
                            {
                                // If size of section is 0, get all data?
                                if (sym.st_size == 0)
                                {
                                    symbolData = section.Data;
                                }
                                //else
                                //if ((sym.st_value & 0x80000000) != 0)
                                //{
                                //    Array.Copy(section.Data, sym.st_value - 0x80000000 - Sections[sym.st_shndx].sh_offset, symbolData, 0, sym.st_size);
                                //    Debug.WriteLine($"LONG CALL {section.Relocations.Count} Off: {(sym.st_value - 0x80000000).ToString("X")} SectionOff: {Sections[sym.st_shndx].sh_offset.ToString("X")} {sym.st_value.ToString("X")} Size: {sym.st_size.ToString("X")} Total Size: {section.Data.Length.ToString("X")}");
                                //}
                                else
                                {
                                    Array.Copy(section.Data, sym.st_value, symbolData, 0, sym.st_size);
                                }

                                // TODO: when to get relocations?
                                relocations = section.Relocations.Where(
                                    e => e.Offset >= sym.st_value &&
                                    (e.Offset < sym.st_value + symbolData.Length)
                                    ).ToList();

                                // make relative
                                foreach (var rel in relocations)
                                {
                                    rel.Offset -= sym.st_value;
                                }
                            }

                            // if the offset is 0 the function is usually in another file
                            SymbolSections[i].External = Sections[sym.st_shndx].sh_offset == 0;
#if DEBUG
                            //Console.WriteLine(section.Name + " " + r.ReadString((int)(symbolStringSection.sh_offset + sym.st_name), -1)
                            //    + " " + Sections[sym.st_shndx].sh_info + " " + Sections[sym.st_shndx].sh_addr + " " + relocations.Count);

                            //Debug.WriteLine($"{section.Name} {r.ReadString((int)(symbolStringSection.sh_offset + sym.st_name), -1)} {(Sections[sym.st_shndx].sh_offset + + sym.st_value).ToString("X")} {sym.st_size.ToString("X")}");


                            if (section.Name == ".debug_line")
                            {
                                //r.Seek(Sections[sym.st_shndx].sh_offset + +sym.st_value);
                                //ParseDebugLine(r);
                            }
#endif
                        }

                        SymbolSections[i].Symbol      = r.ReadString((int)(symbolStringSection.sh_offset + sym.st_name), -1);
                        SymbolSections[i].Data        = symbolData;
                        SymbolSections[i].Relocations = relocations;
                    }
                }
        }