home *** CD-ROM | disk | FTP | other *** search
/ Chip 2003 January / ChipCD_1.03.iso / zkuste / delphi / kompon / d56 / CABD.ZIP / Code / CabIntf.pas next >
Pascal/Delphi Source File  |  2002-08-27  |  67KB  |  1,681 lines

  1. unit CabIntf;
  2.  
  3. (*
  4.  *  Copyright (c) Ravil Batyrshin, 2001-2002
  5.  *  All Rights Reserved
  6.  *  Version 1.20
  7.  *  Aravil Software
  8.  *  web site: aravilsoft.tripod.com
  9.  *  e-mail: aravilsoft@bigfoot.com, wizeman@mail.ru
  10.  *)
  11.  
  12. {$IFDEF VER130}
  13.     {$ALIGN ON}
  14. {$ELSE}
  15.     {$WARN SYMBOL_PLATFORM OFF}
  16.     {$ALIGN 4}
  17. {$ENDIF}
  18. {$MINENUMSIZE 4}
  19. {$RANGECHECKS OFF}
  20. {$BOOLEVAL OFF}
  21.  
  22. //{$DEFINE CABINET_STATIC_LINK}
  23. {$IFDEF CABINET_STATIC_LINK}
  24.     {$WEAKPACKAGEUNIT ON}
  25. {$ENDIF}
  26.  
  27. interface
  28.  
  29. uses
  30.     Windows, SysUtils;
  31.  
  32. type
  33.     WIN_BOOL = Integer;
  34.  
  35. const
  36.     WIN_TRUE = 1;
  37.     WIN_FALSE = 0;
  38.  
  39. type
  40.     UINT1 = Byte;
  41.     UINT2 = Word;
  42.     UINT4 = Longword;
  43.  
  44. (*
  45.  *  FCI.H -- File Compression Interface
  46.  *
  47.  *  Copyright (C) Microsoft Corporation 1993-1997
  48.  *  All Rights Reserved.
  49.  *)
  50.  
  51. type
  52.     PVoid = Pointer;
  53.     USHORT = Word;
  54.     PUSHORT = ^USHORT;
  55.  
  56.     TCHECKSUM = ULONG; { csum }
  57.  
  58.     TUOFF = ULONG; { uoff - uncompressed offset }
  59.     TCOFF = ULONG; { coff - cabinet file offset }
  60.  
  61. (***    ERF - Error structure
  62.  *
  63.  *  This structure returns error information from FCI/FDI.  The caller should
  64.  *  not modify this structure.
  65.  *)
  66.  
  67. type
  68.     TERF = record
  69.         erfOper: Integer;        // FCI/FDI error code -- see FDIERROR_XXX
  70.                                                 //  and FCIERR_XXX equates for details.
  71.         erfType: Integer;        // Optional error value filled in by FCI/FDI.
  72.                                                 // For FCI, this is usually the C run-time
  73.                                                 // *errno* value.
  74.         fError: WIN_BOOL;      // TRUE => error present
  75.     end; { erf }
  76.  
  77.     PERF = ^TERF; { perf }
  78.  
  79. const
  80.     CB_MAX_CHUNK =             32768;
  81.     CB_MAX_DISK =          $7fffffff; //Fixed!
  82.     CB_MAX_FILENAME =            256;
  83.     CB_MAX_CABINET_NAME =        256;
  84.     CB_MAX_CAB_PATH =            256;
  85.     CB_MAX_DISK_NAME =           256;
  86.  
  87. (***    tcompXXX - Compression types
  88.  *
  89.  *  These are passed to FCIAddFile(), and are also stored in the CFFOLDER
  90.  *  structures in cabinet files.
  91.  *
  92.  *  NOTE: We reserve bits for the TYPE, QUANTUM_LEVEL, and QUANTUM_MEM
  93.  *        to provide room for future expansion.  Since this value is stored
  94.  *        in the CFDATA records in the cabinet file, we don't want to
  95.  *        have to change the format for existing compression configurations
  96.  *        if we add new ones in the future.  This will allows us to read
  97.  *        old cabinet files in the future.
  98.  *)
  99.  
  100. type
  101.     TCOMP = USHORT; { tcomp }
  102.  
  103. const
  104.     tcompMASK_TYPE =          $000F;  // Mask for compression type
  105.     tcompTYPE_NONE =          $0000;  // No compression
  106.     tcompTYPE_MSZIP =         $0001;  // MSZIP
  107.     tcompTYPE_QUANTUM =       $0002;  // Quantum
  108.     tcompTYPE_LZX =           $0003;  // LZX
  109.     tcompBAD =                $000F;  // Unspecified compression type
  110.  
  111.     tcompMASK_LZX_WINDOW =    $1F00;  // Mask for LZX Compression Memory
  112.     tcompLZX_WINDOW_LO =      $0F00;  // Lowest LZX Memory (15)
  113.     tcompLZX_WINDOW_HI =      $1500;  // Highest LZX Memory (21)
  114.     tcompSHIFT_LZX_WINDOW =       8;  // Amount to shift over to get int
  115.  
  116.     tcompMASK_QUANTUM_LEVEL = $00F0;  // Mask for Quantum Compression Level
  117.     tcompQUANTUM_LEVEL_LO =   $0010;  // Lowest Quantum Level (1)
  118.     tcompQUANTUM_LEVEL_HI =   $0070;  // Highest Quantum Level (7)
  119.     tcompSHIFT_QUANTUM_LEVEL =    4;  // Amount to shift over to get int
  120.  
  121.     tcompMASK_QUANTUM_MEM =   $1F00;  // Mask for Quantum Compression Memory
  122.     tcompQUANTUM_MEM_LO =     $0A00;  // Lowest Quantum Memory (10)
  123.     tcompQUANTUM_MEM_HI =     $1500;  // Highest Quantum Memory (21)
  124.     tcompSHIFT_QUANTUM_MEM =      8;  // Amount to shift over to get int
  125.  
  126.     tcompMASK_RESERVED =      $E000;  // Reserved bits (high 3 bits)
  127.  
  128. (***    FCIERROR - Error codes returned in erf.erfOper field
  129.  *
  130.  *)
  131.  
  132. type
  133.     TFCIERROR = (
  134.         FCIERR_NONE,                // No error
  135.         FCIERR_OPEN_SRC,            // Failure opening file to be stored in cabinet
  136.                                                                 //  erf.erfTyp has C run-time *errno* value
  137.         FCIERR_READ_SRC,            // Failure reading file to be stored in cabinet
  138.                                                                 //  erf.erfTyp has C run-time *errno* value
  139.         FCIERR_ALLOC_FAIL,          // Out of memory in FCI
  140.         FCIERR_TEMP_FILE,           // Could not create a temporary file
  141.                                                                 //  erf.erfTyp has C run-time *errno* value
  142.         FCIERR_BAD_COMPR_TYPE,      // Unknown compression type
  143.         FCIERR_CAB_FILE,            // Could not create cabinet file
  144.                                                                 //  erf.erfTyp has C run-time *errno* value
  145.         FCIERR_USER_ABORT,          // Client requested abort
  146.         FCIERR_MCI_FAIL            // Failure compressing data
  147.     );
  148.  
  149. (*
  150.  * FAT file attribute flag used by FCI/FDI to indicate that
  151.  * the filename in the CAB is a UTF string
  152.  *)
  153.  
  154. const
  155.     _A_NAME_IS_UTF = $80;
  156.  
  157. (*
  158.  * FAT file attribute flag used by FCI/FDI to indicate that
  159.  * the file should be executed after extraction
  160.  *)
  161.  
  162. const
  163.     _A_EXEC = $40;
  164.  
  165. (***    HFCI - Handle to an FCI Context
  166.  *
  167.  *)
  168.  
  169. type
  170.     HFCI = type PVoid;
  171.  
  172. (***    CCAB - Current Cabinet
  173.  *
  174.  *  This structure is used for passing in the cabinet parameters to FCI,
  175.  *  and is passed back on certain FCI callbacks to provide cabinet
  176.  *  information to the client.
  177.  *)
  178.  
  179. type
  180.     TCCAB = record
  181.         // longs first
  182.         cb: ULONG;                  // size available for cabinet on this media
  183.         cbFolderThresh: ULONG;      // Thresshold for forcing a new Folder
  184.         // then ints
  185.         cbReserveCFHeader: UINT;    // Space to reserve in CFHEADER
  186.         cbReserveCFFolder: UINT;    // Space to reserve in CFFOLDER
  187.         cbReserveCFData: UINT;      // Space to reserve in CFDATA
  188.         iCab: Integer;              // sequential numbers for cabinets
  189.         iDisk: Integer;             // Disk number
  190. {$IFNDEF REMOVE_CHICAGO_M6_HACK}
  191.         fFailOnIncompressible: Integer;  // TRUE => Fail if a block is incompressible
  192. {$ENDIF}
  193.         //  then shorts
  194.         setID: USHORT;               // Cabinet set ID
  195.         // then chars
  196.         szDisk: array[0..CB_MAX_DISK_NAME - 1] of AnsiChar;    // current disk name
  197.         szCab: array[0..CB_MAX_CABINET_NAME - 1] of AnsiChar;  // current cabinet name
  198.         szCabPath: array[0..CB_MAX_CAB_PATH - 1] of AnsiChar;  // path for creating cabinet
  199.     end; { ccab }
  200.  
  201.     PCCAB = ^TCCAB; { pccab }
  202.  
  203. (***    FNFCIALLOC - Memory Allocation
  204.  *      FNFCIFREE  - Memory Free
  205.  *
  206.  *  These are modeled after the C run-time routines malloc() and free()
  207.  *  FCI expects error handling to be identical to these C run-time routines.
  208.  *
  209.  *  As long as you faithfully copy the semantics of malloc() and free(),
  210.  *  you can supply any functions you like!
  211.  *
  212.  *  WARNING: You should never assume anything about the sequence of
  213.  *           FNFCIALLOC and FNFCIFREE calls -- incremental releases of
  214.  *           FCI may have radically different numbers of
  215.  *           FNFCIALLOC calls and allocation sizes!
  216.  *)
  217. //** Memory functions for FCI
  218.  
  219. type
  220.     TFNFCIALLOC = function(cb: ULONG): PVoid; cdecl;
  221.     PFNFCIALLOC = TFNFCIALLOC; { pfna }
  222.  
  223.     TFNFCIFREE = procedure(memory: PVoid); cdecl;
  224.     PFNFCIFREE = TFNFCIFREE; { pfnf }
  225.  
  226. (***    PFNFCIOPEN  - File I/O callbacks for FCI
  227.  *      PFNFCIREAD
  228.  *      PFNFCIWRITE
  229.  *      PFNFCICLOSE
  230.  *      PFNFCISEEK
  231.  *
  232.  *  These are modeled after the C run-time routines _open, _read,
  233.  *  _write, _close, and _lseek.  The values for the PFNFCIOPEN oflag
  234.  *  and pmode calls are those defined for _open.  FCI expects error
  235.  *  handling to be identical to these C run-time routines, except that
  236.  *  the value of errno should be returned via *err.
  237.  *
  238.  *  As long as you faithfully copy these aspects, you can supply
  239.  *  any functions you like!
  240.  *
  241.  *  WARNING: You should never assume you know what file is being
  242.  *           opened at any one point in time!  It is possible
  243.  *           that in a future implementations it may open temporary
  244.  *           files or cabinet files in a different order.
  245.  *)
  246. //** File I/O functions for FCI
  247.  
  248. type
  249.     TFNFCIOPEN = function(pszFile: PAnsiChar; oflag: Integer; pmode: Integer;
  250.         err: PInteger; pv: PVoid): Integer; cdecl;
  251.     PFNFCIOPEN = TFNFCIOPEN;
  252.  
  253.     TFNFCIREAD = function(hf: Integer; memory: PVoid; cb: UINT;
  254.         err: PInteger; pv: PVoid): UINT; cdecl;
  255.     PFNFCIREAD = TFNFCIREAD;
  256.  
  257.     TFNFCIWRITE = function(hf: Integer; memory: PVoid; cb: UINT;
  258.         err: PInteger; pv: PVoid): UINT; cdecl;
  259.     PFNFCIWRITE = TFNFCIWRITE;
  260.  
  261.     TFNFCICLOSE = function(hf: Integer; err: PInteger; pv: PVoid): Integer; cdecl;
  262.     PFNFCICLOSE = TFNFCICLOSE;
  263.  
  264.     TFNFCISEEK = function(hf: Integer; dist: Longint; seektype: Integer;
  265.         err: PInteger; pv: PVoid): Longint; cdecl;
  266.     PFNFCISEEK = TFNFCISEEK;
  267.  
  268.     TFNFCIDELETE = function(pszFile: PAnsiChar; err: PInteger; pv: PVoid): Integer; cdecl;
  269.     PFNFCIDELETE = TFNFCIDELETE;
  270.  
  271. (***    FNFCIGETNEXTCABINET - Callback used to request new cabinet info
  272.  *
  273.  *  Entry:
  274.  *      pccab     - Points to copy of old ccab structure to modify
  275.  *      cbPrevCab - Estimate of size of previous cabinet
  276.  *      pv        - Has the caller's context pointer
  277.  *
  278.  *  Exit-Success:
  279.  *      returns TRUE;
  280.  *
  281.  *  Exit-Failure:
  282.  *      returns FALSE;
  283.  *)
  284.  
  285. type
  286.     TFNFCIGETNEXTCABINET = function(pccab: PCCAB; cbPrevCab: ULONG; pv: PVoid): WIN_BOOL; cdecl;
  287.     PFNFCIGETNEXTCABINET = TFNFCIGETNEXTCABINET; { pfnfcignc }
  288.  
  289. (***    FNFCIFILEPLACED - Notify FCI client that file was placed
  290.  *
  291.  *  Entry:
  292.  *      pccab         - cabinet structure to fill in, with copy of previous one
  293.  *      pszFile       - name of file, from cabinet
  294.  *      cbFile        - length of file
  295.  *      fContinuation - true if this is a later segment of a continued file
  296.  *      pv            - the context of the client
  297.  *
  298.  *  Exit-Success:
  299.  *      return value anything but -1
  300.  *
  301.  *  Exit-Failure:
  302.  *      return value -1 means to abort
  303.  *)
  304.  
  305. type
  306.     TFNFCIFILEPLACED = function(pccab: PCCAB; pszFile: PAnsiChar;
  307.         cbFile: Longint; fContinuation: WIN_BOOL; pv: PVoid): Integer; cdecl;
  308.     PFNFCIFILEPLACED = TFNFCIFILEPLACED; { pfnfcifp }
  309.  
  310. (***    FNCDIGETOPENINFO - Open source file, get date/time/attribs
  311.  *
  312.  *  Entry:
  313.  *      pszName  -- complete path to filename
  314.  *      pdate    -- location to return FAT-style date code
  315.  *      ptime    -- location to return FAT-style time code
  316.  *      pattribs -- location to return FAT-style attributes
  317.  *      pv       -- client's context
  318.  *
  319.  *  Exit-Success:
  320.  *      Return value is file handle of open file to read
  321.  *
  322.  *  Exit-Failure:
  323.  *      Return value is -1
  324.  *)
  325.  
  326. type
  327.     TFNFCIGETOPENINFO = function(pszName: PAnsiChar; pdate: PUSHORT;
  328.         ptime: PUSHORT; pattribs: PUSHORT; err: PInteger; pv: PVoid): Integer; cdecl;
  329.     PFNFCIGETOPENINFO = TFNFCIGETOPENINFO; { pfnfcigoi }
  330.  
  331. (***    FNFCISTATUS - Status/Cabinet Size callback
  332.  *
  333.  *  Entry:
  334.  *      typeStatus == statusFile if compressing a block into a folder
  335.  *                      cb1 = Size of compressed block
  336.  *                      cb2 = Size of uncompressed block
  337.  *
  338.  *      typeStatus == statusFolder if adding a folder to a cabinet
  339.  *                      cb1 = Amount of folder copied to cabinet so far
  340.  *                      cb2 = Total size of folder
  341.  *
  342.  *      typeStatus == statusCabinet if writing out a complete cabinet
  343.  *                      cb1 = Estimated cabinet size that was previously
  344.  *                              passed to fnfciGetNextCabinet().
  345.  *                      cb2 = Actual cabinet size
  346.  *                    NOTE: Return value is desired client size for cabinet
  347.  *                          file.  FCI updates the maximum cabinet size
  348.  *                          remaining using this value.  This allows a client
  349.  *                          to generate multiple cabinets per disk, and have
  350.  *                          FCI limit the size correctly -- the client can do
  351.  *                          cluster size rounding on the cabinet size!
  352.  *                          The client should either return cb2, or round cb2
  353.  *                          up to some larger value and return that.
  354.  *  Exit-Success:
  355.  *      Returns anything other than -1;
  356.  *      NOTE: See statusCabinet for special return values!
  357.  *
  358.  *  Exit-Failure:
  359.  *      Returns -1 to signal that FCI should abort;
  360.  *)
  361.  
  362. const
  363.     statusFile =      0;   // Add File to Folder callback
  364.     statusFolder =    1;   // Add Folder to Cabinet callback
  365.     statusCabinet =   2;   // Write out a completed cabinet callback
  366.  
  367. type
  368.     TFNFCISTATUS = function(typeStatus: UINT; cb1: ULONG; cb2: ULONG; pv: PVoid): Longint; cdecl;
  369.     PFNFCISTATUS = TFNFCISTATUS; { pfnfcis }
  370.  
  371. (***    FNFCIGETTEMPFILE - Callback, requests temporary file name
  372.  *
  373.  *  Entry:
  374.  *      pszTempName - Buffer to receive complete tempfile name
  375.  *      cbTempName  - Size of pszTempName buffer
  376.  *
  377.  *  Exit-Success:
  378.  *      return TRUE
  379.  *
  380.  *  Exit-Failure:
  381.  *      return FALSE; could not create tempfile, or buffer too small
  382.  *
  383.  *  Note:
  384.  *      It is conceivable that this function may return a filename
  385.  *      that will already exist by the time it is opened.  For this
  386.  *      reason, the caller should make several attempts to create
  387.  *      temporary files before giving up.
  388.  *)
  389.  
  390. type
  391.     TFNFCIGETTEMPFILE = function(pszTempName: PAnsiChar; cbTempName: Integer;
  392.         pv: PVoid): WIN_BOOL; cdecl;
  393.     PFNFCIGETTEMPFILE = TFNFCIGETTEMPFILE; { pfnfcigtf }
  394.  
  395. (***    FCICreate -- create an FCI context (an open CAB, an open FOL)
  396.  *
  397.  *  Entry:
  398.  *      perf      - structure where we return error codes
  399.  *      pfnfcifp  - callback to inform caller of eventual dest of files
  400.  *      pfna      - memory allocation function callback
  401.  *      pfnf      - memory free function callback
  402.  *      pfnfcigtf - temp file name generator callback
  403.  *      pccab     - pointer to cabinet/disk name & size structure
  404.  *
  405.  *  Notes:
  406.  *  (1) The alloc/free callbacks must remain valid throughout
  407.  *      the life of the context, up to and including the call to
  408.  *      FCIDestroy.
  409.  *  (2) The perf pointer is stored in the compression context (HCI),
  410.  *      and any errors from subsequent FCI calls are stored in the
  411.  *      erf that was passed in on *this* call.
  412.  *
  413.  *  Exit-Success:
  414.  *      Returns non-NULL handle to an FCI context.
  415.  *
  416.  *  Exit-Failure:
  417.  *      Returns NULL, perf filled in.
  418.  *)
  419.  
  420.     function FCICreate(perf: PERF; pfnfcifp: PFNFCIFILEPLACED;
  421.         pfna: PFNFCIALLOC; pfnf: PFNFCIFREE; pfnopen: PFNFCIOPEN;
  422.         pfnread: PFNFCIREAD; pfnwrite: PFNFCIWRITE; pfnclose: PFNFCICLOSE;
  423.         pfnseek: PFNFCISEEK; pfndelete: PFNFCIDELETE;
  424.         pfnfcigtf: PFNFCIGETTEMPFILE; pccab: PCCAB; pv: PVoid): HFCI; cdecl;
  425.  
  426. type
  427.     TFNFCICreate = function(perf: PERF; pfnfcifp: PFNFCIFILEPLACED;
  428.         pfna: PFNFCIALLOC; pfnf: PFNFCIFREE; pfnopen: PFNFCIOPEN;
  429.         pfnread: PFNFCIREAD; pfnwrite: PFNFCIWRITE; pfnclose: PFNFCICLOSE;
  430.         pfnseek: PFNFCISEEK; pfndelete: PFNFCIDELETE;
  431.         pfnfcigtf: PFNFCIGETTEMPFILE; pccab: PCCAB; pv: PVoid): HFCI; cdecl;
  432.  
  433. (***   FCIAddFile - Add a disk file to a folder/cabinet
  434.  *
  435.  *  Entry:
  436.  *      hfci          - FCI context handle
  437.  *      pszSourceFile - Name of file to add to folder
  438.  *      pszFileName   - Name to store into folder/cabinet
  439.  *      fExecute      - Flag indicating execute on extract
  440.  *      pfn_progress  - Progress callback
  441.  *      pfnfcignc     - GetNextCabinet callback
  442.  *      pfnfcis       - Status callback
  443.  *      pfnfcigoi     - OpenInfo callback
  444.  *      typeCompress  - Type of compression to use for this file
  445.  *      pv            - pointer to caller's internal context
  446.  *
  447.  *  Exit-Success:
  448.  *      returns TRUE
  449.  *
  450.  *  Exit-Failure:
  451.  *      returns FALSE, error filled in
  452.  *
  453.  *    This is the main function used to add file(s) to a cabinet
  454.  *    or series of cabinets.  If the current file causes the current
  455.  *    folder/cabinet to overflow the disk image currently being built,
  456.  *    the cabinet will be terminated, and a new cabinet/disk name will
  457.  *    be prompted for via a callback.  The pending folder will be trimmed
  458.  *    of the data which has already been generated in the finished cabinet.
  459.  *)
  460.  
  461.     function FCIAddFile(hfci: HFCI; pszSourceFile: PAnsiChar; pszFileName: PAnsiChar;
  462.         fExecute: WIN_BOOL; pfnfcignc: PFNFCIGETNEXTCABINET; pfnfcis: PFNFCISTATUS;
  463.         pfnfcigoi: PFNFCIGETOPENINFO; typeCompress: TCOMP): WIN_BOOL; cdecl;
  464.  
  465. type
  466.     TFNFCIAddFile = function(hfci: HFCI; pszSourceFile: PAnsiChar; pszFileName: PAnsiChar;
  467.         fExecute: WIN_BOOL; pfnfcignc: PFNFCIGETNEXTCABINET; pfnfcis: PFNFCISTATUS;
  468.         pfnfcigoi: PFNFCIGETOPENINFO; typeCompress: TCOMP): WIN_BOOL; cdecl;
  469.  
  470. (***   FCIFlushCabinet - Complete the current cabinet under construction
  471.  *
  472.  *  This will cause the current cabinet (assuming it is not empty) to
  473.  *  be gathered together and written to disk.
  474.  *
  475.  *  Entry:
  476.  *      hfci        - FCI context
  477.  *      fGetNextCab - TRUE  => Call GetNextCab to get continuation info;
  478.  *                    FALSE => Don't call GetNextCab unless this cabinet
  479.  *                             overflows.
  480.  *      pfnfcignc   - callback function to get continuation cabinets
  481.  *      pfnfcis     - callback function for progress reporting
  482.  *      pv          - caller's internal context for callbacks
  483.  *
  484.  *  Exit-Success:
  485.  *      return code TRUE
  486.  *
  487.  *  Exit-Failure:
  488.  *      return code FALSE, error structure filled in
  489.  *)
  490.  
  491.     function FCIFlushCabinet(hfci: HFCI; fGetNextCab: WIN_BOOL;
  492.         pfnfcignc: PFNFCIGETNEXTCABINET; pfnfcis: PFNFCISTATUS): WIN_BOOL; cdecl;
  493.  
  494. type
  495.     TFNFCIFlushCabinet = function(hfci: HFCI; fGetNextCab: WIN_BOOL;
  496.         pfnfcignc: PFNFCIGETNEXTCABINET; pfnfcis: PFNFCISTATUS): WIN_BOOL; cdecl;
  497.  
  498. (***   FCIFlushFolder - Complete the current folder under construction
  499.  *
  500.  *  This will force the termination of the current folder, which may or
  501.  *  may not cause one or more cabinet files to be completed.
  502.  *
  503.  *  Entry:
  504.  *      hfci        - FCI context
  505.  *      GetNextCab  - callback function to get continuation cabinets
  506.  *      pfnProgress - callback function for progress reporting
  507.  *      pv          - caller's internal context for callbacks
  508.  *
  509.  *  Exit-Success:
  510.  *      return code TRUE
  511.  *
  512.  *  Exit-Failure:
  513.  *      return code FALSE, error structure filled in
  514.  *)
  515.  
  516.     function FCIFlushFolder(hfci: HFCI; pfnfcignc: PFNFCIGETNEXTCABINET;
  517.         pfnfcis: PFNFCISTATUS): WIN_BOOL; cdecl;
  518.  
  519. type
  520.     TFNFCIFlushFolder = function(hfci: HFCI; pfnfcignc: PFNFCIGETNEXTCABINET;
  521.         pfnfcis: PFNFCISTATUS): WIN_BOOL; cdecl;
  522.  
  523. (***    FCIDestroy - Destroy a FCI context and delete temp files
  524.  *
  525.  *  Entry:
  526.  *      hfci - FCI context
  527.  *
  528.  *  Exit-Success:
  529.  *      return code TRUE
  530.  *
  531.  *  Exit-Failure:
  532.  *      return code FALSE, error structure filled in
  533.  *)
  534.  
  535.     function FCIDestroy(hfci: HFCI): WIN_BOOL; cdecl;
  536.  
  537. type
  538.     TFNFCIDestroy = function(hfci: HFCI): WIN_BOOL; cdecl;
  539.  
  540.  
  541. (*
  542.  *  FDI.H -- File Decompression Interface
  543.  *
  544.  *  Copyright (C) Microsoft Corporation 1993-1997
  545.  *  All Rights Reserved.
  546.  *)
  547.  
  548. (*
  549.  *  Concepts:
  550.  *      A *cabinet* file contains one or more *folders*.  A folder contains
  551.  *      one or more (pieces of) *files*.  A folder is by definition a
  552.  *      decompression unit, i.e., to extract a file from a folder, all of
  553.  *      the data from the start of the folder up through and including the
  554.  *      desired file must be read and decompressed.
  555.  *
  556.  *      A folder can span one (or more) cabinet boundaries, and by implication
  557.  *      a file can also span one (or more) cabinet boundaries.  Indeed, more
  558.  *      than one file can span a cabinet boundary, since FCI concatenates
  559.  *      files together into a single data stream before compressing (actually,
  560.  *      at most one file will span any one cabinet boundary, but FCI does
  561.  *      not know which file this is, since the mapping from uncompressed bytes
  562.  *      to compressed bytes is pretty obscure.  Also, since FCI compresses
  563.  *      in blocks of 32K (at present), any files with data in a 32K block that
  564.  *      spans a cabinet boundary require FDI to read both cabinet files
  565.  *      to get the two halves of the compressed block).
  566.  *
  567.  *  Overview:
  568.  *      The File Decompression Interface is used to simplify the reading of
  569.  *      cabinet files.  A setup program will proceed in a manner very
  570.  *      similar to the pseudo code below.  An FDI context is created, the
  571.  *      setup program calls FDICopy() for each cabinet to be processed.  For
  572.  *      each file in the cabinet, FDICopy() calls a notification callback
  573.  *      routine, asking the setup program if the file should be copied.
  574.  *      This call-back approach is great because it allows the cabinet file
  575.  *      to be read and decompressed in an optimal manner, and also makes FDI
  576.  *      independent of the run-time environment -- FDI makes *no* C run-time
  577.  *      calls whatsoever.  All memory allocation and file I/O functions are
  578.  *      passed into FDI by the client.
  579.  *
  580.  *      main(...)
  581.  *      {
  582.  *          // Read INF file to construct list of desired files.   
  583.  *          //  Ideally, these would be sorted in the same order as the
  584.  *          //  files appear in the cabinets, so that you can just walk
  585.  *          //  down the list in response to fdintCOPY_FILE notifications.
  586.  *
  587.  *          // Construct list of required cabinets. 
  588.  *
  589.  *          hfdi = FDICreate(...);          // Create FDI context
  590.  *          For (cabinet in List of Cabinets) {
  591.  *              FDICopy(hfdi,cabinet,fdiNotify,...);  // Process each cabinet
  592.  *          }
  593.  *          FDIDestroy(hfdi);
  594.  *          ...
  595.  *      }
  596.  *
  597.  *      // Notification callback function 
  598.  *      fdiNotify(fdint,...)
  599.  *      {
  600.  *          If (User Aborted)               // Permit cancellation
  601.  *              if (fdint == fdintCLOSE_FILE_INFO)
  602.  *                  close open file
  603.  *              return -1;
  604.  *          switch (fdint) {
  605.  *              case fdintCOPY_FILE:        // File to copy, maybe
  606.  *                  // Check file against list of desired files 
  607.  *                  if want to copy file
  608.  *                      open destination file and return handle
  609.  *                  else
  610.  *                      return NULL;        // Skip file
  611.  *              case fdintCLOSE_FILE_INFO:
  612.  *                  close file
  613.  *                  set date, time, and attributes
  614.  *
  615.  *              case fdintNEXT_CABINET:
  616.  *                  if not an error callback
  617.  *                      Tell FDI to use suggested directory name
  618.  *                  else
  619.  *                      Tell user what the problem was, and prompt
  620.  *                          for a new disk and/or path.
  621.  *                      if user aborts
  622.  *                          Tell FDI to abort
  623.  *                      else
  624.  *                          return to FDI to try another cabinet
  625.  *
  626.  *              default:
  627.  *                  return 0;               // more messages may be defined
  628.  *              ...
  629.  *      }
  630.  *
  631.  *  Error Handling Suggestions:
  632.  *      Since you the client have passed in *all* of the functions that
  633.  *      FDI uses to interact with the "outside" world, you are in prime
  634.  *      position to understand and deal with errors.
  635.  *
  636.  *      The general philosophy of FDI is to pass all errors back up to
  637.  *      the client.  FDI returns fairly generic error codes in the case
  638.  *      where one of the callback functions (PFNOPEN, PFNREAD, etc.) fail,
  639.  *      since it assumes that the callback function will save enough
  640.  *      information in a static/global so that when FDICopy() returns
  641.  *      fail, the client can examine this information and report enough
  642.  *      detail about the problem that the user can take corrective action.
  643.  *
  644.  *      For very specific errors (CORRUPT_CABINET, for example), FDI returns
  645.  *      very specific error codes.
  646.  *
  647.  *      THE BEST POLICY IS FOR YOUR CALLBACK ROUTINES TO AVOID RETURNING
  648.  *      ERRORS TO FDI!
  649.  *
  650.  *      Examples:
  651.  *          (1) If the disk is getting full, instead of returning an error
  652.  *              from your PFNWRITE function, you should -- inside your
  653.  *              PFNWRITE function -- put up a dialog telling the user to free
  654.  *              some disk space.
  655.  *          (2) When you get the fdintNEXT_CABINET notification, you should
  656.  *              verify that the cabinet you return is the correct one (call
  657.  *              FDIIsCabinet(), and make sure the setID matches the one for
  658.  *              the current cabinet specified in the fdintCABINET_INFO, and
  659.  *              that the disk number is one greater.
  660.  *
  661.  *              NOTE: FDI will continue to call fdintNEXT_CABINET until it
  662.  *                    gets the cabinet it wants, or until you return -1
  663.  *                    to abort the FDICopy() call.
  664.  *
  665.  *      The documentation below on the FDI error codes provides explicit
  666.  *      guidance on how to avoid each error.
  667.  *
  668.  *      If you find you must return a failure to FDI from one of your
  669.  *      callback functions, then FDICopy() frees all resources it allocated
  670.  *      and closes all files.  If you can figure out how to overcome the
  671.  *      problem, you can call FDICopy() again on the last cabinet, and
  672.  *      skip any files that you already copied.  But, note that FDI does
  673.  *      *not* maintain any state between FDICopy() calls, other than possibly
  674.  *      memory allocated for the decompressor.
  675.  *
  676.  *      See FDIERROR for details on FDI error codes and recommended actions.
  677.  *
  678.  *
  679.  *  Progress Indicator Suggestions:
  680.  *      As above, all of the file I/O functions are supplied by you.  So,
  681.  *      updating a progress indicator is very simple.  You keep track of
  682.  *      the target files handles you have opened, along with the uncompressed
  683.  *      size of the target file.  When you see writes to the handle of a
  684.  *      target file, you use the write count to update your status!
  685.  *      Since this method is available, there is no separate callback from
  686.  *      FDI just for progess indication.
  687.  *)
  688.  
  689. (***    FDIERROR - Error codes returned in erf.erfOper field
  690.  *
  691.  *  In general, FDI will only fail if one of the passed in memory or
  692.  *  file I/O functions fails.  Other errors are pretty unlikely, and are
  693.  *  caused by corrupted cabinet files, passing in a file which is not a
  694.  *  cabinet file, or cabinet files out of order.
  695.  *
  696.  *  Description:    Summary of error.
  697.  *  Cause:          List of possible causes of this error.
  698.  *  Response:       How client might respond to this error, or avoid it in
  699.  *                  the first place.
  700.  *)
  701.  
  702. type
  703.     TFDIERROR = (
  704.     FDIERROR_NONE,
  705.         // Description: No error
  706.         // Cause:       Function was successfull.
  707.         // Response:    Keep going!
  708.         FDIERROR_CABINET_NOT_FOUND,
  709.                 // Description: Cabinet not found
  710.                 // Cause:       Bad file name or path passed to FDICopy(), or returned
  711.                 //              to fdintNEXT_CABINET.
  712.                 // Response:    To prevent this error, validate the existence of the
  713.                 //              the cabinet *before* passing the path to FDI.
  714.         FDIERROR_NOT_A_CABINET,
  715.                 // Description: Cabinet file does not have the correct format
  716.                 // Cause:       File passed to to FDICopy(), or returned to
  717.                 //              fdintNEXT_CABINET, is too small to be a cabinet file,
  718.                 //              or does not have the cabinet signature in its first
  719.                 //              four bytes.
  720.                 // Response:    To prevent this error, call FDIIsCabinet() to check a
  721.                 //              cabinet before calling FDICopy() or returning the
  722.                 //              cabinet path to fdintNEXT_CABINET.
  723.         FDIERROR_UNKNOWN_CABINET_VERSION,
  724.                 // Description: Cabinet file has an unknown version number.
  725.                 // Cause:       File passed to to FDICopy(), or returned to
  726.                 //              fdintNEXT_CABINET, has what looks like a cabinet file
  727.                 //              header, but the version of the cabinet file format
  728.                 //              is not one understood by this version of FDI.  The
  729.                 //              erf.erfType field is filled in with the version number
  730.                 //              found in the cabinet file.
  731.                 // Response:    To prevent this error, call FDIIsCabinet() to check a
  732.                 //              cabinet before calling FDICopy() or returning the
  733.                 //              cabinet path to fdintNEXT_CABINET.
  734.         FDIERROR_CORRUPT_CABINET,
  735.                 // Description: Cabinet file is corrupt
  736.                 // Cause:       FDI returns this error any time it finds a problem
  737.                 //              with the logical format of a cabinet file, and any
  738.                 //              time one of the passed-in file I/O calls fails when
  739.                 //              operating on a cabinet (PFNOPEN, PFNSEEK, PFNREAD,
  740.                 //              or PFNCLOSE).  The client can distinguish these two
  741.                 //              cases based upon whether the last file I/O call
  742.                 //              failed or not.
  743.                 // Response:    Assuming this is not a real corruption problem in
  744.                 //              a cabinet file, the file I/O functions could attempt
  745.                 //              to do retries on failure (for example, if there is a
  746.                 //              temporary network connection problem).  If this does
  747.                 //              not work, and the file I/O call has to fail, then the
  748.                 //              FDI client will have to clean up and call the
  749.                 //              FDICopy() function again.
  750.         FDIERROR_ALLOC_FAIL,
  751.                 // Description: Could not allocate enough memory
  752.                 // Cause:       FDI tried to allocate memory with the PFNALLOC
  753.                 //              function, but it failed.
  754.                 // Response:    If possible, PFNALLOC should take whatever steps
  755.                 //              are possible to allocate the memory requested.  If
  756.                 //              memory is not immediately available, it might post a
  757.                 //              dialog asking the user to free memory, for example.
  758.                 //              Note that the bulk of FDI's memory allocations are
  759.                 //              made at FDICreate() time and when the first cabinet
  760.                 //              file is opened during FDICopy().
  761.         FDIERROR_BAD_COMPR_TYPE,
  762.                 // Description: Unknown compression type in a cabinet folder
  763.                 // Cause:       [Should never happen.]  A folder in a cabinet has an
  764.                 //              unknown compression type.  This is probably caused by
  765.                 //              a mismatch between the version of FCI.LIB used to
  766.                 //              create the cabinet and the FDI.LIB used to read the
  767.                 //              cabinet.
  768.                 // Response:    Abort.
  769.         FDIERROR_MDI_FAIL,
  770.                 // Description: Failure decompressing data from a cabinet file
  771.                 // Cause:       The decompressor found an error in the data coming
  772.                 //              from the file cabinet.  The cabinet file was corrupted.
  773.                 //              [11-Apr-1994 bens When checksuming is turned on, this
  774.                 //              error should never occur.]
  775.                 // Response:    Probably should abort; only other choice is to cleanup
  776.                 //              and call FDICopy() again, and hope there was some
  777.                 //              intermittent data error that will not reoccur.
  778.         FDIERROR_TARGET_FILE,
  779.                 // Description: Failure writing to target file
  780.                 // Cause:       FDI returns this error any time it gets an error back
  781.                 //              from one of the passed-in file I/O calls fails when
  782.                 //              writing to a file being extracted from a cabinet.
  783.                 // Response:    To avoid or minimize this error, the file I/O functions
  784.                 //              could attempt to avoid failing.  A common cause might
  785.                 //              be disk full -- in this case, the PFNWRITE function
  786.                 //              could have a check for free space, and put up a dialog
  787.                 //              asking the user to free some disk space.
  788.         FDIERROR_RESERVE_MISMATCH,
  789.                 // Description: Cabinets in a set do not have the same RESERVE sizes
  790.                 // Cause:       [Should never happen]. FDI requires that the sizes of
  791.                 //              the per-cabinet, per-folder, and per-data block
  792.                 //              RESERVE sections be consistent across all the cabinets
  793.                 //              in a set.
  794.                 // Response:    Abort.
  795.         FDIERROR_WRONG_CABINET,
  796.                 // Description: Cabinet returned on fdintNEXT_CABINET is incorrect
  797.                 // Cause:       NOTE: THIS ERROR IS NEVER RETURNED BY FDICopy()!
  798.                 //              Rather, FDICopy() keeps calling the fdintNEXT_CABINET
  799.                 //              callback until either the correct cabinet is specified,
  800.                 //              or you return ABORT.
  801.                 //              When FDICopy() is extracting a file that crosses a
  802.                 //              cabinet boundary, it calls fdintNEXT_CABINET to ask
  803.                 //              for the path to the next cabinet.  Not being very
  804.                 //              trusting, FDI then checks to make sure that the
  805.                 //              correct continuation cabinet was supplied!  It does
  806.                 //              this by checking the "setID" and "iCabinet" fields
  807.                 //              in the cabinet.  When MAKECAB.EXE creates a set of
  808.                 //              cabinets, it constructs the "setID" using the sum
  809.                 //              of the bytes of all the destination file names in
  810.                 //              the cabinet set.  FDI makes sure that the 16-bit
  811.                 //              setID of the continuation cabinet matches the
  812.                 //              cabinet file just processed.  FDI then checks that
  813.                 //              the cabinet number (iCabinet) is one more than the
  814.                 //              cabinet number for the cabinet just processed.
  815.                 // Response:    You need code in your fdintNEXT_CABINET (see below)
  816.                 //              handler to do retries if you get recalled with this
  817.                 //              error.  See the sample code (EXTRACT.C) to see how
  818.                 //              this should be handled.
  819.         FDIERROR_USER_ABORT
  820.                 // Description: FDI aborted.
  821.                 // Cause:       An FDI callback returnd -1 (usually).
  822.                 // Response:    Up to client.
  823.     );
  824.  
  825. (***    HFDI - Handle to an FDI context
  826.  *
  827.  *  FDICreate() creates this, and it must be passed to all other FDI
  828.  *  functions.
  829.  *)
  830.  
  831. type
  832.     HFDI = type PVoid; { hfdi }
  833.  
  834. (***    FDICABINETINFO - Information about a cabinet
  835.  *
  836.  *)
  837.  
  838. type
  839.     TFDICABINETINFO = record
  840.         cbCabinet: Longint;  // Total length of cabinet file
  841.         cFolders: USHORT;    // Count of folders in cabinet
  842.         cFiles: USHORT;      // Count of files in cabinet
  843.         setID: USHORT;       // Cabinet set ID
  844.         iCabinet: USHORT;    // Cabinet number in set (0 based)
  845.         fReserve: WIN_BOOL;  // TRUE => RESERVE present in cabinet
  846.         hasprev: WIN_BOOL;   // TRUE => Cabinet is chained prev
  847.         hasnext: WIN_BOOL;   // TRUE => Cabinet is chained next
  848.     end; { fdici }
  849.  
  850.     PFDICABINETINFO = ^TFDICABINETINFO; { pfdici }
  851.  
  852. (***    FDIDECRYPTTYPE - PFNFDIDECRYPT command types
  853.  *
  854.  *)
  855.  
  856. type
  857.     TFDIDECRYPTTYPE = (
  858.         fdidtNEW_CABINET,                   // New cabinet
  859.         fdidtNEW_FOLDER,                    // New folder
  860.         fdidtDECRYPT                        // Decrypt a data block
  861.     ); { fdidt }
  862.  
  863. (***    FDIDECRYPT - Data for PFNFDIDECRYPT function
  864.  *
  865.  *)
  866.  
  867. type
  868.     TFDIDECRYPT = record
  869.         fdidt: TFDIDECRYPTTYPE;   // Command type (selects union below)
  870.         pvUser: PVoid;            // Decryption context
  871.         case Integer of
  872.             1: (
  873.                 cabinet: record   // fdidtNEW_CABINET
  874.                     pHeaderReserve: PVoid;    // RESERVE section from CFHEADER
  875.                     cbHeaderReserve: USHORT;  // Size of pHeaderReserve
  876.                     setID: USHORT;            // Cabinet set ID
  877.                     iCabinet: Integer;        // Cabinet number in set (0 based)
  878.                 end;
  879.             );
  880.             2: (
  881.                 folder: record   // fdidtNEW_FOLDER
  882.                     pFolderReserve: PVoid;    // RESERVE section from CFFOLDER
  883.                     cbFolderReserve: USHORT;  // Size of pFolderReserve
  884.                     iFolder: USHORT;          // Folder number in cabinet (0 based)
  885.                 end;
  886.             );
  887.             3: (
  888.                 decrypt: record  // fdidtDECRYPT
  889.                     pDataReserve: PVoid;      // RESERVE section from CFDATA
  890.                     cbDataReserve: USHORT;    // Size of pDataReserve
  891.                     pbData: PVoid;            // Data buffer
  892.                     cbData: USHORT;           // Size of data buffer
  893.                     fSplit: WIN_BOOL;         // TRUE if this is a split data block
  894.                     cbPartial: USHORT;        // 0 if this is not a split block, or
  895.                                                                         //  the first piece of a split block;
  896.                                                                         // Greater than 0 if this is the
  897.                                                                         //  second piece of a split block.
  898.                 end;
  899.             );
  900.     end; { fdid }
  901.  
  902.     PFDIDECRYPT = ^TFDIDECRYPT; { pfdid }
  903.  
  904. (***    FNALLOC - Memory Allocation
  905.  *      FNFREE  - Memory Free
  906.  *
  907.  *  These are modeled after the C run-time routines malloc() and free()
  908.  *  FDI expects error handling to be identical to these C run-time routines.
  909.  *
  910.  *  As long as you faithfully copy the semantics of malloc() and free(),
  911.  *  you can supply any functions you like!
  912.  *
  913.  *  WARNING: You should never assume anything about the sequence of
  914.  *           PFNALLOC and PFNFREE calls -- incremental releases of
  915.  *           FDI may have radically different numbers of
  916.  *           PFNALLOC calls and allocation sizes!
  917.  *)
  918. //** Memory functions for FDI
  919.  
  920. type
  921.     TFNALLOC = function(cb: ULONG): PVoid; cdecl;
  922.     PFNALLOC = TFNALLOC; { pfna }
  923.  
  924.     TFNFREE = procedure(pv: PVoid); cdecl;
  925.     PFNFREE = TFNFREE; { pfnf }
  926.  
  927. (***    PFNOPEN  - File I/O callbacks for FDI
  928.  *      PFNREAD
  929.  *      PFNWRITE
  930.  *      PFNCLOSE
  931.  *      PFNSEEK
  932.  *
  933.  *  These are modeled after the C run-time routines _open, _read,
  934.  *  _write, _close, and _lseek.  The values for the PFNOPEN oflag
  935.  *  and pmode calls are those defined for _open.  FDI expects error
  936.  *  handling to be identical to these C run-time routines.
  937.  *
  938.  *  As long as you faithfully copy these aspects, you can supply
  939.  *  any functions you like!
  940.  *
  941.  *  WARNING: You should never assume you know what file is being
  942.  *           opened at any one point in time!  FDI will usually
  943.  *           stick to opening cabinet files, but it is possible
  944.  *           that in a future implementation it may open temporary
  945.  *           files or open cabinet files in a different order.
  946.  *
  947.  *  Notes for Memory Mapped File fans:
  948.  *      You can write wrapper routines to allow FDI to work on memory
  949.  *      mapped files.  You'll have to create your own "handle" type so that
  950.  *      you can store the base memory address of the file and the current
  951.  *      seek position, and then you'll allocate and fill in one of these
  952.  *      structures and return a pointer to it in response to the PFNOPEN
  953.  *      call and the fdintCOPY_FILE call.  Your PFNREAD and PFNWRITE
  954.  *      functions will do memcopy(), and update the seek position in your
  955.  *      "handle" structure.  PFNSEEK will just change the seek position
  956.  *      in your "handle" structure.
  957.  *)
  958. //** File I/O functions for FDI
  959.  
  960. type
  961.     TFNOPEN = function(pszFile: PAnsiChar; oflag: Integer; pmode: Integer): Integer; cdecl;
  962.     PFNOPEN = TFNOPEN;
  963.  
  964.     TFNREAD = function(hf: Integer; pv: PVoid; cb: UINT): UINT; cdecl;
  965.     PFNREAD = TFNREAD;
  966.  
  967.     TFNWRITE = function(hf: Integer; pv: PVoid; cb: UINT): UINT; cdecl;
  968.     PFNWRITE = TFNWRITE;
  969.  
  970.     TFNCLOSE = function(hf: Integer): Integer; cdecl;
  971.     PFNCLOSE = TFNCLOSE;
  972.  
  973.     TFNSEEK = function(hf: Integer; dist: Longint; seektype: Integer): Longint; cdecl;
  974.     PFNSEEK = TFNSEEK;
  975.  
  976. (***    PFNFDIDECRYPT - FDI Decryption callback
  977.  *
  978.  *  If this function is passed on the FDICopy() call, then FDI calls it
  979.  *  at various times to update the decryption state and to decrypt FCDATA
  980.  *  blocks.
  981.  *
  982.  *  Common Entry Conditions:
  983.  *      pfdid->fdidt  - Command type
  984.  *      pfdid->pvUser - pvUser value from FDICopy() call
  985.  *
  986.  *  fdidtNEW_CABINET:   //** Notification of a new cabinet
  987.  *      Entry:
  988.  *        pfdid->cabinet.
  989.  *          pHeaderReserve  - RESERVE section from CFHEADER
  990.  *          cbHeaderReserve - Size of pHeaderReserve
  991.  *          setID           - Cabinet set ID
  992.  *          iCabinet        - Cabinet number in set (0 based)
  993.  *      Exit-Success:
  994.  *          returns anything but -1;
  995.  *      Exit-Failure:
  996.  *          returns -1; FDICopy() is aborted.
  997.  *      Notes:
  998.  *      (1) This call allows the decryption code to pick out any information
  999.  *          from the cabinet header reserved area (placed there by DIACRYPT)
  1000.  *          needed to perform decryption.  If there is no such information,
  1001.  *          this call would presumably be ignored.
  1002.  *      (2) This call is made very soon after fdintCABINET_INFO.
  1003.  *
  1004.  *  fdidtNEW_FOLDER:    //** Notification of a new folder
  1005.  *      Entry:
  1006.  *        pfdid->folder.
  1007.  *          pFolderReserve  - RESERVE section from CFFOLDER
  1008.  *          cbFolderReserve - Size of pFolderReserve
  1009.  *          iFolder         - Folder number in cabinet (0 based)
  1010.  *      Exit-Success:
  1011.  *          returns anything but -1;
  1012.  *      Exit-Failure:
  1013.  *          returns -1; FDICopy() is aborted.
  1014.  *      Notes:
  1015.  *          This call allows the decryption code to pick out any information
  1016.  *          from the folder reserved area (placed there by DIACRYPT) needed
  1017.  *          to perform decryption.  If there is no such information, this
  1018.  *          call would presumably be ignored.
  1019.  *
  1020.  *  fdidtDECRYPT:       //** Decrypt a data buffer
  1021.  *      Entry:
  1022.  *        pfdid->folder.
  1023.  *          pDataReserve  - RESERVE section for this CFDATA block
  1024.  *          cbDataReserve - Size of pDataReserve
  1025.  *          pbData        - Data buffer
  1026.  *          cbData        - Size of data buffer
  1027.  *          fSplit        - TRUE if this is a split data block
  1028.  *          cbPartial     - 0 if this is not a split block, or the first
  1029.  *                              piece of a split block; Greater than 0 if
  1030.  *                              this is the second piece of a split block.
  1031.  *      Exit-Success:
  1032.  *          returns TRUE;
  1033.  *      Exit-Failure:
  1034.  *          returns FALSE; error during decrypt
  1035.  *          returns -1; FDICopy() is aborted.
  1036.  *      Notes:
  1037.  *          FCI will split CFDATA blocks across cabinet boundaries if
  1038.  *          necessary.  To provide maximum flexibility, FDI will call the
  1039.  *          fdidtDECRYPT function twice on such split blocks, once when
  1040.  *          the first portion is read, and again when the second portion
  1041.  *          is read.  And, of course, most data blocks will not be split.
  1042.  *          So, there are three cases:
  1043.  *
  1044.  *           1) fSplit == FALSE
  1045.  *              You have the entire data block, so decrypt it.
  1046.  *
  1047.  *           2) fSplit == TRUE, cbPartial == 0
  1048.  *              This is the first portion of a split data block, so cbData
  1049.  *              is the size of this portion.  You can either choose to decrypt
  1050.  *              this piece, or ignore this call and decrypt the full CFDATA
  1051.  *              block on the next (second) fdidtDECRYPT call.
  1052.  *
  1053.  *           3) fSplit == TRUE, cbPartial > 0
  1054.  *              This is the second portion of a split data block (indeed,
  1055.  *              cbPartial will have the same value as cbData did on the
  1056.  *              immediately preceeding fdidtDECRYPT call!).  If you decrypted
  1057.  *              the first portion on the first call, then you can decrypt the
  1058.  *              second portion now.  If you ignored the first call, then you
  1059.  *              can decrypt the entire buffer.
  1060.  *              NOTE: pbData points to the second portion of the split data
  1061.  *                    block in this case, *not* the entire data block.  If
  1062.  *                    you want to wait until the second piece to decrypt the
  1063.  *                    *entire* block, pbData-cbPartial is the address of the
  1064.  *                    start of the whole block, and cbData+cbPartial is its
  1065.  *                    size.
  1066.  *)
  1067.  
  1068. type
  1069.     TFNFDIDECRYPT = function(pfdid: PFDIDECRYPT): Integer; cdecl;
  1070.     PFNFDIDECRYPT = TFNFDIDECRYPT; { pfnfdid }
  1071.  
  1072. (***    FDINOTIFICATION - Notification structure for PFNFDINOTIFY
  1073.  *
  1074.  *  See the FDINOTIFICATIONTYPE definition for information on usage and
  1075.  *  meaning of these fields.
  1076.  *)
  1077.  
  1078. type
  1079.     TFDINOTIFICATION = record
  1080.         // long fields
  1081.         cb: Longint;
  1082.         psz1: PAnsiChar;
  1083.         psz2: PAnsiChar;
  1084.         psz3: PAnsiChar;                  // Points to a 256 character buffer
  1085.         pv: PVoid;                        // Value for client
  1086.         // int fields
  1087.         hf: Integer;
  1088.         // short fields
  1089.         date: USHORT;
  1090.         time: USHORT;
  1091.         attribs: USHORT;
  1092.  
  1093.         setID: USHORT;                    // Cabinet set ID
  1094.         iCabinet: USHORT;                 // Cabinet number (0-based)
  1095.         iFolder: USHORT;                  // Folder number (0-based)
  1096.  
  1097.         fdie: TFDIERROR;
  1098.     end; { fdin }
  1099.  
  1100.     PFDINOTIFICATION = ^TFDINOTIFICATION; { pfdin }
  1101.  
  1102. (***    FDINOTIFICATIONTYPE - FDICopy notification types
  1103.  *
  1104.  *  The notification function for FDICopy can be called with the following
  1105.  *  values for the fdint parameter.  In all cases, the pfdin->pv field is
  1106.  *  filled in with the value of the pvUser argument passed in to FDICopy().
  1107.  *
  1108.  *  A typical sequence of calls will be something like this:
  1109.  *      fdintCABINET_INFO     // Info about the cabinet
  1110.  *      fdintENUMERATE        // Starting enumeration
  1111.  *      fdintPARTIAL_FILE     // Only if this is not the first cabinet, and
  1112.  *                            // one or more files were continued from the
  1113.  *                            // previous cabinet.
  1114.  *      ...
  1115.  *      fdintPARTIAL_FILE
  1116.  *      fdintCOPY_FILE        // The first file that starts in this cabinet
  1117.  *      ...
  1118.  *      fdintCOPY_FILE        // Now let's assume you want this file...
  1119.  *      // PFNWRITE called multiple times to write to this file.
  1120.  *      fdintCLOSE_FILE_INFO  // File done, set date/time/attributes
  1121.  *
  1122.  *      fdintCOPY_FILE        // Now let's assume you want this file...
  1123.  *      // PFNWRITE called multiple times to write to this file.
  1124.  *      fdintNEXT_CABINET     // File was continued to next cabinet!
  1125.  *      fdintCABINET_INFO     // Info about the new cabinet
  1126.  *      // PFNWRITE called multiple times to write to this file.
  1127.  *      fdintCLOSE_FILE_INFO  // File done, set date/time/attributes
  1128.  *      ...
  1129.  *      fdintENUMERATE        // Ending enumeration
  1130.  *
  1131.  *  fdintCABINET_INFO:
  1132.  *        Called exactly once for each cabinet opened by FDICopy(), including
  1133.  *        continuation cabinets opened due to file(s) spanning cabinet
  1134.  *        boundaries. Primarily intended to permit EXTRACT.EXE to
  1135.  *        automatically select the next cabinet in a cabinet sequence even if
  1136.  *        not copying files that span cabinet boundaries.
  1137.  *      Entry:
  1138.  *          pfdin->psz1     = name of next cabinet
  1139.  *          pfdin->psz2     = name of next disk
  1140.  *          pfdin->psz3     = cabinet path name
  1141.  *          pfdin->setID    = cabinet set ID (a random 16-bit number)
  1142.  *          pfdin->iCabinet = Cabinet number within cabinet set (0-based)
  1143.  *      Exit-Success:
  1144.  *          Return anything but -1
  1145.  *      Exit-Failure:
  1146.  *          Returns -1 => Abort FDICopy() call
  1147.  *      Notes:
  1148.  *          This call is made *every* time a new cabinet is examined by
  1149.  *          FDICopy().  So if "foo2.cab" is examined because a file is
  1150.  *          continued from "foo1.cab", and then you call FDICopy() again
  1151.  *          on "foo2.cab", you will get *two* fdintCABINET_INFO calls all
  1152.  *          told.
  1153.  *
  1154.  *  fdintCOPY_FILE:
  1155.  *        Called for each file that *starts* in the current cabinet, giving
  1156.  *        the client the opportunity to request that the file be copied or
  1157.  *        skipped.
  1158.  *      Entry:
  1159.  *          pfdin->psz1    = file name in cabinet
  1160.  *          pfdin->cb      = uncompressed size of file
  1161.  *          pfdin->date    = file date
  1162.  *          pfdin->time    = file time
  1163.  *          pfdin->attribs = file attributes
  1164.  *          pfdin->iFolder = file's folder index
  1165.  *      Exit-Success:
  1166.  *          Return non-zero file handle for destination file; FDI writes
  1167.  *          data to this file use the PFNWRITE function supplied to FDICreate,
  1168.  *          and then calls fdintCLOSE_FILE_INFO to close the file and set
  1169.  *          the date, time, and attributes.  NOTE: This file handle returned
  1170.  *          must also be closeable by the PFNCLOSE function supplied to
  1171.  *          FDICreate, since if an error occurs while writing to this handle,
  1172.  *          FDI will use the PFNCLOSE function to close the file so that the
  1173.  *          client may delete it.
  1174.  *      Exit-Failure:
  1175.  *          Returns 0  => Skip file, do not copy
  1176.  *          Returns -1 => Abort FDICopy() call
  1177.  *
  1178.  *  fdintCLOSE_FILE_INFO:
  1179.  *        Called after all of the data has been written to a target file.
  1180.  *        This function must close the file and set the file date, time,
  1181.  *        and attributes.
  1182.  *      Entry:
  1183.  *          pfdin->psz1    = file name in cabinet
  1184.  *          pfdin->hf      = file handle
  1185.  *          pfdin->date    = file date
  1186.  *          pfdin->time    = file time
  1187.  *          pfdin->attribs = file attributes
  1188.  *          pfdin->iFolder = file's folder index
  1189.  *          pfdin->cb      = Run After Extract (0 - don't run, 1 Run)
  1190.  *      Exit-Success:
  1191.  *          Returns TRUE
  1192.  *      Exit-Failure:
  1193.  *          Returns FALSE, or -1 to abort;
  1194.  *
  1195.  *              IMPORTANT NOTE IMPORTANT:
  1196.  *                  pfdin->cb is overloaded to no longer be the size of
  1197.  *                  the file but to be a binary indicated run or not
  1198.  *
  1199.  *              IMPORTANT NOTE:
  1200.  *                  FDI assumes that the target file was closed, even if this
  1201.  *                  callback returns failure.  FDI will NOT attempt to use
  1202.  *                  the PFNCLOSE function supplied on FDICreate() to close
  1203.  *                  the file!
  1204.  *
  1205.  *  fdintPARTIAL_FILE:
  1206.  *        Called for files at the front of the cabinet that are CONTINUED
  1207.  *        from a previous cabinet.  This callback occurs only when FDICopy is
  1208.  *        started on second or subsequent cabinet in a series that has files
  1209.  *        continued from a previous cabinet.
  1210.  *      Entry:
  1211.  *          pfdin->psz1 = file name of file CONTINUED from a PREVIOUS cabinet
  1212.  *          pfdin->psz2 = name of cabinet where file starts
  1213.  *          pfdin->psz3 = name of disk where file starts
  1214.  *      Exit-Success:
  1215.  *          Return anything other than -1; enumeration continues
  1216.  *      Exit-Failure:
  1217.  *          Returns -1 => Abort FDICopy() call
  1218.  *
  1219.  *  fdintENUMERATE:
  1220.  *        Called once after a call to FDICopy() starts scanning a CAB's
  1221.  *        CFFILE entries, and again when there are no more CFFILE entries.
  1222.  *        If CAB spanning occurs, an additional call will occur after the
  1223.  *        first spanned file is completed.  If the pfdin->iFolder value is
  1224.  *        changed from zero, additional calls will occur next time it reaches
  1225.  *        zero.  If iFolder is changed to zero, FDICopy will terminate, as if
  1226.  *        there were no more CFFILE entries.  Primarily intended to allow an
  1227.  *        application with it's own file list to help FDI advance quickly to
  1228.  *        a CFFILE entry of interest.  Can also be used to allow an
  1229.  *        application to determine the cb values for each file in the CAB.
  1230.  *      Entry:
  1231.  *        pfdin->cb        = current CFFILE position
  1232.  *        pfdin->iFolder   = number of files remaining
  1233.  *        pfdin->setID     = current CAB's setID value
  1234.  *      Exit-Don't Care:
  1235.  *        Don't change anything.
  1236.  *        Return anything but -1.
  1237.  *      Exit-Forcing a skip:
  1238.  *        pfdin->cb        = desired CFFILE position
  1239.  *        pfdin->iFolder   = desired # of files remaining
  1240.  *        Return anything but -1.
  1241.  *      Exit-Stop:
  1242.  *        pfdin->iFolder    = set to 0
  1243.  *        Return anything but -1.
  1244.  *      Exit-Failure:
  1245.  *        Return -1 => Abort FDICopy call ("user aborted".)
  1246.  *      Notes:
  1247.  *        This call can be ignored by applications which want normal file
  1248.  *        searching.  The application can adjust the supplied values to
  1249.  *        force FDICopy() to continue it's search at another location, or
  1250.  *        to force FDICopy() to terminate the search, by setting iFolder to 0.
  1251.  *        (FDICopy() will report no error when terminated this way.)
  1252.  *        FDI has no means to verify the supplied cb or iFolder values.
  1253.  *        Arbitrary values are likely to cause undesirable results.  An
  1254.  *        application should cross-check pfdin->setID to be certain the
  1255.  *        external database is in sync with the CAB.  Reverse-skips are OK
  1256.  *        (but may be inefficient) unless fdintNEXT_CABINET has been called.
  1257.  *
  1258.  *  fdintNEXT_CABINET:
  1259.  *        This function is *only* called when fdintCOPY_FILE was told to copy
  1260.  *        a file in the current cabinet that is continued to a subsequent
  1261.  *        cabinet file.  It is important that the cabinet path name (psz3)
  1262.  *        be validated before returning!  This function should ensure that
  1263.  *        the cabinet exists and is readable before returning.  So, this
  1264.  *        is the function that should, for example, issue a disk change
  1265.  *        prompt and make sure the cabinet file exists.
  1266.  *
  1267.  *        When this function returns to FDI, FDI will check that the setID
  1268.  *        and iCabinet match the expected values for the next cabinet.
  1269.  *        If not, FDI will continue to call this function until the correct
  1270.  *        cabinet file is specified, or until this function returns -1 to
  1271.  *        abort the FDICopy() function.  pfdin->fdie is set to
  1272.  *        FDIERROR_WRONG_CABINET to indicate this case.
  1273.  *
  1274.  *        If you *haven't* ensured that the cabinet file is present and
  1275.  *        readable, or the cabinet file has been damaged, pfdin->fdie will
  1276.  *        receive other appropriate error codes:
  1277.  *
  1278.  *              FDIERROR_CABINET_NOT_FOUND
  1279.  *              FDIERROR_NOT_A_CABINET
  1280.  *              FDIERROR_UNKNOWN_CABINET_VERSION
  1281.  *              FDIERROR_CORRUPT_CABINET
  1282.  *              FDIERROR_BAD_COMPR_TYPE
  1283.  *              FDIERROR_RESERVE_MISMATCH
  1284.  *              FDIERROR_WRONG_CABINET
  1285.  *
  1286.  *      Entry:
  1287.  *          pfdin->psz1 = name of next cabinet where current file is continued
  1288.  *          pfdin->psz2 = name of next disk where current file is continued
  1289.  *          pfdin->psz3 = cabinet path name; FDI concatenates psz3 with psz1
  1290.  *                          to produce the fully-qualified path for the cabinet
  1291.  *                          file.  The 256-byte buffer pointed at by psz3 may
  1292.  *                          be modified, but psz1 may not!
  1293.  *          pfdin->fdie = FDIERROR_WRONG_CABINET if the previous call to
  1294.  *                        fdintNEXT_CABINET specified a cabinet file that
  1295.  *                        did not match the setID/iCabinet that was expected.
  1296.  *      Exit-Success:
  1297.  *          Return anything but -1
  1298.  *      Exit-Failure:
  1299.  *          Returns -1 => Abort FDICopy() call
  1300.  *      Notes:
  1301.  *          This call is almost always made when a target file is open and
  1302.  *          being written to, and the next cabinet is needed to get more
  1303.  *          data for the file.
  1304.  *)
  1305.  
  1306. type
  1307.     TFDINOTIFICATIONTYPE = (
  1308.     fdintCABINET_INFO,              // General information about cabinet
  1309.     fdintPARTIAL_FILE,              // First file in cabinet is continuation
  1310.     fdintCOPY_FILE,                 // File to be copied
  1311.     fdintCLOSE_FILE_INFO,           // close the file, set relevant info
  1312.     fdintNEXT_CABINET,              // File continued to next cabinet
  1313.         fdintENUMERATE                  // Enumeration status
  1314.     ); { fdint }
  1315.  
  1316.     TFNFDINOTIFY = function(fdint: TFDINOTIFICATIONTYPE; pfdin: PFDINOTIFICATION): Integer; cdecl;
  1317.     PFNFDINOTIFY = TFNFDINOTIFY; { pfnfdin }
  1318.  
  1319. (*** cpuType values for FDICreate()
  1320.  *
  1321.  *  (Ignored by 32-bit FDI.)
  1322.  *)
  1323.  
  1324. const
  1325.     cpuUNKNOWN = -1;
  1326.     cpu80286 = 0;
  1327.     cpu80386 = 1;
  1328.  
  1329. (***    FDICreate - Create an FDI context
  1330.  *
  1331.  *  Entry:
  1332.  *      pfnalloc
  1333.  *      pfnfree
  1334.  *      pfnopen
  1335.  *      pfnread
  1336.  *      pfnwrite
  1337.  *      pfnclose
  1338.  *      pfnlseek
  1339.  *      cpuType  - Select CPU type (auto-detect, 286, or 386+)
  1340.  *                 NOTE: For the 32-bit FDI.LIB, this parameter is ignored!
  1341.  *      perf
  1342.  *
  1343.  *  Exit-Success:
  1344.  *      Returns non-NULL FDI context handle.
  1345.  *
  1346.  *  Exit-Failure:
  1347.  *      Returns NULL; perf filled in with error code
  1348.  *
  1349.  *)
  1350.  
  1351.     function FDICreate(pfnalloc: PFNALLOC; pfnfree: PFNFREE; pfnopen: PFNOPEN;
  1352.         pfnread: PFNREAD; pfnwrite: PFNWRITE; pfnclose: PFNCLOSE;
  1353.         pfnseek: PFNSEEK; cpuType: Integer; perf: PERF): HFDI; cdecl;
  1354.  
  1355. type
  1356.     TFNFDICreate = function(pfnalloc: PFNALLOC; pfnfree: PFNFREE; pfnopen: PFNOPEN;
  1357.         pfnread: PFNREAD; pfnwrite: PFNWRITE; pfnclose: PFNCLOSE;
  1358.         pfnseek: PFNSEEK; cpuType: Integer; perf: PERF): HFDI; cdecl;
  1359.  
  1360. (***    FDIIsCabinet - Determines if file is a cabinet, returns info if it is
  1361.  *
  1362.  *  Entry:
  1363.  *      hfdi   - Handle to FDI context (created by FDICreate())
  1364.  *      hf     - File handle suitable for PFNREAD/PFNSEEK, positioned
  1365.  *               at offset 0 in the file to test.
  1366.  *      pfdici - Buffer to receive info about cabinet if it is one.
  1367.  *
  1368.  *  Exit-Success:
  1369.  *      Returns TRUE; file is a cabinet, pfdici filled in.
  1370.  *
  1371.  *  Exit-Failure:
  1372.  *      Returns FALSE, file is not a cabinet;  If an error occurred,
  1373.  *          perf (passed on FDICreate call!) filled in with error.
  1374.  *)
  1375.  
  1376.     function FDIIsCabinet(hfdi: HFDI; hf: Integer; pfdici: PFDICABINETINFO): WIN_BOOL; cdecl;
  1377.  
  1378. type
  1379.     TFNFDIIsCabinet = function(hfdi: HFDI; hf: Integer; pfdici: PFDICABINETINFO): WIN_BOOL; cdecl;
  1380.  
  1381. (***    FDICopy - extracts files from a cabinet
  1382.  *
  1383.  *  Entry:
  1384.  *      hfdi        - handle to FDI context (created by FDICreate())
  1385.  *      pszCabinet  - main name of cabinet file
  1386.  *      pszCabPath  - Path to cabinet file(s)
  1387.  *      flags       - Flags to modify behavior
  1388.  *      pfnfdin     - Notification function
  1389.  *      pfnfdid     - Decryption function (pass NULL if not used)
  1390.  *      pvUser      - User specified value to pass to notification function
  1391.  *
  1392.  *  Exit-Success:
  1393.  *      Returns TRUE;
  1394.  *
  1395.  *  Exit-Failure:
  1396.  *      Returns FALSE, perf (passed on FDICreate call!) filled in with
  1397.  *          error.
  1398.  *
  1399.  *  Notes:
  1400.  *  (1) If FDICopy() fails while a target file is being written out, then
  1401.  *      FDI will use the PFNCLOSE function to close the file handle for that
  1402.  *      target file that was returned from the fdintCOPY_FILE notification.
  1403.  *      The client application is then free to delete the target file, since
  1404.  *      it will not be in a valid state (since there was an error while
  1405.  *      writing it out).
  1406.  *)
  1407.  
  1408.     function FDICopy(hfdi: HFDI; pszCabinet: PAnsiChar; pszCabPath: PAnsiChar;
  1409.         flags: Integer; pfnfdin: PFNFDINOTIFY; pfnfdid: PFNFDIDECRYPT;
  1410.         pvUser: PVoid): WIN_BOOL; cdecl;
  1411.  
  1412. type
  1413.     TFNFDICopy = function(hfdi: HFDI; pszCabinet: PAnsiChar; pszCabPath: PAnsiChar;
  1414.         flags: Integer; pfnfdin: PFNFDINOTIFY; pfnfdid: PFNFDIDECRYPT;
  1415.         pvUser: PVoid): WIN_BOOL; cdecl;
  1416.  
  1417. (***    FDIDestroy - Destroy an FDI context
  1418.  *
  1419.  *  Entry:
  1420.  *      hfdi - handle to FDI context (created by FDICreate())
  1421.  *
  1422.  *  Exit-Success:
  1423.  *      Returns TRUE;
  1424.  *
  1425.  *  Exit-Failure:
  1426.  *      Returns FALSE;
  1427.  *)
  1428.  
  1429.     function FDIDestroy(hfdi: HFDI): WIN_BOOL; cdecl;
  1430.  
  1431. type
  1432.     TFNFDIDestroy = function(hfdi: HFDI): WIN_BOOL; cdecl;
  1433.  
  1434.  
  1435.     function CompressionTypeFromTCOMP(tc: TCOMP): TCOMP;
  1436.     function CompressionLevelFromTCOMP(tc: TCOMP): TCOMP;
  1437.     function CompressionMemoryFromTCOMP(tc: TCOMP): TCOMP;
  1438.     function TCOMPfromTypeLevelMemory(t, l, m: TCOMP): TCOMP;
  1439.     function LZXCompressionWindowFromTCOMP(tc: TCOMP): TCOMP;
  1440.     function TCOMPfromLZXWindow(w: TCOMP): TCOMP;
  1441.  
  1442. const
  1443.     BooleanToWinBool: array[Boolean] of WIN_BOOL = (WIN_FALSE, WIN_TRUE);
  1444.  
  1445.  
  1446. type
  1447.     // Truncated!
  1448.     TCFHEADER = packed record
  1449.         signature: UINT4;    // cabinet file signature
  1450.         reserved1: UINT4;    // reserved
  1451.         cbCabinet: UINT4;    // size of this cabinet file in bytes
  1452.         reserved2: UINT4;    // reserved
  1453.         coffFiles: UINT4;    // offset of the first CFFILE entry
  1454.         reserved3: UINT4;    // reserved
  1455.         versionMinor: UINT1;    // cabinet file format version, minor
  1456.         versionMajor: UINT1;    // cabinet file format version, major
  1457.         cFolders: UINT2;    // number of CFFOLDER entries in this cabinet
  1458.         cFiles: UINT2;    // number of CFFILE entries in this cabinet
  1459.         flags: UINT2;    // cabinet file option indicators
  1460.         setID: UINT2;    // must be the same for all cabinets in a set
  1461.         iCabinet: UINT2;    // number of this cabinet file in a set
  1462. {        cbCFHeader: UINT2;     // (optional) size of per-cabinet reserved area
  1463.         cbCFFolder: UINT1;     // (optional) size of per-folder reserved area
  1464.         cbCFData: UINT1;     // (optional) size of per-datablock reserved area
  1465.         abReserve: UINT1[];    // (optional) per-cabinet reserved area
  1466.         szCabinetPrev: AnsiChar[];    // (optional) name of previous cabinet file
  1467.         szDiskPrev: AnsiChar[];    // (optional) name of previous disk
  1468.         szCabinetNext: AnsiChar[];    // (optional) name of next cabinet file
  1469.         szDiskNext: AnsiChar[];    // (optional) name of next disk   }
  1470.     end;
  1471.  
  1472. const
  1473.     cfhdrSIGNATURE: UINT4 = $4643534D;
  1474.  
  1475.     cfhdrPREV_CABINET: UINT2 =    $0001;
  1476.     cfhdrNEXT_CABINET: UINT2 =    $0002;
  1477.     cfhdrRESERVE_PRESENT: UINT2 = $0004;
  1478.  
  1479. type
  1480.     // Truncated!
  1481.     TCFFOLDER = packed record
  1482.         coffCabStart: UINT4;    // offset of the first CFDATA block in this folder
  1483.         cCFData: UINT2;    // number of CFDATA blocks in this folder
  1484.         typeCompress: UINT2;    // compression type indicator
  1485. {        abReserve: UINT1[];    // (optional) per-folder reserved area   }
  1486.     end;
  1487.  
  1488.     // Truncated!
  1489.     TCFFILE = packed record
  1490.         cbFile: UINT4;    // uncompressed size of this file in bytes
  1491.         uoffFolderStart: UINT4;    // uncompressed offset of this file in the folder
  1492.         iFolder: UINT2;    // index into the CFFOLDER area
  1493.         date: UINT2;    // date stamp for this file
  1494.         time: UINT2;    // time stamp for this file
  1495.         attribs: UINT2;    // attribute flags for this file
  1496. {        szName: AnsiChar[];    // name of this file   }
  1497.     end;
  1498.  
  1499. const
  1500.     ifoldCONTINUED_FROM_PREV: UINT2 =     $FFFD;
  1501.     ifoldCONTINUED_TO_NEXT: UINT2 =       $FFFE;
  1502.     ifoldCONTINUED_PREV_AND_NEXT: UINT2 = $FFFF;
  1503.  
  1504. type
  1505.     // Truncated!
  1506.     TCFDATA = packed record
  1507.         csum: UINT4;    // checksum of this CFDATA entry
  1508.         cbData: UINT2;    // number of compressed bytes in this block
  1509.         cbUncomp: UINT2;    // number of uncompressed bytes in this block
  1510. {        abReserve: UINT1[];    // (optional) per-datablock reserved area
  1511.         ab: UINT1[cbData];    // compressed data bytes   }
  1512.     end;
  1513.  
  1514. implementation
  1515.  
  1516. function CompressionTypeFromTCOMP(tc: TCOMP): TCOMP;
  1517. begin
  1518.     Result := tc and tcompMASK_TYPE;
  1519. end;
  1520.  
  1521. function CompressionLevelFromTCOMP(tc: TCOMP): TCOMP;
  1522. begin
  1523.     Result := (tc and tcompMASK_QUANTUM_LEVEL) shr tcompSHIFT_QUANTUM_LEVEL;
  1524. end;
  1525.  
  1526. function CompressionMemoryFromTCOMP(tc: TCOMP): TCOMP;
  1527. begin
  1528.     Result := (tc and tcompMASK_QUANTUM_MEM) shr tcompSHIFT_QUANTUM_MEM;
  1529. end;
  1530.  
  1531. function TCOMPfromTypeLevelMemory(t, l, m: TCOMP): TCOMP;
  1532. begin
  1533.     Result := (m shl tcompSHIFT_QUANTUM_MEM) or (l shl tcompSHIFT_QUANTUM_LEVEL) or t;
  1534. end;
  1535.  
  1536. function LZXCompressionWindowFromTCOMP(tc: TCOMP): TCOMP;
  1537. begin
  1538.     Result := (tc and tcompMASK_LZX_WINDOW) shr tcompSHIFT_LZX_WINDOW;
  1539. end;
  1540.  
  1541. function TCOMPfromLZXWindow(w: TCOMP): TCOMP;
  1542. begin
  1543.     Result := (w shl tcompSHIFT_LZX_WINDOW) or tcompTYPE_LZX;
  1544. end;
  1545.  
  1546.  
  1547. const
  1548.     CabinetDll = 'cabinet.dll';
  1549.  
  1550. {$IFDEF CABINET_STATIC_LINK}
  1551.  
  1552. function FCICreate; external CabinetDll name 'FCICreate';
  1553. function FCIAddFile; external CabinetDll name 'FCIAddFile';
  1554. function FCIFlushCabinet; external CabinetDll name 'FCIFlushCabinet';
  1555. function FCIFlushFolder; external CabinetDll name 'FCIFlushFolder';
  1556. function FCIDestroy; external CabinetDll name 'FCIDestroy';
  1557. function FDICreate; external CabinetDll name 'FDICreate';
  1558. function FDIIsCabinet; external CabinetDll name 'FDIIsCabinet';
  1559. function FDICopy; external CabinetDll name 'FDICopy';
  1560. function FDIDestroy; external CabinetDll name 'FDIDestroy';
  1561.  
  1562. {$ELSE}
  1563.  
  1564. var
  1565.     hCabModule: HModule = 0;
  1566.     pFCICreate: TFNFCICreate = nil;
  1567.     pFCIAddFile: TFNFCIAddFile = nil;
  1568.     pFCIFlushCabinet: TFNFCIFlushCabinet = nil;
  1569.     pFCIFlushFolder: TFNFCIFlushFolder = nil;
  1570.     pFCIDestroy: TFNFCIDestroy = nil;
  1571.     pFDICreate: TFNFDICreate = nil;
  1572.     pFDIIsCabinet: TFNFDIIsCabinet = nil;
  1573.     pFDICopy: TFNFDICopy = nil;
  1574.     pFDIDestroy: TFNFDIDestroy = nil;
  1575.  
  1576. procedure InitCabinet;
  1577. begin
  1578.     hCabModule := LoadLibrary(CabinetDll);
  1579.     Win32Check(hCabModule <> 0);
  1580.     try
  1581.         @pFCICreate := GetProcAddress(hCabModule, 'FCICreate');
  1582.         Win32Check(@pFCICreate <> nil);
  1583.         @pFCIAddFile := GetProcAddress(hCabModule, 'FCIAddFile');
  1584.         Win32Check(@pFCIAddFile <> nil);
  1585.         @pFCIFlushCabinet := GetProcAddress(hCabModule, 'FCIFlushCabinet');
  1586.         Win32Check(@pFCIFlushCabinet <> nil);
  1587.         @pFCIFlushFolder := GetProcAddress(hCabModule, 'FCIFlushFolder');
  1588.         Win32Check(@pFCIFlushFolder <> nil);
  1589.         @pFCIDestroy := GetProcAddress(hCabModule, 'FCIDestroy');
  1590.         Win32Check(@pFCIDestroy <> nil);
  1591.         @pFDICreate := GetProcAddress(hCabModule, 'FDICreate');
  1592.         Win32Check(@pFDICreate <> nil);
  1593.         @pFDIIsCabinet := GetProcAddress(hCabModule, 'FDIIsCabinet');
  1594.         Win32Check(@pFDIIsCabinet <> nil);
  1595.         @pFDICopy := GetProcAddress(hCabModule, 'FDICopy');
  1596.         Win32Check(@pFDICopy <> nil);
  1597.         @pFDIDestroy := GetProcAddress(hCabModule, 'FDIDestroy');
  1598.         Win32Check(@pFDIDestroy <> nil);
  1599.     except
  1600.         FreeLibrary(hCabModule);
  1601.         hCabModule := 0;
  1602.         raise;
  1603.     end;
  1604. end;
  1605.  
  1606. function FCICreate(perf: PERF; pfnfcifp: PFNFCIFILEPLACED;
  1607.     pfna: PFNFCIALLOC; pfnf: PFNFCIFREE; pfnopen: PFNFCIOPEN;
  1608.     pfnread: PFNFCIREAD; pfnwrite: PFNFCIWRITE; pfnclose: PFNFCICLOSE;
  1609.     pfnseek: PFNFCISEEK; pfndelete: PFNFCIDELETE;
  1610.     pfnfcigtf: PFNFCIGETTEMPFILE; pccab: PCCAB; pv: PVoid): HFCI; cdecl;
  1611. begin
  1612.     if hCabModule = 0 then
  1613.         InitCabinet;
  1614.     Result := pFCICreate(perf, pfnfcifp, pfna, pfnf, pfnopen, pfnread, pfnwrite,
  1615.         pfnclose, pfnseek, pfndelete, pfnfcigtf, pccab, pv);
  1616. end;
  1617.  
  1618. function FCIAddFile(hfci: HFCI; pszSourceFile: PAnsiChar; pszFileName: PAnsiChar;
  1619.     fExecute: WIN_BOOL; pfnfcignc: PFNFCIGETNEXTCABINET; pfnfcis: PFNFCISTATUS;
  1620.     pfnfcigoi: PFNFCIGETOPENINFO; typeCompress: TCOMP): WIN_BOOL; cdecl;
  1621. begin
  1622.     Result := pFCIAddFile(hfci, pszSourceFile, pszFileName, fExecute,
  1623.         pfnfcignc, pfnfcis, pfnfcigoi, typeCompress);
  1624. end;
  1625.  
  1626. function FCIFlushCabinet(hfci: HFCI; fGetNextCab: WIN_BOOL;
  1627.     pfnfcignc: PFNFCIGETNEXTCABINET; pfnfcis: PFNFCISTATUS): WIN_BOOL; cdecl;
  1628. begin
  1629.     Result := pFCIFlushCabinet(hfci, fGetNextCab, pfnfcignc, pfnfcis);
  1630. end;
  1631.  
  1632. function FCIFlushFolder(hfci: HFCI; pfnfcignc: PFNFCIGETNEXTCABINET;
  1633.     pfnfcis: PFNFCISTATUS): WIN_BOOL; cdecl;
  1634. begin
  1635.     Result := pFCIFlushFolder(hfci, pfnfcignc, pfnfcis);
  1636. end;
  1637.  
  1638. function FCIDestroy(hfci: HFCI): WIN_BOOL; cdecl;
  1639. begin
  1640.     Result := pFCIDestroy(hfci);
  1641. end;
  1642.  
  1643. function FDICreate(pfnalloc: PFNALLOC; pfnfree: PFNFREE; pfnopen: PFNOPEN;
  1644.     pfnread: PFNREAD; pfnwrite: PFNWRITE; pfnclose: PFNCLOSE;
  1645.     pfnseek: PFNSEEK; cpuType: Integer; perf: PERF): HFDI; cdecl;
  1646. begin
  1647.     if hCabModule = 0 then
  1648.         InitCabinet;
  1649.     Result := pFDICreate(pfnalloc, pfnfree, pfnopen, pfnread, pfnwrite,
  1650.         pfnclose, pfnseek, cpuType, perf);
  1651. end;
  1652.  
  1653. function FDIIsCabinet(hfdi: HFDI; hf: Integer; pfdici: PFDICABINETINFO): WIN_BOOL; cdecl;
  1654. begin
  1655.     Result := pFDIIsCabinet(hfdi, hf, pfdici);
  1656. end;
  1657.  
  1658. function FDICopy(hfdi: HFDI; pszCabinet: PAnsiChar; pszCabPath: PAnsiChar;
  1659.     flags: Integer; pfnfdin: PFNFDINOTIFY; pfnfdid: PFNFDIDECRYPT;
  1660.     pvUser: PVoid): WIN_BOOL; cdecl;
  1661. begin
  1662.     Result := pFDICopy(hfdi, pszCabinet, pszCabPath, flags, pfnfdin,
  1663.         pfnfdid, pvUser);
  1664. end;
  1665.  
  1666. function FDIDestroy(hfdi: HFDI): WIN_BOOL; cdecl;
  1667. begin
  1668.     Result := pFDIDestroy(hfdi);
  1669. end;
  1670.  
  1671. initialization
  1672.  
  1673. finalization
  1674.     if hCabModule <> 0 then
  1675.         FreeLibrary(hCabModule);
  1676.  
  1677. {$ENDIF}
  1678.  
  1679. end.
  1680.  
  1681.