version 1.7, 2005/02/11 08:50:58
|
version 2.0, 2005/02/11 10:54:42
|
|
|
#include <fdi.h> | #include <fdi.h> |
#include <fcntl.h> | #include <fcntl.h> |
| |
static int fakeFD = 12; |
/* Do malloc and free output debug messages? |
|
#define DEBUG_ALLOC |
/* This is the hex string representation of the file created by compressing |
*/ |
a simple text file with the contents "This is a test file." |
|
| |
The file was created using COMPRESS.EXE from the Windows Server 2003 |
/* What is our "Fake" Filedescriptor? */ |
Resource Kit from Microsoft. The resource kit was retrieved from the |
static int fakeFD = 22881; |
following URL: |
|
| |
http://www.microsoft.com/downloads/details.aspx?FamilyID=9d467a69-57ff-4ae7-96ee-b18c4790cffd&displaylang=en |
/* |
*/ |
This hex data is the output of makecab.exe (Windows Cabinet SDK/bin) |
|
****** IS USING THE OUTPUT OF A NON LGPL program okay ****** |
| |
|
The cab file is mirrored in the file system as simple.cab |
| |
|
The 'test.txt' in the cab file contains the string 'So long, and thanks for all the fish.' |
|
*/ |
static unsigned char compressed_file[] = | static unsigned char compressed_file[] = |
{0x4D,0x53,0x43,0x46,0x00,0x00,0x00,0x00,0x75,0x00, | {0x4D,0x53,0x43,0x46,0x00,0x00,0x00,0x00,0x75,0x00, |
0x00,0x00,0x00,0x00,0x00,0x00,0x2C,0x00,0x00,0x00, | 0x00,0x00,0x00,0x00,0x00,0x00,0x2C,0x00,0x00,0x00, |
|
|
static int szcompressed_file = sizeof(compressed_file); | static int szcompressed_file = sizeof(compressed_file); |
| |
/* | /* |
static const char uncompressed_data[] = "This is a test file."; |
Multiple File Cabs are included, as cabinet.dll supports multiple file archive types. |
static const DWORD uncompressed_data_size = sizeof(uncompressed_data) - 1; |
The compressed file size had to be greater than 50k, cabarc restricts 'diskette spanning' to |
|
archives above 50k. |
|
The peculiar options were selected specifically to test cabinet.dll more throughly. |
| |
static char *buf; |
complex_lzw.cab cabarc -m LZX:16 -pr -i 32356 N complex_lzw.cab amontillado.txt lgpl.txt gpl.txt midsummer\* |
*/ |
complex_lzw2.cab cabarc -m LZX:17 -d 50000 -pr -i 32356 N complex_lzw*.cab amontillado.txt + lgpl.txt gpl.txt midsummer\* |
|
|
|
complex_zip.cab cabarc -m MSZIP -pr -i 32356 N complex_lzw.cab amontillado.txt lgpl.txt gpl.txt midsummer\* |
|
complex_zip2.cab cabarc -m MSZIP -d 50000 -pr -i 32356 N complex_zip*.cab amontillado.txt + lgpl.txt gpl.txt midsummer\* |
| |
/* To do in FDI: -from wine/include/fdi.h |
complex_none.cab cabarc -m NONE -pr -i 32356 N complex_none.cab amontillado.txt midsummer\act1* |
|
|
|
/* |
|
To do in FDI: -from wine/include/fdi.h |
FDICreate | FDICreate |
File Open -FNOPEN(pszFile,oflag,pmode) |
|
File Read -FNREAD(hf, pv, cb) |
|
File Write -FNWRITE(hf, pv, cb) | File Write -FNWRITE(hf, pv, cb) |
File Close -FNCLOSE(hf) |
|
File Seek -FNSEEK(hf,dist,seektype) | File Seek -FNSEEK(hf,dist,seektype) |
Error Structure | Error Structure |
FDIlsCabinet |
|
FDICabinetInfo Structure |
|
FDICopy | FDICopy |
Notification function | Notification function |
Decryption function | Decryption function |
FDIDestroy | FDIDestroy |
*/ | */ |
| |
FDICABINETINFO fdici; |
#ifndef DEBUG_ALLOC |
|
FNALLOC(final_alloc) { |
|
return malloc(cb); |
/* Currently mostly dummy function pointers */ |
} |
|
FNFREE(final_free) { |
FNALLOC(debug_alloc) { |
free(pv); |
|
return; |
|
} |
|
#else |
|
FNALLOC(final_alloc) { |
printf(" FNALLOC just called with %d\n",cb); | printf(" FNALLOC just called with %d\n",cb); |
return malloc(cb); | return malloc(cb); |
} | } |
|
FNFREE(final_free) { |
FNFREE(debug_free) { |
|
printf(" FNFREE just called with %d\n",pv); | printf(" FNFREE just called with %d\n",pv); |
free(pv); | free(pv); |
return; | return; |
} | } |
|
#endif |
| |
/* |
|
It is not necessary for these functions to actually call _open etc.; |
|
these functions could instead call fopen, fread, fwrite, fclose, and fseek, |
|
or CreateFile, ReadFile, WriteFile, CloseHandle, and SetFilePointer, etc. |
|
However, the parameters and return codes will have to be translated |
|
appropriately (e.g. the file open mode passed in to pfnopen). |
|
| |
|
/* |
Match i/o specs of _open, _read, _write, _close, and _lseek. | Match i/o specs of _open, _read, _write, _close, and _lseek. |
|
|
*/ | */ |
| |
/* | /* |
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclib/html/_crt__open.2c_._wopen.asp |
http://msdn.microsoft.com/library/en-us/vclib/html/_crt__open.2c_._wopen.asp |
_open I: const char *filename, int oflag, int pmode O: int (handler), -1 for err. | _open I: const char *filename, int oflag, int pmode O: int (handler), -1 for err. |
|
DUMMY : FUNCTIONAL FAKE : FUNCTIONAL REAL : FUNCTIONAL |
*/ | */ |
| |
FNOPEN(dummy_open) { | FNOPEN(dummy_open) { |
|
|
return handler; | return handler; |
} | } |
| |
|
|
/* | /* |
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclib/html/_crt__open.2c_._wopen.asp |
http://msdn.microsoft.com/library/en-us/vclib/html/_CRT__read.asp |
_read I: int fd, void *buffer, unsigned int count O: int (szBuffer) | _read I: int fd, void *buffer, unsigned int count O: int (szBuffer) |
|
DUMMY : FUNCTIONAL FAKE : FUNCTIONAL, INCOMPLETE REAL : FUNCTIONAL |
*/ | */ |
| |
FNREAD(dummy_read) { | FNREAD(dummy_read) { |
|
|
return 0; | return 0; |
} | } |
| |
|
/* Doesn't keep virtual file location pointer */ |
FNREAD(fake_read) { | FNREAD(fake_read) { |
printf(" FNREAD (fake) just called with %d, %d, %d\n",hf, pv, cb); | printf(" FNREAD (fake) just called with %d, %d, %d\n",hf, pv, cb); |
if (hf == fakeFD) { | if (hf == fakeFD) { |
printf (" Called with fake file descriptor, populating buffer and size (%d)\n",szcompressed_file); |
printf (" Called with fake file descriptor, populating buffer and size (%d)\n",cb); |
memcpy (pv, compressed_file ,cb); | memcpy (pv, compressed_file ,cb); |
/* TODO */ |
|
} | } |
else { | else { |
printf (" FNREAD (fake) was called with the unknown file handler. Failed!\n",hf); | printf (" FNREAD (fake) was called with the unknown file handler. Failed!\n",hf); |
} | } |
return szcompressed_file; |
return cb; |
} | } |
| |
FNREAD(real_read) { | FNREAD(real_read) { |
|
|
return szBuffer; | return szBuffer; |
} | } |
| |
|
/* |
|
http://msdn.microsoft.com/library/en-us/vclib/html/_CRT__close.asp |
|
_close I: int fd O: int (0=success 1=failure) |
|
DUMMY : FUNCTIONAL FAKE : FUNCTIONAL REAL : FUNCTIONAL |
|
*/ |
| |
|
FNCLOSE(dummy_close) { |
|
printf(" FNCLOSE (dummy) just called with %d - returning %d\n",hf,0); |
|
return 0; |
|
} |
| |
FNWRITE(dummy_write) { |
FNCLOSE(fake_close) { |
printf(" FNWRITE just called with %d, %d, %d\n",hf, pv, cb); |
printf(" FNCLOSE (fake) just called with %d - returning %d\n",hf,0); |
return 0; | return 0; |
} | } |
| |
|
FNCLOSE(real_close) { |
|
int closevalue = _close(hf); |
|
printf(" FNCLOSE (real) just called with %d - returning %d\n",hf,closevalue); |
|
return closevalue; |
|
} |
| |
FNCLOSE(dummy_close) { |
|
printf(" FNCLOSE just called with %d\n",hf); |
|
|
|
|
|
|
FNWRITE(dummy_write) { |
|
printf(" FNWRITE just called with %d, %d, %d\n",hf, pv, cb); |
return 0; | return 0; |
} | } |
| |
|
|
return 0; | return 0; |
} | } |
| |
|
|
|
|
HFDI hfdi_unknown_dummy, hfdi_unknown_fake,hfdi_unknown_real; | HFDI hfdi_unknown_dummy, hfdi_unknown_fake,hfdi_unknown_real; |
FDICABINETINFO fdi_cabinfo; |
|
/* yes its global and ugly */ | /* yes its global and ugly */ |
| |
|
/* Is CPU386 or Unknown more commonly used? */ |
| |
static void TestCreate(void) { | static void TestCreate(void) { |
| |
|
|
printf("Starting TestCreate()\n"); | printf("Starting TestCreate()\n"); |
| |
hfdi_unknown_dummy = FDICreate( | hfdi_unknown_dummy = FDICreate( |
debug_alloc, |
final_alloc, |
debug_free, |
final_free, |
dummy_open, | dummy_open, |
dummy_read, | dummy_read, |
dummy_write, | dummy_write, |
|
|
ok(hfdi_unknown_dummy != NULL,"FDICreate (CPU = unknown) (functions=dummy) failed!\n"); | ok(hfdi_unknown_dummy != NULL,"FDICreate (CPU = unknown) (functions=dummy) failed!\n"); |
| |
hfdi_unknown_fake = FDICreate( | hfdi_unknown_fake = FDICreate( |
debug_alloc, |
final_alloc, |
debug_free, |
final_free, |
fake_open, | fake_open, |
fake_read, | fake_read, |
dummy_write, | dummy_write, |
|
|
ok(hfdi_unknown_fake != NULL,"FDICreate (CPU = unknown) (functions=fake) failed!\n"); | ok(hfdi_unknown_fake != NULL,"FDICreate (CPU = unknown) (functions=fake) failed!\n"); |
| |
hfdi_unknown_real = FDICreate( | hfdi_unknown_real = FDICreate( |
debug_alloc, |
final_alloc, |
debug_free, |
final_free, |
real_open, | real_open, |
real_read, | real_read, |
dummy_write, | dummy_write, |
dummy_close, |
real_close, |
dummy_seek, | dummy_seek, |
cpuUNKNOWN, | cpuUNKNOWN, |
&error_structure | &error_structure |
|
|
} | } |
| |
static void TestInfo(void) { | static void TestInfo(void) { |
|
/* Noticed Behavior : |
|
FDIIsCabinet does not open the file on its own, it requires a file open/close to be done externally. |
|
WHY? |
|
The only functions in HFDI that FDIIsCabinet directly accesses is FNREAD |
|
Important cases to check : |
|
If the filedescriptor == ERR, does it FAIL? (dummy_read) |
|
If the filedescriptor == NOTCABINET, does it FAIL? (fake_read, real_read) |
|
If the filedescriptor == CABINET, does it SUCCEED? (fake_read, real_read) |
|
If the filedescriptor == CABINET, does it populate FDICABINETINFO? (fake_read, real_read) |
|
*/ |
|
|
int realfd; | int realfd; |
int sizer; | int sizer; |
char *buffer = malloc(szcompressed_file); |
FDICABINETINFO fdi_cabinfo_dummy, fdi_cabinfo_simple, fdi_cabinfo_complex; |
| |
printf("Starting TestInfo()\n"); | printf("Starting TestInfo()\n"); |
/* |
|
1=> Does it return T (and fill FDICABINETINFO) if the file descriptor=>cabinet? |
|
2=> Does it return F (and ignore FDICABINETINFO) if the file descriptor != cabinet? |
|
3=> Does it return F (and ignore FDICABINETINFO) if the file descriptor == error? |
|
*/ |
|
ok ( FDIIsCabinet( hfdi_unknown_dummy, -1, &fdi_cabinfo) == FALSE, |
|
"FDIIsCabinet (File = Error) failed!\n"); |
|
|
|
ok ( FDIIsCabinet( hfdi_unknown_fake, fakeFD, &fdi_cabinfo) == FALSE, |
|
"FDIIsCabinet (File = WrongType) failed!\n"); |
|
| |
sizer = fake_read ( 12,buffer,szcompressed_file ); |
/* TEST : ERR filehandle associated, dummy functions should return FALSE */ |
printf(buffer); |
ok ( FDIIsCabinet( hfdi_unknown_dummy, -1, &fdi_cabinfo_dummy) == FALSE, |
|
"FDIIsCabinet (File = Error) failed!\n"); |
| |
realfd = real_open( "TEST1.cab" , _O_BINARY | _O_RDONLY | _O_SEQUENTIAL, 0); |
/* TEST : Fake filehandle associated, memory manually copied, should return TRUE */ |
ok ( FDIIsCabinet( hfdi_unknown_real, realfd, &fdi_cabinfo) == TRUE, |
ok ( FDIIsCabinet( hfdi_unknown_fake, fakeFD, &fdi_cabinfo_simple) == TRUE, |
"FDIIsCabinet (File = Cabinet) failed!\n"); |
"FDIIsCabinet (FakeFile = Cabinet) failed!\n"); |
|
|
|
ok ( fdi_cabinfo_simple.cbCabinet == 117, "FDIIsCabinet,cabinfo (FakeFile = Cabinet) data did not match! Failed!\n"); |
|
ok ( fdi_cabinfo_simple.cFolders == 1, "FDIIsCabinet,cabinfo (FakeFile = Cabinet) data did not match! Failed!\n"); |
|
ok ( fdi_cabinfo_simple.cFiles == 1, "FDIIsCabinet,cabinfo (FakeFile = Cabinet) data did not match! Failed!\n"); |
|
ok ( fdi_cabinfo_simple.setID == 12345, "FDIIsCabinet,cabinfo (FakeFile = Cabinet) data did not match! Failed!\n"); |
|
ok ( fdi_cabinfo_simple.iCabinet == 0, "FDIIsCabinet,cabinfo (FakeFile = Cabinet) data did not match! Failed!\n"); |
|
ok ( fdi_cabinfo_simple.fReserve == 0, "FDIIsCabinet,cabinfo (FakeFile = Cabinet) data did not match! Failed!\n"); |
|
ok ( fdi_cabinfo_simple.hasprev == 0, "FDIIsCabinet,cabinfo (FakeFile = Cabinet) data did not match! Failed!\n"); |
|
ok ( fdi_cabinfo_simple.hasnext == 0, "FDIIsCabinet,cabinfo (FakeFile = Cabinet) data did not match! Failed!\n"); |
|
|
|
|
|
/* simply this with macros? |
|
yes, make one macro with inputs (cabname, testname, [expected values] ) --- using lambda notation |
|
add checks for cabinfo data! |
|
Is it ok to reuse the same hfdi_unknown_real ? */ |
|
|
|
/* TEST : Opened filehandle associated, corrupted cab loaded, should return FALSE */ |
|
/* We can see that the Windows implementation only reads the first 36 bytes - what if we corrupted a CAB after 36 bytes?*/ |
|
|
|
realfd = real_open( "broken.cab" , _O_BINARY | _O_RDONLY | _O_SEQUENTIAL, 0); |
|
|
|
ok ( FDIIsCabinet( hfdi_unknown_real, realfd, &fdi_cabinfo_complex) == FALSE, |
|
"FDIIsCabinet (File = Bad-Cabinet) broken.cab failed!\n"); |
|
real_close(realfd); |
|
|
|
realfd = real_open( "cabinet_fdi.c" , _O_BINARY | _O_RDONLY | _O_SEQUENTIAL, 0); |
|
|
|
ok ( FDIIsCabinet( hfdi_unknown_real, realfd, &fdi_cabinfo_complex) == FALSE, |
|
"FDIIsCabinet (File = Non-Cabinet) cabinet_fdi.c failed!\n"); |
|
real_close(realfd); |
|
|
|
|
|
/* TEST : Opened filehandle associated, valid cab loaded, should return TRUE */ |
|
realfd = real_open( "complex_lzw.cab" , _O_BINARY | _O_RDONLY | _O_SEQUENTIAL, 0); |
|
|
|
ok ( FDIIsCabinet( hfdi_unknown_real, realfd, &fdi_cabinfo_complex) == TRUE, |
|
"FDIIsCabinet (File = Cabinet) complex_lzw.cab failed!\n"); |
|
real_close(realfd); |
|
|
|
printf("Cabinet Data : cbC %d cF %d cFi %d si %d iC %d fr %b hp %d hn %d\n", |
|
fdi_cabinfo_complex.cbCabinet, |
|
fdi_cabinfo_complex.cFolders , |
|
fdi_cabinfo_complex.cFiles , |
|
fdi_cabinfo_complex.setID, |
|
fdi_cabinfo_complex.iCabinet, |
|
fdi_cabinfo_complex.fReserve , |
|
fdi_cabinfo_complex.hasprev , |
|
fdi_cabinfo_complex.hasnext ); |
|
|
|
realfd = real_open( "complex_lzw2.cab" , _O_BINARY | _O_RDONLY | _O_SEQUENTIAL, 0); |
|
|
|
ok ( FDIIsCabinet( hfdi_unknown_real, realfd, &fdi_cabinfo_complex) == TRUE, |
|
"FDIIsCabinet (File = Cabinet) complex_lzw2.cab failed!\n"); |
|
real_close(realfd); |
|
|
|
printf("Cabinet Data : cbC %d cF %d cFi %d si %d iC %d fr %b hp %d hn %d\n", |
|
fdi_cabinfo_complex.cbCabinet, |
|
fdi_cabinfo_complex.cFolders , |
|
fdi_cabinfo_complex.cFiles , |
|
fdi_cabinfo_complex.setID, |
|
fdi_cabinfo_complex.iCabinet, |
|
fdi_cabinfo_complex.fReserve , |
|
fdi_cabinfo_complex.hasprev , |
|
fdi_cabinfo_complex.hasnext ); |
|
|
|
realfd = real_open( "complex_zip.cab" , _O_BINARY | _O_RDONLY | _O_SEQUENTIAL, 0); |
|
|
|
ok ( FDIIsCabinet( hfdi_unknown_real, realfd, &fdi_cabinfo_complex) == TRUE, |
|
"FDIIsCabinet (File = Cabinet) complex_zip.cab failed!\n"); |
|
real_close(realfd); |
|
|
|
printf("Cabinet Data : cbC %d cF %d cFi %d si %d iC %d fr %b hp %d hn %d\n", |
|
fdi_cabinfo_complex.cbCabinet, |
|
fdi_cabinfo_complex.cFolders , |
|
fdi_cabinfo_complex.cFiles , |
|
fdi_cabinfo_complex.setID, |
|
fdi_cabinfo_complex.iCabinet, |
|
fdi_cabinfo_complex.fReserve , |
|
fdi_cabinfo_complex.hasprev , |
|
fdi_cabinfo_complex.hasnext ); |
|
|
|
realfd = real_open( "complex_zip2.cab" , _O_BINARY | _O_RDONLY | _O_SEQUENTIAL, 0); |
|
|
|
ok ( FDIIsCabinet( hfdi_unknown_real, realfd, &fdi_cabinfo_complex) == TRUE, |
|
"FDIIsCabinet (File = Cabinet) complex_zip2.cab failed!\n"); |
|
real_close(realfd); |
|
|
|
printf("Cabinet Data : cbC %d cF %d cFi %d si %d iC %d fr %b hp %d hn %d\n", |
|
fdi_cabinfo_complex.cbCabinet, |
|
fdi_cabinfo_complex.cFolders , |
|
fdi_cabinfo_complex.cFiles , |
|
fdi_cabinfo_complex.setID, |
|
fdi_cabinfo_complex.iCabinet, |
|
fdi_cabinfo_complex.fReserve , |
|
fdi_cabinfo_complex.hasprev , |
|
fdi_cabinfo_complex.hasnext ); |
|
|
|
realfd = real_open( "complex_none.cab" , _O_BINARY | _O_RDONLY | _O_SEQUENTIAL, 0); |
|
|
|
ok ( FDIIsCabinet( hfdi_unknown_real, realfd, &fdi_cabinfo_complex) == TRUE, |
|
"FDIIsCabinet (File = Cabinet) complex_zip.cab failed!\n"); |
|
real_close(realfd); |
|
|
|
printf("Cabinet Data : cbC %d cF %d cFi %d si %d iC %d fr %b hp %d hn %d\n", |
|
fdi_cabinfo_complex.cbCabinet, |
|
fdi_cabinfo_complex.cFolders , |
|
fdi_cabinfo_complex.cFiles , |
|
fdi_cabinfo_complex.setID, |
|
fdi_cabinfo_complex.iCabinet, |
|
fdi_cabinfo_complex.fReserve , |
|
fdi_cabinfo_complex.hasprev , |
|
fdi_cabinfo_complex.hasnext ); |
| |
| |
} | } |
| |
|
|
static void TestDestroy(void) { | static void TestDestroy(void) { |
printf("Starting TestDestroy()\n"); | printf("Starting TestDestroy()\n"); |
/* Only two things to check in FDIDestroy |
/* Should return TRUE if given a valid hfdi, else FALSE (only due to context errors?) */ |
1=> Does it return T if its passed an hfdi |
|
2=> Does it return F if its passed a non hfdi |
|
EDIT : Causes GPL if FDIDestroy is called on an invalid pointer. |
|
ok( 0 == FDIDestroy(0), "Return true incorrectly in TestDestroy()!\n"); |
|
*/ |
|
| |
ok(FDIDestroy(hfdi_unknown_dummy), "FDIDestroy (CPU = unknown) (functions=fake) failed!\n"); | ok(FDIDestroy(hfdi_unknown_dummy), "FDIDestroy (CPU = unknown) (functions=fake) failed!\n"); |
ok(FDIDestroy(hfdi_unknown_fake), "FDIDestroy (CPU = unknown) (functions=fake) failed!\n"); | ok(FDIDestroy(hfdi_unknown_fake), "FDIDestroy (CPU = unknown) (functions=fake) failed!\n"); |
|
ok(FDIDestroy(hfdi_unknown_real), "FDIDestroy (CPU = unknown) (functions=real) failed!\n"); |
printf("Ending TestDestroy()\n"); | printf("Ending TestDestroy()\n"); |
| |
} | } |
| |
|
|
START_TEST(paths) | START_TEST(paths) |
{ | { |
|
|
TestCreate(); | TestCreate(); |
TestInfo(); | TestInfo(); |
/* | /* |
TestCopy(); | TestCopy(); |
*/ | */ |
TestDestroy(); | TestDestroy(); |
|
|
} | } |