using System.Collections.Generic; using System.IO; using System.Text; using System.Runtime.InteropServices; namespace PriFileFormat { public class ReferencedFileSection: Section { public List ReferencedFiles { get; private set; } internal const string Identifier = "[def_file_list]\0"; internal ReferencedFileSection (PriFile priFile) : base (Identifier, priFile) {} protected override bool ParseSectionContent (BinaryReader binaryReader) { ushort numRoots = binaryReader.ReadUInt16 (); ushort numFolders = binaryReader.ReadUInt16 (); ushort numFiles = binaryReader.ReadUInt16 (); binaryReader.ExpectUInt16 (0); uint totalDataLength = binaryReader.ReadUInt32 (); List folderInfos = new List (numFolders); for (int i = 0; i < numFolders; i++) { binaryReader.ExpectUInt16 (0); ushort parentFolder = binaryReader.ReadUInt16 (); ushort numFoldersInFolder = binaryReader.ReadUInt16 (); ushort firstFolderInFolder = binaryReader.ReadUInt16 (); ushort numFilesInFolder = binaryReader.ReadUInt16 (); ushort firstFileInFolder = binaryReader.ReadUInt16 (); ushort folderNameLength = binaryReader.ReadUInt16 (); ushort fullPathLength = binaryReader.ReadUInt16 (); uint folderNameOffset = binaryReader.ReadUInt32 (); folderInfos.Add (new FolderInfo (parentFolder, numFoldersInFolder, firstFolderInFolder, numFilesInFolder, firstFileInFolder, folderNameLength, fullPathLength, folderNameOffset)); } List fileInfos = new List (numFiles); for (int i = 0; i < numFiles; i++) { binaryReader.ReadUInt16 (); ushort parentFolder = binaryReader.ReadUInt16 (); ushort fullPathLength = binaryReader.ReadUInt16 (); ushort fileNameLength = binaryReader.ReadUInt16 (); uint fileNameOffset = binaryReader.ReadUInt32 (); fileInfos.Add (new FileInfo (parentFolder, fullPathLength, fileNameLength, fileNameOffset)); } long dataStartPosition = binaryReader.BaseStream.Position; List referencedFolders = new List (numFolders); for (int i = 0; i < numFolders; i++) { binaryReader.BaseStream.Seek (dataStartPosition + folderInfos [i].FolderNameOffset * 2, SeekOrigin.Begin); string name = binaryReader.ReadString (Encoding.Unicode, folderInfos [i].FolderNameLength); referencedFolders.Add (new ReferencedFolder (null, name)); } for (int i = 0; i < numFolders; i++) if (folderInfos [i].ParentFolder != 0xFFFF) referencedFolders [i].Parent = referencedFolders [folderInfos [i].ParentFolder]; List referencedFiles = new List (numFiles); for (int i = 0; i < numFiles; i++) { binaryReader.BaseStream.Seek (dataStartPosition + fileInfos [i].FileNameOffset * 2, SeekOrigin.Begin); string name = binaryReader.ReadString (Encoding.Unicode, fileInfos [i].FileNameLength); ReferencedFolder parentFolder; if (fileInfos [i].ParentFolder != 0xFFFF) parentFolder = referencedFolders [fileInfos [i].ParentFolder]; else parentFolder = null; referencedFiles.Add (new ReferencedFile (parentFolder, name)); } for (int i = 0; i < numFolders; i++) { List children = new List (folderInfos [i].NumFoldersInFolder + folderInfos [i].NumFilesInFolder); for (int j = 0; j < folderInfos [i].NumFoldersInFolder; j++) children.Add (referencedFolders [folderInfos [i].FirstFolderInFolder + j]); for (int j = 0; j < folderInfos [i].NumFilesInFolder; j++) children.Add (referencedFiles [folderInfos [i].FirstFileInFolder + j]); referencedFolders [i].Children = children; } ReferencedFiles = referencedFiles; return true; } private struct FolderInfo { public ushort ParentFolder; public ushort NumFoldersInFolder; public ushort FirstFolderInFolder; public ushort NumFilesInFolder; public ushort FirstFileInFolder; public ushort FolderNameLength; public ushort FullPathLength; public uint FolderNameOffset; public FolderInfo (ushort parentFolder, ushort numFoldersInFolder, ushort firstFolderInFolder, ushort numFilesInFolder, ushort firstFileInFolder, ushort folderNameLength, ushort fullPathLength, uint folderNameOffset) { ParentFolder = parentFolder; NumFoldersInFolder = numFoldersInFolder; FirstFolderInFolder = firstFolderInFolder; NumFilesInFolder = numFilesInFolder; FirstFileInFolder = firstFileInFolder; FolderNameLength = folderNameLength; FullPathLength = fullPathLength; FolderNameOffset = folderNameOffset; } } private struct FileInfo { public ushort ParentFolder; public ushort FullPathLength; public ushort FileNameLength; public uint FileNameOffset; public FileInfo (ushort parentFolder, ushort fullPathLength, ushort fileNameLength, uint fileNameOffset) { ParentFolder = parentFolder; FullPathLength = fullPathLength; FileNameLength = fileNameLength; FileNameOffset = fileNameOffset; } } ~ReferencedFileSection () { foreach (var file in ReferencedFiles) { file.Parent = null; } ReferencedFiles = null; } } public class ReferencedEntry { public ReferencedFolder Parent { get; internal set; } public string Name { get; } internal ReferencedEntry (ReferencedFolder parent, string name) { Parent = parent; Name = name; } string fullName; public string FullName { get { if (fullName == null) if (Parent == null) fullName = Name; else fullName = Parent.FullName + "\\" + Name; return fullName; } } ~ReferencedEntry () { Parent = null; } } public class ReferencedFolder: ReferencedEntry { internal ReferencedFolder (ReferencedFolder parent, string name) : base (parent, name) {} public IReadOnlyList Children { get; internal set; } ~ReferencedFolder () { Children = null; } } public class ReferencedFile: ReferencedEntry { internal ReferencedFile (ReferencedFolder parent, string name) : base (parent, name) {} } public struct ReferencedFileRef { internal int fileIndex; internal ReferencedFileRef (int fileIndex) { this.fileIndex = fileIndex; } } }