home *** CD-ROM | disk | FTP | other *** search
/ Chip 2002 June / Chip_2002-06_cd1.bin / zkuste / delphi / kompon / d56 / CABD.ZIP / Code / CabIntf.pas next >
Encoding:
Pascal/Delphi Source File  |  2002-03-19  |  63.1 KB  |  1,607 lines

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