/// <summary> /// Opens dat file from stream /// </summary> /// <param name="stream"></param> public void Open(Stream stream) { using (BinaryReaderExt r = new BinaryReaderExt(stream)) { r.BigEndian = true; Stopwatch sw = new Stopwatch(); sw.Start(); // Parse Header ----------------------------- var fsize = r.ReadInt32(); // dat size int relocOffset = r.ReadInt32() + 0x20; int relocCount = r.ReadInt32(); int rootCount = r.ReadInt32(); int refCount = r.ReadInt32(); VersionChars = r.ReadChars(4); // Parse Relocation Table ----------------------------- List <int> Offsets = new List <int>(); HashSet <int> OffsetContain = new HashSet <int>(); Dictionary <int, int> relocOffsets = new Dictionary <int, int>(); Offsets.Add(relocOffset); for (int i = 0; i < relocCount; i++) { r.BaseStream.Position = relocOffset + 4 * i; int offset = r.ReadInt32() + 0x20; r.BaseStream.Position = offset; var objectOff = r.ReadInt32() + 0x20; // if we need to read past end of file then we need to include filesize as an offset // this fixes files that had previously been manually relocated to end of file if (objectOff > relocOffset && !OffsetContain.Contains(fsize)) { Offsets.Add(fsize); } // alternate null pointer if (objectOff < 0) { continue; } relocOffsets.Add(offset, objectOff); if (!OffsetContain.Contains(objectOff)) { OffsetContain.Add(objectOff); Offsets.Add(objectOff); } } Debug.WriteLine("Relocate Parsed: " + sw.ElapsedMilliseconds); sw.Restart(); // Parse Roots--------------------------------- r.BaseStream.Position = relocOffset + relocCount * 4; List <int> rootOffsets = new List <int>(); List <string> rootStrings = new List <string>(); List <int> refOffsets = new List <int>(); List <string> refStrings = new List <string>(); var stringStart = r.BaseStream.Position + (refCount + rootCount) * 8; for (int i = 0; i < rootCount; i++) { rootOffsets.Add(r.ReadInt32() + 0x20); rootStrings.Add(r.ReadString((int)stringStart + r.ReadInt32(), -1)); } for (int i = 0; i < refCount; i++) { var refp = r.ReadInt32() + 0x20; refOffsets.Add(refp); refStrings.Add(r.ReadString((int)stringStart + r.ReadInt32(), -1)); var temp = r.Position; var special = refp; while (true) { r.Seek((uint)special); special = r.ReadInt32(); if (special == 0 || special == -1) { break; } special += 0x20; relocOffsets.Add(refp, special); refp = special; if (!OffsetContain.Contains(special)) { OffsetContain.Add(special); Offsets.Add(special); } } r.Seek(temp); } foreach (var v in rootOffsets) { if (!OffsetContain.Contains(v)) { OffsetContain.Add(v); Offsets.Add(v); } } foreach (var v in refOffsets) { if (!OffsetContain.Contains(v)) { OffsetContain.Add(v); Offsets.Add(v); } } Debug.WriteLine("Roots Parsed: " + sw.ElapsedMilliseconds); sw.Restart(); // Split Raw Struct Data-------------------------- Offsets.Sort(); Debug.WriteLine("Sorted: " + sw.ElapsedMilliseconds); sw.Restart(); Dictionary <int, HSDStruct> offsetToStruct = new Dictionary <int, HSDStruct>(); Dictionary <int, List <int> > offsetToOffsets = new Dictionary <int, List <int> >(); Dictionary <int, List <int> > offsetToInnerOffsets = new Dictionary <int, List <int> >(); var relockeys = relocOffsets.Keys.ToList(); relockeys.Sort(); for (int i = 0; i < Offsets.Count - 1; i++) { r.BaseStream.Position = Offsets[i]; byte[] data = r.ReadBytes(Offsets[i + 1] - Offsets[i]); if (!offsetToOffsets.ContainsKey(Offsets[i])) { var relocKets = new List <int>(); var list = new List <int>(); var min = BinarySearch(relockeys, Offsets[i]); var max = BinarySearch(relockeys, Offsets[i + 1]) + 1; if (min != -1 && max != -1) { for (int v = min; v < max; v++) { if (relockeys[v] >= Offsets[i] && relockeys[v] < Offsets[i + 1]) { relocKets.Add(relockeys[v]); list.Add(relocOffsets[relockeys[v]]); } } } offsetToOffsets.Add(Offsets[i], list); offsetToInnerOffsets.Add(Offsets[i], relocKets); } if (!offsetToStruct.ContainsKey(Offsets[i])) { var struture = new HSDStruct(data); offsetToStruct.Add(Offsets[i], struture); } } Debug.WriteLine("Find All Parsed: " + sw.ElapsedMilliseconds); sw.Restart(); HashSet <HSDStruct> orphans = new HashSet <HSDStruct>(); foreach (var str in offsetToStruct) { orphans.Add(str.Value); } // set references------------------------- foreach (var str in offsetToStruct) { var _o = str.Key; var _s = str.Value; var offsets = offsetToOffsets[_o]; var innerOffsets = offsetToInnerOffsets[_o]; // set references in struct for (int i = 0; i < offsets.Count; i++) { if (offsetToStruct.ContainsKey(offsets[i]) && _s.Length >= innerOffsets[i] - _o + 4) { var refstruct = offsetToStruct[offsets[i]]; _s.SetReferenceStruct(innerOffsets[i] - _o, refstruct); // this not is not an orphan if (refstruct != _s && orphans.Contains(refstruct)) { orphans.Remove(refstruct); } } } _structCache.Add(str.Value); _structCacheToOffset.Add(str.Value, str.Key); } Debug.WriteLine("Set References: " + sw.ElapsedMilliseconds); sw.Restart(); // set roots for (int i = 0; i < rootOffsets.Count; i++) { HSDStruct str = offsetToStruct[rootOffsets[i]]; HSDAccessor a = GuessAccessor(rootStrings[i], str); Roots.Add(new HSDRootNode() { Name = rootStrings[i], Data = a }); if (orphans.Contains(str)) { orphans.Remove(str); } } // set references for (int i = 0; i < refOffsets.Count; i++) { HSDStruct str = offsetToStruct[refOffsets[i]]; HSDAccessor a = new HSDAccessor(); a._s = str; References.Add(new HSDRootNode() { Name = refStrings[i], Data = a }); if (orphans.Contains(str)) { orphans.Remove(str); } } // process special orphans foreach (var orphan in orphans) { HSDStruct str = orphan; HSDAccessor a = new HSDAccessor() { _s = str }; // hack: if this is a subaction append it to previous struct if (str.References.Count > 0) { var maxkey = str.References.Keys.Max(); if (str.References[maxkey] == str && maxkey >= 8 && str.GetInt32(maxkey - 4) == 0x1C000000) { // get previous struct var prev = GetPreviousStruct(str); // add goto pointer to subaction if (prev != null) { var len = prev.Length; prev.Resize(prev.Length + 8); prev.SetInt32(len, 0x1C000000); prev.SetReferenceStruct(len + 4, str); continue; } } } #if DEBUG // add orphans for debugging Roots.Add(new HSDRootNode() { Name = "Orphan0x" + _structCacheToOffset[orphan].ToString("X"), Data = a }); #endif } Debug.WriteLine("Finish: " + sw.ElapsedMilliseconds); sw.Restart(); } }
/// <summary> /// Opens dat file from stream /// </summary> /// <param name="stream"></param> public void Open(Stream stream) { using (BinaryReaderExt r = new BinaryReaderExt(stream)) { r.BigEndian = true; // Parse Header ----------------------------- var fsize = r.ReadInt32(); // dat size int relocOffset = r.ReadInt32() + 0x20; int relocCount = r.ReadInt32(); int rootCount = r.ReadInt32(); int refCount = r.ReadInt32(); VersionChars = r.ReadChars(4); // Parse Relocation Table ----------------------------- List <int> Offsets = new List <int>(); HashSet <int> OffsetContain = new HashSet <int>(); Dictionary <int, int> relocOffsets = new Dictionary <int, int>(); Offsets.Add(relocOffset); r.BaseStream.Position = relocOffset; for (int i = 0; i < relocCount; i++) { int offset = r.ReadInt32() + 0x20; var temp = r.BaseStream.Position; r.BaseStream.Position = offset; var objectOff = r.ReadInt32() + 0x20; // if we need to read past end of file then we need to include filesize as an offset // this fixes files that had previously been manually relocated to end of file if (objectOff > relocOffset && !Offsets.Contains(fsize)) { Offsets.Add(fsize); } // if (objectOff < 0) { r.BaseStream.Position = temp; continue; } relocOffsets.Add(offset, objectOff); if (!OffsetContain.Contains(objectOff)) { OffsetContain.Add(objectOff); Offsets.Add(objectOff); } r.BaseStream.Position = temp; } // Parse Roots--------------------------------- List <int> rootOffsets = new List <int>(); List <string> rootStrings = new List <string>(); List <int> refOffsets = new List <int>(); List <string> refStrings = new List <string>(); var stringStart = r.BaseStream.Position + (refCount + rootCount) * 8; for (int i = 0; i < rootCount; i++) { rootOffsets.Add(r.ReadInt32() + 0x20); rootStrings.Add(r.ReadString((int)stringStart + r.ReadInt32(), -1)); } for (int i = 0; i < refCount; i++) { var refp = r.ReadInt32() + 0x20; refOffsets.Add(refp); refStrings.Add(r.ReadString((int)stringStart + r.ReadInt32(), -1)); var temp = r.Position; var special = refp; while (true) { r.Seek((uint)special); special = r.ReadInt32(); if (special == 0 || special == -1) { break; } special += 0x20; relocOffsets.Add(refp, special); refp = special; if (!OffsetContain.Contains(special)) { OffsetContain.Add(special); Offsets.Add(special); } } r.Seek(temp); } foreach (var v in rootOffsets) { if (!OffsetContain.Contains(v)) { OffsetContain.Add(v); Offsets.Add(v); } } foreach (var v in refOffsets) { if (!OffsetContain.Contains(v)) { OffsetContain.Add(v); Offsets.Add(v); } } // Split Raw Struct Data-------------------------- Offsets.Sort(); Dictionary <int, HSDStruct> offsetToStruct = new Dictionary <int, HSDStruct>(); Dictionary <int, List <int> > offsetToOffsets = new Dictionary <int, List <int> >(); Dictionary <int, List <int> > offsetToInnerOffsets = new Dictionary <int, List <int> >(); var relockeys = relocOffsets.Keys.ToList(); for (int i = 0; i < Offsets.Count - 1; i++) { r.BaseStream.Position = Offsets[i]; byte[] data = r.ReadBytes(Offsets[i + 1] - Offsets[i]); if (!offsetToOffsets.ContainsKey(Offsets[i])) { var relocKets = relockeys.FindAll(e => e >= Offsets[i] && e < Offsets[i + 1]); var list = new List <int>(); foreach (var k in relocKets) { list.Add(relocOffsets[k]); } offsetToOffsets.Add(Offsets[i], list); offsetToInnerOffsets.Add(Offsets[i], relocKets); } if (!offsetToStruct.ContainsKey(Offsets[i])) { var struture = new HSDStruct(data); offsetToStruct.Add(Offsets[i], struture); } } // set references------------------------- foreach (var str in offsetToStruct) { var offsets = offsetToOffsets[str.Key]; var innerOffsets = offsetToInnerOffsets[str.Key]; for (int i = 0; i < offsets.Count; i++) { if (offsetToStruct.ContainsKey(offsets[i]) && str.Value.Length >= innerOffsets[i] - str.Key + 4) { str.Value.SetReferenceStruct(innerOffsets[i] - str.Key, offsetToStruct[offsets[i]]); } } _structCache.Add(str.Value); _structCacheToOffset.Add(str.Value, str.Key); } // set roots for (int i = 0; i < rootOffsets.Count; i++) { HSDStruct str = offsetToStruct[rootOffsets[i]]; HSDAccessor a = new HSDAccessor(); a._s = str; if (rootStrings[i].EndsWith("shapeanim_joint")) { var acc = new HSDAccessor(); acc._s = str; a = acc; } else if (rootStrings[i].EndsWith("matanim_joint")) { var acc = new HSD_MatAnimJoint(); acc._s = str; a = acc; } else if (rootStrings[i].EndsWith("_joint")) { var jobj = new HSD_JOBJ(); jobj._s = str; a = jobj; } else if (rootStrings[i].EndsWith("_animjoint")) { var jobj = new HSD_AnimJoint(); jobj._s = str; a = jobj; } else if (rootStrings[i].EndsWith("_texanim")) { var jobj = new HSD_TexAnim(); jobj._s = str; a = jobj; } else if (rootStrings[i].EndsWith("_figatree")) { var jobj = new HSD_FigaTree(); jobj._s = str; a = jobj; } else if (rootStrings[i].EndsWith("_scene_models") || rootStrings[i].Equals("Stc_rarwmdls") || rootStrings[i].Equals("Stc_scemdls") || rootStrings[i].Equals("lupe") || rootStrings[i].Equals("tdsce")) { var jobj = new HSDNullPointerArrayAccessor <HSD_JOBJDesc>(); jobj._s = str; a = jobj; } else if (rootStrings[i].StartsWith("ftData")) { var acc = new SBM_PlayerData(); acc._s = str; a = acc; } else if (rootStrings[i].EndsWith("MnSelectChrDataTable")) { var acc = new SBM_SelectChrDataTable(); acc._s = str; a = acc; } else if (rootStrings[i].EndsWith("MnSelectStageDataTable")) { var acc = new SBM_MnSelectStageDataTable(); acc._s = str; a = acc; } else if (rootStrings[i].EndsWith("coll_data")) { var acc = new SBM_Coll_Data(); acc._s = str; a = acc; } else if (rootStrings[i].EndsWith("scene_data") || rootStrings[i].Equals("pnlsce") || rootStrings[i].Equals("flmsce") || (rootStrings[i].StartsWith("Sc") && str.Length == 0x10)) { var acc = new HSD_SOBJ(); acc._s = str; a = acc; } else if (rootStrings[i].StartsWith("map_plit")) { var acc = new HSDNullPointerArrayAccessor <HSD_Light>(); acc._s = str; a = acc; } /*else * if (rootStrings[i].StartsWith("grGroundParam")) * { * var acc = new SBM_GroundParam(); * acc._s = str; * a = acc; * }*/ else if (rootStrings[i].StartsWith("map_head")) { var acc = new SBM_Map_Head(); acc._s = str; a = acc; } else if (rootStrings[i].StartsWith("grGroundParam")) { var acc = new SBM_GroundParam(); acc._s = str; a = acc; } else if (rootStrings[i].StartsWith("vcDataStar")) { var acc = new KAR_vcDataStar(); acc._s = str; a = acc; } else if (rootStrings[i].StartsWith("vcDataWheel")) { var acc = new KAR_vcDataWheel(); acc._s = str; a = acc; } else if (rootStrings[i].StartsWith("grModelMotion")) { var acc = new KAR_grModelMotion(); acc._s = str; a = acc; } else if (rootStrings[i].StartsWith("grModel")) { var acc = new KAR_grModel(); acc._s = str; a = acc; } else if (rootStrings[i].StartsWith("grData")) { var acc = new KAR_grData(); acc._s = str; a = acc; } else if (rootStrings[i].EndsWith("_texg")) { var acc = new HSD_TEXGraphicBank(); acc._s = str; a = acc; } else if (rootStrings[i].EndsWith("_ptcl")) { var acc = new HSD_ParticleGroup(); acc._s = str; a = acc; } else if (rootStrings[i].StartsWith("eff")) { var acc = new SBM_EffectTable(); acc._s = str; a = acc; } Roots.Add(new HSDRootNode() { Name = rootStrings[i], Data = a }); } // set references for (int i = 0; i < refOffsets.Count; i++) { HSDStruct str = offsetToStruct[refOffsets[i]]; HSDAccessor a = new HSDAccessor(); a._s = str; References.Add(new HSDRootNode() { Name = refStrings[i], Data = a }); } } }