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 pathArchiveReader.cs
More file actions
102 lines (83 loc) · 3.14 KB
/
ArchiveReader.cs
File metadata and controls
102 lines (83 loc) · 3.14 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
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
namespace CSystemArc
{
internal class ArchiveReader : IDisposable
{
private readonly IList<Stream> _contentStreams;
private readonly bool _leaveOpen;
private readonly Dictionary<char, List<ArchiveEntry>> _entries = new Dictionary<char, List<ArchiveEntry>>();
public ArchiveReader(string indexFilePath, IList<string> contentFilePaths)
{
_contentStreams = new List<Stream>();
foreach (string contentFilePath in contentFilePaths)
{
_contentStreams.Add(File.OpenRead(contentFilePath));
}
_leaveOpen = false;
using Stream indexStream = File.OpenRead(indexFilePath);
ReadEntries(indexStream);
}
public ArchiveReader(Stream indexStream, IList<Stream> contentStreams, bool leaveOpen = false)
{
_contentStreams = contentStreams;
_leaveOpen = leaveOpen;
ReadEntries(indexStream);
if (!leaveOpen)
indexStream.Dispose();
}
private void ReadEntries(Stream compressedIndexStream)
{
byte[] index = BcdCompression.Decompress(compressedIndexStream);
using Stream indexStream = new MemoryStream(index);
BinaryReader indexReader = new BinaryReader(indexStream);
int prevId = -1;
while (indexStream.Position < indexStream.Length)
{
ArchiveEntry entry = new ArchiveEntry();
entry.Read(indexReader);
List<ArchiveEntry> entriesOfType = _entries.FetchValue(entry.Type, () => new List<ArchiveEntry>());
entry.Index = entriesOfType.Count;
entriesOfType.Add(entry);
//if (entry.Id <= prevId)
// throw new InvalidDataException("Entries not sorted by ID");
prevId = entry.Id;
}
}
public IEnumerable<ArchiveEntry> Entries => _entries.SelectMany(p => p.Value);
public ArchiveEntry GetEntry(char type, int index)
{
return _entries[type][index];
}
public byte[] GetEntryContent(ArchiveEntry entry)
{
Stream contentStream = _contentStreams[entry.ContentArchiveIndex];
contentStream.Position = entry.Offset;
byte[] data = new byte[entry.UncompressedSize];
if (entry.CompressedSize == entry.UncompressedSize)
{
contentStream.Read(data, 0, data.Length);
}
else
{
using LzssStream lzss = new LzssStream(contentStream, CompressionMode.Decompress, true);
lzss.Read(data, 0, data.Length);
}
return data;
}
public void Dispose()
{
if (!_leaveOpen)
{
foreach (Stream contentStream in _contentStreams)
{
contentStream.Dispose();
}
}
_contentStreams.Clear();
}
}
}