Skip to content

Commit b7fceee

Browse files
committed
Port more MS-CAB helpers from BOS
1 parent ecf6c95 commit b7fceee

File tree

1 file changed

+93
-11
lines changed

1 file changed

+93
-11
lines changed

SabreTools.Serialization/Wrappers/MicrosoftCabinet.cs

Lines changed: 93 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
using System;
22
using System.IO;
3+
using SabreTools.Models.MicrosoftCabinet;
34

45
namespace SabreTools.Serialization.Wrappers
56
{
6-
public partial class MicrosoftCabinet : WrapperBase<Models.MicrosoftCabinet.Cabinet>
7+
public partial class MicrosoftCabinet : WrapperBase<Cabinet>
78
{
89
#region Descriptive Properties
910

@@ -14,20 +15,20 @@ public partial class MicrosoftCabinet : WrapperBase<Models.MicrosoftCabinet.Cabi
1415

1516
#region Extension Properties
1617

17-
/// <inheritdoc cref="Models.MicrosoftCabinet.Cabinet.Files"/>
18-
public Models.MicrosoftCabinet.CFFILE[]? Files => Model.Files;
18+
/// <inheritdoc cref="Cabinet.Files"/>
19+
public CFFILE[]? Files => Model.Files;
1920

20-
/// <inheritdoc cref="Models.MicrosoftCabinet.CFHEADER.FileCount"/>
21+
/// <inheritdoc cref="CFHEADER.FileCount"/>
2122
public int FileCount => Model.Header?.FileCount ?? 0;
2223

23-
/// <inheritdoc cref="Models.MicrosoftCabinet.Cabinet.Folders"/>
24-
public Models.MicrosoftCabinet.CFFOLDER[]? Folders => Model.Folders;
24+
/// <inheritdoc cref="Cabinet.Folders"/>
25+
public CFFOLDER[]? Folders => Model.Folders;
2526

26-
/// <inheritdoc cref="Models.MicrosoftCabinet.CFHEADER.FolderCount"/>
27+
/// <inheritdoc cref="CFHEADER.FolderCount"/>
2728
public int FolderCount => Model.Header?.FolderCount ?? 0;
2829

29-
/// <inheritdoc cref="Models.MicrosoftCabinet.Cabinet.Header"/>
30-
public Models.MicrosoftCabinet.CFHEADER? Header => Model.Header;
30+
/// <inheritdoc cref="Cabinet.Header"/>
31+
public CFHEADER? Header => Model.Header;
3132

3233
/// <summary>
3334
/// Reference to the next cabinet header
@@ -46,14 +47,14 @@ public partial class MicrosoftCabinet : WrapperBase<Models.MicrosoftCabinet.Cabi
4647
#region Constructors
4748

4849
/// <inheritdoc/>
49-
public MicrosoftCabinet(Models.MicrosoftCabinet.Cabinet? model, byte[]? data, int offset)
50+
public MicrosoftCabinet(Cabinet? model, byte[]? data, int offset)
5051
: base(model, data, offset)
5152
{
5253
// All logic is handled by the base class
5354
}
5455

5556
/// <inheritdoc/>
56-
public MicrosoftCabinet(Models.MicrosoftCabinet.Cabinet? model, Stream? data)
57+
public MicrosoftCabinet(Cabinet? model, Stream? data)
5758
: base(model, data)
5859
{
5960
// All logic is handled by the base class
@@ -298,6 +299,87 @@ private static uint S(byte[] a, int b, int x)
298299
}
299300
}
300301

302+
/// <summary>
303+
/// Get the corrected folder index
304+
/// </summary>
305+
public int GetFolderIndex(CFFILE file)
306+
{
307+
return file.FolderIndex switch
308+
{
309+
FolderIndex.CONTINUED_FROM_PREV => 0,
310+
FolderIndex.CONTINUED_TO_NEXT => (Header?.FolderCount ?? 1) - 1,
311+
FolderIndex.CONTINUED_PREV_AND_NEXT => 0,
312+
_ => (int)file.FolderIndex,
313+
};
314+
}
315+
316+
#endregion
317+
318+
#region Folders
319+
320+
/// <summary>
321+
/// Get the set of data blocks for a folder
322+
/// </summary>
323+
public CFDATA[]? GetDataBlocks(string file, CFFOLDER? folder, int folderIndex, bool skipPrev = false, bool skipNext = false)
324+
{
325+
// Skip invalid folders
326+
if (folder?.DataBlocks == null || folder.DataBlocks.Length == 0)
327+
return null;
328+
329+
// Get all files for the folder
330+
var files = GetFiles(folderIndex);
331+
if (files.Length == 0)
332+
return folder.DataBlocks;
333+
334+
// Check if the folder spans backward
335+
CFDATA[] prevBlocks = [];
336+
if (!skipPrev && Array.Exists(files, f => f.FolderIndex == FolderIndex.CONTINUED_FROM_PREV || f.FolderIndex == FolderIndex.CONTINUED_PREV_AND_NEXT))
337+
{
338+
var prev = OpenPrevious(file);
339+
if (prev?.Model?.Header != null && prev.Model.Folders != null)
340+
{
341+
int prevFolderIndex = prev.Model.Header.FolderCount;
342+
var prevFolder = prev.Model.Folders[prevFolderIndex - 1];
343+
prevBlocks = prev.GetDataBlocks(file, prevFolder, prevFolderIndex, skipNext: true) ?? [];
344+
}
345+
}
346+
347+
// Check if the folder spans forward
348+
CFDATA[] nextBlocks = [];
349+
if (!skipNext && Array.Exists(files, f => f.FolderIndex == FolderIndex.CONTINUED_TO_NEXT || f.FolderIndex == FolderIndex.CONTINUED_PREV_AND_NEXT))
350+
{
351+
var next = OpenNext(file);
352+
if (next?.Model?.Header != null && next.Model.Folders != null)
353+
{
354+
var nextFolder = next.Model.Folders[0];
355+
nextBlocks = next.GetDataBlocks(file, nextFolder, 0, skipPrev: true) ?? [];
356+
}
357+
}
358+
359+
// Return all found blocks in order
360+
return [.. prevBlocks, .. folder.DataBlocks, .. nextBlocks];
361+
}
362+
363+
/// <summary>
364+
/// Get all files for the current folder index
365+
/// </summary>
366+
public CFFILE[] GetFiles(int folderIndex)
367+
{
368+
// Ignore invalid archives
369+
if (Files == null)
370+
return [];
371+
372+
// Get all files with a name and matching index
373+
return Array.FindAll(Files, f =>
374+
{
375+
if (string.IsNullOrEmpty(f.Name))
376+
return false;
377+
378+
int fileFolder = GetFolderIndex(f);
379+
return fileFolder == folderIndex;
380+
});
381+
}
382+
301383
#endregion
302384
}
303385
}

0 commit comments

Comments
 (0)