From 9e49703bc5236ed00da7941deeb3a69bb4698f2a Mon Sep 17 00:00:00 2001 From: Matt Nadareski Date: Mon, 23 May 2022 15:05:03 -0700 Subject: [PATCH] Clean up some CAB decompressor code --- .../External/libmspack/CAB/Compressor.cs | 4 +- .../External/libmspack/CAB/Decompressor.cs | 470 +++++++++--------- 2 files changed, 242 insertions(+), 232 deletions(-) diff --git a/BurnOutSharp/External/libmspack/CAB/Compressor.cs b/BurnOutSharp/External/libmspack/CAB/Compressor.cs index 5bf72ee1..b1e069e2 100644 --- a/BurnOutSharp/External/libmspack/CAB/Compressor.cs +++ b/BurnOutSharp/External/libmspack/CAB/Compressor.cs @@ -16,9 +16,7 @@ namespace LibMSPackSharp.CAB { - /// - /// TODO - /// + // TODO public class Compressor { public SystemImpl System { get; set; } diff --git a/BurnOutSharp/External/libmspack/CAB/Decompressor.cs b/BurnOutSharp/External/libmspack/CAB/Decompressor.cs index 78665750..65e7c14e 100644 --- a/BurnOutSharp/External/libmspack/CAB/Decompressor.cs +++ b/BurnOutSharp/External/libmspack/CAB/Decompressor.cs @@ -54,14 +54,14 @@ namespace LibMSPackSharp.CAB /// and a Cabinet structure will be returned, with a full list of /// folders and files. /// - /// In the case of an error occuring, NULL is returned and the error code + /// In the case of an error occuring, null is returned and the error code /// is available from last_error(). /// /// The filename pointer should be considered "in use" until close() is /// called on the cabinet. /// /// The filename of the cabinet file. This is passed directly to SystemImpl::open(). - /// A pointer to a Cabinet structure, or NULL on failure + /// A pointer to a Cabinet structure, or null on failure /// /// /// @@ -118,26 +118,12 @@ namespace LibMSPackSharp.CAB /// public void Close(Cabinet cabinet) { - FolderData dat, ndat; - Cabinet cab; - Folder fol, nfol; - InternalFile fi, nfi; - Error = Error.MSPACK_ERR_OK; - while (cabinet != null) { - // Free files - for (fi = cabinet.Files; fi != null; fi = nfi) - { - nfi = fi.Next; - } - // Free folders - for (fol = cabinet.Folders; fol != null; fol = nfol) + for (Folder fol = cabinet.Folders; fol != null; fol = fol.Next) { - nfol = fol.Next; - // Free folder decompression state if it has been decompressed if (State != null && (State.Folder == fol)) { @@ -147,19 +133,10 @@ namespace LibMSPackSharp.CAB FreeDecompressionState(); State = null; } - - // Free folder data segments - for (dat = fol.Data.Next; dat != null; dat = ndat) - { - ndat = dat.Next; - } } - // Free actual cabinet structure - cab = cabinet.Next; - // Repeat full procedure again with the cab.Next pointer (if set) - cabinet = cab; + cabinet = cabinet.Next; } } @@ -178,10 +155,10 @@ namespace LibMSPackSharp.CAB /// using the Cabinet::next field. /// /// In the case of an error occuring anywhere other than the simulated - /// open(), NULL is returned and the error code is available from + /// open(), null is returned and the error code is available from /// last_error(). /// - /// If no error occurs, but no cabinets can be found in the file, NULL is + /// If no error occurs, but no cabinets can be found in the file, null is /// returned and last_error() returns MSPACK_ERR_OK. /// /// The filename pointer should be considered in use until close() is @@ -190,45 +167,42 @@ namespace LibMSPackSharp.CAB /// close() should only be called on the result of search(), not on any /// subsequent cabinets in the Cabinet::next chain. /// - /// The filename of the file to search for cabinets. This is passed directly to SystemImpl::open(). - /// a pointer to a Cabinet structure, or NULL + /// The filename of the file to search for cabinets. This is passed directly to SystemImpl.Open(). + /// A pointer to a Cabinet structure, or null /// /// /// public Cabinet Search(string filename) { // Allocate a search buffer - byte[] search_buf = new byte[SearchBufferSize]; - if (search_buf == null) + byte[] searchBuffer = new byte[SearchBufferSize]; + + // Attempt to open the file + FileStream fh = System.Open(filename, OpenMode.MSPACK_SYS_OPEN_READ); + if (fh == null) { - Error = Error.MSPACK_ERR_NOMEMORY; + Error = Error.MSPACK_ERR_OPEN; return null; } - // Open file and get its full file length - FileStream fh; Cabinet cab = null; - if ((fh = System.Open(filename, OpenMode.MSPACK_SYS_OPEN_READ)) != null) - { - long firstlen = 0; - if ((Error = System.GetFileLength(fh, out long filelen)) == Error.MSPACK_ERR_OK) - Error = Find(search_buf, fh, filename, filelen, ref firstlen, out cab); + // Get its full file length + long firstlen = 0; + if ((Error = System.GetFileLength(fh, out long filelen)) != Error.MSPACK_ERR_OK) + return null; - // Truncated / extraneous data warning: - if (firstlen != 0 && (firstlen != filelen) && (cab == null || cab.BaseOffset == 0)) - { - if (firstlen < filelen) - System.Message(fh, $"WARNING; possible {filelen - firstlen} extra bytes at end of file."); - else - System.Message(fh, $"WARNING; file possibly truncated by {firstlen - filelen} bytes."); - } + // Attempt to to find the cabinet + Error = Find(searchBuffer, fh, filename, filelen, ref firstlen, out Cabinet cab); - System.Close(fh); - } - else + // Truncated / extraneous data warning: + if (firstlen != 0 && (firstlen != filelen) && (cab == null || cab.BaseOffset == 0)) { - Error = Error.MSPACK_ERR_OPEN; + if (firstlen < filelen) + System.Message(fh, $"WARNING; possible {filelen - firstlen} extra bytes at end of file."); + else + System.Message(fh, $"WARNING; file possibly truncated by {firstlen - filelen} bytes."); } + System.Close(fh); return cab; } @@ -313,8 +287,6 @@ namespace LibMSPackSharp.CAB if (file == null) return Error = Error.MSPACK_ERR_ARGS; - Folder fol = file.Folder; - // If offset is beyond 2GB, nothing can be extracted if (file.Header.FolderOffset > CAB_LENGTHMAX) return Error = Error.MSPACK_ERR_DATAFORMAT; @@ -331,7 +303,7 @@ namespace LibMSPackSharp.CAB } // Extraction impossible if no folder, or folder needs predecessor - if (fol == null || fol.MergePrev != null) + if (file.Folder == null || file.Folder.MergePrev != null) { System.Message(null, $"ERROR; file \"{file.Filename}\" cannot be extracted, cabinet set is incomplete"); return Error = Error.MSPACK_ERR_DECRUNCH; @@ -341,7 +313,7 @@ namespace LibMSPackSharp.CAB // In salvage mode, don't assume block sizes, just try decoding if (!Salvage) { - long maxlen = fol.Header.NumBlocks * CAB_BLOCKMAX; + long maxlen = file.Folder.Header.NumBlocks * CAB_BLOCKMAX; if ((file.Header.FolderOffset + filelen) > maxlen) { System.Message(null, $"ERROR; file \"{file.Filename}\" cannot be extracted, cabinet set is incomplete"); @@ -356,16 +328,16 @@ namespace LibMSPackSharp.CAB // Allocate generic decompression state State = new DecompressState() { - Folder = fol, - Data = fol.Data, + Folder = file.Folder, + Data = file.Folder.Data, Offset = 0, Block = 0, Outlen = 0, System = System, - InputCabinet = fol.Data.Cab, - InputFileHandle = System.Open(fol.Data.Cab.Filename, OpenMode.MSPACK_SYS_OPEN_READ), + InputCabinet = file.Folder.Data.Cab, + InputFileHandle = System.Open(file.Folder.Data.Cab.Filename, OpenMode.MSPACK_SYS_OPEN_READ), OutputFileHandle = null, // Required for skipping existing data InputPointer = 0, InputEnd = 0, @@ -378,11 +350,11 @@ namespace LibMSPackSharp.CAB return Error = Error.MSPACK_ERR_OPEN; // Seek to start of data blocks - if (!System.Seek(State.InputFileHandle, fol.Data.Offset, SeekMode.MSPACK_SYS_SEEK_START)) + if (!System.Seek(State.InputFileHandle, file.Folder.Data.Offset, SeekMode.MSPACK_SYS_SEEK_START)) return Error = Error.MSPACK_ERR_SEEK; // Set up decompressor - if (InitDecompressionState(fol.Header.CompType) != Error.MSPACK_ERR_OK) + if (InitDecompressionState(file.Folder.Header.CompType) != Error.MSPACK_ERR_OK) return Error; // ReadError lasts for the lifetime of a decompressor @@ -392,16 +364,14 @@ namespace LibMSPackSharp.CAB // If file has more than 0 bytes if (filelen != 0) { - long bytes; - Error error; - // Get to correct offset. - // - use null fh to say 'no writing' to cabd_sys_write() - // - if SysRead() has an error, it will set self.ReadError + // - Use null fh to say 'no writing' to cabd_sys_write() + // - If SysRead() has an error, it will set self.ReadError // and pass back MSPACK_ERR_READ - if ((bytes = file.Header.FolderOffset - State.Offset) != 0) + long bytes = file.Header.FolderOffset - State.Offset; + if (bytes != 0) { - error = State.Decompress(State.DecompressorState, bytes); + Error error = State.Decompress(State.DecompressorState, bytes); Error = (error == Error.MSPACK_ERR_READ) ? ReadError : error; } @@ -414,7 +384,7 @@ namespace LibMSPackSharp.CAB if (Error == Error.MSPACK_ERR_OK) { UpdateDecompressionState(); - error = State.Decompress(State.DecompressorState, filelen); + Error error = State.Decompress(State.DecompressorState, filelen); Error = (error == Error.MSPACK_ERR_READ) ? ReadError : error; } } @@ -814,26 +784,30 @@ namespace LibMSPackSharp.CAB /// private bool CanMergeFolders(Folder lfol, Folder rfol) { - InternalFile lfi, rfi, l, r; bool matching = true; // Check that both folders use the same compression method/settings if (lfol.Header.CompType != rfol.Header.CompType) { - Console.WriteLine("folder merge: compression type mismatch"); + Console.WriteLine("Folder merge: compression type mismatch"); return false; } // Check there are not too many data blocks after merging if ((lfol.Header.NumBlocks + rfol.Header.NumBlocks) > CAB_FOLDERMAX) { - Console.WriteLine("folder merge: too many data blocks in merged folders"); + Console.WriteLine("Folder merge: too many data blocks in merged folders"); return false; } - if ((lfi = lfol.MergeNext) == null || (rfi = rfol.MergePrev) == null) + // Assign the merge next and previous values + InternalFile lfi = lfol.MergeNext; + InternalFile rfi = rfol.MergePrev; + + // Check that we can merge the two cabinets + if (lfi == null || rfi == null) { - Console.WriteLine("folder merge: one cabinet has no files to merge"); + Console.WriteLine("Folder merge: one cabinet has no files to merge"); return false; } @@ -841,7 +815,7 @@ namespace LibMSPackSharp.CAB // only has files to merge), compare them to the files from rfol. They // should be identical in number and order. to verify this, check the // offset and length of each file. - for (l = lfi, r = rfi; l != null; l = l.Next, r = r.Next) + for (InternalFile l = lfi, r = rfi; l != null; l = l.Next, r = r.Next) { if (r == null || (l.Header.FolderOffset != r.Header.FolderOffset) || (l.Header.UncompressedSize != r.Header.UncompressedSize)) { @@ -857,12 +831,13 @@ namespace LibMSPackSharp.CAB // make a judgement call; if at least ONE file from lfol is in rfol, allow // the merge with a warning about missing files. matching = false; - for (l = lfi; l != null; l = l.Next) + for (InternalFile l = lfi; l != null; l = l.Next) { - for (r = rfi; r != null; r = r.Next) + InternalFile r = rfi; + for (; r != null; r = r.Next) { if (l.Header.FolderOffset == r.Header.FolderOffset && l.Header.UncompressedSize == r.Header.UncompressedSize) - break; + break; } if (r != null) @@ -1056,9 +1031,7 @@ namespace LibMSPackSharp.CAB /// private Error Merge(Cabinet lcab, Cabinet rcab) { - FolderData data, ndata; - Folder lfol, rfol; - InternalFile fi, rfi, lfi; + InternalFile rfi, lfi; // Basic args check if (lcab == null || rcab == null || (lcab == rcab)) @@ -1075,8 +1048,7 @@ namespace LibMSPackSharp.CAB } // Do not create circular cabinet chains - Cabinet cab; - for (cab = lcab.PreviousCabinet; cab != null; cab = cab.PreviousCabinet) + for (Cabinet cab = lcab.PreviousCabinet; cab != null; cab = cab.PreviousCabinet) { if (cab == rcab) { @@ -1084,7 +1056,8 @@ namespace LibMSPackSharp.CAB return Error = Error.MSPACK_ERR_ARGS; } } - for (cab = rcab.NextCabinet; cab != null; cab = cab.NextCabinet) + + for (Cabinet cab = rcab.NextCabinet; cab != null; cab = cab.NextCabinet) { if (cab == lcab) { @@ -1101,8 +1074,8 @@ namespace LibMSPackSharp.CAB System.Message(null, "WARNING; merged cabinets with odd order."); // Merging the last folder in lcab with the first folder in rcab - lfol = lcab.Folders; - rfol = rcab.Folders; + Folder lfol = lcab.Folders; + Folder rfol = rcab.Folders; while (lfol.Next != null) { lfol = lfol.Next; @@ -1121,7 +1094,7 @@ namespace LibMSPackSharp.CAB lfol.Next = rfol; // Attach files - fi = lcab.Files; + InternalFile fi = lcab.Files; while (fi.Next != null) { fi = fi.Next; @@ -1136,14 +1109,14 @@ namespace LibMSPackSharp.CAB return Error = Error.MSPACK_ERR_DATAFORMAT; // Allocate a new folder data structure - data = new FolderData(); + FolderData data = new FolderData(); // Attach cabs lcab.NextCabinet = rcab; rcab.PreviousCabinet = lcab; // Append rfol's data to lfol - ndata = lfol.Data; + FolderData ndata = lfol.Data; while (ndata.Next != null) { ndata = ndata.Next; @@ -1170,7 +1143,7 @@ namespace LibMSPackSharp.CAB lfol.Next = rfol.Next; // Attach rfol's files - fi = lcab.Files; + InternalFile fi = lcab.Files; while (fi.Next != null) { fi = fi.Next; @@ -1201,13 +1174,13 @@ namespace LibMSPackSharp.CAB // All done! fix files and folders pointers in alsl cabs so they all // point to the same list - for (cab = lcab.PreviousCabinet; cab != null; cab = cab.PreviousCabinet) + for (Cabinet cab = lcab.PreviousCabinet; cab != null; cab = cab.PreviousCabinet) { cab.Files = lcab.Files; cab.Folders = lcab.Folders; } - for (cab = lcab.NextCabinet; cab != null; cab = cab.NextCabinet) + for (Cabinet cab = lcab.NextCabinet; cab != null; cab = cab.NextCabinet) { cab.Files = lcab.Files; cab.Folders = lcab.Folders; @@ -1224,9 +1197,8 @@ namespace LibMSPackSharp.CAB private Error ReadHeaders(FileStream fh, Cabinet cab, long offset, bool salvage, bool quiet) { Error err = Error.MSPACK_ERR_OK; - Folder fol, linkfol = null; + Folder linkfol = null; InternalFile linkfile = null; - byte[] buf = new byte[64]; // Initialise pointers if (cab == null) @@ -1241,18 +1213,21 @@ namespace LibMSPackSharp.CAB cab.BaseOffset = offset; + #region Cabinet Header + // Seek to CFHEADER if (!System.Seek(fh, offset, SeekMode.MSPACK_SYS_SEEK_START)) - return Error.MSPACK_ERR_SEEK; + return Error = Error.MSPACK_ERR_SEEK; // Read in the CFHEADER + byte[] buf = new byte[_CabinetHeader.Size]; if (System.Read(fh, buf, 0, _CabinetHeader.Size) != _CabinetHeader.Size) - return Error.MSPACK_ERR_READ; + return Error = Error.MSPACK_ERR_READ; // Create a new header based on that err = _CabinetHeader.Create(buf, out _CabinetHeader cabinetHeader); if (err != Error.MSPACK_ERR_OK) - return err; + return Error = err; // Assign the header cab.Header = cabinetHeader; @@ -1260,8 +1235,9 @@ namespace LibMSPackSharp.CAB // Check for the extended header if (cab.Header.Flags.HasFlag(HeaderFlags.MSCAB_HDR_RESV)) { + buf = new byte[_CabinetHeader.ExtendedSize]; if (System.Read(fh, buf, 0, _CabinetHeader.ExtendedSize) != _CabinetHeader.ExtendedSize) - return Error.MSPACK_ERR_READ; + return Error = Error.MSPACK_ERR_READ; // Populate the extended header cabinetHeader.PopulateExtendedHeader(buf); @@ -1270,7 +1246,7 @@ namespace LibMSPackSharp.CAB if (cab.Header.HeaderReserved != 0) { if (!System.Seek(fh, cab.Header.HeaderReserved, SeekMode.MSPACK_SYS_SEEK_CUR)) - return Error.MSPACK_ERR_SEEK; + return Error = Error.MSPACK_ERR_SEEK; } } @@ -1279,11 +1255,11 @@ namespace LibMSPackSharp.CAB { cab.PreviousName = ReadString(fh, false, ref err); if (err != Error.MSPACK_ERR_OK) - return err; + return Error = err; cab.PreviousInfo = ReadString(fh, true, ref err); if (err != Error.MSPACK_ERR_OK) - return err; + return Error = err; } // Read name and info of next cabinet in set, if present @@ -1291,159 +1267,195 @@ namespace LibMSPackSharp.CAB { cab.NextName = ReadString(fh, false, ref err); if (err != Error.MSPACK_ERR_OK) - return err; + return Error = err; cab.NextInfo = ReadString(fh, true, ref err); if (err != Error.MSPACK_ERR_OK) - return err; + return Error = err; } + #endregion + + #region Folder and File Pointers + // Read folders for (int i = 0; i < cab.Header.NumFolders; i++) { - // Read in the FOHEADER - if (System.Read(fh, buf, 0, _FolderHeader.Size) != _FolderHeader.Size) - return Error.MSPACK_ERR_READ; - - if (cab.Header.FolderReserved != 0) - { - if (!System.Seek(fh, cab.Header.FolderReserved, SeekMode.MSPACK_SYS_SEEK_CUR)) - return Error.MSPACK_ERR_SEEK; - } - - // Create an empty folder - fol = new Folder() - { - Next = null, - MergePrev = null, - MergeNext = null, - }; - - // Create a new header based on that - err = _FolderHeader.Create(buf, out _FolderHeader folderHeader); + err = ReadSingleFolder(fh, cab, offset, ref linkfol); if (err != Error.MSPACK_ERR_OK) - return err; - - // Assign the header - fol.Header = folderHeader; - - // Set the folder data fields - fol.Data = new FolderData(); - fol.Data.Next = null; - fol.Data.Cab = cab; - fol.Data.Offset = offset + fol.Header.DataOffset; - - // Link folder into list of folders - if (linkfol == null) - cab.Folders = fol; - else - linkfol.Next = fol; - - linkfol = fol; + return Error = err; } // Read files for (int i = 0; i < cab.Header.NumFiles; i++) { - // Read in the FIHEADER - if (System.Read(fh, buf, 0, _FileHeader.Size) != _FileHeader.Size) - return Error.MSPACK_ERR_READ; - - InternalFile file = new InternalFile() { Next = null }; - - // Create a new header based on that - err = _FileHeader.Create(buf, out _FileHeader fileHeader); + err = ReadSingleFile(fh, cab, salvage, ref linkfile); if (err != Error.MSPACK_ERR_OK) - return err; - - // Assign the header - file.Header = fileHeader; - - // Set folder pointer - if (file.Header.FolderIndex < FileFlags.CONTINUED_FROM_PREV) - { - // Normal folder index; count up to the correct folder - if ((int)file.Header.FolderIndex < cab.Header.NumFolders) - { - Folder ifol = cab.Folders; - while (file.Header.FolderIndex-- != 0) - { - if (ifol != null) - ifol = ifol.Next; - } - - file.Folder = ifol; - } - else - { - Console.WriteLine("Invalid folder index"); - file.Folder = null; - } - } - else - { - // Either CONTINUED_TO_NEXT, CONTINUED_FROM_PREV or CONTINUED_PREV_AND_NEXT - if (file.Header.FolderIndex == FileFlags.CONTINUED_TO_NEXT || file.Header.FolderIndex == FileFlags.CONTINUED_PREV_AND_NEXT) - { - // Get last folder - Folder ifol = cab.Folders; - while (ifol.Next != null) - { - ifol = ifol.Next; - } - - file.Folder = ifol; - - // Set "merge next" pointer - fol = ifol; - if (fol.MergeNext == null) - fol.MergeNext = file; - } - - if (file.Header.FolderIndex == FileFlags.CONTINUED_FROM_PREV || file.Header.FolderIndex == FileFlags.CONTINUED_PREV_AND_NEXT) - { - // Get first folder - file.Folder = cab.Folders; - - // Set "merge prev" pointer - fol = file.Folder; - if (fol.MergePrev == null) - fol.MergePrev = file; - } - } - - // Get filename - file.Filename = ReadString(fh, false, ref err); - - // If folder index or filename are bad, either skip it or fail - if (err != Error.MSPACK_ERR_OK || file.Folder == null) - { - if (salvage) - continue; - - return err != Error.MSPACK_ERR_OK ? err : Error.MSPACK_ERR_DATAFORMAT; - } - - // Link file entry into file list - if (linkfile == null) - cab.Files = file; - else - linkfile.Next = file; - - linkfile = file; + return Error = err; } if (cab.Files == null) { // We never actually added any files to the file list. Something went wrong. - // The file header may have been invalid */ + // The file header may have been invalid Console.WriteLine($"No files found, even though header claimed to have {cab.Header.NumFiles} files"); return Error.MSPACK_ERR_DATAFORMAT; } + #endregion + return Error.MSPACK_ERR_OK; } + /// + /// Read and process a single file + /// + private Error ReadSingleFile(FileStream fh, Cabinet cab, bool salvage, ref InternalFile linkfile) + { + // Read in the FIHEADER + byte[] buf = new byte[64]; + if (System.Read(fh, buf, 0, _FileHeader.Size) != _FileHeader.Size) + return Error.MSPACK_ERR_READ; + + InternalFile file = new InternalFile() { Next = null }; + + // Create a new header based on that + Error err = _FileHeader.Create(buf, out _FileHeader fileHeader); + if (err != Error.MSPACK_ERR_OK) + return err; + + // Assign the header + file.Header = fileHeader; + + // Set folder pointer + if (file.Header.FolderIndex < FileFlags.CONTINUED_FROM_PREV) + { + // Normal folder index; count up to the correct folder + if ((int)file.Header.FolderIndex < cab.Header.NumFolders) + { + Folder ifol = cab.Folders; + while (file.Header.FolderIndex-- != 0) + { + if (ifol != null) + ifol = ifol.Next; + } + + file.Folder = ifol; + } + else + { + Console.WriteLine("Invalid folder index"); + file.Folder = null; + } + } + else + { + // Either CONTINUED_TO_NEXT, CONTINUED_FROM_PREV or CONTINUED_PREV_AND_NEXT + if (file.Header.FolderIndex == FileFlags.CONTINUED_TO_NEXT || file.Header.FolderIndex == FileFlags.CONTINUED_PREV_AND_NEXT) + { + // Get last folder + Folder ifol = cab.Folders; + while (ifol.Next != null) + { + ifol = ifol.Next; + } + + file.Folder = ifol; + + // Set "merge next" pointer + Folder fol = ifol; + if (fol.MergeNext == null) + fol.MergeNext = file; + } + + if (file.Header.FolderIndex == FileFlags.CONTINUED_FROM_PREV || file.Header.FolderIndex == FileFlags.CONTINUED_PREV_AND_NEXT) + { + // Get first folder + file.Folder = cab.Folders; + + // Set "merge prev" pointer + Folder fol = file.Folder; + if (fol.MergePrev == null) + fol.MergePrev = file; + } + } + + // Get filename + file.Filename = ReadString(fh, false, ref err); + + // If folder index or filename are bad, either skip it or fail + if (err != Error.MSPACK_ERR_OK || file.Folder == null) + { + if (salvage) + return Error.MSPACK_ERR_OK; + + return err != Error.MSPACK_ERR_OK ? err : Error.MSPACK_ERR_DATAFORMAT; + } + + // Link file entry into file list + if (linkfile == null) + cab.Files = file; + else + linkfile.Next = file; + + linkfile = file; + return Error.MSPACK_ERR_OK; + } + + /// + /// Read and process a single folder + /// + private Error ReadSingleFolder(FileStream fh, Cabinet cab, long offset, ref Folder linkfol) + { + // Read in the FOHEADER + byte[] buf = new byte[64]; + if (System.Read(fh, buf, 0, _FolderHeader.Size) != _FolderHeader.Size) + return Error.MSPACK_ERR_READ; + + if (cab.Header.FolderReserved != 0) + { + if (!System.Seek(fh, cab.Header.FolderReserved, SeekMode.MSPACK_SYS_SEEK_CUR)) + return Error.MSPACK_ERR_SEEK; + } + + // Create an empty folder + Folder fol = new Folder() + { + Next = null, + MergePrev = null, + MergeNext = null, + }; + + // Create a new header based on that + Error err = _FolderHeader.Create(buf, out _FolderHeader folderHeader); + if (err != Error.MSPACK_ERR_OK) + return err; + + // Assign the header + fol.Header = folderHeader; + + // Set the folder data fields + fol.Data = new FolderData() + { + Next = null, + Cab = cab, + Offset = offset + fol.Header.DataOffset, + }; + + // Link folder into list of folders + if (linkfol == null) + cab.Folders = fol; + else + linkfol.Next = fol; + + linkfol = fol; + + return Error.MSPACK_ERR_OK; + } + + /// + /// Read a possibly empty string from the input + /// private string ReadString(FileStream fh, bool permitEmpty, ref Error error) { long position = System.Tell(fh);