*
This commit is contained in:
@@ -0,0 +1,186 @@
|
||||
using SourceFormatParser.Common;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
|
||||
public class VPKFile
|
||||
{
|
||||
public struct Header {
|
||||
public uint Magic;
|
||||
public uint Version;
|
||||
public uint TreeSizeInBytes;
|
||||
public uint FileDataSectionSize;
|
||||
public uint ArchiveMD5SectionSize;
|
||||
public uint OtherMD5SectionSize;
|
||||
public uint SignatureSectionSize;
|
||||
//Assert(0x55aa1234 == Magic, "WTF");
|
||||
}
|
||||
|
||||
public struct FileDescription {
|
||||
public uint CRC;
|
||||
public ushort PreloadBytes;
|
||||
public ushort ArchiveId;
|
||||
public uint EntryOffset;
|
||||
public uint EntryLength;
|
||||
public ushort ConstFooter;
|
||||
}
|
||||
|
||||
public class FileRecord {
|
||||
public string Name;
|
||||
public FileDescription Description;
|
||||
public byte[] PreloadData;
|
||||
}
|
||||
|
||||
public class DirectoryRecord {
|
||||
public string Name;
|
||||
public List<FileRecord> Files = new List<FileRecord>();
|
||||
}
|
||||
|
||||
public class ExtensionRecord
|
||||
{
|
||||
public string Name;
|
||||
public List<DirectoryRecord> Directories = new List<DirectoryRecord>();
|
||||
}
|
||||
|
||||
|
||||
public static string ReadSZString(BinaryReader reader)
|
||||
{
|
||||
var result = new StringBuilder();
|
||||
while (true) {
|
||||
byte b = reader.ReadByte();
|
||||
if (0 == b)
|
||||
break;
|
||||
result.Append((char)b);
|
||||
}
|
||||
return result.ToString();
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static FileRecord FindFile(List<ExtensionRecord> tree, string path)
|
||||
{
|
||||
var fileNameSeparator = path.LastIndexOf('/');
|
||||
var dir = path.Substring(0, fileNameSeparator);
|
||||
var fileNameWithExtension = path.Substring(fileNameSeparator + 1);
|
||||
|
||||
var extSeparator = fileNameWithExtension.LastIndexOf('.');
|
||||
var fileName = fileNameWithExtension.Substring(0, extSeparator);
|
||||
var ext = fileNameWithExtension.Substring(extSeparator + 1);
|
||||
|
||||
var extRecord = tree.FirstOrDefault(x => x.Name == ext);
|
||||
if (extRecord == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var dirRecord = extRecord.Directories.FirstOrDefault(x => x.Name == dir);
|
||||
if (dirRecord == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var fileRecord = dirRecord.Files.FirstOrDefault(x => x.Name == fileName);
|
||||
return fileRecord;
|
||||
}
|
||||
|
||||
public static byte[] ReadFile(string vpkDirectory, string pakNamePrefix, FileRecord record)
|
||||
{
|
||||
var archiveId = record.Description.ArchiveId;
|
||||
var archiveFileName = pakNamePrefix + "_" + archiveId.ToString("D3") + ".vpk";
|
||||
|
||||
var archiveFilePath = System.IO.Path.Combine(vpkDirectory, archiveFileName);
|
||||
|
||||
var stream = System.IO.File.OpenRead(archiveFilePath);
|
||||
stream.Seek(record.Description.EntryOffset, SeekOrigin.Begin);
|
||||
|
||||
var reader = new BinaryReader(stream);
|
||||
var result = reader.ReadBytes((int)record.Description.EntryLength);
|
||||
|
||||
reader.Close();
|
||||
return result;
|
||||
}
|
||||
|
||||
//pak01_dir.vpk
|
||||
public static List<ExtensionRecord> ReadDirTree(string dirVpkFile)
|
||||
{
|
||||
var stream = File.OpenRead(dirVpkFile);
|
||||
|
||||
BinaryReader br = new BinaryReader(stream, Encoding.ASCII, false);
|
||||
|
||||
Header header = new Header();
|
||||
header.Magic = br.ReadUInt32();
|
||||
if(header.Magic != 0x55aa1234) {
|
||||
throw new Exception("Invalid magic number");
|
||||
}
|
||||
|
||||
header.Version = br.ReadUInt32();
|
||||
if(header.Version != 2) {
|
||||
throw new Exception($"Version {header.Version} is not supported");
|
||||
}
|
||||
|
||||
header.TreeSizeInBytes = br.ReadUInt32();
|
||||
header.FileDataSectionSize = br.ReadUInt32();
|
||||
header.ArchiveMD5SectionSize = br.ReadUInt32();
|
||||
header.OtherMD5SectionSize = br.ReadUInt32();
|
||||
header.SignatureSectionSize = br.ReadUInt32();
|
||||
|
||||
|
||||
List<ExtensionRecord> result = new List<ExtensionRecord>();
|
||||
|
||||
while (true) {
|
||||
string extName = ReadSZString(br);
|
||||
if (string.IsNullOrEmpty(extName)) {
|
||||
break;
|
||||
}
|
||||
|
||||
ExtensionRecord extRecord = new ExtensionRecord();
|
||||
extRecord.Name = extName;
|
||||
|
||||
while (true) {
|
||||
string dirName = ReadSZString(br);
|
||||
if (string.IsNullOrEmpty(dirName)) {
|
||||
break;
|
||||
}
|
||||
|
||||
DirectoryRecord dirRecord = new DirectoryRecord();
|
||||
dirRecord.Name = dirName;
|
||||
|
||||
while (true) {
|
||||
string fileName = ReadSZString(br);
|
||||
if (string.IsNullOrEmpty(fileName)) {
|
||||
break;
|
||||
}
|
||||
|
||||
FileRecord fileRecord = new FileRecord();
|
||||
fileRecord.Name = fileName;
|
||||
|
||||
//read file desc
|
||||
FileDescription desc = new FileDescription();
|
||||
desc.CRC = br.ReadUInt32();
|
||||
desc.PreloadBytes = br.ReadUInt16();
|
||||
desc.ArchiveId = br.ReadUInt16();
|
||||
desc.EntryOffset = br.ReadUInt32();
|
||||
desc.EntryLength = br.ReadUInt32();
|
||||
desc.ConstFooter = br.ReadUInt16();
|
||||
|
||||
fileRecord.Description = desc;
|
||||
|
||||
if(desc.PreloadBytes != 0) {
|
||||
fileRecord.PreloadData = br.ReadBytes(desc.PreloadBytes);
|
||||
}
|
||||
|
||||
dirRecord.Files.Add(fileRecord);
|
||||
}
|
||||
|
||||
extRecord.Directories.Add(dirRecord);
|
||||
}
|
||||
|
||||
result.Add(extRecord);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user