Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-cw
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wine
wine-cw
Commits
f9100240
Commit
f9100240
authored
Aug 05, 2003
by
Gregory M. Turner
Committed by
Alexandre Julliard
Aug 05, 2003
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Many words about cabinets.
parent
95c5a2b6
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
369 additions
and
49 deletions
+369
-49
fdi.c
dlls/cabinet/fdi.c
+369
-49
No files found.
dlls/cabinet/fdi.c
View file @
f9100240
...
@@ -20,13 +20,40 @@
...
@@ -20,13 +20,40 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*
*
*
* This is (or will be) a largely redundant reimplementation of the stuff in
* This is a largely redundant reimplementation of the stuff in cabextract.c. It
* cabextract.c... it would theoretically be preferable to have only one, shared
* would be theoretically preferable to have only one, shared implementation, however
* implementation, however there are semantic differences which may discourage efforts
* there are semantic differences which may discourage efforts to unify the two. It
* to unify the two. It should be possible, if awkward, to go back and reimplement
* should be possible, if awkward, to go back and reimplement cabextract.c using FDI.
* cabextract.c using FDI (once the FDI implementation is complete, of course). Also,
* But this approach would be quite a bit less performant. Probably a better way
* cabextract's implementation is pretty efficient; fdi.c is, by contrast, extremely
* would be to create a "library" of routines in cabextract.c which do the actual
* wasteful...
* decompression, and have both fdi.c and cabextract share those routines. The rest
* of the code is not sufficiently similar to merit a shared implementation.
*
* The worst thing about this API is the bug. "The bug" is this: when you extract a
* cabinet, it /always/ informs you (via the hasnext field of PFDICABINETINFO), that
* there is no subsequent cabinet, even if there is one. wine faithfully reproduces
* this behavior.
*
* TODO:
*
* Wine does not implement the AFAIK undocumented "enumerate" callback during
* FDICopy. It is implemented in Windows and therefore worth investigating...
*
* Lots of pointers flying around here... am I leaking RAM?
*
* WTF is FDITruncate?
*
* Probably, I need to weed out some dead code-paths.
*
* Test unit(s).
*
* The fdintNEXT_CABINET callbacks are probably not working quite as they should.
* There are several FIXME's in the source describing some of the deficiencies in
* some detail. Additionally, we do not do a very good job of returning the right
* error codes to this callback.
*
* FDICopy and fdi_decomp are incomprehensibly large; separating these into smaller
* functions would be nice.
*
*
* -gmt
* -gmt
*/
*/
...
@@ -55,7 +82,7 @@ struct fdi_file {
...
@@ -55,7 +82,7 @@ struct fdi_file {
cab_ULONG
offset
;
/* uncompressed offset in folder */
cab_ULONG
offset
;
/* uncompressed offset in folder */
cab_UWORD
index
;
/* magic index number of folder */
cab_UWORD
index
;
/* magic index number of folder */
cab_UWORD
time
,
date
,
attribs
;
/* MS-DOS time/date/attributes */
cab_UWORD
time
,
date
,
attribs
;
/* MS-DOS time/date/attributes */
BOOL
oppressed
;
/* never to be processed */
BOOL
oppressed
;
/* never to be processed */
};
};
struct
fdi_folder
{
struct
fdi_folder
{
...
@@ -71,7 +98,7 @@ struct fdi_folder {
...
@@ -71,7 +98,7 @@ struct fdi_folder {
* this structure fills the gaps between what is available in a PFDICABINETINFO
* this structure fills the gaps between what is available in a PFDICABINETINFO
* vs what is needed by FDICopy. Memory allocated for these becomes the responsibility
* vs what is needed by FDICopy. Memory allocated for these becomes the responsibility
* of the caller to free. Yes, I am aware that this is totally, utterly inelegant.
* of the caller to free. Yes, I am aware that this is totally, utterly inelegant.
* To make things even more unnec
ce
sarily confusing, we now attach these to the
* To make things even more unnec
es
sarily confusing, we now attach these to the
* fdi_decomp_state.
* fdi_decomp_state.
*/
*/
typedef
struct
{
typedef
struct
{
...
@@ -84,7 +111,7 @@ typedef struct {
...
@@ -84,7 +111,7 @@ typedef struct {
/*
/*
* ugh, well, this ended up being pretty damn silly...
* ugh, well, this ended up being pretty damn silly...
* now that I've conce
e
ded to build equivalent structures to struct cab.*,
* now that I've conceded to build equivalent structures to struct cab.*,
* I should have just used those, or, better yet, unified the two... sue me.
* I should have just used those, or, better yet, unified the two... sue me.
* (Note to Microsoft: That's a joke. Please /don't/ actually sue me! -gmt).
* (Note to Microsoft: That's a joke. Please /don't/ actually sue me! -gmt).
* Nevertheless, I've come this far, it works, so I'm not gonna change it
* Nevertheless, I've come this far, it works, so I'm not gonna change it
...
@@ -122,6 +149,42 @@ typedef struct fdi_cds_fwd {
...
@@ -122,6 +149,42 @@ typedef struct fdi_cds_fwd {
/***********************************************************************
/***********************************************************************
* FDICreate (CABINET.20)
* FDICreate (CABINET.20)
*
* Provided with several callbacks (all of them are mandatory),
* returns a handle which can be used to perform operations
* on cabinet files.
*
* PARAMS
* pfnalloc [I] A pointer to a function which allocates ram. Uses
* the same interface as malloc.
* pfnfree [I] A pointer to a function which frees ram. Uses the
* same interface as free.
* pfnopen [I] A pointer to a function which opens a file. Uses
* the same interface as _open.
* pfnread [I] A pointer to a function which reads from a file into
* a caller-provided buffer. Uses the same interface
* as _read
* pfnwrite [I] A pointer to a function which writes to a file from
* a caller-provided buffer. Uses the same interface
* as _write.
* pfnclose [I] A pointer to a function which closes a file handle.
* Uses the same interface as _close.
* pfnseek [I] A pointer to a function which seeks in a file.
* Uses the same interface as _lseek.
* cpuType [I] The type of CPU; ignored in wine (recommended value:
* cpuUNKNOWN, aka -1).
* perf [IO] A pointer to an ERF structure. When FDICreate
* returns an error condition, error information may
* be found here as well as from GetLastError.
*
* RETURNS
* On success, returns an FDI handle of type HFDI.
* On failure, the NULL file handle is returned. Error
* info can be retrieved from perf.
*
* INCLUDES
* fdi.h
*
*/
*/
HFDI
__cdecl
FDICreate
(
HFDI
__cdecl
FDICreate
(
PFNALLOC
pfnalloc
,
PFNALLOC
pfnalloc
,
...
@@ -177,7 +240,7 @@ HFDI __cdecl FDICreate(
...
@@ -177,7 +240,7 @@ HFDI __cdecl FDICreate(
/*******************************************************************
/*******************************************************************
* FDI_getoffset (internal)
* FDI_getoffset (internal)
*
*
* returns the file pointer position of a
cab
* returns the file pointer position of a
file handle.
*/
*/
long
FDI_getoffset
(
HFDI
hfdi
,
INT_PTR
hf
)
long
FDI_getoffset
(
HFDI
hfdi
,
INT_PTR
hf
)
{
{
...
@@ -188,7 +251,7 @@ long FDI_getoffset(HFDI hfdi, INT_PTR hf)
...
@@ -188,7 +251,7 @@ long FDI_getoffset(HFDI hfdi, INT_PTR hf)
* FDI_realloc (internal)
* FDI_realloc (internal)
*
*
* we can't use _msize; the user might not be using malloc, so we require
* we can't use _msize; the user might not be using malloc, so we require
* an explicit specification of the previous size.
utterly
inefficient.
* an explicit specification of the previous size. inefficient.
*/
*/
void
*
FDI_realloc
(
HFDI
hfdi
,
void
*
mem
,
size_t
prevsize
,
size_t
newsize
)
void
*
FDI_realloc
(
HFDI
hfdi
,
void
*
mem
,
size_t
prevsize
,
size_t
newsize
)
{
{
...
@@ -207,7 +270,7 @@ void *FDI_realloc(HFDI hfdi, void *mem, size_t prevsize, size_t newsize)
...
@@ -207,7 +270,7 @@ void *FDI_realloc(HFDI hfdi, void *mem, size_t prevsize, size_t newsize)
/**********************************************************************
/**********************************************************************
* FDI_read_string (internal)
* FDI_read_string (internal)
*
*
* allocate and read an ar
i
bitrarily long string from the cabinet
* allocate and read an arbitrarily long string from the cabinet
*/
*/
char
*
FDI_read_string
(
HFDI
hfdi
,
INT_PTR
hf
,
long
cabsize
)
char
*
FDI_read_string
(
HFDI
hfdi
,
INT_PTR
hf
,
long
cabsize
)
{
{
...
@@ -261,7 +324,6 @@ char *FDI_read_string(HFDI hfdi, INT_PTR hf, long cabsize)
...
@@ -261,7 +324,6 @@ char *FDI_read_string(HFDI hfdi, INT_PTR hf, long cabsize)
*
*
* process the cabinet header in the style of FDIIsCabinet, but
* process the cabinet header in the style of FDIIsCabinet, but
* without the sanity checks (and bug)
* without the sanity checks (and bug)
*
*/
*/
BOOL
FDI_read_entries
(
BOOL
FDI_read_entries
(
HFDI
hfdi
,
HFDI
hfdi
,
...
@@ -277,6 +339,36 @@ BOOL FDI_read_entries(
...
@@ -277,6 +339,36 @@ BOOL FDI_read_entries(
TRACE
(
"(hfdi == ^%p, hf == %d, pfdici == ^%p)
\n
"
,
hfdi
,
hf
,
pfdici
);
TRACE
(
"(hfdi == ^%p, hf == %d, pfdici == ^%p)
\n
"
,
hfdi
,
hf
,
pfdici
);
/*
* FIXME: I just noticed that I am memorizing the initial file pointer
* offset and restoring it before reading in the rest of the header
* information in the cabinet. Perhaps that's correct -- that is, perhaps
* this API is supposed to support "streaming" cabinets which are embedded
* in other files, or cabinets which begin at file offsets other than zero.
* Otherwise, I should instead go to the absolute beginning of the file.
* (Either way, the semantics of wine's FDICopy require me to leave the
* file pointer where it is afterwards -- If Windows does not do so, we
* ought to duplicate the native behavior in the FDIIsCabinet API, not here.
*
* So, the answer lies in Windows; will native cabinet.dll recognize a
* cabinet "file" embedded in another file? Note that cabextract.c does
* support this, which implies that Microsoft's might. I haven't tried it
* yet so I don't know. ATM, most of wine's FDI cabinet routines (except
* this one) would not work in this way. To fix it, we could just make the
* various references to absolute file positions in the code relative to an
* initial "beginning" offset. Because the FDICopy API doesn't take a
* file-handle like this one, we would therein need to search through the
* file for the beginning of the cabinet (as we also do in cabextract.c).
* Note that this limits us to a maximum of one cabinet per. file: the first.
*
* So, in summary: either the code below is wrong, or the rest of fdi.c is
* wrong... I cannot imagine that both are correct ;) One of these flaws
* should be fixed after determining the behavior on Windows. We ought
* to check both FDIIsCabinet and FDICopy for the right behavior.
*
* -gmt
*/
/* get basic offset & size info */
/* get basic offset & size info */
base_offset
=
FDI_getoffset
(
hfdi
,
hf
);
base_offset
=
FDI_getoffset
(
hfdi
,
hf
);
...
@@ -449,6 +541,30 @@ BOOL FDI_read_entries(
...
@@ -449,6 +541,30 @@ BOOL FDI_read_entries(
/***********************************************************************
/***********************************************************************
* FDIIsCabinet (CABINET.21)
* FDIIsCabinet (CABINET.21)
*
* Informs the caller as to whether or not the provided file handle is
* really a cabinet or not, filling out the provided PFDICABINETINFO
* structure with information about the cabinet. Brief explanations of
* the elements of this structure are available as comments accompanying
* its definition in wine's include/fdi.h.
*
* PARAMS
* hfdi [I] An HFDI from FDICreate
* hf [I] The file handle about which the caller inquires
* pfdici [IO] Pointer to a PFDICABINETINFO structure which will
* be filled out with information about the cabinet
* file indicated by hf if, indeed, it is determined
* to be a cabinet.
*
* RETURNS
* TRUE if the file is a cabinet. The info pointed to by pfdici will
* be provided.
* FALSE if the file is not a cabinet, or if an error was encountered
* while processing the cabinet. The PERF structure provided to
* FDICreate can be queried for more error information.
*
* INCLUDES
* fdi.c
*/
*/
BOOL
__cdecl
FDIIsCabinet
(
BOOL
__cdecl
FDIIsCabinet
(
HFDI
hfdi
,
HFDI
hfdi
,
...
@@ -493,7 +609,7 @@ BOOL __cdecl FDIIsCabinet(
...
@@ -493,7 +609,7 @@ BOOL __cdecl FDIIsCabinet(
/******************************************************************
/******************************************************************
* QTMfdi_initmodel (internal)
* QTMfdi_initmodel (internal)
*
*
* Initiali
s
e a model which decodes symbols from [s] to [s]+[n]-1
* Initiali
z
e a model which decodes symbols from [s] to [s]+[n]-1
*/
*/
void
QTMfdi_initmodel
(
struct
QTMmodel
*
m
,
struct
QTMmodelsym
*
sym
,
int
n
,
int
s
)
{
void
QTMfdi_initmodel
(
struct
QTMmodel
*
m
,
struct
QTMmodelsym
*
sym
,
int
n
,
int
s
)
{
int
i
;
int
i
;
...
@@ -530,7 +646,7 @@ int QTMfdi_init(int window, int level, fdi_decomp_state *decomp_state) {
...
@@ -530,7 +646,7 @@ int QTMfdi_init(int window, int level, fdi_decomp_state *decomp_state) {
QTM
(
window_size
)
=
wndsize
;
QTM
(
window_size
)
=
wndsize
;
QTM
(
window_posn
)
=
0
;
QTM
(
window_posn
)
=
0
;
/* initiali
s
e static slot/extrabits tables */
/* initiali
z
e static slot/extrabits tables */
for
(
i
=
0
,
j
=
0
;
i
<
27
;
i
++
)
{
for
(
i
=
0
,
j
=
0
;
i
<
27
;
i
++
)
{
CAB
(
q_length_extra
)[
i
]
=
(
i
==
26
)
?
0
:
(
i
<
2
?
0
:
i
-
2
)
>>
2
;
CAB
(
q_length_extra
)[
i
]
=
(
i
==
26
)
?
0
:
(
i
<
2
?
0
:
i
-
2
)
>>
2
;
CAB
(
q_length_base
)[
i
]
=
j
;
j
+=
1
<<
((
i
==
26
)
?
5
:
CAB
(
q_length_extra
)[
i
]);
CAB
(
q_length_base
)[
i
]
=
j
;
j
+=
1
<<
((
i
==
26
)
?
5
:
CAB
(
q_length_extra
)[
i
]);
...
@@ -540,7 +656,7 @@ int QTMfdi_init(int window, int level, fdi_decomp_state *decomp_state) {
...
@@ -540,7 +656,7 @@ int QTMfdi_init(int window, int level, fdi_decomp_state *decomp_state) {
CAB
(
q_position_base
)[
i
]
=
j
;
j
+=
1
<<
CAB
(
q_extra_bits
)[
i
];
CAB
(
q_position_base
)[
i
]
=
j
;
j
+=
1
<<
CAB
(
q_extra_bits
)[
i
];
}
}
/* initiali
s
e arithmetic coding models */
/* initiali
z
e arithmetic coding models */
QTMfdi_initmodel
(
&
QTM
(
model7
),
&
QTM
(
m7sym
)[
0
],
7
,
0
);
QTMfdi_initmodel
(
&
QTM
(
model7
),
&
QTM
(
m7sym
)[
0
],
7
,
0
);
...
@@ -580,7 +696,7 @@ int LZXfdi_init(int window, fdi_decomp_state *decomp_state) {
...
@@ -580,7 +696,7 @@ int LZXfdi_init(int window, fdi_decomp_state *decomp_state) {
}
}
LZX
(
window_size
)
=
wndsize
;
LZX
(
window_size
)
=
wndsize
;
/* initiali
s
e static tables */
/* initiali
z
e static tables */
for
(
i
=
0
,
j
=
0
;
i
<=
50
;
i
+=
2
)
{
for
(
i
=
0
,
j
=
0
;
i
<=
50
;
i
+=
2
)
{
CAB
(
extra_bits
)[
i
]
=
CAB
(
extra_bits
)[
i
+
1
]
=
j
;
/* 0,0,0,0,1,1,2,2,3,3... */
CAB
(
extra_bits
)[
i
]
=
CAB
(
extra_bits
)[
i
+
1
]
=
j
;
/* 0,0,0,0,1,1,2,2,3,3... */
if
((
i
!=
0
)
&&
(
j
<
17
))
j
++
;
/* 0,0,1,2,3,4...15,16,17,17,17,17... */
if
((
i
!=
0
)
&&
(
j
<
17
))
j
++
;
/* 0,0,1,2,3,4...15,16,17,17,17,17... */
...
@@ -607,7 +723,7 @@ int LZXfdi_init(int window, fdi_decomp_state *decomp_state) {
...
@@ -607,7 +723,7 @@ int LZXfdi_init(int window, fdi_decomp_state *decomp_state) {
LZX
(
intel_started
)
=
0
;
LZX
(
intel_started
)
=
0
;
LZX
(
window_posn
)
=
0
;
LZX
(
window_posn
)
=
0
;
/* initiali
s
e tables to 0 (because deltas will be applied to them) */
/* initiali
z
e tables to 0 (because deltas will be applied to them) */
for
(
i
=
0
;
i
<
LZX_MAINTREE_MAXSYMBOLS
;
i
++
)
LZX
(
MAINTREE_len
)[
i
]
=
0
;
for
(
i
=
0
;
i
<
LZX_MAINTREE_MAXSYMBOLS
;
i
++
)
LZX
(
MAINTREE_len
)[
i
]
=
0
;
for
(
i
=
0
;
i
<
LZX_LENGTH_MAXSYMBOLS
;
i
++
)
LZX
(
LENGTH_len
)[
i
]
=
0
;
for
(
i
=
0
;
i
<
LZX_LENGTH_MAXSYMBOLS
;
i
++
)
LZX
(
LENGTH_len
)[
i
]
=
0
;
...
@@ -1694,13 +1810,14 @@ int LZXfdi_decomp(int inlen, int outlen, fdi_decomp_state *decomp_state) {
...
@@ -1694,13 +1810,14 @@ int LZXfdi_decomp(int inlen, int outlen, fdi_decomp_state *decomp_state) {
/**********************************************************
/**********************************************************
* fdi_decomp (internal)
* fdi_decomp (internal)
*
*
* Decompress the
"appropriate"
number of bytes. If savemode is zero,
* Decompress the
requested
number of bytes. If savemode is zero,
* do not save the output anywhere, just plow through blocks until we
* do not save the output anywhere, just plow through blocks until we
* reach the starting point for fi, and remember the position of the
* reach the specified (uncompressed) distance from the starting point,
* cabfile pointer after we are done; otherwise, save it out, decompressing
* and remember the position of the cabfile pointer (and which cabfile)
* the number of bytes in the file specified by fi. This is also where we
* after we are done; otherwise, save the data out to CAB(filehf),
* jumping to additional cabinets in the case of split cab's, and provide
* decompressing the requested number of bytes and writing them out. This
* (most of) the NEXT_CABINET notification semantics described in the SDK.
* is also where we jump to additional cabinets in the case of split
* cab's, and provide (some of) the NEXT_CABINET notification semantics.
*/
*/
int
fdi_decomp
(
struct
fdi_file
*
fi
,
int
savemode
,
fdi_decomp_state
*
decomp_state
,
int
fdi_decomp
(
struct
fdi_file
*
fi
,
int
savemode
,
fdi_decomp_state
*
decomp_state
,
char
*
pszCabPath
,
PFNFDINOTIFY
pfnfdin
,
void
*
pvUser
)
char
*
pszCabPath
,
PFNFDINOTIFY
pfnfdin
,
void
*
pvUser
)
...
@@ -1788,7 +1905,7 @@ int fdi_decomp(struct fdi_file *fi, int savemode, fdi_decomp_state *decomp_state
...
@@ -1788,7 +1905,7 @@ int fdi_decomp(struct fdi_file *fi, int savemode, fdi_decomp_state *decomp_state
if
(
pathlen
<
256
)
{
if
(
pathlen
<
256
)
{
for
(
i
=
0
;
i
<=
pathlen
;
i
++
)
for
(
i
=
0
;
i
<=
pathlen
;
i
++
)
userpath
[
i
]
=
pszCabPath
[
i
];
userpath
[
i
]
=
pszCabPath
[
i
];
}
/* else we are in a w
ie
rd place... let's leave it blank and see if the user fixes it */
}
/* else we are in a w
ei
rd place... let's leave it blank and see if the user fixes it */
}
}
/* initial fdintNEXT_CABINET notification */
/* initial fdintNEXT_CABINET notification */
...
@@ -1950,7 +2067,8 @@ int fdi_decomp(struct fdi_file *fi, int savemode, fdi_decomp_state *decomp_state
...
@@ -1950,7 +2067,8 @@ int fdi_decomp(struct fdi_file *fi, int savemode, fdi_decomp_state *decomp_state
}
}
}
}
}
}
if
(
!
success
)
goto
tryanothercab
;
/* this should never happen */
if
(
!
success
)
goto
tryanothercab
;
/* FIXME: shouldn't this trigger
"Wrong Cabinet" notification? */
}
}
}
}
...
@@ -1967,6 +2085,167 @@ int fdi_decomp(struct fdi_file *fi, int savemode, fdi_decomp_state *decomp_state
...
@@ -1967,6 +2085,167 @@ int fdi_decomp(struct fdi_file *fi, int savemode, fdi_decomp_state *decomp_state
/***********************************************************************
/***********************************************************************
* FDICopy (CABINET.22)
* FDICopy (CABINET.22)
*
* Iterates through the files in the Cabinet file indicated by name and
* file-location. May chain forward to additional cabinets (typically
* only one) if files which begin in this Cabinet are continued in another
* cabinet. For each file which is partially contained in this cabinet,
* and partially contained in a prior cabinet, provides fdintPARTIAL_FILE
* notification to the pfnfdin callback. For each file which begins in
* this cabinet, fdintCOPY_FILE notification is provided to the pfnfdin
* callback, and the file is optionally decompressed and saved to disk.
* Notification is not provided for files which are not at least partially
* contained in the specified cabinet file.
*
* See below for a thorough explanation of the various notification
* callbacks.
*
* PARAMS
* hfdi [I] An HFDI from FDICreate
* pszCabinet [I] C-style string containing the filename of the cabinet
* pszCabPath [I] C-style string containing the file path of the cabinet
* flags [I] "Decoder parameters". Ignored. Suggested value: 0.
* pfnfdin [I] Pointer to a notification function. See CALLBACKS below.
* pfnfdid [I] Pointer to a decryption function. Ignored. Suggested
* value: NULL.
* pvUser [I] arbitrary void * value which is passed to callbacks.
*
* RETURNS
* TRUE if successful.
* FALSE if unsuccessful (error information is provided in the ERF structure
* associated with the provided decompression handle by FDICreate).
*
* CALLBACKS
*
* Two pointers to callback functions are provided as parameters to FDICopy:
* pfnfdin(of type PFNFDINOTIFY), and pfnfdid (of type PFNFDIDECRYPT). These
* types are as follows:
*
* typedef INT_PTR (__cdecl *PFNFDINOTIFY) ( FDINOTIFICATIONTYPE fdint,
* PFDINOTIFICATION pfdin );
*
* typedef int (__cdecl *PFNFDIDECRYPT) ( PFDIDECRYPT pfdid );
*
* You can create functions of this type using the FNFDINOTIFY() and
* FNFDIDECRYPT() macros, respectively. For example:
*
* FNFDINOTIFY(mycallback) {
* / * use variables fdint and pfdin to process notification * /
* }
*
* The second callback, which could be used for decrypting encrypted data,
* is not used at all.
*
* Each notification informs the user of some event which has occurred during
* decompression of the cabinet file; each notification is also an opportunity
* for the callee to abort decompression. The information provided to the
* callback and the meaning of the callback's return value vary drastically
* across the various types of notification. The type of notification is the
* fdint parameter; all other information is provided to the callback in
* notification-specific parts of the FDINOTIFICATION structure pointed to by
* pfdin. The only part of that structure which is assigned for every callback
* is the pv element, which contains the arbitrary value which was passed to
* FDICopy in the pvUser argument (psz1 is also used each time, but its meaning
* is highly dependant on fdint).
*
* If you encounter unknown notifications, you should return zero if you want
* decompression to continue (or -1 to abort). All strings used in the
* callbacks are regular C-style strings. Detailed descriptions of each
* notification type follow:
*
* fdintCABINET_INFO:
*
* This is the first notification provided after calling FDICopy, and provides
* the user with various information about the cabinet. Note that this is
* called for each cabinet FDICopy opens, not just the first one. In the
* structure pointed to by pfdin, psz1 contains a pointer to the name of the
* next cabinet file in the set after the one just loaded (if any), psz2
* contains a pointer to the name or "info" of the next disk, psz3
* contains a pointer to the file-path of the current cabinet, setID
* contains an arbitrary constant associated with this set of cabinet files,
* and iCabinet contains the numerical index of the current cabinet within
* that set. Return zero, or -1 to abort.
*
* fdintPARTIAL_FILE:
*
* This notification is provided when FDICopy encounters a part of a file
* contained in this cabinet which is missing its beginning. Files can be
* split across cabinets, so this is not necessarily an abnormality; it just
* means that the file in question begins in another cabinet. No file
* corresponding to this notification is extracted from the cabinet. In the
* structure pointed to by pfdin, psz1 contains a pointer to the name of the
* partial file, psz2 contains a pointer to the file name of the cabinet in
* which this file begins, and psz3 contains a pointer to the disk name or
* "info" of the cabinet where the file begins. Return zero, or -1 to abort.
*
* fdintCOPY_FILE:
*
* This notification is provided when FDICopy encounters a file which starts
* in the cabinet file, provided to FDICopy in pszCabinet. (FDICopy will not
* look for files in cabinets after the first one). One notification will be
* sent for each such file, before the file is decompressed. By returning
* zero, the callback can instruct FDICopy to skip the file. In the structure
* pointed to by pfdin, psz1 contains a pointer to the file's name, cb contains
* the size of the file (uncompressed), attribs contains the file attributes,
* and date and time contain the date and time of the file. attributes, date,
* and time are of the 16-bit ms-dos variety. Return -1 to abort decompression
* for the entire cabinet, 0 to skip just this file but continue scanning the
* cabinet for more files, or an FDIClose()-compatible file-handle.
*
* fdintCLOSE_FILE_INFO:
*
* This notification is important, don't forget to implement it. This
* notification indicates that a file has been successfully uncompressed and
* written to disk. Upon receipt of this notification, the callee is expected
* to close the file handle, to set the attributes and date/time of the
* closed file, and possibly to execute the file. In the structure pointed to
* by pfdin, psz1 contains a pointer to the name of the file, hf will be the
* open file handle (close it), cb contains 1 or zero, indicating respectively
* that the callee should or should not execute the file, and date, time
* and attributes will be set as in fdintCOPY_FILE. Bizarrely, the Cabinet SDK
* specifies that _A_EXEC will be xor'ed out of attributes! wine does not do
* do so. Return TRUE, or FALSE to abort decompression.
*
* fdintNEXT_CABINET:
*
* This notification is called when FDICopy must load in another cabinet. This
* can occur when a file's data is "split" across multiple cabinets. The
* callee has the opportunity to request that FDICopy look in a different file
* path for the specified cabinet file, by writing that data into a provided
* buffer (see below for more information). This notification will be received
* more than once per-cabinet in the instance that FDICopy failed to find a
* valid cabinet at the location specified by the first per-cabinet
* fdintNEXT_CABINET notification. In such instances, the fdie element of the
* structure pointed to by pfdin indicates the error which prevented FDICopy
* from proceeding successfully. Return zero to indicate success, or -1 to
* indicate failure and abort FDICopy.
*
* Upon receipt of this notification, the structure pointed to by pfdin will
* contain the following values: psz1 pointing to the name of the cabinet
* which FDICopy is attempting to open, psz2 pointing to the name ("info") of
* the next disk, psz3 pointing to the presumed file-location of the cabinet,
* and fdie containing either FDIERROR_NONE, or one of the following:
*
* FDIERROR_CABINET_NOT_FOUND, FDIERROR_NOT_A_CABINET,
* FDIERROR_UNKNOWN_CABINET_VERSION, FDIERROR_CORRUPT_CABINET,
* FDIERROR_BAD_COMPR_TYPE, FDIERROR_RESERVE_MISMATCH, and
* FDIERROR_WRONG_CABINET.
*
* The callee may choose to change the path where FDICopy will look for the
* cabinet after this notification. To do so, the caller may write the new
* pathname to the buffer pointed to by psz3, which is 256 characters in
* length, including the terminating null character, before returning zero.
*
* fdintENUMERATE:
*
* Undocumented and unimplemented in wine, this seems to be sent each time
* a cabinet is opened, along with the fdintCABINET_INFO notification. It
* probably has an interface similar to that of fdintCABINET_INFO; maybe this
* provides information about the current cabinet instead of the next one....
* this is just a guess, it has not been looked at closely.
*
* INCLUDES
* fdi.c
*/
*/
BOOL
__cdecl
FDICopy
(
BOOL
__cdecl
FDICopy
(
HFDI
hfdi
,
HFDI
hfdi
,
...
@@ -2145,25 +2424,54 @@ BOOL __cdecl FDICopy(
...
@@ -2145,25 +2424,54 @@ BOOL __cdecl FDICopy(
}
}
for
(
file
=
CAB
(
firstfile
);
(
file
);
file
=
file
->
next
)
{
for
(
file
=
CAB
(
firstfile
);
(
file
);
file
=
file
->
next
)
{
/* partial-file notification (do it just once for the first cabinet) */
/*
* FIXME: This implementation keeps multiple cabinet files open at once
* when encountering a split cabinet. It is a quirk of this implementation
* that sometimes we decrypt the same block of data more than once, to find
* the right starting point for a file, moving the file-pointer backwards.
* If we kept a cache of certain file-pointer information, we could eliminate
* that behavior... in fact I am not sure that the caching we already have
* is not sufficient.
*
* The current implementation seems to work fine in straightforward situations
* where all the cabinet files needed for decryption are simultaneously
* available. But presumably, the API is supposed to support cabinets which
* are split across multiple CDROMS; we may need to change our implementation
* to strictly serialize it's file usage so that it opens only one cabinet
* at a time. Some experimentation with Windows is needed to figure out the
* precise semantics required. The relevant code is here and in fdi_decomp().
*/
/* partial-file notification */
if
((
file
->
index
&
cffileCONTINUED_FROM_PREV
)
==
cffileCONTINUED_FROM_PREV
)
{
if
((
file
->
index
&
cffileCONTINUED_FROM_PREV
)
==
cffileCONTINUED_FROM_PREV
)
{
/* OK, more MS bugs to simulate here, I think. I don't have a huge spanning
/*
* cabinet to test this theory on ATM, but here's the deal. The SDK says that we
* FIXME: Need to create a Cabinet with a single file spanning multiple files
* are supposed to notify the user of the filename and "disk name" (info) of
* and perform some tests to figure out the right behavior. The SDK says
* the cabinet where the spanning file /started/. That would certainly be convenient
* FDICopy will notify the user of the filename and "disk name" (info) of
* for the consumer, who could decide to abort everything and try to start over with
* the cabinet where the spanning file /started/.
* that cabinet so as to avoid partial file notification and successfully unpack. This
*
* task would be a horrible bitch from the implementor's (wine's) perspective: the
* That would certainly be convenient for the API-user, who could abort,
* information is associated nowhere with the file header and is not to be found in
* everything (or parallelize, if that's allowed (it is in wine)), and call
* the cabinet header. So we would have to open the previous cabinet, and check
* FDICopy again with the provided filename, so as to avoid partial file
* if it contains a single spanning file that's continued from yet another prior cabinet,
* notification and successfully unpack. This task could be quite unpleasant
* and so-on, until we find the beginning. Note that cabextract.c has code to do exactly
* from wine's perspective: the information specifying the "start cabinet" for
* this. Luckily, MS clearly didn't implement this logic, so we don't have to either.
* a file is associated nowhere with the file header and is not to be found in
* Watching the callbacks (and debugmsg +file) clearly shows that they don't open
* the cabinet header. We have only the index of the cabinet wherein the folder
* the preceeding cabinet -- and therefore, I deduce, there is NO WAY they could
* begins, which contains the file. To find that cabinet, we must consider the
* have implemented what's in the spec. Instead, they are obviously just returning
* index of the current cabinet, and chain backwards, cabinet-by-cabinet (for
* the previous cabinet and it's info from the header of this cabinet. So we shall
* each cabinet refers to its "next" and "previous" cabinet only, like a linked
* do the same. Of course, I could be missing something...
* list).
*
* Bear in mind that, in the spirit of CABINET.DLL, we must assume that any
* cabinet other than the active one might be at another filepath than the
* current one, or on another CDROM. This could get rather dicey, especially
* if we imagine parallelized access to the FDICopy API.
*
* The current implementation punts -- it just returns the previous cabinet and
* it's info from the header of this cabinet. This provides the right answer in
* 95% of the cases; its worth checking if Microsoft cuts the same corner before
* we "fix" it.
*/
*/
ZeroMemory
(
&
fdin
,
sizeof
(
FDINOTIFICATION
));
ZeroMemory
(
&
fdin
,
sizeof
(
FDINOTIFICATION
));
fdin
.
pv
=
pvUser
;
fdin
.
pv
=
pvUser
;
...
@@ -2231,7 +2539,7 @@ BOOL __cdecl FDICopy(
...
@@ -2231,7 +2539,7 @@ BOOL __cdecl FDICopy(
TRACE
(
"Resetting folder for file %s.
\n
"
,
debugstr_a
(
file
->
filename
));
TRACE
(
"Resetting folder for file %s.
\n
"
,
debugstr_a
(
file
->
filename
));
/* free stuff for the old decompress
o
r */
/* free stuff for the old decompress
e
r */
switch
(
ct2
)
{
switch
(
ct2
)
{
case
cffoldCOMPTYPE_LZX
:
case
cffoldCOMPTYPE_LZX
:
if
(
LZX
(
window
))
{
if
(
LZX
(
window
))
{
...
@@ -2252,7 +2560,7 @@ BOOL __cdecl FDICopy(
...
@@ -2252,7 +2560,7 @@ BOOL __cdecl FDICopy(
CAB
(
offset
)
=
0
;
CAB
(
offset
)
=
0
;
CAB
(
outlen
)
=
0
;
CAB
(
outlen
)
=
0
;
/* initialize the new decompress
o
r */
/* initialize the new decompress
e
r */
switch
(
ct1
)
{
switch
(
ct1
)
{
case
cffoldCOMPTYPE_NONE
:
case
cffoldCOMPTYPE_NONE
:
CAB
(
decompress
)
=
NONEfdi_decomp
;
CAB
(
decompress
)
=
NONEfdi_decomp
;
...
@@ -2346,10 +2654,10 @@ BOOL __cdecl FDICopy(
...
@@ -2346,10 +2654,10 @@ BOOL __cdecl FDICopy(
fdin
.
pv
=
pvUser
;
fdin
.
pv
=
pvUser
;
fdin
.
psz1
=
(
char
*
)
file
->
filename
;
fdin
.
psz1
=
(
char
*
)
file
->
filename
;
fdin
.
hf
=
filehf
;
fdin
.
hf
=
filehf
;
fdin
.
cb
=
(
file
->
attribs
&
cffile_A_EXEC
)
?
TRUE
:
FALSE
;
fdin
.
cb
=
(
file
->
attribs
&
cffile_A_EXEC
)
?
TRUE
:
FALSE
;
/* FIXME: is that right? */
fdin
.
date
=
file
->
date
;
fdin
.
date
=
file
->
date
;
fdin
.
time
=
file
->
time
;
fdin
.
time
=
file
->
time
;
fdin
.
attribs
=
file
->
attribs
;
fdin
.
attribs
=
file
->
attribs
;
/* FIXME: filter _A_EXEC? */
err
=
((
*
pfnfdin
)(
fdintCLOSE_FILE_INFO
,
&
fdin
));
err
=
((
*
pfnfdin
)(
fdintCLOSE_FILE_INFO
,
&
fdin
));
if
(
err
==
FALSE
||
err
==
-
1
)
{
if
(
err
==
FALSE
||
err
==
-
1
)
{
/*
/*
...
@@ -2450,6 +2758,16 @@ BOOL __cdecl FDICopy(
...
@@ -2450,6 +2758,16 @@ BOOL __cdecl FDICopy(
/***********************************************************************
/***********************************************************************
* FDIDestroy (CABINET.23)
* FDIDestroy (CABINET.23)
*
* Frees a handle created by FDICreate. Do /not/ call this in the middle
* of FDICopy. Only reason for failure would be an invalid handle.
*
* PARAMS
* hfdi [I] The HFDI to free
*
* RETURNS
* TRUE for success
* FALSE for failure
*/
*/
BOOL
__cdecl
FDIDestroy
(
HFDI
hfdi
)
BOOL
__cdecl
FDIDestroy
(
HFDI
hfdi
)
{
{
...
@@ -2466,6 +2784,8 @@ BOOL __cdecl FDIDestroy(HFDI hfdi)
...
@@ -2466,6 +2784,8 @@ BOOL __cdecl FDIDestroy(HFDI hfdi)
/***********************************************************************
/***********************************************************************
* FDITruncateCabinet (CABINET.24)
* FDITruncateCabinet (CABINET.24)
*
* Undocumented and unimplemented.
*/
*/
BOOL
__cdecl
FDITruncateCabinet
(
BOOL
__cdecl
FDITruncateCabinet
(
HFDI
hfdi
,
HFDI
hfdi
,
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment