Skip to content

Commit 7b4711f

Browse files
committed
Implement OpenSet for MS-CAB
1 parent 8440668 commit 7b4711f

File tree

2 files changed

+99
-1
lines changed

2 files changed

+99
-1
lines changed

SabreTools.Serialization/Wrappers/InstallShieldCabinet.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ public InstallShieldCabinet(Cabinet? model, Stream? data)
172172
/// Open a cabinet set for reading, if possible
173173
/// </summary>
174174
/// <param name="pattern">Filename pattern for matching cabinet files</param>
175-
/// <returns></returns>
175+
/// <returns>Wrapper representing the set, null on error</returns>
176176
public static InstallShieldCabinet? OpenSet(string? pattern)
177177
{
178178
// An invalid pattern means no cabinet files

SabreTools.Serialization/Wrappers/MicrosoftCabinet.cs

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.IO;
3+
using SabreTools.Models.ArchiveDotOrg;
34

45
namespace SabreTools.Serialization.Wrappers
56
{
@@ -17,9 +18,24 @@ public partial class MicrosoftCabinet : WrapperBase<Models.MicrosoftCabinet.Cabi
1718
/// <inheritdoc cref="Models.MicrosoftCabinet.Cabinet.Files"/>
1819
public Models.MicrosoftCabinet.CFFILE[]? Files => Model.Files;
1920

21+
/// <inheritdoc cref="Models.MicrosoftCabinet.CFHEADER.FileCount"/>
22+
public int FileCount => Model.Header?.FileCount ?? 0;
23+
2024
/// <inheritdoc cref="Models.MicrosoftCabinet.Cabinet.Folders"/>
2125
public Models.MicrosoftCabinet.CFFOLDER[]? Folders => Model.Folders;
2226

27+
/// <inheritdoc cref="Models.MicrosoftCabinet.CFHEADER.FolderCount"/>
28+
public int FolderCount => Model.Header?.FolderCount ?? 0;
29+
30+
/// <inheritdoc cref="Models.MicrosoftCabinet.Cabinet.Header"/>
31+
public Models.MicrosoftCabinet.CFHEADER? Header => Model.Header;
32+
33+
/// <summary>
34+
/// Reference to the next cabinet header
35+
/// </summary>
36+
/// <remarks>Only used in multi-file</remarks>
37+
public MicrosoftCabinet? Next { get; set; }
38+
2339
#endregion
2440

2541
#region Constructors
@@ -86,6 +102,88 @@ public MicrosoftCabinet(Models.MicrosoftCabinet.Cabinet? model, Stream? data)
86102

87103
#endregion
88104

105+
#region Cabinet Set
106+
107+
/// <summary>
108+
/// Open a cabinet set for reading, if possible
109+
/// </summary>
110+
/// <param name="filename">Filename for one cabinet in the set</param>
111+
/// <returns>Wrapper representing the set, null on error</returns>
112+
public static MicrosoftCabinet? OpenSet(string? filename)
113+
{
114+
// If the file is invalid
115+
if (string.IsNullOrEmpty(filename))
116+
return null;
117+
else if (!File.Exists(filename!))
118+
return null;
119+
120+
// Get the full file path and directory
121+
filename = Path.GetFullPath(filename);
122+
string? directory = Path.GetDirectoryName(filename);
123+
124+
// Read in the current file and try to parse
125+
var stream = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
126+
var current = Create(stream);
127+
if (current?.Header == null)
128+
return null;
129+
130+
// Seek to the first part of the cabinet set
131+
while (current.Header.CabinetPrev != null)
132+
{
133+
// Get the path defined in the current header
134+
string prevPath = current.Header.CabinetPrev;
135+
if (directory != null)
136+
prevPath = Path.Combine(directory, prevPath);
137+
138+
// If the file doesn't exist
139+
if (!File.Exists(prevPath))
140+
break;
141+
142+
// Close the previous cabinet part to avoid locking issues
143+
stream.Close();
144+
145+
// Open the previous cabinet and try to parse
146+
stream = File.Open(prevPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
147+
var prev = Create(stream);
148+
if (prev?.Header == null)
149+
break;
150+
151+
// Assign previous as new current
152+
current = prev;
153+
}
154+
155+
// Cache the current start of the cabinet set
156+
var start = current;
157+
158+
// Read in the cabinet parts sequentially
159+
while (current.Header.CabinetNext != null)
160+
{
161+
// Get the path defined in the current header
162+
string nextPath = current.Header.CabinetNext;
163+
if (directory != null)
164+
nextPath = Path.Combine(directory, nextPath);
165+
166+
// If the file doesn't exist
167+
if (!File.Exists(nextPath))
168+
break;
169+
170+
// Open the next cabinet and try to parse
171+
stream = File.Open(nextPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
172+
var next = Create(stream);
173+
if (next?.Header == null)
174+
break;
175+
176+
// Add next to the current and reset current
177+
current.Next = next;
178+
current = next;
179+
}
180+
181+
// Return the start of the set
182+
return start;
183+
}
184+
185+
#endregion
186+
89187
#region Checksumming
90188

91189
/// <summary>

0 commit comments

Comments
 (0)