Leaked source code of windows server 2003
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.

1070 lines
46 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. /*** ERF - Error structure
  46. *
  47. * This structure returns error information from FCI/FDI. The caller should
  48. * not modify this structure.
  49. */
  50. typedef struct {
  51. int erfOper; // FCI/FDI error code -- see FDIERROR_XXX
  52. // and FCIERR_XXX equates for details.
  53. int erfType; // Optional error value filled in by FCI/FDI.
  54. // For FCI, this is usually the C run-time
  55. // *errno* value.
  56. BOOL fError; // TRUE => error present
  57. } ERF; /* erf */
  58. typedef ERF FAR *PERF; /* perf */
  59. #ifdef DBG
  60. // don't hide statics from map during debugging
  61. #define STATIC
  62. #else // !DBG
  63. #define STATIC static
  64. #endif // !DBG
  65. #define CB_MAX_CHUNK 32768U
  66. #define CB_MAX_DISK 0x7ffffffL
  67. #define CB_MAX_FILENAME 256
  68. #define CB_MAX_CABINET_NAME 256
  69. #define CB_MAX_CAB_PATH 256
  70. #define CB_MAX_DISK_NAME 256
  71. /*** tcompXXX - Compression types
  72. *
  73. * These are passed to FCIAddFile(), and are also stored in the CFFOLDER
  74. * structures in cabinet files.
  75. *
  76. * NOTE: We reserve bits for the TYPE, QUANTUM_LEVEL, and QUANTUM_MEM
  77. * to provide room for future expansion. Since this value is stored
  78. * in the CFDATA records in the cabinet file, we don't want to
  79. * have to change the format for existing compression configurations
  80. * if we add new ones in the future. This will allows us to read
  81. * old cabinet files in the future.
  82. */
  83. typedef unsigned short TCOMP; /* tcomp */
  84. #define tcompMASK_TYPE 0x000F // Mask for compression type
  85. #define tcompTYPE_NONE 0x0000 // No compression
  86. #define tcompTYPE_MSZIP 0x0001 // MSZIP
  87. #define tcompTYPE_QUANTUM 0x0002 // Quantum
  88. #define tcompTYPE_LZX 0x0003 // LZX
  89. #define tcompBAD 0x000F // Unspecified compression type
  90. #define tcompMASK_LZX_WINDOW 0x1F00 // Mask for LZX Compression Memory
  91. #define tcompLZX_WINDOW_LO 0x0F00 // Lowest LZX Memory (15)
  92. #define tcompLZX_WINDOW_HI 0x1500 // Highest LZX Memory (21)
  93. #define tcompSHIFT_LZX_WINDOW 8 // Amount to shift over to get int
  94. #define tcompMASK_QUANTUM_LEVEL 0x00F0 // Mask for Quantum Compression Level
  95. #define tcompQUANTUM_LEVEL_LO 0x0010 // Lowest Quantum Level (1)
  96. #define tcompQUANTUM_LEVEL_HI 0x0070 // Highest Quantum Level (7)
  97. #define tcompSHIFT_QUANTUM_LEVEL 4 // Amount to shift over to get int
  98. #define tcompMASK_QUANTUM_MEM 0x1F00 // Mask for Quantum Compression Memory
  99. #define tcompQUANTUM_MEM_LO 0x0A00 // Lowest Quantum Memory (10)
  100. #define tcompQUANTUM_MEM_HI 0x1500 // Highest Quantum Memory (21)
  101. #define tcompSHIFT_QUANTUM_MEM 8 // Amount to shift over to get int
  102. #define tcompMASK_RESERVED 0xE000 // Reserved bits (high 3 bits)
  103. #define CompressionTypeFromTCOMP(tc) \
  104. ((tc) & tcompMASK_TYPE)
  105. #define CompressionLevelFromTCOMP(tc) \
  106. (((tc) & tcompMASK_QUANTUM_LEVEL) >> tcompSHIFT_QUANTUM_LEVEL)
  107. #define CompressionMemoryFromTCOMP(tc) \
  108. (((tc) & tcompMASK_QUANTUM_MEM) >> tcompSHIFT_QUANTUM_MEM)
  109. #define TCOMPfromTypeLevelMemory(t, l,m) \
  110. (((m) << tcompSHIFT_QUANTUM_MEM ) | \
  111. ((l) << tcompSHIFT_QUANTUM_LEVEL) | \
  112. ( t ))
  113. #define LZXCompressionWindowFromTCOMP(tc) \
  114. (((tc) & tcompMASK_LZX_WINDOW) >> tcompSHIFT_LZX_WINDOW)
  115. #define TCOMPfromLZXWindow(w) \
  116. (((w) << tcompSHIFT_LZX_WINDOW ) | \
  117. ( tcompTYPE_LZX ))
  118. //** Revert to default structure packing
  119. #pragma pack()
  120. #endif // !INCLUDED_TYPES_FCI_FDI
  121. /*
  122. * Concepts:
  123. * A *cabinet* file contains one or more *folders*. A folder contains
  124. * one or more (pieces of) *files*. A folder is by definition a
  125. * decompression unit, i.e., to extract a file from a folder, all of
  126. * the data from the start of the folder up through and including the
  127. * desired file must be read and decompressed.
  128. *
  129. * A folder can span one (or more) cabinet boundaries, and by implication
  130. * a file can also span one (or more) cabinet boundaries. Indeed, more
  131. * than one file can span a cabinet boundary, since FCI concatenates
  132. * files together into a single data stream before compressing (actually,
  133. * at most one file will span any one cabinet boundary, but FCI does
  134. * not know which file this is, since the mapping from uncompressed bytes
  135. * to compressed bytes is pretty obscure. Also, since FCI compresses
  136. * in blocks of 32K (at present), any files with data in a 32K block that
  137. * spans a cabinet boundary require FDI to read both cabinet files
  138. * to get the two halves of the compressed block).
  139. *
  140. * Overview:
  141. * The File Decompression Interface is used to simplify the reading of
  142. * cabinet files. A setup program will proceed in a manner very
  143. * similar to the pseudo code below. An FDI context is created, the
  144. * setup program calls FDICopy() for each cabinet to be processed. For
  145. * each file in the cabinet, FDICopy() calls a notification callback
  146. * routine, asking the setup program if the file should be copied.
  147. * This call-back approach is great because it allows the cabinet file
  148. * to be read and decompressed in an optimal manner, and also makes FDI
  149. * independent of the run-time environment -- FDI makes *no* C run-time
  150. * calls whatsoever. All memory allocation and file I/O functions are
  151. * passed into FDI by the client.
  152. *
  153. * main(...)
  154. * {
  155. * // Read INF file to construct list of desired files.
  156. * // Ideally, these would be sorted in the same order as the
  157. * // files appear in the cabinets, so that you can just walk
  158. * // down the list in response to fdintCOPY_FILE notifications.
  159. *
  160. * // Construct list of required cabinets.
  161. *
  162. * hfdi = FDICreate(...); // Create FDI context
  163. * For (cabinet in List of Cabinets) {
  164. * FDICopy(hfdi, cabinet,fdiNotify,...); // Process each cabinet
  165. * }
  166. * FDIDestroy(hfdi);
  167. * ...
  168. * }
  169. *
  170. * // Notification callback function
  171. * fdiNotify(fdint, ...)
  172. * {
  173. * If (User Aborted) // Permit cancellation
  174. * if (fdint == fdintCLOSE_FILE_INFO)
  175. * close open file
  176. * return -1;
  177. * switch (fdint) {
  178. * case fdintCOPY_FILE: // File to copy, maybe
  179. * // Check file against list of desired files
  180. * if want to copy file
  181. * open destination file and return handle
  182. * else
  183. * return NULL; // Skip file
  184. * case fdintCLOSE_FILE_INFO:
  185. * close file
  186. * set date, time, and attributes
  187. *
  188. * case fdintNEXT_CABINET:
  189. * if not an error callback
  190. * Tell FDI to use suggested directory name
  191. * else
  192. * Tell user what the problem was, and prompt
  193. * for a new disk and/or path.
  194. * if user aborts
  195. * Tell FDI to abort
  196. * else
  197. * return to FDI to try another cabinet
  198. *
  199. * default:
  200. * return 0; // more messages may be defined
  201. * ...
  202. * }
  203. *
  204. * Error Handling Suggestions:
  205. * Since you the client have passed in *all* of the functions that
  206. * FDI uses to interact with the "outside" world, you are in prime
  207. * position to understand and deal with errors.
  208. *
  209. * The general philosophy of FDI is to pass all errors back up to
  210. * the client. FDI returns fairly generic error codes in the case
  211. * where one of the callback functions (PFNOPEN, PFNREAD, etc.) fail,
  212. * since it assumes that the callback function will save enough
  213. * information in a static/global so that when FDICopy() returns
  214. * fail, the client can examine this information and report enough
  215. * detail about the problem that the user can take corrective action.
  216. *
  217. * For very specific errors (CORRUPT_CABINET, for example), FDI returns
  218. * very specific error codes.
  219. *
  220. * THE BEST POLICY IS FOR YOUR CALLBACK ROUTINES TO AVOID RETURNING
  221. * ERRORS TO FDI!
  222. *
  223. * Examples:
  224. * (1) If the disk is getting full, instead of returning an error
  225. * from your PFNWRITE function, you should -- inside your
  226. * PFNWRITE function -- put up a dialog telling the user to free
  227. * some disk space.
  228. * (2) When you get the fdintNEXT_CABINET notification, you should
  229. * verify that the cabinet you return is the correct one (call
  230. * FDIIsCabinet(), and make sure the setID matches the one for
  231. * the current cabinet specified in the fdintCABINET_INFO, and
  232. * that the disk number is one greater.
  233. *
  234. * NOTE: FDI will continue to call fdintNEXT_CABINET until it
  235. * gets the cabinet it wants, or until you return -1
  236. * to abort the FDICopy() call.
  237. *
  238. * The documentation below on the FDI error codes provides explicit
  239. * guidance on how to avoid each error.
  240. *
  241. * If you find you must return a failure to FDI from one of your
  242. * callback functions, then FDICopy() frees all resources it allocated
  243. * and closes all files. If you can figure out how to overcome the
  244. * problem, you can call FDICopy() again on the last cabinet, and
  245. * skip any files that you already copied. But, note that FDI does
  246. * *not* maintain any state between FDICopy() calls, other than possibly
  247. * memory allocated for the decompressor.
  248. *
  249. * See FDIERROR for details on FDI error codes and recommended actions.
  250. *
  251. *
  252. * Progress Indicator Suggestions:
  253. * As above, all of the file I/O functions are supplied by you. So,
  254. * updating a progress indicator is very simple. You keep track of
  255. * the target files handles you have opened, along with the uncompressed
  256. * size of the target file. When you see writes to the handle of a
  257. * target file, you use the write count to update your status!
  258. * Since this method is available, there is no separate callback from
  259. * FDI just for progess indication.
  260. */
  261. #ifndef INCLUDED_FDI
  262. #define INCLUDED_FDI 1
  263. //** Specify structure packing explicitly for clients of FDI
  264. #pragma pack(4)
  265. /*** FDIERROR - Error codes returned in erf.erfOper field
  266. *
  267. * In general, FDI will only fail if one of the passed in memory or
  268. * file I/O functions fails. Other errors are pretty unlikely, and are
  269. * caused by corrupted cabinet files, passing in a file which is not a
  270. * cabinet file, or cabinet files out of order.
  271. *
  272. * Description: Summary of error.
  273. * Cause: List of possible causes of this error.
  274. * Response: How client might respond to this error, or avoid it in
  275. * the first place.
  276. */
  277. typedef enum {
  278. FDIERROR_NONE,
  279. // Description: No error
  280. // Cause: Function was successfull.
  281. // Response: Keep going!
  282. FDIERROR_CABINET_NOT_FOUND,
  283. // Description: Cabinet not found
  284. // Cause: Bad file name or path passed to FDICopy(), or returned
  285. // to fdintNEXT_CABINET.
  286. // Response: To prevent this error, validate the existence of the
  287. // the cabinet *before* passing the path to FDI.
  288. FDIERROR_NOT_A_CABINET,
  289. // Description: Cabinet file does not have the correct format
  290. // Cause: File passed to to FDICopy(), or returned to
  291. // fdintNEXT_CABINET, is too small to be a cabinet file,
  292. // or does not have the cabinet signature in its first
  293. // four bytes.
  294. // Response: To prevent this error, call FDIIsCabinet() to check a
  295. // cabinet before calling FDICopy() or returning the
  296. // cabinet path to fdintNEXT_CABINET.
  297. FDIERROR_UNKNOWN_CABINET_VERSION,
  298. // Description: Cabinet file has an unknown version number.
  299. // Cause: File passed to to FDICopy(), or returned to
  300. // fdintNEXT_CABINET, has what looks like a cabinet file
  301. // header, but the version of the cabinet file format
  302. // is not one understood by this version of FDI. The
  303. // erf.erfType field is filled in with the version number
  304. // found in the cabinet file.
  305. // Response: To prevent this error, call FDIIsCabinet() to check a
  306. // cabinet before calling FDICopy() or returning the
  307. // cabinet path to fdintNEXT_CABINET.
  308. FDIERROR_CORRUPT_CABINET,
  309. // Description: Cabinet file is corrupt
  310. // Cause: FDI returns this error any time it finds a problem
  311. // with the logical format of a cabinet file, and any
  312. // time one of the passed-in file I/O calls fails when
  313. // operating on a cabinet (PFNOPEN, PFNSEEK, PFNREAD,
  314. // or PFNCLOSE). The client can distinguish these two
  315. // cases based upon whether the last file I/O call
  316. // failed or not.
  317. // Response: Assuming this is not a real corruption problem in
  318. // a cabinet file, the file I/O functions could attempt
  319. // to do retries on failure (for example, if there is a
  320. // temporary network connection problem). If this does
  321. // not work, and the file I/O call has to fail, then the
  322. // FDI client will have to clean up and call the
  323. // FDICopy() function again.
  324. FDIERROR_ALLOC_FAIL,
  325. // Description: Could not allocate enough memory
  326. // Cause: FDI tried to allocate memory with the PFNALLOC
  327. // function, but it failed.
  328. // Response: If possible, PFNALLOC should take whatever steps
  329. // are possible to allocate the memory requested. If
  330. // memory is not immediately available, it might post a
  331. // dialog asking the user to free memory, for example.
  332. // Note that the bulk of FDI's memory allocations are
  333. // made at FDICreate() time and when the first cabinet
  334. // file is opened during FDICopy().
  335. FDIERROR_BAD_COMPR_TYPE,
  336. // Description: Unknown compression type in a cabinet folder
  337. // Cause: [Should never happen.] A folder in a cabinet has an
  338. // unknown compression type. This is probably caused by
  339. // a mismatch between the version of FCI.LIB used to
  340. // create the cabinet and the FDI.LIB used to read the
  341. // cabinet.
  342. // Response: Abort.
  343. FDIERROR_MDI_FAIL,
  344. // Description: Failure decompressing data from a cabinet file
  345. // Cause: The decompressor found an error in the data coming
  346. // from the file cabinet. The cabinet file was corrupted.
  347. // [11-Apr-1994 bens When checksuming is turned on, this
  348. // error should never occur.]
  349. // Response: Probably should abort; only other choice is to cleanup
  350. // and call FDICopy() again, and hope there was some
  351. // intermittent data error that will not reoccur.
  352. FDIERROR_TARGET_FILE,
  353. // Description: Failure writing to target file
  354. // Cause: FDI returns this error any time it gets an error back
  355. // from one of the passed-in file I/O calls fails when
  356. // writing to a file being extracted from a cabinet.
  357. // Response: To avoid or minimize this error, the file I/O functions
  358. // could attempt to avoid failing. A common cause might
  359. // be disk full -- in this case, the PFNWRITE function
  360. // could have a check for free space, and put up a dialog
  361. // asking the user to free some disk space.
  362. FDIERROR_RESERVE_MISMATCH,
  363. // Description: Cabinets in a set do not have the same RESERVE sizes
  364. // Cause: [Should never happen]. FDI requires that the sizes of
  365. // the per-cabinet, per-folder, and per-data block
  366. // RESERVE sections be consistent across all the cabinets
  367. // in a set.
  368. // Response: Abort.
  369. FDIERROR_WRONG_CABINET,
  370. // Description: Cabinet returned on fdintNEXT_CABINET is incorrect
  371. // Cause: NOTE: THIS ERROR IS NEVER RETURNED BY FDICopy()!
  372. // Rather, FDICopy() keeps calling the fdintNEXT_CABINET
  373. // callback until either the correct cabinet is specified,
  374. // or you return ABORT.
  375. // When FDICopy() is extracting a file that crosses a
  376. // cabinet boundary, it calls fdintNEXT_CABINET to ask
  377. // for the path to the next cabinet. Not being very
  378. // trusting, FDI then checks to make sure that the
  379. // correct continuation cabinet was supplied! It does
  380. // this by checking the "setID" and "iCabinet" fields
  381. // in the cabinet. When MAKECAB.EXE creates a set of
  382. // cabinets, it constructs the "setID" using the sum
  383. // of the bytes of all the destination file names in
  384. // the cabinet set. FDI makes sure that the 16-bit
  385. // setID of the continuation cabinet matches the
  386. // cabinet file just processed. FDI then checks that
  387. // the cabinet number (iCabinet) is one more than the
  388. // cabinet number for the cabinet just processed.
  389. // Response: You need code in your fdintNEXT_CABINET (see below)
  390. // handler to do retries if you get recalled with this
  391. // error. See the sample code (EXTRACT.C) to see how
  392. // this should be handled.
  393. FDIERROR_USER_ABORT,
  394. // Description: FDI aborted.
  395. // Cause: An FDI callback returnd -1 (usually).
  396. // Response: Up to client.
  397. } FDIERROR;
  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