예제 #1
0
        /// <summary>
        /// Reads the entry from the VPK package.
        /// </summary>
        /// <param name="entry">Package entry.</param>
        /// <param name="output">Output buffer.</param>
        /// <param name="validateCrc">If true, CRC32 will be calculated and verified for read data.</param>
        public void ReadEntry(PackageEntry entry, out byte[] output, bool validateCrc = true)
        {
            output = new byte[entry.SmallData.Length + entry.Length];

            if (entry.SmallData.Length > 0)
            {
                entry.SmallData.CopyTo(output, 0);
            }

            if (entry.Length > 0)
            {
                Stream fs = null;

                try
                {
                    var offset = entry.Offset;

                    if (entry.ArchiveIndex != 0x7FFF)
                    {
                        if (!IsDirVPK)
                        {
                            throw new InvalidOperationException("Given VPK is not a _dir, but entry is referencing an external archive.");
                        }

                        var fileName = string.Format("{0}_{1:D3}.vpk", FileName, entry.ArchiveIndex);

                        fs = new FileStream(fileName, FileMode.Open, FileAccess.Read);
                    }
                    else
                    {
                        fs = Reader.BaseStream;

                        offset += OffsetAfterHeader;
                    }

                    fs.Seek(offset, SeekOrigin.Begin);
                    fs.Read(output, entry.SmallData.Length, (int)entry.Length);
                }
                finally
                {
                    if (entry.ArchiveIndex != 0x7FFF && fs != null)
                    {
                        fs.Close();
                    }
                }
            }

            if (validateCrc && entry.CRC32 != Crc32.Compute(output))
            {
                throw new InvalidDataException("CRC32 mismatch for read data.");
            }
        }
예제 #2
0
        /// <summary>
        /// Reads the given <see cref="Stream"/>.
        /// </summary>
        /// <param name="input">The input <see cref="Stream"/> to read from.</param>
        /// <returns>Returns true if this archive contains inline entries, false otherwise.</returns>
        public bool Read(Stream input)
        {
            if (FileName == null)
            {
                throw new InvalidOperationException("If you call Read() directly with a stream, you must call SetFileName() first.");
            }

            Reader = new BinaryReader(input);

            if (Reader.ReadUInt32() != Package.MAGIC)
            {
                throw new InvalidDataException("Given file is not a VPK.");
            }

            Version  = Reader.ReadUInt32();
            TreeSize = Reader.ReadUInt32();

            if (Version == 1)
            {
                // Nothing else
            }
            else if (Version == 2)
            {
                FileDataSectionSize   = Reader.ReadUInt32();
                ArchiveMD5SectionSize = Reader.ReadUInt32();
                OtherMD5SectionSize   = Reader.ReadUInt32();
                SignatureSectionSize  = Reader.ReadUInt32();
            }
            else
            {
                throw new InvalidDataException(string.Format("Bad VPK version. ({0})", Version));
            }

            var  typeEntries      = new Dictionary <string, List <PackageEntry> >();
            bool hasInlineEntries = false;

            // Types
            while (true)
            {
                string typeName = Reader.ReadNullTermString(Encoding.UTF8);

                if (typeName == "")
                {
                    break;
                }

                var entries = new List <PackageEntry>();

                // Directories
                while (true)
                {
                    string directoryName = Reader.ReadNullTermString(Encoding.UTF8);

                    if (directoryName == "")
                    {
                        break;
                    }

                    // Files
                    while (true)
                    {
                        string fileName = Reader.ReadNullTermString(Encoding.UTF8);

                        if (fileName == "")
                        {
                            break;
                        }

                        var entry = new PackageEntry();
                        entry.FileName      = fileName;
                        entry.DirectoryName = directoryName.Replace("/", "\\");
                        entry.TypeName      = typeName;
                        entry.CRC32         = Reader.ReadUInt32();
                        entry.SmallData     = new byte[Reader.ReadUInt16()];
                        entry.ArchiveIndex  = Reader.ReadUInt16();
                        entry.Offset        = Reader.ReadUInt32();
                        entry.Length        = Reader.ReadUInt32();

                        if (Reader.ReadUInt16() != 0xFFFF)
                        {
                            throw new FormatException("Invalid terminator.");
                        }

                        if (entry.SmallData.Length > 0)
                        {
                            Reader.Read(entry.SmallData, 0, entry.SmallData.Length);
                        }

                        if (entry.ArchiveIndex == 0x7FFF)
                        {
                            hasInlineEntries = true;
                        }

                        entries.Add(entry);
                    }
                }

                typeEntries.Add(typeName, entries);
            }

            Entries = typeEntries;

            OffsetAfterHeader = (uint)Reader.BaseStream.Position;

            return(hasInlineEntries);
        }
예제 #3
0
        /// <summary>
        /// Reads the entry from the VPK package.
        /// </summary>
        /// <param name="entry">Package entry.</param>
        /// <param name="output">Output buffer.</param>
        /// <param name="validateCrc">If true, CRC32 will be calculated and verified for read data.</param>
        public void ReadEntry(PackageEntry entry, out byte[] output, bool validateCrc = true)
        {
            output = new byte[entry.SmallData.Length + entry.Length];

            if (entry.SmallData.Length > 0)
            {
                entry.SmallData.CopyTo(output, 0);
            }

            if (entry.Length > 0)
            {
                Stream fs = null;

                try
                {
                    var offset = entry.Offset;

                    if (entry.ArchiveIndex != 0x7FFF)
                    {
                        if (!IsDirVPK)
                        {
                            throw new InvalidOperationException("Given VPK is not a _dir, but entry is referencing an external archive.");
                        }

                        var fileName = string.Format("{0}_{1:D3}.vpk", FileName, entry.ArchiveIndex);

                        fs = new FileStream(fileName, FileMode.Open, FileAccess.Read);
                    }
                    else
                    {
                        fs = Reader.BaseStream;

                        offset += OffsetAfterHeader;
                    }

                    fs.Seek(offset, SeekOrigin.Begin);
                    fs.Read(output, entry.SmallData.Length, (int)entry.Length);
                }
                finally
                {
                    if (entry.ArchiveIndex != 0x7FFF && fs != null)
                    {
                        fs.Close();
                    }
                }
            }

            if (validateCrc && entry.CRC32 != Crc32.Compute(output))
            {
                throw new InvalidDataException("CRC32 mismatch for read data.");
            }
        }
예제 #4
0
        /// <summary>
        /// Reads the given <see cref="Stream"/>.
        /// </summary>
        /// <param name="input">The input <see cref="Stream"/> to read from.</param>
        /// <returns>Returns true if this archive contains inline entries, false otherwise.</returns>
        public bool Read(Stream input)
        {
            if (FileName == null)
            {
                throw new InvalidOperationException("If you call Read() directly with a stream, you must call SetFileName() first.");
            }

            Reader = new BinaryReader(input);

            if (Reader.ReadUInt32() != Package.MAGIC)
            {
                throw new InvalidDataException("Given file is not a VPK.");
            }

            Version = Reader.ReadUInt32();
            TreeSize = Reader.ReadUInt32();

            if (Version == 1)
            {
                // Nothing else
            }
            else if (Version == 2)
            {
                FileDataSectionSize = Reader.ReadUInt32();
                ArchiveMD5SectionSize = Reader.ReadUInt32();
                OtherMD5SectionSize = Reader.ReadUInt32();
                SignatureSectionSize = Reader.ReadUInt32();
            }
            else
            {
                throw new InvalidDataException(string.Format("Bad VPK version. ({0})", Version));
            }

            var typeEntries = new Dictionary<string, List<PackageEntry>>();
            bool hasInlineEntries = false;

            // Types
            while (true)
            {
                string typeName = Reader.ReadNullTermString(Encoding.UTF8);

                if (typeName == "")
                {
                    break;
                }

                var entries = new List<PackageEntry>();

                // Directories
                while (true)
                {
                    string directoryName = Reader.ReadNullTermString(Encoding.UTF8);

                    if (directoryName == "")
                    {
                        break;
                    }

                    // Files
                    while (true)
                    {
                        string fileName = Reader.ReadNullTermString(Encoding.UTF8);

                        if (fileName == "")
                        {
                            break;
                        }

                        var entry = new PackageEntry();
                        entry.FileName = fileName;
                        entry.DirectoryName = directoryName.Replace("/", "\\");
                        entry.TypeName = typeName;
                        entry.CRC32 = Reader.ReadUInt32();
                        entry.SmallData = new byte[Reader.ReadUInt16()];
                        entry.ArchiveIndex = Reader.ReadUInt16();
                        entry.Offset = Reader.ReadUInt32();
                        entry.Length = Reader.ReadUInt32();

                        if (Reader.ReadUInt16() != 0xFFFF)
                        {
                            throw new FormatException("Invalid terminator.");
                        }

                        if (entry.SmallData.Length > 0)
                        {
                            Reader.Read(entry.SmallData, 0, entry.SmallData.Length);
                        }

                        if (entry.ArchiveIndex == 0x7FFF)
                        {
                            hasInlineEntries = true;
                        }

                        entries.Add(entry);
                    }
                }

                typeEntries.Add(typeName, entries);
            }

            Entries = typeEntries;

            OffsetAfterHeader = (uint)Reader.BaseStream.Position;

            return hasInlineEntries;
        }
예제 #5
0
        private void ReadEntries()
        {
            var typeEntries = new Dictionary <string, List <PackageEntry> >();

            // Types
            while (true)
            {
                var typeName = Reader.ReadNullTermString(Encoding.UTF8);

                if (typeName == string.Empty)
                {
                    break;
                }

                var entries = new List <PackageEntry>();

                // Directories
                while (true)
                {
                    var directoryName = Reader.ReadNullTermString(Encoding.UTF8);

                    if (directoryName == string.Empty)
                    {
                        break;
                    }

                    // Files
                    while (true)
                    {
                        var fileName = Reader.ReadNullTermString(Encoding.UTF8);

                        if (fileName == string.Empty)
                        {
                            break;
                        }

                        var entry = new PackageEntry();
                        entry.FileName      = fileName;
                        entry.DirectoryName = directoryName.Replace("/", "\\");
                        entry.TypeName      = typeName;
                        entry.CRC32         = Reader.ReadUInt32();
                        entry.SmallData     = new byte[Reader.ReadUInt16()];
                        entry.ArchiveIndex  = Reader.ReadUInt16();
                        entry.Offset        = Reader.ReadUInt32();
                        entry.Length        = Reader.ReadUInt32();

                        if (Reader.ReadUInt16() != 0xFFFF)
                        {
                            throw new FormatException("Invalid terminator.");
                        }

                        if (entry.SmallData.Length > 0)
                        {
                            Reader.Read(entry.SmallData, 0, entry.SmallData.Length);
                        }

                        entries.Add(entry);
                    }
                }

                typeEntries.Add(typeName, entries);
            }

            Entries = typeEntries;
        }
예제 #6
0
        private void ReadEntries()
        {
            var typeEntries = new Dictionary <string, List <PackageEntry> >();

            // Types
            while (true)
            {
                var typeName = Reader.ReadNullTermString(Encoding.UTF8);

                if (typeName == string.Empty)
                {
                    break;
                }

                // Valve uses a space for missing extensions,
                // we replace it with an empty string to match how System.IO.Path deals with it.
                if (typeName == " ")
                {
                    typeName = string.Empty;
                }

                var entries = new List <PackageEntry>();

                // Directories
                while (true)
                {
                    var directoryName = Reader.ReadNullTermString(Encoding.UTF8);

                    if (directoryName == string.Empty)
                    {
                        break;
                    }

                    // Valve uses a space for blank directory names,
                    // we replace it with a null to match how System.IO.Path deals with root paths.
                    if (directoryName == " ")
                    {
                        directoryName = null;
                    }

                    // Files
                    while (true)
                    {
                        var fileName = Reader.ReadNullTermString(Encoding.UTF8);

                        if (fileName == string.Empty)
                        {
                            break;
                        }

                        var entry = new PackageEntry
                        {
                            FileName      = fileName,
                            DirectoryName = directoryName,
                            TypeName      = typeName,
                            CRC32         = Reader.ReadUInt32(),
                            SmallData     = new byte[Reader.ReadUInt16()],
                            ArchiveIndex  = Reader.ReadUInt16(),
                            Offset        = Reader.ReadUInt32(),
                            Length        = Reader.ReadUInt32()
                        };

                        if (Reader.ReadUInt16() != 0xFFFF)
                        {
                            throw new FormatException("Invalid terminator.");
                        }

                        if (entry.SmallData.Length > 0)
                        {
                            Reader.Read(entry.SmallData, 0, entry.SmallData.Length);
                        }

                        entries.Add(entry);
                    }
                }

                typeEntries.Add(typeName, entries);
            }

            Entries = typeEntries;
        }
        /// <summary>
        /// Adds a node to the tree based on the passed file information. This is useful when building a directory-based tree.
        /// </summary>
        /// <param name="file"></param>
        /// <param name="fileType"></param>
        public void AddFileNode(PackageEntry file, KeyValuePair<string, List<PackageEntry>> fileType)
        {
            TreeNode currentNode = null;

            string fileName = String.Format("{0}.{1}", file.FileName, fileType.Key);
            string path = Path.Combine(file.DirectoryName, fileName);
            string[] subPaths = path.Split(Path.DirectorySeparatorChar);

            foreach (string subPath in subPaths)
            {
                if (currentNode == null) //Root directory
                {
                    if (subPath == " ")
                    {
                        continue; //root files
                    }

                    if (null == this.Nodes[subPath])
                    {
                        currentNode = this.Nodes.Add(subPath, subPath);
                    }
                    else
                    {
                        currentNode = this.Nodes[subPath];
                    }
                }
                else //Not root directory
                {
                    if (null == currentNode.Nodes[subPath])
                    {
                        currentNode = currentNode.Nodes.Add(subPath, subPath);
                    }
                    else
                    {
                        currentNode = currentNode.Nodes[subPath];
                    }
                }

                var ext = Path.GetExtension(currentNode.Name);

                if (ext.Length == 0)
                {
                    ext = "_folder";

                    currentNode.Tag = new Controls.TreeViewFolder(file.DirectoryName, currentNode.Nodes.Count + 1); //is this enough?
                }
                else
                {
                    currentNode.Tag = file; //so we can use it later

                    ext = ext.Substring(1);

                    if (ext.EndsWith("_c", StringComparison.Ordinal))
                    {
                        ext = ext.Substring(0, ext.Length - 2);
                    }

                    if (!ImageList.Images.ContainsKey(ext))
                    {
                        if (ext[0] == 'v')
                        {
                            ext = ext.Substring(1);

                            if (!ImageList.Images.ContainsKey(ext))
                            {
                                ext = "_default";
                            }
                        }
                        else
                        {
                            ext = "_default";
                        }
                    }
                }

                currentNode.ImageKey = ext;
                currentNode.SelectedImageKey = ext;
            }
        }