Example #1
1
static int list_cabinet( char *cab_dir )
{
    ERF erf;
    int ret = 0;
    HFDI fdi = FDICreate( cab_alloc, cab_free, fdi_open, fdi_read,
                          fdi_write, fdi_close, fdi_lseek, cpuUNKNOWN, &erf );

    if (!FDICopy( fdi, opt_cab_file, cab_dir, 0, list_notify, NULL, NULL )) ret = GetLastError();
    FDIDestroy( fdi );
    return ret;
}
Example #2
0
File: fdi.c Project: devyn/wine
static void test_FDIDestroy(void)
{
    HFDI hfdi;
    ERF erf;
    BOOL ret;

    /* native crashes if hfdi is NULL or invalid */

    hfdi = FDICreate(fdi_alloc, fdi_free, fdi_open, fdi_read,
                     fdi_write, fdi_close, fdi_seek,
                     cpuUNKNOWN, &erf);
    ok(hfdi != NULL, "Expected non-NULL context\n");

    /* successfully destroy hfdi */
    ret = FDIDestroy(hfdi);
    ok(ret == TRUE, "Expected TRUE, got %d\n", ret);

    /* native crashes if you try to destroy hfdi twice */
    if (0)
    {
        /* try to destroy hfdi again */
        ret = FDIDestroy(hfdi);
        ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
    }
}
Example #3
0
/***********************************************************************
 *            extract_cabinet_file
 *
 * Extract files from a cab file.
 */
static BOOL extract_cabinet_file(MSIPACKAGE* package, LPCWSTR source, 
                                 LPCWSTR path)
{
    HFDI hfdi;
    ERF erf;
    BOOL ret;
    char *cabinet;
    char *cab_path;
    CabData data;

    TRACE("Extracting %s to %s\n",debugstr_w(source), debugstr_w(path));

    hfdi = FDICreate(cabinet_alloc,
                     cabinet_free,
                     cabinet_open,
                     cabinet_read,
                     cabinet_write,
                     cabinet_close,
                     cabinet_seek,
                     0,
                     &erf);
    if (!hfdi)
    {
        ERR("FDICreate failed\n");
        return FALSE;
    }

    if (!(cabinet = strdupWtoA( source )))
    {
        FDIDestroy(hfdi);
        return FALSE;
    }
    if (!(cab_path = strdupWtoA( path )))
    {
        FDIDestroy(hfdi);
        msi_free(cabinet);
        return FALSE;
    }

    data.package = package;
    data.cab_path = cab_path;

    ret = FDICopy(hfdi, cabinet, "", 0, cabinet_notify, NULL, &data);

    if (!ret)
        ERR("FDICopy failed\n");

    FDIDestroy(hfdi);

    msi_free(cabinet);
    msi_free(cab_path);

    return ret;
}
Example #4
0
/**
 * ExtractCabResource
 **/
UINT __fastcall ExtractCabResource( PSTR pszOutputPath, PSTR pszOutputPathAppend )
{
	ERF erf;

	EXTRACTDATA ed = {
		pszOutputPath,        // PSTR pszOutputPath
		pszOutputPathAppend,  // PSTR pszOutputPathAppend
		0                     // UINT uExtractedFiles
	};

	HFDI hfdi = FDICreate(
		fdimalloc,
		fdifree,
		fdiopen,
		fdiread,
		fdiwrite,
		fdiclose,
		fdiseek,
		cpuUNKNOWN,
		&erf
	);

	if (hfdi)
	{
		FDICopy(hfdi, "0", pszOutputPath, 0, fdiNotify, NULL, &ed);
		FDIDestroy(hfdi);
	}

	return(ed.uExtractedFiles);
}
Example #5
0
VOID
TermDiamond(
    VOID
    )
{
    if(FdiContext) {
        FDIDestroy(FdiContext);
        FdiContext = NULL;
    }
}
Example #6
0
PVOID SfcabExtractMemory(
	PVOID CabPtr,
	ULONG CabSize,
	PULONG ExtractedBytes
	)
{

	HFDI hfdi;
	ERF erf;
	CHAR text[32];
	CHAR name[1];
	PVOID Buffer = NULL;
	CABDATA Data;
	
	if (ExtractedBytes == NULL)
		return NULL;

	__try {

		RtlSecureZeroMemory(&erf, sizeof(ERF));
		hfdi = FDICreate((PFNALLOC)fdiAlloc, (PFNFREE)fdiFree, (PFNOPEN)fdiOpen, (PFNREAD)fdiRead,
			(PFNWRITE)fdiWrite, (PFNCLOSE)fdiClose, (PFNSEEK)fdiSeek, cpu80386, &erf);

		if (hfdi) {

			g_CabParam.Buffer = CabPtr;
			g_CabParam.Size = CabSize;
			g_CabParam.Offset = 0;

			RtlSecureZeroMemory(&text, sizeof(text));
#ifdef _WIN64
			u64tostr_a((ULONG_PTR)&g_CabParam, text);
#else 
			ultostr_a((ULONG_PTR)&g_CabParam, text);
#endif

			name[0] = 0;

			Data.Size = '_';
			Data.Buffer = NULL;
			Data.Offset = 0;
			if (FDICopy(hfdi, name, text, 0, fdiNotify, 0, &Data)) {
				Buffer = Data.Buffer;
				*ExtractedBytes = Data.Size;
			}
			FDIDestroy(hfdi);
		}
	}
	__except (EXCEPTION_EXECUTE_HANDLER)
	{
		return NULL;
	}
	return Buffer;
}
Example #7
0
static int extract_cabinet( char *cab_dir )
{
    ERF erf;
    int ret = 0;
    HFDI fdi = FDICreate( cab_alloc, cab_free, fdi_open, fdi_read,
                          fdi_write, fdi_close, fdi_lseek, cpuUNKNOWN, &erf );

    if (!FDICopy( fdi, opt_cab_file, cab_dir, 0, extract_notify, NULL, NULL ))
    {
        ret = GetLastError();
        WINE_WARN("FDICopy() failed: code %u\n", ret);
    }
    FDIDestroy( fdi );
    return ret;
}
Example #8
0
/***********************************************************************
 *            extract_cabinet_file
 *
 * Extract files from a cab file.
 */
static BOOL extract_cabinet_file(MSIPACKAGE* package, struct media_info *mi)
{
    LPSTR cabinet, cab_path = NULL;
    LPWSTR ptr;
    HFDI hfdi;
    ERF erf;
    BOOL ret = FALSE;
    CabData data;

    TRACE("Extracting %s\n", debugstr_w(mi->source));

    hfdi = FDICreate(cabinet_alloc, cabinet_free, cabinet_open, cabinet_read,
                     cabinet_write, cabinet_close, cabinet_seek, 0, &erf);
    if (!hfdi)
    {
        ERR("FDICreate failed\n");
        return FALSE;
    }

    ptr = strrchrW(mi->source, '\\') + 1;
    cabinet = strdupWtoA(ptr);
    if (!cabinet)
        goto done;

    cab_path = strdupWtoA(mi->source);
    if (!cab_path)
        goto done;

    cab_path[ptr - mi->source] = '\0';

    data.package = package;
    data.mi = mi;

    ret = FDICopy(hfdi, cabinet, cab_path, 0, cabinet_notify, NULL, &data);
    if (!ret)
        ERR("FDICopy failed\n");

done:
    FDIDestroy(hfdi);
    msi_free(cabinet);
    msi_free(cab_path);

    if (ret)
        mi->is_extracted = TRUE;

    return ret;
}
Example #9
0
File: fdi.c Project: devyn/wine
static void test_FDICopy(void)
{
    CCAB cabParams;
    HFDI hfdi;
    HFCI hfci;
    ERF erf;
    BOOL ret;
    char name[] = "extract.cab";
    char path[MAX_PATH + 1];

    GetCurrentDirectoryA(MAX_PATH, path);

    set_cab_parameters(&cabParams);

    hfci = FCICreate(&erf, file_placed, mem_alloc, mem_free, fci_open,
                     fci_read, fci_write, fci_close, fci_seek,
                     fci_delete, get_temp_file, &cabParams, NULL);

    ret = FCIFlushCabinet(hfci, FALSE, get_next_cabinet, progress);
    ok(ret, "Failed to flush the cabinet\n");

    FCIDestroy(hfci);

    hfdi = FDICreate(fdi_alloc, fdi_free, fdi_open, fdi_read,
                     fdi_write, fdi_close, fdi_seek,
                     cpuUNKNOWN, &erf);

    /* cabinet with no files or folders */
    SetLastError(0xdeadbeef);
    ret = FDICopy(hfdi, name, path, 0, CopyProgress, NULL, 0);
    ok(ret == FALSE, "Expected FALSE, got %d\n", ret);
    todo_wine
    {
        ok(GetLastError() == ERROR_INVALID_HANDLE,
           "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
    }

    FDIDestroy(hfdi);
    DeleteFileA(name);
}
Example #10
0
void STDCALL gcabd_destroy( HFDI hfdi )
{
   FDIDestroy( hfdi );
}
Example #11
0
File: fdi.c Project: devyn/wine
static void test_FDICreate(void)
{
    HFDI hfdi;
    ERF erf;

    /* native crashes if pfnalloc is NULL */

    /* FDICreate does not crash with a NULL pfnfree,
     * but FDIDestroy will crash when it tries to access it.
     */
    if (0)
    {
        SetLastError(0xdeadbeef);
        erf.erfOper = 0xcafefeed;
        erf.erfType = 0xdeadbabe;
        erf.fError = 0xdecaface;
        hfdi = FDICreate(fdi_alloc, NULL, fdi_open, fdi_read,
                         fdi_write, fdi_close, fdi_seek,
                         cpuUNKNOWN, &erf);
        ok(hfdi != NULL, "Expected non-NULL context\n");
        ok(GetLastError() == 0xdeadbeef,
           "Expected 0xdeadbeef, got %d\n", GetLastError());
        ok(erf.erfOper == 0xcafefeed, "Expected 0xcafefeed, got %d\n", erf.erfOper);
        ok(erf.erfType == 0xdeadbabe, "Expected 0xdeadbabe, got %d\n", erf.erfType);
        ok(erf.fError == 0xdecaface, "Expected 0xdecaface, got %d\n", erf.fError);

        FDIDestroy(hfdi);
    }

    SetLastError(0xdeadbeef);
    erf.erfOper = 0xcafefeed;
    erf.erfType = 0xdeadbabe;
    erf.fError = 0xdecaface;
    hfdi = FDICreate(fdi_alloc, fdi_free, NULL, fdi_read,
                     fdi_write, fdi_close, fdi_seek,
                     cpuUNKNOWN, &erf);
    ok(hfdi != NULL, "Expected non-NULL context\n");
    ok(GetLastError() == 0xdeadbeef,
       "Expected 0xdeadbeef, got %d\n", GetLastError());
    ok((erf.erfOper == 0xcafefeed || erf.erfOper == 0 /* Vista */), "Expected 0xcafefeed or 0, got %d\n", erf.erfOper);
    ok((erf.erfType == 0xdeadbabe || erf.erfType == 0 /* Vista */), "Expected 0xdeadbabe or 0, got %d\n", erf.erfType);
    ok((erf.fError == 0xdecaface || erf.fError == 0 /* Vista */), "Expected 0xdecaface or 0, got %d\n", erf.fError);

    FDIDestroy(hfdi);

    SetLastError(0xdeadbeef);
    erf.erfOper = 0xcafefeed;
    erf.erfType = 0xdeadbabe;
    erf.fError = 0xdecaface;
    hfdi = FDICreate(fdi_alloc, fdi_free, fdi_open, NULL,
                     fdi_write, fdi_close, fdi_seek,
                     cpuUNKNOWN, &erf);
    ok(hfdi != NULL, "Expected non-NULL context\n");
    ok(GetLastError() == 0xdeadbeef,
       "Expected 0xdeadbeef, got %d\n", GetLastError());
    ok((erf.erfOper == 0xcafefeed || erf.erfOper == 0 /* Vista */), "Expected 0xcafefeed or 0, got %d\n", erf.erfOper);
    ok((erf.erfType == 0xdeadbabe || erf.erfType == 0 /* Vista */), "Expected 0xdeadbabe or 0, got %d\n", erf.erfType);
    ok((erf.fError == 0xdecaface || erf.fError == 0 /* Vista */), "Expected 0xdecaface or 0, got %d\n", erf.fError);

    FDIDestroy(hfdi);

    SetLastError(0xdeadbeef);
    erf.erfOper = 0xcafefeed;
    erf.erfType = 0xdeadbabe;
    erf.fError = 0xdecaface;
    hfdi = FDICreate(fdi_alloc, fdi_free, fdi_open, fdi_read,
                     NULL, fdi_close, fdi_seek,
                     cpuUNKNOWN, &erf);
    ok(hfdi != NULL, "Expected non-NULL context\n");
    ok(GetLastError() == 0xdeadbeef,
       "Expected 0xdeadbeef, got %d\n", GetLastError());
    ok((erf.erfOper == 0xcafefeed || erf.erfOper == 0 /* Vista */), "Expected 0xcafefeed or 0, got %d\n", erf.erfOper);
    ok((erf.erfType == 0xdeadbabe || erf.erfType == 0 /* Vista */), "Expected 0xdeadbabe or 0, got %d\n", erf.erfType);
    ok((erf.fError == 0xdecaface || erf.fError == 0 /* Vista */), "Expected 0xdecaface or 0, got %d\n", erf.fError);

    FDIDestroy(hfdi);

    SetLastError(0xdeadbeef);
    erf.erfOper = 0xcafefeed;
    erf.erfType = 0xdeadbabe;
    erf.fError = 0xdecaface;
    hfdi = FDICreate(fdi_alloc, fdi_free, fdi_open, fdi_read,
                     fdi_write, NULL, fdi_seek,
                     cpuUNKNOWN, &erf);
    ok(hfdi != NULL, "Expected non-NULL context\n");
    ok(GetLastError() == 0xdeadbeef,
       "Expected 0xdeadbeef, got %d\n", GetLastError());
    ok((erf.erfOper == 0xcafefeed || erf.erfOper == 0 /* Vista */), "Expected 0xcafefeed or 0, got %d\n", erf.erfOper);
    ok((erf.erfType == 0xdeadbabe || erf.erfType == 0 /* Vista */), "Expected 0xdeadbabe or 0, got %d\n", erf.erfType);
    ok((erf.fError == 0xdecaface || erf.fError == 0 /* Vista */), "Expected 0xdecaface or 0, got %d\n", erf.fError);

    FDIDestroy(hfdi);

    SetLastError(0xdeadbeef);
    erf.erfOper = 0xcafefeed;
    erf.erfType = 0xdeadbabe;
    erf.fError = 0xdecaface;
    hfdi = FDICreate(fdi_alloc, fdi_free, fdi_open, fdi_read,
                     fdi_write, fdi_close, NULL,
                     cpuUNKNOWN, &erf);
    ok(hfdi != NULL, "Expected non-NULL context\n");
    ok(GetLastError() == 0xdeadbeef,
       "Expected 0xdeadbeef, got %d\n", GetLastError());
    ok((erf.erfOper == 0xcafefeed || erf.erfOper == 0 /* Vista */), "Expected 0xcafefeed or 0, got %d\n", erf.erfOper);
    ok((erf.erfType == 0xdeadbabe || erf.erfType == 0 /* Vista */), "Expected 0xdeadbabe or 0, got %d\n", erf.erfType);
    ok((erf.fError == 0xdecaface || erf.fError == 0 /* Vista */), "Expected 0xdecaface or 0, got %d\n", erf.fError);

    FDIDestroy(hfdi);

    SetLastError(0xdeadbeef);
    erf.erfOper = 0xcafefeed;
    erf.erfType = 0xdeadbabe;
    erf.fError = 0xdecaface;
    hfdi = FDICreate(fdi_alloc, fdi_free, fdi_open, fdi_read,
                     fdi_write, fdi_close, fdi_seek,
                     cpuUNKNOWN, NULL);
    /* XP sets hfdi to a non-NULL value, but Vista sets it to NULL! */
    ok(GetLastError() == 0xdeadbeef,
       "Expected 0xdeadbeef, got %d\n", GetLastError());
    /* NULL is passed to FDICreate instead of &erf, so don't retest the erf member values. */

    FDIDestroy(hfdi);

    /* bad cpu type */
    SetLastError(0xdeadbeef);
    erf.erfOper = 0xcafefeed;
    erf.erfType = 0xdeadbabe;
    erf.fError = 0xdecaface;
    hfdi = FDICreate(fdi_alloc, fdi_free, fdi_open, fdi_read,
                     fdi_write, fdi_close, fdi_seek,
                     0xcafebabe, &erf);
    ok(hfdi != NULL, "Expected non-NULL context\n");
    ok(GetLastError() == 0xdeadbeef,
       "Expected 0xdeadbeef, got %d\n", GetLastError());
    ok((erf.erfOper == 0xcafefeed || erf.erfOper == 0 /* Vista */), "Expected 0xcafefeed or 0, got %d\n", erf.erfOper);
    ok((erf.erfType == 0xdeadbabe || erf.erfType == 0 /* Vista */), "Expected 0xdeadbabe or 0, got %d\n", erf.erfType);
    ok((erf.fError == 0xdecaface || erf.fError == 0 /* Vista */), "Expected 0xdecaface or 0, got %d\n", erf.fError);

    FDIDestroy(hfdi);

    /* pfnalloc fails */
    SetLastError(0xdeadbeef);
    erf.erfOper = 0xcafefeed;
    erf.erfType = 0xdeadbabe;
    erf.fError = 0xdecaface;
    hfdi = FDICreate(fdi_alloc_bad, fdi_free, fdi_open, fdi_read,
                     fdi_write, fdi_close, fdi_seek,
                     cpuUNKNOWN, &erf);
    ok(hfdi == NULL, "Expected NULL context, got %p\n", hfdi);
    ok(erf.erfOper == FDIERROR_ALLOC_FAIL,
       "Expected FDIERROR_ALLOC_FAIL, got %d\n", erf.erfOper);
    ok(erf.fError == TRUE, "Expected TRUE, got %d\n", erf.fError);
    todo_wine
    {
        ok(GetLastError() == 0xdeadbeef,
           "Expected 0xdeadbeef, got %d\n", GetLastError());
        ok(erf.erfType == 0, "Expected 0, got %d\n", erf.erfType);
    }
}
Example #12
0
File: fdi.c Project: devyn/wine
static void test_FDIIsCabinet(void)
{
    ERF erf;
    BOOL ret;
    HFDI hfdi;
    INT_PTR fd;
    FDICABINETINFO cabinfo;
    char temp[] = "temp.txt";
    char extract[] = "extract.cab";

    create_test_files();
    create_cab_file();

    hfdi = FDICreate(fdi_alloc, fdi_free, fdi_open, fdi_read,
                     fdi_write, fdi_close, fdi_seek,
                     cpuUNKNOWN, &erf);
    ok(hfdi != NULL, "Expected non-NULL context\n");

    /* native crashes if hfdi or cabinfo are NULL or invalid */

    /* invalid file handle */
    ZeroMemory(&cabinfo, sizeof(FDICABINETINFO));
    SetLastError(0xdeadbeef);
    ret = FDIIsCabinet(hfdi, -1, &cabinfo);
    ok(ret == FALSE, "Expected FALSE, got %d\n", ret);
    ok(GetLastError() == ERROR_INVALID_HANDLE,
       "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
    ok(cabinfo.cbCabinet == 0, "Expected 0, got %d\n", cabinfo.cbCabinet);
    ok(cabinfo.cFiles == 0, "Expected 0, got %d\n", cabinfo.cFiles);
    ok(cabinfo.cFolders == 0, "Expected 0, got %d\n", cabinfo.cFolders);
    ok(cabinfo.iCabinet == 0, "Expected 0, got %d\n", cabinfo.iCabinet);
    ok(cabinfo.setID == 0, "Expected 0, got %d\n", cabinfo.setID);

    createTestFile("temp.txt");
    fd = fdi_open(temp, 0, 0);

    /* file handle doesn't point to a cabinet */
    ZeroMemory(&cabinfo, sizeof(FDICABINETINFO));
    SetLastError(0xdeadbeef);
    ret = FDIIsCabinet(hfdi, fd, &cabinfo);
    ok(ret == FALSE, "Expected FALSE, got %d\n", ret);
    ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
    ok(cabinfo.cbCabinet == 0, "Expected 0, got %d\n", cabinfo.cbCabinet);
    ok(cabinfo.cFiles == 0, "Expected 0, got %d\n", cabinfo.cFiles);
    ok(cabinfo.cFolders == 0, "Expected 0, got %d\n", cabinfo.cFolders);
    ok(cabinfo.iCabinet == 0, "Expected 0, got %d\n", cabinfo.iCabinet);
    ok(cabinfo.setID == 0, "Expected 0, got %d\n", cabinfo.setID);

    fdi_close(fd);
    DeleteFileA("temp.txt");

    /* try a real cab */
    fd = fdi_open(extract, 0, 0);
    ZeroMemory(&cabinfo, sizeof(FDICABINETINFO));
    SetLastError(0xdeadbeef);
    ret = FDIIsCabinet(hfdi, fd, &cabinfo);
    ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
    ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
    ok(cabinfo.cFiles == 4, "Expected 4, got %d\n", cabinfo.cFiles);
    ok(cabinfo.cFolders == 1, "Expected 1, got %d\n", cabinfo.cFolders);
    ok(cabinfo.setID == 0xbeef, "Expected 0xbeef, got %d\n", cabinfo.setID);
    todo_wine
    {
        ok(cabinfo.cbCabinet == 182, "Expected 182, got %d\n", cabinfo.cbCabinet);
        ok(cabinfo.iCabinet == 0, "Expected 0, got %d\n", cabinfo.iCabinet);
    }

    fdi_close(fd);
    FDIDestroy(hfdi);
    delete_test_files();
}
Example #13
0
/***********************************************************************
 * Extract (CABINET.3)
 *
 * Extracts the contents of the cabinet file to the specified
 * destination.
 *
 * PARAMS
 *   dest      [I/O] Controls the operation of Extract.  See NOTES.
 *   szCabName [I] Filename of the cabinet to extract.
 *
 * RETURNS
 *     Success: S_OK.
 *     Failure: E_FAIL.
 *
 * NOTES
 *   The following members of the dest struct control the operation
 *   of Extract:
 *       FileSize    [O] The size of all files extracted up to CurrentFile.
 *       Error       [O] The error in case the extract operation fails.
 *       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.
 *       Operation   [I] See Operation.
 *       Destination [I] The destination directory.
 *       CurrentFile [O] The last file extracted.
 *       FilterList  [I] A linked list of files that should not be extracted.
 *
 *   Operation
 *     If Operation contains EXTRACT_FILLFILELIST, then FileList will be
 *     filled with all the files in the cabinet.  If Operation 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 Operation contains both EXTRACT_FILLFILELIST
 *     and EXTRACT_EXTRACTFILES, then all the files in the cabinet
 *     will be extracted.
 */
HRESULT WINAPI Extract(SESSION *dest, LPCSTR szCabName)
{
    HRESULT res = S_OK;
    HFDI hfdi;
    char *str, *end, *path = NULL, *name = NULL;

    TRACE("(%p, %s)\n", dest, debugstr_a(szCabName));

    hfdi = FDICreate(mem_alloc,
                     mem_free,
                     fdi_open,
                     fdi_read,
                     fdi_write,
                     fdi_close,
                     fdi_seek,
                     cpuUNKNOWN,
                     &dest->Error);

    if (!hfdi)
        return E_FAIL;

    if (GetFileAttributesA(dest->Destination) == INVALID_FILE_ATTRIBUTES)
    {
        res = S_OK;
        goto end;
    }

    /* split the cabinet name into path + name */
    str = HeapAlloc(GetProcessHeap(), 0, lstrlenA(szCabName)+1);
    if (!str)
    {
        res = E_OUTOFMEMORY;
        goto end;
    }
    lstrcpyA(str, szCabName);

    if ((end = strrchr(str, '\\')))
    {
        path = str;
        end++;
        name = HeapAlloc( GetProcessHeap(), 0, strlen(end) + 1 );
        if (!name)
        {
            res = E_OUTOFMEMORY;
            goto end;
        }
        strcpy( name, end );
        *end = 0;
    }
    else
    {
        name = str;
        path = NULL;
    }

    dest->FileSize = 0;

    if (!FDICopy(hfdi, name, path, 0,
         fdi_notify_extract, NULL, dest))
        res = HRESULT_FROM_WIN32(GetLastError());

end:
    HeapFree(GetProcessHeap(), 0, path);
    HeapFree(GetProcessHeap(), 0, name);
    FDIDestroy(hfdi);
    return res;
}