index is 1-based at this point, index == line->nb_fields is the last
[reactos.git] / reactos / lib / setupapi / parser.c
index 9d3f2c0..e14e7fb 100644 (file)
 #include "winternl.h"
 #include "winerror.h"
 #include "setupapi.h"
+#include "setupapi_private.h"
 
 #include "wine/unicode.h"
 #include "wine/debug.h"
 
 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 */
@@ -168,8 +174,7 @@ static void *grow_array( void *array, unsigned int *count, size_t elem )
     if (new_array)
         *count = new_count;
     else
-       if (array)
-           HeapFree( GetProcessHeap(), 0, array );
+        HeapFree( GetProcessHeap(), 0, array );
     return new_array;
 }
 
@@ -177,7 +182,7 @@ static void *grow_array( void *array, unsigned int *count, size_t elem )
 /* find a section by name */
 static int find_section( struct inf_file *file, const WCHAR *name )
 {
-    int i;
+    unsigned int i;
 
     for (i = 0; i < file->nb_sections; i++)
         if (!strcmpiW( name, file->sections[i]->name )) return i;
@@ -312,7 +317,8 @@ static const WCHAR *get_string_subst( struct inf_file *file, const WCHAR *str, u
     struct section *strings_section;
     struct line *line;
     struct field *field;
-    int i, dirid;
+    unsigned int i;
+    int dirid;
     WCHAR *dirid_str, *end;
     const WCHAR *ret = NULL;
 
@@ -568,7 +574,7 @@ static void close_current_line( struct parser *parser )
 static const WCHAR *line_start_state( struct parser *parser, const WCHAR *pos )
 {
     const WCHAR *p;
-    
+
     for (p = pos; !is_eof( parser, p ); p++)
     {
         switch(*p)
@@ -646,7 +652,7 @@ static const WCHAR *key_name_state( struct parser *parser, const WCHAR *pos )
             set_state( parser, COMMENT );
             return p + 1;
         case '"':
-            push_token( parser, token_end );
+            push_token( parser, p );
             parser->start = p + 1;
             push_state( parser, KEY_NAME );
             set_state( parser, QUOTES );
@@ -698,7 +704,7 @@ static const WCHAR *value_name_state( struct parser *parser, const WCHAR *pos )
             set_state( parser, LEADING_SPACES );
             return p + 1;
         case '"':
-            push_token( parser, token_end );
+            push_token( parser, p );
             parser->start = p + 1;
             push_state( parser, VALUE_NAME );
             set_state( parser, QUOTES );
@@ -795,7 +801,7 @@ static const WCHAR *quotes_state( struct parser *parser, const WCHAR *pos )
 static const WCHAR *leading_spaces_state( struct parser *parser, const WCHAR *pos )
 {
     const WCHAR *p;
+
     for (p = pos; !is_eol( parser, p ); p++)
     {
         if (*p == '\\')
@@ -945,7 +951,7 @@ static struct inf_file *parse_file( HANDLE handle, const WCHAR *class, UINT *err
     file->string_pos = file->strings;
     file->strings_section = -1;
 
-    if (TRUE)//(!RtlIsTextUnicode( buffer, size, NULL )) // Fireball, 07 Feb 04, temp fix
+    if (!RtlIsTextUnicode( buffer, size, NULL ))
     {
         WCHAR *new_buff = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) );
         if (new_buff)
@@ -956,7 +962,14 @@ static struct inf_file *parse_file( HANDLE handle, const WCHAR *class, UINT *err
             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 */
     {
@@ -999,6 +1012,32 @@ const WCHAR *PARSER_get_src_root( HINF hinf )
 }
 
 
+/***********************************************************************
+ *            PARSER_get_dest_dir
+ *
+ * retrieve a destination dir of the form "dirid,relative_path" in the given entry.
+ * returned buffer must be freed by caller.
+ */
+WCHAR *PARSER_get_dest_dir( INFCONTEXT *context )
+{
+    const WCHAR *dir;
+    WCHAR *ptr, *ret;
+    INT dirid;
+    DWORD len1, len2;
+
+    if (!SetupGetIntField( context, 1, &dirid )) return NULL;
+    if (!(dir = DIRID_get_string( context->Inf, dirid ))) return NULL;
+    len1 = strlenW(dir) + 1;
+    if (!SetupGetStringFieldW( context, 2, NULL, 0, &len2 )) len2 = 0;
+    if (!(ret = HeapAlloc( GetProcessHeap(), 0, (len1+len2) * sizeof(WCHAR) ))) return NULL;
+    strcpyW( ret, dir );
+    ptr = ret + strlenW(ret);
+    if (len2 && ptr > ret && ptr[-1] != '\\') *ptr++ = '\\';
+    if (!SetupGetStringFieldW( context, 2, ptr, len2, NULL )) *ptr = 0;
+    return ret;
+}
+
+
 /***********************************************************************
  *            SetupOpenInfFileA   (SETUPAPI.@)
  */
@@ -1033,6 +1072,8 @@ HINF WINAPI SetupOpenInfFileW( PCWSTR name, PCWSTR class, DWORD style, UINT *err
     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;
@@ -1067,6 +1108,7 @@ HINF WINAPI SetupOpenInfFileW( PCWSTR name, PCWSTR class, DWORD style, UINT *err
             handle = CreateFileW( path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );
         }
     }
+
     if (handle != INVALID_HANDLE_VALUE)
     {
         file = parse_file( handle, class, error );
@@ -1133,13 +1175,28 @@ BOOL WINAPI SetupOpenAppendInfFileW( PCWSTR name, HINF parent_hinf, UINT *error
 }
 
 
+/***********************************************************************
+ *            SetupOpenMasterInf   (SETUPAPI.@)
+ */
+HINF WINAPI SetupOpenMasterInf( VOID )
+{
+    static const WCHAR Layout[] = {'\\','i','n','f','\\', 'l', 'a', 'y', 'o', 'u', 't', '.', 'i', 'n', 'f', 0};
+    WCHAR Buffer[MAX_PATH];
+
+    GetWindowsDirectoryW( Buffer, MAX_PATH );
+    strcatW( Buffer, Layout );
+    return SetupOpenInfFileW( Buffer, NULL, INF_STYLE_WIN4, NULL);
+}
+
+
+
 /***********************************************************************
  *            SetupCloseInfFile   (SETUPAPI.@)
  */
 void WINAPI SetupCloseInfFile( HINF hinf )
 {
     struct inf_file *file = hinf;
-    int i;
+    unsigned int i;
 
     for (i = 0; i < file->nb_sections; i++) HeapFree( GetProcessHeap(), 0, file->sections[i] );
     HeapFree( GetProcessHeap(), 0, file->src_root );
@@ -1466,13 +1523,13 @@ BOOL WINAPI SetupGetLineTextW( PINFCONTEXT context, HINF hinf, PCWSTR section_na
         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 );
@@ -1517,13 +1574,13 @@ BOOL WINAPI SetupGetLineTextA( PINFCONTEXT context, HINF hinf, PCSTR section_nam
         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 );
@@ -1562,13 +1619,13 @@ BOOL WINAPI SetupGetStringFieldA( PINFCONTEXT context, DWORD index, PSTR buffer,
     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",
@@ -1593,13 +1650,13 @@ BOOL WINAPI SetupGetStringFieldW( PINFCONTEXT context, DWORD index, PWSTR buffer
     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",
@@ -1657,7 +1714,7 @@ BOOL WINAPI SetupGetBinaryField( PINFCONTEXT context, DWORD index, BYTE *buffer,
         SetLastError( ERROR_LINE_NOT_FOUND );
         return FALSE;
     }
-    if (!index || index >= line->nb_fields)
+    if (!index || index > line->nb_fields)
     {
         SetLastError( ERROR_INVALID_PARAMETER );
         return FALSE;
@@ -1716,7 +1773,7 @@ BOOL WINAPI SetupGetMultiSzFieldA( PINFCONTEXT context, DWORD index, PSTR buffer
         SetLastError( ERROR_LINE_NOT_FOUND );
         return FALSE;
     }
-    if (!index || index >= line->nb_fields)
+    if (!index || index > line->nb_fields)
     {
         SetLastError( ERROR_INVALID_PARAMETER );
         return FALSE;
@@ -1765,7 +1822,7 @@ BOOL WINAPI SetupGetMultiSzFieldW( PINFCONTEXT context, DWORD index, PWSTR buffe
         SetLastError( ERROR_LINE_NOT_FOUND );
         return FALSE;
     }
-    if (!index || index >= line->nb_fields)
+    if (!index || index > line->nb_fields)
     {
         SetLastError( ERROR_INVALID_PARAMETER );
         return FALSE;
@@ -1794,3 +1851,224 @@ BOOL WINAPI SetupGetMultiSzFieldW( PINFCONTEXT context, DWORD index, PWSTR buffe
     *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;
+}