_Inside Windows Cabinet Files_ by Sven B. Schreiber Listing One // ================================================================= // CAB FILE LAYOUT // ================================================================= /* (1) CAB_HEADER structure (2) Reserved area, if CAB_HEADER.flags & CAB_FLAG_RESERVE (3) Previous cabinet name, if CAB_HEADER.flags & CAB_FLAG_HASPREV (4) Previous disk name, if CAB_HEADER.flags & CAB_FLAG_HASPREV (5) Next cabinet name, if CAB_HEADER.flags & CAB_FLAG_HASNEXT (6) Next disk name, if CAB_HEADER.flags & CAB_FLAG_HASNEXT (7) CAB_FOLDER structures (n = CAB_HEADER.cFolders) (8) CAB_ENTRY structures / file names (n = CAB_HEADER.cFiles) (9) File data (offset = CAB_FOLDER.coffCabStart) */ // ================================================================= // MACROS // ================================================================= #define SWAPWORD(x) ((WORD) (((x) << 8) | ((x) >> 8))) #define SWAPDWORD(x) ((SWAPWORD ((WORD) (x)) << 16) | \ (SWAPWORD ((WORD) ((x) >> 16)))) // ================================================================= // CONSTANTS // ================================================================= #define CAB_SIGNATURE SWAPDWORD ('MSCF') #define CAB_VERSION 0x0103 #define CAB_FLAG_HASPREV 0x0001 #define CAB_FLAG_HASNEXT 0x0002 #define CAB_FLAG_RESERVE 0x0004 #define CAB_ATTRIB_READONLY 0x0001 #define CAB_ATTRIB_HIDDEN 0x0002 #define CAB_ATTRIB_SYSTEM 0x0004 #define CAB_ATTRIB_VOLUME 0x0008 #define CAB_ATTRIB_DIRECTORY 0x0010 #define CAB_ATTRIB_ARCHIVE 0x0020 #define CAB_FILE_FIRST 0x0000 #define CAB_FILE_NEXT 0x0001 #define CAB_FILE_SPLIT 0xFFFE #define CAB_FILE_CONTINUED 0xFFFD #define CAB_NOTIFY_OK 1 #define CAB_NOTIFY_ERROR 0 #define CAB_NOTIFY_SKIP 0 #define CAB_NOTIFY_ABORT (-1) // ================================================================= // CABINET STRUCTURES // ================================================================= typedef struct _CAB_HEADER { DWORD sig; // file signature 'MSCF' (CAB_SIGNATURE) DWORD csumHeader; // header checksum (0 if not used) DWORD cbCabinet; // cabinet file size DWORD csumFolders; // folders checksum (0 if not used) DWORD coffFiles; // offset of first CAB_ENTRY DWORD csumFiles; // files checksum (0 if not used) WORD version; // cabinet version (CAB_VERSION) WORD cFolders; // number of folders WORD cFiles; // number of files WORD flags; // cabinet flags (CAB_FLAG_*) WORD setID; // cabinet set id WORD iCabinet; // zero-based cabinet number } CAB_HEADER, *PCAB_HEADER; #define CAB_HEADER_ sizeof (CAB_HEADER) // ----------------------------------------------------------------- typedef struct _CAB_FOLDER { DWORD coffCabStart; // offset of folder data WORD cCFData; // ??? WORD typeCompress; // compression type (tcomp* in FDI.h) } CAB_FOLDER, *PCAB_FOLDER; #define CAB_FOLDER_ sizeof (CAB_FOLDER) // ----------------------------------------------------------------- typedef struct _CAB_ENTRY { DWORD cbFile; // uncompressed file size DWORD uoffFolderStart; // file offset after decompression WORD iFolder; // file control id (CAB_FILE_*) WORD date; // file date stamp, as used by DOS WORD time; // file time stamp, as used by DOS WORD attribs; // file attributes (CAB_ATTRIB_*) } CAB_ENTRY, *PCAB_ENTRY; #define CAB_ENTRY_ sizeof (CAB_ENTRY) Listing Two // ================================================================= // FILE EXTRACTION CALLBACK // ================================================================= int DIAMONDAPI FDIExtract (FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin) { FILETIME ft, lft; BYTE abFile [MAX_PATH]; int hf, iResult; switch (fdint) { case fdintCOPY_FILE: if (lstrcmpi (pfdin->psz1, ((PEXTRACT_FILE) pfdin->pv)->pbEntry)) { iResult = CAB_NOTIFY_SKIP; } else { hf = FDIOpen (((PEXTRACT_FILE) pfdin->pv)->pbFile, _O_RDWR | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE); if (hf != -1) { iResult = hf; } else { printfMessage (((PEXTRACT_FILE) pfdin->pv)->hWnd, MB_ICONERROR | MB_OK, "CabLib Error", "Unable to create file \"%s\"", ((PEXTRACT_FILE) pfdin->pv)->pbFile); iResult = CAB_NOTIFY_ABORT; } } break; case fdintNEXT_CABINET: if (lstrlen (pfdin->psz3) + lstrlen (pfdin->psz1) < MAX_PATH) { lstrcpy (abFile, pfdin->psz3); lstrcat (abFile, pfdin->psz1); hf = FDIOpen (abFile, _O_RDONLY, 0); } else { hf = -1; } if (hf != -1) { FDIClose (hf); iResult = CAB_NOTIFY_OK; } else { printfMessage (((PEXTRACT_FILE) pfdin->pv)->hWnd, MB_ICONERROR | MB_OK, "CabLib Error", "Unable to open file \"%s%s\"", pfdin->psz3, pfdin->psz1); iResult = CAB_NOTIFY_ABORT; } break; case fdintCLOSE_FILE_INFO: DosDateTimeToFileTime (pfdin->date, pfdin->time, &lft); LocalFileTimeToFileTime (&lft, &ft); SetFileTime ((HANDLE) pfdin->hf, &ft, &ft, &ft); if (FDIClose (pfdin->hf) == -1) { printfMessage (((PEXTRACT_FILE) pfdin->pv)->hWnd, MB_ICONERROR | MB_OK, "CabLib Error", "Unable to close file \"%s\"", ((PEXTRACT_FILE) pfdin->pv)->pbFile); } iResult = CAB_NOTIFY_OK; break; default: iResult = CAB_NOTIFY_OK; break; } return iResult; } Example 1: HFDI FAR DIAMONDAPI FDICreate (PFNALLOC pfnalloc, PFNFREE pfnfree, PFNOPEN pfnopen, PFNREAD pfnread, PFNWRITE pfnwrite, PFNCLOSE pfnclose, PFNSEEK pfnseek, int cpuType, PERF perf); Example 2: BOOL FAR DIAMONDAPI FDICopy (HFDI hfdi, char FAR *pszCabinet, char FAR *pszCabPath, int flags, PFNFDINOTIFY pfnfdin, PFNFDIDECRYPT pfnfdid, void FAR *pvUser); 4