Implement SetupGetInfFileListW and SetupGetInfInformationW
Inf file parser now accept UNICODE files with FF FE header
Return required buffer size when buffer is too small in SetupGetLineTextA/W, SetupGetStringFieldA/W
Modified: trunk/reactos/lib/setupapi/parser.c
Modified: trunk/reactos/lib/setupapi/setupapi.spec

Modified: trunk/reactos/lib/setupapi/parser.c
--- trunk/reactos/lib/setupapi/parser.c	2005-08-07 11:52:27 UTC (rev 17161)
+++ trunk/reactos/lib/setupapi/parser.c	2005-08-07 11:59:43 UTC (rev 17162)
@@ -43,6 +43,11 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
 
+/* Unicode constants */
+static const WCHAR BackSlash[] = {'\\',0};
+static const WCHAR InfDirectory[] = {'i','n','f','\\',0};
+static const WCHAR InfFileSpecification[] = {'*','.','i','n','f',0};
+
 #define CONTROL_Z  '\x1a'
 #define MAX_SECTION_NAME_LEN  255
 #define MAX_FIELD_LEN         511  /* larger fields get silently truncated */
@@ -957,7 +962,14 @@
             HeapFree( GetProcessHeap(), 0, new_buff );
         }
     }
-    else err = parse_buffer( file, buffer, (WCHAR *)((char *)buffer + size), error_line );
+    else
+    {
+        WCHAR *new_buff = (WCHAR *)buffer;
+        /* Some UNICODE files may start with the UNICODE marker */
+        if (*new_buff == 0xfeff)
+            new_buff++;
+        err = parse_buffer( file, new_buff, (WCHAR *)((char *)new_buff + size), error_line );
+    }
 
     if (!err)  /* now check signature */
     {
@@ -1060,6 +1072,8 @@
     WCHAR *path, *p;
     UINT len;
 
+    TRACE("%S %S %lx %p\n", name, class, style, error);
+
     if (strchrW( name, '\\' ) || strchrW( name, '/' ))
     {
         if (!(len = GetFullPathNameW( name, 0, NULL, NULL ))) return (HINF)INVALID_HANDLE_VALUE;
@@ -1509,13 +1523,13 @@
         total += PARSER_string_substW( file, field->text, NULL, 0 ) + 1;
 
     if (required) *required = total;
+    if (total > size)
+    {
+        SetLastError( ERROR_INSUFFICIENT_BUFFER );
+        return FALSE;
+    }
     if (buffer)
     {
-        if (total > size)
-        {
-            SetLastError( ERROR_INSUFFICIENT_BUFFER );
-            return FALSE;
-        }
         for (i = 0, field = &file->fields[line->first_field]; i < line->nb_fields; i++, field++)
         {
             unsigned int len = PARSER_string_substW( file, field->text, buffer, size );
@@ -1560,13 +1574,13 @@
         total += PARSER_string_substA( file, field->text, NULL, 0 ) + 1;
 
     if (required) *required = total;
+    if (total > size)
+    {
+        SetLastError( ERROR_INSUFFICIENT_BUFFER );
+        return FALSE;
+    }
     if (buffer)
     {
-        if (total > size)
-        {
-            SetLastError( ERROR_INSUFFICIENT_BUFFER );
-            return FALSE;
-        }
         for (i = 0, field = &file->fields[line->first_field]; i < line->nb_fields; i++, field++)
         {
             unsigned int len = PARSER_string_substA( file, field->text, buffer, size );
@@ -1605,13 +1619,13 @@
     if (!field) return FALSE;
     len = PARSER_string_substA( file, field->text, NULL, 0 );
     if (required) *required = len + 1;
+    if (size <= len)
+    {
+        SetLastError( ERROR_INSUFFICIENT_BUFFER );
+        return FALSE;
+    }
     if (buffer)
     {
-        if (size <= len)
-        {
-            SetLastError( ERROR_INSUFFICIENT_BUFFER );
-            return FALSE;
-        }
         PARSER_string_substA( file, field->text, buffer, size );
 
         TRACE( "context %p/%p/%d/%d index %ld returning %s\n",
@@ -1636,13 +1650,13 @@
     if (!field) return FALSE;
     len = PARSER_string_substW( file, field->text, NULL, 0 );
     if (required) *required = len + 1;
+    if (size <= len)
+    {
+        SetLastError( ERROR_INSUFFICIENT_BUFFER );
+        return FALSE;
+    }
     if (buffer)
     {
-        if (size <= len)
-        {
-            SetLastError( ERROR_INSUFFICIENT_BUFFER );
-            return FALSE;
-        }
         PARSER_string_substW( file, field->text, buffer, size );
 
         TRACE( "context %p/%p/%d/%d index %ld returning %s\n",
@@ -1837,3 +1851,224 @@
     *buffer = 0;  /* add final null */
     return TRUE;
 }
+
+/***********************************************************************
+ *		SetupGetInfInformationW    (SETUPAPI.@)
+ */
+BOOL WINAPI
+SetupGetInfInformationW(
+    IN LPCVOID InfSpec,
+    IN DWORD SearchControl,
+    IN PSP_INF_INFORMATION ReturnBuffer,
+    IN DWORD ReturnBufferSize,
+    IN PDWORD RequiredSize)
+{
+    HINF hInf;
+    DWORD requiredSize;
+    BOOL Ret = FALSE;
+    
+    TRACE("%p %lx %p %ld %p\n", InfSpec, SearchControl, ReturnBuffer,
+        ReturnBufferSize, RequiredSize);
+
+    if (SearchControl != INFINFO_INF_SPEC_IS_HINF
+        && SearchControl != INFINFO_INF_NAME_IS_ABSOLUTE
+        && SearchControl != INFINFO_DEFAULT_SEARCH
+        && SearchControl != INFINFO_REVERSE_DEFAULT_SEARCH
+        && SearchControl != INFINFO_INF_PATH_LIST_SEARCH)
+    {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return FALSE;
+    }
+
+    if (SearchControl == INFINFO_INF_SPEC_IS_HINF)
+        hInf = (HINF)InfSpec;
+    else
+    {
+        /* open .inf file and put its handle to hInf */
+        FIXME("SearchControl 0x%lx not implemented\n", SearchControl);
+        SetLastError(ERROR_GEN_FAILURE);
+        return FALSE;
+    }
+
+    /* FIXME: add size of [Version] section */
+    requiredSize = sizeof(SP_INF_INFORMATION);
+
+    if (requiredSize <= ReturnBufferSize)
+    {
+        ReturnBuffer->InfStyle = INF_STYLE_WIN4; /* FIXME */
+        ReturnBuffer->InfCount = 1; /* FIXME */
+        /* FIXME: memcpy(ReturnBuffer->VersionData, ...); */
+        Ret = TRUE;
+    }
+    else
+        SetLastError(ERROR_INSUFFICIENT_BUFFER);
+
+    if (RequiredSize)
+        *RequiredSize = requiredSize;
+
+    if (SearchControl != INFINFO_INF_SPEC_IS_HINF)
+        SetupCloseInfFile(hInf);
+    return Ret;
+}
+
+/***********************************************************************
+ *		SetupGetInfFileListW    (SETUPAPI.@)
+ */
+BOOL WINAPI
+SetupGetInfFileListW(
+    IN PCWSTR DirectoryPath OPTIONAL,
+    IN DWORD InfStyle,
+    IN OUT PWSTR ReturnBuffer OPTIONAL,
+    IN DWORD ReturnBufferSize OPTIONAL,
+    OUT PDWORD RequiredSize OPTIONAL)
+{
+    HANDLE hSearch;
+    LPWSTR pFileSpecification, pFileName;
+    LPWSTR pBuffer = ReturnBuffer;
+    WIN32_FIND_DATAW wfdFileInfo;
+    PVOID Buffer = NULL;
+    size_t len;
+    DWORD requiredSizeInfo;
+    DWORD requiredSize = 0;
+    BOOL ret = FALSE;
+
+    TRACE("%S %lx %p %ld %p\n", DirectoryPath, InfStyle,
+        ReturnBuffer, ReturnBufferSize, RequiredSize);
+
+    if (InfStyle & ~(INF_STYLE_OLDNT | INF_STYLE_WIN4))
+    {
+        TRACE("Unknown flags: 0x%08lx\n", InfStyle & ~(INF_STYLE_OLDNT  | INF_STYLE_WIN4));
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return FALSE;
+    }
+
+    if (DirectoryPath)
+    {
+        len = wcslen(DirectoryPath);
+        pFileSpecification = HeapAlloc(
+            GetProcessHeap(), 0,
+            (len + MAX_PATH + 2) * sizeof(WCHAR));
+        if (!pFileSpecification)
+        {
+            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+            return FALSE;
+        }
+        wcscpy(pFileSpecification, DirectoryPath);
+        if (DirectoryPath[len] == '\\')
+        {
+            pFileName = &pFileSpecification[len];
+        }
+        else
+        {
+            wcscat(pFileSpecification, BackSlash);
+            pFileName = &pFileSpecification[len + 1];
+        }
+    }
+    else
+    {
+        WCHAR windir[MAX_PATH];
+        if (GetSystemWindowsDirectoryW(windir, MAX_PATH) == 0)
+            return FALSE;
+        len = wcslen(windir);
+        pFileSpecification = HeapAlloc(
+            GetProcessHeap(), 0,
+            (len + MAX_PATH + 6) * sizeof(WCHAR));
+        if (!pFileSpecification)
+        {
+            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+            return FALSE;
+        }
+        wcscpy(pFileSpecification, windir);
+        if (windir[len] != '\\')
+            wcscat(pFileSpecification, BackSlash);
+        wcscat(pFileSpecification, InfDirectory);
+        pFileName = &pFileSpecification[wcslen(pFileSpecification)];
+    }
+    wcscpy(pFileName, InfFileSpecification);
+    hSearch = FindFirstFileW(pFileSpecification, &wfdFileInfo);
+    if (hSearch == INVALID_HANDLE_VALUE)
+    {
+        HeapFree(GetProcessHeap(), 0, pFileSpecification);
+        return FALSE;
+    }
+
+    ret = TRUE;
+    do
+    {
+        HINF hInf;
+
+        wcscpy(pFileName, wfdFileInfo.cFileName);
+        hInf = SetupOpenInfFileW(
+            pFileSpecification,
+            NULL, /* Inf class */
+            InfStyle,
+            NULL /* Error line */);
+        if (hInf == INVALID_HANDLE_VALUE)
+        {
+            if (GetLastError() == ERROR_CLASS_MISMATCH)
+            {
+                /* InfStyle was not correct. Skip this file */
+                continue;
+            }
+            TRACE("Invalid .inf file %S\n", pFileSpecification);
+            continue;
+        }
+
+        ret = SetupGetInfInformationW(
+            hInf,
+            INFINFO_INF_SPEC_IS_HINF,
+            NULL, 0,
+            &requiredSizeInfo);
+        if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+            break;
+
+        if (!ret)
+        {
+            Buffer = HeapAlloc(GetProcessHeap(), 0, requiredSizeInfo);
+            if (!Buffer)
+            {
+                SetupCloseInfFile(hInf);
+                ret = FALSE;
+                SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+                break;
+            }
+    
+            ret = SetupGetInfInformationW(
+                hInf,
+                INFINFO_INF_SPEC_IS_HINF,
+                Buffer, requiredSizeInfo,
+                &requiredSizeInfo);
+            if (!ret)
+                break;
+        }
+
+        len = wcslen(wfdFileInfo.cFileName) + 1;
+        requiredSize += (DWORD)(len * sizeof(WCHAR));
+        if (requiredSize <= ReturnBufferSize)
+        {
+            wcscpy(pBuffer, wfdFileInfo.cFileName);
+            pBuffer = &pBuffer[len];
+        }
+        HeapFree(GetProcessHeap(), 0, Buffer);
+        SetupCloseInfFile(hInf);
+        ret = TRUE;
+    } while (FindNextFileW(hSearch, &wfdFileInfo));
+    FindClose(hSearch);
+
+    if (ret)
+    {
+        requiredSize += sizeof(WCHAR); /* Final NULL char */
+        if (requiredSize <= ReturnBufferSize)
+            *pBuffer = '\0';
+        else
+        {
+            SetLastError(ERROR_INSUFFICIENT_BUFFER);
+            ret = FALSE;
+        }
+        if (RequiredSize)
+            *RequiredSize = requiredSize;
+    }
+
+    HeapFree(GetProcessHeap(), 0, pFileSpecification);
+    return ret;
+}

Modified: trunk/reactos/lib/setupapi/setupapi.spec
--- trunk/reactos/lib/setupapi/setupapi.spec	2005-08-07 11:52:27 UTC (rev 17161)
+++ trunk/reactos/lib/setupapi/setupapi.spec	2005-08-07 11:59:43 UTC (rev 17162)
@@ -399,9 +399,9 @@
 @ stdcall SetupGetFileQueueCount(long long ptr)
 @ stdcall SetupGetFileQueueFlags(long ptr)
 @ stub SetupGetInfFileListA
-@ stub SetupGetInfFileListW
+@ stdcall SetupGetInfFileListW(wstr long wstr long ptr)
 @ stdcall SetupGetInfInformationA(ptr long ptr long ptr)
-@ stub SetupGetInfInformationW
+@ stdcall SetupGetInfInformationW(ptr long ptr long ptr)
 @ stub SetupGetInfSections
 @ stdcall SetupGetIntField(ptr long ptr)
 @ stdcall SetupGetLineByIndexA(long str long ptr)