This repository was archived by the owner on Jun 2, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathArchiveWriter.cs
More file actions
121 lines (104 loc) · 3.97 KB
/
ArchiveWriter.cs
File metadata and controls
121 lines (104 loc) · 3.97 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
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
namespace CSystemArc
{
internal class ArchiveWriter : IDisposable
{
private const int MaxContentArchiveSize = 0x7FFFFFFF;
private readonly int _version;
private readonly Stream _indexStream;
private readonly IList<Stream> _contentStreams;
private readonly bool _leaveOpen;
private bool _disposed;
private readonly List<ArchiveEntry> _entries = new List<ArchiveEntry>();
public ArchiveWriter(int version, string indexFilePath, IList<string> contentFilePaths)
{
_version = version;
_indexStream = File.Open(indexFilePath, FileMode.Create, FileAccess.Write);
_contentStreams = new List<Stream>();
foreach (string contentFilePath in contentFilePaths)
{
_contentStreams.Add(File.Open(contentFilePath, FileMode.Create, FileAccess.Write));
}
_leaveOpen = false;
}
public ArchiveWriter(int version, Stream indexStream, IList<Stream> contentStreams, bool leaveOpen = false)
{
_version = version;
_indexStream = indexStream;
_contentStreams = contentStreams;
_leaveOpen = leaveOpen;
}
public void Write(int id, char type, char subType, byte[] content)
{
Write(id, type, subType, new ArraySegment<byte>(content));
}
public void Write(int id, char type, char subType, ArraySegment<byte> content)
{
int contentArchiveIndex = 0;
while (_contentStreams[contentArchiveIndex].Length + content.Count > MaxContentArchiveSize)
{
contentArchiveIndex++;
}
Stream contentStream = _contentStreams[contentArchiveIndex];
ArchiveEntry entry =
new ArchiveEntry
{
Version = _version,
ContentArchiveIndex = contentArchiveIndex,
Id = id,
Type = type,
SubType = subType,
Offset = (int)contentStream.Position,
UncompressedSize = content.Count
};
bool compressed = (type == 'b' ||
type == 'c' ||
type == 'e' ||
type == 'n' ||
type == 'o' ||
type == 'p');
if (compressed)
{
using LzssStream lzss = new LzssStream(contentStream, CompressionMode.Compress, true);
lzss.Write(content.Array, content.Offset, content.Count);
}
else
{
contentStream.Write(content.Array, content.Offset, content.Count);
}
entry.CompressedSize = (int)contentStream.Position - entry.Offset;
_entries.Add(entry);
}
private void WriteIndex()
{
using MemoryStream uncompressedIndexStream = new MemoryStream();
BinaryWriter writer = new BinaryWriter(uncompressedIndexStream);
foreach (ArchiveEntry entry in _entries.OrderBy(e => e.Id))
{
entry.Write(writer);
}
uncompressedIndexStream.TryGetBuffer(out ArraySegment<byte> uncompressedIndexData);
BcdCompression.Compress(uncompressedIndexData, _indexStream);
}
public void Dispose()
{
if (_disposed)
return;
WriteIndex();
if (!_leaveOpen)
{
foreach (Stream contentStream in _contentStreams)
{
contentStream.Dispose();
}
_indexStream?.Dispose();
}
_contentStreams.Clear();
_disposed = true;
}
}
}