Sync to Wine-0_9_9:

Gerold J. Wucherpfennig <gjwucherpfennig@gmx.net>
- cabinet: Set proper error information on failures.

Sync to Wine-0_9_6:
James Hawkins <truiken@gmail.com>
- cabinet: Implement Extract on top of FDI.
- cabinet: Clean up the documentation for Extract.
- cabinet: Fix the second parameter name of Extract.
- cabinet: Add documentation for FDITruncateCabinet.
- cabinet: Store the cab file handle before extracting files so we can
  close the cab file even if no files are extracted.
- cabinet: Move the remaining cabextract.c functions to fdi.c.
- cabinet: Add initial tests for Extract.
- cabinet: Add the two flags used by Extract to cabinet.h.
- cabinet: Define the flags member of the EXTRACTdest structure.

svn path=/trunk/; revision=21610
This commit is contained in:
Aleksey Bragin 2006-04-16 15:49:02 +00:00
parent 1888104b32
commit 2122478f7b
7 changed files with 774 additions and 2938 deletions

File diff suppressed because it is too large Load diff

View file

@ -340,6 +340,7 @@ typedef struct {
cab_ULONG sizeFileCFFILE2;
cab_ULONG sizeFileCFFOLDER;
BOOL fNewPrevious;
cab_ULONG estimatedCabinetSize;
} FCI_Int, *PFCI_Int;
typedef struct {
@ -613,6 +614,10 @@ static const cab_UWORD Zipmask[17] = {
0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff \
}
/* EXTRACTdest flags */
#define EXTRACT_FILLFILELIST 0x00000001
#define EXTRACT_EXTRACTFILES 0x00000002
struct ExtractFileList {
LPSTR filename;
struct ExtractFileList *next;
@ -625,14 +630,13 @@ typedef struct {
long unknown1[3]; /* 0x004 */
struct ExtractFileList *filelist; /* 0x010 */
long filecount; /* 0x014 */
long unknown2; /* 0x018 */
DWORD flags; /* 0x018 */
char directory[0x104]; /* 0x01c */
char lastfile[0x20c]; /* 0x120 */
} EXTRACTdest;
/* from cabextract.c */
BOOL process_cabinet(LPCSTR cabname, LPCSTR dir, BOOL fix, BOOL lower, EXTRACTdest *dest);
/* from fdi.c */
void QTMupdatemodel(struct QTMmodel *model, int sym);
int make_decode_table(cab_ULONG nsyms, cab_ULONG nbits, cab_UBYTE *length, cab_UWORD *table);
cab_ULONG checksum(cab_UBYTE *data, cab_UWORD bytes, cab_ULONG csum);

View file

@ -14,7 +14,6 @@
<library>kernel32</library>
<library>advapi32</library>
<library>iphlpapi</library>
<file>cabextract.c</file>
<file>cabinet_main.c</file>
<file>fci.c</file>
<file>fdi.c</file>

View file

@ -37,6 +37,14 @@
WINE_DEFAULT_DEBUG_CHANNEL(cabinet);
/* the following defintions are copied from msvcrt/fcntl.h */
#define _O_RDONLY 0
#define _O_WRONLY 1
#define _O_RDWR 2
#define _O_ACCMODE (_O_RDONLY|_O_WRONLY|_O_RDWR)
/***********************************************************************
* DllGetVersion (CABINET.2)
*
@ -66,70 +74,259 @@ HRESULT WINAPI DllGetVersion (DLLVERSIONINFO *pdvi)
return S_OK;
}
/* FDI callback functions */
static void *mem_alloc(ULONG cb)
{
return HeapAlloc(GetProcessHeap(), 0, cb);
}
static void mem_free(void *memory)
{
HeapFree(GetProcessHeap(), 0, memory);
}
static INT_PTR fdi_open(char *pszFile, int oflag, int pmode)
{
HANDLE handle;
DWORD dwAccess = 0;
DWORD dwShareMode = 0;
DWORD dwCreateDisposition = OPEN_EXISTING;
switch (oflag & _O_ACCMODE)
{
case _O_RDONLY:
dwAccess = GENERIC_READ;
dwShareMode = FILE_SHARE_READ | FILE_SHARE_DELETE;
break;
case _O_WRONLY:
dwAccess = GENERIC_WRITE;
dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
break;
case _O_RDWR:
dwAccess = GENERIC_READ | GENERIC_WRITE;
dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
break;
}
if (GetFileAttributesA(pszFile) != INVALID_FILE_ATTRIBUTES)
dwCreateDisposition = OPEN_EXISTING;
else
dwCreateDisposition = CREATE_NEW;
handle = CreateFileA(pszFile, dwAccess, dwShareMode, NULL,
dwCreateDisposition, 0, NULL);
return (INT_PTR) handle;
}
static UINT fdi_read(INT_PTR hf, void *pv, UINT cb)
{
HANDLE handle = (HANDLE) hf;
DWORD dwRead;
if (ReadFile(handle, pv, cb, &dwRead, NULL))
return dwRead;
return 0;
}
static UINT fdi_write(INT_PTR hf, void *pv, UINT cb)
{
HANDLE handle = (HANDLE) hf;
DWORD dwWritten;
if (WriteFile(handle, pv, cb, &dwWritten, NULL))
return dwWritten;
return 0;
}
static int fdi_close(INT_PTR hf)
{
HANDLE handle = (HANDLE) hf;
return CloseHandle(handle) ? 0 : -1;
}
static long fdi_seek(INT_PTR hf, long dist, int seektype)
{
HANDLE handle = (HANDLE) hf;
return SetFilePointer(handle, dist, NULL, seektype);
}
static void fill_file_node(struct ExtractFileList *pNode, LPSTR szFilename)
{
pNode->next = NULL;
pNode->unknown = TRUE;
pNode->filename = HeapAlloc(GetProcessHeap(), 0, strlen(szFilename) + 1);
lstrcpyA(pNode->filename, szFilename);
}
static BOOL file_in_list(struct ExtractFileList *pNode, LPSTR szFilename)
{
while (pNode)
{
if (!lstrcmpiA(pNode->filename, szFilename))
return TRUE;
pNode = pNode->next;
}
return FALSE;
}
static INT_PTR fdi_notify_extract(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
{
switch (fdint)
{
case fdintCOPY_FILE:
{
struct ExtractFileList **fileList;
EXTRACTdest *pDestination = pfdin->pv;
LPSTR szFullPath, szDirectory;
HANDLE hFile = 0;
DWORD dwSize;
dwSize = lstrlenA(pDestination->directory) +
lstrlenA("\\") + lstrlenA(pfdin->psz1) + 1;
szFullPath = HeapAlloc(GetProcessHeap(), 0, dwSize);
lstrcpyA(szFullPath, pDestination->directory);
lstrcatA(szFullPath, "\\");
lstrcatA(szFullPath, pfdin->psz1);
/* pull out the destination directory string from the full path */
dwSize = strrchr(szFullPath, '\\') - szFullPath + 1;
szDirectory = HeapAlloc(GetProcessHeap(), 0, dwSize);
lstrcpynA(szDirectory, szFullPath, dwSize);
if (pDestination->flags & EXTRACT_FILLFILELIST)
{
fileList = &pDestination->filelist;
while (*fileList)
fileList = &((*fileList)->next);
*fileList = HeapAlloc(GetProcessHeap(), 0,
sizeof(struct ExtractFileList));
fill_file_node(*fileList, pfdin->psz1);
lstrcpyA(pDestination->lastfile, szFullPath);
pDestination->filecount++;
}
if (pDestination->flags & EXTRACT_EXTRACTFILES)
{
/* skip this file it it's not in the file list */
if (!file_in_list(pDestination->filelist, pfdin->psz1))
return 0;
/* create the destination directory if it doesn't exist */
if (GetFileAttributesA(szDirectory) == INVALID_FILE_ATTRIBUTES)
CreateDirectoryA(szDirectory, NULL);
hFile = CreateFileA(szFullPath, GENERIC_READ | GENERIC_WRITE, 0, NULL,
CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
hFile = 0;
}
HeapFree(GetProcessHeap(), 0, szFullPath);
HeapFree(GetProcessHeap(), 0, szDirectory);
return (INT_PTR) hFile;
}
case fdintCLOSE_FILE_INFO:
{
FILETIME ft;
FILETIME ftLocal;
HANDLE handle = (HANDLE) pfdin->hf;
if (!DosDateTimeToFileTime(pfdin->date, pfdin->time, &ft))
return FALSE;
if (!LocalFileTimeToFileTime(&ft, &ftLocal))
return FALSE;
if (!SetFileTime(handle, &ftLocal, 0, &ftLocal))
return FALSE;
CloseHandle(handle);
return TRUE;
}
default:
return 0;
}
}
/***********************************************************************
* Extract (CABINET.3)
*
* Apparently an undocumented function, presumably to extract a CAB file
* to somewhere...
* Extracts the contents of the cabinet file to the specified
* destination.
*
* PARAMS
* dest pointer to a buffer of 0x32c bytes containing
* [I] - number with value 1 at index 0x18
* - the dest path starting at index 0x1c
* [O] - a linked list with the filename existing inside the
* CAB file at idx 0x10
* - the number of files inside the CAB file at index 0x14
* - the name of the last file with dest path at idx 0x120
* what [I] char* describing what to uncompress, I guess.
* dest [I/O] Controls the operation of Extract. See NOTES.
* szCabName [I] Filename of the cabinet to extract.
*
* RETURNS
* Success: S_OK
* Failure: E_OUTOFMEMORY (?)
* Success: S_OK.
* Failure: E_FAIL.
*
* NOTES
* The following members of the dest struct control the operation
* of Extract:
* filelist [I] A linked list of filenames. Extract only extracts
* files from the cabinet that are in this list.
* filecount [O] Contains the number of files in filelist on
* completion.
* flags [I] See Operation.
* directory [I] The destination directory.
* lastfile [O] The last file extracted.
*
* Operation
* If flags contains EXTRACT_FILLFILELIST, then filelist will be
* filled with all the files in the cabinet. If flags contains
* EXTRACT_EXTRACTFILES, then only the files in the filelist will
* be extracted from the cabinet. EXTRACT_FILLFILELIST can be called
* by itself, but EXTRACT_EXTRACTFILES must have a valid filelist
* in order to succeed. If flags contains both EXTRACT_FILLFILELIST
* and EXTRACT_EXTRACTFILES, then all the files in the cabinet
* will be extracted.
*/
HRESULT WINAPI Extract(EXTRACTdest *dest, LPCSTR what)
HRESULT WINAPI Extract(EXTRACTdest *dest, LPCSTR szCabName)
{
#define DUMPC(idx) idx >= sizeof(EXTRACTdest) ? ' ' : \
((unsigned char*) dest)[idx] >= 0x20 ? \
((unsigned char*) dest)[idx] : '.'
HRESULT res = S_OK;
HFDI hfdi;
ERF erf;
#define DUMPH(idx) idx >= sizeof(EXTRACTdest) ? 0x55 : ((unsigned char*) dest)[idx]
TRACE("(%p, %s)\n", dest, szCabName);
LPSTR dir;
unsigned int i;
hfdi = FDICreate(mem_alloc,
mem_free,
fdi_open,
fdi_read,
fdi_write,
fdi_close,
fdi_seek,
cpuUNKNOWN,
&erf);
TRACE("(dest == %0lx, what == %s)\n", (long) dest, debugstr_a(what));
if (!hfdi)
return E_FAIL;
if (!dest) {
/* win2k will crash here */
FIXME("called without valid parameter dest!\n");
return E_OUTOFMEMORY;
}
for (i=0; i < sizeof(EXTRACTdest); i+=8)
TRACE( "dest[%04x]:%02x %02x %02x %02x %02x %02x %02x %02x %c%c%c%c%c%c%c%c\n",
i,
DUMPH(i+0), DUMPH(i+1), DUMPH(i+2), DUMPH(i+3),
DUMPH(i+4), DUMPH(i+5), DUMPH(i+6), DUMPH(i+7),
DUMPC(i+0), DUMPC(i+1), DUMPC(i+2), DUMPC(i+3),
DUMPC(i+4), DUMPC(i+5), DUMPC(i+6), DUMPC(i+7));
if (GetFileAttributesA(dest->directory) == INVALID_FILE_ATTRIBUTES)
return S_OK;
dir = LocalAlloc(LPTR, strlen(dest->directory)+1);
if (!dir) return E_OUTOFMEMORY;
lstrcpyA(dir, dest->directory);
dest->filecount=0;
dest->filelist = NULL;
if (!FDICopy(hfdi, (LPSTR)szCabName, "", 0,
fdi_notify_extract, NULL, dest))
res = E_FAIL;
TRACE("extracting to dir: %s\n", debugstr_a(dir));
FDIDestroy(hfdi);
/* FIXME: what to do on failure? */
if (!process_cabinet(what, dir, FALSE, FALSE, dest)) {
LocalFree(dir);
return E_OUTOFMEMORY;
}
LocalFree(dir);
TRACE("filecount %08lx,lastfile %s\n",
dest->filecount, debugstr_a(dest->lastfile));
return S_OK;
return res;
}

File diff suppressed because it is too large Load diff

View file

@ -148,6 +148,169 @@ typedef struct fdi_cds_fwd {
struct fdi_cds_fwd *next;
} fdi_decomp_state;
/****************************************************************
* QTMupdatemodel (internal)
*/
void QTMupdatemodel(struct QTMmodel *model, int sym) {
struct QTMmodelsym temp;
int i, j;
for (i = 0; i < sym; i++) model->syms[i].cumfreq += 8;
if (model->syms[0].cumfreq > 3800) {
if (--model->shiftsleft) {
for (i = model->entries - 1; i >= 0; i--) {
/* -1, not -2; the 0 entry saves this */
model->syms[i].cumfreq >>= 1;
if (model->syms[i].cumfreq <= model->syms[i+1].cumfreq) {
model->syms[i].cumfreq = model->syms[i+1].cumfreq + 1;
}
}
}
else {
model->shiftsleft = 50;
for (i = 0; i < model->entries ; i++) {
/* no -1, want to include the 0 entry */
/* this converts cumfreqs into frequencies, then shifts right */
model->syms[i].cumfreq -= model->syms[i+1].cumfreq;
model->syms[i].cumfreq++; /* avoid losing things entirely */
model->syms[i].cumfreq >>= 1;
}
/* now sort by frequencies, decreasing order -- this must be an
* inplace selection sort, or a sort with the same (in)stability
* characteristics
*/
for (i = 0; i < model->entries - 1; i++) {
for (j = i + 1; j < model->entries; j++) {
if (model->syms[i].cumfreq < model->syms[j].cumfreq) {
temp = model->syms[i];
model->syms[i] = model->syms[j];
model->syms[j] = temp;
}
}
}
/* then convert frequencies back to cumfreq */
for (i = model->entries - 1; i >= 0; i--) {
model->syms[i].cumfreq += model->syms[i+1].cumfreq;
}
/* then update the other part of the table */
for (i = 0; i < model->entries; i++) {
model->tabloc[model->syms[i].sym] = i;
}
}
}
}
/*************************************************************************
* make_decode_table (internal)
*
* This function was coded by David Tritscher. It builds a fast huffman
* decoding table out of just a canonical huffman code lengths table.
*
* PARAMS
* nsyms: total number of symbols in this huffman tree.
* nbits: any symbols with a code length of nbits or less can be decoded
* in one lookup of the table.
* length: A table to get code lengths from [0 to syms-1]
* table: The table to fill up with decoded symbols and pointers.
*
* RETURNS
* OK: 0
* error: 1
*/
int make_decode_table(cab_ULONG nsyms, cab_ULONG nbits, cab_UBYTE *length, cab_UWORD *table) {
register cab_UWORD sym;
register cab_ULONG leaf;
register cab_UBYTE bit_num = 1;
cab_ULONG fill;
cab_ULONG pos = 0; /* the current position in the decode table */
cab_ULONG table_mask = 1 << nbits;
cab_ULONG bit_mask = table_mask >> 1; /* don't do 0 length codes */
cab_ULONG next_symbol = bit_mask; /* base of allocation for long codes */
/* fill entries for codes short enough for a direct mapping */
while (bit_num <= nbits) {
for (sym = 0; sym < nsyms; sym++) {
if (length[sym] == bit_num) {
leaf = pos;
if((pos += bit_mask) > table_mask) return 1; /* table overrun */
/* fill all possible lookups of this symbol with the symbol itself */
fill = bit_mask;
while (fill-- > 0) table[leaf++] = sym;
}
}
bit_mask >>= 1;
bit_num++;
}
/* if there are any codes longer than nbits */
if (pos != table_mask) {
/* clear the remainder of the table */
for (sym = pos; sym < table_mask; sym++) table[sym] = 0;
/* give ourselves room for codes to grow by up to 16 more bits */
pos <<= 16;
table_mask <<= 16;
bit_mask = 1 << 15;
while (bit_num <= 16) {
for (sym = 0; sym < nsyms; sym++) {
if (length[sym] == bit_num) {
leaf = pos >> 16;
for (fill = 0; fill < bit_num - nbits; fill++) {
/* if this path hasn't been taken yet, 'allocate' two entries */
if (table[leaf] == 0) {
table[(next_symbol << 1)] = 0;
table[(next_symbol << 1) + 1] = 0;
table[leaf] = next_symbol++;
}
/* follow the path and select either left or right for next bit */
leaf = table[leaf] << 1;
if ((pos >> (15-fill)) & 1) leaf++;
}
table[leaf] = sym;
if ((pos += bit_mask) > table_mask) return 1; /* table overflow */
}
}
bit_mask >>= 1;
bit_num++;
}
}
/* full table? */
if (pos == table_mask) return 0;
/* either erroneous table, or all elements are 0 - let's find out. */
for (sym = 0; sym < nsyms; sym++) if (length[sym]) return 1;
return 0;
}
/*************************************************************************
* checksum (internal)
*/
cab_ULONG checksum(cab_UBYTE *data, cab_UWORD bytes, cab_ULONG csum) {
int len;
cab_ULONG ul = 0;
for (len = bytes >> 2; len--; data += 4) {
csum ^= ((data[0]) | (data[1]<<8) | (data[2]<<16) | (data[3]<<24));
}
switch (bytes & 3) {
case 3: ul |= *data++ << 16;
case 2: ul |= *data++ << 8;
case 1: ul |= *data;
}
csum ^= ul;
return csum;
}
/***********************************************************************
* FDICreate (CABINET.20)
*
@ -2370,6 +2533,7 @@ BOOL __cdecl FDICopy(
CAB(setID) = fdici.setID;
CAB(iCabinet) = fdici.iCabinet;
CAB(cabhf) = cabhf;
/* read folders */
for (i = 0; i < fdici.cFolders; i++) {
@ -2554,7 +2718,6 @@ BOOL __cdecl FDICopy(
/* set up decomp_state */
CAB(hfdi) = hfdi;
CAB(filehf) = filehf;
CAB(cabhf) = cabhf;
/* Was there a change of folder? Compression type? Did we somehow go backwards? */
if ((ct1 != ct2) || (CAB(current) != fol) || (file->offset < CAB(offset))) {
@ -2819,7 +2982,21 @@ BOOL __cdecl FDIDestroy(HFDI hfdi)
/***********************************************************************
* FDITruncateCabinet (CABINET.24)
*
* Undocumented and unimplemented.
* Removes all folders of a cabinet file after and including the
* specified folder number.
*
* PARAMS
* hfdi [I] Handle to the FDI context.
* pszCabinetName [I] Filename of the cabinet.
* iFolderToDelete [I] Index of the first folder to delete.
*
* RETURNS
* Success: TRUE.
* Failure: FALSE.
*
* NOTES
* The PFNWRITE function supplied to FDICreate must truncate the
* file at the current position if the number of bytes to write is 0.
*/
BOOL __cdecl FDITruncateCabinet(
HFDI hfdi,

View file

@ -38,7 +38,7 @@ reactos/tools/widl # Forked at Wine-20050930
The following libraries are shared with Wine.
reactos/dll/win32/avifil32 # Synced to Wine-0_9_5
reactos/dll/win32/cabinet # Synced to Wine-0_9_5
reactos/dll/win32/cabinet # Synced to Wine-0_9_10
reactos/dll/win32/comctl32 # Synced to Wine-20060328
reactos/dll/win32/comdlg32 # Synced to Wine-0_9_5
reactos/dll/win32/crypt32 # Synced to Wine-0_9_5