2 * Unit tests for the File Decompression Interface
4 * Copyright (C) 2006 James Hawkins
5 * Copyright (C) 2013 Dmitry Timoshkov
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 //#include <windows.h>
24 #include <wine/test.h>
28 /* make the max size large so there is only one cab file */
29 #define MEDIA_SIZE 999999999
30 #define FOLDER_THRESHOLD 900000
32 static CHAR CURR_DIR
[MAX_PATH
];
34 /* avoid including CRT headers */
36 # define _O_BINARY 0x8000
40 # define _S_IREAD 0x0100
41 # define _S_IWRITE 0x0080
48 UCHAR signature
[4]; /* file signature */
49 ULONG reserved1
; /* reserved */
50 ULONG cbCabinet
; /* size of this cabinet file in bytes */
51 ULONG reserved2
; /* reserved */
52 ULONG coffFiles
; /* offset of the first CFFILE entry */
53 ULONG reserved3
; /* reserved */
54 UCHAR versionMinor
; /* cabinet file format version, minor */
55 UCHAR versionMajor
; /* cabinet file format version, major */
56 USHORT cFolders
; /* number of CFFOLDER entries in this cabinet */
57 USHORT cFiles
; /* number of CFFILE entries in this cabinet */
58 USHORT flags
; /* cabinet file option indicators */
59 USHORT setID
; /* must be the same for all cabinets in a set */
60 USHORT iCabinet
; /* number of this cabinet file in a set */
62 USHORT cbCFHeader
; /* (optional) size of per-cabinet reserved area */
63 UCHAR cbCFFolder
; /* (optional) size of per-folder reserved area */
64 UCHAR cbCFData
; /* (optional) size of per-datablock reserved area */
65 UCHAR abReserve
; /* (optional) per-cabinet reserved area */
66 UCHAR szCabinetPrev
; /* (optional) name of previous cabinet file */
67 UCHAR szDiskPrev
; /* (optional) name of previous disk */
68 UCHAR szCabinetNext
; /* (optional) name of next cabinet file */
69 UCHAR szDiskNext
; /* (optional) name of next disk */
75 ULONG coffCabStart
; /* offset of the first CFDATA block in this folder */
76 USHORT cCFData
; /* number of CFDATA blocks in this folder */
77 USHORT typeCompress
; /* compression type indicator */
79 UCHAR abReserve
[]; /* (optional) per-folder reserved area */
85 ULONG cbFile
; /* uncompressed size of this file in bytes */
86 ULONG uoffFolderStart
; /* uncompressed offset of this file in the folder */
87 USHORT iFolder
; /* index into the CFFOLDER area */
88 USHORT date
; /* date stamp for this file */
89 USHORT time
; /* time stamp for this file */
90 USHORT attribs
; /* attribute flags for this file */
92 UCHAR szName
[]; /* name of this file */
98 ULONG csum
; /* checksum of this CFDATA entry */
99 USHORT cbData
; /* number of compressed bytes in this block */
100 USHORT cbUncomp
; /* number of uncompressed bytes in this block */
102 UCHAR abReserve
[]; /* (optional) per-datablock reserved area */
103 UCHAR ab
[cbData
]; /* compressed data bytes */
109 struct CFHEADER header
;
110 struct CFFOLDER folder
;
112 UCHAR szName
[sizeof("file.dat")];
114 UCHAR ab
[sizeof("Hello World!")-1];
117 { {'M','S','C','F'}, 0, 0x59, 0, sizeof(struct CFHEADER
) + sizeof(struct CFFOLDER
), 0, 3,1, 1, 1, 0, 0x1225, 0x2013 },
118 { sizeof(struct CFHEADER
) + sizeof(struct CFFOLDER
) + sizeof(struct CFFILE
) + sizeof("file.dat"), 1, tcompTYPE_NONE
},
119 { sizeof("Hello World!")-1, 0, 0, 0x1225, 0x2013, 0xa114 },
120 { 'f','i','l','e','.','d','a','t',0 },
121 { 0, sizeof("Hello World!")-1, sizeof("Hello World!")-1 },
122 { 'H','e','l','l','o',' ','W','o','r','l','d','!' }
135 static void * CDECL
fdi_alloc(ULONG cb
)
137 return HeapAlloc(GetProcessHeap(), 0, cb
);
140 static void * CDECL
fdi_alloc_bad(ULONG cb
)
145 static void CDECL
fdi_free(void *pv
)
147 HeapFree(GetProcessHeap(), 0, pv
);
150 static INT_PTR CDECL
fdi_open(char *pszFile
, int oflag
, int pmode
)
153 handle
= CreateFileA(pszFile
, GENERIC_READ
| GENERIC_WRITE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
,
154 OPEN_EXISTING
, 0, NULL
);
155 if (handle
== INVALID_HANDLE_VALUE
)
157 return (INT_PTR
) handle
;
160 static UINT CDECL
fdi_read(INT_PTR hf
, void *pv
, UINT cb
)
162 HANDLE handle
= (HANDLE
) hf
;
164 if (ReadFile(handle
, pv
, cb
, &dwRead
, NULL
))
169 static UINT CDECL
fdi_write(INT_PTR hf
, void *pv
, UINT cb
)
171 HANDLE handle
= (HANDLE
) hf
;
173 if (WriteFile(handle
, pv
, cb
, &dwWritten
, NULL
))
178 static int CDECL
fdi_close(INT_PTR hf
)
180 HANDLE handle
= (HANDLE
) hf
;
181 return CloseHandle(handle
) ? 0 : -1;
184 static LONG CDECL
fdi_seek(INT_PTR hf
, LONG dist
, int seektype
)
186 HANDLE handle
= (HANDLE
) hf
;
187 return SetFilePointer(handle
, dist
, NULL
, seektype
);
190 static void test_FDICreate(void)
195 /* native crashes if pfnalloc is NULL */
197 /* FDICreate does not crash with a NULL pfnfree,
198 * but FDIDestroy will crash when it tries to access it.
202 SetLastError(0xdeadbeef);
203 erf
.erfOper
= 0x1abe11ed;
204 erf
.erfType
= 0x5eed1e55;
205 erf
.fError
= 0x1ead1e55;
206 hfdi
= FDICreate(fdi_alloc
, NULL
, fdi_open
, fdi_read
,
207 fdi_write
, fdi_close
, fdi_seek
,
209 ok(hfdi
!= NULL
, "Expected non-NULL context\n");
210 ok(GetLastError() == 0xdeadbeef,
211 "Expected 0xdeadbeef, got %d\n", GetLastError());
212 ok(erf
.erfOper
== 0x1abe11ed, "Expected 0x1abe11ed, got %d\n", erf
.erfOper
);
213 ok(erf
.erfType
== 0x5eed1e55, "Expected 0x5eed1e55, got %d\n", erf
.erfType
);
214 ok(erf
.fError
== 0x1ead1e55, "Expected 0x1ead1e55, got %d\n", erf
.fError
);
219 SetLastError(0xdeadbeef);
220 erf
.erfOper
= 0x1abe11ed;
221 erf
.erfType
= 0x5eed1e55;
222 erf
.fError
= 0x1ead1e55;
223 hfdi
= FDICreate(fdi_alloc
, fdi_free
, NULL
, fdi_read
,
224 fdi_write
, fdi_close
, fdi_seek
,
226 ok(hfdi
!= NULL
, "Expected non-NULL context\n");
227 ok(GetLastError() == 0xdeadbeef,
228 "Expected 0xdeadbeef, got %d\n", GetLastError());
229 ok((erf
.erfOper
== 0x1abe11ed || erf
.erfOper
== 0 /* Vista */), "Expected 0x1abe11ed or 0, got %d\n", erf
.erfOper
);
230 ok((erf
.erfType
== 0x5eed1e55 || erf
.erfType
== 0 /* Vista */), "Expected 0x5eed1e55 or 0, got %d\n", erf
.erfType
);
231 ok((erf
.fError
== 0x1ead1e55 || erf
.fError
== 0 /* Vista */), "Expected 0x1ead1e55 or 0, got %d\n", erf
.fError
);
235 SetLastError(0xdeadbeef);
236 erf
.erfOper
= 0x1abe11ed;
237 erf
.erfType
= 0x5eed1e55;
238 erf
.fError
= 0x1ead1e55;
239 hfdi
= FDICreate(fdi_alloc
, fdi_free
, fdi_open
, NULL
,
240 fdi_write
, fdi_close
, fdi_seek
,
242 ok(hfdi
!= NULL
, "Expected non-NULL context\n");
243 ok(GetLastError() == 0xdeadbeef,
244 "Expected 0xdeadbeef, got %d\n", GetLastError());
245 ok((erf
.erfOper
== 0x1abe11ed || erf
.erfOper
== 0 /* Vista */), "Expected 0x1abe11ed or 0, got %d\n", erf
.erfOper
);
246 ok((erf
.erfType
== 0x5eed1e55 || erf
.erfType
== 0 /* Vista */), "Expected 0x5eed1e55 or 0, got %d\n", erf
.erfType
);
247 ok((erf
.fError
== 0x1ead1e55 || erf
.fError
== 0 /* Vista */), "Expected 0x1ead1e55 or 0, got %d\n", erf
.fError
);
251 SetLastError(0xdeadbeef);
252 erf
.erfOper
= 0x1abe11ed;
253 erf
.erfType
= 0x5eed1e55;
254 erf
.fError
= 0x1ead1e55;
255 hfdi
= FDICreate(fdi_alloc
, fdi_free
, fdi_open
, fdi_read
,
256 NULL
, fdi_close
, fdi_seek
,
258 ok(hfdi
!= NULL
, "Expected non-NULL context\n");
259 ok(GetLastError() == 0xdeadbeef,
260 "Expected 0xdeadbeef, got %d\n", GetLastError());
261 ok((erf
.erfOper
== 0x1abe11ed || erf
.erfOper
== 0 /* Vista */), "Expected 0x1abe11ed or 0, got %d\n", erf
.erfOper
);
262 ok((erf
.erfType
== 0x5eed1e55 || erf
.erfType
== 0 /* Vista */), "Expected 0x5eed1e55 or 0, got %d\n", erf
.erfType
);
263 ok((erf
.fError
== 0x1ead1e55 || erf
.fError
== 0 /* Vista */), "Expected 0x1ead1e55 or 0, got %d\n", erf
.fError
);
267 SetLastError(0xdeadbeef);
268 erf
.erfOper
= 0x1abe11ed;
269 erf
.erfType
= 0x5eed1e55;
270 erf
.fError
= 0x1ead1e55;
271 hfdi
= FDICreate(fdi_alloc
, fdi_free
, fdi_open
, fdi_read
,
272 fdi_write
, NULL
, fdi_seek
,
274 ok(hfdi
!= NULL
, "Expected non-NULL context\n");
275 ok(GetLastError() == 0xdeadbeef,
276 "Expected 0xdeadbeef, got %d\n", GetLastError());
277 ok((erf
.erfOper
== 0x1abe11ed || erf
.erfOper
== 0 /* Vista */), "Expected 0x1abe11ed or 0, got %d\n", erf
.erfOper
);
278 ok((erf
.erfType
== 0x5eed1e55 || erf
.erfType
== 0 /* Vista */), "Expected 0x5eed1e55 or 0, got %d\n", erf
.erfType
);
279 ok((erf
.fError
== 0x1ead1e55 || erf
.fError
== 0 /* Vista */), "Expected 0x1ead1e55 or 0, got %d\n", erf
.fError
);
283 SetLastError(0xdeadbeef);
284 erf
.erfOper
= 0x1abe11ed;
285 erf
.erfType
= 0x5eed1e55;
286 erf
.fError
= 0x1ead1e55;
287 hfdi
= FDICreate(fdi_alloc
, fdi_free
, fdi_open
, fdi_read
,
288 fdi_write
, fdi_close
, NULL
,
290 ok(hfdi
!= NULL
, "Expected non-NULL context\n");
291 ok(GetLastError() == 0xdeadbeef,
292 "Expected 0xdeadbeef, got %d\n", GetLastError());
293 ok((erf
.erfOper
== 0x1abe11ed || erf
.erfOper
== 0 /* Vista */), "Expected 0x1abe11ed or 0, got %d\n", erf
.erfOper
);
294 ok((erf
.erfType
== 0x5eed1e55 || erf
.erfType
== 0 /* Vista */), "Expected 0x5eed1e55 or 0, got %d\n", erf
.erfType
);
295 ok((erf
.fError
== 0x1ead1e55 || erf
.fError
== 0 /* Vista */), "Expected 0x1ead1e55 or 0, got %d\n", erf
.fError
);
299 SetLastError(0xdeadbeef);
300 erf
.erfOper
= 0x1abe11ed;
301 erf
.erfType
= 0x5eed1e55;
302 erf
.fError
= 0x1ead1e55;
303 hfdi
= FDICreate(fdi_alloc
, fdi_free
, fdi_open
, fdi_read
,
304 fdi_write
, fdi_close
, fdi_seek
,
306 /* XP sets hfdi to a non-NULL value, but Vista sets it to NULL! */
307 ok(GetLastError() == 0xdeadbeef,
308 "Expected 0xdeadbeef, got %d\n", GetLastError());
309 /* NULL is passed to FDICreate instead of &erf, so don't retest the erf member values. */
314 SetLastError(0xdeadbeef);
315 erf
.erfOper
= 0x1abe11ed;
316 erf
.erfType
= 0x5eed1e55;
317 erf
.fError
= 0x1ead1e55;
318 hfdi
= FDICreate(fdi_alloc
, fdi_free
, fdi_open
, fdi_read
,
319 fdi_write
, fdi_close
, fdi_seek
,
321 ok(hfdi
!= NULL
, "Expected non-NULL context\n");
322 ok(GetLastError() == 0xdeadbeef,
323 "Expected 0xdeadbeef, got %d\n", GetLastError());
324 ok((erf
.erfOper
== 0x1abe11ed || erf
.erfOper
== 0 /* Vista */), "Expected 0x1abe11ed or 0, got %d\n", erf
.erfOper
);
325 ok((erf
.erfType
== 0x5eed1e55 || erf
.erfType
== 0 /* Vista */), "Expected 0x5eed1e55 or 0, got %d\n", erf
.erfType
);
326 ok((erf
.fError
== 0x1ead1e55 || erf
.fError
== 0 /* Vista */), "Expected 0x1ead1e55 or 0, got %d\n", erf
.fError
);
331 SetLastError(0xdeadbeef);
332 erf
.erfOper
= 0x1abe11ed;
333 erf
.erfType
= 0x5eed1e55;
334 erf
.fError
= 0x1ead1e55;
335 hfdi
= FDICreate(fdi_alloc_bad
, fdi_free
, fdi_open
, fdi_read
,
336 fdi_write
, fdi_close
, fdi_seek
,
338 ok(hfdi
== NULL
, "Expected NULL context, got %p\n", hfdi
);
339 ok(erf
.erfOper
== FDIERROR_ALLOC_FAIL
,
340 "Expected FDIERROR_ALLOC_FAIL, got %d\n", erf
.erfOper
);
341 ok(erf
.fError
== TRUE
, "Expected TRUE, got %d\n", erf
.fError
);
342 ok(GetLastError() == 0xdeadbeef,
343 "Expected 0xdeadbeef, got %d\n", GetLastError());
344 ok(erf
.erfType
== 0, "Expected 0, got %d\n", erf
.erfType
);
347 static void test_FDIDestroy(void)
353 /* native crashes if hfdi is NULL or invalid */
355 hfdi
= FDICreate(fdi_alloc
, fdi_free
, fdi_open
, fdi_read
,
356 fdi_write
, fdi_close
, fdi_seek
,
358 ok(hfdi
!= NULL
, "Expected non-NULL context\n");
360 /* successfully destroy hfdi */
361 ret
= FDIDestroy(hfdi
);
362 ok(ret
== TRUE
, "Expected TRUE, got %d\n", ret
);
364 /* native crashes if you try to destroy hfdi twice */
367 /* try to destroy hfdi again */
368 ret
= FDIDestroy(hfdi
);
369 ok(ret
== TRUE
, "Expected TRUE, got %d\n", ret
);
373 static void createTestFile(const CHAR
*name
)
378 file
= CreateFileA(name
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, 0, NULL
);
379 ok(file
!= INVALID_HANDLE_VALUE
, "Failure to open file %s\n", name
);
380 WriteFile(file
, name
, strlen(name
), &written
, NULL
);
381 WriteFile(file
, "\n", strlen("\n"), &written
, NULL
);
385 static void create_test_files(void)
389 len
= GetCurrentDirectoryA(MAX_PATH
, CURR_DIR
);
391 if(len
&& (CURR_DIR
[len
-1] == '\\'))
394 createTestFile("a.txt");
395 createTestFile("b.txt");
396 CreateDirectoryA("testdir", NULL
);
397 createTestFile("testdir\\c.txt");
398 createTestFile("testdir\\d.txt");
401 static void delete_test_files(void)
403 DeleteFileA("a.txt");
404 DeleteFileA("b.txt");
405 DeleteFileA("testdir\\c.txt");
406 DeleteFileA("testdir\\d.txt");
407 RemoveDirectoryA("testdir");
409 DeleteFileA("extract.cab");
414 static void * CDECL
mem_alloc(ULONG cb
)
416 return HeapAlloc(GetProcessHeap(), 0, cb
);
419 static void CDECL
mem_free(void *memory
)
421 HeapFree(GetProcessHeap(), 0, memory
);
424 static BOOL CDECL
get_next_cabinet(PCCAB pccab
, ULONG cbPrevCab
, void *pv
)
429 static LONG CDECL
progress(UINT typeStatus
, ULONG cb1
, ULONG cb2
, void *pv
)
434 static int CDECL
file_placed(PCCAB pccab
, char *pszFile
, LONG cbFile
,
435 BOOL fContinuation
, void *pv
)
440 static INT_PTR CDECL
fci_open(char *pszFile
, int oflag
, int pmode
, int *err
, void *pv
)
444 DWORD dwShareMode
= 0;
445 DWORD dwCreateDisposition
= OPEN_EXISTING
;
447 dwAccess
= GENERIC_READ
| GENERIC_WRITE
;
448 /* FILE_SHARE_DELETE is not supported by Windows Me/98/95 */
449 dwShareMode
= FILE_SHARE_READ
| FILE_SHARE_WRITE
;
451 if (GetFileAttributesA(pszFile
) != INVALID_FILE_ATTRIBUTES
)
452 dwCreateDisposition
= OPEN_EXISTING
;
454 dwCreateDisposition
= CREATE_NEW
;
456 handle
= CreateFileA(pszFile
, dwAccess
, dwShareMode
, NULL
,
457 dwCreateDisposition
, 0, NULL
);
459 ok(handle
!= INVALID_HANDLE_VALUE
, "Failed to CreateFile %s\n", pszFile
);
461 return (INT_PTR
)handle
;
464 static UINT CDECL
fci_read(INT_PTR hf
, void *memory
, UINT cb
, int *err
, void *pv
)
466 HANDLE handle
= (HANDLE
)hf
;
470 res
= ReadFile(handle
, memory
, cb
, &dwRead
, NULL
);
471 ok(res
, "Failed to ReadFile\n");
476 static UINT CDECL
fci_write(INT_PTR hf
, void *memory
, UINT cb
, int *err
, void *pv
)
478 HANDLE handle
= (HANDLE
)hf
;
482 res
= WriteFile(handle
, memory
, cb
, &dwWritten
, NULL
);
483 ok(res
, "Failed to WriteFile\n");
488 static int CDECL
fci_close(INT_PTR hf
, int *err
, void *pv
)
490 HANDLE handle
= (HANDLE
)hf
;
491 ok(CloseHandle(handle
), "Failed to CloseHandle\n");
496 static LONG CDECL
fci_seek(INT_PTR hf
, LONG dist
, int seektype
, int *err
, void *pv
)
498 HANDLE handle
= (HANDLE
)hf
;
501 ret
= SetFilePointer(handle
, dist
, NULL
, seektype
);
502 ok(ret
!= INVALID_SET_FILE_POINTER
, "Failed to SetFilePointer\n");
507 static int CDECL
fci_delete(char *pszFile
, int *err
, void *pv
)
509 BOOL ret
= DeleteFileA(pszFile
);
510 ok(ret
, "Failed to DeleteFile %s\n", pszFile
);
515 static BOOL CDECL
get_temp_file(char *pszTempName
, int cbTempName
, void *pv
)
519 tempname
= HeapAlloc(GetProcessHeap(), 0, MAX_PATH
);
520 GetTempFileNameA(".", "xx", 0, tempname
);
522 if (tempname
&& (strlen(tempname
) < (unsigned)cbTempName
))
524 lstrcpyA(pszTempName
, tempname
);
525 HeapFree(GetProcessHeap(), 0, tempname
);
529 HeapFree(GetProcessHeap(), 0, tempname
);
534 static INT_PTR CDECL
get_open_info(char *pszName
, USHORT
*pdate
, USHORT
*ptime
,
535 USHORT
*pattribs
, int *err
, void *pv
)
537 BY_HANDLE_FILE_INFORMATION finfo
;
543 handle
= CreateFileA(pszName
, GENERIC_READ
, FILE_SHARE_READ
, NULL
,
544 OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
| FILE_FLAG_SEQUENTIAL_SCAN
, NULL
);
546 ok(handle
!= INVALID_HANDLE_VALUE
, "Failed to CreateFile %s\n", pszName
);
548 res
= GetFileInformationByHandle(handle
, &finfo
);
549 ok(res
, "Expected GetFileInformationByHandle to succeed\n");
551 FileTimeToLocalFileTime(&finfo
.ftLastWriteTime
, &filetime
);
552 FileTimeToDosDateTime(&filetime
, pdate
, ptime
);
554 attrs
= GetFileAttributesA(pszName
);
555 ok(attrs
!= INVALID_FILE_ATTRIBUTES
, "Failed to GetFileAttributes\n");
556 /* fixme: should convert attrs to *pattribs, make sure
557 * have a test that catches the fact that we don't?
560 return (INT_PTR
)handle
;
563 static void add_file(HFCI hfci
, char *file
)
568 lstrcpyA(path
, CURR_DIR
);
569 lstrcatA(path
, "\\");
570 lstrcatA(path
, file
);
572 res
= FCIAddFile(hfci
, path
, file
, FALSE
, get_next_cabinet
, progress
,
573 get_open_info
, tcompTYPE_MSZIP
);
574 ok(res
, "Expected FCIAddFile to succeed\n");
577 static void set_cab_parameters(PCCAB pCabParams
)
579 ZeroMemory(pCabParams
, sizeof(CCAB
));
581 pCabParams
->cb
= MEDIA_SIZE
;
582 pCabParams
->cbFolderThresh
= FOLDER_THRESHOLD
;
583 pCabParams
->setID
= 0xbeef;
584 lstrcpyA(pCabParams
->szCabPath
, CURR_DIR
);
585 lstrcatA(pCabParams
->szCabPath
, "\\");
586 lstrcpyA(pCabParams
->szCab
, "extract.cab");
589 static void create_cab_file(void)
594 static CHAR a_txt
[] = "a.txt",
596 testdir_c_txt
[] = "testdir\\c.txt",
597 testdir_d_txt
[] = "testdir\\d.txt";
600 set_cab_parameters(&cabParams
);
602 hfci
= FCICreate(&erf
, file_placed
, mem_alloc
, mem_free
, fci_open
,
603 fci_read
, fci_write
, fci_close
, fci_seek
, fci_delete
,
604 get_temp_file
, &cabParams
, NULL
);
606 ok(hfci
!= NULL
, "Failed to create an FCI context\n");
608 add_file(hfci
, a_txt
);
609 add_file(hfci
, b_txt
);
610 add_file(hfci
, testdir_c_txt
);
611 add_file(hfci
, testdir_d_txt
);
613 res
= FCIFlushCabinet(hfci
, FALSE
, get_next_cabinet
, progress
);
614 ok(res
, "Failed to flush the cabinet\n");
616 res
= FCIDestroy(hfci
);
617 ok(res
, "Failed to destroy the cabinet\n");
620 static void test_FDIIsCabinet(void)
626 FDICABINETINFO cabinfo
;
627 char temp
[] = "temp.txt";
628 char extract
[] = "extract.cab";
633 hfdi
= FDICreate(fdi_alloc
, fdi_free
, fdi_open
, fdi_read
,
634 fdi_write
, fdi_close
, fdi_seek
,
636 ok(hfdi
!= NULL
, "Expected non-NULL context\n");
638 /* native crashes if hfdi or cabinfo are NULL or invalid */
640 /* invalid file handle */
641 ZeroMemory(&cabinfo
, sizeof(FDICABINETINFO
));
642 SetLastError(0xdeadbeef);
643 ret
= FDIIsCabinet(hfdi
, -1, &cabinfo
);
644 ok(ret
== FALSE
, "Expected FALSE, got %d\n", ret
);
645 ok(GetLastError() == ERROR_INVALID_HANDLE
,
646 "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
647 ok(cabinfo
.cbCabinet
== 0, "Expected 0, got %d\n", cabinfo
.cbCabinet
);
648 ok(cabinfo
.cFiles
== 0, "Expected 0, got %d\n", cabinfo
.cFiles
);
649 ok(cabinfo
.cFolders
== 0, "Expected 0, got %d\n", cabinfo
.cFolders
);
650 ok(cabinfo
.iCabinet
== 0, "Expected 0, got %d\n", cabinfo
.iCabinet
);
651 ok(cabinfo
.setID
== 0, "Expected 0, got %d\n", cabinfo
.setID
);
653 createTestFile("temp.txt");
654 fd
= fdi_open(temp
, 0, 0);
656 /* file handle doesn't point to a cabinet */
657 ZeroMemory(&cabinfo
, sizeof(FDICABINETINFO
));
658 SetLastError(0xdeadbeef);
659 ret
= FDIIsCabinet(hfdi
, fd
, &cabinfo
);
660 ok(ret
== FALSE
, "Expected FALSE, got %d\n", ret
);
661 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
662 ok(cabinfo
.cbCabinet
== 0, "Expected 0, got %d\n", cabinfo
.cbCabinet
);
663 ok(cabinfo
.cFiles
== 0, "Expected 0, got %d\n", cabinfo
.cFiles
);
664 ok(cabinfo
.cFolders
== 0, "Expected 0, got %d\n", cabinfo
.cFolders
);
665 ok(cabinfo
.iCabinet
== 0, "Expected 0, got %d\n", cabinfo
.iCabinet
);
666 ok(cabinfo
.setID
== 0, "Expected 0, got %d\n", cabinfo
.setID
);
669 DeleteFileA("temp.txt");
672 fd
= fdi_open(extract
, 0, 0);
673 ZeroMemory(&cabinfo
, sizeof(FDICABINETINFO
));
674 SetLastError(0xdeadbeef);
675 ret
= FDIIsCabinet(hfdi
, fd
, &cabinfo
);
676 ok(ret
== TRUE
, "Expected TRUE, got %d\n", ret
);
677 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
678 ok(cabinfo
.cFiles
== 4, "Expected 4, got %d\n", cabinfo
.cFiles
);
679 ok(cabinfo
.cFolders
== 1, "Expected 1, got %d\n", cabinfo
.cFolders
);
680 ok(cabinfo
.setID
== 0xbeef, "Expected 0xbeef, got %d\n", cabinfo
.setID
);
681 ok(cabinfo
.cbCabinet
== 182, "Expected 182, got %d\n", cabinfo
.cbCabinet
);
682 ok(cabinfo
.iCabinet
== 0, "Expected 0, got %d\n", cabinfo
.iCabinet
);
690 static INT_PTR __cdecl
CopyProgress(FDINOTIFICATIONTYPE fdint
, PFDINOTIFICATION pfdin
)
695 static INT_PTR CDECL
fdi_mem_open(char *name
, int oflag
, int pmode
)
697 static const char expected
[] = "memory\\block";
698 struct mem_data
*data
;
700 ok(!strcmp(name
, expected
), "expected %s, got %s\n", expected
, name
);
701 ok(oflag
== _O_BINARY
, "expected _O_BINARY, got %x\n", oflag
);
702 ok(pmode
== (_S_IREAD
| _S_IWRITE
), "expected _S_IREAD | _S_IWRITE, got %x\n", pmode
);
704 data
= HeapAlloc(GetProcessHeap(), 0, sizeof(*data
));
705 if (!data
) return -1;
707 data
->base
= (const char *)&cab_data
;
708 data
->size
= sizeof(cab_data
);
711 trace("mem_open(%s,%x,%x) => %p\n", name
, oflag
, pmode
, data
);
712 return (INT_PTR
)data
;
715 static UINT CDECL
fdi_mem_read(INT_PTR hf
, void *pv
, UINT cb
)
717 struct mem_data
*data
= (struct mem_data
*)hf
;
718 UINT available
, cb_read
;
720 available
= data
->size
- data
->pos
;
721 cb_read
= (available
>= cb
) ? cb
: available
;
723 memcpy(pv
, data
->base
+ data
->pos
, cb_read
);
724 data
->pos
+= cb_read
;
726 /*trace("mem_read(%p,%p,%u) => %u\n", hf, pv, cb, cb_read);*/
730 static UINT CDECL
fdi_mem_write(INT_PTR hf
, void *pv
, UINT cb
)
732 static const char expected
[12] = "Hello World!";
734 trace("mem_write(%#lx,%p,%u)\n", hf
, pv
, cb
);
736 ok(hf
== 0x12345678, "expected 0x12345678, got %#lx\n", hf
);
737 ok(cb
== 12, "expected 12, got %u\n", cb
);
738 ok(!memcmp(pv
, expected
, 12), "expected %s, got %s\n", expected
, (const char *)pv
);
743 static int CDECL
fdi_mem_close(INT_PTR hf
)
745 HeapFree(GetProcessHeap(), 0, (void *)hf
);
749 static LONG CDECL
fdi_mem_seek(INT_PTR hf
, LONG dist
, int seektype
)
751 struct mem_data
*data
= (struct mem_data
*)hf
;
765 ok(0, "seek: not expected type %d\n", seektype
);
769 if (data
->pos
< 0) data
->pos
= 0;
770 if (data
->pos
> data
->size
) data
->pos
= data
->size
;
772 /*mem_seek(%p,%d,%d) => %u\n", hf, dist, seektype, data->pos);*/
776 static INT_PTR CDECL
fdi_mem_notify(FDINOTIFICATIONTYPE fdint
, FDINOTIFICATION
*info
)
778 static const char expected
[9] = "file.dat\0";
782 case fdintCLOSE_FILE_INFO
:
783 trace("mem_notify: CLOSE_FILE_INFO %s, handle %#lx\n", info
->psz1
, info
->hf
);
785 ok(!strcmp(info
->psz1
, expected
), "expected %s, got %s\n", expected
, info
->psz1
);
786 ok(info
->date
== 0x1225, "expected 0x1225, got %#x\n", info
->date
);
787 ok(info
->time
== 0x2013, "expected 0x2013, got %#x\n", info
->time
);
788 ok(info
->attribs
== 0xa114, "expected 0xa114, got %#x\n", info
->attribs
);
789 ok(info
->iFolder
== 0, "expected 0, got %#x\n", info
->iFolder
);
794 trace("mem_notify: COPY_FILE %s, %d bytes\n", info
->psz1
, info
->cb
);
796 ok(info
->cb
== 12, "expected 12, got %u\n", info
->cb
);
797 ok(!strcmp(info
->psz1
, expected
), "expected %s, got %s\n", expected
, info
->psz1
);
798 return 0x12345678; /* call write() callback */
802 trace("mem_notify(%d,%p)\n", fdint
, info
);
809 static void test_FDICopy(void)
816 char name
[] = "extract.cab";
817 char path
[MAX_PATH
+ 1];
818 char memory_block
[] = "memory\\block";
819 char memory
[] = "memory\\";
820 char block
[] = "block";
824 set_cab_parameters(&cabParams
);
826 hfci
= FCICreate(&erf
, file_placed
, mem_alloc
, mem_free
, fci_open
,
827 fci_read
, fci_write
, fci_close
, fci_seek
,
828 fci_delete
, get_temp_file
, &cabParams
, NULL
);
830 ret
= FCIFlushCabinet(hfci
, FALSE
, get_next_cabinet
, progress
);
831 ok(ret
, "Failed to flush the cabinet\n");
835 lstrcpyA(path
, CURR_DIR
);
837 /* path doesn't have a trailing backslash */
838 if (lstrlenA(path
) > 2)
840 hfdi
= FDICreate(fdi_alloc
, fdi_free
, fdi_open
, fdi_read
,
841 fdi_write
, fdi_close
, fdi_seek
,
844 SetLastError(0xdeadbeef);
845 ret
= FDICopy(hfdi
, name
, path
, 0, CopyProgress
, NULL
, 0);
846 ok(ret
== FALSE
, "Expected FALSE, got %d\n", ret
);
847 ok(GetLastError() == ERROR_INVALID_HANDLE
,
848 "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
853 skip("Running on a root drive directory.\n");
855 lstrcatA(path
, "\\");
857 hfdi
= FDICreate(fdi_alloc
, fdi_free
, fdi_open
, fdi_read
,
858 fdi_write
, fdi_close
, fdi_seek
,
861 /* cabinet with no files or folders */
862 SetLastError(0xdeadbeef);
863 ret
= FDICopy(hfdi
, name
, path
, 0, CopyProgress
, NULL
, 0);
864 ok(ret
== TRUE
, "Expected TRUE, got %d\n", ret
);
865 ok(GetLastError() == 0, "Expected 0f, got %d\n", GetLastError());
871 /* test extracting from a memory block */
872 hfdi
= FDICreate(fdi_alloc
, fdi_free
, fdi_mem_open
, fdi_mem_read
,
873 fdi_mem_write
, fdi_mem_close
, fdi_mem_seek
, cpuUNKNOWN
, &erf
);
874 ok(hfdi
!= NULL
, "FDICreate error %d\n", erf
.erfOper
);
876 fd
= fdi_mem_open(memory_block
, _O_BINARY
, _S_IREAD
| _S_IWRITE
);
877 ok(fd
!= -1, "fdi_open failed\n");
879 memset(&info
, 0, sizeof(info
));
880 ret
= FDIIsCabinet(hfdi
, fd
, &info
);
881 ok(ret
, "FDIIsCabinet error %d\n", erf
.erfOper
);
882 ok(info
.cbCabinet
== 0x59, "expected 0x59, got %#x\n", info
.cbCabinet
);
883 ok(info
.cFiles
== 1, "expected 1, got %d\n", info
.cFiles
);
884 ok(info
.cFolders
== 1, "expected 1, got %d\n", info
.cFolders
);
885 ok(info
.setID
== 0x1225, "expected 0x1225, got %#x\n", info
.setID
);
886 ok(info
.iCabinet
== 0x2013, "expected 0x2013, got %#x\n", info
.iCabinet
);
890 ret
= FDICopy(hfdi
, block
, memory
, 0, fdi_mem_notify
, NULL
, 0);
891 ok(ret
, "FDICopy error %d\n", erf
.erfOper
);