public void Deserialize(Stream input)
        {
            Endian endian;

            Package.HeaderV6 header;

            using (var data = input.ReadToMemoryStream(2048))
            {
                var magic = data.ReadValueU32(Endian.Little);
                if (magic != 0x51890ACE &&
                    magic.Swap() != 0x51890ACE)
                {
                    throw new FormatException("not a package file");
                }
                endian = magic == 0x51890ACE ? Endian.Little : Endian.Big;

                var version = data.ReadValueU32(endian);
                if (version != 6)
                {
                    throw new FormatException("unexpected package version (expected 6)");
                }

                header = new Package.HeaderV6();
                header.Deserialize(data, endian);
            }

            this.Entries.Clear();
            using (var directory = input.ReadToMemoryStream(header.DirectorySize.Align(2048)))
            {
                using (var names = input.ReadToMemoryStream(header.NamesSize.Align(2048)))
                {
                    for (int i = 0; i < header.DirectoryCount; i++)
                    {
                        var nameOffset = directory.ReadValueU32(endian);
                        directory.Seek(4, SeekOrigin.Current); // runtime offset
                        var offset           = directory.ReadValueU32(endian);
                        var uncompressedSize = directory.ReadValueU32(endian);
                        var compressedSize   = directory.ReadValueU32(endian);
                        directory.Seek(4, SeekOrigin.Current); // package pointer

                        names.Seek(nameOffset, SeekOrigin.Begin);
                        var name = names.ReadStringZ(Encoding.ASCII);

                        this.Entries.Add(new Package.Entry()
                        {
                            Name             = name,
                            Offset           = offset,
                            UncompressedSize = uncompressedSize,
                            CompressedSize   = compressedSize,
                        });
                    }
                }
            }

            this.Endian           = endian;
            this.Flags            = ConvertFlags(header.Flags);
            this.UncompressedSize = header.UncompressedSize;
            this.CompressedSize   = header.CompressedSize;
            this.DataOffset       = input.Position;
        }
        public void Serialize(Stream output)
        {
            var endian = this.Endian;

            var names     = new MemoryStream();
            var directory = new MemoryStream();

            foreach (var entry in this.Entries)
            {
                directory.WriteValueU32((uint)names.Position, endian);
                directory.WriteValueU32(0, endian);
                directory.WriteValueU32(entry.Offset, endian);
                directory.WriteValueU32(entry.UncompressedSize, endian);
                directory.WriteValueU32(entry.CompressedSize, endian);
                directory.WriteValueU32(0, endian);
                names.WriteStringZ(entry.Name, Encoding.ASCII);
            }

            var header = new Package.HeaderV6();

            header.Name = "         Created using      Gibbed's     Volition Tools ";
            header.Path = "           Read the       Foundation     Novels from       Asimov.       I liked them. ";

            header.Flags = ConvertFlags(this.Flags);

            if (this.ExtraFlags != 0)
            {
                header.Flags |= (Package.HeaderFlagsV6) this.ExtraFlags;
            }

            header.DirectoryCount   = (uint)this.Entries.Count;
            header.PackageSize      = this.TotalSize;
            header.DirectorySize    = (uint)directory.Length;
            header.NamesSize        = (uint)names.Length;
            header.UncompressedSize = this.UncompressedSize;
            header.CompressedSize   = (this.Flags & Package.HeaderFlags.Compressed) != 0 ?
                                      this.CompressedSize : 0xFFFFFFFF;

            directory.Seek(0, SeekOrigin.Begin);
            directory.SetLength(directory.Length.Align(2048));

            names.Seek(0, SeekOrigin.Begin);
            names.SetLength(names.Length.Align(2048));

            output.WriteValueU32(0x51890ACE, endian);
            output.WriteValueU32(6, endian);

            header.Serialize(output, endian);
            output.Seek(2048, SeekOrigin.Begin);
            output.WriteFromStream(directory, directory.Length);
            output.WriteFromStream(names, names.Length);
        }