Rewrote usetup's file copy and cabinet extraction code to use memory mapped files
This increased performance and the code is cleaner
Still needs a bit more cleaning up, but so far, looks good, needs some testing
Modified: trunk/reactos/subsys/system/usetup/cabinet.c
Modified: trunk/reactos/subsys/system/usetup/cabinet.h
Modified: trunk/reactos/subsys/system/usetup/filesup.c

Modified: trunk/reactos/subsys/system/usetup/cabinet.c
--- trunk/reactos/subsys/system/usetup/cabinet.c	2005-05-18 22:05:11 UTC (rev 15402)
+++ trunk/reactos/subsys/system/usetup/cabinet.c	2005-05-19 00:59:40 UTC (rev 15403)
@@ -46,30 +46,21 @@
 static WCHAR DiskNext[256];             // Label of cabinet in file CabinetNext
 static ULONG FolderUncompSize = 0;      // Uncompressed size of folder
 static ULONG BytesLeftInBlock = 0;      // Number of bytes left in current block
-static BOOL ReuseBlock = FALSE;
 static WCHAR DestPath[MAX_PATH];
 static HANDLE FileHandle;
+static HANDLE FileSectionHandle;
+static PUCHAR FileBuffer;
+static ULONG DestFileSize;
+static ULONG FileSize;
 static BOOL FileOpen = FALSE;
-static CFHEADER CABHeader;
+static PCFHEADER PCABHeader;
+static PCFFOLDER CabinetFolders;
 static ULONG CabinetReserved = 0;
 static ULONG FolderReserved = 0;
 static ULONG DataReserved = 0;
-static PCFFOLDER_NODE FolderListHead = NULL;
-static PCFFOLDER_NODE FolderListTail = NULL;
-static PCFFOLDER_NODE CurrentFolderNode = NULL;
-static PCFDATA_NODE CurrentDataNode = NULL;
-static PCFFILE_NODE FileListHead = NULL;
-static PCFFILE_NODE FileListTail = NULL;
 static ULONG CodecId;
 static PCABINET_CODEC_UNCOMPRESS CodecUncompress = NULL;
 static BOOL CodecSelected = FALSE;
-static PVOID InputBuffer = NULL;
-static PVOID CurrentIBuffer = NULL;       // Current offset in input buffer
-static ULONG CurrentIBufferSize = 0;      // Bytes left in input buffer
-static PVOID OutputBuffer = NULL;
-static PVOID CurrentOBuffer = NULL;       // Current offset in output buffer
-static ULONG CurrentOBufferSize = 0;      // Bytes left in output buffer
-static BOOL RestartSearch = FALSE;
 static ULONG LastFileOffset = 0;          // Uncompressed offset of last extracted file
 static PCABINET_OVERWRITE OverwriteHandler = NULL;
 static PCABINET_EXTRACT ExtractHandler = NULL;
@@ -94,20 +85,23 @@
 
 ULONG
 RawCodecUncompress(PVOID OutputBuffer,
-  PVOID InputBuffer,
-  ULONG InputLength,
-  PULONG OutputLength)
+				   PVOID InputBuffer,
+				   PLONG InputLength,
+				   PLONG OutputLength)
 /*
  * FUNCTION: Uncompresses data in a buffer
  * ARGUMENTS:
  *     OutputBuffer = Pointer to buffer to place uncompressed data
  *     InputBuffer  = Pointer to buffer with data to be uncompressed
- *     InputLength  = Length of input buffer
- *     OutputLength = Address of buffer to place size of uncompressed data
+ *     InputLength  = Length of input buffer before, and amount consumed after
+ *                    Negative to indicate that this is not the start of a new block
+ *     OutputLength = Length of output buffer before, amount filled after
+ *                    Negative to indicate that this is not the end of the block
  */
 {
-  memcpy(OutputBuffer, InputBuffer, InputLength);
-  *OutputLength = InputLength;
+  LONG In = abs(*InputLength), Out = abs(*OutputLength);
+  memcpy(OutputBuffer, InputBuffer, In < Out ? In : Out);
+  *InputLength = *OutputLength = In < Out ? In : Out;
   return CS_SUCCESS;
 }
 
@@ -116,70 +110,80 @@
 
 ULONG
 MSZipCodecUncompress(PVOID OutputBuffer,
-  PVOID InputBuffer,
-  ULONG InputLength,
-  PULONG OutputLength)
+					 PVOID InputBuffer,
+					 PLONG InputLength,
+					 PLONG OutputLength)
 /*
  * FUNCTION: Uncompresses data in a buffer
  * ARGUMENTS:
  *     OutputBuffer = Pointer to buffer to place uncompressed data
  *     InputBuffer  = Pointer to buffer with data to be uncompressed
- *     InputLength  = Length of input buffer
- *     OutputLength = Address of buffer to place size of uncompressed data
+ *     InputLength  = Length of input buffer before, and amount consumed after
+ *                    Negative to indicate that this is not the start of a new block
+ *     OutputLength = Length of output buffer before, amount filled after
+ *                    Negative to indicate that this is not the end of the block
  */
 {
   USHORT Magic;
   INT Status;
 
-  DPRINT("InputLength (%d).\n", InputLength);
+  DPRINT("MSZipCodecUncompress( OutputBuffer = %x, InputBuffer = %x, InputLength = %d, OutputLength = %d.\n", OutputBuffer, InputBuffer, *InputLength, *OutputLength);
+  if( *InputLength > 0 )
+	{
+	  Magic = *((PUSHORT)InputBuffer);
 
-  Magic = *((PUSHORT)InputBuffer);
+	  if (Magic != MSZIP_MAGIC)
+		{
+		  DPRINT("Bad MSZIP block header magic (0x%X)\n", Magic);
+		  return CS_BADSTREAM;
+		}
+	
+	  ZStream.next_in   = (PUCHAR)((ULONG)InputBuffer + 2);
+	  ZStream.avail_in  = *InputLength - 2;
+	  ZStream.next_out  = (PUCHAR)OutputBuffer;
+	  ZStream.avail_out = abs(*OutputLength);
 
-  if (Magic != MSZIP_MAGIC)
-    {
-      DPRINT("Bad MSZIP block header magic (0x%X)\n", Magic);
-      return CS_BADSTREAM;
-    }
+	  /* WindowBits is passed < 0 to tell that there is no zlib header.
+	   * Note that in this case inflate *requires* an extra "dummy" byte
+	   * after the compressed stream in order to complete decompression and
+	   * return Z_STREAM_END.
+	   */
+	  Status = inflateInit2(&ZStream, -MAX_WBITS);
+	  if (Status != Z_OK)
+		{
+		  DPRINT("inflateInit2() returned (%d).\n", Status);
+		  return CS_BADSTREAM;
+		}
+	  ZStream.total_in = 2;
+	}
+  else {
+	ZStream.avail_in = -*InputLength;
+	ZStream.next_in = (PUCHAR)InputBuffer;
+	ZStream.next_out = (PUCHAR)OutputBuffer;
+	ZStream.avail_out = abs(*OutputLength);
+	ZStream.total_in = 0;
+  }
+  ZStream.total_out = 0;
+  Status = inflate(&ZStream, Z_SYNC_FLUSH );
+  if (Status != Z_OK && Status != Z_STREAM_END)
+	{
+	  DPRINT("inflate() returned (%d) (%s).\n", Status, ZStream.msg);
+	  if (Status == Z_MEM_ERROR)
+		return CS_NOMEMORY;
+	  return CS_BADSTREAM;
+	}
 
-	ZStream.next_in   = (PUCHAR)((ULONG)InputBuffer + 2);
-	ZStream.avail_in  = InputLength - 2;
-	ZStream.next_out  = (PUCHAR)OutputBuffer;
-  ZStream.avail_out = CAB_BLOCKSIZE + 12;
-
-  /* WindowBits is passed < 0 to tell that there is no zlib header.
-   * Note that in this case inflate *requires* an extra "dummy" byte
-   * after the compressed stream in order to complete decompression and
-   * return Z_STREAM_END.
-   */
-  Status = inflateInit2(&ZStream, -MAX_WBITS);
-  if (Status != Z_OK)
-    {
-      DPRINT("inflateInit2() returned (%d).\n", Status);
-      return CS_BADSTREAM;
-    }
-
-  while ((ZStream.total_out < CAB_BLOCKSIZE + 12) &&
-    (ZStream.total_in < InputLength - 2))
-    {
-      Status = inflate(&ZStream, Z_NO_FLUSH);
-      if (Status == Z_STREAM_END) break;
-      if (Status != Z_OK)
-        {
-          DPRINT("inflate() returned (%d) (%s).\n", Status, ZStream.msg);
-          if (Status == Z_MEM_ERROR)
-              return CS_NOMEMORY;
-          return CS_BADSTREAM;
-        }
-    }
-
+  if( *OutputLength > 0 )
+	{
+	  Status = inflateEnd(&ZStream);
+	  if (Status != Z_OK)
+		{
+		  DPRINT("inflateEnd() returned (%d).\n", Status);
+		  return CS_BADSTREAM;
+		}
+	}
   *OutputLength = ZStream.total_out;
-
-  Status = inflateEnd(&ZStream);
-  if (Status != Z_OK)
-    {
-      DPRINT("inflateEnd() returned (%d).\n", Status);
-      return CS_BADSTREAM;
-    }
+  *InputLength = ZStream.total_in;
   return CS_SUCCESS;
 }
 
@@ -197,97 +201,14 @@
   RtlFreeHeap(ProcessHeap, 0, address);
 }
 
-
-static DWORD
-SeekInFile(HANDLE hFile,
-  LONG lDistanceToMove,
-  PLONG lpDistanceToMoveHigh,
-  DWORD dwMoveMethod,
-  PNTSTATUS Status)
-{
-  FILE_POSITION_INFORMATION FilePosition;
-  FILE_STANDARD_INFORMATION FileStandard;
-  NTSTATUS errCode;
-  IO_STATUS_BLOCK IoStatusBlock;
-  LARGE_INTEGER Distance;
-
-  DPRINT("SeekInFile(hFile %x, lDistanceToMove %d, dwMoveMethod %d)\n",
-    hFile,lDistanceToMove,dwMoveMethod);
-
-  Distance.u.LowPart = lDistanceToMove;
-  if (lpDistanceToMoveHigh)
-    {
-      Distance.u.HighPart = *lpDistanceToMoveHigh;
-    }
-  else if (lDistanceToMove >= 0)
-    {
-      Distance.u.HighPart = 0;
-    }
-  else
-    {
-      Distance.u.HighPart = -1;
-    }
-
-  if (dwMoveMethod == SEEK_CURRENT)
-    {
-      NtQueryInformationFile(hFile,
-        &IoStatusBlock,
-        &FilePosition,
-        sizeof(FILE_POSITION_INFORMATION),
-        FilePositionInformation);
-        FilePosition.CurrentByteOffset.QuadPart += Distance.QuadPart;
-    }
-  else if (dwMoveMethod == SEEK_END)
-    {
-      NtQueryInformationFile(hFile,
-        &IoStatusBlock,
-        &FileStandard,
-        sizeof(FILE_STANDARD_INFORMATION),
-        FileStandardInformation);
-        FilePosition.CurrentByteOffset.QuadPart =
-        FileStandard.EndOfFile.QuadPart + Distance.QuadPart;
-    }
-  else if ( dwMoveMethod == SEEK_BEGIN )
-    {
-      FilePosition.CurrentByteOffset.QuadPart = Distance.QuadPart;
-    }
-
-//  DPRINT1("GOTO FILE OFFSET: %I64d\n", FilePosition.CurrentByteOffset.QuadPart);
-
-  errCode = NtSetInformationFile(hFile,
-    &IoStatusBlock,
-    &FilePosition,
-    sizeof(FILE_POSITION_INFORMATION),
-    FilePositionInformation);
-  if (!NT_SUCCESS(errCode))
-    {
-      if (Status != NULL)
-        {
-          *Status = errCode;
-        }
-      return -1;
-    }
-
-  if (lpDistanceToMoveHigh != NULL)
-    {
-      *lpDistanceToMoveHigh = FilePosition.CurrentByteOffset.u.HighPart;
-    }
-  if (Status != NULL)
-    {
-      *Status = STATUS_SUCCESS;
-    }
-  return FilePosition.CurrentByteOffset.u.LowPart;
-}
-
-
 static BOOL
 ConvertSystemTimeToFileTime(
-  CONST SYSTEMTIME *  lpSystemTime,
+  CONST SYSTEMTIME *  lpSystemTime,	
   LPFILETIME  lpFileTime)
 {
   TIME_FIELDS TimeFields;
   LARGE_INTEGER liTime;
-
+  
   TimeFields.Year = lpSystemTime->wYear;
   TimeFields.Month = lpSystemTime->wMonth;
   TimeFields.Day = lpSystemTime->wDay;
@@ -295,7 +216,7 @@
   TimeFields.Minute = lpSystemTime->wMinute;
   TimeFields.Second = lpSystemTime->wSecond;
   TimeFields.Milliseconds = lpSystemTime->wMilliseconds;
-
+  
   if (RtlTimeFieldsToTime(&TimeFields, &liTime))
     {
       lpFileTime->dwLowDateTime = liTime.u.LowPart;
@@ -315,21 +236,21 @@
   PDOSTIME  pdtime = (PDOSTIME) &wFatTime;
   PDOSDATE  pddate = (PDOSDATE) &wFatDate;
   SYSTEMTIME SystemTime;
-
+  
   if (lpFileTime == NULL)
     return FALSE;
-
+  
   SystemTime.wMilliseconds = 0;
   SystemTime.wSecond = pdtime->Second;
   SystemTime.wMinute = pdtime->Minute;
   SystemTime.wHour = pdtime->Hour;
-
+  
   SystemTime.wDay = pddate->Day;
   SystemTime.wMonth = pddate->Month;
   SystemTime.wYear = 1980 + pddate->Year;
-
+  
   ConvertSystemTimeToFileTime(&SystemTime,lpFileTime);
-
+  
   return TRUE;
 }
 
@@ -345,9 +266,9 @@
  */
 {
   ULONG i, j;
-
+  
   j = i = 0;
-
+  
   while (Path [i++])
     {
       if (Path[i - 1] == L'\\') j = i;
@@ -366,10 +287,10 @@
 {
   PWCHAR FileName;
   DWORD i;
-
+  
   i = 0;
   FileName = GetFileName(Path + i);
-
+  
   if ((FileName != (Path + i)) && (FileName [-1] == L'\\'))
     FileName--;
   if ((FileName == (Path + i)) && (FileName [0] == L'\\'))
@@ -379,7 +300,7 @@
 
 
 static BOOL
-SetAttributesOnFile(PCFFILE_NODE File, HANDLE hFile)
+SetAttributesOnFile(PCFFILE File, HANDLE hFile)
 /*
  * FUNCTION: Sets attributes on a file
  * ARGUMENTS:
@@ -393,19 +314,19 @@
   NTSTATUS NtStatus;
   ULONG Attributes = 0;
 
-  if (File->File.Attributes & CAB_ATTRIB_READONLY)
+  if (File->Attributes & CAB_ATTRIB_READONLY)
     Attributes |= FILE_ATTRIBUTE_READONLY;
 
-  if (File->File.Attributes & CAB_ATTRIB_HIDDEN)
+  if (File->Attributes & CAB_ATTRIB_HIDDEN)
     Attributes |= FILE_ATTRIBUTE_HIDDEN;
 
-  if (File->File.Attributes & CAB_ATTRIB_SYSTEM)
+  if (File->Attributes & CAB_ATTRIB_SYSTEM)
     Attributes |= FILE_ATTRIBUTE_SYSTEM;
 
-  if (File->File.Attributes & CAB_ATTRIB_DIRECTORY)
+  if (File->Attributes & CAB_ATTRIB_DIRECTORY)
     Attributes |= FILE_ATTRIBUTE_DIRECTORY;
 
-  if (File->File.Attributes & CAB_ATTRIB_ARCHIVE)
+  if (File->Attributes & CAB_ATTRIB_ARCHIVE)
     Attributes |= FILE_ATTRIBUTE_ARCHIVE;
 
   NtStatus = NtQueryInformationFile(hFile,
@@ -435,698 +356,7 @@
   return NT_SUCCESS(NtStatus);
 }
 
-
 static ULONG
-ReadBlock(PVOID Buffer,
-  ULONG Size,
-  PULONG BytesRead)
-/*
- * FUNCTION: Read a block of data from file
- * ARGUMENTS:
- *     Buffer    = Pointer to data buffer
- *     Size      = Length of data buffer
- *     BytesRead = Pointer to ULONG that on return will contain
- *                 number of bytes read
- * RETURNS:
- *     Status of operation
- */
-{
-  IO_STATUS_BLOCK IoStatusBlock;
-  NTSTATUS NtStatus;
-
-  NtStatus = NtReadFile(FileHandle,
-	  NULL,
-	  NULL,
-	  NULL,
-	  &IoStatusBlock,
-	  Buffer,
-	  Size,
-	  NULL,
-	  NULL);
-  if (!NT_SUCCESS(NtStatus))
-	  {
-      DPRINT("ReadBlock for %d bytes failed (%x)\n", Size, NtStatus);
-      *BytesRead = 0;
-      return CAB_STATUS_INVALID_CAB;
-    }
-  *BytesRead = Size;
-  return CAB_STATUS_SUCCESS;
-}
-
-
-static PCFFOLDER_NODE
-NewFolderNode()
-/*
- * FUNCTION: Creates a new folder node
- * RETURNS:
- *     Pointer to node if there was enough free memory available, otherwise NULL
- */
-{
-  PCFFOLDER_NODE Node;
-
-  Node = (PCFFOLDER_NODE)RtlAllocateHeap (ProcessHeap, 0, sizeof(CFFOLDER_NODE));
-  if (!Node)
-    return NULL;
-
-  RtlZeroMemory(Node, sizeof(CFFOLDER_NODE));
-
-  Node->Folder.CompressionType = CAB_COMP_NONE;
-
-  Node->Prev = FolderListTail;
-
-  if (FolderListTail != NULL)
-    {
-      FolderListTail->Next = Node;
-    }
-  else
-    {
-      FolderListHead = Node;
-    }
-  FolderListTail = Node;
-
-  return Node;
-}
-
-
-static PCFFILE_NODE
-NewFileNode()
-/*
- * FUNCTION: Creates a new file node
- * ARGUMENTS:
- *     FolderNode = Pointer to folder node to bind file to
- * RETURNS:
- *     Pointer to node if there was enough free memory available, otherwise NULL
- */
-{
-  PCFFILE_NODE Node;
-
-  Node = (PCFFILE_NODE)RtlAllocateHeap (ProcessHeap, 0, sizeof(CFFILE_NODE));
-  if (!Node)
-    return NULL;
-
-  RtlZeroMemory(Node, sizeof(CFFILE_NODE));
-
-  Node->Prev = FileListTail;
-
-  if (FileListTail != NULL)
-    {
-      FileListTail->Next = Node;
-    }
-  else
-    {
-      FileListHead = Node;
-    }
-  FileListTail = Node;
-
-  return Node;
-}
-
-
-static PCFDATA_NODE
-NewDataNode(PCFFOLDER_NODE FolderNode)
-/*
- * FUNCTION: Creates a new data block node
- * ARGUMENTS:
- *     FolderNode = Pointer to folder node to bind data block to
- * RETURNS:
- *     Pointer to node if there was enough free memory available, otherwise NULL
- */
-{
-  PCFDATA_NODE Node;
-
-  Node = (PCFDATA_NODE)RtlAllocateHeap (ProcessHeap, 0, sizeof(CFDATA_NODE));
-  if (!Node)
-    return NULL;
-
-  RtlZeroMemory(Node, sizeof(CFDATA_NODE));
-
-  Node->Prev = FolderNode->DataListTail;
-
-  if (FolderNode->DataListTail != NULL)
-    {
-      FolderNode->DataListTail->Next = Node;
-    }
-  else
-    {
-      FolderNode->DataListHead = Node;
-    }
-  FolderNode->DataListTail = Node;
-
-  return Node;
-}
-
-
-static VOID
-DestroyDataNodes(PCFFOLDER_NODE FolderNode)
-/*
- * FUNCTION: Destroys data block nodes bound to a folder node
- * ARGUMENTS:
- *     FolderNode = Pointer to folder node
- */
-{
-  PCFDATA_NODE PrevNode;
-  PCFDATA_NODE NextNode;
-
-  NextNode = FolderNode->DataListHead;
-  while (NextNode != NULL)
-    {
-      PrevNode = NextNode->Next;
-      RtlFreeHeap(ProcessHeap, 0, NextNode);
-      NextNode = PrevNode;
-    }
-  FolderNode->DataListHead = NULL;
-  FolderNode->DataListTail = NULL;
-}
-
-
-static VOID
-DestroyFileNodes()
-/*
- * FUNCTION: Destroys file nodes
- * ARGUMENTS:
- *     FolderNode = Pointer to folder node
- */
-{
-  PCFFILE_NODE PrevNode;
-  PCFFILE_NODE NextNode;
-
-  NextNode = FileListHead;
-  while (NextNode != NULL)
-    {
-      PrevNode = NextNode->Next;
-      if (NextNode->FileName)
-        RtlFreeHeap(ProcessHeap, 0, NextNode->FileName);
-      RtlFreeHeap(ProcessHeap, 0, NextNode);
-      NextNode = PrevNode;
-    }
-  FileListHead = NULL;
-  FileListTail = NULL;
-}
-
-
-#if 0
-static VOID
-DestroyDeletedFileNodes()
-/*
- * FUNCTION: Destroys file nodes that are marked for deletion
- */
-{
-  PCFFILE_NODE CurNode;
-  PCFFILE_NODE NextNode;
-
-  CurNode = FileListHead;
-  while (CurNode != NULL)
-    {
-      NextNode = CurNode->Next;
-
-      if (CurNode->Delete)
-        {
-          if (CurNode->Prev != NULL)
-            {
-              CurNode->Prev->Next = CurNode->Next;
-            }
-          else
-            {
-              FileListHead = CurNode->Next;
-              if (FileListHead)
-                  FileListHead->Prev = NULL;
-            }
-
-          if (CurNode->Next != NULL)
-            {
-              CurNode->Next->Prev = CurNode->Prev;
-            }
-          else
-            {
-              FileListTail = CurNode->Prev;
-              if (FileListTail)
-                  FileListTail->Next = NULL;
-            }
-
-          DPRINT("Deleting file: '%S'\n", CurNode->FileName);
-
-          if (CurNode->FileName)
-            RtlFreeHeap(ProcessHeap, 0, CurNode->FileName);
-          RtlFreeHeap(ProcessHeap, 0, CurNode);
-        }
-      CurNode = NextNode;
-    }
-}
-#endif
-
-static VOID
-DestroyFolderNodes()
-/*
- * FUNCTION: Destroys folder nodes
- */
-{
-  PCFFOLDER_NODE PrevNode;
-  PCFFOLDER_NODE NextNode;
-
-  NextNode = FolderListHead;
-  while (NextNode != NULL)
-    {
-      PrevNode = NextNode->Next;
-      DestroyDataNodes(NextNode);
-      RtlFreeHeap(ProcessHeap, 0, NextNode);
-      NextNode = PrevNode;
-    }
-  FolderListHead = NULL;
-  FolderListTail = NULL;
-}
-
-#if 0
-static VOID
-DestroyDeletedFolderNodes()
-/*
- * FUNCTION: Destroys folder nodes that are marked for deletion
- */
-{
-  PCFFOLDER_NODE CurNode;
-  PCFFOLDER_NODE NextNode;
-
-  CurNode = FolderListHead;
-  while (CurNode != NULL)
-    {
-      NextNode = CurNode->Next;
-
-      if (CurNode->Delete)
-        {
-          if (CurNode->Prev != NULL)
-            {
-              CurNode->Prev->Next = CurNode->Next;
-            }
-          else
-            {
-              FolderListHead = CurNode->Next;
-              if (FolderListHead)
-                FolderListHead->Prev = NULL;
-            }
-
-          if (CurNode->Next != NULL)
-            {
-              CurNode->Next->Prev = CurNode->Prev;
-            }
-          else
-            {
-              FolderListTail = CurNode->Prev;
-              if (FolderListTail)
-                  FolderListTail->Next = NULL;
-            }
-
-          DestroyDataNodes(CurNode);
-          RtlFreeHeap(ProcessHeap, 0, CurNode);
-      }
-      CurNode = NextNode;
-    }
-}
-#endif
-
-static PCFFOLDER_NODE
-LocateFolderNode(ULONG Index)
-/*
- * FUNCTION: Locates a folder node
- * ARGUMENTS:
- *     Index = Folder index
- * RETURNS:
- *     Pointer to folder node or NULL if the folder node was not found
- */
-{
-  PCFFOLDER_NODE Node;
-
-  switch (Index)
-    {
-      case CAB_FILE_SPLIT:
-        return FolderListTail;
-
-      case CAB_FILE_CONTINUED:
-      case CAB_FILE_PREV_NEXT:
-        return FolderListHead;
-    }
-
-  Node = FolderListHead;
-  while (Node != NULL)
-    {
-      if (Node->Index == Index)
-        return Node;
-      Node = Node->Next;
-    }
-  return NULL;
-}
-
-
-static ULONG
-GetAbsoluteOffset(PCFFILE_NODE File)
-/*
- * FUNCTION: Returns the absolute offset of a file
- * ARGUMENTS:
- *     File = Pointer to CFFILE_NODE structure for file
- * RETURNS:
- *     Status of operation
- */
-{
-  PCFDATA_NODE Node;
-
-  DPRINT("FileName '%S'  FileOffset (0x%X)  FileSize (%d).\n",
-    (PWCHAR)File->FileName,
-    (UINT)File->File.FileOffset,
-    (UINT)File->File.FileSize);
-
-  Node = CurrentFolderNode->DataListHead;
-  while (Node != NULL)
-    {
-      DPRINT("GetAbsoluteOffset(): Comparing (0x%X, 0x%X) (%d).\n",
-          (UINT)Node->UncompOffset,
-          (UINT)Node->UncompOffset + Node->Data.UncompSize,
-          (UINT)Node->Data.UncompSize);
-
-      /* Node->Data.UncompSize will be 0 if the block is split
-         (ie. it is the last block in this cabinet) */
-      if ((Node->Data.UncompSize == 0) ||
-        ((File->File.FileOffset >= Node->UncompOffset) &&
-        (File->File.FileOffset < Node->UncompOffset +
-        Node->Data.UncompSize)))
-        {
-          File->DataBlock = Node;
-          return CAB_STATUS_SUCCESS;
-        }
-
-      Node = Node->Next;
-    }
-  return CAB_STATUS_INVALID_CAB;
-}
-
-
-static ULONG
-LocateFile(PWCHAR FileName,
-  PCFFILE_NODE *File)
-/*
- * FUNCTION: Locates a file in the cabinet
- * ARGUMENTS:
- *     FileName = Pointer to string with name of file to locate
- *     File     = Address of pointer to CFFILE_NODE structure to fill
- * RETURNS:
- *     Status of operation
- * NOTES:
- *     Current folder is set to the folder of the file
- */
-{
-  PCFFILE_NODE Node;
-  ULONG Status;
-
-  DPRINT("FileName '%S'\n", FileName);
-
-  Node = FileListHead;
-  while (Node != NULL)
-    {
-      if (_wcsicmp(FileName, Node->FileName) == 0)
-        {
-          CurrentFolderNode = LocateFolderNode(Node->File.FileControlID);
-          if (!CurrentFolderNode)
-            {
-              DPRINT("Folder with index number (%d) not found.\n",
-                (UINT)Node->File.FileControlID);
-              return CAB_STATUS_INVALID_CAB;
-            }
-
-          if (Node->DataBlock == NULL)
-            {
-              Status = GetAbsoluteOffset(Node);
-            }
-          else
-            Status = CAB_STATUS_SUCCESS;
-          *File = Node;
-          return Status;
-      }
-      Node = Node->Next;
-  }
-  return CAB_STATUS_NOFILE;
-}
-
-
-static ULONG
-ReadString(PWCHAR String, ULONG MaxLength)
-/*
- * FUNCTION: Reads a NULL-terminated string from the cabinet
- * ARGUMENTS:
- *     String    = Pointer to buffer to place string
- *     MaxLength = Maximum length of string
- * RETURNS:
- *     Status of operation
- */
-{
-  NTSTATUS NtStatus;
-  ULONG BytesRead;
-  ULONG Offset;
-  ULONG Status;
-  ULONG Size;
-  BOOL Found;
-  CHAR buf[MAX_PATH];
-  ANSI_STRING as;
-  UNICODE_STRING us;
-
-  Offset = 0;
-  Found  = FALSE;
-  do
-    {
-      Size = ((Offset + 32) <= MaxLength)? 32 : MaxLength - Offset;
-
-      if (Size == 0)
-        {
-          DPRINT("Too long a filename.\n");
-          return CAB_STATUS_INVALID_CAB;
-        }
-
-      Status = ReadBlock((PCFDATA)&buf[Offset], Size, &BytesRead);
-      if ((Status != CAB_STATUS_SUCCESS) || (BytesRead != Size))
-        {
-          DPRINT("Cannot read from file (%d).\n", (UINT)Status);
-          return CAB_STATUS_INVALID_CAB;
-        }
-
-      for (Size = Offset; Size < Offset + BytesRead; Size++)
-        {
-          if (buf[Size] == '\0')
-            {
-              Found = TRUE;
-              break;
-            }
-        }
-
-      Offset += BytesRead;
-    } while (!Found);
-
-  /* Back up some bytes */
-  Size = (BytesRead - Size) - 1;
-  SeekInFile(FileHandle, -(LONG)Size, NULL, SEEK_CURRENT, &NtStatus);
-  if (!NT_SUCCESS(NtStatus))
-    {
-      DPRINT("SeekInFile() failed (%x).\n", NtStatus);
-      return CAB_STATUS_INVALID_CAB;
-    }
-
-  RtlInitAnsiString(&as, buf);
-  us.Buffer = String;
-  us.MaximumLength = MaxLength * sizeof(WCHAR);
-  us.Length = 0;
-
-  RtlAnsiStringToUnicodeString(&us, &as, FALSE);
-
-  return CAB_STATUS_SUCCESS;
-}
-
-
-static ULONG
-ReadFileTable(VOID)
-/*
- * FUNCTION: Reads the file table from the cabinet file
- * RETURNS:
- *     Status of operation
- */
-{
-  ULONG i;
-  ULONG Status;
-  ULONG BytesRead;
-  PCFFILE_NODE File;
-  NTSTATUS NtStatus;
-
-  DPRINT("Reading file table at absolute offset (0x%X).\n",
-    CABHeader.FileTableOffset);
-
-  /* Seek to file table */
-  SeekInFile(FileHandle, CABHeader.FileTableOffset, NULL, SEEK_BEGIN, &NtStatus);
-  if (!NT_SUCCESS(NtStatus))
-    {
-      DPRINT("SeekInFile() failed (%x).\n", NtStatus);
-      return CAB_STATUS_INVALID_CAB;
-    }
-
-  for (i = 0; i < CABHeader.FileCount; i++)
-    {
-      File = NewFileNode();
-      if (!File)
-        {
-          DPRINT("Insufficient memory.\n");
-          return CAB_STATUS_NOMEMORY;
-        }
-
-      if ((Status = ReadBlock(&File->File, sizeof(CFFILE),
-          &BytesRead)) != CAB_STATUS_SUCCESS) {
-          DPRINT("Cannot read from file (%d).\n", (UINT)Status);
-          return CAB_STATUS_INVALID_CAB;
-      }
-
-      File->FileName = (PWCHAR)RtlAllocateHeap(ProcessHeap, 0, MAX_PATH * sizeof(WCHAR));
-      if (!File->FileName)
-        {
-          DPRINT("Insufficient memory.\n");
-          return CAB_STATUS_NOMEMORY;
-        }
-
-      /* Read file name */
-      Status = ReadString(File->FileName, MAX_PATH);
-      if (Status != CAB_STATUS_SUCCESS)
-        return Status;
-
-      DPRINT("Found file '%S' at uncompressed offset (0x%X).  Size (%d bytes)  ControlId (0x%X).\n",
-        (PWCHAR)File->FileName,
-        (UINT)File->File.FileOffset,
-        (UINT)File->File.FileSize,
-        (UINT)File->File.FileControlID);
-    }
-  return CAB_STATUS_SUCCESS;
-}
-
-
-static ULONG
-ReadDataBlocks(PCFFOLDER_NODE FolderNode)
-/*
- * FUNCTION: Reads all CFDATA blocks for a folder from the cabinet file
- * ARGUMENTS:
- *     FolderNode = Pointer to CFFOLDER_NODE structure for folder
- * RETURNS:
- *     Status of operation
- */
-{
-  ULONG AbsoluteOffset;
-  ULONG UncompOffset;
-  PCFDATA_NODE Node;
-  NTSTATUS NtStatus;
-  ULONG BytesRead;
-  ULONG Status;
-  ULONG i;
-
-  DPRINT("Reading data blocks for folder (%d)  at absolute offset (0x%X).\n",
-    FolderNode->Index, FolderNode->Folder.DataOffset);
-
-  AbsoluteOffset = FolderNode->Folder.DataOffset;
-  UncompOffset = FolderNode->UncompOffset;
-
-  for (i = 0; i < FolderNode->Folder.DataBlockCount; i++)
-    {
-      Node = NewDataNode(FolderNode);
-      if (!Node)
-        {
-          DPRINT("Insufficient memory.\n");
-          return CAB_STATUS_NOMEMORY;
-        }
-
-      /* Seek to data block */
-      SeekInFile(FileHandle, AbsoluteOffset, NULL, SEEK_BEGIN, &NtStatus);
[truncated at 1000 lines; 1631 more skipped]