Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1068 lines
45 KiB

  1. /*
  2. * FDI.H -- File Decompression Interface
  3. *
  4. * Copyright (C) Microsoft Corporation 1993-1997
  5. * All Rights Reserved.
  6. */
  7. #ifdef __cplusplus
  8. extern "C" {
  9. #endif
  10. #ifndef INCLUDED_TYPES_FCI_FDI
  11. #define INCLUDED_TYPES_FCI_FDI 1
  12. #ifndef HUGE
  13. #define HUGE
  14. #endif
  15. #ifndef FAR
  16. #define FAR
  17. #endif
  18. #ifndef DIAMONDAPI
  19. #define DIAMONDAPI __cdecl
  20. #endif
  21. //** Specify structure packing explicitly for clients of FDI
  22. #pragma pack(4)
  23. //** Don't redefine types defined in Win16 WINDOWS.H (_INC_WINDOWS)
  24. // or Win32 WINDOWS.H (_WINDOWS_)
  25. //
  26. #if !defined(_INC_WINDOWS) && !defined(_WINDOWS_)
  27. typedef int BOOL; /* f */
  28. typedef unsigned char BYTE; /* b */
  29. typedef unsigned int UINT; /* ui */
  30. typedef unsigned short USHORT; /* us */
  31. typedef unsigned long ULONG; /* ul */
  32. #endif // _INC_WINDOWS
  33. typedef unsigned long CHECKSUM; /* csum */
  34. typedef unsigned long UOFF; /* uoff - uncompressed offset */
  35. typedef unsigned long COFF; /* coff - cabinet file offset */
  36. #ifndef TRUE
  37. #define TRUE 1
  38. #endif
  39. #ifndef FALSE
  40. #define FALSE 0
  41. #endif
  42. #ifndef NULL
  43. #define NULL 0
  44. #endif
  45. #ifdef _DEBUG
  46. // don't hide statics from map during debugging
  47. #define STATIC
  48. #else // !DEBUG
  49. #define STATIC static
  50. #endif // !DEBUG
  51. #define CB_MAX_CHUNK 32768U
  52. #define CB_MAX_DISK 0x7ffffffL
  53. #define CB_MAX_FILENAME 256
  54. #define CB_MAX_CABINET_NAME 256
  55. #define CB_MAX_CAB_PATH 256
  56. #define CB_MAX_DISK_NAME 256
  57. /*** tcompXXX - Compression types
  58. *
  59. * These are passed to FCIAddFile(), and are also stored in the CFFOLDER
  60. * structures in cabinet files.
  61. *
  62. * NOTE: We reserve bits for the TYPE, QUANTUM_LEVEL, and QUANTUM_MEM
  63. * to provide room for future expansion. Since this value is stored
  64. * in the CFDATA records in the cabinet file, we don't want to
  65. * have to change the format for existing compression configurations
  66. * if we add new ones in the future. This will allows us to read
  67. * old cabinet files in the future.
  68. */
  69. typedef unsigned short TCOMP; /* tcomp */
  70. #define tcompMASK_TYPE 0x000F // Mask for compression type
  71. #define tcompTYPE_NONE 0x0000 // No compression
  72. #define tcompTYPE_MSZIP 0x0001 // MSZIP
  73. #define tcompTYPE_QUANTUM 0x0002 // Quantum
  74. #define tcompTYPE_LZX 0x0003 // LZX
  75. #define tcompBAD 0x000F // Unspecified compression type
  76. #define tcompMASK_LZX_WINDOW 0x1F00 // Mask for LZX Compression Memory
  77. #define tcompLZX_WINDOW_LO 0x0F00 // Lowest LZX Memory (15)
  78. #define tcompLZX_WINDOW_HI 0x1500 // Highest LZX Memory (21)
  79. #define tcompSHIFT_LZX_WINDOW 8 // Amount to shift over to get int
  80. #define tcompMASK_QUANTUM_LEVEL 0x00F0 // Mask for Quantum Compression Level
  81. #define tcompQUANTUM_LEVEL_LO 0x0010 // Lowest Quantum Level (1)
  82. #define tcompQUANTUM_LEVEL_HI 0x0070 // Highest Quantum Level (7)
  83. #define tcompSHIFT_QUANTUM_LEVEL 4 // Amount to shift over to get int
  84. #define tcompMASK_QUANTUM_MEM 0x1F00 // Mask for Quantum Compression Memory
  85. #define tcompQUANTUM_MEM_LO 0x0A00 // Lowest Quantum Memory (10)
  86. #define tcompQUANTUM_MEM_HI 0x1500 // Highest Quantum Memory (21)
  87. #define tcompSHIFT_QUANTUM_MEM 8 // Amount to shift over to get int
  88. #define tcompMASK_RESERVED 0xE000 // Reserved bits (high 3 bits)
  89. #define CompressionTypeFromTCOMP(tc) \
  90. ((tc) & tcompMASK_TYPE)
  91. #define CompressionLevelFromTCOMP(tc) \
  92. (((tc) & tcompMASK_QUANTUM_LEVEL) >> tcompSHIFT_QUANTUM_LEVEL)
  93. #define CompressionMemoryFromTCOMP(tc) \
  94. (((tc) & tcompMASK_QUANTUM_MEM) >> tcompSHIFT_QUANTUM_MEM)
  95. #define TCOMPfromTypeLevelMemory(t,l,m) \
  96. (((m) << tcompSHIFT_QUANTUM_MEM ) | \
  97. ((l) << tcompSHIFT_QUANTUM_LEVEL) | \
  98. ( t ))
  99. #define LZXCompressionWindowFromTCOMP(tc) \
  100. (((tc) & tcompMASK_LZX_WINDOW) >> tcompSHIFT_LZX_WINDOW)
  101. #define TCOMPfromLZXWindow(w) \
  102. (((w) << tcompSHIFT_LZX_WINDOW ) | \
  103. ( tcompTYPE_LZX ))
  104. //** Revert to default structure packing
  105. #pragma pack()
  106. #endif // !INCLUDED_TYPES_FCI_FDI
  107. /*
  108. * Concepts:
  109. * A *cabinet* file contains one or more *folders*. A folder contains
  110. * one or more (pieces of) *files*. A folder is by definition a
  111. * decompression unit, i.e., to extract a file from a folder, all of
  112. * the data from the start of the folder up through and including the
  113. * desired file must be read and decompressed.
  114. *
  115. * A folder can span one (or more) cabinet boundaries, and by implication
  116. * a file can also span one (or more) cabinet boundaries. Indeed, more
  117. * than one file can span a cabinet boundary, since FCI concatenates
  118. * files together into a single data stream before compressing (actually,
  119. * at most one file will span any one cabinet boundary, but FCI does
  120. * not know which file this is, since the mapping from uncompressed bytes
  121. * to compressed bytes is pretty obscure. Also, since FCI compresses
  122. * in blocks of 32K (at present), any files with data in a 32K block that
  123. * spans a cabinet boundary require FDI to read both cabinet files
  124. * to get the two halves of the compressed block).
  125. *
  126. * Overview:
  127. * The File Decompression Interface is used to simplify the reading of
  128. * cabinet files. A setup program will proceed in a manner very
  129. * similar to the pseudo code below. An FDI context is created, the
  130. * setup program calls FDICopy() for each cabinet to be processed. For
  131. * each file in the cabinet, FDICopy() calls a notification callback
  132. * routine, asking the setup program if the file should be copied.
  133. * This call-back approach is great because it allows the cabinet file
  134. * to be read and decompressed in an optimal manner, and also makes FDI
  135. * independent of the run-time environment -- FDI makes *no* C run-time
  136. * calls whatsoever. All memory allocation and file I/O functions are
  137. * passed into FDI by the client.
  138. *
  139. * main(...)
  140. * {
  141. * // Read INF file to construct list of desired files.
  142. * // Ideally, these would be sorted in the same order as the
  143. * // files appear in the cabinets, so that you can just walk
  144. * // down the list in response to fdintCOPY_FILE notifications.
  145. *
  146. * // Construct list of required cabinets.
  147. *
  148. * hfdi = FDICreate(...); // Create FDI context
  149. * For (cabinet in List of Cabinets) {
  150. * FDICopy(hfdi,cabinet,fdiNotify,...); // Process each cabinet
  151. * }
  152. * FDIDestroy(hfdi);
  153. * ...
  154. * }
  155. *
  156. * // Notification callback function
  157. * fdiNotify(fdint,...)
  158. * {
  159. * If (User Aborted) // Permit cancellation
  160. * if (fdint == fdintCLOSE_FILE_INFO)
  161. * close open file
  162. * return -1;
  163. * switch (fdint) {
  164. * case fdintCOPY_FILE: // File to copy, maybe
  165. * // Check file against list of desired files
  166. * if want to copy file
  167. * open destination file and return handle
  168. * else
  169. * return NULL; // Skip file
  170. * case fdintCLOSE_FILE_INFO:
  171. * close file
  172. * set date, time, and attributes
  173. *
  174. * case fdintNEXT_CABINET:
  175. * if not an error callback
  176. * Tell FDI to use suggested directory name
  177. * else
  178. * Tell user what the problem was, and prompt
  179. * for a new disk and/or path.
  180. * if user aborts
  181. * Tell FDI to abort
  182. * else
  183. * return to FDI to try another cabinet
  184. *
  185. * default:
  186. * return 0; // more messages may be defined
  187. * ...
  188. * }
  189. *
  190. * Error Handling Suggestions:
  191. * Since you the client have passed in *all* of the functions that
  192. * FDI uses to interact with the "outside" world, you are in prime
  193. * position to understand and deal with errors.
  194. *
  195. * The general philosophy of FDI is to pass all errors back up to
  196. * the client. FDI returns fairly generic error codes in the case
  197. * where one of the callback functions (PFNOPEN, PFNREAD, etc.) fail,
  198. * since it assumes that the callback function will save enough
  199. * information in a static/global so that when FDICopy() returns
  200. * fail, the client can examine this information and report enough
  201. * detail about the problem that the user can take corrective action.
  202. *
  203. * For very specific errors (CORRUPT_CABINET, for example), FDI returns
  204. * very specific error codes.
  205. *
  206. * THE BEST POLICY IS FOR YOUR CALLBACK ROUTINES TO AVOID RETURNING
  207. * ERRORS TO FDI!
  208. *
  209. * Examples:
  210. * (1) If the disk is getting full, instead of returning an error
  211. * from your PFNWRITE function, you should -- inside your
  212. * PFNWRITE function -- put up a dialog telling the user to free
  213. * some disk space.
  214. * (2) When you get the fdintNEXT_CABINET notification, you should
  215. * verify that the cabinet you return is the correct one (call
  216. * FDIIsCabinet(), and make sure the setID matches the one for
  217. * the current cabinet specified in the fdintCABINET_INFO, and
  218. * that the disk number is one greater.
  219. *
  220. * NOTE: FDI will continue to call fdintNEXT_CABINET until it
  221. * gets the cabinet it wants, or until you return -1
  222. * to abort the FDICopy() call.
  223. *
  224. * The documentation below on the FDI error codes provides explicit
  225. * guidance on how to avoid each error.
  226. *
  227. * If you find you must return a failure to FDI from one of your
  228. * callback functions, then FDICopy() frees all resources it allocated
  229. * and closes all files. If you can figure out how to overcome the
  230. * problem, you can call FDICopy() again on the last cabinet, and
  231. * skip any files that you already copied. But, note that FDI does
  232. * *not* maintain any state between FDICopy() calls, other than possibly
  233. * memory allocated for the decompressor.
  234. *
  235. * See FDIERROR for details on FDI error codes and recommended actions.
  236. *
  237. *
  238. * Progress Indicator Suggestions:
  239. * As above, all of the file I/O functions are supplied by you. So,
  240. * updating a progress indicator is very simple. You keep track of
  241. * the target files handles you have opened, along with the uncompressed
  242. * size of the target file. When you see writes to the handle of a
  243. * target file, you use the write count to update your status!
  244. * Since this method is available, there is no separate callback from
  245. * FDI just for progess indication.
  246. */
  247. #ifndef INCLUDED_FDI
  248. #define INCLUDED_FDI 1
  249. //** Specify structure packing explicitly for clients of FDI
  250. #pragma pack(4)
  251. /*** FDIERROR - Error codes returned in erf.erfOper field
  252. *
  253. * In general, FDI will only fail if one of the passed in memory or
  254. * file I/O functions fails. Other errors are pretty unlikely, and are
  255. * caused by corrupted cabinet files, passing in a file which is not a
  256. * cabinet file, or cabinet files out of order.
  257. *
  258. * Description: Summary of error.
  259. * Cause: List of possible causes of this error.
  260. * Response: How client might respond to this error, or avoid it in
  261. * the first place.
  262. */
  263. typedef enum {
  264. FDIERROR_NONE,
  265. // Description: No error
  266. // Cause: Function was successfull.
  267. // Response: Keep going!
  268. FDIERROR_CABINET_NOT_FOUND,
  269. // Description: Cabinet not found
  270. // Cause: Bad file name or path passed to FDICopy(), or returned
  271. // to fdintNEXT_CABINET.
  272. // Response: To prevent this error, validate the existence of the
  273. // the cabinet *before* passing the path to FDI.
  274. FDIERROR_NOT_A_CABINET,
  275. // Description: Cabinet file does not have the correct format
  276. // Cause: File passed to to FDICopy(), or returned to
  277. // fdintNEXT_CABINET, is too small to be a cabinet file,
  278. // or does not have the cabinet signature in its first
  279. // four bytes.
  280. // Response: To prevent this error, call FDIIsCabinet() to check a
  281. // cabinet before calling FDICopy() or returning the
  282. // cabinet path to fdintNEXT_CABINET.
  283. FDIERROR_UNKNOWN_CABINET_VERSION,
  284. // Description: Cabinet file has an unknown version number.
  285. // Cause: File passed to to FDICopy(), or returned to
  286. // fdintNEXT_CABINET, has what looks like a cabinet file
  287. // header, but the version of the cabinet file format
  288. // is not one understood by this version of FDI. The
  289. // erf.erfType field is filled in with the version number
  290. // found in the cabinet file.
  291. // Response: To prevent this error, call FDIIsCabinet() to check a
  292. // cabinet before calling FDICopy() or returning the
  293. // cabinet path to fdintNEXT_CABINET.
  294. FDIERROR_CORRUPT_CABINET,
  295. // Description: Cabinet file is corrupt
  296. // Cause: FDI returns this error any time it finds a problem
  297. // with the logical format of a cabinet file, and any
  298. // time one of the passed-in file I/O calls fails when
  299. // operating on a cabinet (PFNOPEN, PFNSEEK, PFNREAD,
  300. // or PFNCLOSE). The client can distinguish these two
  301. // cases based upon whether the last file I/O call
  302. // failed or not.
  303. // Response: Assuming this is not a real corruption problem in
  304. // a cabinet file, the file I/O functions could attempt
  305. // to do retries on failure (for example, if there is a
  306. // temporary network connection problem). If this does
  307. // not work, and the file I/O call has to fail, then the
  308. // FDI client will have to clean up and call the
  309. // FDICopy() function again.
  310. FDIERROR_ALLOC_FAIL,
  311. // Description: Could not allocate enough memory
  312. // Cause: FDI tried to allocate memory with the PFNALLOC
  313. // function, but it failed.
  314. // Response: If possible, PFNALLOC should take whatever steps
  315. // are possible to allocate the memory requested. If
  316. // memory is not immediately available, it might post a
  317. // dialog asking the user to free memory, for example.
  318. // Note that the bulk of FDI's memory allocations are
  319. // made at FDICreate() time and when the first cabinet
  320. // file is opened during FDICopy().
  321. FDIERROR_BAD_COMPR_TYPE,
  322. // Description: Unknown compression type in a cabinet folder
  323. // Cause: [Should never happen.] A folder in a cabinet has an
  324. // unknown compression type. This is probably caused by
  325. // a mismatch between the version of FCI.LIB used to
  326. // create the cabinet and the FDI.LIB used to read the
  327. // cabinet.
  328. // Response: Abort.
  329. FDIERROR_MDI_FAIL,
  330. // Description: Failure decompressing data from a cabinet file
  331. // Cause: The decompressor found an error in the data coming
  332. // from the file cabinet. The cabinet file was corrupted.
  333. // [11-Apr-1994 bens When checksuming is turned on, this
  334. // error should never occur.]
  335. // Response: Probably should abort; only other choice is to cleanup
  336. // and call FDICopy() again, and hope there was some
  337. // intermittent data error that will not reoccur.
  338. FDIERROR_TARGET_FILE,
  339. // Description: Failure writing to target file
  340. // Cause: FDI returns this error any time it gets an error back
  341. // from one of the passed-in file I/O calls fails when
  342. // writing to a file being extracted from a cabinet.
  343. // Response: To avoid or minimize this error, the file I/O functions
  344. // could attempt to avoid failing. A common cause might
  345. // be disk full -- in this case, the PFNWRITE function
  346. // could have a check for free space, and put up a dialog
  347. // asking the user to free some disk space.
  348. FDIERROR_RESERVE_MISMATCH,
  349. // Description: Cabinets in a set do not have the same RESERVE sizes
  350. // Cause: [Should never happen]. FDI requires that the sizes of
  351. // the per-cabinet, per-folder, and per-data block
  352. // RESERVE sections be consistent across all the cabinets
  353. // in a set.
  354. // Response: Abort.
  355. FDIERROR_WRONG_CABINET,
  356. // Description: Cabinet returned on fdintNEXT_CABINET is incorrect
  357. // Cause: NOTE: THIS ERROR IS NEVER RETURNED BY FDICopy()!
  358. // Rather, FDICopy() keeps calling the fdintNEXT_CABINET
  359. // callback until either the correct cabinet is specified,
  360. // or you return ABORT.
  361. // When FDICopy() is extracting a file that crosses a
  362. // cabinet boundary, it calls fdintNEXT_CABINET to ask
  363. // for the path to the next cabinet. Not being very
  364. // trusting, FDI then checks to make sure that the
  365. // correct continuation cabinet was supplied! It does
  366. // this by checking the "setID" and "iCabinet" fields
  367. // in the cabinet. When MAKECAB.EXE creates a set of
  368. // cabinets, it constructs the "setID" using the sum
  369. // of the bytes of all the destination file names in
  370. // the cabinet set. FDI makes sure that the 16-bit
  371. // setID of the continuation cabinet matches the
  372. // cabinet file just processed. FDI then checks that
  373. // the cabinet number (iCabinet) is one more than the
  374. // cabinet number for the cabinet just processed.
  375. // Response: You need code in your fdintNEXT_CABINET (see below)
  376. // handler to do retries if you get recalled with this
  377. // error. See the sample code (EXTRACT.C) to see how
  378. // this should be handled.
  379. FDIERROR_USER_ABORT,
  380. // Description: FDI aborted.
  381. // Cause: An FDI callback returnd -1 (usually).
  382. // Response: Up to client.
  383. } FDIERROR;
  384. /*** ERF - Error structure
  385. *
  386. * This structure returns error information from FCI/FDI. The caller should
  387. * not modify this structure.
  388. */
  389. typedef struct {
  390. FDIERROR erfOper; // FCI/FDI error code -- see FDIERROR_XXX
  391. // and FCIERR_XXX equates for details.
  392. int erfType; // Optional error value filled in by FCI/FDI.
  393. // For FCI, this is usually the C run-time
  394. // *errno* value.
  395. BOOL fError; // TRUE => error present
  396. } ERF; /* erf */
  397. typedef ERF FAR *PERF; /* perf */
  398. /*
  399. * FAT file attribute flag used by FCI/FDI to indicate that
  400. * the filename in the CAB is a UTF string
  401. */
  402. #ifndef _A_NAME_IS_UTF
  403. #define _A_NAME_IS_UTF 0x80
  404. #endif
  405. /*
  406. * FAT file attribute flag used by FCI/FDI to indicate that
  407. * the file should be executed after extraction
  408. */
  409. #ifndef _A_EXEC
  410. #define _A_EXEC 0x40
  411. #endif
  412. /*** HFDI - Handle to an FDI context
  413. *
  414. * FDICreate() creates this, and it must be passed to all other FDI
  415. * functions.
  416. */
  417. typedef void FAR *HFDI; /* hfdi */
  418. /*** FDICABINETINFO - Information about a cabinet
  419. *
  420. */
  421. typedef struct {
  422. long cbCabinet; // Total length of cabinet file
  423. USHORT cFolders; // Count of folders in cabinet
  424. USHORT cFiles; // Count of files in cabinet
  425. USHORT setID; // Cabinet set ID
  426. USHORT iCabinet; // Cabinet number in set (0 based)
  427. BOOL fReserve; // TRUE => RESERVE present in cabinet
  428. BOOL hasprev; // TRUE => Cabinet is chained prev
  429. BOOL hasnext; // TRUE => Cabinet is chained next
  430. } FDICABINETINFO; /* fdici */
  431. typedef FDICABINETINFO FAR *PFDICABINETINFO; /* pfdici */
  432. /*** FDIDECRYPTTYPE - PFNFDIDECRYPT command types
  433. *
  434. */
  435. typedef enum {
  436. fdidtNEW_CABINET, // New cabinet
  437. fdidtNEW_FOLDER, // New folder
  438. fdidtDECRYPT, // Decrypt a data block
  439. } FDIDECRYPTTYPE; /* fdidt */
  440. /*** FDIDECRYPT - Data for PFNFDIDECRYPT function
  441. *
  442. */
  443. typedef struct {
  444. FDIDECRYPTTYPE fdidt; // Command type (selects union below)
  445. void FAR *pvUser; // Decryption context
  446. union {
  447. struct { // fdidtNEW_CABINET
  448. void FAR *pHeaderReserve; // RESERVE section from CFHEADER
  449. USHORT cbHeaderReserve; // Size of pHeaderReserve
  450. USHORT setID; // Cabinet set ID
  451. int iCabinet; // Cabinet number in set (0 based)
  452. } cabinet;
  453. struct { // fdidtNEW_FOLDER
  454. void FAR *pFolderReserve; // RESERVE section from CFFOLDER
  455. USHORT cbFolderReserve; // Size of pFolderReserve
  456. USHORT iFolder; // Folder number in cabinet (0 based)
  457. } folder;
  458. struct { // fdidtDECRYPT
  459. void FAR *pDataReserve; // RESERVE section from CFDATA
  460. USHORT cbDataReserve; // Size of pDataReserve
  461. void FAR *pbData; // Data buffer
  462. USHORT cbData; // Size of data buffer
  463. BOOL fSplit; // TRUE if this is a split data block
  464. USHORT cbPartial; // 0 if this is not a split block, or
  465. // the first piece of a split block;
  466. // Greater than 0 if this is the
  467. // second piece of a split block.
  468. } decrypt;
  469. };
  470. } FDIDECRYPT; /* fdid */
  471. typedef FDIDECRYPT FAR *PFDIDECRYPT; /* pfdid */
  472. /*** FNALLOC - Memory Allocation
  473. * FNFREE - Memory Free
  474. *
  475. * These are modeled after the C run-time routines malloc() and free()
  476. * FDI expects error handling to be identical to these C run-time routines.
  477. *
  478. * As long as you faithfully copy the semantics of malloc() and free(),
  479. * you can supply any functions you like!
  480. *
  481. * WARNING: You should never assume anything about the sequence of
  482. * PFNALLOC and PFNFREE calls -- incremental releases of
  483. * FDI may have radically different numbers of
  484. * PFNALLOC calls and allocation sizes!
  485. */
  486. //** Memory functions for FDI
  487. typedef void HUGE * (FAR DIAMONDAPI *PFNALLOC)(ULONG cb); /* pfna */
  488. #define FNALLOC(fn) void HUGE * FAR DIAMONDAPI fn(ULONG cb)
  489. typedef void (FAR DIAMONDAPI *PFNFREE)(void HUGE *pv); /* pfnf */
  490. #define FNFREE(fn) void FAR DIAMONDAPI fn(void HUGE *pv)
  491. /*** PFNOPEN - File I/O callbacks for FDI
  492. * PFNREAD
  493. * PFNWRITE
  494. * PFNCLOSE
  495. * PFNSEEK
  496. *
  497. * These are modeled after the C run-time routines _open, _read,
  498. * _write, _close, and _lseek. The values for the PFNOPEN oflag
  499. * and pmode calls are those defined for _open. FDI expects error
  500. * handling to be identical to these C run-time routines.
  501. *
  502. * As long as you faithfully copy these aspects, you can supply
  503. * any functions you like!
  504. *
  505. * WARNING: You should never assume you know what file is being
  506. * opened at any one point in time! FDI will usually
  507. * stick to opening cabinet files, but it is possible
  508. * that in a future implementation it may open temporary
  509. * files or open cabinet files in a different order.
  510. *
  511. * Notes for Memory Mapped File fans:
  512. * You can write wrapper routines to allow FDI to work on memory
  513. * mapped files. You'll have to create your own "handle" type so that
  514. * you can store the base memory address of the file and the current
  515. * seek position, and then you'll allocate and fill in one of these
  516. * structures and return a pointer to it in response to the PFNOPEN
  517. * call and the fdintCOPY_FILE call. Your PFNREAD and PFNWRITE
  518. * functions will do memcopy(), and update the seek position in your
  519. * "handle" structure. PFNSEEK will just change the seek position
  520. * in your "handle" structure.
  521. */
  522. //** File I/O functions for FDI
  523. typedef int (FAR DIAMONDAPI *PFNOPEN) (char FAR *pszFile, int oflag, int pmode);
  524. typedef UINT (FAR DIAMONDAPI *PFNREAD) (int hf, void FAR *pv, UINT cb);
  525. typedef UINT (FAR DIAMONDAPI *PFNWRITE)(int hf, void FAR *pv, UINT cb);
  526. typedef int (FAR DIAMONDAPI *PFNCLOSE)(int hf);
  527. typedef long (FAR DIAMONDAPI *PFNSEEK) (int hf, long dist, int seektype);
  528. #define FNOPEN(fn) int FAR DIAMONDAPI fn(char FAR *pszFile, int oflag, int pmode)
  529. #define FNREAD(fn) UINT FAR DIAMONDAPI fn(int hf, void FAR *pv, UINT cb)
  530. #define FNWRITE(fn) UINT FAR DIAMONDAPI fn(int hf, void FAR *pv, UINT cb)
  531. #define FNCLOSE(fn) int FAR DIAMONDAPI fn(int hf)
  532. #define FNSEEK(fn) long FAR DIAMONDAPI fn(int hf, long dist, int seektype)
  533. /*** PFNFDIDECRYPT - FDI Decryption callback
  534. *
  535. * If this function is passed on the FDICopy() call, then FDI calls it
  536. * at various times to update the decryption state and to decrypt FCDATA
  537. * blocks.
  538. *
  539. * Common Entry Conditions:
  540. * pfdid->fdidt - Command type
  541. * pfdid->pvUser - pvUser value from FDICopy() call
  542. *
  543. * fdidtNEW_CABINET: //** Notification of a new cabinet
  544. * Entry:
  545. * pfdid->cabinet.
  546. * pHeaderReserve - RESERVE section from CFHEADER
  547. * cbHeaderReserve - Size of pHeaderReserve
  548. * setID - Cabinet set ID
  549. * iCabinet - Cabinet number in set (0 based)
  550. * Exit-Success:
  551. * returns anything but -1;
  552. * Exit-Failure:
  553. * returns -1; FDICopy() is aborted.
  554. * Notes:
  555. * (1) This call allows the decryption code to pick out any information
  556. * from the cabinet header reserved area (placed there by DIACRYPT)
  557. * needed to perform decryption. If there is no such information,
  558. * this call would presumably be ignored.
  559. * (2) This call is made very soon after fdintCABINET_INFO.
  560. *
  561. * fdidtNEW_FOLDER: //** Notification of a new folder
  562. * Entry:
  563. * pfdid->folder.
  564. * pFolderReserve - RESERVE section from CFFOLDER
  565. * cbFolderReserve - Size of pFolderReserve
  566. * iFolder - Folder number in cabinet (0 based)
  567. * Exit-Success:
  568. * returns anything but -1;
  569. * Exit-Failure:
  570. * returns -1; FDICopy() is aborted.
  571. * Notes:
  572. * This call allows the decryption code to pick out any information
  573. * from the folder reserved area (placed there by DIACRYPT) needed
  574. * to perform decryption. If there is no such information, this
  575. * call would presumably be ignored.
  576. *
  577. * fdidtDECRYPT: //** Decrypt a data buffer
  578. * Entry:
  579. * pfdid->folder.
  580. * pDataReserve - RESERVE section for this CFDATA block
  581. * cbDataReserve - Size of pDataReserve
  582. * pbData - Data buffer
  583. * cbData - Size of data buffer
  584. * fSplit - TRUE if this is a split data block
  585. * cbPartial - 0 if this is not a split block, or the first
  586. * piece of a split block; Greater than 0 if
  587. * this is the second piece of a split block.
  588. * Exit-Success:
  589. * returns TRUE;
  590. * Exit-Failure:
  591. * returns FALSE; error during decrypt
  592. * returns -1; FDICopy() is aborted.
  593. * Notes:
  594. * FCI will split CFDATA blocks across cabinet boundaries if
  595. * necessary. To provide maximum flexibility, FDI will call the
  596. * fdidtDECRYPT function twice on such split blocks, once when
  597. * the first portion is read, and again when the second portion
  598. * is read. And, of course, most data blocks will not be split.
  599. * So, there are three cases:
  600. *
  601. * 1) fSplit == FALSE
  602. * You have the entire data block, so decrypt it.
  603. *
  604. * 2) fSplit == TRUE, cbPartial == 0
  605. * This is the first portion of a split data block, so cbData
  606. * is the size of this portion. You can either choose to decrypt
  607. * this piece, or ignore this call and decrypt the full CFDATA
  608. * block on the next (second) fdidtDECRYPT call.
  609. *
  610. * 3) fSplit == TRUE, cbPartial > 0
  611. * This is the second portion of a split data block (indeed,
  612. * cbPartial will have the same value as cbData did on the
  613. * immediately preceeding fdidtDECRYPT call!). If you decrypted
  614. * the first portion on the first call, then you can decrypt the
  615. * second portion now. If you ignored the first call, then you
  616. * can decrypt the entire buffer.
  617. * NOTE: pbData points to the second portion of the split data
  618. * block in this case, *not* the entire data block. If
  619. * you want to wait until the second piece to decrypt the
  620. * *entire* block, pbData-cbPartial is the address of the
  621. * start of the whole block, and cbData+cbPartial is its
  622. * size.
  623. */
  624. typedef int (FAR DIAMONDAPI *PFNFDIDECRYPT)(PFDIDECRYPT pfdid); /* pfnfdid */
  625. #define FNFDIDECRYPT(fn) int FAR DIAMONDAPI fn(PFDIDECRYPT pfdid)
  626. /*** FDINOTIFICATION - Notification structure for PFNFDINOTIFY
  627. *
  628. * See the FDINOTIFICATIONTYPE definition for information on usage and
  629. * meaning of these fields.
  630. */
  631. typedef struct {
  632. // long fields
  633. long cb;
  634. char FAR *psz1;
  635. char FAR *psz2;
  636. char FAR *psz3; // Points to a 256 character buffer
  637. void FAR *pv; // Value for client
  638. // int fields
  639. int hf;
  640. // short fields
  641. USHORT date;
  642. USHORT time;
  643. USHORT attribs;
  644. USHORT setID; // Cabinet set ID
  645. USHORT iCabinet; // Cabinet number (0-based)
  646. USHORT iFolder; // Folder number (0-based)
  647. FDIERROR fdie;
  648. } FDINOTIFICATION, FAR *PFDINOTIFICATION; /* fdin, pfdin */
  649. /*** FDINOTIFICATIONTYPE - FDICopy notification types
  650. *
  651. * The notification function for FDICopy can be called with the following
  652. * values for the fdint parameter. In all cases, the pfdin->pv field is
  653. * filled in with the value of the pvUser argument passed in to FDICopy().
  654. *
  655. * A typical sequence of calls will be something like this:
  656. * fdintCABINET_INFO // Info about the cabinet
  657. * fdintENUMERATE // Starting enumeration
  658. * fdintPARTIAL_FILE // Only if this is not the first cabinet, and
  659. * // one or more files were continued from the
  660. * // previous cabinet.
  661. * ...
  662. * fdintPARTIAL_FILE
  663. * fdintCOPY_FILE // The first file that starts in this cabinet
  664. * ...
  665. * fdintCOPY_FILE // Now let's assume you want this file...
  666. * // PFNWRITE called multiple times to write to this file.
  667. * fdintCLOSE_FILE_INFO // File done, set date/time/attributes
  668. *
  669. * fdintCOPY_FILE // Now let's assume you want this file...
  670. * // PFNWRITE called multiple times to write to this file.
  671. * fdintNEXT_CABINET // File was continued to next cabinet!
  672. * fdintCABINET_INFO // Info about the new cabinet
  673. * // PFNWRITE called multiple times to write to this file.
  674. * fdintCLOSE_FILE_INFO // File done, set date/time/attributes
  675. * ...
  676. * fdintENUMERATE // Ending enumeration
  677. *
  678. * fdintCABINET_INFO:
  679. * Called exactly once for each cabinet opened by FDICopy(), including
  680. * continuation cabinets opened due to file(s) spanning cabinet
  681. * boundaries. Primarily intended to permit EXTRACT.EXE to
  682. * automatically select the next cabinet in a cabinet sequence even if
  683. * not copying files that span cabinet boundaries.
  684. * Entry:
  685. * pfdin->psz1 = name of next cabinet
  686. * pfdin->psz2 = name of next disk
  687. * pfdin->psz3 = cabinet path name
  688. * pfdin->setID = cabinet set ID (a random 16-bit number)
  689. * pfdin->iCabinet = Cabinet number within cabinet set (0-based)
  690. * Exit-Success:
  691. * Return anything but -1
  692. * Exit-Failure:
  693. * Returns -1 => Abort FDICopy() call
  694. * Notes:
  695. * This call is made *every* time a new cabinet is examined by
  696. * FDICopy(). So if "foo2.cab" is examined because a file is
  697. * continued from "foo1.cab", and then you call FDICopy() again
  698. * on "foo2.cab", you will get *two* fdintCABINET_INFO calls all
  699. * told.
  700. *
  701. * fdintCOPY_FILE:
  702. * Called for each file that *starts* in the current cabinet, giving
  703. * the client the opportunity to request that the file be copied or
  704. * skipped.
  705. * Entry:
  706. * pfdin->psz1 = file name in cabinet
  707. * pfdin->cb = uncompressed size of file
  708. * pfdin->date = file date
  709. * pfdin->time = file time
  710. * pfdin->attribs = file attributes
  711. * pfdin->iFolder = file's folder index
  712. * Exit-Success:
  713. * Return non-zero file handle for destination file; FDI writes
  714. * data to this file use the PFNWRITE function supplied to FDICreate,
  715. * and then calls fdintCLOSE_FILE_INFO to close the file and set
  716. * the date, time, and attributes. NOTE: This file handle returned
  717. * must also be closeable by the PFNCLOSE function supplied to
  718. * FDICreate, since if an error occurs while writing to this handle,
  719. * FDI will use the PFNCLOSE function to close the file so that the
  720. * client may delete it.
  721. * Exit-Failure:
  722. * Returns 0 => Skip file, do not copy
  723. * Returns -1 => Abort FDICopy() call
  724. *
  725. * fdintCLOSE_FILE_INFO:
  726. * Called after all of the data has been written to a target file.
  727. * This function must close the file and set the file date, time,
  728. * and attributes.
  729. * Entry:
  730. * pfdin->psz1 = file name in cabinet
  731. * pfdin->hf = file handle
  732. * pfdin->date = file date
  733. * pfdin->time = file time
  734. * pfdin->attribs = file attributes
  735. * pfdin->iFolder = file's folder index
  736. * pfdin->cb = Run After Extract (0 - don't run, 1 Run)
  737. * Exit-Success:
  738. * Returns TRUE
  739. * Exit-Failure:
  740. * Returns FALSE, or -1 to abort;
  741. *
  742. * IMPORTANT NOTE IMPORTANT:
  743. * pfdin->cb is overloaded to no longer be the size of
  744. * the file but to be a binary indicated run or not
  745. *
  746. * IMPORTANT NOTE:
  747. * FDI assumes that the target file was closed, even if this
  748. * callback returns failure. FDI will NOT attempt to use
  749. * the PFNCLOSE function supplied on FDICreate() to close
  750. * the file!
  751. *
  752. * fdintPARTIAL_FILE:
  753. * Called for files at the front of the cabinet that are CONTINUED
  754. * from a previous cabinet. This callback occurs only when FDICopy is
  755. * started on second or subsequent cabinet in a series that has files
  756. * continued from a previous cabinet.
  757. * Entry:
  758. * pfdin->psz1 = file name of file CONTINUED from a PREVIOUS cabinet
  759. * pfdin->psz2 = name of cabinet where file starts
  760. * pfdin->psz3 = name of disk where file starts
  761. * Exit-Success:
  762. * Return anything other than -1; enumeration continues
  763. * Exit-Failure:
  764. * Returns -1 => Abort FDICopy() call
  765. *
  766. * fdintENUMERATE:
  767. * Called once after a call to FDICopy() starts scanning a CAB's
  768. * CFFILE entries, and again when there are no more CFFILE entries.
  769. * If CAB spanning occurs, an additional call will occur after the
  770. * first spanned file is completed. If the pfdin->iFolder value is
  771. * changed from zero, additional calls will occur next time it reaches
  772. * zero. If iFolder is changed to zero, FDICopy will terminate, as if
  773. * there were no more CFFILE entries. Primarily intended to allow an
  774. * application with it's own file list to help FDI advance quickly to
  775. * a CFFILE entry of interest. Can also be used to allow an
  776. * application to determine the cb values for each file in the CAB.
  777. * Entry:
  778. * pfdin->cb = current CFFILE position
  779. * pfdin->iFolder = number of files remaining
  780. * pfdin->setID = current CAB's setID value
  781. * Exit-Don't Care:
  782. * Don't change anything.
  783. * Return anything but -1.
  784. * Exit-Forcing a skip:
  785. * pfdin->cb = desired CFFILE position
  786. * pfdin->iFolder = desired # of files remaining
  787. * Return anything but -1.
  788. * Exit-Stop:
  789. * pfdin->iFolder = set to 0
  790. * Return anything but -1.
  791. * Exit-Failure:
  792. * Return -1 => Abort FDICopy call ("user aborted".)
  793. * Notes:
  794. * This call can be ignored by applications which want normal file
  795. * searching. The application can adjust the supplied values to
  796. * force FDICopy() to continue it's search at another location, or
  797. * to force FDICopy() to terminate the search, by setting iFolder to 0.
  798. * (FDICopy() will report no error when terminated this way.)
  799. * FDI has no means to verify the supplied cb or iFolder values.
  800. * Arbitrary values are likely to cause undesirable results. An
  801. * application should cross-check pfdin->setID to be certain the
  802. * external database is in sync with the CAB. Reverse-skips are OK
  803. * (but may be inefficient) unless fdintNEXT_CABINET has been called.
  804. *
  805. * fdintNEXT_CABINET:
  806. * This function is *only* called when fdintCOPY_FILE was told to copy
  807. * a file in the current cabinet that is continued to a subsequent
  808. * cabinet file. It is important that the cabinet path name (psz3)
  809. * be validated before returning! This function should ensure that
  810. * the cabinet exists and is readable before returning. So, this
  811. * is the function that should, for example, issue a disk change
  812. * prompt and make sure the cabinet file exists.
  813. *
  814. * When this function returns to FDI, FDI will check that the setID
  815. * and iCabinet match the expected values for the next cabinet.
  816. * If not, FDI will continue to call this function until the correct
  817. * cabinet file is specified, or until this function returns -1 to
  818. * abort the FDICopy() function. pfdin->fdie is set to
  819. * FDIERROR_WRONG_CABINET to indicate this case.
  820. *
  821. * If you *haven't* ensured that the cabinet file is present and
  822. * readable, or the cabinet file has been damaged, pfdin->fdie will
  823. * receive other appropriate error codes:
  824. *
  825. * FDIERROR_CABINET_NOT_FOUND
  826. * FDIERROR_NOT_A_CABINET
  827. * FDIERROR_UNKNOWN_CABINET_VERSION
  828. * FDIERROR_CORRUPT_CABINET
  829. * FDIERROR_BAD_COMPR_TYPE
  830. * FDIERROR_RESERVE_MISMATCH
  831. * FDIERROR_WRONG_CABINET
  832. *
  833. * Entry:
  834. * pfdin->psz1 = name of next cabinet where current file is continued
  835. * pfdin->psz2 = name of next disk where current file is continued
  836. * pfdin->psz3 = cabinet path name; FDI concatenates psz3 with psz1
  837. * to produce the fully-qualified path for the cabinet
  838. * file. The 256-byte buffer pointed at by psz3 may
  839. * be modified, but psz1 may not!
  840. * pfdin->fdie = FDIERROR_WRONG_CABINET if the previous call to
  841. * fdintNEXT_CABINET specified a cabinet file that
  842. * did not match the setID/iCabinet that was expected.
  843. * Exit-Success:
  844. * Return anything but -1
  845. * Exit-Failure:
  846. * Returns -1 => Abort FDICopy() call
  847. * Notes:
  848. * This call is almost always made when a target file is open and
  849. * being written to, and the next cabinet is needed to get more
  850. * data for the file.
  851. */
  852. typedef enum {
  853. fdintCABINET_INFO, // General information about cabinet
  854. fdintPARTIAL_FILE, // First file in cabinet is continuation
  855. fdintCOPY_FILE, // File to be copied
  856. fdintCLOSE_FILE_INFO, // close the file, set relevant info
  857. fdintNEXT_CABINET, // File continued to next cabinet
  858. fdintENUMERATE, // Enumeration status
  859. } FDINOTIFICATIONTYPE; /* fdint */
  860. typedef int (FAR DIAMONDAPI *PFNFDINOTIFY)(FDINOTIFICATIONTYPE fdint,
  861. PFDINOTIFICATION pfdin); /* pfnfdin */
  862. #define FNFDINOTIFY(fn) int FAR DIAMONDAPI fn(FDINOTIFICATIONTYPE fdint, \
  863. PFDINOTIFICATION pfdin)
  864. /*** cpuType values for FDICreate()
  865. *
  866. * (Ignored by 32-bit FDI.)
  867. */
  868. #define cpuUNKNOWN (-1) /* FDI does detection */
  869. #define cpu80286 (0) /* '286 opcodes only */
  870. #define cpu80386 (1) /* '386 opcodes used */
  871. /*** FDICreate - Create an FDI context
  872. *
  873. * Entry:
  874. * pfnalloc
  875. * pfnfree
  876. * pfnopen
  877. * pfnread
  878. * pfnwrite
  879. * pfnclose
  880. * pfnlseek
  881. * cpuType - Select CPU type (auto-detect, 286, or 386+)
  882. * NOTE: For the 32-bit FDI.LIB, this parameter is ignored!
  883. * perf
  884. *
  885. * Exit-Success:
  886. * Returns non-NULL FDI context handle.
  887. *
  888. * Exit-Failure:
  889. * Returns NULL; perf filled in with error code
  890. *
  891. */
  892. HFDI FAR DIAMONDAPI FDICreate(PFNALLOC pfnalloc,
  893. PFNFREE pfnfree,
  894. PFNOPEN pfnopen,
  895. PFNREAD pfnread,
  896. PFNWRITE pfnwrite,
  897. PFNCLOSE pfnclose,
  898. PFNSEEK pfnseek,
  899. int cpuType,
  900. PERF perf);
  901. /*** FDIIsCabinet - Determines if file is a cabinet, returns info if it is
  902. *
  903. * Entry:
  904. * hfdi - Handle to FDI context (created by FDICreate())
  905. * hf - File handle suitable for PFNREAD/PFNSEEK, positioned
  906. * at offset 0 in the file to test.
  907. * pfdici - Buffer to receive info about cabinet if it is one.
  908. *
  909. * Exit-Success:
  910. * Returns TRUE; file is a cabinet, pfdici filled in.
  911. *
  912. * Exit-Failure:
  913. * Returns FALSE, file is not a cabinet; If an error occurred,
  914. * perf (passed on FDICreate call!) filled in with error.
  915. */
  916. BOOL FAR DIAMONDAPI FDIIsCabinet(HFDI hfdi,
  917. int hf,
  918. PFDICABINETINFO pfdici);
  919. /*** FDICopy - extracts files from a cabinet
  920. *
  921. * Entry:
  922. * hfdi - handle to FDI context (created by FDICreate())
  923. * pszCabinet - main name of cabinet file
  924. * pszCabPath - Path to cabinet file(s)
  925. * flags - Flags to modify behavior
  926. * pfnfdin - Notification function
  927. * pfnfdid - Decryption function (pass NULL if not used)
  928. * pvUser - User specified value to pass to notification function
  929. *
  930. * Exit-Success:
  931. * Returns TRUE;
  932. *
  933. * Exit-Failure:
  934. * Returns FALSE, perf (passed on FDICreate call!) filled in with
  935. * error.
  936. *
  937. * Notes:
  938. * (1) If FDICopy() fails while a target file is being written out, then
  939. * FDI will use the PFNCLOSE function to close the file handle for that
  940. * target file that was returned from the fdintCOPY_FILE notification.
  941. * The client application is then free to delete the target file, since
  942. * it will not be in a valid state (since there was an error while
  943. * writing it out).
  944. */
  945. BOOL FAR DIAMONDAPI FDICopy(HFDI hfdi,
  946. char FAR *pszCabinet,
  947. char FAR *pszCabPath,
  948. int flags,
  949. PFNFDINOTIFY pfnfdin,
  950. PFNFDIDECRYPT pfnfdid,
  951. void FAR *pvUser);
  952. /*** FDIDestroy - Destroy an FDI context
  953. *
  954. * Entry:
  955. * hfdi - handle to FDI context (created by FDICreate())
  956. *
  957. * Exit-Success:
  958. * Returns TRUE;
  959. *
  960. * Exit-Failure:
  961. * Returns FALSE;
  962. */
  963. BOOL FAR DIAMONDAPI FDIDestroy(HFDI hfdi);
  964. //** Revert to default structure packing
  965. #pragma pack()
  966. #endif // !INCLUDED_FDI
  967. #ifdef __cplusplus
  968. }
  969. #endif