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