2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS text-mode setup
4 * FILE: subsys/system/usetup/cabinet.c
5 * PURPOSE: Cabinet routines
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
8 * CSH 15/08-2003 Created
21 #define SEEK_CURRENT 1
24 typedef struct __DOSTIME
32 typedef struct __DOSDATE
39 static WCHAR CabinetName[256]; // Filename of current cabinet
40 static WCHAR CabinetPrev[256]; // Filename of previous cabinet
41 static WCHAR DiskPrev[256]; // Label of cabinet in file CabinetPrev
42 static WCHAR CabinetNext[256]; // Filename of next cabinet
43 static WCHAR DiskNext[256]; // Label of cabinet in file CabinetNext
44 static ULONG FolderUncompSize = 0; // Uncompressed size of folder
45 static ULONG BytesLeftInBlock = 0; // Number of bytes left in current block
46 static BOOL ReuseBlock = FALSE;
47 static WCHAR DestPath[MAX_PATH];
48 static HANDLE FileHandle;
49 static BOOL FileOpen = FALSE;
50 static CFHEADER CABHeader;
51 static ULONG CabinetReserved = 0;
52 static ULONG FolderReserved = 0;
53 static ULONG DataReserved = 0;
54 static PCFFOLDER_NODE FolderListHead = NULL;
55 static PCFFOLDER_NODE FolderListTail = NULL;
56 static PCFFOLDER_NODE CurrentFolderNode = NULL;
57 static PCFDATA_NODE CurrentDataNode = NULL;
58 static PCFFILE_NODE FileListHead = NULL;
59 static PCFFILE_NODE FileListTail = NULL;
61 static PCABINET_CODEC_UNCOMPRESS CodecUncompress = NULL;
62 static BOOL CodecSelected = FALSE;
63 static PVOID InputBuffer = NULL;
64 static PVOID CurrentIBuffer = NULL; // Current offset in input buffer
65 static ULONG CurrentIBufferSize = 0; // Bytes left in input buffer
66 static PVOID OutputBuffer = NULL;
67 static PVOID CurrentOBuffer = NULL; // Current offset in output buffer
68 static ULONG CurrentOBufferSize = 0; // Bytes left in output buffer
69 static BOOL RestartSearch = FALSE;
70 static ULONG LastFileOffset = 0; // Uncompressed offset of last extracted file
71 static PCABINET_OVERWRITE OverwriteHandler = NULL;
72 static PCABINET_EXTRACT ExtractHandler = NULL;
73 static PCABINET_DISK_CHANGE DiskChangeHandler = NULL;
74 static z_stream ZStream;
75 static PVOID CabinetReservedArea = NULL;
78 /* Needed by zlib, but we don't want the dependency on msvcrt.dll */
82 RtlFreeHeap(ProcessHeap, 0, _ptr);
85 void* calloc(size_t _nmemb, size_t _size)
87 return (void*)RtlAllocateHeap (ProcessHeap, HEAP_ZERO_MEMORY, _size);
93 RawCodecUncompress(PVOID OutputBuffer,
98 * FUNCTION: Uncompresses data in a buffer
100 * OutputBuffer = Pointer to buffer to place uncompressed data
101 * InputBuffer = Pointer to buffer with data to be uncompressed
102 * InputLength = Length of input buffer
103 * OutputLength = Address of buffer to place size of uncompressed data
106 memcpy(OutputBuffer, InputBuffer, InputLength);
107 *OutputLength = InputLength;
115 MSZipCodecUncompress(PVOID OutputBuffer,
120 * FUNCTION: Uncompresses data in a buffer
122 * OutputBuffer = Pointer to buffer to place uncompressed data
123 * InputBuffer = Pointer to buffer with data to be uncompressed
124 * InputLength = Length of input buffer
125 * OutputLength = Address of buffer to place size of uncompressed data
131 DPRINT("InputLength (%d).\n", InputLength);
133 Magic = *((PUSHORT)InputBuffer);
135 if (Magic != MSZIP_MAGIC)
137 DPRINT("Bad MSZIP block header magic (0x%X)\n", Magic);
141 ZStream.next_in = (PUCHAR)((ULONG)InputBuffer + 2);
142 ZStream.avail_in = InputLength - 2;
143 ZStream.next_out = (PUCHAR)OutputBuffer;
144 ZStream.avail_out = CAB_BLOCKSIZE + 12;
146 /* WindowBits is passed < 0 to tell that there is no zlib header.
147 * Note that in this case inflate *requires* an extra "dummy" byte
148 * after the compressed stream in order to complete decompression and
149 * return Z_STREAM_END.
151 Status = inflateInit2(&ZStream, -MAX_WBITS);
154 DPRINT("inflateInit2() returned (%d).\n", Status);
158 while ((ZStream.total_out < CAB_BLOCKSIZE + 12) &&
159 (ZStream.total_in < InputLength - 2))
161 Status = inflate(&ZStream, Z_NO_FLUSH);
162 if (Status == Z_STREAM_END) break;
165 DPRINT("inflate() returned (%d) (%s).\n", Status, ZStream.msg);
166 if (Status == Z_MEM_ERROR)
172 *OutputLength = ZStream.total_out;
174 Status = inflateEnd(&ZStream);
177 DPRINT("inflateEnd() returned (%d).\n", Status);
185 /* Memory functions */
187 voidpf MSZipAlloc(voidpf opaque, uInt items, uInt size)
189 return (voidpf)RtlAllocateHeap (ProcessHeap, 0, items * size);
192 void MSZipFree (voidpf opaque, voidpf address)
194 RtlFreeHeap(ProcessHeap, 0, address);
199 SeekInFile(HANDLE hFile,
200 LONG lDistanceToMove,
201 PLONG lpDistanceToMoveHigh,
205 FILE_POSITION_INFORMATION FilePosition;
206 FILE_STANDARD_INFORMATION FileStandart;
208 IO_STATUS_BLOCK IoStatusBlock;
209 LARGE_INTEGER Distance;
211 DPRINT("SeekInFile(hFile %x, lDistanceToMove %d, dwMoveMethod %d)\n",
212 hFile,lDistanceToMove,dwMoveMethod);
214 Distance.u.LowPart = lDistanceToMove;
215 if (lpDistanceToMoveHigh)
217 Distance.u.HighPart = *lpDistanceToMoveHigh;
219 else if (lDistanceToMove >= 0)
221 Distance.u.HighPart = 0;
225 Distance.u.HighPart = -1;
228 if (dwMoveMethod == SEEK_CURRENT)
230 NtQueryInformationFile(hFile,
233 sizeof(FILE_POSITION_INFORMATION),
234 FilePositionInformation);
235 FilePosition.CurrentByteOffset.QuadPart += Distance.QuadPart;
237 else if (dwMoveMethod == SEEK_END)
239 NtQueryInformationFile(hFile,
242 sizeof(FILE_STANDARD_INFORMATION),
243 FileStandardInformation);
244 FilePosition.CurrentByteOffset.QuadPart =
245 FileStandart.EndOfFile.QuadPart + Distance.QuadPart;
247 else if ( dwMoveMethod == SEEK_BEGIN )
249 FilePosition.CurrentByteOffset.QuadPart = Distance.QuadPart;
252 // DPRINT1("GOTO FILE OFFSET: %I64d\n", FilePosition.CurrentByteOffset.QuadPart);
254 errCode = NtSetInformationFile(hFile,
257 sizeof(FILE_POSITION_INFORMATION),
258 FilePositionInformation);
259 if (!NT_SUCCESS(errCode))
268 if (lpDistanceToMoveHigh != NULL)
270 *lpDistanceToMoveHigh = FilePosition.CurrentByteOffset.u.HighPart;
274 *Status = STATUS_SUCCESS;
276 return FilePosition.CurrentByteOffset.u.LowPart;
281 ConvertSystemTimeToFileTime(
282 CONST SYSTEMTIME * lpSystemTime,
283 LPFILETIME lpFileTime)
285 TIME_FIELDS TimeFields;
286 LARGE_INTEGER liTime;
288 TimeFields.Year = lpSystemTime->wYear;
289 TimeFields.Month = lpSystemTime->wMonth;
290 TimeFields.Day = lpSystemTime->wDay;
291 TimeFields.Hour = lpSystemTime->wHour;
292 TimeFields.Minute = lpSystemTime->wMinute;
293 TimeFields.Second = lpSystemTime->wSecond;
294 TimeFields.Milliseconds = lpSystemTime->wMilliseconds;
296 if (RtlTimeFieldsToTime(&TimeFields, &liTime))
298 lpFileTime->dwLowDateTime = liTime.u.LowPart;
299 lpFileTime->dwHighDateTime = liTime.u.HighPart;
307 ConvertDosDateTimeToFileTime(
310 LPFILETIME lpFileTime)
312 PDOSTIME pdtime = (PDOSTIME) &wFatTime;
313 PDOSDATE pddate = (PDOSDATE) &wFatDate;
314 SYSTEMTIME SystemTime;
316 if (lpFileTime == NULL)
319 SystemTime.wMilliseconds = 0;
320 SystemTime.wSecond = pdtime->Second;
321 SystemTime.wMinute = pdtime->Minute;
322 SystemTime.wHour = pdtime->Hour;
324 SystemTime.wDay = pddate->Day;
325 SystemTime.wMonth = pddate->Month;
326 SystemTime.wYear = 1980 + pddate->Year;
328 ConvertSystemTimeToFileTime(&SystemTime,lpFileTime);
335 GetFileName(PWCHAR Path)
337 * FUNCTION: Returns a pointer to file name
339 * Path = Pointer to string with pathname
341 * Pointer to filename
350 if (Path[i - 1] == L'\\') j = i;
357 RemoveFileName(PWCHAR Path)
359 * FUNCTION: Removes a file name from a path
361 * Path = Pointer to string with path
368 FileName = GetFileName(Path + i);
370 if ((FileName != (Path + i)) && (FileName [-1] == L'\\'))
372 if ((FileName == (Path + i)) && (FileName [0] == L'\\'))
379 SetAttributesOnFile(PCFFILE_NODE File, HANDLE hFile)
381 * FUNCTION: Sets attributes on a file
383 * File = Pointer to CFFILE node for file
385 * Status of operation
388 FILE_BASIC_INFORMATION FileBasic;
389 IO_STATUS_BLOCK IoStatusBlock;
391 ULONG Attributes = 0;
393 if (File->File.Attributes & CAB_ATTRIB_READONLY)
394 Attributes |= FILE_ATTRIBUTE_READONLY;
396 if (File->File.Attributes & CAB_ATTRIB_HIDDEN)
397 Attributes |= FILE_ATTRIBUTE_HIDDEN;
399 if (File->File.Attributes & CAB_ATTRIB_SYSTEM)
400 Attributes |= FILE_ATTRIBUTE_SYSTEM;
402 if (File->File.Attributes & CAB_ATTRIB_DIRECTORY)
403 Attributes |= FILE_ATTRIBUTE_DIRECTORY;
405 if (File->File.Attributes & CAB_ATTRIB_ARCHIVE)
406 Attributes |= FILE_ATTRIBUTE_ARCHIVE;
408 NtStatus = NtQueryInformationFile(hFile,
411 sizeof(FILE_BASIC_INFORMATION),
412 FileBasicInformation);
413 if (!NT_SUCCESS(NtStatus))
415 DPRINT("NtQueryInformationFile() failed (%x).\n", NtStatus);
419 FileBasic.FileAttributes = Attributes;
421 NtStatus = NtSetInformationFile(hFile,
424 sizeof(FILE_BASIC_INFORMATION),
425 FileBasicInformation);
426 if (!NT_SUCCESS(NtStatus))
428 DPRINT("NtSetInformationFile() failed (%x).\n", NtStatus);
432 return NT_SUCCESS(NtStatus);
437 ReadBlock(PVOID Buffer,
441 * FUNCTION: Read a block of data from file
443 * Buffer = Pointer to data buffer
444 * Size = Length of data buffer
445 * BytesRead = Pointer to ULONG that on return will contain
446 * number of bytes read
448 * Status of operation
451 IO_STATUS_BLOCK IoStatusBlock;
454 NtStatus = NtReadFile(FileHandle,
463 if (!NT_SUCCESS(NtStatus))
465 DPRINT("ReadBlock for %d bytes failed (%x)\n", Size, NtStatus);
467 return CAB_STATUS_INVALID_CAB;
470 return CAB_STATUS_SUCCESS;
474 static PCFFOLDER_NODE
477 * FUNCTION: Creates a new folder node
479 * Pointer to node if there was enough free memory available, otherwise NULL
484 Node = (PCFFOLDER_NODE)RtlAllocateHeap (ProcessHeap, 0, sizeof(CFFOLDER_NODE));
488 RtlZeroMemory(Node, sizeof(CFFOLDER_NODE));
490 Node->Folder.CompressionType = CAB_COMP_NONE;
492 Node->Prev = FolderListTail;
494 if (FolderListTail != NULL)
496 FolderListTail->Next = Node;
500 FolderListHead = Node;
502 FolderListTail = Node;
511 * FUNCTION: Creates a new file node
513 * FolderNode = Pointer to folder node to bind file to
515 * Pointer to node if there was enough free memory available, otherwise NULL
520 Node = (PCFFILE_NODE)RtlAllocateHeap (ProcessHeap, 0, sizeof(CFFILE_NODE));
524 RtlZeroMemory(Node, sizeof(CFFILE_NODE));
526 Node->Prev = FileListTail;
528 if (FileListTail != NULL)
530 FileListTail->Next = Node;
543 NewDataNode(PCFFOLDER_NODE FolderNode)
545 * FUNCTION: Creates a new data block node
547 * FolderNode = Pointer to folder node to bind data block to
549 * Pointer to node if there was enough free memory available, otherwise NULL
554 Node = (PCFDATA_NODE)RtlAllocateHeap (ProcessHeap, 0, sizeof(CFDATA_NODE));
558 RtlZeroMemory(Node, sizeof(CFDATA_NODE));
560 Node->Prev = FolderNode->DataListTail;
562 if (FolderNode->DataListTail != NULL)
564 FolderNode->DataListTail->Next = Node;
568 FolderNode->DataListHead = Node;
570 FolderNode->DataListTail = Node;
577 DestroyDataNodes(PCFFOLDER_NODE FolderNode)
579 * FUNCTION: Destroys data block nodes bound to a folder node
581 * FolderNode = Pointer to folder node
584 PCFDATA_NODE PrevNode;
585 PCFDATA_NODE NextNode;
587 NextNode = FolderNode->DataListHead;
588 while (NextNode != NULL)
590 PrevNode = NextNode->Next;
591 RtlFreeHeap(ProcessHeap, 0, NextNode);
594 FolderNode->DataListHead = NULL;
595 FolderNode->DataListTail = NULL;
602 * FUNCTION: Destroys file nodes
604 * FolderNode = Pointer to folder node
607 PCFFILE_NODE PrevNode;
608 PCFFILE_NODE NextNode;
610 NextNode = FileListHead;
611 while (NextNode != NULL)
613 PrevNode = NextNode->Next;
614 if (NextNode->FileName)
615 RtlFreeHeap(ProcessHeap, 0, NextNode->FileName);
616 RtlFreeHeap(ProcessHeap, 0, NextNode);
625 DestroyDeletedFileNodes()
627 * FUNCTION: Destroys file nodes that are marked for deletion
630 PCFFILE_NODE CurNode;
631 PCFFILE_NODE NextNode;
633 CurNode = FileListHead;
634 while (CurNode != NULL)
636 NextNode = CurNode->Next;
640 if (CurNode->Prev != NULL)
642 CurNode->Prev->Next = CurNode->Next;
646 FileListHead = CurNode->Next;
648 FileListHead->Prev = NULL;
651 if (CurNode->Next != NULL)
653 CurNode->Next->Prev = CurNode->Prev;
657 FileListTail = CurNode->Prev;
659 FileListTail->Next = NULL;
662 DPRINT("Deleting file: '%S'\n", CurNode->FileName);
664 if (CurNode->FileName)
665 RtlFreeHeap(ProcessHeap, 0, CurNode->FileName);
666 RtlFreeHeap(ProcessHeap, 0, CurNode);
676 * FUNCTION: Destroys folder nodes
679 PCFFOLDER_NODE PrevNode;
680 PCFFOLDER_NODE NextNode;
682 NextNode = FolderListHead;
683 while (NextNode != NULL)
685 PrevNode = NextNode->Next;
686 DestroyDataNodes(NextNode);
687 RtlFreeHeap(ProcessHeap, 0, NextNode);
690 FolderListHead = NULL;
691 FolderListTail = NULL;
696 DestroyDeletedFolderNodes()
698 * FUNCTION: Destroys folder nodes that are marked for deletion
701 PCFFOLDER_NODE CurNode;
702 PCFFOLDER_NODE NextNode;
704 CurNode = FolderListHead;
705 while (CurNode != NULL)
707 NextNode = CurNode->Next;
711 if (CurNode->Prev != NULL)
713 CurNode->Prev->Next = CurNode->Next;
717 FolderListHead = CurNode->Next;
719 FolderListHead->Prev = NULL;
722 if (CurNode->Next != NULL)
724 CurNode->Next->Prev = CurNode->Prev;
728 FolderListTail = CurNode->Prev;
730 FolderListTail->Next = NULL;
733 DestroyDataNodes(CurNode);
734 RtlFreeHeap(ProcessHeap, 0, CurNode);
741 static PCFFOLDER_NODE
742 LocateFolderNode(ULONG Index)
744 * FUNCTION: Locates a folder node
746 * Index = Folder index
748 * Pointer to folder node or NULL if the folder node was not found
756 return FolderListTail;
758 case CAB_FILE_CONTINUED:
759 case CAB_FILE_PREV_NEXT:
760 return FolderListHead;
763 Node = FolderListHead;
766 if (Node->Index == Index)
775 GetAbsoluteOffset(PCFFILE_NODE File)
777 * FUNCTION: Returns the absolute offset of a file
779 * File = Pointer to CFFILE_NODE structure for file
781 * Status of operation
786 DPRINT("FileName '%S' FileOffset (0x%X) FileSize (%d).\n",
787 (PWCHAR)File->FileName,
788 (UINT)File->File.FileOffset,
789 (UINT)File->File.FileSize);
791 Node = CurrentFolderNode->DataListHead;
794 DPRINT("GetAbsoluteOffset(): Comparing (0x%X, 0x%X) (%d).\n",
795 (UINT)Node->UncompOffset,
796 (UINT)Node->UncompOffset + Node->Data.UncompSize,
797 (UINT)Node->Data.UncompSize);
799 /* Node->Data.UncompSize will be 0 if the block is split
800 (ie. it is the last block in this cabinet) */
801 if ((Node->Data.UncompSize == 0) ||
802 ((File->File.FileOffset >= Node->UncompOffset) &&
803 (File->File.FileOffset < Node->UncompOffset +
804 Node->Data.UncompSize)))
806 File->DataBlock = Node;
807 return CAB_STATUS_SUCCESS;
812 return CAB_STATUS_INVALID_CAB;
817 LocateFile(PWCHAR FileName,
820 * FUNCTION: Locates a file in the cabinet
822 * FileName = Pointer to string with name of file to locate
823 * File = Address of pointer to CFFILE_NODE structure to fill
825 * Status of operation
827 * Current folder is set to the folder of the file
833 DPRINT("FileName '%S'\n", FileName);
838 if (_wcsicmp(FileName, Node->FileName) == 0)
840 CurrentFolderNode = LocateFolderNode(Node->File.FileControlID);
841 if (!CurrentFolderNode)
843 DPRINT("Folder with index number (%d) not found.\n",
844 (UINT)Node->File.FileControlID);
845 return CAB_STATUS_INVALID_CAB;
848 if (Node->DataBlock == NULL)
850 Status = GetAbsoluteOffset(Node);
853 Status = CAB_STATUS_SUCCESS;
859 return CAB_STATUS_NOFILE;
864 ReadString(PWCHAR String, ULONG MaxLength)
866 * FUNCTION: Reads a NULL-terminated string from the cabinet
868 * String = Pointer to buffer to place string
869 * MaxLength = Maximum length of string
871 * Status of operation
888 Size = ((Offset + 32) <= MaxLength)? 32 : MaxLength - Offset;
892 DPRINT("Too long a filename.\n");
893 return CAB_STATUS_INVALID_CAB;
896 Status = ReadBlock((PCFDATA)&buf[Offset], Size, &BytesRead);
897 if ((Status != CAB_STATUS_SUCCESS) || (BytesRead != Size))
899 DPRINT("Cannot read from file (%d).\n", (UINT)Status);
900 return CAB_STATUS_INVALID_CAB;
903 for (Size = Offset; Size < Offset + BytesRead; Size++)
905 if (buf[Size] == '\0')
915 /* Back up some bytes */
916 Size = (BytesRead - Size) - 1;
917 SeekInFile(FileHandle, -(LONG)Size, NULL, SEEK_CURRENT, &NtStatus);
918 if (!NT_SUCCESS(NtStatus))
920 DPRINT("SeekInFile() failed (%x).\n", NtStatus);
921 return CAB_STATUS_INVALID_CAB;
924 RtlInitAnsiString(&as, buf);
926 us.MaximumLength = MaxLength * sizeof(WCHAR);
929 RtlAnsiStringToUnicodeString(&us, &as, FALSE);
931 return CAB_STATUS_SUCCESS;
938 * FUNCTION: Reads the file table from the cabinet file
940 * Status of operation
949 DPRINT("Reading file table at absolute offset (0x%X).\n",
950 CABHeader.FileTableOffset);
952 /* Seek to file table */
953 SeekInFile(FileHandle, CABHeader.FileTableOffset, NULL, SEEK_BEGIN, &NtStatus);
954 if (!NT_SUCCESS(NtStatus))
956 DPRINT("SeekInFile() failed (%x).\n", NtStatus);
957 return CAB_STATUS_INVALID_CAB;
960 for (i = 0; i < CABHeader.FileCount; i++)
962 File = NewFileNode();
965 DPRINT("Insufficient memory.\n");
966 return CAB_STATUS_NOMEMORY;
969 if ((Status = ReadBlock(&File->File, sizeof(CFFILE),
970 &BytesRead)) != CAB_STATUS_SUCCESS) {
971 DPRINT("Cannot read from file (%d).\n", (UINT)Status);
972 return CAB_STATUS_INVALID_CAB;
975 File->FileName = (PWCHAR)RtlAllocateHeap(ProcessHeap, 0, MAX_PATH * sizeof(WCHAR));
978 DPRINT("Insufficient memory.\n");
979 return CAB_STATUS_NOMEMORY;
983 Status = ReadString(File->FileName, MAX_PATH);
984 if (Status != CAB_STATUS_SUCCESS)
987 DPRINT("Found file '%S' at uncompressed offset (0x%X). Size (%d bytes) ControlId (0x%X).\n",
988 (PWCHAR)File->FileName,
989 (UINT)File->File.FileOffset,
990 (UINT)File->File.FileSize,
991 (UINT)File->File.FileControlID);
993 return CAB_STATUS_SUCCESS;
998 ReadDataBlocks(PCFFOLDER_NODE FolderNode)
1000 * FUNCTION: Reads all CFDATA blocks for a folder from the cabinet file
1002 * FolderNode = Pointer to CFFOLDER_NODE structure for folder
1004 * Status of operation
1007 ULONG AbsoluteOffset;
1015 DPRINT("Reading data blocks for folder (%d) at absolute offset (0x%X).\n",
1016 FolderNode->Index, FolderNode->Folder.DataOffset);
1018 AbsoluteOffset = FolderNode->Folder.DataOffset;
1019 UncompOffset = FolderNode->UncompOffset;
1021 for (i = 0; i < FolderNode->Folder.DataBlockCount; i++)
1023 Node = NewDataNode(FolderNode);
1026 DPRINT("Insufficient memory.\n");
1027 return CAB_STATUS_NOMEMORY;
1030 /* Seek to data block */
1031 SeekInFile(FileHandle, AbsoluteOffset, NULL, SEEK_BEGIN, &NtStatus);
1032 if (!NT_SUCCESS(NtStatus))
1034 DPRINT("SeekInFile() failed (%x).\n", NtStatus);
1035 return CAB_STATUS_INVALID_CAB;
1038 if ((Status = ReadBlock(&Node->Data, sizeof(CFDATA),
1039 &BytesRead)) != CAB_STATUS_SUCCESS)
1041 DPRINT("Cannot read from file (%d).\n", (UINT)Status);
1042 return CAB_STATUS_INVALID_CAB;
1045 DPRINT("AbsOffset (0x%X) UncompOffset (0x%X) Checksum (0x%X) CompSize (%d) UncompSize (%d).\n",
1046 (UINT)AbsoluteOffset,
1048 (UINT)Node->Data.Checksum,
1049 (UINT)Node->Data.CompSize,
1050 (UINT)Node->Data.UncompSize);
1052 Node->AbsoluteOffset = AbsoluteOffset;
1053 Node->UncompOffset = UncompOffset;
1055 AbsoluteOffset += sizeof(CFDATA) + Node->Data.CompSize;
1056 UncompOffset += Node->Data.UncompSize;
1059 FolderUncompSize = UncompOffset;
1061 return CAB_STATUS_SUCCESS;
1066 ComputeChecksum(PVOID Buffer,
1070 * FUNCTION: Computes checksum for data block
1072 * Buffer = Pointer to data buffer
1073 * Size = Length of data buffer
1074 * Seed = Previously computed checksum
1076 * Checksum of buffer
1079 INT UlongCount; // Number of ULONGs in block
1080 ULONG Checksum; // Checksum accumulator
1084 /* FIXME: Doesn't seem to be correct. EXTRACT.EXE
1085 won't accept checksums computed by this routine */
1087 DPRINT("Checksumming buffer (0x%X) Size (%d)\n", (UINT)Buffer, Size);
1089 UlongCount = Size / 4; // Number of ULONGs
1090 Checksum = Seed; // Init checksum
1091 pb = (PBYTE)Buffer; // Start at front of data block
1093 /* Checksum integral multiple of ULONGs */
1094 while (UlongCount-- > 0)
1096 /* NOTE: Build ULONG in big/little-endian independent manner */
1097 ul = *pb++; // Get low-order byte
1098 ul |= (((ULONG)(*pb++)) << 8); // Add 2nd byte
1099 ul |= (((ULONG)(*pb++)) << 16); // Add 3nd byte
1100 ul |= (((ULONG)(*pb++)) << 24); // Add 4th byte
1102 Checksum ^= ul; // Update checksum
1105 /* Checksum remainder bytes */
1110 ul |= (((ULONG)(*pb++)) << 16); // Add 3rd byte
1112 ul |= (((ULONG)(*pb++)) << 8); // Add 2nd byte
1114 ul |= *pb++; // Get low-order byte
1118 Checksum ^= ul; // Update checksum
1120 /* Return computed checksum */
1128 * FUNCTION: Closes the current cabinet
1130 * Status of operation
1133 PCFFOLDER_NODE PrevNode;
1134 PCFFOLDER_NODE NextNode;
1139 DestroyFolderNodes();
1143 RtlFreeHeap(ProcessHeap, 0, InputBuffer);
1149 RtlFreeHeap(ProcessHeap, 0, OutputBuffer);
1150 OutputBuffer = NULL;
1153 NtClose(FileHandle);
1160 * FUNCTION: Initialize archiver
1163 ZStream.zalloc = MSZipAlloc;
1164 ZStream.zfree = MSZipFree;
1165 ZStream.opaque = (voidpf)0;
1168 wcscpy(DestPath, L"");
1170 FolderListHead = NULL;
1171 FolderListTail = NULL;
1172 FileListHead = NULL;
1173 FileListTail = NULL;
1175 CodecId = CAB_CODEC_RAW;
1176 CodecSelected = TRUE;
1178 OutputBuffer = NULL;
1179 CurrentOBuffer = NULL;
1180 CurrentOBufferSize = 0;
1182 CurrentIBuffer = NULL;
1183 CurrentIBufferSize = 0;
1185 FolderUncompSize = 0;
1186 BytesLeftInBlock = 0;
1187 CabinetReserved = 0;
1191 CurrentFolderNode = NULL;
1192 CurrentDataNode = NULL;
1193 CabinetReservedArea = NULL;
1194 RestartSearch = FALSE;
1202 * FUNCTION: Cleanup archiver
1210 CabinetNormalizePath(PWCHAR Path,
1213 * FUNCTION: Normalizes a path
1215 * Path = Pointer to string with pathname
1216 * Length = Number of characters in Path
1218 * TRUE if there was enough room in Path, or FALSE
1224 if ((n = wcslen(Path)) &&
1225 (Path[n - 1] != L'\\') &&
1226 (OK = ((n + 1) < Length)))
1236 CabinetGetCabinetName()
1238 * FUNCTION: Returns pointer to cabinet file name
1240 * Pointer to string with name of cabinet
1248 CabinetSetCabinetName(PWCHAR FileName)
1250 * FUNCTION: Sets cabinet file name
1252 * FileName = Pointer to string with name of cabinet
1255 wcscpy(CabinetName, FileName);
1260 CabinetSetDestinationPath(PWCHAR DestinationPath)
1262 * FUNCTION: Sets destination path
1264 * DestinationPath = Pointer to string with name of destination path
1267 wcscpy(DestPath, DestinationPath);
1268 if (wcslen(DestPath) > 0)
1269 CabinetNormalizePath(DestPath, MAX_PATH);
1274 CabinetGetDestinationPath()
1276 * FUNCTION: Returns destination path
1278 * Pointer to string with name of destination path
1288 * FUNCTION: Opens a cabinet file
1290 * Status of operation
1293 WCHAR CabinetFileName[256];
1294 PCFFOLDER_NODE FolderNode;
1300 OBJECT_ATTRIBUTES ObjectAttributes;
1301 IO_STATUS_BLOCK IoStatusBlock;
1302 UNICODE_STRING FileName;
1307 OutputBuffer = RtlAllocateHeap(ProcessHeap, 0, CAB_BLOCKSIZE + 12); // This should be enough
1309 return CAB_STATUS_NOMEMORY;
1311 RtlInitUnicodeString(&FileName,
1314 InitializeObjectAttributes(&ObjectAttributes,
1316 OBJ_CASE_INSENSITIVE,
1320 NtStatus = NtOpenFile(&FileHandle,
1325 FILE_SYNCHRONOUS_IO_ALERT);
1326 if (!NT_SUCCESS(NtStatus))
1328 DPRINT("Cannot open file (%S) (%x).\n", CabinetName, NtStatus);
1329 return CAB_STATUS_CANNOT_OPEN;
1334 /* Load CAB header */
1335 if ((Status = ReadBlock(&CABHeader, sizeof(CFHEADER), &BytesRead)) != CAB_STATUS_SUCCESS)
1337 DPRINT("Cannot read from file (%d).\n", (UINT)Status);
1338 return CAB_STATUS_INVALID_CAB;
1342 if ((BytesRead != sizeof(CFHEADER)) ||
1343 (CABHeader.Signature != CAB_SIGNATURE ) ||
1344 (CABHeader.Version != CAB_VERSION ) ||
1345 (CABHeader.FolderCount == 0 ) ||
1346 (CABHeader.FileCount == 0 ) ||
1347 (CABHeader.FileTableOffset < sizeof(CFHEADER))) {
1349 DPRINT("File has invalid header.\n");
1350 return CAB_STATUS_INVALID_CAB;
1355 /* Read/skip any reserved bytes */
1356 if (CABHeader.Flags & CAB_FLAG_RESERVE)
1358 if ((Status = ReadBlock(&Size, sizeof(ULONG), &BytesRead)) != CAB_STATUS_SUCCESS)
1360 DPRINT("Cannot read from file (%d).\n", (UINT)Status);
1361 return CAB_STATUS_INVALID_CAB;
1363 CabinetReserved = Size & 0xFFFF;
1364 FolderReserved = (Size >> 16) & 0xFF;
1365 DataReserved = (Size >> 24) & 0xFF;
1367 if (CabinetReserved > 0)
1369 CabinetReservedArea = RtlAllocateHeap(ProcessHeap, 0, CabinetReserved);
1370 if (!CabinetReservedArea)
1372 return CAB_STATUS_NOMEMORY;
1375 if ((Status = ReadBlock(CabinetReservedArea, CabinetReserved, &BytesRead)) != CAB_STATUS_SUCCESS)
1377 DPRINT("Cannot read from file (%d).\n", (UINT)Status);
1378 return CAB_STATUS_INVALID_CAB;
1382 SeekInFile(FileHandle, CabinetReserved, NULL, SEEK_CURRENT, &NtStatus);
1383 if (!NT_SUCCESS(NtStatus))
1385 DPRINT("SeekInFile() failed (%x).\n", NtStatus);
1386 return CAB_STATUS_INVALID_CAB;
1391 if ((CABHeader.Flags & CAB_FLAG_HASPREV) > 0)
1393 /* Read name of previous cabinet */
1394 Status = ReadString(CabinetFileName, 256);
1395 if (Status != CAB_STATUS_SUCCESS)
1398 /* The previous cabinet file is in the same directory as the current */
1399 wcscpy(CabinetPrev, CabinetName);
1400 RemoveFileName(CabinetPrev);
1401 CabinetNormalizePath(CabinetPrev, 256);
1402 wcscat(CabinetPrev, CabinetFileName);
1404 /* Read label of previous disk */
1405 Status = ReadString(DiskPrev, 256);
1406 if (Status != CAB_STATUS_SUCCESS)
1411 wcscpy(CabinetPrev, L"");
1412 wcscpy(DiskPrev, L"");
1415 if ((CABHeader.Flags & CAB_FLAG_HASNEXT) > 0)
1417 /* Read name of next cabinet */
1418 Status = ReadString(CabinetFileName, 256);
1419 if (Status != CAB_STATUS_SUCCESS)
1422 /* The next cabinet file is in the same directory as the previous */
1423 wcscpy(CabinetNext, CabinetName);
1424 RemoveFileName(CabinetNext);
1425 CabinetNormalizePath(CabinetNext, 256);
1426 wcscat(CabinetNext, CabinetFileName);
1428 /* Read label of next disk */
1429 Status = ReadString(DiskNext, 256);
1430 if (Status != CAB_STATUS_SUCCESS)
1435 wcscpy(CabinetNext, L"");
1436 wcscpy(DiskNext, L"");
1439 /* Read all folders */
1440 for (Index = 0; Index < CABHeader.FolderCount; Index++)
1442 FolderNode = NewFolderNode();
1445 DPRINT("Insufficient resources.\n");
1446 return CAB_STATUS_NOMEMORY;
1450 FolderNode->UncompOffset = FolderUncompSize;
1452 FolderNode->Index = Index;
1454 if ((Status = ReadBlock(&FolderNode->Folder,
1455 sizeof(CFFOLDER), &BytesRead)) != CAB_STATUS_SUCCESS)
1457 DPRINT("Cannot read from file (%d).\n", (UINT)Status);
1458 return CAB_STATUS_INVALID_CAB;
1462 /* Read file entries */
1463 Status = ReadFileTable();
1464 if (Status != CAB_STATUS_SUCCESS)
1466 DPRINT("ReadFileTable() failed (%d).\n", (UINT)Status);
1470 /* Read data blocks for all folders */
1471 FolderNode = FolderListHead;
1472 while (FolderNode != NULL)
1474 Status = ReadDataBlocks(FolderNode);
1475 if (Status != CAB_STATUS_SUCCESS)
1477 DPRINT("ReadDataBlocks() failed (%d).\n", (UINT)Status);
1480 FolderNode = FolderNode->Next;
1483 return CAB_STATUS_SUCCESS;
1490 * FUNCTION: Closes the cabinet file
1497 if (CabinetReservedArea != NULL)
1499 RtlFreeHeap(ProcessHeap, 0, CabinetReservedArea);
1500 CabinetReservedArea = NULL;
1509 CabinetFindFirst(PWCHAR FileName,
1512 * FUNCTION: Finds the first file in the cabinet that matches a search criteria
1514 * FileName = Pointer to search criteria
1515 * Search = Pointer to search structure
1517 * Status of operation
1520 RestartSearch = FALSE;
1521 wcsncpy(Search->Search, FileName, MAX_PATH);
1522 Search->Next = FileListHead;
1523 return CabinetFindNext(Search);
1528 CabinetFindNext(PCAB_SEARCH Search)
1530 * FUNCTION: Finds next file in the cabinet that matches a search criteria
1532 * Search = Pointer to search structure
1534 * Status of operation
1541 Search->Next = FileListHead;
1543 /* Skip split files already extracted */
1544 while ((Search->Next) &&
1545 (Search->Next->File.FileControlID > CAB_FILE_MAX_FOLDER) &&
1546 (Search->Next->File.FileOffset <= LastFileOffset))
1548 DPRINT("Skipping file (%s) FileOffset (0x%X) LastFileOffset (0x%X).\n",
1549 Search->Next->FileName, Search->Next->File.FileOffset, LastFileOffset);
1550 Search->Next = Search->Next->Next;
1553 RestartSearch = FALSE;
1556 /* FIXME: Check search criteria */
1560 if (wcslen(DiskNext) > 0)
1564 CabinetSetCabinetName(CabinetNext);
1566 if (DiskChangeHandler != NULL)
1568 DiskChangeHandler(CabinetNext, DiskNext);
1571 Status = CabinetOpen();
1572 if (Status != CAB_STATUS_SUCCESS)
1575 Search->Next = FileListHead;
1577 return CAB_STATUS_NOFILE;
1581 return CAB_STATUS_NOFILE;
1585 Search->File = &Search->Next->File;
1586 Search->FileName = Search->Next->FileName;
1587 Search->Next = Search->Next->Next;
1588 return CAB_STATUS_SUCCESS;
1593 CabinetExtractFile(PWCHAR FileName)
1595 * FUNCTION: Extracts a file from the cabinet
1597 * FileName = Pointer to buffer with name of file
1599 * Status of operation
1609 ULONG TotalBytesRead;
1610 ULONG CurrentOffset;
1612 PUCHAR CurrentBuffer;
1619 WCHAR DestName[MAX_PATH];
1620 WCHAR TempName[MAX_PATH];
1622 UNICODE_STRING UnicodeString;
1623 IO_STATUS_BLOCK IoStatusBlock;
1624 OBJECT_ATTRIBUTES ObjectAttributes;
1625 FILE_BASIC_INFORMATION FileBasic;
1627 Status = LocateFile(FileName, &File);
1628 if (Status != CAB_STATUS_SUCCESS)
1630 DPRINT("Cannot locate file (%d).\n", (UINT)Status);
1634 LastFileOffset = File->File.FileOffset;
1636 switch (CurrentFolderNode->Folder.CompressionType & CAB_COMP_MASK)
1639 CabinetSelectCodec(CAB_CODEC_RAW);
1641 case CAB_COMP_MSZIP:
1642 CabinetSelectCodec(CAB_CODEC_MSZIP);
1645 return CAB_STATUS_UNSUPPCOMP;
1648 DPRINT("Extracting file at uncompressed offset (0x%X) Size (%d bytes) AO (0x%X) UO (0x%X).\n",
1649 (UINT)File->File.FileOffset,
1650 (UINT)File->File.FileSize,
1651 (UINT)File->DataBlock->AbsoluteOffset,
1652 (UINT)File->DataBlock->UncompOffset);
1654 wcscpy(DestName, DestPath);
1655 wcscat(DestName, FileName);
1657 /* Create destination file, fail if it already exists */
1658 RtlInitUnicodeString(&UnicodeString,
1661 InitializeObjectAttributes(&ObjectAttributes,
1663 OBJ_CASE_INSENSITIVE,
1667 NtStatus = NtCreateFile(&DestFile,
1672 FILE_ATTRIBUTE_NORMAL,
1675 FILE_SYNCHRONOUS_IO_ALERT,
1678 if (!NT_SUCCESS(NtStatus))
1680 DPRINT("NtCreateFile() failed (%S) (%x).\n", DestName, NtStatus);
1682 /* If file exists, ask to overwrite file */
1683 if (OverwriteHandler == NULL || OverwriteHandler(&File->File, FileName))
1685 /* Create destination file, overwrite if it already exists */
1686 NtStatus = NtCreateFile(&DestFile,
1691 FILE_ATTRIBUTE_NORMAL,
1694 FILE_SYNCHRONOUS_IO_ALERT,
1697 if (!NT_SUCCESS(NtStatus))
1699 DPRINT("NtCreateFile() failed 2 (%S) (%x).\n", DestName, NtStatus);
1700 return CAB_STATUS_CANNOT_CREATE;
1705 DPRINT("File (%S) exists.\n", DestName);
1706 return CAB_STATUS_FILE_EXISTS;
1710 if (!ConvertDosDateTimeToFileTime(File->File.FileDate, File->File.FileTime, &FileTime))
1713 DPRINT("DosDateTimeToFileTime() failed.\n");
1714 return CAB_STATUS_CANNOT_WRITE;
1717 NtStatus = NtQueryInformationFile(DestFile,
1720 sizeof(FILE_BASIC_INFORMATION),
1721 FileBasicInformation);
1722 if (!NT_SUCCESS(Status))
1724 DPRINT("NtQueryInformationFile() failed (%x).\n", NtStatus);
1728 memcpy(&FileBasic.LastAccessTime, &FileTime, sizeof(FILETIME));
1730 NtStatus = NtSetInformationFile(DestFile,
1733 sizeof(FILE_BASIC_INFORMATION),
1734 FileBasicInformation);
1735 if (!NT_SUCCESS(NtStatus))
1737 DPRINT("NtSetInformationFile() failed (%x).\n", NtStatus);
1741 SetAttributesOnFile(File, DestFile);
1743 Buffer = RtlAllocateHeap(ProcessHeap, 0, CAB_BLOCKSIZE + 12); // This should be enough
1747 DPRINT("Insufficient memory.\n");
1748 return CAB_STATUS_NOMEMORY;
1751 /* Call extract event handler */
1752 if (ExtractHandler != NULL)
1754 ExtractHandler(&File->File, FileName);
1757 /* Search to start of file */
1758 Offset = SeekInFile(FileHandle,
1759 File->DataBlock->AbsoluteOffset,
1763 if (!NT_SUCCESS(NtStatus))
1765 DPRINT("SeekInFile() failed (%x).\n", NtStatus);
1766 return CAB_STATUS_INVALID_CAB;
1769 Size = File->File.FileSize;
1770 Offset = File->File.FileOffset;
1771 CurrentOffset = File->DataBlock->UncompOffset;
1775 ReuseBlock = (CurrentDataNode == File->DataBlock);
1780 DPRINT("CO (0x%X) ReuseBlock (%d) Offset (0x%X) Size (%d) BytesLeftInBlock (%d)\n",
1781 File->DataBlock->UncompOffset, (UINT)ReuseBlock, Offset, Size,
1784 if (/*(CurrentDataNode != File->DataBlock) &&*/ (!ReuseBlock) || (BytesLeftInBlock <= 0))
1786 DPRINT("Filling buffer. ReuseBlock (%d)\n", (UINT)ReuseBlock);
1788 CurrentBuffer = Buffer;
1792 DPRINT("Size (%d bytes).\n", Size);
1794 if (((Status = ReadBlock(&CFData, sizeof(CFDATA), &BytesRead)) !=
1795 CAB_STATUS_SUCCESS) || (BytesRead != sizeof(CFDATA)))
1798 RtlFreeHeap(ProcessHeap, 0, Buffer);
1799 DPRINT("Cannot read from file (%d).\n", (UINT)Status);
1800 return CAB_STATUS_INVALID_CAB;
1803 DPRINT("Data block: Checksum (0x%X) CompSize (%d bytes) UncompSize (%d bytes) Offset (0x%X).\n",
1804 (UINT)CFData.Checksum,
1805 (UINT)CFData.CompSize,
1806 (UINT)CFData.UncompSize,
1807 (UINT)SeekInFile(FileHandle, 0, NULL, SEEK_CURRENT, &NtStatus));
1809 //ASSERT(CFData.CompSize <= CAB_BLOCKSIZE + 12);
1811 BytesToRead = CFData.CompSize;
1813 DPRINT("Read: (0x%X,0x%X).\n",
1814 CurrentBuffer, Buffer);
1816 if (((Status = ReadBlock(CurrentBuffer, BytesToRead, &BytesRead)) !=
1817 CAB_STATUS_SUCCESS) || (BytesToRead != BytesRead))
1820 RtlFreeHeap(ProcessHeap, 0, Buffer);
1821 DPRINT("Cannot read from file (%d).\n", (UINT)Status);
1822 return CAB_STATUS_INVALID_CAB;
1825 /* FIXME: Does not work with files generated by makecab.exe */
1827 if (CFData.Checksum != 0)
1829 ULONG Checksum = ComputeChecksum(CurrentBuffer, BytesRead, 0);
1830 if (Checksum != CFData.Checksum)
1833 RtlFreeHeap(ProcessHeap, 0, Buffer);
1834 DPRINT("Bad checksum (is 0x%X, should be 0x%X).\n",
1835 Checksum, CFData.Checksum);
1836 return CAB_STATUS_INVALID_CAB;
1840 TotalBytesRead += BytesRead;
1842 CurrentBuffer += BytesRead;
1844 if (CFData.UncompSize == 0)
1846 if (wcslen(DiskNext) == 0)
1847 return CAB_STATUS_NOFILE;
1849 /* CloseCabinet() will destroy all file entries so in case
1850 FileName refers to the FileName field of a CFFOLDER_NODE
1851 structure, we have to save a copy of the filename */
1852 wcscpy(TempName, FileName);
1856 CabinetSetCabinetName(CabinetNext);
1858 if (DiskChangeHandler != NULL)
1860 DiskChangeHandler(CabinetNext, DiskNext);
1863 Status = CabinetOpen();
1864 if (Status != CAB_STATUS_SUCCESS)
1867 /* The first data block of the file will not be
1868 found as it is located in the previous file */
1869 Status = LocateFile(TempName, &File);
1870 if (Status == CAB_STATUS_NOFILE)
1872 DPRINT("Cannot locate file (%d).\n", (UINT)Status);
1876 /* The file is continued in the first data block in the folder */
1877 File->DataBlock = CurrentFolderNode->DataListHead;
1879 /* Search to start of file */
1880 SeekInFile(FileHandle,
1881 File->DataBlock->AbsoluteOffset,
1885 if (!NT_SUCCESS(NtStatus))
1887 DPRINT("SeekInFile() failed (%x).\n", NtStatus);
1888 return CAB_STATUS_INVALID_CAB;
1891 DPRINT("Continuing extraction of file at uncompressed offset (0x%X) Size (%d bytes) AO (0x%X) UO (0x%X).\n",
1892 (UINT)File->File.FileOffset,
1893 (UINT)File->File.FileSize,
1894 (UINT)File->DataBlock->AbsoluteOffset,
1895 (UINT)File->DataBlock->UncompOffset);
1897 CurrentDataNode = File->DataBlock;
1900 RestartSearch = TRUE;
1902 } while (CFData.UncompSize == 0);
1904 DPRINT("TotalBytesRead (%d).\n", TotalBytesRead);
1906 Status = CodecUncompress(OutputBuffer, Buffer, TotalBytesRead, &BytesToWrite);
1907 if (Status != CS_SUCCESS)
1910 RtlFreeHeap(ProcessHeap, 0, Buffer);
1911 DPRINT("Cannot uncompress block.\n");
1912 if (Status == CS_NOMEMORY)
1913 return CAB_STATUS_NOMEMORY;
1914 return CAB_STATUS_INVALID_CAB;
1917 if (BytesToWrite != CFData.UncompSize)
1919 DPRINT("BytesToWrite (%d) != CFData.UncompSize (%d)\n",
1920 BytesToWrite, CFData.UncompSize);
1921 return CAB_STATUS_INVALID_CAB;
1924 BytesLeftInBlock = BytesToWrite;
1928 DPRINT("Using same buffer. ReuseBlock (%d)\n", (UINT)ReuseBlock);
1930 BytesToWrite = BytesLeftInBlock;
1932 DPRINT("Seeking to absolute offset 0x%X.\n",
1933 CurrentDataNode->AbsoluteOffset + sizeof(CFDATA) +
1934 CurrentDataNode->Data.CompSize);
1936 if (((Status = ReadBlock(&CFData, sizeof(CFDATA), &BytesRead)) !=
1937 CAB_STATUS_SUCCESS) || (BytesRead != sizeof(CFDATA)))
1940 RtlFreeHeap(ProcessHeap, 0, Buffer);
1941 DPRINT("Cannot read from file (%d).\n", (UINT)Status);
1942 return CAB_STATUS_INVALID_CAB;
1945 DPRINT("CFData.CompSize 0x%X CFData.UncompSize 0x%X.\n",
1946 CFData.CompSize, CFData.UncompSize);
1948 /* Go to next data block */
1949 SeekInFile(FileHandle,
1950 CurrentDataNode->AbsoluteOffset + sizeof(CFDATA) +
1951 CurrentDataNode->Data.CompSize,
1955 if (!NT_SUCCESS(NtStatus))
1957 DPRINT("SeekInFile() failed (%x).\n", NtStatus);
1958 return CAB_STATUS_INVALID_CAB;
1965 BytesSkipped = (Offset - CurrentOffset);
1969 BytesToWrite -= BytesSkipped;
1971 if (Size < BytesToWrite)
1972 BytesToWrite = Size;
1974 DPRINT("Offset (0x%X) CurrentOffset (0x%X) ToWrite (%d) Skipped (%d)(%d) Size (%d).\n",
1976 (UINT)CurrentOffset,
1978 (UINT)BytesSkipped, (UINT)Skip,
1981 // if (!WriteFile(DestFile, (PVOID)((ULONG)OutputBuffer + BytesSkipped),
1982 // BytesToWrite, &BytesWritten, NULL) ||
1983 // (BytesToWrite != BytesWritten))
1985 NtStatus = NtWriteFile(DestFile,
1990 (PVOID)((ULONG)OutputBuffer + BytesSkipped),
1994 BytesWritten = BytesToWrite;
1995 if (!NT_SUCCESS(NtStatus))
1997 DPRINT("Status 0x%X.\n", NtStatus);
2000 RtlFreeHeap(ProcessHeap, 0, Buffer);
2001 DPRINT("Cannot write to file.\n");
2002 return CAB_STATUS_CANNOT_WRITE;
2004 Size -= BytesToWrite;
2006 CurrentOffset += BytesToWrite;
2008 /* Don't skip any more bytes */
2015 RtlFreeHeap(ProcessHeap, 0, Buffer);
2017 return CAB_STATUS_SUCCESS;
2022 CabinetSelectCodec(ULONG Id)
2024 * FUNCTION: Selects codec engine to use
2026 * Id = Codec identifier
2034 CodecSelected = FALSE;
2040 CodecUncompress = RawCodecUncompress;
2042 case CAB_CODEC_MSZIP:
2043 CodecUncompress = MSZipCodecUncompress;
2050 CodecSelected = TRUE;
2055 CabinetSetEventHandlers(PCABINET_OVERWRITE Overwrite,
2056 PCABINET_EXTRACT Extract,
2057 PCABINET_DISK_CHANGE DiskChange)
2059 * FUNCTION: Set event handlers
2061 * Overwrite = Handler called when a file is to be overwritten
2062 * Extract = Handler called when a file is to be extracted
2063 * DiskChange = Handler called when changing the disk
2066 OverwriteHandler = Overwrite;
2067 ExtractHandler = Extract;
2068 DiskChangeHandler = DiskChange;
2073 CabinetGetCabinetReservedArea(PULONG Size)
2075 * FUNCTION: Get pointer to cabinet reserved area. NULL if none
2078 if (CabinetReservedArea != NULL)
2082 *Size = CabinetReserved;
2084 return CabinetReservedArea;