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
28 #include "wine/test.h"
30 /* make the max size large so there is only one cab file */
31 #define MEDIA_SIZE 999999999
32 #define FOLDER_THRESHOLD 900000
34 static CHAR CURR_DIR
[MAX_PATH
];
40 UCHAR signature
[4]; /* file signature */
41 ULONG reserved1
; /* reserved */
42 ULONG cbCabinet
; /* size of this cabinet file in bytes */
43 ULONG reserved2
; /* reserved */
44 ULONG coffFiles
; /* offset of the first CFFILE entry */
45 ULONG reserved3
; /* reserved */
46 UCHAR versionMinor
; /* cabinet file format version, minor */
47 UCHAR versionMajor
; /* cabinet file format version, major */
48 USHORT cFolders
; /* number of CFFOLDER entries in this cabinet */
49 USHORT cFiles
; /* number of CFFILE entries in this cabinet */
50 USHORT flags
; /* cabinet file option indicators */
51 USHORT setID
; /* must be the same for all cabinets in a set */
52 USHORT iCabinet
; /* number of this cabinet file in a set */
54 USHORT cbCFHeader
; /* (optional) size of per-cabinet reserved area */
55 UCHAR cbCFFolder
; /* (optional) size of per-folder reserved area */
56 UCHAR cbCFData
; /* (optional) size of per-datablock reserved area */
57 UCHAR abReserve
; /* (optional) per-cabinet reserved area */
58 UCHAR szCabinetPrev
; /* (optional) name of previous cabinet file */
59 UCHAR szDiskPrev
; /* (optional) name of previous disk */
60 UCHAR szCabinetNext
; /* (optional) name of next cabinet file */
61 UCHAR szDiskNext
; /* (optional) name of next disk */
67 ULONG coffCabStart
; /* offset of the first CFDATA block in this folder */
68 USHORT cCFData
; /* number of CFDATA blocks in this folder */
69 USHORT typeCompress
; /* compression type indicator */
71 UCHAR abReserve
[]; /* (optional) per-folder reserved area */
77 ULONG cbFile
; /* uncompressed size of this file in bytes */
78 ULONG uoffFolderStart
; /* uncompressed offset of this file in the folder */
79 USHORT iFolder
; /* index into the CFFOLDER area */
80 USHORT date
; /* date stamp for this file */
81 USHORT time
; /* time stamp for this file */
82 USHORT attribs
; /* attribute flags for this file */
84 UCHAR szName
[]; /* name of this file */
90 ULONG csum
; /* checksum of this CFDATA entry */
91 USHORT cbData
; /* number of compressed bytes in this block */
92 USHORT cbUncomp
; /* number of uncompressed bytes in this block */
94 UCHAR abReserve
[]; /* (optional) per-datablock reserved area */
95 UCHAR ab
[cbData
]; /* compressed data bytes */
101 struct CFHEADER header
;
102 struct CFFOLDER folder
;
104 UCHAR szName
[sizeof("file.dat")];
106 UCHAR ab
[sizeof("Hello World!")-1];
109 { {'M','S','C','F'}, 0, 0x59, 0, sizeof(struct CFHEADER
) + sizeof(struct CFFOLDER
), 0, 3,1, 1, 1, 0, 0x1225, 0x2013 },
110 { sizeof(struct CFHEADER
) + sizeof(struct CFFOLDER
) + sizeof(struct CFFILE
) + sizeof("file.dat"), 1, tcompTYPE_NONE
},
111 { sizeof("Hello World!")-1, 0, 0x1234, 0x1225, 0x2013, 0xa114 },
112 { 'f','i','l','e','.','d','a','t',0 },
113 { 0, sizeof("Hello World!")-1, sizeof("Hello World!")-1 },
114 { 'H','e','l','l','o',' ','W','o','r','l','d','!' }
127 static void * CDECL
fdi_alloc(ULONG cb
)
129 return HeapAlloc(GetProcessHeap(), 0, cb
);
132 static void * CDECL
fdi_alloc_bad(ULONG cb
)
137 static void CDECL
fdi_free(void *pv
)
139 HeapFree(GetProcessHeap(), 0, pv
);
142 static INT_PTR CDECL
fdi_open(char *pszFile
, int oflag
, int pmode
)
145 handle
= CreateFileA(pszFile
, GENERIC_READ
| GENERIC_WRITE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
,
146 OPEN_EXISTING
, 0, NULL
);
147 if (handle
== INVALID_HANDLE_VALUE
)
149 return (INT_PTR
) handle
;
152 static UINT CDECL
fdi_read(INT_PTR hf
, void *pv
, UINT cb
)
154 HANDLE handle
= (HANDLE
) hf
;
156 if (ReadFile(handle
, pv
, cb
, &dwRead
, NULL
))
161 static UINT CDECL
fdi_write(INT_PTR hf
, void *pv
, UINT cb
)
163 HANDLE handle
= (HANDLE
) hf
;
165 if (WriteFile(handle
, pv
, cb
, &dwWritten
, NULL
))
170 static int CDECL
fdi_close(INT_PTR hf
)
172 HANDLE handle
= (HANDLE
) hf
;
173 return CloseHandle(handle
) ? 0 : -1;
176 static LONG CDECL
fdi_seek(INT_PTR hf
, LONG dist
, int seektype
)
178 HANDLE handle
= (HANDLE
) hf
;
179 return SetFilePointer(handle
, dist
, NULL
, seektype
);
182 /* Callbacks for testing FDIIsCabinet with hf == 0 */
183 static INT_PTR static_fdi_handle
;
185 static INT_PTR CDECL
fdi_open_static(char *pszFile
, int oflag
, int pmode
)
187 ok(0, "FDIIsCabinet shouldn't call pfnopen\n");
191 static UINT CDECL
fdi_read_static(INT_PTR hf
, void *pv
, UINT cb
)
193 ok(hf
== 0, "unexpected hf %Ix\n", hf
);
194 return fdi_read(static_fdi_handle
, pv
, cb
);
197 static UINT CDECL
fdi_write_static(INT_PTR hf
, void *pv
, UINT cb
)
199 ok(0, "FDIIsCabinet shouldn't call pfnwrite\n");
203 static int CDECL
fdi_close_static(INT_PTR hf
)
205 ok(0, "FDIIsCabinet shouldn't call pfnclose\n");
209 static LONG CDECL
fdi_seek_static(INT_PTR hf
, LONG dist
, int seektype
)
211 ok(hf
== 0, "unexpected hf %Ix\n", hf
);
212 return fdi_seek(static_fdi_handle
, dist
, seektype
);
215 static void test_FDICreate(void)
220 /* native crashes if pfnalloc is NULL */
222 /* FDICreate does not crash with a NULL pfnfree,
223 * but FDIDestroy will crash when it tries to access it.
227 SetLastError(0xdeadbeef);
228 erf
.erfOper
= 0x1abe11ed;
229 erf
.erfType
= 0x5eed1e55;
230 erf
.fError
= 0x1ead1e55;
231 hfdi
= FDICreate(fdi_alloc
, NULL
, fdi_open
, fdi_read
,
232 fdi_write
, fdi_close
, fdi_seek
,
234 ok(hfdi
!= NULL
, "Expected non-NULL context\n");
235 ok(GetLastError() == 0xdeadbeef,
236 "Expected 0xdeadbeef, got %ld\n", GetLastError());
237 ok(erf
.erfOper
== 0x1abe11ed, "Expected 0x1abe11ed, got %d\n", erf
.erfOper
);
238 ok(erf
.erfType
== 0x5eed1e55, "Expected 0x5eed1e55, got %d\n", erf
.erfType
);
239 ok(erf
.fError
== 0x1ead1e55, "Expected 0x1ead1e55, got %d\n", erf
.fError
);
244 SetLastError(0xdeadbeef);
245 erf
.erfOper
= 0x1abe11ed;
246 erf
.erfType
= 0x5eed1e55;
247 erf
.fError
= 0x1ead1e55;
248 hfdi
= FDICreate(fdi_alloc
, fdi_free
, NULL
, fdi_read
,
249 fdi_write
, fdi_close
, fdi_seek
,
251 ok(hfdi
!= NULL
, "Expected non-NULL context\n");
252 ok(GetLastError() == 0xdeadbeef,
253 "Expected 0xdeadbeef, got %ld\n", GetLastError());
254 ok((erf
.erfOper
== 0x1abe11ed || erf
.erfOper
== 0 /* Vista */), "Expected 0x1abe11ed or 0, got %d\n", erf
.erfOper
);
255 ok((erf
.erfType
== 0x5eed1e55 || erf
.erfType
== 0 /* Vista */), "Expected 0x5eed1e55 or 0, got %d\n", erf
.erfType
);
256 ok((erf
.fError
== 0x1ead1e55 || erf
.fError
== 0 /* Vista */), "Expected 0x1ead1e55 or 0, got %d\n", erf
.fError
);
260 SetLastError(0xdeadbeef);
261 erf
.erfOper
= 0x1abe11ed;
262 erf
.erfType
= 0x5eed1e55;
263 erf
.fError
= 0x1ead1e55;
264 hfdi
= FDICreate(fdi_alloc
, fdi_free
, fdi_open
, NULL
,
265 fdi_write
, fdi_close
, fdi_seek
,
267 ok(hfdi
!= NULL
, "Expected non-NULL context\n");
268 ok(GetLastError() == 0xdeadbeef,
269 "Expected 0xdeadbeef, got %ld\n", GetLastError());
270 ok((erf
.erfOper
== 0x1abe11ed || erf
.erfOper
== 0 /* Vista */), "Expected 0x1abe11ed or 0, got %d\n", erf
.erfOper
);
271 ok((erf
.erfType
== 0x5eed1e55 || erf
.erfType
== 0 /* Vista */), "Expected 0x5eed1e55 or 0, got %d\n", erf
.erfType
);
272 ok((erf
.fError
== 0x1ead1e55 || erf
.fError
== 0 /* Vista */), "Expected 0x1ead1e55 or 0, got %d\n", erf
.fError
);
276 SetLastError(0xdeadbeef);
277 erf
.erfOper
= 0x1abe11ed;
278 erf
.erfType
= 0x5eed1e55;
279 erf
.fError
= 0x1ead1e55;
280 hfdi
= FDICreate(fdi_alloc
, fdi_free
, fdi_open
, fdi_read
,
281 NULL
, fdi_close
, fdi_seek
,
283 ok(hfdi
!= NULL
, "Expected non-NULL context\n");
284 ok(GetLastError() == 0xdeadbeef,
285 "Expected 0xdeadbeef, got %ld\n", GetLastError());
286 ok((erf
.erfOper
== 0x1abe11ed || erf
.erfOper
== 0 /* Vista */), "Expected 0x1abe11ed or 0, got %d\n", erf
.erfOper
);
287 ok((erf
.erfType
== 0x5eed1e55 || erf
.erfType
== 0 /* Vista */), "Expected 0x5eed1e55 or 0, got %d\n", erf
.erfType
);
288 ok((erf
.fError
== 0x1ead1e55 || erf
.fError
== 0 /* Vista */), "Expected 0x1ead1e55 or 0, got %d\n", erf
.fError
);
292 SetLastError(0xdeadbeef);
293 erf
.erfOper
= 0x1abe11ed;
294 erf
.erfType
= 0x5eed1e55;
295 erf
.fError
= 0x1ead1e55;
296 hfdi
= FDICreate(fdi_alloc
, fdi_free
, fdi_open
, fdi_read
,
297 fdi_write
, NULL
, fdi_seek
,
299 ok(hfdi
!= NULL
, "Expected non-NULL context\n");
300 ok(GetLastError() == 0xdeadbeef,
301 "Expected 0xdeadbeef, got %ld\n", GetLastError());
302 ok((erf
.erfOper
== 0x1abe11ed || erf
.erfOper
== 0 /* Vista */), "Expected 0x1abe11ed or 0, got %d\n", erf
.erfOper
);
303 ok((erf
.erfType
== 0x5eed1e55 || erf
.erfType
== 0 /* Vista */), "Expected 0x5eed1e55 or 0, got %d\n", erf
.erfType
);
304 ok((erf
.fError
== 0x1ead1e55 || erf
.fError
== 0 /* Vista */), "Expected 0x1ead1e55 or 0, got %d\n", erf
.fError
);
308 SetLastError(0xdeadbeef);
309 erf
.erfOper
= 0x1abe11ed;
310 erf
.erfType
= 0x5eed1e55;
311 erf
.fError
= 0x1ead1e55;
312 hfdi
= FDICreate(fdi_alloc
, fdi_free
, fdi_open
, fdi_read
,
313 fdi_write
, fdi_close
, NULL
,
315 ok(hfdi
!= NULL
, "Expected non-NULL context\n");
316 ok(GetLastError() == 0xdeadbeef,
317 "Expected 0xdeadbeef, got %ld\n", GetLastError());
318 ok((erf
.erfOper
== 0x1abe11ed || erf
.erfOper
== 0 /* Vista */), "Expected 0x1abe11ed or 0, got %d\n", erf
.erfOper
);
319 ok((erf
.erfType
== 0x5eed1e55 || erf
.erfType
== 0 /* Vista */), "Expected 0x5eed1e55 or 0, got %d\n", erf
.erfType
);
320 ok((erf
.fError
== 0x1ead1e55 || erf
.fError
== 0 /* Vista */), "Expected 0x1ead1e55 or 0, got %d\n", erf
.fError
);
324 SetLastError(0xdeadbeef);
325 erf
.erfOper
= 0x1abe11ed;
326 erf
.erfType
= 0x5eed1e55;
327 erf
.fError
= 0x1ead1e55;
328 hfdi
= FDICreate(fdi_alloc
, fdi_free
, fdi_open
, fdi_read
,
329 fdi_write
, fdi_close
, fdi_seek
,
331 /* XP sets hfdi to a non-NULL value, but Vista sets it to NULL! */
332 ok(GetLastError() == 0xdeadbeef,
333 "Expected 0xdeadbeef, got %ld\n", GetLastError());
334 /* NULL is passed to FDICreate instead of &erf, so don't retest the erf member values. */
339 SetLastError(0xdeadbeef);
340 erf
.erfOper
= 0x1abe11ed;
341 erf
.erfType
= 0x5eed1e55;
342 erf
.fError
= 0x1ead1e55;
343 hfdi
= FDICreate(fdi_alloc
, fdi_free
, fdi_open
, fdi_read
,
344 fdi_write
, fdi_close
, fdi_seek
,
346 ok(hfdi
!= NULL
, "Expected non-NULL context\n");
347 ok(GetLastError() == 0xdeadbeef,
348 "Expected 0xdeadbeef, got %ld\n", GetLastError());
349 ok((erf
.erfOper
== 0x1abe11ed || erf
.erfOper
== 0 /* Vista */), "Expected 0x1abe11ed or 0, got %d\n", erf
.erfOper
);
350 ok((erf
.erfType
== 0x5eed1e55 || erf
.erfType
== 0 /* Vista */), "Expected 0x5eed1e55 or 0, got %d\n", erf
.erfType
);
351 ok((erf
.fError
== 0x1ead1e55 || erf
.fError
== 0 /* Vista */), "Expected 0x1ead1e55 or 0, got %d\n", erf
.fError
);
356 SetLastError(0xdeadbeef);
357 erf
.erfOper
= 0x1abe11ed;
358 erf
.erfType
= 0x5eed1e55;
359 erf
.fError
= 0x1ead1e55;
360 hfdi
= FDICreate(fdi_alloc_bad
, fdi_free
, fdi_open
, fdi_read
,
361 fdi_write
, fdi_close
, fdi_seek
,
363 ok(hfdi
== NULL
, "Expected NULL context, got %p\n", hfdi
);
364 ok(erf
.erfOper
== FDIERROR_ALLOC_FAIL
,
365 "Expected FDIERROR_ALLOC_FAIL, got %d\n", erf
.erfOper
);
366 ok(erf
.fError
== TRUE
, "Expected TRUE, got %d\n", erf
.fError
);
367 ok(GetLastError() == 0xdeadbeef,
368 "Expected 0xdeadbeef, got %ld\n", GetLastError());
369 ok(erf
.erfType
== 0, "Expected 0, got %d\n", erf
.erfType
);
372 static void test_FDIDestroy(void)
378 /* native crashes if hfdi is NULL or invalid */
380 hfdi
= FDICreate(fdi_alloc
, fdi_free
, fdi_open
, fdi_read
,
381 fdi_write
, fdi_close
, fdi_seek
,
383 ok(hfdi
!= NULL
, "Expected non-NULL context\n");
385 /* successfully destroy hfdi */
386 ret
= FDIDestroy(hfdi
);
387 ok(ret
== TRUE
, "Expected TRUE, got %d\n", ret
);
389 /* native crashes if you try to destroy hfdi twice */
392 /* try to destroy hfdi again */
393 ret
= FDIDestroy(hfdi
);
394 ok(ret
== TRUE
, "Expected TRUE, got %d\n", ret
);
398 static void createTestFile(const CHAR
*name
)
403 file
= CreateFileA(name
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, 0, NULL
);
404 ok(file
!= INVALID_HANDLE_VALUE
, "Failure to open file %s\n", name
);
405 WriteFile(file
, name
, strlen(name
), &written
, NULL
);
406 WriteFile(file
, "\n", strlen("\n"), &written
, NULL
);
410 static void create_test_files(void)
414 len
= GetCurrentDirectoryA(MAX_PATH
, CURR_DIR
);
416 if(len
&& (CURR_DIR
[len
-1] == '\\'))
419 createTestFile("a.txt");
420 createTestFile("b.txt");
421 CreateDirectoryA("testdir", NULL
);
422 createTestFile("testdir\\c.txt");
423 createTestFile("testdir\\d.txt");
426 static void delete_test_files(void)
428 DeleteFileA("a.txt");
429 DeleteFileA("b.txt");
430 DeleteFileA("testdir\\c.txt");
431 DeleteFileA("testdir\\d.txt");
432 RemoveDirectoryA("testdir");
434 DeleteFileA("extract.cab");
439 static void * CDECL
mem_alloc(ULONG cb
)
441 return HeapAlloc(GetProcessHeap(), 0, cb
);
444 static void CDECL
mem_free(void *memory
)
446 HeapFree(GetProcessHeap(), 0, memory
);
449 static BOOL CDECL
get_next_cabinet(PCCAB pccab
, ULONG cbPrevCab
, void *pv
)
454 static LONG CDECL
progress(UINT typeStatus
, ULONG cb1
, ULONG cb2
, void *pv
)
459 static int CDECL
file_placed(PCCAB pccab
, char *pszFile
, LONG cbFile
,
460 BOOL fContinuation
, void *pv
)
465 static INT_PTR CDECL
fci_open(char *pszFile
, int oflag
, int pmode
, int *err
, void *pv
)
469 DWORD dwShareMode
= 0;
470 DWORD dwCreateDisposition
= OPEN_EXISTING
;
472 dwAccess
= GENERIC_READ
| GENERIC_WRITE
;
473 /* FILE_SHARE_DELETE is not supported by Windows Me/98/95 */
474 dwShareMode
= FILE_SHARE_READ
| FILE_SHARE_WRITE
;
476 if (GetFileAttributesA(pszFile
) != INVALID_FILE_ATTRIBUTES
)
477 dwCreateDisposition
= OPEN_EXISTING
;
479 dwCreateDisposition
= CREATE_NEW
;
481 handle
= CreateFileA(pszFile
, dwAccess
, dwShareMode
, NULL
,
482 dwCreateDisposition
, 0, NULL
);
484 ok(handle
!= INVALID_HANDLE_VALUE
, "Failed to CreateFile %s\n", pszFile
);
486 return (INT_PTR
)handle
;
489 static UINT CDECL
fci_read(INT_PTR hf
, void *memory
, UINT cb
, int *err
, void *pv
)
491 HANDLE handle
= (HANDLE
)hf
;
495 res
= ReadFile(handle
, memory
, cb
, &dwRead
, NULL
);
496 ok(res
, "Failed to ReadFile\n");
501 static UINT CDECL
fci_write(INT_PTR hf
, void *memory
, UINT cb
, int *err
, void *pv
)
503 HANDLE handle
= (HANDLE
)hf
;
507 res
= WriteFile(handle
, memory
, cb
, &dwWritten
, NULL
);
508 ok(res
, "Failed to WriteFile\n");
513 static int CDECL
fci_close(INT_PTR hf
, int *err
, void *pv
)
515 HANDLE handle
= (HANDLE
)hf
;
516 ok(CloseHandle(handle
), "Failed to CloseHandle\n");
521 static LONG CDECL
fci_seek(INT_PTR hf
, LONG dist
, int seektype
, int *err
, void *pv
)
523 HANDLE handle
= (HANDLE
)hf
;
526 ret
= SetFilePointer(handle
, dist
, NULL
, seektype
);
527 ok(ret
!= INVALID_SET_FILE_POINTER
, "Failed to SetFilePointer\n");
532 static int CDECL
fci_delete(char *pszFile
, int *err
, void *pv
)
534 BOOL ret
= DeleteFileA(pszFile
);
535 ok(ret
, "Failed to DeleteFile %s\n", pszFile
);
540 static BOOL CDECL
get_temp_file(char *pszTempName
, int cbTempName
, void *pv
)
544 tempname
= HeapAlloc(GetProcessHeap(), 0, MAX_PATH
);
545 GetTempFileNameA(".", "xx", 0, tempname
);
547 if (tempname
&& (strlen(tempname
) < (unsigned)cbTempName
))
549 lstrcpyA(pszTempName
, tempname
);
550 HeapFree(GetProcessHeap(), 0, tempname
);
554 HeapFree(GetProcessHeap(), 0, tempname
);
559 static INT_PTR CDECL
get_open_info(char *pszName
, USHORT
*pdate
, USHORT
*ptime
,
560 USHORT
*pattribs
, int *err
, void *pv
)
562 BY_HANDLE_FILE_INFORMATION finfo
;
568 handle
= CreateFileA(pszName
, GENERIC_READ
, FILE_SHARE_READ
, NULL
,
569 OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
| FILE_FLAG_SEQUENTIAL_SCAN
, NULL
);
571 ok(handle
!= INVALID_HANDLE_VALUE
, "Failed to CreateFile %s\n", pszName
);
573 res
= GetFileInformationByHandle(handle
, &finfo
);
574 ok(res
, "Expected GetFileInformationByHandle to succeed\n");
576 FileTimeToLocalFileTime(&finfo
.ftLastWriteTime
, &filetime
);
577 FileTimeToDosDateTime(&filetime
, pdate
, ptime
);
579 attrs
= GetFileAttributesA(pszName
);
580 ok(attrs
!= INVALID_FILE_ATTRIBUTES
, "Failed to GetFileAttributes\n");
581 /* fixme: should convert attrs to *pattribs, make sure
582 * have a test that catches the fact that we don't?
585 return (INT_PTR
)handle
;
588 static void add_file(HFCI hfci
, char *file
)
593 lstrcpyA(path
, CURR_DIR
);
594 lstrcatA(path
, "\\");
595 lstrcatA(path
, file
);
597 res
= FCIAddFile(hfci
, path
, file
, FALSE
, get_next_cabinet
, progress
,
598 get_open_info
, tcompTYPE_MSZIP
);
599 ok(res
, "Expected FCIAddFile to succeed\n");
602 static void set_cab_parameters(PCCAB pCabParams
)
604 ZeroMemory(pCabParams
, sizeof(CCAB
));
606 pCabParams
->cb
= MEDIA_SIZE
;
607 pCabParams
->cbFolderThresh
= FOLDER_THRESHOLD
;
608 pCabParams
->setID
= 0xbeef;
609 lstrcpyA(pCabParams
->szCabPath
, CURR_DIR
);
610 lstrcatA(pCabParams
->szCabPath
, "\\");
611 lstrcpyA(pCabParams
->szCab
, "extract.cab");
614 static void create_cab_file(void)
619 static CHAR a_txt
[] = "a.txt",
621 testdir_c_txt
[] = "testdir\\c.txt",
622 testdir_d_txt
[] = "testdir\\d.txt";
625 set_cab_parameters(&cabParams
);
627 hfci
= FCICreate(&erf
, file_placed
, mem_alloc
, mem_free
, fci_open
,
628 fci_read
, fci_write
, fci_close
, fci_seek
, fci_delete
,
629 get_temp_file
, &cabParams
, NULL
);
631 ok(hfci
!= NULL
, "Failed to create an FCI context\n");
633 add_file(hfci
, a_txt
);
634 add_file(hfci
, b_txt
);
635 add_file(hfci
, testdir_c_txt
);
636 add_file(hfci
, testdir_d_txt
);
638 res
= FCIFlushCabinet(hfci
, FALSE
, get_next_cabinet
, progress
);
639 ok(res
, "Failed to flush the cabinet\n");
641 res
= FCIDestroy(hfci
);
642 ok(res
, "Failed to destroy the cabinet\n");
645 static void test_FDIIsCabinet(void)
651 FDICABINETINFO cabinfo
;
652 char temp
[] = "temp.txt";
653 char extract
[] = "extract.cab";
658 hfdi
= FDICreate(fdi_alloc
, fdi_free
, fdi_open
, fdi_read
,
659 fdi_write
, fdi_close
, fdi_seek
,
661 ok(hfdi
!= NULL
, "Expected non-NULL context\n");
663 /* native crashes if hfdi or cabinfo are NULL or invalid */
665 /* invalid file handle */
666 ZeroMemory(&cabinfo
, sizeof(FDICABINETINFO
));
667 SetLastError(0xdeadbeef);
668 ret
= FDIIsCabinet(hfdi
, -1, &cabinfo
);
669 ok(ret
== FALSE
, "Expected FALSE, got %d\n", ret
);
670 ok(GetLastError() == ERROR_INVALID_HANDLE
,
671 "Expected ERROR_INVALID_HANDLE, got %ld\n", GetLastError());
672 ok(cabinfo
.cbCabinet
== 0, "Expected 0, got %ld\n", cabinfo
.cbCabinet
);
673 ok(cabinfo
.cFiles
== 0, "Expected 0, got %d\n", cabinfo
.cFiles
);
674 ok(cabinfo
.cFolders
== 0, "Expected 0, got %d\n", cabinfo
.cFolders
);
675 ok(cabinfo
.iCabinet
== 0, "Expected 0, got %d\n", cabinfo
.iCabinet
);
676 ok(cabinfo
.setID
== 0, "Expected 0, got %d\n", cabinfo
.setID
);
678 createTestFile("temp.txt");
679 fd
= fdi_open(temp
, 0, 0);
681 /* file handle doesn't point to a cabinet */
682 ZeroMemory(&cabinfo
, sizeof(FDICABINETINFO
));
683 SetLastError(0xdeadbeef);
684 ret
= FDIIsCabinet(hfdi
, fd
, &cabinfo
);
685 ok(ret
== FALSE
, "Expected FALSE, got %d\n", ret
);
686 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
687 ok(cabinfo
.cbCabinet
== 0, "Expected 0, got %ld\n", cabinfo
.cbCabinet
);
688 ok(cabinfo
.cFiles
== 0, "Expected 0, got %d\n", cabinfo
.cFiles
);
689 ok(cabinfo
.cFolders
== 0, "Expected 0, got %d\n", cabinfo
.cFolders
);
690 ok(cabinfo
.iCabinet
== 0, "Expected 0, got %d\n", cabinfo
.iCabinet
);
691 ok(cabinfo
.setID
== 0, "Expected 0, got %d\n", cabinfo
.setID
);
694 DeleteFileA("temp.txt");
697 fd
= fdi_open(extract
, 0, 0);
698 ZeroMemory(&cabinfo
, sizeof(FDICABINETINFO
));
699 SetLastError(0xdeadbeef);
700 ret
= FDIIsCabinet(hfdi
, fd
, &cabinfo
);
701 ok(ret
== TRUE
, "Expected TRUE, got %d\n", ret
);
702 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
703 ok(cabinfo
.cFiles
== 4, "Expected 4, got %d\n", cabinfo
.cFiles
);
704 ok(cabinfo
.cFolders
== 1, "Expected 1, got %d\n", cabinfo
.cFolders
);
705 ok(cabinfo
.setID
== 0xbeef, "Expected 0xbeef, got %d\n", cabinfo
.setID
);
706 ok(cabinfo
.cbCabinet
== 182, "Expected 182, got %ld\n", cabinfo
.cbCabinet
);
707 ok(cabinfo
.iCabinet
== 0, "Expected 0, got %d\n", cabinfo
.iCabinet
);
712 hfdi
= FDICreate(fdi_alloc
, fdi_free
, fdi_open_static
, fdi_read_static
,
713 fdi_write_static
, fdi_close_static
, fdi_seek_static
,
715 ok(hfdi
!= NULL
, "Expected non-NULL context\n");
717 /* FDIIsCabinet accepts hf == 0 even though it's not a valid result of pfnopen */
718 static_fdi_handle
= fdi_open(extract
, 0, 0);
719 ZeroMemory(&cabinfo
, sizeof(FDICABINETINFO
));
720 SetLastError(0xdeadbeef);
721 ret
= FDIIsCabinet(hfdi
, 0, &cabinfo
);
722 ok(ret
== TRUE
, "Expected TRUE, got %d\n", ret
);
723 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
724 ok(cabinfo
.cFiles
== 4, "Expected 4, got %d\n", cabinfo
.cFiles
);
725 ok(cabinfo
.cFolders
== 1, "Expected 1, got %d\n", cabinfo
.cFolders
);
726 ok(cabinfo
.setID
== 0xbeef, "Expected 0xbeef, got %d\n", cabinfo
.setID
);
727 ok(cabinfo
.cbCabinet
== 182, "Expected 182, got %ld\n", cabinfo
.cbCabinet
);
728 ok(cabinfo
.iCabinet
== 0, "Expected 0, got %d\n", cabinfo
.iCabinet
);
730 fdi_close(static_fdi_handle
);
737 static INT_PTR __cdecl
CopyProgress(FDINOTIFICATIONTYPE fdint
, PFDINOTIFICATION pfdin
)
739 return 37; /* doc says 0, but anything != -1 apparently means success as well */
742 static INT_PTR CDECL
fdi_mem_open(char *name
, int oflag
, int pmode
)
744 static const char expected
[] = "memory\\block";
745 struct mem_data
*data
;
747 ok(!strcmp(name
, expected
), "expected %s, got %s\n", expected
, name
);
748 ok(oflag
== _O_BINARY
, "expected _O_BINARY, got %x\n", oflag
);
749 ok(pmode
== (_S_IREAD
| _S_IWRITE
), "expected _S_IREAD | _S_IWRITE, got %x\n", pmode
);
751 data
= HeapAlloc(GetProcessHeap(), 0, sizeof(*data
));
752 if (!data
) return -1;
754 data
->base
= (const char *)&cab_data
;
755 data
->size
= sizeof(cab_data
);
758 trace("mem_open(%s,%x,%x) => %p\n", name
, oflag
, pmode
, data
);
759 return (INT_PTR
)data
;
762 static UINT CDECL
fdi_mem_read(INT_PTR hf
, void *pv
, UINT cb
)
764 struct mem_data
*data
= (struct mem_data
*)hf
;
765 UINT available
, cb_read
;
767 available
= data
->size
- data
->pos
;
768 cb_read
= (available
>= cb
) ? cb
: available
;
770 memcpy(pv
, data
->base
+ data
->pos
, cb_read
);
771 data
->pos
+= cb_read
;
773 /*trace("mem_read(%p,%p,%u) => %u\n", hf, pv, cb, cb_read);*/
777 static UINT CDECL
fdi_mem_write(INT_PTR hf
, void *pv
, UINT cb
)
779 static const char expected
[] = "Hello World!";
781 trace("mem_write(%#Ix,%p,%u)\n", hf
, pv
, cb
);
783 ok(hf
== 0x12345678, "expected 0x12345678, got %#Ix\n", hf
);
784 ok(cb
== 12, "expected 12, got %u\n", cb
);
785 ok(!memcmp(pv
, expected
, 12), "expected %s, got %s\n", expected
, (const char *)pv
);
790 static int CDECL
fdi_mem_close(INT_PTR hf
)
792 HeapFree(GetProcessHeap(), 0, (void *)hf
);
796 static LONG CDECL
fdi_mem_seek(INT_PTR hf
, LONG dist
, int seektype
)
798 struct mem_data
*data
= (struct mem_data
*)hf
;
812 ok(0, "seek: not expected type %d\n", seektype
);
816 if (data
->pos
< 0) data
->pos
= 0;
817 if (data
->pos
> data
->size
) data
->pos
= data
->size
;
819 /*mem_seek(%p,%d,%d) => %u\n", hf, dist, seektype, data->pos);*/
823 static INT_PTR CDECL
fdi_mem_notify(FDINOTIFICATIONTYPE fdint
, FDINOTIFICATION
*info
)
825 static const char expected
[9] = "file.dat\0";
829 case fdintCLOSE_FILE_INFO
:
830 trace("mem_notify: CLOSE_FILE_INFO %s, handle %#Ix\n", info
->psz1
, info
->hf
);
832 ok(!strcmp(info
->psz1
, expected
), "expected %s, got %s\n", expected
, info
->psz1
);
833 ok(info
->date
== 0x1225, "expected 0x1225, got %#x\n", info
->date
);
834 ok(info
->time
== 0x2013, "expected 0x2013, got %#x\n", info
->time
);
835 ok(info
->attribs
== 0xa114, "expected 0xa114, got %#x\n", info
->attribs
);
836 ok(info
->iFolder
== 0x1234, "expected 0x1234, got %#x\n", info
->iFolder
);
841 trace("mem_notify: COPY_FILE %s, %ld bytes\n", info
->psz1
, info
->cb
);
843 ok(info
->cb
== 12, "expected 12, got %lu\n", info
->cb
);
844 ok(!strcmp(info
->psz1
, expected
), "expected %s, got %s\n", expected
, info
->psz1
);
845 ok(info
->iFolder
== 0x1234, "expected 0x1234, got %#x\n", info
->iFolder
);
846 return 0x12345678; /* call write() callback */
850 trace("mem_notify(%d,%p)\n", fdint
, info
);
857 static void test_FDICopy(void)
864 char name
[] = "extract.cab";
865 char path
[MAX_PATH
+ 1];
866 char memory_block
[] = "memory\\block";
867 char memory
[] = "memory\\";
868 char block
[] = "block";
872 set_cab_parameters(&cabParams
);
874 hfci
= FCICreate(&erf
, file_placed
, mem_alloc
, mem_free
, fci_open
,
875 fci_read
, fci_write
, fci_close
, fci_seek
,
876 fci_delete
, get_temp_file
, &cabParams
, NULL
);
878 ret
= FCIFlushCabinet(hfci
, FALSE
, get_next_cabinet
, progress
);
879 ok(ret
, "Failed to flush the cabinet\n");
883 lstrcpyA(path
, CURR_DIR
);
885 /* path doesn't have a trailing backslash */
886 if (lstrlenA(path
) > 2)
888 hfdi
= FDICreate(fdi_alloc
, fdi_free
, fdi_open
, fdi_read
,
889 fdi_write
, fdi_close
, fdi_seek
,
892 SetLastError(0xdeadbeef);
893 ret
= FDICopy(hfdi
, name
, path
, 0, CopyProgress
, NULL
, 0);
894 ok(ret
== FALSE
, "Expected FALSE, got %d\n", ret
);
895 ok(GetLastError() == ERROR_INVALID_HANDLE
,
896 "Expected ERROR_INVALID_HANDLE, got %ld\n", GetLastError());
901 skip("Running on a root drive directory.\n");
903 lstrcatA(path
, "\\");
905 hfdi
= FDICreate(fdi_alloc
, fdi_free
, fdi_open
, fdi_read
,
906 fdi_write
, fdi_close
, fdi_seek
,
909 /* cabinet with no files or folders */
910 SetLastError(0xdeadbeef);
911 ret
= FDICopy(hfdi
, name
, path
, 0, CopyProgress
, NULL
, 0);
912 ok(ret
== TRUE
, "Expected TRUE, got %d\n", ret
);
913 ok(GetLastError() == 0, "Expected 0f, got %ld\n", GetLastError());
919 /* test extracting from a memory block */
920 hfdi
= FDICreate(fdi_alloc
, fdi_free
, fdi_mem_open
, fdi_mem_read
,
921 fdi_mem_write
, fdi_mem_close
, fdi_mem_seek
, cpuUNKNOWN
, &erf
);
922 ok(hfdi
!= NULL
, "FDICreate error %d\n", erf
.erfOper
);
924 fd
= fdi_mem_open(memory_block
, _O_BINARY
, _S_IREAD
| _S_IWRITE
);
925 ok(fd
!= -1, "fdi_open failed\n");
927 memset(&info
, 0, sizeof(info
));
928 ret
= FDIIsCabinet(hfdi
, fd
, &info
);
929 ok(ret
, "FDIIsCabinet error %d\n", erf
.erfOper
);
930 ok(info
.cbCabinet
== 0x59, "expected 0x59, got %#lx\n", info
.cbCabinet
);
931 ok(info
.cFiles
== 1, "expected 1, got %d\n", info
.cFiles
);
932 ok(info
.cFolders
== 1, "expected 1, got %d\n", info
.cFolders
);
933 ok(info
.setID
== 0x1225, "expected 0x1225, got %#x\n", info
.setID
);
934 ok(info
.iCabinet
== 0x2013, "expected 0x2013, got %#x\n", info
.iCabinet
);
938 ret
= FDICopy(hfdi
, block
, memory
, 0, fdi_mem_notify
, NULL
, 0);
939 ok(ret
, "FDICopy error %d\n", erf
.erfOper
);