예제 #1
0
        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);
        }
예제 #2
0
        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;
            }
        }
예제 #3
0
 public DirectoryNode()
 {
     Children = new DirectoryTree();
 }
예제 #4
0
        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);
                }
            }
        }