Skip to content

Commit d13c496

Browse files
committed
Add temporary test code for MS-ZIP
1 parent b6d9dcd commit d13c496

File tree

1 file changed

+286
-1
lines changed

1 file changed

+286
-1
lines changed

Test/Program.cs

Lines changed: 286 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
using SabreTools.Compression;
1+
using System;
2+
using System.IO;
3+
using System.Text;
4+
using SabreTools.Compression.MSZIP;
5+
using SabreTools.IO.Extensions;
6+
using SabreTools.Models.MicrosoftCabinet;
7+
using static SabreTools.Models.MicrosoftCabinet.Constants;
28

39
namespace Test
410
{
@@ -8,5 +14,284 @@ public static void Main(string[] args)
814
{
915
// No implementation, used for experimentation
1016
}
17+
18+
private static void READMSZIPTEST()
19+
{
20+
using var fs = File.OpenRead("INFILE.cab");
21+
var cab = Deserialize(fs);
22+
if (cab == null || cab.Folders == null || cab.Files == null)
23+
return;
24+
25+
for (int f = 0; f < cab!.Folders.Length; f++)
26+
{
27+
var folder = cab.Folders[f];
28+
if (folder?.DataBlocks == null || folder.DataBlocks.Length == 0)
29+
continue;
30+
31+
var decomp = Decompressor.Create();
32+
33+
var ms = new MemoryStream();
34+
foreach (var db in folder.DataBlocks)
35+
{
36+
if (db?.CompressedData == null)
37+
continue;
38+
39+
decomp.CopyTo(db.CompressedData, ms);
40+
}
41+
42+
if (cab?.Files == null || cab.Files.Length == 0)
43+
continue;
44+
45+
foreach (var file in cab.Files)
46+
{
47+
if (file?.Name == null || file.FolderIndex != (FolderIndex)f)
48+
continue;
49+
50+
byte[] fileData = new byte[file.FileSize];
51+
Array.Copy(ms.ToArray(), file.FolderStartOffset, fileData, 0, file.FileSize);
52+
53+
using var of = File.OpenWrite(Path.Combine("OUTDIR", file.Name));
54+
of.Write(fileData);
55+
of.Flush();
56+
}
57+
}
58+
}
59+
60+
/// <summary>
61+
/// Parse a Stream into a cabinet
62+
/// </summary>
63+
/// <param name="data">Stream to parse</param>
64+
/// <returns>Filled cabinet on success, null on error</returns>
65+
private static Cabinet? Deserialize(Stream? data)
66+
{
67+
// If the data is invalid
68+
if (data == null || !data.CanRead)
69+
return null;
70+
71+
try
72+
{
73+
// Cache the current offset
74+
int initialOffset = (int)data.Position;
75+
76+
// Create a new cabinet to fill
77+
var cabinet = new Cabinet();
78+
79+
#region Cabinet Header
80+
81+
// Try to parse the cabinet header
82+
var cabinetHeader = ParseCabinetHeader(data);
83+
if (cabinetHeader == null)
84+
return null;
85+
86+
// Set the cabinet header
87+
cabinet.Header = cabinetHeader;
88+
89+
#endregion
90+
91+
#region Folders
92+
93+
// Set the folder array
94+
cabinet.Folders = new CFFOLDER[cabinetHeader.FolderCount];
95+
96+
// Try to parse each folder, if we have any
97+
for (int i = 0; i < cabinetHeader.FolderCount; i++)
98+
{
99+
var folder = ParseFolder(data, cabinetHeader);
100+
if (folder == null)
101+
return null;
102+
103+
// Set the folder
104+
cabinet.Folders[i] = folder;
105+
}
106+
107+
#endregion
108+
109+
#region Files
110+
111+
// Get the files offset
112+
int filesOffset = (int)cabinetHeader.FilesOffset + initialOffset;
113+
if (filesOffset > data.Length)
114+
return null;
115+
116+
// Seek to the offset
117+
data.Seek(filesOffset, SeekOrigin.Begin);
118+
119+
// Set the file array
120+
cabinet.Files = new CFFILE[cabinetHeader.FileCount];
121+
122+
// Try to parse each file, if we have any
123+
for (int i = 0; i < cabinetHeader.FileCount; i++)
124+
{
125+
var file = ParseFile(data);
126+
if (file == null)
127+
return null;
128+
129+
// Set the file
130+
cabinet.Files[i] = file;
131+
}
132+
133+
#endregion
134+
135+
return cabinet;
136+
}
137+
catch
138+
{
139+
// Ignore the actual error
140+
return null;
141+
}
142+
}
143+
144+
/// <summary>
145+
/// Parse a Stream into a cabinet header
146+
/// </summary>
147+
/// <param name="data">Stream to parse</param>
148+
/// <returns>Filled cabinet header on success, null on error</returns>
149+
private static CFHEADER? ParseCabinetHeader(Stream data)
150+
{
151+
var header = new CFHEADER();
152+
153+
byte[] signature = data.ReadBytes(4);
154+
header.Signature = Encoding.ASCII.GetString(signature);
155+
if (header.Signature != SignatureString)
156+
return null;
157+
158+
header.Reserved1 = data.ReadUInt32();
159+
header.CabinetSize = data.ReadUInt32();
160+
header.Reserved2 = data.ReadUInt32();
161+
header.FilesOffset = data.ReadUInt32();
162+
header.Reserved3 = data.ReadUInt32();
163+
header.VersionMinor = data.ReadByteValue();
164+
header.VersionMajor = data.ReadByteValue();
165+
header.FolderCount = data.ReadUInt16();
166+
header.FileCount = data.ReadUInt16();
167+
header.Flags = (HeaderFlags)data.ReadUInt16();
168+
header.SetID = data.ReadUInt16();
169+
header.CabinetIndex = data.ReadUInt16();
170+
171+
#if NET20 || NET35
172+
if ((header.Flags & HeaderFlags.RESERVE_PRESENT) != 0)
173+
#else
174+
if (header.Flags.HasFlag(HeaderFlags.RESERVE_PRESENT))
175+
#endif
176+
{
177+
header.HeaderReservedSize = data.ReadUInt16();
178+
if (header.HeaderReservedSize > 60_000)
179+
return null;
180+
181+
header.FolderReservedSize = data.ReadByteValue();
182+
header.DataReservedSize = data.ReadByteValue();
183+
184+
if (header.HeaderReservedSize > 0)
185+
header.ReservedData = data.ReadBytes(header.HeaderReservedSize);
186+
}
187+
188+
#if NET20 || NET35
189+
if ((header.Flags & HeaderFlags.PREV_CABINET) != 0)
190+
#else
191+
if (header.Flags.HasFlag(HeaderFlags.PREV_CABINET))
192+
#endif
193+
{
194+
header.CabinetPrev = data.ReadNullTerminatedAnsiString();
195+
header.DiskPrev = data.ReadNullTerminatedAnsiString();
196+
}
197+
198+
#if NET20 || NET35
199+
if ((header.Flags & HeaderFlags.NEXT_CABINET) != 0)
200+
#else
201+
if (header.Flags.HasFlag(HeaderFlags.NEXT_CABINET))
202+
#endif
203+
{
204+
header.CabinetNext = data.ReadNullTerminatedAnsiString();
205+
header.DiskNext = data.ReadNullTerminatedAnsiString();
206+
}
207+
208+
return header;
209+
}
210+
211+
/// <summary>
212+
/// Parse a Stream into a folder
213+
/// </summary>
214+
/// <param name="data">Stream to parse</param>
215+
/// <param name="header">Cabinet header to get flags and sizes from</param>
216+
/// <returns>Filled folder on success, null on error</returns>
217+
private static CFFOLDER ParseFolder(Stream data, CFHEADER header)
218+
{
219+
var folder = new CFFOLDER();
220+
221+
folder.CabStartOffset = data.ReadUInt32();
222+
folder.DataCount = data.ReadUInt16();
223+
folder.CompressionType = (CompressionType)data.ReadUInt16() & CompressionType.MASK_TYPE;
224+
225+
if (header.FolderReservedSize > 0)
226+
folder.ReservedData = data.ReadBytes(header.FolderReservedSize);
227+
228+
if (folder.CabStartOffset > 0)
229+
{
230+
long currentPosition = data.Position;
231+
data.Seek(folder.CabStartOffset, SeekOrigin.Begin);
232+
233+
folder.DataBlocks = new CFDATA[folder.DataCount];
234+
for (int i = 0; i < folder.DataCount; i++)
235+
{
236+
CFDATA dataBlock = ParseDataBlock(data, header.DataReservedSize);
237+
folder.DataBlocks[i] = dataBlock;
238+
}
239+
240+
data.Seek(currentPosition, SeekOrigin.Begin);
241+
}
242+
243+
return folder;
244+
}
245+
246+
/// <summary>
247+
/// Parse a Stream into a data block
248+
/// </summary>
249+
/// <param name="data">Stream to parse</param>
250+
/// <param name="dataReservedSize">Reserved byte size for data blocks</param>
251+
/// <returns>Filled folder on success, null on error</returns>
252+
private static CFDATA ParseDataBlock(Stream data, byte dataReservedSize)
253+
{
254+
var dataBlock = new CFDATA();
255+
256+
dataBlock.Checksum = data.ReadUInt32();
257+
dataBlock.CompressedSize = data.ReadUInt16();
258+
dataBlock.UncompressedSize = data.ReadUInt16();
259+
260+
if (dataReservedSize > 0)
261+
dataBlock.ReservedData = data.ReadBytes(dataReservedSize);
262+
263+
if (dataBlock.CompressedSize > 0)
264+
dataBlock.CompressedData = data.ReadBytes(dataBlock.CompressedSize);
265+
266+
return dataBlock;
267+
}
268+
269+
/// <summary>
270+
/// Parse a Stream into a file
271+
/// </summary>
272+
/// <param name="data">Stream to parse</param>
273+
/// <returns>Filled file on success, null on error</returns>
274+
private static CFFILE ParseFile(Stream data)
275+
{
276+
var file = new CFFILE();
277+
278+
file.FileSize = data.ReadUInt32();
279+
file.FolderStartOffset = data.ReadUInt32();
280+
file.FolderIndex = (FolderIndex)data.ReadUInt16();
281+
file.Date = data.ReadUInt16();
282+
file.Time = data.ReadUInt16();
283+
file.Attributes = (SabreTools.Models.MicrosoftCabinet.FileAttributes)data.ReadUInt16();
284+
285+
#if NET20 || NET35
286+
if ((file.Attributes & SabreTools.Models.MicrosoftCabinet.FileAttributes.NAME_IS_UTF) != 0)
287+
#else
288+
if (file.Attributes.HasFlag(SabreTools.Models.MicrosoftCabinet.FileAttributes.NAME_IS_UTF))
289+
#endif
290+
file.Name = data.ReadNullTerminatedUnicodeString();
291+
else
292+
file.Name = data.ReadNullTerminatedAnsiString();
293+
294+
return file;
295+
}
11296
}
12297
}

0 commit comments

Comments
 (0)