- Factor out .inf handling code from usetup
- Provide a dual interface, for use in build tools and for use in ReactOS code
Modified: trunk/reactos/lib/directory.xml
Added: trunk/reactos/lib/inflib/
Added: trunk/reactos/lib/inflib/README.txt
Added: trunk/reactos/lib/inflib/builddep.h
Added: trunk/reactos/lib/inflib/infcommon.h
Added: trunk/reactos/lib/inflib/infcore.c
Added: trunk/reactos/lib/inflib/infget.c
Added: trunk/reactos/lib/inflib/infhost.h
Added: trunk/reactos/lib/inflib/infhostgen.c
Added: trunk/reactos/lib/inflib/infhostget.c
Added: trunk/reactos/lib/inflib/inflib.h
Added: trunk/reactos/lib/inflib/inflib.mak
Added: trunk/reactos/lib/inflib/inflib.xml
Added: trunk/reactos/lib/inflib/infpriv.h
Added: trunk/reactos/lib/inflib/infros.h
Added: trunk/reactos/lib/inflib/infrosgen.c
Added: trunk/reactos/lib/inflib/infrosget.c
Modified: trunk/reactos/lib/lib.mak

Modified: trunk/reactos/lib/directory.xml
--- trunk/reactos/lib/directory.xml	2005-11-24 06:07:04 UTC (rev 19515)
+++ trunk/reactos/lib/directory.xml	2005-11-24 08:07:12 UTC (rev 19516)
@@ -119,6 +119,9 @@
 <directory name="imm32">
 	<xi:include href="imm32/imm32.xml" />
 </directory>
+<directory name="inflib">
+	<xi:include href="inflib/inflib.xml" />
+</directory>
 <directory name="intrlck">
 	<xi:include href="intrlck/intrlck.xml" />
 </directory>

Added: trunk/reactos/lib/inflib/README.txt
--- trunk/reactos/lib/inflib/README.txt	2005-11-24 06:07:04 UTC (rev 19515)
+++ trunk/reactos/lib/inflib/README.txt	2005-11-24 08:07:12 UTC (rev 19516)
@@ -0,0 +1,14 @@
+Routines to handle .inf files.
+
+This library is used to share .inf handling code between build tools and
+ReactOS code. Two versions are built, "inflib_host" (for use by build tools)
+and "inflib" (for use by ReactOS code). Both depend on the same core source,
+with a wrapper for the appropriate interface.
+Most of the differences between the host and the ReactOS environment are
+abstracted away in builddep.h. Of particular note is that the host version
+uses Ansi characters while the ReactOS version uses Unicode. So, the core
+source uses TCHARs. builddep.h depends on a preprocessor variable INFLIB_HOST
+which is defined when building the host version (inflib.mak) but not defined
+when building the ReactOS version (inflib.xml).
+The wrappers have "host" or "ros" in their filename. The library interface is
+"infhost.h" for the host version, "infros.h" for the ReactOS version.
Property changes on: trunk/reactos/lib/inflib/README.txt
___________________________________________________________________
Name: svn:eol-style
   + native

Added: trunk/reactos/lib/inflib/builddep.h
--- trunk/reactos/lib/inflib/builddep.h	2005-11-24 06:07:04 UTC (rev 19515)
+++ trunk/reactos/lib/inflib/builddep.h	2005-11-24 08:07:12 UTC (rev 19516)
@@ -0,0 +1,75 @@
+/*
+ * COPYRIGHT:       See COPYING in the top level directory
+ * PROJECT:         .inf file parser
+ * FILE:            lib/inflib/builddep.h
+ * PURPOSE:         Build dependent definitions
+ * PROGRAMMER:      Ge van Geldorp <gvg@reactos.org>
+ */
+
+#ifdef INFLIB_HOST
+
+/* Definitions native to the host on which we're building */
+
+#include <string.h>
+#include <errno.h>
+
+#define FREE(Area) free(Area)
+#define MALLOC(Size) malloc(Size)
+#define ZEROMEMORY(Area, Size) memset((Area), '\0', (Size))
+#define MEMCPY(Dest, Src, Size) memcpy((Dest), (Src), (Size))
+
+#define INF_STATUS_SUCCESS           0
+#define INF_STATUS_NO_MEMORY         ENOMEM
+#define INF_STATUS_INVALID_PARAMETER EINVAL
+#define INF_STATUS_NOT_FOUND         ENOENT
+#define INF_STATUS_BUFFER_OVERFLOW   E2BIG
+#define INF_SUCCESS(x) (0 == (x))
+
+typedef char CHAR, *PCHAR;
+typedef unsigned char UCHAR, *PUCHAR;
+typedef long LONG, *PLONG;
+typedef unsigned long ULONG, *PULONG;
+typedef void VOID, *PVOID;
+typedef UCHAR BOOLEAN, *PBOOLEAN;
+
+typedef char TCHAR, *PTCHAR, *PTSTR;
+#define _T(x) x
+#define _tcsicmp strcasecmp
+#define _tcslen strlen
+#define _tcscpy strcpy
+#define _tcstoul strtoul
+#define _tcstol strtol
+
+extern void DbgPrint(const char *Fmt, ...);
+
+#else /* ! defined(INFLIB_HOST) */
+
+/* ReactOS definitions */
+
+#define UNICODE
+#define _UNICODE
+#include <tchar.h>
+#define WIN32_NO_STATUS
+#include <windows.h>
+#define NTOS_MODE_USER
+#include <ndk/ntndk.h>
+
+extern PVOID InfpHeap;
+
+#define FREE(Area) RtlFreeHeap(InfpHeap, 0, (Area))
+#define MALLOC(Size) RtlAllocateHeap(InfpHeap, 0, (Size))
+#define ZEROMEMORY(Area, Size) RtlZeroMemory((Area), (Size))
+#define MEMCPY(Dest, Src, Size) RtlCopyMemory((Dest), (Src), (Size))
+
+#define INF_STATUS_SUCCESS           STATUS_SUCCESS
+#define INF_STATUS_NO_MEMORY         STATUS_NO_MEMORY
+#define INF_STATUS_INVALID_PARAMETER STATUS_INVALID_PARAMETER
+#define INF_STATUS_NOT_FOUND         STATUS_NOT_FOUND
+#define INF_STATUS_BUFFER_OVERFLOW   STATUS_BUFFER_OVERFLOW
+#define INF_SUCCESS(x) (0 <= (x))
+
+#endif /* INFLIB_HOST */
+
+typedef const TCHAR *PCTSTR;
+
+/* EOF */
Property changes on: trunk/reactos/lib/inflib/builddep.h
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision
Name: svn:eol-style
   + native

Added: trunk/reactos/lib/inflib/infcommon.h
--- trunk/reactos/lib/inflib/infcommon.h	2005-11-24 06:07:04 UTC (rev 19515)
+++ trunk/reactos/lib/inflib/infcommon.h	2005-11-24 08:07:12 UTC (rev 19516)
@@ -0,0 +1,21 @@
+/*
+ * COPYRIGHT:       See COPYING in the top level directory
+ * PROJECT:         .inf file parser
+ * FILE:            lib/inflib/infcommon.h
+ * PURPOSE:         Public .inf routines
+ * PROGRAMMER:      Royce Mitchell III
+ *                  Eric Kohl
+ *                  Ge van Geldorp
+ */
+
+#ifndef INFCOMMON_H_INCLUDED
+#define INFCOMMON_H_INCLUDED
+
+#define MAX_INF_STRING_LENGTH  512
+
+typedef void *HINF, **PHINF;
+typedef struct _INFCONTEXT *PINFCONTEXT;
+
+#endif /* INFCOMMON_H_INCLUDED */
+
+/* EOF */
Property changes on: trunk/reactos/lib/inflib/infcommon.h
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision
Name: svn:eol-style
   + native

Copied: trunk/reactos/lib/inflib/infcore.c (from rev 19508, trunk/reactos/subsys/system/usetup/infcache.c)
--- trunk/reactos/subsys/system/usetup/infcache.c	2005-11-23 23:02:35 UTC (rev 19508)
+++ trunk/reactos/lib/inflib/infcore.c	2005-11-24 08:07:12 UTC (rev 19516)
@@ -0,0 +1,811 @@
+/*
+ * COPYRIGHT:       See COPYING in the top level directory
+ * PROJECT:         .inf file parser
+ * FILE:            lib/inflib/infcore.c
+ * PURPOSE:         INF file parser that caches contents of INF file in memory
+ * PROGRAMMER:      Royce Mitchell III
+ *                  Eric Kohl
+ *                  Ge van Geldorp
+ */
+
+/* INCLUDES *****************************************************************/
+
+#include "inflib.h"
+
+#define NDEBUG
+#include <debug.h>
+
+#define CONTROL_Z  '\x1a'
+#define MAX_SECTION_NAME_LEN  255
+#define MAX_FIELD_LEN         511  /* larger fields get silently truncated */
+/* actual string limit is MAX_INF_STRING_LENGTH+1 (plus terminating null) under Windows */
+#define MAX_STRING_LEN        (MAX_INF_STRING_LENGTH+1)
+
+
+/* parser definitions */
+
+enum parser_state
+{
+  LINE_START,      /* at beginning of a line */
+  SECTION_NAME,    /* parsing a section name */
+  KEY_NAME,        /* parsing a key name */
+  VALUE_NAME,      /* parsing a value name */
+  EOL_BACKSLASH,   /* backslash at end of line */
+  QUOTES,          /* inside quotes */
+  LEADING_SPACES,  /* leading spaces */
+  TRAILING_SPACES, /* trailing spaces */
+  COMMENT,         /* inside a comment */
+  NB_PARSER_STATES
+};
+
+struct parser
+{
+  const CHAR        *start;       /* start position of item being parsed */
+  const CHAR        *end;         /* end of buffer */
+  PINFCACHE         file;         /* file being built */
+  enum parser_state state;        /* current parser state */
+  enum parser_state stack[4];     /* state stack */
+  int               stack_pos;    /* current pos in stack */
+
+  PINFCACHESECTION cur_section;   /* pointer to the section being parsed*/
+  PINFCACHELINE    line;          /* current line */
+  unsigned int     line_pos;      /* current line position in file */
+  unsigned int     error;         /* error code */
+  unsigned int     token_len;     /* current token len */
+  TCHAR token[MAX_FIELD_LEN+1];   /* current token */
+};
+
+typedef const CHAR * (*parser_state_func)( struct parser *parser, const CHAR *pos );
+
+/* parser state machine functions */
+static const CHAR *line_start_state( struct parser *parser, const CHAR *pos );
+static const CHAR *section_name_state( struct parser *parser, const CHAR *pos );
+static const CHAR *key_name_state( struct parser *parser, const CHAR *pos );
+static const CHAR *value_name_state( struct parser *parser, const CHAR *pos );
+static const CHAR *eol_backslash_state( struct parser *parser, const CHAR *pos );
+static const CHAR *quotes_state( struct parser *parser, const CHAR *pos );
+static const CHAR *leading_spaces_state( struct parser *parser, const CHAR *pos );
+static const CHAR *trailing_spaces_state( struct parser *parser, const CHAR *pos );
+static const CHAR *comment_state( struct parser *parser, const CHAR *pos );
+
+static const parser_state_func parser_funcs[NB_PARSER_STATES] =
+{
+  line_start_state,      /* LINE_START */
+  section_name_state,    /* SECTION_NAME */
+  key_name_state,        /* KEY_NAME */
+  value_name_state,      /* VALUE_NAME */
+  eol_backslash_state,   /* EOL_BACKSLASH */
+  quotes_state,          /* QUOTES */
+  leading_spaces_state,  /* LEADING_SPACES */
+  trailing_spaces_state, /* TRAILING_SPACES */
+  comment_state          /* COMMENT */
+};
+
+
+/* PRIVATE FUNCTIONS ********************************************************/
+
+static PINFCACHELINE
+InfpCacheFreeLine (PINFCACHELINE Line)
+{
+  PINFCACHELINE Next;
+  PINFCACHEFIELD Field;
+
+  if (Line == NULL)
+    {
+      return NULL;
+    }
+
+  Next = Line->Next;
+  if (Line->Key != NULL)
+    {
+      FREE (Line->Key);
+      Line->Key = NULL;
+    }
+
+  /* Remove data fields */
+  while (Line->FirstField != NULL)
+    {
+      Field = Line->FirstField->Next;
+      FREE (Line->FirstField);
+      Line->FirstField = Field;
+    }
+  Line->LastField = NULL;
+
+  FREE (Line);
+
+  return Next;
+}
+
+
+PINFCACHESECTION
+InfpCacheFreeSection (PINFCACHESECTION Section)
+{
+  PINFCACHESECTION Next;
+
+  if (Section == NULL)
+    {
+      return NULL;
+    }
+
+  /* Release all keys */
+  Next = Section->Next;
+  while (Section->FirstLine != NULL)
+    {
+      Section->FirstLine = InfpCacheFreeLine (Section->FirstLine);
+    }
+  Section->LastLine = NULL;
+
+  FREE (Section);
+
+  return Next;
+}
+
+
+static PINFCACHESECTION
+InfpCacheFindSection (PINFCACHE Cache,
+		      PCTSTR Name)
+{
+  PINFCACHESECTION Section = NULL;
+
+  if (Cache == NULL || Name == NULL)
+    {
+      return NULL;
+    }
+
+  /* iterate through list of sections */
+  Section = Cache->FirstSection;
+  while (Section != NULL)
+    {
+      if (_tcsicmp (Section->Name, Name) == 0)
+	{
+	  return Section;
+	}
+
+      /* get the next section*/
+      Section = Section->Next;
+    }
+
+  return NULL;
+}
+
+
+static PINFCACHESECTION
+InfpCacheAddSection (PINFCACHE Cache,
+		     PTCHAR Name)
+{
+  PINFCACHESECTION Section = NULL;
+  ULONG Size;
+
+  if (Cache == NULL || Name == NULL)
+    {
+      DPRINT("Invalid parameter\n");
+      return NULL;
+    }
+
+  /* Allocate and initialize the new section */
+  Size = sizeof(INFCACHESECTION) + (_tcslen (Name) * sizeof(TCHAR));
+  Section = (PINFCACHESECTION)MALLOC (Size);
+  if (Section == NULL)
+    {
+      DPRINT("MALLOC() failed\n");
+      return NULL;
+    }
+  ZEROMEMORY (Section,
+              Size);
+
+  /* Copy section name */
+  _tcscpy (Section->Name, Name);
+
+  /* Append section */
+  if (Cache->FirstSection == NULL)
+    {
+      Cache->FirstSection = Section;
+      Cache->LastSection = Section;
+    }
+  else
+    {
+      Cache->LastSection->Next = Section;
+      Section->Prev = Cache->LastSection;
+      Cache->LastSection = Section;
+    }
+
+  return Section;
+}
+
+
+static PINFCACHELINE
+InfpCacheAddLine (PINFCACHESECTION Section)
+{
+  PINFCACHELINE Line;
+
+  if (Section == NULL)
+    {
+      DPRINT("Invalid parameter\n");
+      return NULL;
+    }
+
+  Line = (PINFCACHELINE)MALLOC (sizeof(INFCACHELINE));
+  if (Line == NULL)
+    {
+      DPRINT("MALLOC() failed\n");
+      return NULL;
+    }
+  ZEROMEMORY(Line,
+             sizeof(INFCACHELINE));
+
+  /* Append line */
+  if (Section->FirstLine == NULL)
+    {
+      Section->FirstLine = Line;
+      Section->LastLine = Line;
+    }
+  else
+    {
+      Section->LastLine->Next = Line;
+      Line->Prev = Section->LastLine;
+      Section->LastLine = Line;
+    }
+  Section->LineCount++;
+
+  return Line;
+}
+
+
+static PVOID
+InfpAddKeyToLine (PINFCACHELINE Line,
+		  PTCHAR Key)
+{
+  if (Line == NULL)
+    return NULL;
+
+  if (Line->Key != NULL)
+    return NULL;
+
+  Line->Key = (PTCHAR)MALLOC ((_tcslen (Key) + 1) * sizeof(TCHAR));
+  if (Line->Key == NULL)
+    return NULL;
+
+  _tcscpy (Line->Key, Key);
+
+  return (PVOID)Line->Key;
+}
+
+
+static PVOID
+InfpAddFieldToLine (PINFCACHELINE Line,
+		    PTCHAR Data)
+{
+  PINFCACHEFIELD Field;
+  ULONG Size;
+
+  Size = sizeof(INFCACHEFIELD) + (_tcslen(Data) * sizeof(TCHAR));
+  Field = (PINFCACHEFIELD)MALLOC (Size);
+  if (Field == NULL)
+    {
+      return NULL;
+    }
+  ZEROMEMORY (Field,
+              Size);
+  _tcscpy (Field->Data, Data);
+
+  /* Append key */
+  if (Line->FirstField == NULL)
+    {
+      Line->FirstField = Field;
+      Line->LastField = Field;
+    }
+  else
+    {
+      Line->LastField->Next = Field;
+      Field->Prev = Line->LastField;
+      Line->LastField = Field;
+    }
+  Line->FieldCount++;
+
+  return (PVOID)Field;
+}
+
+
+PINFCACHELINE
+InfpCacheFindKeyLine (PINFCACHESECTION Section,
+		      PTCHAR Key)
+{
+  PINFCACHELINE Line;
+
+  Line = Section->FirstLine;
+  while (Line != NULL)
+    {
+      if (Line->Key != NULL && _tcsicmp (Line->Key, Key) == 0)
+	{
+	  return Line;
+	}
+
+      Line = Line->Next;
+    }
+
+  return NULL;
+}
+
+
+/* push the current state on the parser stack */
+inline static void push_state( struct parser *parser, enum parser_state state )
+{
+//  assert( parser->stack_pos < sizeof(parser->stack)/sizeof(parser->stack[0]) );
+  parser->stack[parser->stack_pos++] = state;
+}
+
+
+/* pop the current state */
+inline static void pop_state( struct parser *parser )
+{
+//  assert( parser->stack_pos );
+  parser->state = parser->stack[--parser->stack_pos];
+}
+
+
+/* set the parser state and return the previous one */
+inline static enum parser_state set_state( struct parser *parser, enum parser_state state )
+{
+  enum parser_state ret = parser->state;
+  parser->state = state;
+  return ret;
+}
+
+
+/* check if the pointer points to an end of file */
+inline static int is_eof( struct parser *parser, const CHAR *ptr )
+{
+  return (ptr >= parser->end || *ptr == CONTROL_Z);
+}
+
+
+/* check if the pointer points to an end of line */
+inline static int is_eol( struct parser *parser, const CHAR *ptr )
+{
+  return (ptr >= parser->end ||
+	  *ptr == CONTROL_Z ||
+	  *ptr == '\n' ||
+	  (*ptr == '\r' && *(ptr + 1) == '\n'));
+}
+
+
+/* push data from current token start up to pos into the current token */
+static int push_token( struct parser *parser, const CHAR *pos )
+{
+  unsigned int len = pos - parser->start;
+  const CHAR *src = parser->start;
+  TCHAR *dst = parser->token + parser->token_len;
+
+  if (len > MAX_FIELD_LEN - parser->token_len)
+    len = MAX_FIELD_LEN - parser->token_len;
+
+  parser->token_len += len;
+  for ( ; len > 0; len--, dst++, src++)
+    *dst = *src ? (TCHAR)*src : L' ';
+  *dst = 0;
+  parser->start = pos;
+
+  return 0;
+}
+
+
+
+/* add a section with the current token as name */
+static PVOID add_section_from_token( struct parser *parser )
+{
+  PINFCACHESECTION Section;
+
+  if (parser->token_len > MAX_SECTION_NAME_LEN)
+    {
+      parser->error = INF_STATUS_SECTION_NAME_TOO_LONG;
+      return NULL;
+    }
+
+  Section = InfpCacheFindSection (parser->file,
+				  parser->token);
+  if (Section == NULL)
+    {
+      /* need to create a new one */
+      Section= InfpCacheAddSection (parser->file,
+				    parser->token);
+      if (Section == NULL)
+	{
+	  parser->error = INF_STATUS_NOT_ENOUGH_MEMORY;
+	  return NULL;
+	}
+    }
+
+  parser->token_len = 0;
+  parser->cur_section = Section;
+
+  return (PVOID)Section;
+}
+
+
+/* add a field containing the current token to the current line */
+static struct field *add_field_from_token( struct parser *parser, int is_key )
+{
+  PVOID field;
+
+  if (!parser->line)  /* need to start a new line */
+    {
+      if (parser->cur_section == NULL)  /* got a line before the first section */
+	{
+	  parser->error = INF_STATUS_WRONG_INF_STYLE;
+	  return NULL;
+	}
+
+      parser->line = InfpCacheAddLine (parser->cur_section);
+      if (parser->line == NULL)
+	goto error;
+    }
+  else
+    {
+//      assert(!is_key);
+    }
+
+  if (is_key)
+    {
+      field = InfpAddKeyToLine(parser->line, parser->token);
+    }
+  else
+    {
+      field = InfpAddFieldToLine(parser->line, parser->token);
+    }
+
+  if (field != NULL)
+    {
+      parser->token_len = 0;
+      return field;
+    }
+
+error:
+  parser->error = INF_STATUS_NOT_ENOUGH_MEMORY;
+  return NULL;
+}
+
+
+/* close the current line and prepare for parsing a new one */
+static void close_current_line( struct parser *parser )
+{
+  parser->line = NULL;
+}
+
+
+
+/* handler for parser LINE_START state */
+static const CHAR *line_start_state( struct parser *parser, const CHAR *pos )
+{
+  const CHAR *p;
+
+  for (p = pos; !is_eof( parser, p ); p++)
+    {
+      switch(*p)
+	{
+	  case '\r':
+	    continue;
+
+	  case '\n':
+	    parser->line_pos++;
+	    close_current_line( parser );
+	    break;
+
+	  case ';':
+	    push_state( parser, LINE_START );
+	    set_state( parser, COMMENT );
+	    return p + 1;
+
+	  case '[':
+	    parser->start = p + 1;
+	    set_state( parser, SECTION_NAME );
+	    return p + 1;
+
+	  default:
+	    if (!isspace(*p))
+	      {
+		parser->start = p;
+		set_state( parser, KEY_NAME );
+		return p;
+	      }
+	    break;
+	}
+    }
+  close_current_line( parser );
+  return NULL;
+}
+
+
+/* handler for parser SECTION_NAME state */
+static const CHAR *section_name_state( struct parser *parser, const CHAR *pos )
+{
+  const CHAR *p;
+
+  for (p = pos; !is_eol( parser, p ); p++)
+    {
+      if (*p == ']')
+	{
+	  push_token( parser, p );
+	  if (add_section_from_token( parser ) == NULL)
+	    return NULL;
+	  push_state( parser, LINE_START );
+	  set_state( parser, COMMENT );  /* ignore everything else on the line */
+	  return p + 1;
+	}
+    }
+  parser->error = INF_STATUS_BAD_SECTION_NAME_LINE; /* unfinished section name */
+  return NULL;
+}
+
+
+/* handler for parser KEY_NAME state */
+static const CHAR *key_name_state( struct parser *parser, const CHAR *pos )
+{
+    const CHAR *p, *token_end = parser->start;
+
+    for (p = pos; !is_eol( parser, p ); p++)
+    {
+        if (*p == ',') break;
+        switch(*p)
+        {
+
+         case '=':
+            push_token( parser, token_end );
+            if (!add_field_from_token( parser, 1 )) return NULL;
+            parser->start = p + 1;
+            push_state( parser, VALUE_NAME );
+            set_state( parser, LEADING_SPACES );
+            return p + 1;
+        case ';':
+            push_token( parser, token_end );
+            if (!add_field_from_token( parser, 0 )) return NULL;
+            push_state( parser, LINE_START );
+            set_state( parser, COMMENT );
+            return p + 1;
+        case '"':
+            push_token( parser, token_end );
+            parser->start = p + 1;
+            push_state( parser, KEY_NAME );
+            set_state( parser, QUOTES );
+            return p + 1;
+        case '\\':
+            push_token( parser, token_end );
+            parser->start = p;
+            push_state( parser, KEY_NAME );
+            set_state( parser, EOL_BACKSLASH );
+            return p;
+        default:
+            if (!isspace(*p)) token_end = p + 1;
+            else
+            {
+                push_token( parser, p );
+                push_state( parser, KEY_NAME );
+                set_state( parser, TRAILING_SPACES );
+                return p;
+            }
+            break;
+        }
+    }
+    push_token( parser, token_end );
+    set_state( parser, VALUE_NAME );
+    return p;
+}
+
+
+/* handler for parser VALUE_NAME state */
+static const CHAR *value_name_state( struct parser *parser, const CHAR *pos )
+{
+    const CHAR *p, *token_end = parser->start;
+
+    for (p = pos; !is_eol( parser, p ); p++)
+    {
+        switch(*p)
+        {
+        case ';':
+            push_token( parser, token_end );
+            if (!add_field_from_token( parser, 0 )) return NULL;
+            push_state( parser, LINE_START );
+            set_state( parser, COMMENT );
+            return p + 1;
+        case ',':
+            push_token( parser, token_end );
+            if (!add_field_from_token( parser, 0 )) return NULL;
+            parser->start = p + 1;
+            push_state( parser, VALUE_NAME );
+            set_state( parser, LEADING_SPACES );
+            return p + 1;
+        case '"':
+            push_token( parser, token_end );
+            parser->start = p + 1;
+            push_state( parser, VALUE_NAME );
+            set_state( parser, QUOTES );
+            return p + 1;
+        case '\\':
+            push_token( parser, token_end );
+            parser->start = p;
+            push_state( parser, VALUE_NAME );
+            set_state( parser, EOL_BACKSLASH );
+            return p;
+        default:
+            if (!isspace(*p)) token_end = p + 1;
+            else
+            {
+                push_token( parser, p );
+                push_state( parser, VALUE_NAME );
+                set_state( parser, TRAILING_SPACES );
+                return p;
+            }
+            break;
+        }
+    }
+    push_token( parser, token_end );
+    if (!add_field_from_token( parser, 0 )) return NULL;
+    set_state( parser, LINE_START );
+    return p;
+}
+
+
+/* handler for parser EOL_BACKSLASH state */
+static const CHAR *eol_backslash_state( struct parser *parser, const CHAR *pos )
+{
+  const CHAR *p;
+
+  for (p = pos; !is_eof( parser, p ); p++)
+    {
+      switch(*p)
+	{
+	  case '\r':
+	    continue;
+
+	  case '\n':
+	    parser->line_pos++;
+	    parser->start = p + 1;
+	    set_state( parser, LEADING_SPACES );
+	    return p + 1;
+
+	  case '\\':
+	    continue;
+
+	  case ';':
+	    push_state( parser, EOL_BACKSLASH );
+	    set_state( parser, COMMENT );
+	    return p + 1;
+
+	  default:
+	    if (isspace(*p))
+	      continue;
+	    push_token( parser, p );
+	    pop_state( parser );
+	    return p;
+	}
+    }
+  parser->start = p;
+  pop_state( parser );
+
+  return p;
+}
+
+
+/* handler for parser QUOTES state */
+static const CHAR *quotes_state( struct parser *parser, const CHAR *pos )
+{
+  const CHAR *p, *token_end = parser->start;
+
+  for (p = pos; !is_eol( parser, p ); p++)
+    {
+      if (*p == '"')
+	{
+	  if (p+1 < parser->end && p[1] == '"')  /* double quotes */
+	    {
+	      push_token( parser, p + 1 );
+	      parser->start = token_end = p + 2;
+	      p++;
+	    }
+	  else  /* end of quotes */
+	    {
+	      push_token( parser, p );
+	      parser->start = p + 1;
+	      pop_state( parser );
+	      return p + 1;
+	    }
+	}
+    }
+  push_token( parser, p );
+  pop_state( parser );
+  return p;
+}
+
+
+/* handler for parser LEADING_SPACES state */
+static const CHAR *leading_spaces_state( struct parser *parser, const CHAR *pos )
+{
+  const CHAR *p;
+
+  for (p = pos; !is_eol( parser, p ); p++)
+    {
+      if (*p == '\\')
+	{
+	  parser->start = p;
+	  set_state( parser, EOL_BACKSLASH );
+	  return p;
+	}
+      if (!isspace(*p))
+	break;
+    }
+  parser->start = p;
+  pop_state( parser );
+  return p;
+}
+
+
+/* handler for parser TRAILING_SPACES state */
+static const CHAR *trailing_spaces_state( struct parser *parser, const CHAR *pos )
+{
+  const CHAR *p;
+
+  for (p = pos; !is_eol( parser, p ); p++)
+    {
+      if (*p == '\\')
+	{
+	  set_state( parser, EOL_BACKSLASH );
+	  return p;
+	}
+      if (!isspace(*p))
+	break;
+    }
+  pop_state( parser );
+  return p;
+}
+
+
+/* handler for parser COMMENT state */
+static const CHAR *comment_state( struct parser *parser, const CHAR *pos )
+{
+  const CHAR *p = pos;
+
+  while (!is_eol( parser, p ))
+     p++;
+  pop_state( parser );
+  return p;
+}
+
+
+/* parse a complete buffer */
+INFSTATUS
+InfpParseBuffer (PINFCACHE file,
+		 const CHAR *buffer,
+		 const CHAR *end,
+		 PULONG error_line)
+{
+  struct parser parser;
+  const CHAR *pos = buffer;
+
+  parser.start       = buffer;
+  parser.end         = end;
+  parser.file        = file;
+  parser.line        = NULL;
+  parser.state       = LINE_START;
+  parser.stack_pos   = 0;
+  parser.cur_section = NULL;
+  parser.line_pos    = 1;
+  parser.error       = 0;
+  parser.token_len   = 0;
+
+  /* parser main loop */
+  while (pos)
+    pos = (parser_funcs[parser.state])(&parser, pos);
+
+  if (parser.error)
+    {
+      if (error_line)
+	*error_line = parser.line_pos;
+      return parser.error;
+    }
+
+  /* find the [strings] section */
+  file->StringsSection = InfpCacheFindSection (file,
+					       _T("Strings"));
+
+  return INF_STATUS_SUCCESS;
+}
+
+/* EOF */

Copied: trunk/reactos/lib/inflib/infget.c (from rev 19508, trunk/reactos/subsys/system/usetup/infcache.c)
--- trunk/reactos/subsys/system/usetup/infcache.c	2005-11-23 23:02:35 UTC (rev 19508)
+++ trunk/reactos/lib/inflib/infget.c	2005-11-24 08:07:12 UTC (rev 19516)
@@ -0,0 +1,529 @@
+/*
+ * COPYRIGHT:       See COPYING in the top level directory
+ * PROJECT:         .inf file parser
+ * FILE:            lib/inflib/infrosget.c
+ * PURPOSE:         Read .inf routines for use in ReactOS
+ * PROGRAMMER:      Royce Mitchell III
+ *                  Eric Kohl
+ *                  Ge van Geldorp
+ */
+
+/* INCLUDES *****************************************************************/
+
+#include "inflib.h"
+
+#define NDEBUG
+#include <debug.h>
+
+
+INFSTATUS
+InfpFindFirstLine(HINF InfHandle,
+                  PCTSTR Section,
+                  PCTSTR Key,
+                  PINFCONTEXT *Context)
+{
[truncated at 1000 lines; 1832 more skipped]