-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathVirtualFileSystem.cs
More file actions
220 lines (180 loc) · 4.72 KB
/
Copy pathVirtualFileSystem.cs
File metadata and controls
220 lines (180 loc) · 4.72 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
using SteamDatabase.ValvePak;
using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Text;
using System.Threading.Tasks;
namespace SourceMapAnalyzer
{
public class VirtualFileSystem
{
private readonly string[] RootDirs = new string[] { "maps", "materials", "models", "particles", "resource", "sound" };
private VfsNode _root;
public VirtualFileSystem(string[] vpkFiles, string[] dirs)
{
_root = new VfsNode("", null);
foreach(var vpk in vpkFiles)
{
AddVpkToTree(vpk);
}
foreach(var dir in dirs)
{
AddDirToTree(dir);
}
}
public bool ExistsNoExtension(string file)
{
file = file.ToLower();
var node = GetNode(Path.GetDirectoryName(file));
if(node == null)
{
return false;
}
return node.Children.Any(c => c.Name.Split('.')[0] == file);
}
public bool Exists(string file) => GetNode(file) != null;
public IVfsFile GetFile(string file) => GetNode(file)?.File;
public IEnumerable<IVfsFile> GetFiles(string dir)
{
var dirNode = GetNode(dir);
return dirNode.Children.Where(c => !c.Children.Any()).Select(c => c.File);
}
private VfsNode GetNode(string path)
{
var parts = path.ToLower().Split(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
var node = _root;
foreach (var part in parts)
{
if (!node.TryGetChild(part, out var newNode))
{
return null;
}
node = newNode;
}
return node;
}
private void AddVpkToTree(string vpk)
{
var package = new Package();
package.Read(vpk);
foreach(var ext in package.Entries)
{
foreach(var entry in ext.Value)
{
var parts = entry.GetFullPath().Split('/');
var node = _root;
foreach(var part in parts)
{
VfsNode newNode;
if(!node.TryGetChild(part, out newNode))
{
newNode = new VfsNode(part, new VpkFile(package, entry));
node.AddChild(newNode);
}
node = newNode;
}
}
}
}
private void AddDirToTree(string dir)
{
foreach(var d in RootDirs)
{
AddDirToTree(dir, Path.Combine(dir, d), new string[] { }, _root);
}
}
private void AddDirToTree(string baseDir, string dir, string[] parts, VfsNode parentNode)
{
var dirName = Path.GetFileName(dir);
VfsNode thisNode;
if(!parentNode.TryGetChild(dirName, out thisNode))
{
thisNode = new VfsNode(dirName, new DirFile(baseDir, dir));
parentNode.AddChild(thisNode);
}
foreach(var f in Directory.EnumerateFiles(dir))
{
var name = Path.GetFileName(f);
thisNode.AddChild(new VfsNode(name, new DirFile(baseDir, f)));
}
foreach(var d in Directory.EnumerateDirectories(dir))
{
var name = Path.GetFileName(d);
AddDirToTree(baseDir, d, parts.Concat(new string[] { name }).ToArray(), thisNode);
}
}
public interface IVfsFile
{
Stream OpenRead();
string ReadAllText();
void Copy(string dest);
string FileName { get; }
string FilePath { get; }
}
private class VpkFile : IVfsFile
{
private PackageEntry _entry;
private Package _package;
public string FileName => _entry.FileName;
public string FilePath => _entry.GetFullPath();
public VpkFile(Package package, PackageEntry entry)
{
_package = package;
_entry = entry;
}
public Stream OpenRead()
{
_package.ReadEntry(_entry, out var bytes);
return new MemoryStream(bytes);
}
public string ReadAllText()
{
_package.ReadEntry(_entry, out var bytes);
return Encoding.UTF8.GetString(bytes);
}
public void Copy(string dest)
{
_package.ReadEntry(_entry, out var bytes);
File.WriteAllBytes(dest, bytes);
}
}
private class DirFile : IVfsFile
{
private string _path;
private string _baseDir;
public string FileName => Path.GetFileName(_path);
public string FilePath => Path.GetFullPath(_path).Replace(Path.GetFullPath(_baseDir) + "\\", "");
public DirFile(string baseDir, string path)
{
_path = path;
_baseDir = baseDir;
}
public Stream OpenRead() => File.OpenRead(_path);
public string ReadAllText() => File.ReadAllText(_path);
public void Copy(string dest) => File.Copy(_path, dest);
}
private class VfsNode
{
public string Name;
public IVfsFile File => _file;
public IEnumerable<VfsNode> Children => _children.Values;
private IVfsFile _file;
private Dictionary<string, VfsNode> _children;
public VfsNode(string name, IVfsFile file)
{
Name = name.ToLower();
_file = file;
_children = new Dictionary<string, VfsNode>();
}
public void AddChild(VfsNode node)
{
_children[node.Name] = node;
}
public bool TryGetChild(string name, out VfsNode node)
{
return _children.TryGetValue(name.ToLower(), out node);
}
}
}
}