public static long filealignment = 1024; // 1^10 - align to kilobyte boundaries /// <summary> /// Construct a VPK object with a specific filename /// </summary> /// <param name="filename">The filename (relative) where the vpk is</param> public VPK(string filename) { vpkmutex.WaitOne(); if (filename.EndsWith(".vpk")) { filename = filename.Substring(0, filename.Length - 4); } if (filename.EndsWith("_dir")) { filename = filename.Substring(0, filename.Length - 4); } fileprefix = filename; if (!File.Exists(fileprefix + "_dir.vpk")) { //we've gotta make a new vpk from scratch using (FileStream headfile = File.Create(fileprefix + "_dir.vpk")) { using (BinaryWriter writer = new BinaryWriter(headfile)) { VPKHeader head = new VPKHeader(null); writer.Write(StructTools.RawSerialize(head)); } } } vpkmutex.ReleaseMutex(); }
/// <summary> /// Write a new _dir.vpk file, based on a vpk directory structure. /// </summary> /// <param name="directoryinfo">A big directory information structure as a List of VPKExts</param> private void WriteDirectory(List <VPKExt> directoryinfo) { using (FileStream output = File.OpenWrite(fileprefix + "_dir.vpk")) { using (BinaryWriter bw = new BinaryWriter(output)) { VPKHeader headerbin = new VPKHeader(null); bw.Write(StructTools.RawSerialize(headerbin)); foreach (VPKExt ext in directoryinfo) { bw.Write(Encoding.ASCII.GetBytes(ext.ext)); bw.Write((byte)0); //null terminator foreach (VPKDirectory dir in ext.directories) { bw.Write(Encoding.ASCII.GetBytes(dir.path)); bw.Write((byte)0); foreach (VPKFileEntry fe in dir.entries) { bw.Write(Encoding.ASCII.GetBytes(fe.name)); bw.Write(StructTools.RawSerialize(fe.body)); } bw.Write((byte)0); } bw.Write((byte)0); } // Go back and fix up the length long len = bw.BaseStream.Position; bw.Seek(0, SeekOrigin.Begin); headerbin.tree_length = (uint)(len - 18); bw.Write(StructTools.RawSerialize(headerbin)); } } }
/// <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); }