public static List <Anim> UnpackMOT(string path) { var anims = new List <Anim>(); using (BinaryReaderExt r = new BinaryReaderExt(new FileStream(path, FileMode.Open))) { r.BigEndian = true; r.ReadInt32(); // unknown int count = r.ReadInt32(); uint headerSize = r.ReadUInt32(); uint fileLength = r.ReadUInt32(); if (fileLength != r.Length) { throw new Exception("File Length Mismatch"); } for (uint i = 0; i < count; i++) { r.Seek(headerSize + i * 4); r.Seek(r.ReadUInt32()); Anim anim = new Anim(); if (r.Position != 0) { anim.Parse(r); } anims.Add(anim); } } return(anims); }
public static HSD_Spline KMP_ExtractRouteSpline(string kmpFile) { List <HSD_Vector3> points = new List <HSD_Vector3>(); using (FileStream f = new FileStream(kmpFile, FileMode.Open)) using (BinaryReaderExt r = new BinaryReaderExt(f)) { r.BigEndian = true; r.Seek(0x14); var enpt = r.ReadUInt32(); r.Seek(enpt + 0x4C); r.Skip(4); int count = r.ReadInt16(); int unk = r.ReadInt16(); for (int i = 0; i < count; i++) { points.Add(new HSD_Vector3() { X = r.ReadSingle() * Scale, Y = r.ReadSingle() * Scale + YTrans, Z = r.ReadSingle() * Scale }); var range = r.ReadSingle(); r.Skip(4); // settings } } HSD_Spline spline = new HSD_Spline(); spline.Points = points.ToArray(); spline.PointCount = (short)points.Count; float totalLength = 0; foreach (var e in points) { totalLength += new Vector3(e.X, e.Y, e.Z).Length; } float[] lengths = new float[points.Count]; //float length = 0; for (int i = 0; i < lengths.Length; i++) { lengths[i] = i / (float)(lengths.Length - 1); //length += new Vector3(points[i].X, points[i].Y, points[i].Z).Length; } spline.TotalLength = totalLength; spline.Lengths = new HSDFloatArray() { Array = lengths }; return(spline); }
/// <summary> /// /// </summary> /// <param name="path"></param> private void OpenSEMFile(string path) { using (BinaryReaderExt r = new BinaryReaderExt(new FileStream(path, FileMode.Open))) { r.BigEndian = true; r.Seek(8); var entryCount = r.ReadInt32(); var offsetTableStart = r.Position + (entryCount + 1) * 4; for (uint i = 0; i < entryCount; i++) { SEMEntry e = new SEMEntry(); e.Index = (int)i; Entries.Add(e); r.Seek(0x0C + i * 4); var startIndex = r.ReadInt32(); var endIndex = r.ReadInt32(); HashSet <int> UniqueEntries = new HashSet <int>(); int largestEntry = 0; for (uint j = 0; j < endIndex - startIndex; j++) { SEMSound s = new SEMSound(); s.Index = (int)j; r.Seek((uint)(offsetTableStart + startIndex * 4 + j * 4)); var dataOffsetStart = r.ReadUInt32(); var dataOffsetEnd = r.ReadUInt32(); if (dataOffsetEnd == 0) { dataOffsetEnd = (uint)r.Length; } r.Seek(dataOffsetStart); s.CommandData = r.ReadBytes((int)(dataOffsetEnd - dataOffsetStart)); e.Sounds.Add(s); var entryId = ((s.CommandData[1] & 0xFF) << 16) | ((s.CommandData[2] & 0xFF) << 8) | ((s.CommandData[3] & 0xFF)); if (!UniqueEntries.Contains(entryId)) { UniqueEntries.Add(entryId); } } e.UniqueCount = UniqueEntries.Count; //e.UniqueCount = largestEntry; } } }
/// <summary> /// /// </summary> /// <param name="filePath"></param> /// <returns></returns> public static short[] GetJointTable(string filePath) { if (!File.Exists(filePath)) { MessageBox.Show("No JCV file loaded", "JCV File", MessageBoxButtons.OK, MessageBoxIcon.Warning); return(new short[0]); } using (BinaryReaderExt r = new BinaryReaderExt(new FileStream(filePath, FileMode.Open))) { r.BigEndian = true; r.Seek(0x10); var count = r.ReadInt16(); short[] vals = new short[count]; for (int i = 0; i < vals.Length; i++) { vals[i] = r.ReadInt16(); } return(vals); } }
private DSP ImportDSP(string filePath) { using (BinaryReaderExt r = new BinaryReaderExt(new FileStream(filePath, FileMode.Open))) { r.BigEndian = true; var dsp = new DSP(); r.ReadInt32(); var nibbleCount = r.ReadInt32(); dsp.Frequency = r.ReadInt32(); 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 r.Seek(0x60); channel.NibbleCount = nibbleCount; channel.LoopStart = LoopStartOffset - CurrentAddress; channel.Data = r.ReadBytes((int)Math.Ceiling(nibbleCount / 2d)); dsp.Channels.Add(channel); r.BaseStream.Close(); return(dsp); } }
private void FromDSP(byte[] data) { Channels.Clear(); using (BinaryReaderExt r = new BinaryReaderExt(new MemoryStream(data))) { r.BigEndian = true; r.ReadInt32(); var nibbleCount = r.ReadInt32(); Frequency = r.ReadInt32(); 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 r.Seek(0x60); channel.NibbleCount = nibbleCount; channel.LoopStart = LoopStartOffset - CurrentAddress; channel.Data = r.ReadBytes((int)Math.Ceiling(nibbleCount / 2d)); Channels.Add(channel); r.BaseStream.Close(); } }
/// <summary> /// /// </summary> /// <param name="r"></param> /// <param name="sec"></param> /// <returns></returns> private ELFRelocA[] ParseRelocationSection(BinaryReaderExt r, ELFSection sec) { ELFRelocA[] relocA = new ELFRelocA[0]; if (sec.sh_type == SectionType.SHT_RELA || sec.sh_type == SectionType.SHT_REL) { uint relSize = 0x0C; var count = (sec.sh_size / relSize); relocA = new ELFRelocA[count]; for (uint i = 0; i < count; i++) { r.Seek(sec.sh_offset + relSize * i); relocA[i] = new ELFRelocA() { r_offset = r.ReadUInt32(), r_info = r.ReadUInt32(), r_addend = (sec.sh_type == SectionType.SHT_RELA ? r.ReadUInt32() : 0) }; } } return(relocA); }
private static void ReadTrack(BinaryReaderExt r, int frameCount, int type, FOBJ_Player track, uint dataOffset, AnimNode node) { var offset = r.ReadUInt32() + dataOffset; var temp = r.Position; r.Seek(offset); int fCount = -1; float scale = 0; float[] frame = null, step = null, tan = null; if (type == 0x1) { fCount = r.ReadUInt16(); r.Skip(2); scale = r.ReadSingle(); float stepb = r.ReadSingle(); float base2 = r.ReadSingle(); frame = new float[fCount]; step = new float[fCount]; tan = new float[fCount]; for (int i = 0; i < fCount; i++) { var v = r.ReadInt32(); frame[i] = (v >> 24) & 0xFF; int th = v & 0xFFFFFF; step[i] = base2 + ((th >> 12) & 0xfff) * stepb; tan[i] = (Sign12Bit(th & 0xfff) / 32f); track.Keys.Add(new FOBJKey() { Frame = frame[i], Value = step[i], Tan = tan[i], InterpolationType = GXInterpolationType.HSD_A_OP_SPL }); } } if (type == 0x2) { fCount = r.ReadUInt16(); r.Skip(2); scale = r.ReadSingle(); float stepb = r.ReadSingle(); float base2 = r.ReadSingle(); frame = new float[fCount]; step = new float[fCount]; tan = new float[fCount]; for (int i = 0; i < fCount; i++) { frame[i] = r.ReadUInt16() / 32f; step[i] = base2 + r.ReadUInt16() * stepb; tan[i] = (r.ReadInt16() / 256f); track.Keys.Add(new FOBJKey() { Frame = frame[i], Value = step[i], Tan = tan[i], InterpolationType = GXInterpolationType.HSD_A_OP_SPL }); } } if (type == 0x3) { fCount = r.ReadUInt16(); r.Skip(2); scale = r.ReadSingle(); frame = new float[fCount]; step = new float[fCount]; tan = new float[fCount]; for (int i = 0; i < fCount; i++) { frame[i] = r.ReadSingle(); step[i] = r.ReadSingle(); tan[i] = r.ReadSingle(); track.Keys.Add(new FOBJKey() { Frame = frame[i], Value = step[i], Tan = tan[i], InterpolationType = GXInterpolationType.HSD_A_OP_SPL }); } } if (type == 0x4) { float stepb = r.ReadSingle(); float base2 = r.ReadSingle(); for (int i = 0; i < frameCount; i++) { float v = base2 + stepb * (r.ReadByte()); track.Keys.Add(new FOBJKey() { Frame = i, Value = v, InterpolationType = GXInterpolationType.HSD_A_OP_LIN }); } } if (type == 0x6) { for (int i = 0; i < frameCount; i++) { float v = r.ReadSingle(); track.Keys.Add(new FOBJKey() { Frame = i, Value = v, InterpolationType = GXInterpolationType.HSD_A_OP_LIN }); } } r.Seek(temp); }
private static void ReadKeys(BinaryReaderExt r, AnimNode node, int frameCount, FOBJ_Player xtrack, FOBJ_Player ytrack, FOBJ_Player ztrack, bool isIsotrophic, bool isXFixed, bool isYFixed, bool isZFixed, int type, uint dataOffset) { if (isIsotrophic) { var temp = r.Position + 4; if (!isXFixed && !isYFixed && !isZFixed) { var offset = r.ReadUInt32() + r.Position; r.Seek(offset); } float iss = r.ReadSingle(); xtrack.Keys.Add(new FOBJKey() { Frame = 0, Value = iss, InterpolationType = GXInterpolationType.HSD_A_OP_KEY }); ytrack.Keys.Add(new FOBJKey() { Frame = 0, Value = iss, InterpolationType = GXInterpolationType.HSD_A_OP_KEY }); ztrack.Keys.Add(new FOBJKey() { Frame = 0, Value = iss, InterpolationType = GXInterpolationType.HSD_A_OP_KEY }); r.Seek(temp); } else { if (isXFixed) { xtrack.Keys.Add(new FOBJKey() { Frame = 0, Value = r.ReadSingle(), InterpolationType = GXInterpolationType.HSD_A_OP_KEY }); } else { ReadTrack(r, frameCount, type, xtrack, dataOffset, node); } if (isYFixed) { ytrack.Keys.Add(new FOBJKey() { Frame = 0, Value = r.ReadSingle(), InterpolationType = GXInterpolationType.HSD_A_OP_KEY }); } else { ReadTrack(r, frameCount, type, ytrack, dataOffset, node); } if (isZFixed) { ztrack.Keys.Add(new FOBJKey() { Frame = 0, Value = r.ReadSingle(), InterpolationType = GXInterpolationType.HSD_A_OP_KEY }); } else { ReadTrack(r, frameCount, type, ztrack, dataOffset, node); } } }
/// <summary> /// /// </summary> /// <param name="filePath"></param> /// <returns></returns> public static JointAnimManager LoadCHR0(string filePath, JointMap jointMap) { JointAnimManager anim = new JointAnimManager(); for (int i = 0; i < jointMap.Count; i++) { anim.Nodes.Add(new AnimNode()); } using (BinaryReaderExt r = new BinaryReaderExt(new FileStream(filePath, FileMode.Open))) { r.BigEndian = true; if (r.BaseStream.Length < 4 || new string(r.ReadChars(4)) != "CHR0") { throw new InvalidDataException("CHR0 file is not valid"); } r.Skip(4); int versionNum = r.ReadInt32(); if (versionNum != 4) { throw new InvalidDataException($"CHR0 version {versionNum} not supported"); } r.Seek(0x10); var indexGroupOffset = r.ReadUInt32(); var animName = r.ReadString(r.ReadInt32(), -1); r.Skip(4); anim.FrameCount = r.ReadUInt16() - 1; int animDataCount = r.ReadUInt16(); r.Skip(8); r.Seek(indexGroupOffset); var sectionOffset = r.ReadUInt32() + indexGroupOffset; int sectionCount = r.ReadInt32(); for (uint i = 0; i < sectionCount; i++) { r.Seek(indexGroupOffset + 8 + 16 * i); r.Skip(4); // id and unknown r.Skip(2); // let r.Skip(2); // right var boneName = r.ReadString(r.ReadInt32() + (int)indexGroupOffset, -1); var dataOffset = r.ReadUInt32() + indexGroupOffset; if (dataOffset == indexGroupOffset) { sectionCount += 1; continue; } if (jointMap.IndexOf(boneName) == -1) { continue; } r.Seek(dataOffset); var nameOff = r.Position + r.ReadUInt32(); var flags = r.ReadInt32(); //Console.WriteLine(boneName + " " + flags.ToString("X")); //r.PrintPosition(); //01BFE019 int t_type = (flags >> 0x1e) & 0x3; int r_type = (flags >> 0x1b) & 0x7; int s_type = (flags >> 0x19) & 0x3; int hasT = (flags >> 0x18) & 0x1; int hasR = (flags >> 0x17) & 0x1; int hasS = (flags >> 0x16) & 0x1; int Zfixed = (flags >> 0x15) & 0x1; int Yfixed = (flags >> 0x14) & 0x1; int Xfixed = (flags >> 0x13) & 0x1; int RZfixed = (flags >> 0x12) & 0x1; int RYfixed = (flags >> 0x11) & 0x1; int RXfixed = (flags >> 0x10) & 0x1; int SZfixed = (flags >> 0xf) & 0x1; int SYfixed = (flags >> 0xe) & 0x1; int SXfixed = (flags >> 0xd) & 0x1; int Tiso = (flags >> 0x6) & 0x1; int Riso = (flags >> 0x5) & 0x1; int Siso = (flags >> 0x4) & 0x1; AnimNode node = new AnimNode(); FOBJ_Player trackX = new FOBJ_Player() { JointTrackType = JointTrackType.HSD_A_J_TRAX }; FOBJ_Player trackY = new FOBJ_Player() { JointTrackType = JointTrackType.HSD_A_J_TRAY }; FOBJ_Player trackZ = new FOBJ_Player() { JointTrackType = JointTrackType.HSD_A_J_TRAZ }; FOBJ_Player trackRX = new FOBJ_Player() { JointTrackType = JointTrackType.HSD_A_J_ROTX }; FOBJ_Player trackRY = new FOBJ_Player() { JointTrackType = JointTrackType.HSD_A_J_ROTY }; FOBJ_Player trackRZ = new FOBJ_Player() { JointTrackType = JointTrackType.HSD_A_J_ROTZ }; FOBJ_Player trackSX = new FOBJ_Player() { JointTrackType = JointTrackType.HSD_A_J_SCAX }; FOBJ_Player trackSY = new FOBJ_Player() { JointTrackType = JointTrackType.HSD_A_J_SCAY }; FOBJ_Player trackSZ = new FOBJ_Player() { JointTrackType = JointTrackType.HSD_A_J_SCAZ }; if (hasS == 1) { ReadKeys(r, node, (int)anim.FrameCount, trackSX, trackSY, trackSZ, Siso == 1, SXfixed == 1, SYfixed == 1, SZfixed == 1, s_type, dataOffset); } if (hasR == 1) { ReadKeys(r, node, (int)anim.FrameCount, trackRX, trackRY, trackRZ, Riso == 1, RXfixed == 1, RYfixed == 1, RZfixed == 1, r_type, dataOffset); } if (hasT == 1) { ReadKeys(r, node, (int)anim.FrameCount, trackX, trackY, trackZ, Tiso == 1, Xfixed == 1, Yfixed == 1, Zfixed == 1, t_type, dataOffset); } if (trackX.Keys.Count > 0) { node.Tracks.Add(trackX); } if (trackY.Keys.Count > 0) { node.Tracks.Add(trackY); } if (trackZ.Keys.Count > 0) { node.Tracks.Add(trackZ); } if (trackRX.Keys.Count > 0) { node.Tracks.Add(trackRX); } if (trackRY.Keys.Count > 0) { node.Tracks.Add(trackRY); } if (trackRZ.Keys.Count > 0) { node.Tracks.Add(trackRZ); } if (trackSX.Keys.Count > 0) { node.Tracks.Add(trackSX); } if (trackSY.Keys.Count > 0) { node.Tracks.Add(trackSY); } if (trackSZ.Keys.Count > 0) { node.Tracks.Add(trackSZ); } foreach (var k in trackRX.Keys) { k.Value = MathHelper.DegreesToRadians(k.Value); k.Tan = MathHelper.DegreesToRadians(k.Tan); } foreach (var k in trackRY.Keys) { k.Value = MathHelper.DegreesToRadians(k.Value); k.Tan = MathHelper.DegreesToRadians(k.Tan); } foreach (var k in trackRZ.Keys) { k.Value = MathHelper.DegreesToRadians(k.Value); k.Tan = MathHelper.DegreesToRadians(k.Tan); } // make sure all tracks start at frame 0 foreach (var track in node.Tracks) { if (track.Keys.Count > 0 && track.Keys[0].Frame != 0) { track.Keys.Insert(0, new FOBJKey() { Frame = 0, Value = track.Keys[0].Value, InterpolationType = GXInterpolationType.HSD_A_OP_CON, }); } } //Console.WriteLine(boneName + " Tracks:" + node.Tracks.Count + " " + flags.ToString("X")); //Console.WriteLine($"{trackX.Keys.Count} {trackY.Keys.Count} {trackZ.Keys.Count}"); //Console.WriteLine($"{trackRX.Keys.Count} {trackRY.Keys.Count} {trackRZ.Keys.Count}"); //Console.WriteLine($"{trackSX.Keys.Count} {trackSY.Keys.Count} {trackSZ.Keys.Count}"); anim.Nodes[jointMap.IndexOf(boneName)] = node; } } return(anim); }
public List <FOBJKey> GetKeys(float FrameCount = -1) { List <FOBJKey> Keys = new List <FOBJKey>(); int clock = 0; Reader.Seek(0); while (Reader.Position < Reader.BaseStream.Length) { int type = Reader.ReadPacked(); GXInterpolationType interpolation = (GXInterpolationType)((type) & 0x0F); int numOfKey = ((type >> 4)) + 1; if (interpolation == 0) { break; } for (int i = 0; i < numOfKey; i++) { double value = 0; double tan = 0; int time = 0; switch (interpolation) { case GXInterpolationType.HSD_A_OP_CON: value = ParseFloat(Reader, FOBJ.ValueFormat, FOBJ.ValueScale); time = Reader.ReadPacked(); break; case GXInterpolationType.HSD_A_OP_LIN: value = ParseFloat(Reader, FOBJ.ValueFormat, FOBJ.ValueScale); time = Reader.ReadPacked(); break; case GXInterpolationType.HSD_A_OP_SPL0: value = ParseFloat(Reader, FOBJ.ValueFormat, FOBJ.ValueScale); time = Reader.ReadPacked(); break; case GXInterpolationType.HSD_A_OP_SPL: value = ParseFloat(Reader, FOBJ.ValueFormat, FOBJ.ValueScale); tan = ParseFloat(Reader, FOBJ.TanFormat, FOBJ.TanScale); time = Reader.ReadPacked(); break; case GXInterpolationType.HSD_A_OP_SLP: tan = ParseFloat(Reader, FOBJ.TanFormat, FOBJ.TanScale); break; case GXInterpolationType.HSD_A_OP_KEY: value = ParseFloat(Reader, FOBJ.ValueFormat, FOBJ.ValueScale); break; default: throw new Exception("Unknown Interpolation Type " + interpolation.ToString("X")); } FOBJKey kf = new FOBJKey(); kf.InterpolationType = interpolation; kf.Value = (float)value; kf.Frame = clock; kf.Tan = (float)tan; Keys.Add(kf); clock += time; } } return(Keys); }
public void Parse(BinaryReaderExt r) { r.BigEndian = true; var start = r.Position; var sectionCount = r.ReadInt32(); var sectionHeaderLength = r.ReadInt32(); PlaySpeed = r.ReadSingle(); EndTime = r.ReadSingle(); for (int j = 0; j < sectionCount; j++) { Joint joint = new Joint(); Joints.Add(joint); joint.Flag1 = r.ReadByte(); joint.Flag2 = r.ReadByte(); joint.Flag3 = r.ReadUInt16(); joint.BoneID = r.ReadInt16(); var floatCount = r.ReadInt16(); joint.MaxTime = r.ReadSingle(); joint.Unknown = r.ReadInt32(); var offset1 = r.ReadUInt32() + start; var offset2 = r.ReadUInt32() + start; var offset3 = r.ReadUInt32() + start; var offset4 = r.ReadUInt32() + start; if (offset3 != start) { throw new NotSupportedException("Section 3 detected"); } if (offset4 != start) { throw new NotSupportedException("Section 4 detected"); } var temp = r.Position; for (uint k = 0; k < floatCount; k++) { Key key = new Key(); r.Seek(offset1 + 4 * k); key.Time = r.ReadSingle(); if (offset2 != start) { r.Seek(offset2 + 8 * k); key.X = BitConverter.ToSingle(BitConverter.GetBytes(((r.ReadByte() & 0xFF) << 24) | ((r.ReadByte() & 0xFF) << 16)), 0); key.Y = BitConverter.ToSingle(BitConverter.GetBytes(((r.ReadByte() & 0xFF) << 24) | ((r.ReadByte() & 0xFF) << 16)), 0); key.Z = BitConverter.ToSingle(BitConverter.GetBytes(((r.ReadByte() & 0xFF) << 24) | ((r.ReadByte() & 0xFF) << 16)), 0); key.W = BitConverter.ToSingle(BitConverter.GetBytes(((r.ReadByte() & 0xFF) << 24) | ((r.ReadByte() & 0xFF) << 16)), 0); } joint.Keys.Add(key); } r.Seek(temp); } }
/// <summary> /// Used in Eighting Engine Games /// </summary> /// <param name="filePath"></param> private void OpenSDI(string filePath) { var sam = filePath.Replace(".sdi", ".sam"); if (!File.Exists(sam)) { return; } using (BinaryReaderExt r = new BinaryReaderExt(new FileStream(filePath, FileMode.Open))) using (BinaryReaderExt d = new BinaryReaderExt(new FileStream(sam, FileMode.Open))) { r.BigEndian = true; while (true) { var id = r.ReadInt32(); if (id == -1) { break; } var dataoffset = r.ReadUInt32(); var padding = r.ReadInt32(); var flags = r.ReadInt16(); var frequency = r.ReadInt16(); var value = r.ReadInt32(); r.Skip(8); // unknown uint coefOffset = r.ReadUInt32(); DSP dsp = new DSP(); dsp.Frequency = frequency; DSPChannel channel = new DSPChannel(); channel.NibbleCount = value; var temp = r.Position; var end = (uint)d.Length; if (r.ReadInt32() != -1) { end = r.ReadUInt32(); } r.Seek(coefOffset); r.ReadInt32(); r.ReadInt32(); for (int i = 0; i < 0x10; i++) { channel.COEF[i] = r.ReadInt16(); } r.Seek(temp); d.Seek(dataoffset); byte[] data = d.ReadBytes((int)(end - dataoffset)); channel.Data = data; channel.InitialPredictorScale = data[0]; dsp.Channels.Add(channel); Sounds.Add(dsp); } } }
/// <summary> /// /// </summary> /// <param name="filePath"></param> /// <returns></returns> public static JointAnimManager LoadCHR0(string filePath, Dictionary <int, string> BoneLabelMap) { JointAnimManager anim = new JointAnimManager(); Dictionary <string, int> nameToIndex = new Dictionary <string, int>(); foreach (var v in BoneLabelMap) { nameToIndex.Add(v.Value, v.Key); anim.Nodes.Add(new AnimNode()); } using (BinaryReaderExt r = new BinaryReaderExt(new FileStream(filePath, FileMode.Open))) { r.BigEndian = true; if (r.BaseStream.Length < 4 || new string(r.ReadChars(4)) != "CHR0") { throw new InvalidDataException("CHR0 file is not valid"); } r.Skip(4); int versionNum = r.ReadInt32(); if (versionNum != 4) { throw new InvalidDataException($"CHR0 version {versionNum} not supported"); } System.Console.WriteLine("Reading Track "); r.Seek(0x10); var indexGroupOffset = r.ReadUInt32(); var animName = r.ReadString(r.ReadInt32(), -1); r.Skip(4); anim.FrameCount = r.ReadUInt16(); int animDataCount = r.ReadUInt16(); r.Skip(8); r.Seek(indexGroupOffset); var sectionOffset = r.ReadUInt32() + indexGroupOffset; int sectionCount = r.ReadInt32(); for (uint i = 0; i < sectionCount; i++) { r.Seek(indexGroupOffset + 8 + 16 * i); r.Skip(4); // id and unknown r.Skip(2); // let r.Skip(2); // right var boneName = r.ReadString(r.ReadInt32() + (int)indexGroupOffset, -1); var dataOffset = r.ReadUInt32() + indexGroupOffset; if (dataOffset == indexGroupOffset) { sectionCount += 1; continue; } if (!nameToIndex.ContainsKey(boneName)) { continue; } r.Seek(dataOffset); var nameOff = r.Position + r.ReadUInt32(); var flags = r.ReadInt32(); int t_type = (flags >> 0x1e) & 0x3; int r_type = (flags >> 0x1b) & 0x7; int s_type = (flags >> 0x19) & 0x3; int hasT = (flags >> 0x18) & 0x1; int hasR = (flags >> 0x17) & 0x1; int hasS = (flags >> 0x16) & 0x1; int Zfixed = (flags >> 0x15) & 0x1; int Yfixed = (flags >> 0x14) & 0x1; int Xfixed = (flags >> 0x13) & 0x1; int RZfixed = (flags >> 0x12) & 0x1; int RYfixed = (flags >> 0x11) & 0x1; int RXfixed = (flags >> 0x10) & 0x1; int SZfixed = (flags >> 0xf) & 0x1; int SYfixed = (flags >> 0xe) & 0x1; int SXfixed = (flags >> 0xd) & 0x1; int Tiso = (flags >> 0x6) & 0x1; int Riso = (flags >> 0x5) & 0x1; int Siso = (flags >> 0x4) & 0x1; AnimNode node = new AnimNode(); FOBJ_Player trackX = new FOBJ_Player() { JointTrackType = JointTrackType.HSD_A_J_TRAX }; FOBJ_Player trackY = new FOBJ_Player() { JointTrackType = JointTrackType.HSD_A_J_TRAY }; FOBJ_Player trackZ = new FOBJ_Player() { JointTrackType = JointTrackType.HSD_A_J_TRAZ }; FOBJ_Player trackRX = new FOBJ_Player() { JointTrackType = JointTrackType.HSD_A_J_ROTX }; FOBJ_Player trackRY = new FOBJ_Player() { JointTrackType = JointTrackType.HSD_A_J_ROTY }; FOBJ_Player trackRZ = new FOBJ_Player() { JointTrackType = JointTrackType.HSD_A_J_ROTZ }; FOBJ_Player trackSX = new FOBJ_Player() { JointTrackType = JointTrackType.HSD_A_J_SCAX }; FOBJ_Player trackSY = new FOBJ_Player() { JointTrackType = JointTrackType.HSD_A_J_SCAY }; FOBJ_Player trackSZ = new FOBJ_Player() { JointTrackType = JointTrackType.HSD_A_J_SCAZ }; if (hasS == 1) { ReadKeys(r, node, (int)anim.FrameCount, trackSX, trackSY, trackSZ, Siso == 1, SXfixed == 1, SYfixed == 1, SZfixed == 1, s_type, dataOffset); } if (hasR == 1) { ReadKeys(r, node, (int)anim.FrameCount, trackRX, trackRY, trackRZ, Riso == 1, RXfixed == 1, RYfixed == 1, RZfixed == 1, r_type, dataOffset); } if (hasT == 1) { ReadKeys(r, node, (int)anim.FrameCount, trackX, trackY, trackZ, Tiso == 1, Xfixed == 1, Yfixed == 1, Zfixed == 1, t_type, dataOffset); } if (trackX.Keys.Count > 1) { node.Tracks.Add(trackX); } if (trackY.Keys.Count > 1) { node.Tracks.Add(trackY); } if (trackZ.Keys.Count > 1) { node.Tracks.Add(trackZ); } if (trackRX.Keys.Count > 1) { node.Tracks.Add(trackRX); } if (trackRY.Keys.Count > 1) { node.Tracks.Add(trackRY); } if (trackRZ.Keys.Count > 1) { node.Tracks.Add(trackRZ); } if (trackSX.Keys.Count > 1) { node.Tracks.Add(trackSX); } if (trackSY.Keys.Count > 1) { node.Tracks.Add(trackSY); } if (trackSZ.Keys.Count > 1) { node.Tracks.Add(trackSZ); } foreach (var k in trackRX.Keys) { k.Value = MathHelper.DegreesToRadians(k.Value); k.Tan = MathHelper.DegreesToRadians(k.Value); } foreach (var k in trackRY.Keys) { k.Value = MathHelper.DegreesToRadians(k.Value); k.Tan = MathHelper.DegreesToRadians(k.Value); } foreach (var k in trackRZ.Keys) { k.Value = MathHelper.DegreesToRadians(k.Value); k.Tan = MathHelper.DegreesToRadians(k.Value); } Console.WriteLine(boneName + " Tracks:" + node.Tracks.Count); Console.WriteLine($"{trackX.Keys.Count} {trackY.Keys.Count} {trackZ.Keys.Count}"); Console.WriteLine($"{trackRX.Keys.Count} {trackRY.Keys.Count} {trackRZ.Keys.Count}"); Console.WriteLine($"{trackSX.Keys.Count} {trackSY.Keys.Count} {trackSZ.Keys.Count}"); anim.Nodes[nameToIndex[boneName]] = node; } } return(anim); }
public static KAR_grCollisionNode KCLtoKAR(string kclFile, out KAR_grCollisionTree tree) { KAR_grCollisionNode node = new KAR_grCollisionNode(); List <KAR_CollisionTriangle> tris = new List <KAR_CollisionTriangle>(); List <GXVector3> verts = new List <GXVector3>(); using (FileStream f = new FileStream(kclFile, FileMode.Open)) using (BinaryReaderExt r = new BinaryReaderExt(f)) { r.BigEndian = true; var posOffset = r.ReadInt32(); var nrmOffset = r.ReadInt32(); var triOffset = r.ReadInt32() + 0x10; var partOffste = r.ReadInt32(); var triCount = (partOffste - triOffset) / 0x10; for (int i = 0; i < triCount; i++) { r.Seek((uint)(triOffset + i * 0x10)); var length = r.ReadSingle(); var pi = r.ReadUInt16(); var di = r.ReadUInt16(); var n1 = r.ReadUInt16(); var n2 = r.ReadUInt16(); var n3 = r.ReadUInt16(); var fl = r.ReadUInt16(); r.Seek((uint)(posOffset + pi * 0xC)); var position = new Vector3(r.ReadSingle(), r.ReadSingle(), r.ReadSingle()); r.Seek((uint)(nrmOffset + di * 0xC)); var direction = new Vector3(r.ReadSingle(), r.ReadSingle(), r.ReadSingle()); r.Seek((uint)(nrmOffset + n1 * 0xC)); var normalA = new Vector3(r.ReadSingle(), r.ReadSingle(), r.ReadSingle()); r.Seek((uint)(nrmOffset + n2 * 0xC)); var normalB = new Vector3(r.ReadSingle(), r.ReadSingle(), r.ReadSingle()); r.Seek((uint)(nrmOffset + n3 * 0xC)); var normalC = new Vector3(r.ReadSingle(), r.ReadSingle(), r.ReadSingle()); var crossA = Vector3.Cross(normalA, direction); var crossB = Vector3.Cross(normalB, direction); var vertex1 = position; var vertex2 = position + crossB * (length / Vector3.Dot(crossB, normalC)); var vertex3 = position + crossA * (length / Vector3.Dot(crossA, normalC)); tris.Add(new KAR_CollisionTriangle() { Flags = 0x81, V1 = verts.Count + 2, V2 = verts.Count + 1, V3 = verts.Count }); // scale vertex1 *= Scale; vertex2 *= Scale; vertex3 *= Scale; vertex1.Y += YTrans; vertex2.Y += YTrans; vertex3.Y += YTrans; verts.Add(new GXVector3() { X = vertex1.X, Y = vertex1.Y, Z = vertex1.Z }); verts.Add(new GXVector3() { X = vertex2.X, Y = vertex2.Y, Z = vertex2.Z }); verts.Add(new GXVector3() { X = vertex3.X, Y = vertex3.Y, Z = vertex3.Z }); } } { var height = verts.Min(e => e.Y) - 10; var v1 = new Vector3(-10000, height, -10000); var v2 = new Vector3(10000, height, -10000); var v3 = new Vector3(10000, height, 10000); var v4 = new Vector3(-10000, height, 10000); tris.Add(new KAR_CollisionTriangle() { Flags = 0x81, V1 = verts.Count, V2 = verts.Count + 1, V3 = verts.Count + 2 }); verts.Add(new GXVector3() { X = v1.X, Y = v1.Y, Z = v1.Z }); verts.Add(new GXVector3() { X = v2.X, Y = v2.Y, Z = v2.Z }); verts.Add(new GXVector3() { X = v3.X, Y = v3.Y, Z = v3.Z }); tris.Add(new KAR_CollisionTriangle() { Flags = 0x81, V1 = verts.Count, V2 = verts.Count + 1, V3 = verts.Count + 2 }); verts.Add(new GXVector3() { X = v1.X, Y = v1.Y, Z = v1.Z }); verts.Add(new GXVector3() { X = v3.X, Y = v3.Y, Z = v3.Z }); verts.Add(new GXVector3() { X = v4.X, Y = v4.Y, Z = v4.Z }); } node.Triangles = tris.ToArray(); node.Vertices = verts.ToArray(); node.Joints = new KAR_CollisionJoint[] { new KAR_CollisionJoint() { VertexStart = 0, VertexSize = verts.Count, FaceStart = 0, FaceSize = tris.Count } }; tree = BucketGen.GenerateBucketPartition(node); return(node); }
public List <FOBJKey> GetKeys(float startframe, float frame_count = -1) { List <FOBJKey> Keys = new List <FOBJKey>(); if (FOBJ.JointTrackType == JointTrackType.HSD_A_J_PTCL) { return(Keys); } float clock = 0;// startframe; Reader.Seek(0); while (Reader.Position < Reader.BaseStream.Length) { int type = Reader.ReadPacked(); GXInterpolationType interpolation = (GXInterpolationType)((type) & 0x0F); int numOfKey = ((type >> 4)) + 1; if (interpolation == 0) { break; } for (int i = 0; i < numOfKey; i++) { double value = 0; double tan = 0; int time = 0; switch (interpolation) { case GXInterpolationType.HSD_A_OP_CON: value = ParseFloat(Reader, FOBJ.ValueFormat, FOBJ.ValueScale); time = Reader.ReadPacked(); break; case GXInterpolationType.HSD_A_OP_LIN: value = ParseFloat(Reader, FOBJ.ValueFormat, FOBJ.ValueScale); time = Reader.ReadPacked(); break; case GXInterpolationType.HSD_A_OP_SPL0: value = ParseFloat(Reader, FOBJ.ValueFormat, FOBJ.ValueScale); time = Reader.ReadPacked(); break; case GXInterpolationType.HSD_A_OP_SPL: value = ParseFloat(Reader, FOBJ.ValueFormat, FOBJ.ValueScale); tan = ParseFloat(Reader, FOBJ.TanFormat, FOBJ.TanScale); time = Reader.ReadPacked(); break; case GXInterpolationType.HSD_A_OP_SLP: tan = ParseFloat(Reader, FOBJ.TanFormat, FOBJ.TanScale); break; case GXInterpolationType.HSD_A_OP_KEY: value = ParseFloat(Reader, FOBJ.ValueFormat, FOBJ.ValueScale); break; default: throw new Exception("Unknown Interpolation Type " + interpolation.ToString("X")); } FOBJKey kf = new FOBJKey(); kf.InterpolationType = interpolation; kf.Value = (float)value; kf.Frame = clock; kf.Tan = (float)tan; Keys.Add(kf); clock += time; } } // hack for animations that don't start on frame 0 if (startframe != 0) { // create a player in order to bake keys FOBJ_Player player = new FOBJ_Player(0, Keys); // move starting frame foreach (var k in Keys) { k.Frame -= startframe; } // remove all keys out of bounds Keys.RemoveAll(e => e.Frame < 0); // bake the keys from frame 0 to first key frame if (Keys.Count > 0 && Keys[0].Frame != 0) { var firstFrame = Keys[0].Frame; for (int i = 0; i < firstFrame; i++) { Keys.Insert(i, new FOBJKey() { Frame = i, Value = player.GetValue(i - startframe), InterpolationType = GXInterpolationType.HSD_A_OP_LIN }); } } } return(Keys); }
public List <FOBJKey> GetKeys(float startframe, float frame_count = -1) { List <FOBJKey> Keys = new List <FOBJKey>(); if (FOBJ.JointTrackType == JointTrackType.HSD_A_J_PTCL) { return(Keys); } float clock = startframe; Reader.Seek(0); while (Reader.Position < Reader.BaseStream.Length) { int type = Reader.ReadPacked(); GXInterpolationType interpolation = (GXInterpolationType)((type) & 0x0F); int numOfKey = ((type >> 4)) + 1; if (interpolation == 0) { break; } for (int i = 0; i < numOfKey; i++) { double value = 0; double tan = 0; int time = 0; switch (interpolation) { case GXInterpolationType.HSD_A_OP_CON: value = ParseFloat(Reader, FOBJ.ValueFormat, FOBJ.ValueScale); time = Reader.ReadPacked(); break; case GXInterpolationType.HSD_A_OP_LIN: value = ParseFloat(Reader, FOBJ.ValueFormat, FOBJ.ValueScale); time = Reader.ReadPacked(); break; case GXInterpolationType.HSD_A_OP_SPL0: value = ParseFloat(Reader, FOBJ.ValueFormat, FOBJ.ValueScale); time = Reader.ReadPacked(); break; case GXInterpolationType.HSD_A_OP_SPL: value = ParseFloat(Reader, FOBJ.ValueFormat, FOBJ.ValueScale); tan = ParseFloat(Reader, FOBJ.TanFormat, FOBJ.TanScale); time = Reader.ReadPacked(); break; case GXInterpolationType.HSD_A_OP_SLP: tan = ParseFloat(Reader, FOBJ.TanFormat, FOBJ.TanScale); break; case GXInterpolationType.HSD_A_OP_KEY: value = ParseFloat(Reader, FOBJ.ValueFormat, FOBJ.ValueScale); break; default: throw new Exception("Unknown Interpolation Type " + interpolation.ToString("X")); } FOBJKey kf = new FOBJKey(); kf.InterpolationType = interpolation; kf.Value = (float)value; kf.Frame = clock; kf.Tan = (float)tan; Keys.Add(kf); clock += time; } } // hack for animations that don't start on frame 0 if (Keys.Count > 0 && Keys[0].Frame != 0) { Keys.Insert(0, new FOBJKey() { Frame = 0, Value = Keys[0].Value, InterpolationType = GXInterpolationType.HSD_A_OP_CON }); } return(Keys); }
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(); } }
/// <summary> /// /// </summary> /// <param name="filePath"></param> /// <returns></returns> public static List <SEMEntry> ReadSEMFile(string filePath, bool loadSoundBanks, MEX_Data mexData = null) { var Entries = new List <SEMEntry>(); Dictionary <int, SSM> indexToSSM = new Dictionary <int, SSM>(); if (loadSoundBanks) { foreach (var f in Directory.GetFiles(Path.GetDirectoryName(filePath))) { if (f.ToLower().EndsWith(".ssm")) { var ssm = new SSM(); ssm.Open(f); indexToSSM.Add(ssm.StartIndex, ssm); } } } //if (!loadSoundBanks) // return Entries; using (BinaryReaderExt r = new BinaryReaderExt(new FileStream(filePath, FileMode.Open))) { r.BigEndian = true; r.Seek(8); var entryCount = r.ReadInt32(); var offsetTableStart = r.Position + (entryCount + 1) * 4; for (uint i = 0; i < entryCount; i++) { SEMEntry e = new SEMEntry(); Entries.Add(e); r.Seek(0x0C + i * 4); var startIndex = r.ReadInt32(); var endIndex = r.ReadInt32(); var ssmStartIndex = int.MaxValue; for (uint j = 0; j < endIndex - startIndex; j++) { SEMScript s = new SEMScript(); r.Seek((uint)(offsetTableStart + startIndex * 4 + j * 4)); var dataOffsetStart = r.ReadUInt32(); var dataOffsetEnd = r.ReadUInt32(); if (dataOffsetEnd == 0) { dataOffsetEnd = (uint)r.Length; } r.Seek(dataOffsetStart); s.CommandData = r.ReadBytes((int)(dataOffsetEnd - dataOffsetStart)); e.AddScript(s); ssmStartIndex = Math.Min(ssmStartIndex, s.SoundCommandIndex); } if (loadSoundBanks && indexToSSM.ContainsKey(ssmStartIndex)) { e.SoundBank = indexToSSM[ssmStartIndex]; if (mexData != null) { var index = mexData.SSMTable.SSM_SSMFiles.Array.ToList().FindIndex(s => s.Value.Equals(e.SoundBank.Name)); if (index != -1) { e.SoundBank.GroupFlags = mexData.SSMTable.SSM_LookupTable[index].EntireFlag; e.SoundBank.Flag = mexData.SSMTable.SSM_BufferSizes[index].Flag; } } foreach (var v in e.Scripts) { v.SoundCommandIndex -= ssmStartIndex; } } } } return(Entries); }
/// <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; } } }