コード例 #1
0
ファイル: VPK.cs プロジェクト: ModDota/ModDotaClient2
        /// <summary>
        /// Adds a file (already in memory) to a vpk.
        /// </summary>
        /// <param name="contents">The file contents.</param>
        /// <param name="internalfilename">The file name, including path, internally.</param>
        public void AddFile(byte[] contents, string internalfilename)
        {
            Crc32.Crc32Algorithm checker = new Crc32.Crc32Algorithm();
            byte[] crc = checker.ComputeHash(contents);
            if (crc.Length != 4)
            {
                Console.WriteLine("wtf the crc isn't 32 bits long");
            }
            VPKFile asfile = new VPKFile(null);

            asfile.CRC32        = BitConverter.ToUInt32(crc, 0);
            asfile.entry_length = (uint)(contents.Length);

            // Now that we have the basics of the file, we need to figure out how to store it
            // This involves first loading the vpk directory information
            List <VPKExt> dir = GetDirectory();
            // Now we need to just add the file, and write new directory information
            // Get the location to which to write the file
            Tuple <int, uint> slot = GetNewestSpace(dir);
            int  paddinglength     = (int)filealignment - (int)((int)(slot.Item2) % (int)filealignment);
            int  archivenum        = slot.Item1;
            uint offset            = slot.Item2;

            // Create a new archive file if necessary
            if (contents.Length + slot.Item2 + paddinglength > maxarchivesize)
            {
                paddinglength = 0;
                archivenum++;
                offset = 0;
            }
            // Write the file to the archive
            using (FileStream foo = File.OpenWrite(String.Format("{0}_{1:D3}.vpk", fileprefix, archivenum)))
            {
                using (BinaryWriter bw = new BinaryWriter(foo))
                {
                    bw.Seek((int)offset, SeekOrigin.Begin);
                    for (int i = 0; i < paddinglength; i++)
                    {
                        bw.Write((byte)0);
                    }
                    bw.Write(contents);
                }
            }
            // Add the padding to the offset so it properly reflects the file
            offset += (uint)paddinglength;
            // Add the file information to the directory
            string ext = internalfilename.Substring(internalfilename.IndexOf('.') + 1);

            internalfilename = internalfilename.Substring(0, internalfilename.IndexOf('.'));
            char[] lookfor = { '\\', '/' };
            string path    = internalfilename.Substring(0, internalfilename.LastIndexOfAny(lookfor));
            string name    = internalfilename.Substring(internalfilename.LastIndexOfAny(lookfor) + 1);
            // Find where to put it
            VPKExt writeext = null;

            foreach (VPKExt vext in dir)
            {
                if (vext.ext == ext)
                {
                    writeext = vext;
                }
            }
            if (writeext == null)
            {
                writeext             = new VPKExt();
                writeext.ext         = ext;
                writeext.directories = new List <VPKDirectory>();
                dir.Add(writeext);
            }
            VPKDirectory writedir = null;

            foreach (VPKDirectory vpkd in writeext.directories)
            {
                if (vpkd.path == path)
                {
                    writedir = vpkd;
                }
            }
            if (writedir == null)
            {
                writedir         = new VPKDirectory();
                writedir.path    = path;
                writedir.ext     = ext;
                writedir.entries = new List <VPKFileEntry>();
                writeext.directories.Add(writedir);
            }
            VPKFileEntry writefile = null;

            foreach (VPKFileEntry vpkfe in writedir.entries)
            {
                if (vpkfe.name == name)
                {
                    writefile = vpkfe;
                    //ok, we gotta do a file replacement
                    //thankfully, this is just overwriting a few values
                    writefile.body.archive_index = (ushort)archivenum;
                    writefile.body.CRC32         = BitConverter.ToUInt32(crc, 0);
                    writefile.body.entry_length  = (uint)(contents.Length);
                    writefile.body.entry_offset  = offset;
                    writefile.body.preload_bytes = 0;
                }
            }
            if (writefile == null)
            {
                // Didn't find a file entry, so let's add one
                writefile = new VPKFileEntry();
                writefile.body.archive_index = (ushort)archivenum;
                writefile.body.CRC32         = BitConverter.ToUInt32(crc, 0);
                writefile.body.entry_length  = (uint)(contents.Length);
                writefile.body.entry_offset  = offset;
                writefile.body.preload_bytes = 0;
                writedir.entries.Add(writefile);
            }
            // Write the new directory to the directory file.
            WriteDirectory(dir);
        }
コード例 #2
0
ファイル: VPK.cs プロジェクト: ModDota/ModDotaClient2
        /// <summary>
        /// Read the directory from the file. This is mostly ported code from my [pw]
        /// vpk.h from vpktool.
        /// </summary>
        /// <returns>The VPKDirectory for the file's contents</returns>
        private List <VPKExt> GetDirectory()
        {
            byte[] body   = null;
            int    length = 0;

            using (FileStream vpkfile = File.OpenRead(fileprefix + "_dir.vpk"))
            {
                using (BinaryReader reader = new BinaryReader(vpkfile))
                {
                    byte[]    headerbytes = reader.ReadBytes(12);
                    VPKHeader head        = StructTools.RawDeserialize <VPKHeader>(headerbytes, 0);
                    if (head.version != 1)
                    {
                        return(null);
                    }
                    body   = reader.ReadBytes((int)head.tree_length);
                    length = (int)head.tree_length;
                }
            }
            if (body == null)
            {
                return(null);
            }
            List <VPKExt> ret     = new List <VPKExt>();
            int           index   = 0;
            int           level   = 0;
            VPKExt        curext  = new VPKExt();
            VPKDirectory  curpath = new VPKDirectory();

            while (index < length && level >= 0)
            {
                if (body[index] == '\0')
                {
                    switch (level)
                    {
                    case 0:
                        break;

                    case 1:
                        ret.Add(curext);
                        break;

                    case 2:
                        curext.directories.Add(curpath);
                        break;
                    }
                    index++;
                    level--;
                    continue;
                }
                switch (level)
                {
                case 0:     //ext level
                    int extstartindex = index;
                    level++;
                    while (body[index] != 0)
                    {
                        index++;
                    }
                    index++;
                    curext             = new VPKExt();
                    curext.ext         = Encoding.ASCII.GetString(body, extstartindex, index - extstartindex);
                    curext.directories = new List <VPKDirectory>();
                    break;

                case 1:
                    int pathstartindex = index;
                    level++;
                    while (body[index] != 0)
                    {
                        index++;
                    }
                    index++;
                    curpath         = new VPKDirectory();
                    curpath.path    = Encoding.ASCII.GetString(body, pathstartindex, index - pathstartindex);
                    curpath.ext     = curext.ext;
                    curpath.entries = new List <VPKFileEntry>();
                    break;

                case 2:
                    int filestartindex = index;
                    while (body[index] != 0)
                    {
                        index++;
                    }
                    index++;
                    VPKFileEntry vpkfile = new VPKFileEntry();
                    vpkfile.name = Encoding.ASCII.GetString(body, filestartindex, index - filestartindex);
                    vpkfile.path = curpath.path;
                    vpkfile.ext  = curext.ext;
                    vpkfile.body = StructTools.RawDeserialize <VPKFile>(body, index);
                    index       += 18;
                    index       += vpkfile.body.preload_bytes; // we ignore preload data
                    curpath.entries.Add(vpkfile);
                    break;
                }
            }
            return(ret);
        }