private int CalculateSize(DirectoryTree tree) { int totalSize = 8; foreach (var node in tree) { totalSize += 9; totalSize += node.Key.Length + 1; if (node.Children.Count != 0) { totalSize += CalculateSize(node.Children); } else { totalSize += 9; } } return(totalSize); }
internal static void SetEntries(DirectoryTree tree, BinaryWriter bw, IEnumerator <FileEntry> sequence) { bw.Write(tree.Count); //Root Entries number in directory bw.Write((int)bw.BaseStream.Position + 4); //Entries Offset point to next for (int i = 0; i < tree.Count; ++i) { int posString; if (i == 0) { posString = (int)bw.BaseStream.Position + (tree.Count - i) * 9; } else { posString = (int)bw.BaseStream.Length; } bw.Write(posString); //NameOffset; /* points to the file name */ int posNext = posString + tree[i].Key.Length + 1; bw.Write(posNext); //DirDataOffset; /* points to directory data */ bool isDir = tree[i].Children.Count != 0; bw.Write(isDir); int previousPos = (int)bw.BaseStream.Position; bw.BaseStream.Position = posString; WriteStringCP437NullTerminated(bw, tree[i].Key); if (isDir) { SetEntries(tree[i].Children, bw, sequence); } else { sequence.MoveNext(); bw.Write(sequence.Current.OffsetOfCompressedData); //OffsetOfData bw.Write(sequence.Current.UncompressedSize); //UncompressedSize bw.Write((byte)sequence.Current.FlagCompression); //FlagCompression } bw.BaseStream.Position = previousPos; } }
public DirectoryNode() { Children = new DirectoryTree(); }
private static void WriteToFile(string destinationArchiveFileName, SortedDictionary <string, FileEntry> entries) { var tree = new DirectoryTree(); //Provisory Tree foreach (var fileName in entries.Keys) { tree.AddEntry(fileName); } int directorySize = tree.CalculateSize() + 20; using (var fileStream = File.Create(destinationArchiveFileName)) { BinaryWriter chunckWriter = new BinaryWriter(fileStream); chunckWriter.BaseStream.Position = directorySize; foreach (var file in entries) { if (chunckWriter.BaseStream.Position > Int32.MaxValue) { throw new Exception("Maximum allowed size is 2GB (2 147 483 647 bytes)."); } file.Value.OffsetOfCompressedData = (int)chunckWriter.BaseStream.Position; if (file.Value.FlagCompression != CompressionMethod.None) { foreach (var size in file.Value.compressedChunkSizes) { chunckWriter.Write(size); } } foreach (var chunk in file.Value.ChunkBytes) { chunckWriter.Write(chunk); } } chunckWriter.Write("Copyright " + DateTime.Now.Year.ToString() + " Cavedog Entertainment"); //Endfile mandatory string BinaryWriter headerWriter = new BinaryWriter(new MemoryStream()); headerWriter.BaseStream.Position = 0; headerWriter.Write(HpiArchive.HeaderMarker); headerWriter.Write(HpiArchive.DefaultVersion); tree = new DirectoryTree(); //Definitive Tree foreach (var item in entries.Keys) { tree.AddEntry(item); } directorySize = tree.CalculateSize() + 20; //TO IMPROVE, BAD CODE headerWriter.Write(directorySize); headerWriter.Write(HpiArchive.NoObfuscationKey); int directoryStart = 20; headerWriter.Write(directoryStart); //Directory Start at Pos20 IEnumerator <FileEntry> sequence = entries.Values.ToList().GetEnumerator(); HpiArchive.SetEntries(tree, headerWriter, sequence); fileStream.Position = 0; headerWriter.BaseStream.Position = 0; headerWriter.BaseStream.CopyTo(fileStream); if (fileStream.Length > Int32.MaxValue) { MessageBox.Show("The HPI file was created, but its size exceeds 2GB (2 147 483 647 bytes). A fatal error may occur when loading the game.", "Oversize Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); } } }