setupapi: Implement SetupIterateCabinetW() on top of SetupIterateCabinetA().

Signed-off-by: Zebediah Figura <z.figura12@gmail.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Zebediah Figura 2021-03-04 20:08:13 -06:00 committed by Alexandre Julliard
parent 31af1aeb78
commit 85afec5f2d
1 changed files with 91 additions and 213 deletions

View File

@ -84,16 +84,6 @@ typedef struct {
CHAR most_recent_target[MAX_PATH];
} SC_HSC_A, *PSC_HSC_A;
#define SC_HSC_W_MAGIC 0x0CABFEED
typedef struct {
UINT magic;
HFDI hfdi;
PSP_FILE_CALLBACK_W msghandler;
PVOID context;
WCHAR most_recent_cabinet_name[MAX_PATH];
WCHAR most_recent_target[MAX_PATH];
} SC_HSC_W, *PSC_HSC_W;
WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
static BOOL LoadCABINETDll(void)
@ -386,158 +376,6 @@ static INT_PTR CDECL sc_FNNOTIFY_A(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION p
}
}
static INT_PTR CDECL sc_FNNOTIFY_W(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
{
FILE_IN_CABINET_INFO_W fici;
PSC_HSC_W phsc;
CABINET_INFO_W ci;
FILEPATHS_W fp;
UINT err;
int len;
WCHAR mysterio[SIZEOF_MYSTERIO]; /* how big? undocumented! */
WCHAR buf[MAX_PATH], buf2[MAX_PATH];
CHAR charbuf[MAX_PATH];
memset(mysterio, 0, SIZEOF_MYSTERIO * sizeof(WCHAR));
memset(buf, 0, MAX_PATH * sizeof(WCHAR));
memset(buf2, 0, MAX_PATH * sizeof(WCHAR));
memset(charbuf, 0, MAX_PATH);
TRACE("(fdint == %d, pfdin == ^%p)\n", fdint, pfdin);
if (pfdin && pfdin->pv && (((PSC_HSC_W) pfdin->pv)->magic == SC_HSC_W_MAGIC))
phsc = pfdin->pv;
else {
ERR("pv %p is not an SC_HSC_W.\n", (pfdin) ? pfdin->pv : NULL);
return -1;
}
switch (fdint) {
case fdintCABINET_INFO:
TRACE("Cabinet info notification\n");
/* TRACE(" Cabinet name: %s\n", debugstr_a(pfdin->psz1));
TRACE(" Cabinet disk: %s\n", debugstr_a(pfdin->psz2));
TRACE(" Cabinet path: %s\n", debugstr_a(pfdin->psz3));
TRACE(" Cabinet Set#: %d\n", pfdin->setID);
TRACE(" Cabinet Cab#: %d\n", pfdin->iCabinet); */
WARN("SPFILENOTIFY_CABINETINFO undocumented: guess implementation.\n");
ci.CabinetFile = phsc->most_recent_cabinet_name;
len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz3, -1, buf, MAX_PATH);
if ((len > MAX_PATH) || (len <= 1))
buf[0] = '\0';
ci.CabinetPath = buf;
len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz2, -1, buf2, MAX_PATH);
if ((len > MAX_PATH) || (len <= 1))
buf2[0] = '\0';
ci.DiskName = buf2;
ci.SetId = pfdin->setID;
ci.CabinetNumber = pfdin->iCabinet;
phsc->msghandler(phsc->context, SPFILENOTIFY_CABINETINFO, (UINT_PTR)&ci, 0);
return 0;
case fdintPARTIAL_FILE:
TRACE("Partial file notification\n");
/* TRACE(" Partial file name: %s\n", debugstr_a(pfdin->psz1)); */
return 0;
case fdintCOPY_FILE:
TRACE("Copy file notification\n");
TRACE(" File name: %s\n", debugstr_a(pfdin->psz1));
/* TRACE(" File size: %ld\n", pfdin->cb);
TRACE(" File date: %u\n", pfdin->date);
TRACE(" File time: %u\n", pfdin->time);
TRACE(" File attr: %u\n", pfdin->attribs); */
len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz1, -1, buf2, MAX_PATH);
if ((len > MAX_PATH) || (len <= 1))
buf2[0] = '\0';
fici.NameInCabinet = buf2;
fici.FileSize = pfdin->cb;
fici.Win32Error = 0;
fici.DosDate = pfdin->date;
fici.DosTime = pfdin->time;
fici.DosAttribs = pfdin->attribs;
memset(fici.FullTargetName, 0, MAX_PATH * sizeof(WCHAR));
err = phsc->msghandler(phsc->context, SPFILENOTIFY_FILEINCABINET,
(UINT_PTR)&fici, (UINT_PTR)pfdin->psz1);
if (err == FILEOP_DOIT) {
TRACE(" Callback specified filename: %s\n", debugstr_w(fici.FullTargetName));
if (fici.FullTargetName[0]) {
len = lstrlenW(fici.FullTargetName) + 1;
if ((len > MAX_PATH ) || (len <= 1))
return 0;
if (!WideCharToMultiByte(CP_ACP, 0, fici.FullTargetName, len, charbuf, MAX_PATH, 0, 0))
return 0;
} else {
WARN("Empty buffer string caused abort.\n");
SetLastError(ERROR_PATH_NOT_FOUND);
return -1;
}
lstrcpyW( phsc->most_recent_target, fici.FullTargetName );
return sc_cb_open(charbuf, _O_BINARY | _O_CREAT | _O_WRONLY, _S_IREAD | _S_IWRITE);
} else {
TRACE(" Callback skipped file.\n");
return 0;
}
case fdintCLOSE_FILE_INFO:
TRACE("Close file notification\n");
/* TRACE(" File name: %s\n", debugstr_a(pfdin->psz1));
TRACE(" Exec file? %s\n", (pfdin->cb) ? "Yes" : "No");
TRACE(" File hndl: %d\n", pfdin->hf); */
fp.Source = phsc->most_recent_cabinet_name;
fp.Target = phsc->most_recent_target;
fp.Win32Error = 0;
fp.Flags = 0;
/* a valid fixme -- but occurs too many times */
/* FIXME("Should set file date/time/attribs (and execute files?)\n"); */
if (sc_cb_close(pfdin->hf))
WARN("_close failed.\n");
err = phsc->msghandler(phsc->context, SPFILENOTIFY_FILEEXTRACTED, (UINT_PTR)&fp, 0);
if (err) {
SetLastError(err);
return FALSE;
} else
return TRUE;
case fdintNEXT_CABINET:
TRACE("Next cabinet notification\n");
/* TRACE(" Cabinet name: %s\n", debugstr_a(pfdin->psz1));
TRACE(" Cabinet disk: %s\n", debugstr_a(pfdin->psz2));
TRACE(" Cabinet path: %s\n", debugstr_a(pfdin->psz3));
TRACE(" Cabinet Set#: %d\n", pfdin->setID);
TRACE(" Cabinet Cab#: %d\n", pfdin->iCabinet); */
/* remember the new cabinet name */
len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz1, -1, phsc->most_recent_cabinet_name, MAX_PATH);
if ((len > MAX_PATH) || (len <= 1))
phsc->most_recent_cabinet_name[0] = '\0';
ci.CabinetFile = phsc->most_recent_cabinet_name;
len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz3, -1, buf, MAX_PATH);
if ((len > MAX_PATH) || (len <= 1))
buf[0] = '\0';
ci.CabinetPath = buf;
len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz2, -1, buf2, MAX_PATH);
if ((len > MAX_PATH) || (len <= 1))
buf2[0] = '\0';
ci.DiskName = buf2;
ci.SetId = pfdin->setID;
ci.CabinetNumber = pfdin->iCabinet;
err = phsc->msghandler(phsc->context, SPFILENOTIFY_NEEDNEWCABINET, (UINT_PTR)&ci, (UINT_PTR)mysterio);
if (err) {
SetLastError(err);
return -1;
} else {
if (mysterio[0]) {
len = lstrlenW(mysterio) + 1;
if ((len > 255) || (len <= 1))
return 0;
if (!WideCharToMultiByte(CP_ACP, 0, mysterio, len, pfdin->psz3, 255, 0, 0))
return 0;
}
return 0;
}
default:
FIXME("Unknown notification type %d.\n", fdint);
return 0;
}
}
/***********************************************************************
* SetupIterateCabinetA (SETUPAPI.@)
*/
@ -602,71 +440,111 @@ BOOL WINAPI SetupIterateCabinetA(PCSTR CabinetFile, DWORD Reserved,
return ret;
}
/***********************************************************************
* SetupIterateCabinetW (SETUPAPI.@)
*/
BOOL WINAPI SetupIterateCabinetW(PCWSTR CabinetFile, DWORD Reserved,
PSP_FILE_CALLBACK_W MsgHandler, PVOID Context)
struct iterate_wtoa_ctx
{
CHAR pszCabinet[MAX_PATH], pszCabPath[MAX_PATH];
UINT len;
SC_HSC_W my_hsc;
ERF erf;
WCHAR pszCabPathW[MAX_PATH], *p = NULL;
DWORD fpnsize;
BOOL ret;
PSP_FILE_CALLBACK_A orig_cb;
void *orig_ctx;
};
TRACE("(CabinetFile == %s, Reserved == %u, MsgHandler == ^%p, Context == ^%p)\n",
debugstr_w(CabinetFile), Reserved, MsgHandler, Context);
static UINT WINAPI iterate_wtoa_cb(void *pctx, UINT message, UINT_PTR param1, UINT_PTR param2)
{
struct iterate_wtoa_ctx *ctx = pctx;
if (!LoadCABINETDll())
return FALSE;
switch (message)
{
case SPFILENOTIFY_CABINETINFO:
case SPFILENOTIFY_NEEDNEWCABINET:
{
const CABINET_INFO_A *infoA = (const CABINET_INFO_A *)param1;
WCHAR pathW[MAX_PATH], fileW[MAX_PATH], diskW[MAX_PATH];
CABINET_INFO_W infoW =
{
.CabinetPath = pathW,
.CabinetFile = fileW,
.DiskName = diskW,
.SetId = infoA->SetId,
.CabinetNumber = infoA->CabinetNumber,
};
if (!CabinetFile)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
MultiByteToWideChar(CP_ACP, 0, infoA->CabinetPath, -1, pathW, ARRAY_SIZE(pathW));
MultiByteToWideChar(CP_ACP, 0, infoA->CabinetFile, -1, fileW, ARRAY_SIZE(fileW));
MultiByteToWideChar(CP_ACP, 0, infoA->DiskName, -1, diskW, ARRAY_SIZE(diskW));
fpnsize = GetFullPathNameW(CabinetFile, MAX_PATH, pszCabPathW, &p);
if (fpnsize > MAX_PATH) {
SetLastError(ERROR_BAD_PATHNAME);
return FALSE;
}
if (message == SPFILENOTIFY_CABINETINFO)
return ctx->orig_cb(ctx->orig_ctx, message, (UINT_PTR)&infoW, 0);
else
{
char *newpathA = (char *)param2;
WCHAR newpathW[MAX_PATH] = {0};
BOOL ret = ctx->orig_cb(ctx->orig_ctx, message, (UINT_PTR)&infoW, (UINT_PTR)newpathW);
if (p) {
lstrcpyW(my_hsc.most_recent_cabinet_name, p);
*p = 0;
len = WideCharToMultiByte(CP_ACP, 0, pszCabPathW, -1, pszCabPath,
MAX_PATH, 0, 0);
if (!len) return FALSE;
} else {
lstrcpyW(my_hsc.most_recent_cabinet_name, CabinetFile);
pszCabPath[0] = '\0';
}
WideCharToMultiByte(CP_ACP, 0, newpathW, -1, newpathA, MAX_PATH, NULL, NULL);
return ret;
}
}
case SPFILENOTIFY_FILEINCABINET:
{
FILE_IN_CABINET_INFO_A *infoA = (FILE_IN_CABINET_INFO_A *)param1;
const char *cabA = (const char *)param2;
WCHAR cabW[MAX_PATH], fileW[MAX_PATH];
FILE_IN_CABINET_INFO_W infoW =
{
.NameInCabinet = fileW,
.FileSize = infoA->FileSize,
.Win32Error = infoA->Win32Error,
.DosDate = infoA->DosDate,
.DosTime = infoA->DosTime,
.DosAttribs = infoA->DosAttribs,
};
BOOL ret;
len = WideCharToMultiByte(CP_ACP, 0, my_hsc.most_recent_cabinet_name, -1,
pszCabinet, MAX_PATH, 0, 0);
if (!len) return FALSE;
MultiByteToWideChar(CP_ACP, 0, infoA->NameInCabinet, -1, fileW, ARRAY_SIZE(fileW));
MultiByteToWideChar(CP_ACP, 0, cabA, -1, cabW, ARRAY_SIZE(cabW));
TRACE("path: %s, cabfile: %s\n",
debugstr_a(pszCabPath), debugstr_a(pszCabinet));
ret = ctx->orig_cb(ctx->orig_ctx, message, (UINT_PTR)&infoW, (UINT_PTR)cabW);
my_hsc.magic = SC_HSC_W_MAGIC;
my_hsc.msghandler = MsgHandler;
my_hsc.context = Context;
my_hsc.hfdi = sc_FDICreate( sc_cb_alloc, sc_cb_free, sc_cb_open, sc_cb_read,
sc_cb_write, sc_cb_close, sc_cb_lseek, cpuUNKNOWN, &erf );
WideCharToMultiByte(CP_ACP, 0, infoW.FullTargetName, -1, infoA->FullTargetName,
ARRAY_SIZE(infoA->FullTargetName), NULL, NULL);
if (!my_hsc.hfdi) return FALSE;
return ret;
}
case SPFILENOTIFY_FILEEXTRACTED:
{
const FILEPATHS_A *pathsA = (const FILEPATHS_A *)param1;
WCHAR targetW[MAX_PATH], sourceW[MAX_PATH];
FILEPATHS_W pathsW =
{
.Target = targetW,
.Source = sourceW,
.Win32Error = pathsA->Win32Error,
.Flags = pathsA->Flags,
};
ret = sc_FDICopy(my_hsc.hfdi, pszCabinet, pszCabPath, 0, sc_FNNOTIFY_W, NULL, &my_hsc);
MultiByteToWideChar(CP_ACP, 0, pathsA->Target, -1, targetW, ARRAY_SIZE(targetW));
MultiByteToWideChar(CP_ACP, 0, pathsA->Source, -1, sourceW, ARRAY_SIZE(sourceW));
sc_FDIDestroy(my_hsc.hfdi);
return ret;
return ctx->orig_cb(ctx->orig_ctx, message, (UINT_PTR)&pathsW, 0);
}
default:
FIXME("Unexpected callback %#x.\n", message);
return FALSE;
}
}
/***********************************************************************
* SetupIterateCabinetW (SETUPAPI.@)
*/
BOOL WINAPI SetupIterateCabinetW(const WCHAR *fileW, DWORD reserved,
PSP_FILE_CALLBACK_W handler, void *context)
{
struct iterate_wtoa_ctx ctx = {handler, context};
char fileA[MAX_PATH];
if (!WideCharToMultiByte(CP_ACP, 0, fileW, -1, fileA, ARRAY_SIZE(fileA), NULL, NULL))
return FALSE;
return SetupIterateCabinetA(fileA, reserved, iterate_wtoa_cb, &ctx);
}
/***********************************************************************
* DllMain