Survivalcraft API 1.8.2.3 v1.8.2.3
Survivalcraft 2.4
载入中...
搜索中...
未找到
ZipArchive.cs
浏览该文件的文档.
1using System.IO.Compression;
2using System.Text;
3
4namespace Game {
5 public class ZipArchive : IDisposable {
6 public enum Compression : ushort {
7 Store = 0,
9 }
10
11 public bool ForceDeflating;
12
13 public bool KeepStreamOpen;
14
15 public List<ZipArchiveEntry> Files = [];
16
17 public Stream ZipFileStream;
18
19 public string Comment = "";
20
21 public byte[] CentralDirImage;
22
23 public ushort ExistingFiles;
24
25 public bool ReadOnly;
26
27 public static uint[] CrcTable;
28
29 static ZipArchive() {
30 CrcTable = new uint[256];
31 for (int i = 0; i < CrcTable.Length; i++) {
32 uint num = (uint)i;
33 for (int j = 0; j < 8; j++) {
34 num = (uint)((num & 1) == 0 ? (int)(num >> 1) : -306674912 ^ (int)(num >> 1));
35 }
36 CrcTable[i] = num;
37 }
38 }
39
40 public static ZipArchive Create(Stream stream, bool keepStreamOpen = false) => new() {
41 Comment = string.Empty, ZipFileStream = stream, ReadOnly = false, KeepStreamOpen = keepStreamOpen
42 };
43
44 public static ZipArchive Open(Stream stream, bool keepStreamOpen = false) {
45 ZipArchive zipArchive = new() { ZipFileStream = stream, ReadOnly = true, KeepStreamOpen = keepStreamOpen };
46 return zipArchive.ReadFileInfo() ? zipArchive : throw new InvalidDataException();
47 }
48
49 public void AddStream(string filenameInZip, Stream source) {
50 if (ReadOnly) {
51 throw new InvalidOperationException("Writing is not allowed");
52 }
53 ZipArchiveEntry zipArchiveEntry = new() {
54 Method = Compression.Deflate,
55 FilenameInZip = NormalizedFilename(filenameInZip),
56 Comment = string.Empty,
57 Crc32 = 0u,
58 HeaderOffset = (uint)ZipFileStream.Position,
59 ModifyTime = DateTime.Now
60 };
61 WriteLocalHeader(zipArchiveEntry);
62 zipArchiveEntry.FileOffset = (uint)ZipFileStream.Position;
63 Store(zipArchiveEntry, source);
64 UpdateCrcAndSizes(zipArchiveEntry);
65 Files.Add(zipArchiveEntry);
66 }
67
68 public void Close() {
69 if (!ReadOnly) {
70 uint offset = (uint)ZipFileStream.Position;
71 uint num = 0u;
72 if (CentralDirImage != null) {
74 }
75 for (int i = 0; i < Files.Count; i++) {
76 long position = ZipFileStream.Position;
78 num = (uint)((int)num + (int)(ZipFileStream.Position - position));
79 }
80 if (CentralDirImage != null) {
81 WriteEndRecord((uint)((int)num + CentralDirImage.Length), offset);
82 }
83 else {
84 WriteEndRecord(num, offset);
85 }
86 }
87 if (ZipFileStream != null
88 && !KeepStreamOpen) {
89 ZipFileStream.Flush();
90 ZipFileStream.Dispose();
91 }
92 ZipFileStream = null;
93 }
94
95 public static bool IsUTF8Bytes(byte[] data, int start, int count) {
96 int charByteCounter = 1; //计算当前正分析的字符应还有的字节数
97 byte curByte; //当前分析的字节.
98 int end = start + count;
99 for (int i = start; i < end; i++) {
100 curByte = data[i];
101 if (charByteCounter == 1) {
102 if (curByte >= 0x80) {
103 while (((curByte <<= 1) & 0x80) != 0) {
104 charByteCounter++;
105 }
106 if (charByteCounter == 1
107 || charByteCounter > 6) {
108 return false;
109 }
110 }
111 }
112 else {
113 if ((curByte & 0xC0) != 0x80) {
114 return false;
115 }
116 charByteCounter--;
117 }
118 }
119 if (charByteCounter > 1) {
120 throw new Exception("非预期的byte格式");
121 }
122 return true;
123 }
124
125 public List<ZipArchiveEntry> ReadCentralDir() {
126 if (CentralDirImage == null) {
127 throw new InvalidOperationException("Central directory currently does not exist");
128 }
129 List<ZipArchiveEntry> list = new();
130 ushort num;
131 ushort num2;
132 ushort num3;
133 for (int i = 0; i < CentralDirImage.Length && BitConverter.ToUInt32(CentralDirImage, i) == 33639248; i += 46 + num + num2 + num3) {
134 ushort method = BitConverter.ToUInt16(CentralDirImage, i + 10);
135 uint dt = BitConverter.ToUInt32(CentralDirImage, i + 12);
136 uint crc = BitConverter.ToUInt32(CentralDirImage, i + 16);
137 uint compressedSize = BitConverter.ToUInt32(CentralDirImage, i + 20);
138 uint fileSize = BitConverter.ToUInt32(CentralDirImage, i + 24);
139 num = BitConverter.ToUInt16(CentralDirImage, i + 28);
140 num2 = BitConverter.ToUInt16(CentralDirImage, i + 30);
141 num3 = BitConverter.ToUInt16(CentralDirImage, i + 32);
142 uint headerOffset = BitConverter.ToUInt32(CentralDirImage, i + 42);
143 uint headerSize = (uint)(46 + num + num2 + num3);
144 Encoding uTF = Encoding.UTF8;
145 ZipArchiveEntry zipArchiveEntry = new() {
146 Method = (Compression)method,
147 FilenameInZip = NormalizedFilename(uTF.GetString(CentralDirImage, i + 46, num)),
148 IsFilenameUtf8 = IsUTF8Bytes(CentralDirImage, i + 46, num),
149 FileOffset = GetFileOffset(headerOffset),
150 FileSize = fileSize,
151 CompressedSize = compressedSize,
152 HeaderOffset = headerOffset,
153 HeaderSize = headerSize,
154 Crc32 = crc,
155 ModifyTime = DosTimeToDateTime(dt)
156 };
157 if (num3 > 0) {
158 zipArchiveEntry.Comment = uTF.GetString(CentralDirImage, i + 46 + num + num2, num3);
159 }
160 list.Add(zipArchiveEntry);
161 }
162 return list;
163 }
164
165 public void ExtractFile(ZipArchiveEntry zfe, Stream stream) {
166 if (!stream.CanWrite) {
167 throw new InvalidOperationException("Stream cannot be written");
168 }
169 byte[] array = new byte[4];
170 ZipFileStream.Seek(zfe.HeaderOffset, SeekOrigin.Begin);
171 ZipFileStream.ReadExactly(array, 0, 4);
172 if (BitConverter.ToUInt32(array, 0) != 67324752) {
173 throw new InvalidOperationException("Unsupported zip archive.");
174 }
175 Stream stream2;
176 if (zfe.Method == Compression.Store) {
177 stream2 = ZipFileStream;
178 }
179 else {
180 if (zfe.Method != Compression.Deflate) {
181 throw new InvalidOperationException("Unsupported zip archive.");
182 }
183 stream2 = new DeflateStream(ZipFileStream, CompressionMode.Decompress, true);
184 }
185 byte[] array2 = new byte[16384];
186 ZipFileStream.Seek(zfe.FileOffset, SeekOrigin.Begin);
187 uint num = zfe.FileSize;
188 while (num != 0) {
189 int num2 = stream2.Read(array2, 0, (int)Math.Min(num, array2.Length));
190 stream.Write(array2, 0, num2);
191 num = (uint)((int)num - num2);
192 }
193 stream.Flush();
194 if (zfe.Method == Compression.Deflate) {
195 stream2.Dispose();
196 }
197 }
198
199 public uint GetFileOffset(uint _headerOffset) {
200 byte[] array = new byte[2];
201 ZipFileStream.Seek(_headerOffset + 26, SeekOrigin.Begin);
202 ZipFileStream.ReadExactly(array, 0, 2);
203 ushort num = BitConverter.ToUInt16(array, 0);
204 ZipFileStream.ReadExactly(array, 0, 2);
205 ushort num2 = BitConverter.ToUInt16(array, 0);
206 return (uint)(30 + num + num2 + _headerOffset);
207 }
208
210 long position = ZipFileStream.Position;
211 byte[] bytes = Encoding.UTF8.GetBytes(_zfe.FilenameInZip);
212 ZipFileStream.Write([80, 75, 3, 4, 20, 0], 0, 6);
213 ZipFileStream.Write(BitConverter.GetBytes((ushort)(_zfe.EncodeUTF8 ? 2048 : 0)), 0, 2);
214 ZipFileStream.Write(BitConverter.GetBytes((ushort)_zfe.Method), 0, 2);
215 ZipFileStream.Write(BitConverter.GetBytes(DateTimeToDosTime(_zfe.ModifyTime)), 0, 4);
216 ZipFileStream.Write(new byte[12], 0, 12);
217 ZipFileStream.Write(BitConverter.GetBytes((ushort)bytes.Length), 0, 2);
218 ZipFileStream.Write(BitConverter.GetBytes((ushort)0), 0, 2);
219 ZipFileStream.Write(bytes, 0, bytes.Length);
220 _zfe.HeaderSize = (uint)(ZipFileStream.Position - position);
221 }
222
224 Encoding uTF = Encoding.UTF8;
225 byte[] bytes = uTF.GetBytes(_zfe.FilenameInZip);
226 byte[] bytes2 = uTF.GetBytes(_zfe.Comment);
227 ZipFileStream.Write(
228 [
229 80,
230 75,
231 1,
232 2,
233 23,
234 11,
235 20,
236 0
237 ],
238 0,
239 8
240 );
241 ZipFileStream.Write(BitConverter.GetBytes((ushort)(_zfe.EncodeUTF8 ? 2048 : 0)), 0, 2);
242 ZipFileStream.Write(BitConverter.GetBytes((ushort)_zfe.Method), 0, 2);
243 ZipFileStream.Write(BitConverter.GetBytes(DateTimeToDosTime(_zfe.ModifyTime)), 0, 4);
244 ZipFileStream.Write(BitConverter.GetBytes(_zfe.Crc32), 0, 4);
245 ZipFileStream.Write(BitConverter.GetBytes(_zfe.CompressedSize), 0, 4);
246 ZipFileStream.Write(BitConverter.GetBytes(_zfe.FileSize), 0, 4);
247 ZipFileStream.Write(BitConverter.GetBytes((ushort)bytes.Length), 0, 2);
248 ZipFileStream.Write(BitConverter.GetBytes((ushort)0), 0, 2);
249 ZipFileStream.Write(BitConverter.GetBytes((ushort)bytes2.Length), 0, 2);
250 ZipFileStream.Write(BitConverter.GetBytes((ushort)0), 0, 2);
251 ZipFileStream.Write(BitConverter.GetBytes((ushort)0), 0, 2);
252 ZipFileStream.Write(BitConverter.GetBytes((ushort)0), 0, 2);
253 ZipFileStream.Write(BitConverter.GetBytes((ushort)33024), 0, 2);
254 ZipFileStream.Write(BitConverter.GetBytes(_zfe.HeaderOffset), 0, 4);
255 ZipFileStream.Write(bytes, 0, bytes.Length);
256 ZipFileStream.Write(bytes2, 0, bytes2.Length);
257 }
258
259 public void WriteEndRecord(uint _size, uint _offset) {
260 byte[] bytes = Encoding.UTF8.GetBytes(Comment);
261 ZipFileStream.Write(
262 [
263 80,
264 75,
265 5,
266 6,
267 0,
268 0,
269 0,
270 0
271 ],
272 0,
273 8
274 );
275 ZipFileStream.Write(BitConverter.GetBytes((ushort)Files.Count + ExistingFiles), 0, 2);
276 ZipFileStream.Write(BitConverter.GetBytes((ushort)Files.Count + ExistingFiles), 0, 2);
277 ZipFileStream.Write(BitConverter.GetBytes(_size), 0, 4);
278 ZipFileStream.Write(BitConverter.GetBytes(_offset), 0, 4);
279 ZipFileStream.Write(BitConverter.GetBytes((ushort)bytes.Length), 0, 2);
280 ZipFileStream.Write(bytes, 0, bytes.Length);
281 }
282
283 public void Store(ZipArchiveEntry _zfe, Stream _source) {
284 byte[] array = new byte[16384];
285 uint num = 0u;
286 long position = ZipFileStream.Position;
287 long position2 = _source.Position;
288 Stream stream = _zfe.Method != 0 ? new DeflateStream(ZipFileStream, CompressionMode.Compress, true) : ZipFileStream;
289 _zfe.Crc32 = 4294967295u;
290 int num2;
291 do {
292 num2 = _source.Read(array, 0, array.Length);
293 num = (uint)((int)num + num2);
294 if (num2 > 0) {
295 stream.Write(array, 0, num2);
296 for (uint num3 = 0u; num3 < num2; num3++) {
297 _zfe.Crc32 = CrcTable[(_zfe.Crc32 ^ array[num3]) & 0xFF] ^ (_zfe.Crc32 >> 8);
298 }
299 }
300 }
301 while (num2 == array.Length);
302 stream.Flush();
303 if (_zfe.Method == Compression.Deflate) {
304 stream.Dispose();
305 }
306 _zfe.Crc32 ^= 4294967295u;
307 _zfe.FileSize = num;
308 _zfe.CompressedSize = (uint)(ZipFileStream.Position - position);
309 if (_zfe.Method == Compression.Deflate
311 && _source.CanSeek
312 && _zfe.CompressedSize > _zfe.FileSize) {
313 _zfe.Method = Compression.Store;
314 ZipFileStream.Position = position;
315 ZipFileStream.SetLength(position);
316 _source.Position = position2;
317 Store(_zfe, _source);
318 }
319 }
320
321 public uint DateTimeToDosTime(DateTime _dt) => (uint)((_dt.Second / 2)
322 | (_dt.Minute << 5)
323 | (_dt.Hour << 11)
324 | (_dt.Day << 16)
325 | (_dt.Month << 21)
326 | ((_dt.Year - 1980) << 25));
327
328 public DateTime DosTimeToDateTime(uint _dt) => new(
329 (int)((_dt >> 25) + 1980),
330 (int)((_dt >> 21) & 0xF),
331 (int)((_dt >> 16) & 0x1F),
332 (int)((_dt >> 11) & 0x1F),
333 (int)((_dt >> 5) & 0x3F),
334 (int)((_dt & 0x1F) * 2)
335 );
336
337 public virtual void UpdateCrcAndSizes(ZipArchiveEntry _zfe) {
338 long position = ZipFileStream.Position;
339 ZipFileStream.Position = _zfe.HeaderOffset + 8;
340 ZipFileStream.Write(BitConverter.GetBytes((ushort)_zfe.Method), 0, 2);
341 ZipFileStream.Position = _zfe.HeaderOffset + 14;
342 ZipFileStream.Write(BitConverter.GetBytes(_zfe.Crc32), 0, 4);
343 ZipFileStream.Write(BitConverter.GetBytes(_zfe.CompressedSize), 0, 4);
344 ZipFileStream.Write(BitConverter.GetBytes(_zfe.FileSize), 0, 4);
345 ZipFileStream.Position = position;
346 }
347
348 public string NormalizedFilename(string _filename) {
349 string text = _filename.Replace('\\', '/');
350 int num = text.IndexOf(':');
351 if (num >= 0) {
352 text = text.Remove(0, num + 1);
353 }
354 return text.Trim('/');
355 }
356
357 public bool ReadFileInfo() {
358 if (ZipFileStream.Length < 22) {
359 return false;
360 }
361 try {
362 ZipFileStream.Seek(-17L, SeekOrigin.End);
363 BinaryReader binaryReader = new(ZipFileStream);
364 do {
365 ZipFileStream.Seek(-5L, SeekOrigin.Current);
366 if (binaryReader.ReadUInt32() == 101010256) {
367 ZipFileStream.Seek(6L, SeekOrigin.Current);
368 ushort existingFiles = binaryReader.ReadUInt16();
369 int num = binaryReader.ReadInt32();
370 uint num2 = binaryReader.ReadUInt32();
371 ushort num3 = binaryReader.ReadUInt16();
372 if (ZipFileStream.Position + num3 != ZipFileStream.Length) {
373 return false;
374 }
375 ExistingFiles = existingFiles;
376 CentralDirImage = new byte[num];
377 ZipFileStream.Seek(num2, SeekOrigin.Begin);
378 ZipFileStream.ReadExactly(CentralDirImage, 0, num);
379 ZipFileStream.Seek(num2, SeekOrigin.Begin);
380 return true;
381 }
382 }
383 while (ZipFileStream.Position > 0);
384 }
385 catch {
386 // ignored
387 }
388 return false;
389 }
390
391 public void Dispose() {
392 Close();
393 }
394 }
395}
DateTime ModifyTime
uint CompressedSize
string FilenameInZip
ZipArchive.Compression Method
uint HeaderOffset
uint FileOffset
bool EncodeUTF8
uint FileSize
uint Crc32
string Comment
static ZipArchive Create(Stream stream, bool keepStreamOpen=false)
uint DateTimeToDosTime(DateTime _dt)
DateTime DosTimeToDateTime(uint _dt)
uint GetFileOffset(uint _headerOffset)
void ExtractFile(ZipArchiveEntry zfe, Stream stream)
void AddStream(string filenameInZip, Stream source)
void WriteEndRecord(uint _size, uint _offset)
void Store(ZipArchiveEntry _zfe, Stream _source)
string NormalizedFilename(string _filename)
static uint[] CrcTable
virtual void UpdateCrcAndSizes(ZipArchiveEntry _zfe)
List< ZipArchiveEntry > Files
List< ZipArchiveEntry > ReadCentralDir()
void WriteLocalHeader(ZipArchiveEntry _zfe)
static bool IsUTF8Bytes(byte[] data, int start, int count)
void WriteCentralDirRecord(ZipArchiveEntry _zfe)
static ZipArchive Open(Stream stream, bool keepStreamOpen=false)