Skip to content

Commit 1789208

Browse files
authored
Merge pull request #6 from Sichii/master
EffectTable / bugfixes / performance/ qol
2 parents d214b38 + 4e1aea6 commit 1789208

File tree

13 files changed

+500
-64
lines changed

13 files changed

+500
-64
lines changed

DALib/Cryptography/CRC32.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
public static class CRC32
77
{
88
private static readonly uint[] CRC32_TABLE =
9-
{
9+
[
1010
0x00000000,
1111
0x77073096,
1212
0xEE0E612C,
@@ -263,7 +263,7 @@ public static class CRC32
263263
0xC30C8EA1,
264264
0x5A05DF1B,
265265
0x2D02EF8D
266-
};
266+
];
267267

268268
/// <summary>
269269
/// Calculates the 32bit checksum of the specified buffer

DALib/Data/DataArchive.cs

Lines changed: 92 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,74 @@ public virtual void Dispose()
7575
IsDisposed = true;
7676
}
7777

78+
/// <summary>
79+
/// Compiles the contents of the specified directory into a new archive.
80+
/// </summary>
81+
/// <param name="fromDir">
82+
/// The directory to compile into an archive
83+
/// </param>
84+
/// <param name="toPath">
85+
/// The destination path of the archive
86+
/// </param>
87+
public static void Compile(string fromDir, string toPath)
88+
{
89+
const int HEADER_LENGTH = 4;
90+
const int ENTRY_HEADER_LENGTH = 4 + CONSTANTS.DATA_ARCHIVE_ENTRY_NAME_LENGTH;
91+
92+
var files = Directory.GetFiles(fromDir);
93+
var dataStreams = new List<Stream>();
94+
95+
using var dat = File.Create(toPath.WithExtension(".dat"));
96+
using var writer = new BinaryWriter(dat, Encoding.Default, true);
97+
98+
writer.Write(files.Length + 1);
99+
100+
//add the file header length
101+
//plus the entry header length * number of entries
102+
//plus 4 bytes for the final entry's end address (which could also be considered the total number of bytes)
103+
var address = HEADER_LENGTH + files.Length * ENTRY_HEADER_LENGTH + 4;
104+
105+
foreach (var file in files)
106+
{
107+
var nameStr = Path.GetFileName(file);
108+
109+
// ReSharper disable once ConvertIfStatementToSwitchStatement
110+
if (nameStr.Length > CONSTANTS.DATA_ARCHIVE_ENTRY_NAME_LENGTH)
111+
throw new InvalidOperationException("Entry name is too long, must be 13 characters or less");
112+
113+
if (nameStr.Length < CONSTANTS.DATA_ARCHIVE_ENTRY_NAME_LENGTH)
114+
nameStr = nameStr.PadRight(CONSTANTS.DATA_ARCHIVE_ENTRY_NAME_LENGTH, '\0');
115+
116+
//get bytes for the name field (binaryWriter.Write(string) doesn't work for this)
117+
var nameStrBytes = Encoding.ASCII.GetBytes(nameStr);
118+
119+
writer.Write(address);
120+
writer.Write(nameStrBytes);
121+
122+
var dataStream = File.Open(
123+
file,
124+
new FileStreamOptions
125+
{
126+
Access = FileAccess.Read,
127+
Mode = FileMode.Open,
128+
Options = FileOptions.SequentialScan,
129+
Share = FileShare.ReadWrite,
130+
BufferSize = 8192
131+
});
132+
dataStreams.Add(dataStream);
133+
134+
address += (int)dataStream.Length;
135+
}
136+
137+
writer.Write(address);
138+
139+
foreach (var stream in dataStreams)
140+
{
141+
stream.CopyTo(dat);
142+
stream.Dispose();
143+
}
144+
}
145+
78146
/// <summary>
79147
/// Extracts the contents of the current archive to the specified directory.
80148
/// </summary>
@@ -171,8 +239,12 @@ public virtual void Patch(string entryName, ISavable item)
171239
{
172240
ThrowIfDisposed();
173241

174-
//if an entry exists with the same name, remove it
175-
Remove(entryName);
242+
//if an entry exists with the same name
243+
//grab its index, so we can replace it and preserve order
244+
var index = -1;
245+
246+
if (TryGetValue(entryName, out var existingEntry))
247+
index = IndexOf(existingEntry);
176248

177249
BaseStream.Seek(0, SeekOrigin.End);
178250
var address = (int)BaseStream.Length;
@@ -188,8 +260,11 @@ public virtual void Patch(string entryName, ISavable item)
188260
address,
189261
length);
190262

191-
//add entry to archive
192-
Add(entry);
263+
//if index is not -1, replace the existing entry
264+
if (index != -1)
265+
this[index] = entry;
266+
else //otherwise add new entry
267+
Add(entry);
193268
}
194269

195270
internal void ThrowIfDisposed() => ObjectDisposedException.ThrowIf(IsDisposed, this);
@@ -253,10 +328,9 @@ public virtual void Save(Stream stream)
253328
//plus 4 bytes for the final entry's end address (which could also be considered the total number of bytes)
254329
var address = HEADER_LENGTH + Count * ENTRY_HEADER_LENGTH + 4;
255330

256-
var orderedEntries = this.OrderBy(entry => entry.EntryName)
257-
.ToList();
331+
var entries = this.ToList();
258332

259-
foreach (var entry in orderedEntries)
333+
foreach (var entry in entries)
260334
{
261335
//reconstruct the name field with the required terminator
262336
var nameStr = entry.EntryName;
@@ -279,7 +353,7 @@ public virtual void Save(Stream stream)
279353

280354
writer.Write(address);
281355

282-
foreach (var entry in orderedEntries)
356+
foreach (var entry in entries)
283357
{
284358
using var segment = entry.ToStreamSegment();
285359
segment.CopyTo(stream);
@@ -300,15 +374,21 @@ public virtual void Save(Stream stream)
300374
/// </returns>
301375
public static DataArchive FromDirectory(string dir)
302376
{
377+
//create a buffer with a count of 0 entries
303378
var buffer = new MemoryStream();
379+
buffer.Write(new byte[4]);
380+
buffer.Seek(0, SeekOrigin.Begin);
304381

305382
//create a new in-memory archive
383+
//this will read the stream, finding 0 entries
306384
var archive = new DataArchive(buffer);
385+
buffer.Seek(0, SeekOrigin.End); //just incase
307386

308-
var address = 0;
387+
//start the address at 4, since the first 4 bytes are the entry count
388+
var address = 4;
309389

310390
//enumerate the directory, copying each file into the memory archive
311-
//maintain accurate address offsets for each file so that the archive is useable
391+
//maintain accurate address offsets for each file so that the archive is usable
312392
foreach (var file in Directory.EnumerateFiles(dir))
313393
{
314394
using var stream = File.Open(
@@ -338,6 +418,8 @@ public static DataArchive FromDirectory(string dir)
338418
archive.Add(entry);
339419
}
340420

421+
buffer.Seek(0, SeekOrigin.Begin);
422+
341423
return archive;
342424
}
343425

DALib/Data/DataArchiveEntry.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ namespace DALib.Data;
77
/// <summary>
88
/// Represents an entry in a data archive.
99
/// </summary>
10-
public sealed class DataArchiveEntry(
10+
public class DataArchiveEntry(
1111
DataArchive archive,
1212
string entryName,
1313
int address,

DALib/Data/PatchEntry.cs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
using System;
2+
using System.IO;
3+
using DALib.Abstractions;
4+
5+
namespace DALib.Data;
6+
7+
/// <summary>
8+
/// Represents an entry that can be used to patch a DataArchive without knowing it's underlying type
9+
/// </summary>
10+
public class PatchEntry : ISavable, IDisposable
11+
{
12+
private readonly Stream SourceStream;
13+
14+
/// <summary>
15+
/// Initializes a new instance of the <see cref="PatchEntry" /> class
16+
/// </summary>
17+
/// <param name="stream">
18+
/// The stream containing the data of this entry
19+
/// </param>
20+
public PatchEntry(Stream stream) => SourceStream = stream;
21+
22+
/// <inheritdoc />
23+
public void Dispose() => SourceStream.Dispose();
24+
25+
/// <inheritdoc />
26+
public void Save(string path)
27+
{
28+
using var stream = File.Open(
29+
path,
30+
new FileStreamOptions
31+
{
32+
Access = FileAccess.Write,
33+
Mode = FileMode.Create,
34+
Options = FileOptions.SequentialScan,
35+
Share = FileShare.ReadWrite
36+
});
37+
38+
Save(stream);
39+
}
40+
41+
/// <inheritdoc />
42+
public void Save(Stream stream)
43+
{
44+
SourceStream.Seek(0, SeekOrigin.Begin);
45+
SourceStream.CopyTo(stream);
46+
SourceStream.Seek(0, SeekOrigin.Begin);
47+
}
48+
}

0 commit comments

Comments
 (0)