internal void Read(BinaryReader reader) { reader.BaseStream.Position = Offset + 12; Unknowns.ReadInt32s(reader, 1); Unknowns.ReadInt16s(reader, 2); Unknowns.ReadInt32s(reader, 1); if (Format != null) { int length = DataLength; if (Format.Header != null) { Header = new MissionTableHeader(this, Format.Header, reader); length -= Format.Header.Size; } if (length % Format.Row.Size != 0) { throw new InvalidDataException(); } int count = length / Format.Row.Size; for (int index = 0; index < count; index++) { new MissionRow(this, Format.Row, reader); } } }
internal PictureCel(Picture picture, int celIndex, AssetLoader loader) : base(loader) { Name = "Cel " + celIndex; BinaryReader reader = loader.Reader; reader.BaseStream.Position = 0x0E + celIndex * 0x2A; Vector2i dimensions = new Vector2i(reader.ReadUInt16(), reader.ReadUInt16()); Displacement = new Vector2i(reader.ReadUInt16(), reader.ReadUInt16()); MaskIndex = reader.ReadByte(); loader.ExpectZeroes(1, 3); Unknowns.ReadInt32s(reader, 2, "Data offsets?"); loader.ExpectZeroes(4, 1); int dataOffset = reader.ReadInt32(); loader.ExpectZeroes(4, 2); Priority = reader.ReadUInt16(); Offset = new Vector2i(reader.ReadUInt16(), reader.ReadUInt16()) * 2; if (Offset.Y > 0) { Offset = new Vector2i(Offset.X, Offset.Y * 6 / 5); } reader.BaseStream.Position = dataOffset; int[] indices = reader.ReadBytesAsInt32(dimensions.Product); Setup(picture.Palette.PaletteAsset, dimensions.X, dimensions.Y, indices); }
internal Point(Table table, int index, AssetLoader loader) : base(table, index) { BinaryReader reader = loader.Reader; long start = reader.BaseStream.Position; loader.Expect(HeaderLength); loader.ExpectZeroes(4, 1); // Probably type, always zero. loader.Expect(index); // Zero-based index of the row with this type. Subtype = reader.ReadInt32(); Position = new Vector3f(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); Rotation = Angle3.Degrees(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); int unknown1Offset = reader.ReadInt32(); // Offset to Unknown1 from start of row. int unknown2Offset = reader.ReadInt32(); // Offset to Unknown2 from start of row (Unknown1Offset + 4). int unknown3Offset = reader.ReadInt32(); // Offset to Unknown3 from start of row, or 0 if none (Unknown2Offset + 4). int unknown4Offset = reader.ReadInt32(); // Offset to Unknown3 from start of row (Unknown2Offset + 4 or Unknown3Offset + 12). loader.ExpectZeroes(4, 1); Name = reader.ReadStringz(EncodingShiftJis); reader.BaseStream.Position = start + unknown1Offset; loader.ExpectZeroes(4, 2); // Unknown1 and Unknown2 if (unknown3Offset != 0) { Unknowns.ReadSingles(reader, 3); } Unknowns.ReadInt32s(reader, 1); // -1 or values like 1002000 for events. var errors = loader.Errors; }
internal TextureArchiveRecord(TextureArchive archive, BinaryReader reader, ByteOrder order) : base(archive, "") { Offset = reader.ReadInt32(order); Size = reader.ReadInt32(order); if (Archive.Platform == DSPlatform.PS3) { int format = reader.ReadInt16(order); Id = reader.ReadInt16(order); Ps3Dimensions = new Vector2i(reader.ReadUInt16(order), reader.ReadUInt16(order)); switch (format) { case 0: Ps3Format = Glare.Graphics.Formats.DXT1; break; case 0x0500: Ps3Format = Glare.Graphics.Formats.DXT5; break; case 0x0900: Ps3Format = Glare.Graphics.Formats.Vector4nb; break; default: throw new NotSupportedException(string.Format("PS3 format 0x{0:X4} (dimensions {1}, data size {2}) is not known.", format, Ps3Dimensions, Size)); } Unknowns.ReadInt32s(reader, 1); reader.RequireZeroes(4); } else { Id = reader.ReadInt32(order); } Name = reader.ReadStringzAtUInt32(order, Alexandria.Engines.DarkSouls.Archive.ShiftJis); reader.RequireZeroes(4); }
internal MCGTable3(MCG mcg, int index, AssetLoader loader) : base(mcg, index) { var reader = loader.Reader; int count = reader.ReadInt32(); Position = reader.ReadVector3f(); Table1U1 = mcg.GetTable1Slice(count, reader.ReadInt32()); Table1U2 = mcg.GetTable1Slice(count, reader.ReadInt32()); Unknowns.ReadInt32s(reader, 2); }
internal MCPTable2(MCP mcp, int index, AssetLoader loader) : base(mcp, index) { var reader = loader.Reader; Unknowns.ReadInt32s(reader, 1); loader.Expect(index); int count1 = reader.ReadInt32(); int offset1 = reader.ReadInt32(); Table1U1 = mcp.GetTable1Slice(count1, offset1); Box = loader.ReadCheckedAbsoluteBox3f(); }
internal Model(Table table, int index, AssetLoader loader) : base(table, index) { BinaryReader reader = loader.Reader; loader.Expect(HeaderLength); Type = (ModelType)reader.ReadInt32(); Index = reader.ReadInt32(); int contentSize = reader.ReadInt32(); // Size from start to end of Name Unknowns.ReadInt32s(reader, 1); loader.ExpectZeroes(4, 3); Name = reader.ReadStringz(EncodingShiftJis); Path = reader.ReadStringz(EncodingShiftJis); }
internal ModelMesh(FolderAsset folder, int index, AssetLoader loader) : base(folder, index, loader) { var reader = loader.Reader; Unknowns.ReadInt32s(reader, 1); // 1? MaterialIndex = reader.ReadInt32(); reader.RequireZeroes(4 * 2); Unknowns.ReadInt32s(reader, 1); // 0 or 1, seems to be material-related but is not transparency; second seems bones-related int boneCount = reader.ReadInt32(); reader.RequireZeroes(4 * 1); int boneIndicesOffset = reader.ReadInt32(); PartCount = reader.ReadInt32(); int partIndicesOffset = reader.ReadInt32(); reader.Require(1); int indexOffset = reader.ReadInt32(); long reset = reader.BaseStream.Position; reader.BaseStream.Position = boneIndicesOffset; var bones = new Codex <ModelBone>(); Bones = bones; for (int i = 0; i < boneCount; i++) { bones.Add(Model.Bones[reader.ReadInt32()]); } // Read the part indices. reader.BaseStream.Position = partIndicesOffset; int partStart = PartStartIndex; for (int i = 0; i < PartCount; i++) { reader.Require(i + partStart); } reader.BaseStream.Position = indexOffset; reader.Require(Index); reader.BaseStream.Position = reset; }
internal ParameterTable(AssetLoader loader) : base(loader) { var reader = loader.Reader; int stringsOffset = reader.ReadInt32(); int firstRowDataOffset = reader.ReadUInt16(); Unknowns.ReadInt16s(reader, 2); int rowCount = reader.ReadUInt16(); Name = reader.ReadStringz(0x20, Encoding.ASCII); Unknowns.ReadInt32s(reader, 1); // Read in the row headers. RowInfo[] rows = new RowInfo[rowCount]; for (int index = 0; index < rowCount; index++) { rows[index].Read(reader); } // Read in the rows. for (int index = 0; index < rowCount; index++) { loader.Position = rows[index].DataOffset; int next = index < rows.Length - 1 ? rows[index + 1].DataOffset : stringsOffset; ParameterTableRow item = ParameterTableRow.ReadRow(this, index, loader, next); item.Id = rows[index].Id; if (loader.Position != next) { loader.AddError(rows[index].DataOffset, "Row {0} of the table did not read the correct amount; position should be {1}, but is {2}.", index, next, loader.Position); } } // Read in the row names. for (int index = 0; index < rowCount; index++) { loader.Position = rows[index].NameOffset; ((ParameterTableRow)Children[index]).Name = reader.ReadStringz(EncodingShiftJis).Trim(); //((index < rows.Length - 1 ? rows[index + 1].NameOffset : loader.ShortLength) - rows[index].NameOffset - 1, EncodingShiftJis)); } }
internal ModelBone(FolderAsset folder, int index, AssetLoader loader) : base(folder, index, loader) { var reader = loader.Reader; Position = reader.ReadVector3f(); Name = reader.ReadStringzAtUInt32(Encoding); Angle = Angle3.Radians(reader.ReadVector3f()); parentIndex = reader.ReadInt16(); firstChildIndex = reader.ReadInt16(); Scale = reader.ReadVector3f(); nextSiblingIndex = reader.ReadInt16(); previousSiblingIndex = reader.ReadInt16(); var min = reader.ReadVector3f(); Unknowns.ReadInt32s(reader, 1); // 0 or 1 var max = reader.ReadVector3f(); Bounds = new Box3f(min, max); reader.RequireZeroes(4 * 13); }
internal ModelMaterial(FolderAsset parent, int index, AssetLoader loader) : base(parent, index, loader) { var reader = loader.Reader; Name = reader.ReadStringzAtUInt32(Encoding); ShaderName = reader.ReadStringzAtUInt32(Encoding); ParameterCount = reader.ReadInt32(); int parameterStartIndex = reader.ReadInt32(); Unknowns.ReadInt32s(reader, 1); if (IsDS2) { Unknowns.ReadInt32s(reader, 1); } reader.RequireZeroes(4 * (IsDS1 ? 3 : 2)); if (parameterStartIndex != ParameterStartIndex) { throw new InvalidDataException("Parameter start index is not valid."); } }
internal MCGTable2(MCG mcg, int index, AssetLoader loader) : base(mcg, index) { var reader = loader.Reader; Unknowns.ReadInt32s(reader, 1); int count1 = reader.ReadInt32(); int offset1 = reader.ReadInt32(); Table1U1 = mcg.GetTable1Slice(count1, offset1); Unknowns.ReadInt32s(reader, 1); int count2 = reader.ReadInt32(); int offset2 = reader.ReadInt32(); Table1U2 = mcg.GetTable1Slice(count2, offset2); Unknowns.ReadInt32s(reader, 2); Unknowns.ReadSingles(reader, 1); }
internal Event(Table table, int index, AssetLoader loader, int next) : base(table, index) { BinaryReader reader = loader.Reader; long start = loader.Position; loader.Expect(HeaderLength); Unknowns.ReadInt32s(reader, 1); Type = reader.ReadInt32(); Index = reader.ReadInt32(); int offseta = reader.ReadInt32(); int offsetb = reader.ReadInt32(); if (offsetb != offseta + 0x10) { loader.AddError(start, "{0} index {1} does not have a normal offset A/B", GetType().Name, index); } loader.ExpectZeroes(4, 1); Name = reader.ReadStringz(EncodingShiftJis); loader.Position = start + offseta; Unknowns.ReadInt32s(reader, 4); Unknowns.ReadInt32s(reader, (next - (int)loader.Position) / 4); }
internal Part(Table table, int index, AssetLoader loader, int next) : base(table, index) { BinaryReader reader = loader.Reader; long start = reader.BaseStream.Position; loader.Expect(HeaderLength); Type = (ModelType)reader.ReadInt32(); Unknowns.ReadInt32s(reader, 1); Index = reader.ReadInt32(); int pathOffset = reader.ReadInt32(); Position = reader.ReadVector3f(); Rotation = Angle3.Degrees(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); Scale = reader.ReadVector3f(); Unknowns.ReadInt32s(reader, 8); int offset1 = reader.ReadInt32(); int offset2 = reader.ReadInt32(); if (offset1 + 0x18 != offset2) { loader.AddError(start, "Offset2 is not correct."); } loader.ExpectZeroes(4, 1); Name = reader.ReadStringz(EncodingShiftJis); Path = reader.ReadStringz(EncodingShiftJis); loader.Position = start + offset1; Unknowns.ReadInt32s(reader, 6, "Offset1s"); if (loader.Position > next || (next - loader.Position) / 4 > 64) { } Unknowns.ReadInt32s(reader, (int)(next - loader.Position) / 4, "Offset2s"); }
internal ArchiveRecord(Archive archive, int index, BinaryReader reader, int recordHeaderSize) : base(archive, "") { archive.records.Add(this); Index = index; switch (archive.Variant) { case ArchiveVariant.V3: reader.Require(0x40); Size = reader.ReadInt32(); Offset = reader.ReadInt32(); Id = reader.ReadInt32(); Name = reader.ReadStringzAtUInt32(Archive.ShiftJis); int size2 = reader.ReadInt32(); if (Size != size2) { throw new Exception(); } fixedUncompressedSize = Size; break; case ArchiveVariant.V4: Compression = reader.ReadInt32(); // 2 or 3 - compression? reader.ReadMatch(-1); Size = reader.ReadInt64(); if (recordHeaderSize == 0x1C) { Offset = reader.ReadInt64(); Name = reader.ReadStringzAtUInt32(Archive.ShiftJis); } else { fixedUncompressedSize = reader.ReadInt64(); Offset = reader.ReadUInt32(); Unknowns.ReadInt32s(reader, 1); // 'Compression' = 2, Unknown = 0, Encoding = UTF8 Name = reader.ReadStringzAtUInt32(Archive.ShiftJis); } Id = DarkSouls.Archive.HashFilename(Name); break; case ArchiveVariant.V5: Id = reader.ReadInt32(); Size = reader.ReadInt32(); Offset = reader.ReadInt32(); reader.RequireZeroes(4); // NameOffset, but zero? string foundName; if (!Archive.KnownFiles.TryGetValue(Id, out foundName)) { Name = string.Format("#{0:X}", Id); } else { Name = foundName; } break; default: throw new NotImplementedException(); } MoveIntoPath(Name); }
internal Model(AssetLoader loader) : base(loader) { Asset context = loader.Context; string name = loader.Name; BinaryReader reader = loader.Reader; FolderAsset textureArchive = null; FolderAsset bonesFolder = new FolderAsset(this, "Bones"); FolderAsset materialsFolder = new FolderAsset(this, "Materials"); FolderAsset meshesFolder = new FolderAsset(this, "Meshes"); FolderAsset vertexDeclarationsFolder = new FolderAsset(this, "Vertex declarations"); ArrayBackedList <byte> bufferData = new ArrayBackedList <byte>(); if (context != null && context.Parent is FolderAsset) { // @"/map/m##_##_##_##/m*.flver.dcx" for DS1; textures are in the @"/map/m##/" folder. if (name.StartsWith(@"map/m")) { string folderName = name.Substring(4, 3); FolderAsset maps = (FolderAsset)context.Parent.Parent; foreach (FolderAsset child in maps.Children) { if (child.Name == folderName) { textureArchive = child; break; } } } else { textureArchive = (FolderAsset)context.Parent; } } #if Marking MarkingStream markingStream = loader.StartMarking(out reader); #endif loader.ExpectMagic(Magic); char endian = (char)reader.ReadByte(); switch (endian) { case 'L': ByteOrder = ByteOrder.LittleEndian; break; case 'B': reader = loader.MakeBigEndian(); ByteOrder = ByteOrder.BigEndian; break; default: throw new Exception(); } using (reader) { // Read header. loader.Expect((byte)0); Version = (ModelVersion)reader.ReadInt32(); if (Version != ModelVersion.DarkSouls && Version != ModelVersion.DarkSouls2) { loader.AddError(loader.Position - 4, "Unknown model version " + VersionString + "; will try to load it anyway."); } int dataOffset = reader.ReadInt32(); int dataSize = reader.ReadInt32(); if (((dataOffset + dataSize + 31) & ~31) != reader.BaseStream.Length) { loader.AddError(loader.Position - 4, "Data size and offset aren't correct."); } int boneUnknownCount = reader.ReadInt32(); int materialCount = reader.ReadInt32(); int boneCount = reader.ReadInt32(); int meshCount = reader.ReadInt32(); int meshCount2 = reader.ReadInt32(); if (meshCount != meshCount2) { loader.AddError(loader.Position - 4, "Mesh count 1 and 2 aren't the same."); } Bounds = new Box3f(reader.ReadVector3f(), reader.ReadVector3f()); Unknowns.ReadInt32s(reader, 1); // Possible the non-degenerate triangle count. Seems related. int triangleCount = reader.ReadInt32(); loader.Expect(IsDS1 ? 272 : 0x10010100); loader.Expect(IsDS1 ? 0 : 0xFFFF); int partCount = reader.ReadInt32(); int vertexDeclarationCount = reader.ReadInt32(); int materialParameterCount = reader.ReadInt32(); loader.Expect(IsDS1 ? 0 : 0x1000000); loader.ExpectZeroes(4, 8); // Calculate offsets. long boneUnknownsOffset = HeaderSize; long materialsOffset = boneUnknownsOffset + boneUnknownCount * ModelBoneUnknown.DataSize; long bonesOffset = materialsOffset + materialCount * ModelMaterial.DataSize; long meshesOffset = bonesOffset + boneCount * ModelBone.DataSize; long detailLevelsOffset = meshesOffset + meshCount * ModelMesh.DataSize; long meshVerticesOffset = detailLevelsOffset + partCount * ModelDetailLevel.DataSize; long vertexDeclarationsOffset = meshVerticesOffset + meshCount * ModelMesh.DataSizeVertexHeader; long materialParametersOffset = vertexDeclarationsOffset + vertexDeclarationCount * ModelVertexDeclaration.DataSize; long postHeaderOffset = materialParametersOffset + materialParameterCount * ModelMaterialParameter.DataSize; // BoneUnknowns ExpectedOffset(loader, boneUnknownsOffset, typeof(ModelBoneUnknown).Name); for (int index = 0; index < boneUnknownCount; index++) { boneUnknowns.Add(new ModelBoneUnknown(bonesFolder, index, loader)); } // Materials ExpectedOffset(loader, materialsOffset, typeof(ModelMaterial).Name); for (int index = 0; index < materialCount; index++) { materials.Add(new ModelMaterial(materialsFolder, index, loader)); } int expectedMaterialParameterCount = materialCount > 0 ? materials[materialCount - 1].ParameterEndIndex : 0; if (expectedMaterialParameterCount != materialParameterCount) { loader.AddError(null, "Expected material parameter count {0} doesn't match actual count {1}.", expectedMaterialParameterCount, materialParameterCount); } // Bones ExpectedOffset(loader, bonesOffset, typeof(ModelBone).Name); for (int index = 0; index < boneCount; index++) { bones.Add(new ModelBone(bonesFolder, index, loader)); } // Meshes ExpectedOffset(loader, meshesOffset, typeof(ModelMesh).Name); for (int index = 0; index < meshCount; index++) { meshes.Add(new ModelMesh(meshesFolder, index, loader)); } int expectedPartCount = meshCount > 0 ? meshes[meshCount - 1].PartEndIndex : 0; if (expectedPartCount != partCount) { throw new InvalidDataException("Expected part count doesn't match actual count."); } // Detail levels ExpectedOffset(loader, detailLevelsOffset, typeof(ModelDetailLevel).Name); foreach (ModelMesh mesh in meshes) { mesh.ReadDetailLevels(loader, dataOffset, bufferData); detailLevels.AddRange(mesh.DetailLevels); } // Mesh vertices ExpectedOffset(loader, meshVerticesOffset, typeof(ModelMesh).Name + " vertex header"); foreach (ModelMesh mesh in meshes) { mesh.ReadVertexHeaders(reader, dataOffset, bufferData); } // Vertex declarations ExpectedOffset(loader, vertexDeclarationsOffset, typeof(ModelVertexDeclaration).Name); for (int index = 0; index < vertexDeclarationCount; index++) { vertexDeclarations.Add(new ModelVertexDeclaration(vertexDeclarationsFolder, index, loader)); } // Material parameters ExpectedOffset(loader, materialParametersOffset, typeof(ModelMaterialParameter).Name); foreach (ModelMaterial material in materials) { material.ReadParameters(loader, textureArchive); materialParameters.AddRange(material.Parameters); } ExpectedOffset(loader, postHeaderOffset, "Post-header"); #if Marking if (markingStream != null) { markingStream.Report(loader); } #endif // Marking #if SkippedChecks /*int vertexDataSize = 0, indexCount = 0, indexSize = 0, vertexCount = 0, expectedTriangleCount = 0, nondegenerateTriangleCount = 0; * foreach (var mesh in Meshes) { * vertexDataSize += mesh.VertexCount * mesh.VertexSize; * vertexCount += mesh.VertexCount; * foreach (var part in mesh.Parts) { * indexCount += part.Indices.Length; * indexSize += part.Indices.Length * 2; * expectedTriangleCount += part.Indices.Length - 2; * for (int index = 0; index < part.Indices.Length - 2; index++) { * if (part.Indices[index] != part.Indices[index + 1] && part.Indices[index + 1] != part.Indices[index + 2] && part.Indices[index] != part.Indices[index + 2]) * nondegenerateTriangleCount++; * } * } * } * if (Math.Abs(expectedTriangleCount - triangleCount) > partCount) * throw new InvalidDataException("Expected triangle count doesn't match the read value.");*/ #endif } Buffer = new GraphicsBuffer(bufferData.Count == 0 ? 1 : bufferData.Count); Buffer.Write(0, bufferData.Array, 0, bufferData.Count); }
internal ResourceMap(AssetManager manager, AssetLoader loader) : base(manager, loader.Name) { var reader = loader.Reader; Path = loader.Name; FileManager = loader.FileManager; Version = DetectVersion(loader); Dictionary <ResourceType, FolderAsset> folders = new Dictionary <ResourceType, FolderAsset>(); using (reader) { if (Version == ResourceMapVersion.Sci0) { // Simple list of entries of type (short typeAndIndex, int offsetAndPage), terminated with a (-1, -1) while (true) { ResourceId id = new ResourceId(reader, Version); if (id.IsEnd) { break; } AddResource(id, folders); } } else if (Version == ResourceMapVersion.Sci1) { List <KeyValuePair <ResourceType, int> > types = new List <KeyValuePair <ResourceType, int> >(); while (true) { ResourceType type = (ResourceType)reader.ReadByte(); int offset = reader.ReadUInt16(); types.Add(new KeyValuePair <ResourceType, int>(type == ResourceType.End ? type : (ResourceType)((int)type & 0x7F), offset)); if (type == ResourceType.End) { break; } } for (int typeIndex = 0; typeIndex < types.Count - 1; typeIndex++) { ResourceType type = types[typeIndex].Key; int end = types[typeIndex + 1].Value; while (reader.BaseStream.Position < end) { ResourceId id = new ResourceId(reader, Version, type); AddResource(id, folders); } } } else if (Version == ResourceMapVersion.Sci2) { List <KeyValuePair <ResourceType, int> > types = new List <KeyValuePair <ResourceType, int> >(); while (true) { ResourceType type = (ResourceType)reader.ReadByte(); int offset = reader.ReadUInt16(); types.Add(new KeyValuePair <ResourceType, int>(type, offset)); if (type == ResourceType.End) { break; } } Unknowns.ReadInt32s(reader, 1, "Post offsets"); for (int typeIndex = 0; typeIndex < types.Count - 1; typeIndex++) { ResourceType type = types[typeIndex].Key; int offset = types[typeIndex].Value; int end = types[typeIndex + 1].Value; if ((end - offset) % 6 != 0) { throw new InvalidDataException(); } int count = (end - offset) / 6; for (int index = 0; index < count; index++) { ResourceId id = new ResourceId(reader, Version, type); AddResource(id, folders); } } } else { throw new NotImplementedException(); } } SortChildrenRecursively(); }
internal MCGTable1(MCG mcg, int index, AssetLoader loader) : base(mcg, index) { Unknowns.ReadInt32s(loader.Reader, 1); }
internal Rom(AssetLoader loader) : base(loader) { BinaryReader reader = Reader = loader.Reader; Codex <RomFile> files = new Codex <RomFile>(); Codex <RomFolder> folders = new Codex <RomFolder>(); Files = files; Folders = folders; GameTitle = Reader.ReadStringz(12, Encoding.ASCII); GameCode = Reader.ReadStringz(4, Encoding.ASCII); // Offset 0x10 MakerCode = Reader.ReadStringz(2, Encoding.ASCII); UnitCode = reader.ReadByte(); DeviceCode = reader.ReadByte(); CardSizeBase = reader.ReadByte(); loader.ExpectZeroes(1, 7); Unknowns.ReadInt32s(reader, 1); // Usually 0, Alice in Wonderland: 3 // Offset 0x20 PageSize = reader.ReadInt32(); // Usually (always?) 0x4000 Unknowns.ReadInt16s(reader, 2); // The Dark Spire: 0x800; Trauma Center: 0xF780 (-2176) loader.Expect(0x2000000); Unknowns.ReadInt32s(reader, 1); // The Dark Spire: 0x9BEF8; Trauma Center: 0x1DC518 // Offset 0x30 Unknowns.ReadInt32s(reader, 1); // Entry points? The Dark Spire: 0x152200; Trauma Center: 0x1E0600 loader.Expect(0x2380000); loader.Expect(0x2380000); Unknowns.ReadInt16s(reader, 1); // The Dark Spire: 0x6F28; Trauma Center: 0x6F24 loader.Expect((short)0x2); // Offset 0x40 int fileNameTableOffset = reader.ReadInt32(); int fileNameTableSize = reader.ReadInt32(); int fileSizeTableOffset = reader.ReadInt32(); int fileSizeTableSize = reader.ReadInt32(); // Offset 0x50 Unknowns.ReadInt32s(reader, 2, "Offset and size"); // Used in The Dark Spire, zeroes in Trauma Center. loader.ExpectZeroes(4, 2); // Offset 0x60 Unknowns.ReadInt32s(reader, 2); int iconAndTitleOffset = reader.ReadInt32(); Unknowns.ReadInt32s(reader, 1); // Offset 0x70 Unknowns.ReadInt32s(reader, 2); loader.ExpectZeroes(4, 2); // Offset 0x80 DataLength = reader.ReadInt32(); loader.Expect(PageSize); Unknowns.ReadInt32s(reader, 2); // The Dark Spire: 0x4B68; 0 in Trauma Center. ReadIconAndTitle(iconAndTitleOffset); if (fileNameTableOffset > 0) { int folderNamesOffset = reader.ReadInt32At(fileNameTableOffset); reader.BaseStream.Position = fileNameTableOffset; int folderCount = folderNamesOffset / 8; for (int index = 0; index < folderCount; index++) { folders.Add(new RomFolder(this, index, reader)); } byte[] folderNames = reader.ReadBytes(fileNameTableSize - folderNamesOffset); reader.BaseStream.Position = fileSizeTableOffset; int fileCount = fileSizeTableSize / 8; for (int index = 0; index < fileCount; index++) { files.Add(new RomFile(this, index, reader)); } folders[0].Sort(this, "Root", folderNamesOffset, folderNames); FolderAsset orphanedFolders = null, orphanedFiles = null; foreach (RomFolder folder in folders) { if (folder.Used) { continue; } if (orphanedFolders == null) { orphanedFolders = new FolderAsset(this, "Orphaned folder[s]"); } folder.Sort(this, folder.Name, folderNamesOffset, folderNames); } foreach (RomFile file in files) { if (file.Used) { continue; } if (orphanedFiles == null) { orphanedFiles = new FolderAsset(this, "Orphaned file[s]"); } file.Sort(orphanedFiles, file.Name); } } }