[NEWINFLIB]
authorEric Kohl <eric.kohl@reactos.org>
Sun, 25 Apr 2010 15:58:34 +0000 (15:58 +0000)
committerEric Kohl <eric.kohl@reactos.org>
Sun, 25 Apr 2010 15:58:34 +0000 (15:58 +0000)
Add a UNICODE-aware version of the inflib library.
It is not used by other components yet but usetup and mkhive will use it in the future.
ATTENTION: This commit might break the build bot because I could not test a build on a Linux system.

svn path=/trunk/; revision=47016

20 files changed:
reactos/lib/lib.rbuild
reactos/lib/newinflib/README.txt [new file with mode: 0644]
reactos/lib/newinflib/builddep.h [new file with mode: 0644]
reactos/lib/newinflib/infcommon.h [new file with mode: 0644]
reactos/lib/newinflib/infcore.c [new file with mode: 0644]
reactos/lib/newinflib/infget.c [new file with mode: 0644]
reactos/lib/newinflib/infhost.h [new file with mode: 0644]
reactos/lib/newinflib/infhostgen.c [new file with mode: 0644]
reactos/lib/newinflib/infhostget.c [new file with mode: 0644]
reactos/lib/newinflib/infhostput.c [new file with mode: 0644]
reactos/lib/newinflib/infhostrtl.c [new file with mode: 0644]
reactos/lib/newinflib/inflib.h [new file with mode: 0644]
reactos/lib/newinflib/inflib.mak [new file with mode: 0644]
reactos/lib/newinflib/inflib.rbuild [new file with mode: 0644]
reactos/lib/newinflib/infpriv.h [new file with mode: 0644]
reactos/lib/newinflib/infput.c [new file with mode: 0644]
reactos/lib/newinflib/infros.h [new file with mode: 0644]
reactos/lib/newinflib/infrosgen.c [new file with mode: 0644]
reactos/lib/newinflib/infrosget.c [new file with mode: 0644]
reactos/lib/newinflib/infrosput.c [new file with mode: 0644]

index 42e49d6..fe9cf99 100644 (file)
@@ -37,6 +37,9 @@
        <directory name="lsalib">
                <xi:include href="lsalib/lsalib.rbuild" />
        </directory>
+       <directory name="newinflib">
+               <xi:include href="newinflib/inflib.rbuild" />
+       </directory>
        <directory name="nls">
                <xi:include href="nls/nls.rbuild" />
        </directory>
diff --git a/reactos/lib/newinflib/README.txt b/reactos/lib/newinflib/README.txt
new file mode 100644 (file)
index 0000000..5e27e2b
--- /dev/null
@@ -0,0 +1,16 @@
+Routines to handle .inf files.
+
+This is the UNICODE-enabled version of inflib. It will be used by usetup and mkhive.
+
+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.
diff --git a/reactos/lib/newinflib/builddep.h b/reactos/lib/newinflib/builddep.h
new file mode 100644 (file)
index 0000000..c768a2c
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * PROJECT:   .inf file parser
+ * LICENSE:   GPL - See COPYING in the top level directory
+ * COPYRIGHT: Copyright 2005 Ge van Geldorp <gvg@reactos.org>
+ */
+
+#ifdef INFLIB_HOST
+
+/* Definitions native to the host on which we're building */
+
+#include <host/typedefs.h>
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#define FREE(Area) free(Area)
+#define MALLOC(Size) malloc((size_t)(Size))
+#define ZEROMEMORY(Area, Size) memset((Area), '\0', (size_t)(Size))
+#define MEMCPY(Dest, Src, Size) memcpy((Dest), (Src), (size_t)(Size))
+
+#define STATUS_SUCCESS               0
+#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 TCHAR, *PTCHAR, *PTSTR;
+typedef const TCHAR *PCTSTR;
+typedef WORD LCID;
+
+#define _T(x) x
+#define _tcsicmp strcasecmp
+#define _tcslen strlen
+#define _tcscpy strcpy
+#define _tcstoul strtoul
+#define _tcstol strtol
+#define STRFMT "%s"
+
+#ifdef _MSC_VER
+#define strcasecmp _stricmp
+#endif
+
+#define IS_TEXT_UNICODE_ASCII16 1
+#define IS_TEXT_UNICODE_REVERSE_ASCII16 16
+#define IS_TEXT_UNICODE_STATISTICS 2
+#define IS_TEXT_UNICODE_REVERSE_STATISTICS 32
+#define IS_TEXT_UNICODE_CONTROLS 4
+#define IS_TEXT_UNICODE_REVERSE_CONTROLS 64
+#define IS_TEXT_UNICODE_SIGNATURE 8
+#define IS_TEXT_UNICODE_REVERSE_SIGNATURE 128
+#define IS_TEXT_UNICODE_ILLEGAL_CHARS 256
+#define IS_TEXT_UNICODE_ODD_LENGTH 512
+#define IS_TEXT_UNICODE_NULL_BYTES 4096
+#define IS_TEXT_UNICODE_UNICODE_MASK 15
+#define IS_TEXT_UNICODE_REVERSE_MASK 240
+#define IS_TEXT_UNICODE_NOT_UNICODE_MASK 3840
+#define IS_TEXT_UNICODE_NOT_ASCII_MASK 61440
+
+#define SUBLANG_NEUTRAL 0
+#define PRIMARYLANGID(lgid)  ((WORD)(lgid) & 0x3ff)
+#define MAKELANGID(p, s)     ((((WORD)(s)) << 10) | (WORD)(p))
+
+
+#else /* ! defined(INFLIB_HOST) */
+
+/* ReactOS definitions */
+
+#define UNICODE
+#define _UNICODE
+#define WIN32_NO_STATUS
+#include <windows.h>
+#define NTOS_MODE_USER
+#include <ndk/ntndk.h>
+#include <tchar.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))
+
+#define STRFMT "%S"
+
+#endif /* INFLIB_HOST */
+
+/* EOF */
diff --git a/reactos/lib/newinflib/infcommon.h b/reactos/lib/newinflib/infcommon.h
new file mode 100644 (file)
index 0000000..a80f202
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * PROJECT:    .inf file parser
+ * LICENSE:    GPL - See COPYING in the top level directory
+ * PROGRAMMER: Royce Mitchell III
+ *             Eric Kohl
+ *             Ge van Geldorp <gvg@reactos.org>
+ */
+
+#pragma once
+
+#define MAX_INF_STRING_LENGTH  512
+
+typedef void *HINF, **PHINF;
+typedef struct _INFCONTEXT *PINFCONTEXT;
+
+/* EOF */
diff --git a/reactos/lib/newinflib/infcore.c b/reactos/lib/newinflib/infcore.c
new file mode 100644 (file)
index 0000000..3582ec5
--- /dev/null
@@ -0,0 +1,831 @@
+/*
+ * PROJECT:    .inf file parser
+ * LICENSE:    GPL - See COPYING in the top level directory
+ * PROGRAMMER: Royce Mitchell III
+ *             Eric Kohl
+ *             Ge van Geldorp <gvg@reactos.org>
+ */
+
+/* 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 WCHAR       *start;       /* start position of item being parsed */
+  const WCHAR       *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 */
+  INFSTATUS        error;         /* error code */
+  unsigned int     token_len;     /* current token len */
+  WCHAR token[MAX_FIELD_LEN+1];   /* current token */
+};
+
+typedef const WCHAR * (*parser_state_func)( struct parser *parser, const WCHAR *pos );
+
+/* parser state machine functions */
+static const WCHAR *line_start_state( struct parser *parser, const WCHAR *pos );
+static const WCHAR *section_name_state( struct parser *parser, const WCHAR *pos );
+static const WCHAR *key_name_state( struct parser *parser, const WCHAR *pos );
+static const WCHAR *value_name_state( struct parser *parser, const WCHAR *pos );
+static const WCHAR *eol_backslash_state( struct parser *parser, const WCHAR *pos );
+static const WCHAR *quotes_state( struct parser *parser, const WCHAR *pos );
+static const WCHAR *leading_spaces_state( struct parser *parser, const WCHAR *pos );
+static const WCHAR *trailing_spaces_state( struct parser *parser, const WCHAR *pos );
+static const WCHAR *comment_state( struct parser *parser, const WCHAR *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
+InfpFreeLine (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
+InfpFreeSection (PINFCACHESECTION Section)
+{
+  PINFCACHESECTION Next;
+
+  if (Section == NULL)
+    {
+      return NULL;
+    }
+
+  /* Release all keys */
+  Next = Section->Next;
+  while (Section->FirstLine != NULL)
+    {
+      Section->FirstLine = InfpFreeLine (Section->FirstLine);
+    }
+  Section->LastLine = NULL;
+
+  FREE (Section);
+
+  return Next;
+}
+
+
+PINFCACHESECTION
+InfpFindSection(PINFCACHE Cache,
+                PCWSTR Name)
+{
+  PINFCACHESECTION Section = NULL;
+
+  if (Cache == NULL || Name == NULL)
+    {
+      return NULL;
+    }
+
+  /* iterate through list of sections */
+  Section = Cache->FirstSection;
+  while (Section != NULL)
+    {
+      if (_wcsicmp (Section->Name, Name) == 0)
+        {
+          return Section;
+        }
+
+      /* get the next section*/
+      Section = Section->Next;
+    }
+
+  return NULL;
+}
+
+
+PINFCACHESECTION
+InfpAddSection(PINFCACHE Cache,
+               PCWSTR Name)
+{
+  PINFCACHESECTION Section = NULL;
+  ULONG Size;
+
+  if (Cache == NULL || Name == NULL)
+    {
+      DPRINT("Invalid parameter\n");
+      return NULL;
+    }
+
+  /* Allocate and initialize the new section */
+  Size = (ULONG)FIELD_OFFSET(INFCACHESECTION,
+                             Name[wcslen (Name) + 1]);
+  Section = (PINFCACHESECTION)MALLOC(Size);
+  if (Section == NULL)
+    {
+      DPRINT("MALLOC() failed\n");
+      return NULL;
+    }
+  ZEROMEMORY (Section,
+              Size);
+
+  /* Copy section name */
+  wcscpy (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;
+}
+
+
+PINFCACHELINE
+InfpAddLine(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;
+}
+
+
+PVOID
+InfpAddKeyToLine(PINFCACHELINE Line,
+                 PCWSTR Key)
+{
+  if (Line == NULL)
+    {
+      DPRINT1("Invalid Line\n");
+      return NULL;
+    }
+
+  if (Line->Key != NULL)
+    {
+      DPRINT1("Line already has a key\n");
+      return NULL;
+    }
+
+  Line->Key = (PWCHAR)MALLOC((wcslen(Key) + 1) * sizeof(WCHAR));
+  if (Line->Key == NULL)
+    {
+      DPRINT1("MALLOC() failed\n");
+      return NULL;
+    }
+
+  wcscpy(Line->Key, Key);
+
+  return (PVOID)Line->Key;
+}
+
+
+PVOID
+InfpAddFieldToLine(PINFCACHELINE Line,
+                   PCWSTR Data)
+{
+  PINFCACHEFIELD Field;
+  ULONG Size;
+
+  Size = (ULONG)FIELD_OFFSET(INFCACHEFIELD,
+                             Data[wcslen(Data) + 1]);
+  Field = (PINFCACHEFIELD)MALLOC(Size);
+  if (Field == NULL)
+    {
+      DPRINT1("MALLOC() failed\n");
+      return NULL;
+    }
+  ZEROMEMORY (Field,
+              Size);
+  wcscpy (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
+InfpFindKeyLine(PINFCACHESECTION Section,
+                PCWSTR Key)
+{
+  PINFCACHELINE Line;
+
+  Line = Section->FirstLine;
+  while (Line != NULL)
+    {
+      if (Line->Key != NULL && _wcsicmp (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 WCHAR *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 WCHAR *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 WCHAR *pos )
+{
+  UINT len = (UINT)(pos - parser->start);
+  const WCHAR *src = parser->start;
+  WCHAR *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++)
+  {
+    if (*src)
+    {
+      *dst = *src;
+    }
+    else
+    {
+      *dst = ' ';
+    }
+  }
+
+  *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 = InfpFindSection(parser->file,
+                            parser->token);
+  if (Section == NULL)
+    {
+      /* need to create a new one */
+      Section= InfpAddSection(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 = InfpAddLine(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 WCHAR *line_start_state( struct parser *parser, const WCHAR *pos )
+{
+  const WCHAR *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 (!iswspace(*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 WCHAR *section_name_state( struct parser *parser, const WCHAR *pos )
+{
+  const WCHAR *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 WCHAR *key_name_state( struct parser *parser, const WCHAR *pos )
+{
+    const WCHAR *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 (!iswspace(*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 WCHAR *value_name_state( struct parser *parser, const WCHAR *pos )
+{
+    const WCHAR *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 WCHAR *eol_backslash_state( struct parser *parser, const WCHAR *pos )
+{
+  const WCHAR *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 (iswspace(*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 WCHAR *quotes_state( struct parser *parser, const WCHAR *pos )
+{
+  const WCHAR *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 WCHAR *leading_spaces_state( struct parser *parser, const WCHAR *pos )
+{
+  const WCHAR *p;
+
+  for (p = pos; !is_eol( parser, p ); p++)
+    {
+      if (*p == '\\')
+        {
+          parser->start = p;
+          set_state( parser, EOL_BACKSLASH );
+          return p;
+        }
+      if (!iswspace(*p))
+        break;
+    }
+  parser->start = p;
+  pop_state( parser );
+  return p;
+}
+
+
+/* handler for parser TRAILING_SPACES state */
+static const WCHAR *trailing_spaces_state( struct parser *parser, const WCHAR *pos )
+{
+  const WCHAR *p;
+
+  for (p = pos; !is_eol( parser, p ); p++)
+    {
+      if (*p == '\\')
+        {
+          set_state( parser, EOL_BACKSLASH );
+          return p;
+        }
+      if (!iswspace(*p))
+        break;
+    }
+  pop_state( parser );
+  return p;
+}
+
+
+/* handler for parser COMMENT state */
+static const WCHAR *comment_state( struct parser *parser, const WCHAR *pos )
+{
+  const WCHAR *p = pos;
+
+  while (!is_eol( parser, p ))
+     p++;
+  pop_state( parser );
+  return p;
+}
+
+
+/* parse a complete buffer */
+INFSTATUS
+InfpParseBuffer (PINFCACHE file,
+                 const WCHAR *buffer,
+                 const WCHAR *end,
+                 PULONG error_line)
+{
+  struct parser parser;
+  const WCHAR *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 = InfpFindSection(file,
+                                         L"Strings");
+
+  return INF_STATUS_SUCCESS;
+}
+
+/* EOF */
diff --git a/reactos/lib/newinflib/infget.c b/reactos/lib/newinflib/infget.c
new file mode 100644 (file)
index 0000000..1cdbebf
--- /dev/null
@@ -0,0 +1,668 @@
+/*
+ * PROJECT:    .inf file parser
+ * LICENSE:    GPL - See COPYING in the top level directory
+ * PROGRAMMER: Royce Mitchell III
+ *             Eric Kohl
+ *             Ge van Geldorp <gvg@reactos.org>
+ */
+
+/* INCLUDES *****************************************************************/
+
+#include "inflib.h"
+
+#define NDEBUG
+#include <debug.h>
+
+static unsigned int
+InfpSubstituteString(PINFCACHE Inf,
+                     const WCHAR *text,
+                     WCHAR *buffer,
+                     unsigned int size);
+
+/* retrieve the string substitution for a given string, or NULL if not found */
+/* if found, len is set to the substitution length */
+static PCWSTR
+InfpGetSubstitutionString(PINFCACHE Inf,
+                          PCWSTR str,
+                          unsigned int *len,
+                          BOOL no_trailing_slash)
+{
+    static const WCHAR percent = '%';
+
+    INFSTATUS Status = INF_STATUS_NOT_FOUND;
+    PINFCONTEXT Context = NULL;
+    PWCHAR Data = NULL;
+    WCHAR ValueName[MAX_INF_STRING_LENGTH +1];
+    WCHAR StringLangId[13];
+
+    if (!*len)  /* empty string (%%) is replaced by single percent */
+    {
+        *len = 1;
+        return &percent;
+    }
+
+    wcsncpy(ValueName, str, *len);
+    ValueName[*len] = 0;
+
+    DPRINT("Value name: %S\n", ValueName);
+
+    if (Inf->LocaleId != 0)
+    {
+        swprintf(StringLangId,
+                 L"Strings.%04hx",
+                 Inf->LocaleId);
+
+        Status = InfpFindFirstLine(Inf,
+                                   StringLangId,
+                                   ValueName,
+                                   &Context);
+        if (Status != INF_STATUS_SUCCESS)
+        {
+            swprintf(StringLangId,
+                     L"Strings.%04hx",
+                     MAKELANGID(PRIMARYLANGID(Inf->LocaleId), SUBLANG_NEUTRAL));
+
+            Status = InfpFindFirstLine(Inf,
+                                       StringLangId,
+                                       ValueName,
+                                       &Context);
+            if (Status != INF_STATUS_SUCCESS)
+            {
+                Status = InfpFindFirstLine(Inf,
+                                           L"Strings",
+                                           ValueName,
+                                           &Context);
+            }
+        }
+    }
+    else
+    {
+        Status = InfpFindFirstLine(Inf,
+                                   L"Strings",
+                                   ValueName,
+                                   &Context);
+    }
+
+    if (Status != INF_STATUS_SUCCESS || Context == NULL)
+        return NULL;
+
+    Status = InfpGetData(Context,
+                         NULL,
+                         &Data);
+
+    InfpFreeContext(Context);
+
+    if (Status == STATUS_SUCCESS)
+    {
+        *len = wcslen(Data);
+        DPRINT("Substitute: %S  Length: %ul\n", Data, *len);
+        return Data;
+    }
+
+    return NULL;
+}
+
+
+/* do string substitutions on the specified text */
+/* the buffer is assumed to be large enough */
+/* returns necessary length not including terminating null */
+static unsigned int
+InfpSubstituteString(PINFCACHE Inf,
+                     PCWSTR text,
+                     PWSTR buffer,
+                     unsigned int size)
+{
+    const WCHAR *start, *subst, *p;
+    unsigned int len, total = 0;
+    int inside = 0;
+
+    if (!buffer) size = MAX_INF_STRING_LENGTH + 1;
+    for (p = start = text; *p; p++)
+    {
+        if (*p != '%') continue;
+        inside = !inside;
+        if (inside)  /* start of a %xx% string */
+        {
+            len = (unsigned int)(p - start);
+            if (len > size - 1) len = size - 1;
+            if (buffer) memcpy( buffer + total, start, len * sizeof(WCHAR) );
+            total += len;
+            size -= len;
+            start = p;
+        }
+        else /* end of the %xx% string, find substitution */
+        {
+            len = (unsigned int)(p - start - 1);
+            subst = InfpGetSubstitutionString( Inf, start + 1, &len, p[1] == '\\' );
+            if (!subst)
+            {
+                subst = start;
+                len = (unsigned int)(p - start + 1);
+            }
+            if (len > size - 1) len = size - 1;
+            if (buffer) memcpy( buffer + total, subst, len * sizeof(WCHAR) );
+            total += len;
+            size -= len;
+            start = p + 1;
+        }
+    }
+
+    if (start != p) /* unfinished string, copy it */
+    {
+        len = (unsigned int)(p - start);
+        if (len > size - 1) len = size - 1;
+        if (buffer) memcpy( buffer + total, start, len * sizeof(WCHAR) );
+        total += len;
+    }
+    if (buffer && size) buffer[total] = 0;
+    return total;
+}
+
+
+INFSTATUS
+InfpFindFirstLine(PINFCACHE Cache,
+                  PCWSTR Section,
+                  PCWSTR Key,
+                  PINFCONTEXT *Context)
+{
+  PINFCACHESECTION CacheSection;
+  PINFCACHELINE CacheLine;
+
+  if (Cache == NULL || Section == NULL || Context == NULL)
+    {
+      DPRINT1("Invalid parameter\n");
+      return INF_STATUS_INVALID_PARAMETER;
+    }
+
+  CacheSection = InfpFindSection(Cache, Section);
+  if (NULL == CacheSection)
+    {
+      DPRINT("Section not found\n");
+      return INF_STATUS_NOT_FOUND;
+    }
+
+  if (Key != NULL)
+    {
+      CacheLine = InfpFindKeyLine(CacheSection, Key);
+    }
+  else
+    {
+      CacheLine = CacheSection->FirstLine;
+    }
+
+  if (NULL == CacheLine)
+    {
+      DPRINT("Key not found\n");
+      return INF_STATUS_NOT_FOUND;
+    }
+
+  *Context = MALLOC(sizeof(INFCONTEXT));
+  if (NULL == *Context)
+    {
+      DPRINT1("MALLOC() failed\n");
+      return INF_STATUS_NO_MEMORY;
+    }
+  (*Context)->Inf = (PVOID)Cache;
+  (*Context)->Section = (PVOID)CacheSection;
+  (*Context)->Line = (PVOID)CacheLine;
+
+  return INF_STATUS_SUCCESS;
+}
+
+
+INFSTATUS
+InfpFindNextLine(PINFCONTEXT ContextIn,
+                 PINFCONTEXT ContextOut)
+{
+  PINFCACHELINE CacheLine;
+
+  if (ContextIn == NULL || ContextOut == NULL)
+    return INF_STATUS_INVALID_PARAMETER;
+
+  if (ContextIn->Line == NULL)
+    return INF_STATUS_INVALID_PARAMETER;
+
+  CacheLine = (PINFCACHELINE)ContextIn->Line;
+  if (CacheLine->Next == NULL)
+    return INF_STATUS_NOT_FOUND;
+
+  if (ContextIn != ContextOut)
+    {
+      ContextOut->Inf = ContextIn->Inf;
+      ContextOut->Section = ContextIn->Section;
+    }
+  ContextOut->Line = (PVOID)(CacheLine->Next);
+
+  return INF_STATUS_SUCCESS;
+}
+
+
+INFSTATUS
+InfpFindFirstMatchLine(PINFCONTEXT ContextIn,
+                       PCWSTR Key,
+                       PINFCONTEXT ContextOut)
+{
+  PINFCACHELINE CacheLine;
+
+  if (ContextIn == NULL || ContextOut == NULL || Key == NULL || *Key == 0)
+    return INF_STATUS_INVALID_PARAMETER;
+
+  if (ContextIn->Inf == NULL || ContextIn->Section == NULL)
+    return INF_STATUS_INVALID_PARAMETER;
+
+  CacheLine = ((PINFCACHESECTION)(ContextIn->Section))->FirstLine;
+  while (CacheLine != NULL)
+    {
+      if (CacheLine->Key != NULL && _wcsicmp (CacheLine->Key, Key) == 0)
+        {
+
+          if (ContextIn != ContextOut)
+            {
+              ContextOut->Inf = ContextIn->Inf;
+              ContextOut->Section = ContextIn->Section;
+            }
+          ContextOut->Line = (PVOID)CacheLine;
+
+          return INF_STATUS_SUCCESS;
+        }
+
+      CacheLine = CacheLine->Next;
+    }
+
+  return INF_STATUS_NOT_FOUND;
+}
+
+
+INFSTATUS
+InfpFindNextMatchLine(PINFCONTEXT ContextIn,
+                      PCWSTR Key,
+                      PINFCONTEXT ContextOut)
+{
+  PINFCACHELINE CacheLine;
+
+  if (ContextIn == NULL || ContextOut == NULL || Key == NULL || *Key == 0)
+    return INF_STATUS_INVALID_PARAMETER;
+
+  if (ContextIn->Inf == NULL || ContextIn->Section == NULL || ContextIn->Line == NULL)
+    return INF_STATUS_INVALID_PARAMETER;
+
+  CacheLine = (PINFCACHELINE)ContextIn->Line;
+  while (CacheLine != NULL)
+    {
+      if (CacheLine->Key != NULL && _wcsicmp (CacheLine->Key, Key) == 0)
+        {
+
+          if (ContextIn != ContextOut)
+            {
+              ContextOut->Inf = ContextIn->Inf;
+              ContextOut->Section = ContextIn->Section;
+            }
+          ContextOut->Line = (PVOID)CacheLine;
+
+          return INF_STATUS_SUCCESS;
+        }
+
+      CacheLine = CacheLine->Next;
+    }
+
+  return INF_STATUS_NOT_FOUND;
+}
+
+
+LONG
+InfpGetLineCount(HINF InfHandle,
+                 PCWSTR Section)
+{
+  PINFCACHE Cache;
+  PINFCACHESECTION CacheSection;
+
+  if (InfHandle == NULL || Section == NULL)
+    {
+      DPRINT("Invalid parameter\n");
+      return -1;
+    }
+
+  Cache = (PINFCACHE)InfHandle;
+
+  /* Iterate through list of sections */
+  CacheSection = Cache->FirstSection;
+  while (CacheSection != NULL)
+    {
+      /* Are the section names the same? */
+      if (_wcsicmp(CacheSection->Name, Section) == 0)
+        {
+          return CacheSection->LineCount;
+        }
+
+      /* Get the next section */
+      CacheSection = CacheSection->Next;
+    }
+
+  DPRINT("Section not found\n");
+
+  return -1;
+}
+
+
+/* InfpGetLineText */
+
+
+LONG
+InfpGetFieldCount(PINFCONTEXT Context)
+{
+  if (Context == NULL || Context->Line == NULL)
+    return 0;
+
+  return ((PINFCACHELINE)Context->Line)->FieldCount;
+}
+
+
+INFSTATUS
+InfpGetBinaryField(PINFCONTEXT Context,
+                   ULONG FieldIndex,
+                   PUCHAR ReturnBuffer,
+                   ULONG ReturnBufferSize,
+                   PULONG RequiredSize)
+{
+  PINFCACHELINE CacheLine;
+  PINFCACHEFIELD CacheField;
+  ULONG Index;
+  ULONG Size;
+  PUCHAR Ptr;
+
+  if (Context == NULL || Context->Line == NULL || FieldIndex == 0)
+    {
+      DPRINT("Invalid parameter\n");
+      return INF_STATUS_INVALID_PARAMETER;
+    }
+
+  if (RequiredSize != NULL)
+    *RequiredSize = 0;
+
+  CacheLine = (PINFCACHELINE)Context->Line;
+
+  if (FieldIndex > (ULONG)CacheLine->FieldCount)
+    return INF_STATUS_NOT_FOUND;
+
+  CacheField = CacheLine->FirstField;
+  for (Index = 1; Index < FieldIndex; Index++)
+    CacheField = CacheField->Next;
+
+  Size = (ULONG)CacheLine->FieldCount - FieldIndex + 1;
+
+  if (RequiredSize != NULL)
+    *RequiredSize = Size;
+
+  if (ReturnBuffer != NULL)
+    {
+      if (ReturnBufferSize < Size)
+        return INF_STATUS_BUFFER_OVERFLOW;
+
+      /* Copy binary data */
+      Ptr = ReturnBuffer;
+      while (CacheField != NULL)
+        {
+          *Ptr = (UCHAR)wcstoul(CacheField->Data, NULL, 16);
+
+          Ptr++;
+          CacheField = CacheField->Next;
+        }
+    }
+
+  return INF_STATUS_SUCCESS;
+}
+
+
+INFSTATUS
+InfpGetIntField(PINFCONTEXT Context,
+                ULONG FieldIndex,
+                PLONG IntegerValue)
+{
+  PINFCACHELINE CacheLine;
+  PINFCACHEFIELD CacheField;
+  ULONG Index;
+  PWCHAR Ptr;
+
+  if (Context == NULL || Context->Line == NULL || IntegerValue == NULL)
+    {
+      DPRINT("Invalid parameter\n");
+      return INF_STATUS_INVALID_PARAMETER;
+    }
+
+  CacheLine = (PINFCACHELINE)Context->Line;
+
+  if (FieldIndex > (ULONG)CacheLine->FieldCount)
+    {
+      DPRINT("Invalid parameter\n");
+      return INF_STATUS_INVALID_PARAMETER;
+    }
+
+  if (FieldIndex == 0)
+    {
+      Ptr = CacheLine->Key;
+    }
+  else
+    {
+      CacheField = CacheLine->FirstField;
+      for (Index = 1; Index < FieldIndex; Index++)
+        CacheField = CacheField->Next;
+
+      Ptr = CacheField->Data;
+    }
+
+  *IntegerValue = (LONG)wcstol(Ptr, NULL, 0);
+
+  return INF_STATUS_SUCCESS;
+}
+
+
+INFSTATUS
+InfpGetMultiSzField(PINFCONTEXT Context,
+                    ULONG FieldIndex,
+                    PWSTR ReturnBuffer,
+                    ULONG ReturnBufferSize,
+                    PULONG RequiredSize)
+{
+  PINFCACHELINE CacheLine;
+  PINFCACHEFIELD CacheField;
+  PINFCACHEFIELD FieldPtr;
+  ULONG Index;
+  ULONG Size;
+  PWCHAR Ptr;
+
+  if (Context == NULL || Context->Line == NULL || FieldIndex == 0)
+    {
+      DPRINT("Invalid parameter\n");
+      return INF_STATUS_INVALID_PARAMETER;
+    }
+
+  if (RequiredSize != NULL)
+    *RequiredSize = 0;
+
+  CacheLine = (PINFCACHELINE)Context->Line;
+
+  if (FieldIndex > (ULONG)CacheLine->FieldCount)
+    return INF_STATUS_INVALID_PARAMETER;
+
+  CacheField = CacheLine->FirstField;
+  for (Index = 1; Index < FieldIndex; Index++)
+    CacheField = CacheField->Next;
+
+  /* Calculate the required buffer size */
+  FieldPtr = CacheField;
+  Size = 0;
+  while (FieldPtr != NULL)
+    {
+      Size += ((ULONG)wcslen (FieldPtr->Data) + 1);
+      FieldPtr = FieldPtr->Next;
+    }
+  Size++;
+
+  if (RequiredSize != NULL)
+    *RequiredSize = Size;
+
+  if (ReturnBuffer != NULL)
+    {
+      if (ReturnBufferSize < Size)
+        return INF_STATUS_BUFFER_OVERFLOW;
+
+      /* Copy multi-sz string */
+      Ptr = ReturnBuffer;
+      FieldPtr = CacheField;
+      while (FieldPtr != NULL)
+        {
+          Size = (ULONG)wcslen (FieldPtr->Data) + 1;
+
+          wcscpy (Ptr, FieldPtr->Data);
+
+          Ptr = Ptr + Size;
+          FieldPtr = FieldPtr->Next;
+        }
+      *Ptr = 0;
+    }
+
+  return INF_STATUS_SUCCESS;
+}
+
+
+INFSTATUS
+InfpGetStringField(PINFCONTEXT Context,
+                   ULONG FieldIndex,
+                   PWSTR ReturnBuffer,
+                   ULONG ReturnBufferSize,
+                   PULONG RequiredSize)
+{
+  PINFCACHELINE CacheLine;
+  PINFCACHEFIELD CacheField;
+  ULONG Index;
+  PWCHAR Ptr;
+  ULONG Size;
+
+  if (Context == NULL || Context->Line == NULL || FieldIndex == 0)
+    {
+      DPRINT("Invalid parameter\n");
+      return INF_STATUS_INVALID_PARAMETER;
+    }
+
+  if (RequiredSize != NULL)
+    *RequiredSize = 0;
+
+  CacheLine = (PINFCACHELINE)Context->Line;
+
+  if (FieldIndex > (ULONG)CacheLine->FieldCount)
+    return INF_STATUS_INVALID_PARAMETER;
+
+  if (FieldIndex == 0)
+    {
+      Ptr = CacheLine->Key;
+    }
+  else
+    {
+      CacheField = CacheLine->FirstField;
+      for (Index = 1; Index < FieldIndex; Index++)
+        CacheField = CacheField->Next;
+
+      Ptr = CacheField->Data;
+    }
+
+//  Size = (ULONG)wcslen (Ptr) + 1;
+  Size = InfpSubstituteString(Context->Inf,
+                              Ptr,
+                              NULL,
+                              0);
+
+  if (RequiredSize != NULL)
+    *RequiredSize = Size + 1;
+
+  if (ReturnBuffer != NULL)
+    {
+      if (ReturnBufferSize <= Size)
+        return INF_STATUS_BUFFER_OVERFLOW;
+
+//      wcscpy (ReturnBuffer, Ptr);
+      InfpSubstituteString(Context->Inf,
+                           Ptr,
+                           ReturnBuffer,
+                           ReturnBufferSize);
+    }
+
+  return INF_STATUS_SUCCESS;
+}
+
+
+INFSTATUS
+InfpGetData(PINFCONTEXT Context,
+            PWCHAR *Key,
+            PWCHAR *Data)
+{
+  PINFCACHELINE CacheKey;
+
+  if (Context == NULL || Context->Line == NULL || Data == NULL)
+    {
+      DPRINT("Invalid parameter\n");
+      return INF_STATUS_INVALID_PARAMETER;
+    }
+
+  CacheKey = (PINFCACHELINE)Context->Line;
+  if (Key != NULL)
+    *Key = CacheKey->Key;
+
+  if (Data != NULL)
+    {
+      if (CacheKey->FirstField == NULL)
+        {
+          *Data = NULL;
+        }
+      else
+        {
+          *Data = CacheKey->FirstField->Data;
+        }
+    }
+
+  return INF_STATUS_SUCCESS;
+}
+
+
+INFSTATUS
+InfpGetDataField(PINFCONTEXT Context,
+                 ULONG FieldIndex,
+                 PWCHAR *Data)
+{
+  PINFCACHELINE CacheLine;
+  PINFCACHEFIELD CacheField;
+  ULONG Index;
+
+  if (Context == NULL || Context->Line == NULL || Data == NULL)
+    {
+      DPRINT("Invalid parameter\n");
+      return INF_STATUS_INVALID_PARAMETER;
+    }
+
+  CacheLine = (PINFCACHELINE)Context->Line;
+
+  if (FieldIndex > (ULONG)CacheLine->FieldCount)
+    return INF_STATUS_INVALID_PARAMETER;
+
+  if (FieldIndex == 0)
+    {
+      *Data = CacheLine->Key;
+    }
+  else
+    {
+      CacheField = CacheLine->FirstField;
+      for (Index = 1; Index < FieldIndex; Index++)
+        CacheField = CacheField->Next;
+
+      *Data = CacheField->Data;
+    }
+
+  return INF_STATUS_SUCCESS;
+}
+
+VOID
+InfpFreeContext(PINFCONTEXT Context)
+{
+  FREE(Context);
+}
+
+/* EOF */
diff --git a/reactos/lib/newinflib/infhost.h b/reactos/lib/newinflib/infhost.h
new file mode 100644 (file)
index 0000000..6cdb37c
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * PROJECT:    .inf file parser
+ * LICENSE:    GPL - See COPYING in the top level directory
+ * PROGRAMMER: Royce Mitchell III
+ *             Eric Kohl
+ *             Ge van Geldorp <gvg@reactos.org>
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#include "infcommon.h"
+
+extern NTSTATUS NTAPI RtlMultiByteToUnicodeN(IN PWCHAR UnicodeString,
+    IN ULONG UnicodeSize, IN PULONG ResultSize, IN PCSTR MbString, IN ULONG MbSize);
+
+extern BOOLEAN NTAPI RtlIsTextUnicode( PVOID buf, INT len, INT *pf );
+
+
+extern int InfHostOpenBufferedFile(PHINF InfHandle,
+                                   void *Buffer,
+                                   ULONG BufferSize,
+                                   LCID LocaleId,
+                                   ULONG *ErrorLine);
+extern int InfHostOpenFile(PHINF InfHandle,
+                           const CHAR *FileName,
+                           LCID LocaleId,
+                           ULONG *ErrorLine);
+extern int InfHostWriteFile(HINF InfHandle,
+                            const CHAR *FileName,
+                            const CHAR *HeaderComment);
+extern void InfHostCloseFile(HINF InfHandle);
+extern int InfHostFindFirstLine(HINF InfHandle,
+                                const WCHAR *Section,
+                                const WCHAR *Key,
+                                PINFCONTEXT *Context);
+extern int InfHostFindNextLine(PINFCONTEXT ContextIn,
+                               PINFCONTEXT ContextOut);
+extern int InfHostFindFirstMatchLine(PINFCONTEXT ContextIn,
+                                     const WCHAR *Key,
+                                     PINFCONTEXT ContextOut);
+extern int InfHostFindNextMatchLine(PINFCONTEXT ContextIn,
+                                    const WCHAR *Key,
+                                    PINFCONTEXT ContextOut);
+extern LONG InfHostGetLineCount(HINF InfHandle,
+                                const WCHAR *Section);
+extern LONG InfHostGetFieldCount(PINFCONTEXT Context);
+extern int InfHostGetBinaryField(PINFCONTEXT Context,
+                                 ULONG FieldIndex,
+                                 UCHAR *ReturnBuffer,
+                                 ULONG ReturnBufferSize,
+                                 ULONG *RequiredSize);
+extern int InfHostGetIntField(PINFCONTEXT Context,
+                              ULONG FieldIndex,
+                              ULONG *IntegerValue);
+extern int InfHostGetMultiSzField(PINFCONTEXT Context,
+                                  ULONG FieldIndex,
+                                  WCHAR *ReturnBuffer,
+                                  ULONG ReturnBufferSize,
+                                  ULONG *RequiredSize);
+extern int InfHostGetStringField(PINFCONTEXT Context,
+                                 ULONG FieldIndex,
+                                 WCHAR *ReturnBuffer,
+                                 ULONG ReturnBufferSize,
+                                 ULONG *RequiredSize);
+extern int InfHostGetData(PINFCONTEXT Context,
+                          WCHAR **Key,
+                          WCHAR **Data);
+extern int InfHostGetDataField(PINFCONTEXT Context,
+                               ULONG FieldIndex,
+                               WCHAR **Data);
+extern int InfHostFindOrAddSection(HINF InfHandle,
+                                   const WCHAR *Section,
+                                   PINFCONTEXT *Context);
+extern int InfHostAddLine(PINFCONTEXT Context, const WCHAR *Key);
+extern int InfHostAddField(PINFCONTEXT Context, const WCHAR *Data);
+extern void InfHostFreeContext(PINFCONTEXT Context);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+/* EOF */
diff --git a/reactos/lib/newinflib/infhostgen.c b/reactos/lib/newinflib/infhostgen.c
new file mode 100644 (file)
index 0000000..e5ad1b9
--- /dev/null
@@ -0,0 +1,316 @@
+/*
+ * PROJECT:    .inf file parser
+ * LICENSE:    GPL - See COPYING in the top level directory
+ * PROGRAMMER: Royce Mitchell III
+ *             Eric Kohl
+ *             Ge van Geldorp <gvg@reactos.org>
+ */
+
+/* INCLUDES *****************************************************************/
+
+#include "inflib.h"
+#include "infhost.h"
+
+#define NDEBUG
+#include <debug.h>
+
+/* PUBLIC FUNCTIONS *********************************************************/
+
+int
+InfHostOpenBufferedFile(PHINF InfHandle,
+                        void *Buffer,
+                        ULONG BufferSize,
+                        LCID LocaleId,
+                        ULONG *ErrorLine)
+{
+  INFSTATUS Status;
+  PINFCACHE Cache;
+  WCHAR *FileBuffer;
+  ULONG FileBufferSize;
+
+  *InfHandle = NULL;
+  *ErrorLine = (ULONG)-1;
+
+  /* Allocate file buffer */
+  FileBufferSize = BufferSize + 2;
+  FileBuffer = MALLOC(FileBufferSize);
+  if (FileBuffer == NULL)
+    {
+      DPRINT1("MALLOC() failed\n");
+      return(INF_STATUS_INSUFFICIENT_RESOURCES);
+    }
+
+  MEMCPY(FileBuffer, Buffer, BufferSize);
+
+  /* Append string terminator */
+  FileBuffer[BufferSize] = 0;
+  FileBuffer[BufferSize + 1] = 0;
+
+  /* Allocate infcache header */
+  Cache = (PINFCACHE)MALLOC(sizeof(INFCACHE));
+  if (Cache == NULL)
+    {
+      DPRINT1("MALLOC() failed\n");
+      FREE(FileBuffer);
+      return(INF_STATUS_INSUFFICIENT_RESOURCES);
+    }
+
+  /* Initialize inicache header */
+  ZEROMEMORY(Cache,
+             sizeof(INFCACHE));
+
+    Cache->LocaleId = LocaleId;
+
+    if (!RtlIsTextUnicode(FileBuffer, (INT)FileBufferSize, NULL))
+    {
+//        static const BYTE utf8_bom[3] = { 0xef, 0xbb, 0xbf };
+        WCHAR *new_buff;
+//        UINT codepage = CP_ACP;
+        UINT offset = 0;
+
+//        if (BufferSize > sizeof(utf8_bom) && !memcmp(FileBuffer, utf8_bom, sizeof(utf8_bom) ))
+//        {
+//            codepage = CP_UTF8;
+//            offset = sizeof(utf8_bom);
+//        }
+
+        new_buff = MALLOC(FileBufferSize * sizeof(WCHAR));
+        if (new_buff != NULL)
+        {
+//            DWORD len = MultiByteToWideChar( codepage, 0, (char *)FileBuffer + offset,
+//                                             FileBufferSize - offset, new_buff, FileBufferSize);
+
+            ULONG len;
+            Status = RtlMultiByteToUnicodeN(new_buff,
+                                            FileBufferSize * sizeof(WCHAR),
+                                            &len,
+                                            (char *)FileBuffer + offset,
+                                            FileBufferSize - offset);
+
+            Status = InfpParseBuffer(Cache,
+                                     new_buff,
+                                     new_buff + len / sizeof(WCHAR),
+                                     ErrorLine);
+            FREE(new_buff);
+        }
+        else
+            Status = INF_STATUS_INSUFFICIENT_RESOURCES;
+    }
+    else
+    {
+        WCHAR *new_buff = (WCHAR *)FileBuffer;
+        /* UCS-16 files should start with the Unicode BOM; we should skip it */
+        if (*new_buff == 0xfeff)
+        {
+            new_buff++;
+            FileBufferSize -= sizeof(WCHAR);
+        }
+        Status = InfpParseBuffer(Cache,
+                                 new_buff,
+                                 (WCHAR*)((char*)new_buff + FileBufferSize),
+                                 ErrorLine);
+    }
+
+  /* Parse the inf buffer */
+//  Status = InfpParseBuffer (Cache,
+//                         FileBuffer,
+//                         FileBuffer + BufferSize,
+//                         ErrorLine);
+  if (!INF_SUCCESS(Status))
+    {
+      FREE(Cache);
+      Cache = NULL;
+    }
+
+  /* Free file buffer */
+  FREE(FileBuffer);
+
+  *InfHandle = (HINF)Cache;
+
+  return INF_SUCCESS(Status) ? 0 : -1;
+}
+
+
+int
+InfHostOpenFile(PHINF InfHandle,
+                const CHAR *FileName,
+                LCID LocaleId,
+                ULONG *ErrorLine)
+{
+  FILE *File;
+  CHAR *FileBuffer;
+  ULONG FileLength;
+  ULONG FileBufferLength;
+  PINFCACHE Cache;
+  INFSTATUS Status = INF_STATUS_SUCCESS;
+
+  *InfHandle = NULL;
+  *ErrorLine = (ULONG)-1;
+
+  /* Open the inf file */
+  File = fopen(FileName, "rb");
+  if (NULL == File)
+    {
+      DPRINT1("fopen() failed (errno %d)\n", errno);
+      return -1;
+    }
+
+  DPRINT("fopen() successful\n");
+
+  /* Query file size */
+  if (fseek(File, (size_t)0, SEEK_END))
+    {
+      DPRINT1("fseek() to EOF failed (errno %d)\n", errno);
+      fclose(File);
+      return -1;
+    }
+
+  FileLength = (ULONG)ftell(File);
+  if ((ULONG) -1 == FileLength)
+    {
+      DPRINT1("ftell() failed (errno %d)\n", errno);
+      fclose(File);
+      return -1;
+    }
+  DPRINT("File size: %u\n", (UINT)FileLength);
+
+  /* Rewind */
+  if (fseek(File, (size_t)0, SEEK_SET))
+    {
+      DPRINT1("fseek() to BOF failed (errno %d)\n", errno);
+      fclose(File);
+      return -1;
+    }
+
+  /* Allocate file buffer */
+  FileBufferLength = FileLength + 2;
+  FileBuffer = MALLOC(FileBufferLength);
+  if (FileBuffer == NULL)
+    {
+      DPRINT1("MALLOC() failed\n");
+      fclose(File);
+      return -1;
+    }
+
+  /* Read file */
+  if (FileLength != fread(FileBuffer, (size_t)1, (size_t)FileLength, File))
+    {
+      DPRINT1("fread() failed (errno %d)\n", errno);
+      fclose(File);
+      return -1;
+    }
+
+  fclose(File);
+
+  /* Append string terminator */
+  FileBuffer[FileLength] = 0;
+  FileBuffer[FileLength + 1] = 0;
+
+  /* Allocate infcache header */
+  Cache = (PINFCACHE)MALLOC(sizeof(INFCACHE));
+  if (Cache == NULL)
+    {
+      DPRINT1("MALLOC() failed\n");
+      FREE(FileBuffer);
+      return -1;
+    }
+
+  /* Initialize inicache header */
+  ZEROMEMORY(Cache,
+             sizeof(INFCACHE));
+
+    Cache->LocaleId = LocaleId;
+
+  /* Parse the inf buffer */
+    if (!RtlIsTextUnicode(FileBuffer, (INT)FileBufferLength, NULL))
+    {
+//        static const BYTE utf8_bom[3] = { 0xef, 0xbb, 0xbf };
+        WCHAR *new_buff;
+//        UINT codepage = CP_ACP;
+        UINT offset = 0;
+
+//        if (FileLength > sizeof(utf8_bom) && !memcmp(FileBuffer, utf8_bom, sizeof(utf8_bom) ))
+//        {
+//            codepage = CP_UTF8;
+//            offset = sizeof(utf8_bom);
+//        }
+
+        new_buff = MALLOC(FileBufferLength * sizeof(WCHAR));
+        if (new_buff != NULL)
+        {
+//            DWORD len = MultiByteToWideChar( codepage, 0, (char *)FileBuffer + offset,
+//                                             FileLength - offset, new_buff, FileLength);
+
+            ULONG len;
+            Status = RtlMultiByteToUnicodeN(new_buff,
+                                            FileBufferLength * sizeof(WCHAR),
+                                            &len,
+                                            (char *)FileBuffer + offset,
+                                            FileBufferLength - offset);
+
+            Status = InfpParseBuffer(Cache,
+                                     new_buff,
+                                     new_buff + len / sizeof(WCHAR),
+                                     ErrorLine);
+
+            FREE(new_buff);
+        }
+        else
+            Status = INF_STATUS_INSUFFICIENT_RESOURCES;
+    }
+    else
+    {
+        WCHAR *new_buff = (WCHAR *)FileBuffer;
+        /* UCS-16 files should start with the Unicode BOM; we should skip it */
+        if (*new_buff == 0xfeff)
+        {
+            new_buff++;
+            FileBufferLength -= sizeof(WCHAR);
+        }
+        Status = InfpParseBuffer(Cache,
+                                 new_buff,
+                                 (WCHAR*)((char*)new_buff + FileBufferLength),
+                                 ErrorLine);
+    }
+
+//  Status = InfpParseBuffer (Cache,
+//                         FileBuffer,
+//                         FileBuffer + FileLength,
+//                         ErrorLine);
+  if (!INF_SUCCESS(Status))
+    {
+      FREE(Cache);
+      Cache = NULL;
+    }
+
+  /* Free file buffer */
+  FREE(FileBuffer);
+
+  *InfHandle = (HINF)Cache;
+
+  return INF_SUCCESS(Status) ? 0 : -1;
+}
+
+
+void
+InfHostCloseFile(HINF InfHandle)
+{
+  PINFCACHE Cache;
+
+  Cache = (PINFCACHE)InfHandle;
+
+  if (Cache == NULL)
+    {
+      return;
+    }
+
+  while (Cache->FirstSection != NULL)
+    {
+      Cache->FirstSection = InfpFreeSection(Cache->FirstSection);
+    }
+  Cache->LastSection = NULL;
+
+  FREE(Cache);
+}
+
+/* EOF */
diff --git a/reactos/lib/newinflib/infhostget.c b/reactos/lib/newinflib/infhostget.c
new file mode 100644 (file)
index 0000000..bd49be1
--- /dev/null
@@ -0,0 +1,249 @@
+/*
+ * PROJECT:    .inf file parser
+ * LICENSE:    GPL - See COPYING in the top level directory
+ * PROGRAMMER: Royce Mitchell III
+ *             Eric Kohl
+ *             Ge van Geldorp <gvg@reactos.org>
+ */
+
+/* INCLUDES *****************************************************************/
+
+#include "inflib.h"
+#include "infhost.h"
+
+#define NDEBUG
+#include <debug.h>
+
+int
+InfHostFindFirstLine(HINF InfHandle,
+                     const WCHAR *Section,
+                     const WCHAR *Key,
+                     PINFCONTEXT *Context)
+{
+  INFSTATUS Status;
+
+  Status = InfpFindFirstLine(InfHandle, Section, Key, Context);
+  if (INF_SUCCESS(Status))
+    {
+      return 0;
+    }
+  else
+    {
+      errno = Status;
+      return -1;
+    }
+}
+
+
+int
+InfHostFindNextLine(PINFCONTEXT ContextIn,
+                    PINFCONTEXT ContextOut)
+{
+  INFSTATUS Status;
+
+  Status = InfpFindNextLine(ContextIn, ContextOut);
+  if (INF_SUCCESS(Status))
+    {
+      return 0;
+    }
+  else
+    {
+      errno = Status;
+      return -1;
+    }
+}
+
+
+int
+InfHostFindFirstMatchLine(PINFCONTEXT ContextIn,
+                          const WCHAR *Key,
+                          PINFCONTEXT ContextOut)
+{
+  INFSTATUS Status;
+
+  Status = InfpFindFirstMatchLine(ContextIn, Key, ContextOut);
+  if (INF_SUCCESS(Status))
+    {
+      return 0;
+    }
+  else
+    {
+      errno = Status;
+      return -1;
+    }
+}
+
+
+int
+InfHostFindNextMatchLine(PINFCONTEXT ContextIn,
+                         const WCHAR *Key,
+                         PINFCONTEXT ContextOut)
+{
+  INFSTATUS Status;
+
+  Status = InfpFindNextMatchLine(ContextIn, Key, ContextOut);
+  if (INF_SUCCESS(Status))
+    {
+      return 0;
+    }
+  else
+    {
+      errno = Status;
+      return -1;
+    }
+}
+
+
+LONG
+InfHostGetLineCount(HINF InfHandle,
+                    PCWSTR Section)
+{
+  return InfpGetLineCount(InfHandle, Section);
+}
+
+
+/* InfGetLineText */
+
+
+LONG
+InfHostGetFieldCount(PINFCONTEXT Context)
+{
+  return InfpGetFieldCount(Context);
+}
+
+
+int
+InfHostGetBinaryField(PINFCONTEXT Context,
+                      ULONG FieldIndex,
+                      UCHAR *ReturnBuffer,
+                      ULONG ReturnBufferSize,
+                      ULONG *RequiredSize)
+{
+  INFSTATUS Status;
+
+  Status = InfpGetBinaryField(Context, FieldIndex, ReturnBuffer,
+                              ReturnBufferSize, RequiredSize);
+  if (INF_SUCCESS(Status))
+    {
+      return 0;
+    }
+  else
+    {
+      errno = Status;
+      return -1;
+    }
+}
+
+
+int
+InfHostGetIntField(PINFCONTEXT Context,
+                   ULONG FieldIndex,
+                   ULONG *IntegerValue)
+{
+  INFSTATUS Status;
+
+  Status = InfpGetIntField(Context, FieldIndex, (PLONG)IntegerValue);
+  if (INF_SUCCESS(Status))
+    {
+      return 0;
+    }
+  else
+    {
+      errno = Status;
+      return -1;
+    }
+}
+
+
+int
+InfHostGetMultiSzField(PINFCONTEXT Context,
+                       ULONG FieldIndex,
+                       WCHAR *ReturnBuffer,
+                       ULONG ReturnBufferSize,
+                       ULONG *RequiredSize)
+{
+  INFSTATUS Status;
+
+  Status = InfpGetMultiSzField(Context, FieldIndex, ReturnBuffer,
+                               ReturnBufferSize, RequiredSize);
+  if (INF_SUCCESS(Status))
+    {
+      return 0;
+    }
+  else
+    {
+      errno = Status;
+      return -1;
+    }
+}
+
+
+int
+InfHostGetStringField(PINFCONTEXT Context,
+                      ULONG FieldIndex,
+                      WCHAR *ReturnBuffer,
+                      ULONG ReturnBufferSize,
+                      ULONG *RequiredSize)
+{
+  INFSTATUS Status;
+
+  Status = InfpGetStringField(Context, FieldIndex, ReturnBuffer,
+                              ReturnBufferSize, RequiredSize);
+  if (INF_SUCCESS(Status))
+    {
+      return 0;
+    }
+  else
+    {
+      errno = Status;
+      return -1;
+    }
+}
+
+
+int
+InfHostGetData(PINFCONTEXT Context,
+               WCHAR **Key,
+               WCHAR **Data)
+{
+  INFSTATUS Status;
+
+  Status = InfpGetData(Context, Key, Data);
+  if (INF_SUCCESS(Status))
+    {
+      return 0;
+    }
+  else
+    {
+      errno = Status;
+      return -1;
+    }
+}
+
+
+int
+InfHostGetDataField(PINFCONTEXT Context,
+                    ULONG FieldIndex,
+                    WCHAR **Data)
+{
+  INFSTATUS Status;
+
+  Status = InfpGetDataField(Context, FieldIndex, Data);
+  if (INF_SUCCESS(Status))
+    {
+      return 0;
+    }
+  else
+    {
+      errno = Status;
+      return -1;
+    }
+}
+
+VOID
+InfHostFreeContext(PINFCONTEXT Context)
+{
+  InfpFreeContext(Context);
+}
+
+/* EOF */
diff --git a/reactos/lib/newinflib/infhostput.c b/reactos/lib/newinflib/infhostput.c
new file mode 100644 (file)
index 0000000..a5233e5
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * PROJECT:    .inf file parser
+ * LICENSE:    GPL - See COPYING in the top level directory
+ * COPYRIGHT:  Copyright 2005 Ge van Geldorp <gvg@reactos.org>
+ */
+
+/* INCLUDES *****************************************************************/
+
+#include "inflib.h"
+#include "infhost.h"
+
+#define NDEBUG
+#include <debug.h>
+
+int
+InfHostWriteFile(HINF InfHandle,
+                 const CHAR *FileName,
+                 const CHAR *HeaderComment)
+{
+  WCHAR *Buffer;
+  ULONG BufferSize;
+  INFSTATUS Status;
+  FILE *File;
+
+  Status = InfpBuildFileBuffer((PINFCACHE) InfHandle, &Buffer, &BufferSize);
+  if (! INF_SUCCESS(Status))
+    {
+      errno = Status;
+      return -1;
+    }
+
+  File = fopen(FileName, "wb");
+  if (NULL == File)
+    {
+      FREE(Buffer);
+      DPRINT1("fopen() failed (errno %d)\n", errno);
+      return -1;
+    }
+
+  DPRINT("fopen() successful\n");
+
+  if (NULL != HeaderComment && '\0' != *HeaderComment)
+    {
+//      fprintf(File, "; %s\r\n\r\n", HeaderComment);
+    }
+
+  if (BufferSize != fwrite(Buffer, (size_t)1, (size_t)BufferSize, File))
+    {
+      DPRINT1("fwrite() failed (errno %d)\n", errno);
+      fclose(File);
+      FREE(Buffer);
+      return -1;
+    }
+
+  fclose(File);
+
+  FREE(Buffer);
+
+  return 0;
+}
+
+int
+InfHostFindOrAddSection(HINF InfHandle,
+                        const WCHAR *Section,
+                        PINFCONTEXT *Context)
+{
+  INFSTATUS Status;
+
+  Status = InfpFindOrAddSection((PINFCACHE) InfHandle, Section, Context);
+  if (INF_SUCCESS(Status))
+    {
+      return 0;
+    }
+  else
+    {
+      errno = Status;
+      return -1;
+    }
+}
+
+int
+InfHostAddLine(PINFCONTEXT Context, const WCHAR *Key)
+{
+  INFSTATUS Status;
+
+  Status = InfpAddLineWithKey(Context, Key);
+  if (INF_SUCCESS(Status))
+    {
+      return 0;
+    }
+  else
+    {
+      errno = Status;
+      return -1;
+    }
+}
+
+int
+InfHostAddField(PINFCONTEXT Context, const WCHAR *Data)
+{
+  INFSTATUS Status;
+
+  Status = InfpAddField(Context, Data);
+  if (INF_SUCCESS(Status))
+    {
+      return 0;
+    }
+  else
+    {
+      errno = Status;
+      return -1;
+    }
+}
+
+/* EOF */
diff --git a/reactos/lib/newinflib/infhostrtl.c b/reactos/lib/newinflib/infhostrtl.c
new file mode 100644 (file)
index 0000000..c9a5221
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * PROJECT:    .inf file parser
+ * LICENSE:    GPL - See COPYING in the top level directory
+ * PROGRAMMER: Royce Mitchell III
+ *             Eric Kohl
+ *             Ge van Geldorp <gvg@reactos.org>
+ */
+
+/* INCLUDES *****************************************************************/
+
+#include "inflib.h"
+#include "infhost.h"
+
+#define NDEBUG
+#include <debug.h>
+
+NTSTATUS NTAPI
+RtlMultiByteToUnicodeN(
+   IN PWCHAR UnicodeString,
+   IN ULONG UnicodeSize,
+   IN PULONG ResultSize,
+   IN PCSTR MbString,
+   IN ULONG MbSize)
+{
+    ULONG Size = 0;
+    ULONG i;
+    PUCHAR WideString;
+
+    /* single-byte code page */
+    if (MbSize > (UnicodeSize / sizeof(WCHAR)))
+        Size = UnicodeSize / sizeof(WCHAR);
+    else
+        Size = MbSize;
+
+    if (ResultSize != NULL)
+        *ResultSize = Size * sizeof(WCHAR);
+
+    WideString = (PUCHAR)UnicodeString;
+    for (i = 0; i <= Size; i++)
+    {
+        WideString[2 * i + 0] = (UCHAR)MbString[i];
+        WideString[2 * i + 1] = 0;
+    }
+
+    return STATUS_SUCCESS;
+}
+
+
+BOOLEAN
+NTAPI
+RtlIsTextUnicode( PVOID buf, INT len, INT *pf )
+{
+    static const WCHAR std_control_chars[] = {'\r','\n','\t',' ',0x3000,0};
+    static const WCHAR byterev_control_chars[] = {0x0d00,0x0a00,0x0900,0x2000,0};
+    const WCHAR *s = buf;
+    int i;
+    unsigned int flags = MAXULONG, out_flags = 0;
+
+    if (len < sizeof(WCHAR))
+    {
+        /* FIXME: MSDN documents IS_TEXT_UNICODE_BUFFER_TOO_SMALL but there is no such thing... */
+        if (pf) *pf = 0;
+        return FALSE;
+    }
+    if (pf)
+        flags = (unsigned int)*pf;
+    /*
+     * Apply various tests to the text string. According to the
+     * docs, each test "passed" sets the corresponding flag in
+     * the output flags. But some of the tests are mutually
+     * exclusive, so I don't see how you could pass all tests ...
+     */
+
+    /* Check for an odd length ... pass if even. */
+    if (len & 1) out_flags |= IS_TEXT_UNICODE_ODD_LENGTH;
+
+    if (((char *)buf)[len - 1] == 0)
+        len--;  /* Windows seems to do something like that to avoid e.g. false IS_TEXT_UNICODE_NULL_BYTES  */
+
+    len /= (INT)sizeof(WCHAR);
+    /* Windows only checks the first 256 characters */
+    if (len > 256) len = 256;
+
+    /* Check for the special byte order unicode marks. */
+    if (*s == 0xFEFF) out_flags |= IS_TEXT_UNICODE_SIGNATURE;
+    if (*s == 0xFFFE) out_flags |= IS_TEXT_UNICODE_REVERSE_SIGNATURE;
+
+    /* apply some statistical analysis */
+    if (flags & IS_TEXT_UNICODE_STATISTICS)
+    {
+        int stats = 0;
+        /* FIXME: checks only for ASCII characters in the unicode stream */
+        for (i = 0; i < len; i++)
+        {
+            if (s[i] <= 255) stats++;
+        }
+        if (stats > len / 2)
+            out_flags |= IS_TEXT_UNICODE_STATISTICS;
+    }
+
+    /* Check for unicode NULL chars */
+    if (flags & IS_TEXT_UNICODE_NULL_BYTES)
+    {
+        for (i = 0; i < len; i++)
+        {
+            if (!(s[i] & 0xff) || !(s[i] >> 8))
+            {
+                out_flags |= IS_TEXT_UNICODE_NULL_BYTES;
+                break;
+            }
+        }
+    }
+
+    if (flags & IS_TEXT_UNICODE_CONTROLS)
+    {
+        for (i = 0; i < len; i++)
+        {
+            if (wcschr(std_control_chars, s[i]))
+            {
+                out_flags |= IS_TEXT_UNICODE_CONTROLS;
+                break;
+            }
+        }
+    }
+
+    if (flags & IS_TEXT_UNICODE_REVERSE_CONTROLS)
+    {
+        for (i = 0; i < len; i++)
+        {
+            if (wcschr(byterev_control_chars, s[i]))
+            {
+                out_flags |= IS_TEXT_UNICODE_REVERSE_CONTROLS;
+                break;
+            }
+        }
+    }
+
+    if (pf)
+    {
+        out_flags &= (unsigned int)*pf;
+        *pf = (INT)out_flags;
+    }
+    /* check for flags that indicate it's definitely not valid Unicode */
+    if (out_flags & (IS_TEXT_UNICODE_REVERSE_MASK | IS_TEXT_UNICODE_NOT_UNICODE_MASK)) return FALSE;
+    /* now check for invalid ASCII, and assume Unicode if so */
+    if (out_flags & IS_TEXT_UNICODE_NOT_ASCII_MASK) return TRUE;
+    /* now check for Unicode flags */
+    if (out_flags & IS_TEXT_UNICODE_UNICODE_MASK) return TRUE;
+    /* no flags set */
+    return FALSE;
+}
diff --git a/reactos/lib/newinflib/inflib.h b/reactos/lib/newinflib/inflib.h
new file mode 100644 (file)
index 0000000..7dff17f
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * PROJECT:    .inf file parser
+ * LICENSE:    GPL - See COPYING in the top level directory
+ * COPYRIGHT:  Copyright 2005 Ge van Geldorp <gvg@reactos.org>
+ */
+
+#include <ctype.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+#include "builddep.h"
+#include "infcommon.h"
+#include "infpriv.h"
+
+/* EOF */
diff --git a/reactos/lib/newinflib/inflib.mak b/reactos/lib/newinflib/inflib.mak
new file mode 100644 (file)
index 0000000..a0edbe2
--- /dev/null
@@ -0,0 +1,76 @@
+INFLIB_BASE = $(LIB_BASE_)newinflib
+INFLIB_BASE_ = $(INFLIB_BASE)$(SEP)
+INFLIB_INT = $(INTERMEDIATE_)$(INFLIB_BASE)_host
+INFLIB_INT_ = $(INTERMEDIATE_)$(INFLIB_BASE)_host$(SEP)
+INFLIB_OUT = $(OUTPUT_)$(INFLIB_BASE)_host
+INFLIB_OUT_ = $(OUTPUT_)$(INFLIB_BASE)_host$(SEP)
+
+$(INFLIB_INT): | $(LIB_INT)
+       $(ECHO_MKDIR)
+       ${mkdir} $@
+
+ifneq ($(INTERMEDIATE),$(OUTPUT))
+$(INFLIB_OUT): | $(OUTPUT_)$(LIB_BASE)
+       $(ECHO_MKDIR)
+       ${mkdir} $@
+endif
+
+INFLIB_HOST_TARGET = \
+       $(INFLIB_OUT)$(SEP)newinflib.a
+
+INFLIB_HOST_SOURCES = $(addprefix $(INFLIB_BASE_), \
+       infcore.c \
+       infget.c \
+       infput.c \
+       infhostgen.c \
+       infhostget.c \
+       infhostput.c \
+       infhostrtl.c \
+       )
+
+INFLIB_HOST_OBJECTS = \
+       $(subst $(INFLIB_BASE), $(INFLIB_INT), $(INFLIB_HOST_SOURCES:.c=.o))
+
+INFLIB_HOST_CFLAGS = -O3 -Wall -Wpointer-arith -Wconversion \
+  -Wstrict-prototypes -Wmissing-prototypes -DINFLIB_HOST \
+  -Iinclude/reactos -Iinclude $(HOST_CFLAGS)
+
+$(INFLIB_HOST_TARGET): $(INFLIB_HOST_OBJECTS) | $(INFLIB_OUT)
+       $(ECHO_HOSTAR)
+       $(host_ar) -r $@ $(INFLIB_HOST_OBJECTS)
+
+$(INFLIB_INT_)infcore.o: $(INFLIB_BASE_)infcore.c | $(INFLIB_INT)
+       $(ECHO_HOSTCC)
+       ${host_gcc} $(INFLIB_HOST_CFLAGS) -c $< -o $@
+
+$(INFLIB_INT_)infget.o: $(INFLIB_BASE_)infget.c | $(INFLIB_INT)
+       $(ECHO_HOSTCC)
+       ${host_gcc} $(INFLIB_HOST_CFLAGS) -c $< -o $@
+
+$(INFLIB_INT_)infput.o: $(INFLIB_BASE_)infput.c | $(INFLIB_INT)
+       $(ECHO_HOSTCC)
+       ${host_gcc} $(INFLIB_HOST_CFLAGS) -c $< -o $@
+
+$(INFLIB_INT_)infhostgen.o: $(INFLIB_BASE_)infhostgen.c | $(INFLIB_INT)
+       $(ECHO_HOSTCC)
+       ${host_gcc} $(INFLIB_HOST_CFLAGS) -c $< -o $@
+
+$(INFLIB_INT_)infhostget.o: $(INFLIB_BASE_)infhostget.c | $(INFLIB_INT)
+       $(ECHO_HOSTCC)
+       ${host_gcc} $(INFLIB_HOST_CFLAGS) -c $< -o $@
+
+$(INFLIB_INT_)infhostput.o: $(INFLIB_BASE_)infhostput.c | $(INFLIB_INT)
+       $(ECHO_HOSTCC)
+       ${host_gcc} $(INFLIB_HOST_CFLAGS) -c $< -o $@
+
+$(INFLIB_INT_)infhostrtl.o: $(INFLIB_BASE_)infhostrtl.c | $(INFLIB_INT)
+       $(ECHO_HOSTCC)
+       ${host_gcc} $(INFLIB_HOST_CFLAGS) -c $< -o $@
+
+.PHONY: newinflib_host
+newinflib_host: $(INFLIB_HOST_TARGET)
+
+.PHONY: newinflib_host_clean
+newinflib_host_clean:
+       -@$(rm) $(INFLIB_HOST_TARGET) $(INFLIB_HOST_OBJECTS) 2>$(NUL)
+clean: newinflib_host_clean
diff --git a/reactos/lib/newinflib/inflib.rbuild b/reactos/lib/newinflib/inflib.rbuild
new file mode 100644 (file)
index 0000000..fc7c2cd
--- /dev/null
@@ -0,0 +1,31 @@
+<?xml version="1.0"?>
+<!DOCTYPE module SYSTEM "../../tools/rbuild/project.dtd">
+<group>
+<module name="newinflib" type="staticlibrary">
+       <include base="newinflib">.</include>
+       <file>infcore.c</file>
+       <file>infget.c</file>
+       <file>infput.c</file>
+       <file>infrosgen.c</file>
+       <file>infrosget.c</file>
+       <file>infrosput.c</file>
+</module>
+<module name="newinflibhost" type="hoststaticlibrary" allowwarnings="true">
+       <include base="newinflibhost">.</include>
+       <define name="__NO_CTYPE_INLINES" />
+       <group compilerset="gcc">
+               <compilerflag>-Wpointer-arith</compilerflag>
+               <compilerflag>-Wconversion</compilerflag>
+               <compilerflag>-Wstrict-prototypes</compilerflag>
+               <compilerflag>-Wmissing-prototypes</compilerflag>
+       </group>
+       <define name="INFLIB_HOST" />
+       <file>infcore.c</file>
+       <file>infget.c</file>
+       <file>infput.c</file>
+       <file>infhostgen.c</file>
+       <file>infhostget.c</file>
+       <file>infhostput.c</file>
+       <file>infhostrtl.c</file>
+</module>
+</group>
diff --git a/reactos/lib/newinflib/infpriv.h b/reactos/lib/newinflib/infpriv.h
new file mode 100644 (file)
index 0000000..0d2cea9
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * PROJECT:    .inf file parser
+ * LICENSE:    GPL - See COPYING in the top level directory
+ * PROGRAMMER: Royce Mitchell III
+ *             Eric Kohl
+ *             Ge van Geldorp <gvg@reactos.org>
+ */
+
+#pragma once
+
+#ifndef FIELD_OFFSET
+#define FIELD_OFFSET(t,f) ((ptrdiff_t)&(((t*)0)->f))
+#endif
+
+#define INF_STATUS_INSUFFICIENT_RESOURCES  ((INFSTATUS)0xC000009A)
+#define INF_STATUS_BAD_SECTION_NAME_LINE   ((INFSTATUS)0xC0700001)
+#define INF_STATUS_SECTION_NAME_TOO_LONG   ((INFSTATUS)0xC0700002)
+#define INF_STATUS_WRONG_INF_STYLE         ((INFSTATUS)0xC0700003)
+#define INF_STATUS_NOT_ENOUGH_MEMORY       ((INFSTATUS)0xC0700004)
+
+typedef struct _INFCACHEFIELD
+{
+  struct _INFCACHEFIELD *Next;
+  struct _INFCACHEFIELD *Prev;
+
+  WCHAR Data[1];
+} INFCACHEFIELD, *PINFCACHEFIELD;
+
+typedef struct _INFCACHELINE
+{
+  struct _INFCACHELINE *Next;
+  struct _INFCACHELINE *Prev;
+
+  LONG FieldCount;
+
+  PWCHAR Key;
+
+  PINFCACHEFIELD FirstField;
+  PINFCACHEFIELD LastField;
+
+} INFCACHELINE, *PINFCACHELINE;
+
+typedef struct _INFCACHESECTION
+{
+  struct _INFCACHESECTION *Next;
+  struct _INFCACHESECTION *Prev;
+
+  PINFCACHELINE FirstLine;
+  PINFCACHELINE LastLine;
+
+  LONG LineCount;
+
+  WCHAR Name[1];
+} INFCACHESECTION, *PINFCACHESECTION;
+
+typedef struct _INFCACHE
+{
+  LCID LocaleId;
+  PINFCACHESECTION FirstSection;
+  PINFCACHESECTION LastSection;
+
+  PINFCACHESECTION StringsSection;
+} INFCACHE, *PINFCACHE;
+
+typedef struct _INFCONTEXT
+{
+  PINFCACHE Inf;
+  PINFCACHESECTION Section;
+  PINFCACHELINE Line;
+} INFCONTEXT;
+
+typedef int INFSTATUS;
+
+/* FUNCTIONS ****************************************************************/
+
+extern INFSTATUS InfpParseBuffer(PINFCACHE file,
+                                 const WCHAR *buffer,
+                                 const WCHAR *end,
+                                 PULONG error_line);
+extern PINFCACHESECTION InfpFreeSection(PINFCACHESECTION Section);
+extern PINFCACHESECTION InfpAddSection(PINFCACHE Cache,
+                                       PCWSTR Name);
+extern PINFCACHELINE InfpAddLine(PINFCACHESECTION Section);
+extern PVOID InfpAddKeyToLine(PINFCACHELINE Line,
+                              PCWSTR Key);
+extern PVOID InfpAddFieldToLine(PINFCACHELINE Line,
+                                PCWSTR Data);
+extern PINFCACHELINE InfpFindKeyLine(PINFCACHESECTION Section,
+                                     PCWSTR Key);
+extern PINFCACHESECTION InfpFindSection(PINFCACHE Cache,
+                                        PCWSTR Section);
+
+extern INFSTATUS InfpBuildFileBuffer(PINFCACHE InfHandle,
+                                     PWCHAR *Buffer,
+                                     PULONG BufferSize);
+
+extern INFSTATUS InfpFindFirstLine(PINFCACHE InfHandle,
+                                   PCWSTR Section,
+                                   PCWSTR Key,
+                                   PINFCONTEXT *Context);
+extern INFSTATUS InfpFindNextLine(PINFCONTEXT ContextIn,
+                                  PINFCONTEXT ContextOut);
+extern INFSTATUS InfpFindFirstMatchLine(PINFCONTEXT ContextIn,
+                                        PCWSTR Key,
+                                        PINFCONTEXT ContextOut);
+extern INFSTATUS InfpFindNextMatchLine(PINFCONTEXT ContextIn,
+                                       PCWSTR Key,
+                                       PINFCONTEXT ContextOut);
+extern LONG InfpGetLineCount(HINF InfHandle,
+                             PCWSTR Section);
+extern LONG InfpGetFieldCount(PINFCONTEXT Context);
+extern INFSTATUS InfpGetBinaryField(PINFCONTEXT Context,
+                                    ULONG FieldIndex,
+                                    PUCHAR ReturnBuffer,
+                                    ULONG ReturnBufferSize,
+                                    PULONG RequiredSize);
+extern INFSTATUS InfpGetIntField(PINFCONTEXT Context,
+                                 ULONG FieldIndex,
+                                 PLONG IntegerValue);
+extern INFSTATUS InfpGetMultiSzField(PINFCONTEXT Context,
+                                     ULONG FieldIndex,
+                                     PWSTR ReturnBuffer,
+                                     ULONG ReturnBufferSize,
+                                     PULONG RequiredSize);
+extern INFSTATUS InfpGetStringField(PINFCONTEXT Context,
+                                    ULONG FieldIndex,
+                                    PWSTR ReturnBuffer,
+                                    ULONG ReturnBufferSize,
+                                    PULONG RequiredSize);
+extern INFSTATUS InfpGetData(PINFCONTEXT Context,
+                             PWCHAR *Key,
+                             PWCHAR *Data);
+extern INFSTATUS InfpGetDataField(PINFCONTEXT Context,
+                                  ULONG FieldIndex,
+                                  PWCHAR *Data);
+
+extern INFSTATUS InfpFindOrAddSection(PINFCACHE Cache,
+                                      PCWSTR Section,
+                                      PINFCONTEXT *Context);
+extern INFSTATUS InfpAddLineWithKey(PINFCONTEXT Context, PCWSTR Key);
+extern INFSTATUS InfpAddField(PINFCONTEXT Context, PCWSTR Data);
+
+extern VOID InfpFreeContext(PINFCONTEXT Context);
+
+/* EOF */
diff --git a/reactos/lib/newinflib/infput.c b/reactos/lib/newinflib/infput.c
new file mode 100644 (file)
index 0000000..2d60af0
--- /dev/null
@@ -0,0 +1,264 @@
+/*
+ * PROJECT:    .inf file parser
+ * LICENSE:    GPL - See COPYING in the top level directory
+ * COPYRIGHT:  Copyright 2005 Ge van Geldorp <gvg@reactos.org>
+ */
+
+/* INCLUDES *****************************************************************/
+
+#include "inflib.h"
+
+#define NDEBUG
+#include <debug.h>
+
+#define EOL      L"\r\n"
+#define SIZE_INC 1024
+
+typedef struct _OUTPUTBUFFER
+{
+  PWCHAR Buffer;
+  PWCHAR Current;
+  ULONG TotalSize;
+  ULONG FreeSize;
+  INFSTATUS Status;
+} OUTPUTBUFFER, *POUTPUTBUFFER;
+
+static void
+Output(POUTPUTBUFFER OutBuf, PCWSTR Text)
+{
+  ULONG Length;
+  PWCHAR NewBuf;
+  ULONG NewSize;
+
+  /* Skip mode? */
+  if (! INF_SUCCESS(OutBuf->Status))
+    {
+      return;
+    }
+
+  /* Doesn't fit? */
+  Length = (ULONG)wcslen(Text) * sizeof(WCHAR);
+  if (OutBuf->FreeSize < Length + 1 && INF_SUCCESS(OutBuf->Status))
+    {
+      DPRINT("Out of free space. TotalSize %u FreeSize %u Length %u\n",
+             (UINT)OutBuf->TotalSize, (UINT)OutBuf->FreeSize, (UINT)Length);
+      /* Round up to next SIZE_INC */
+      NewSize = OutBuf->TotalSize +
+                (((Length + 1) - OutBuf->FreeSize + (SIZE_INC - 1)) /
+                 SIZE_INC) * SIZE_INC;
+      DPRINT("NewSize %u\n", (UINT)NewSize);
+      NewBuf = MALLOC(NewSize);
+      /* Abort if failed */
+      if (NULL == NewBuf)
+        {
+          DPRINT1("MALLOC() failed\n");
+          OutBuf->Status = INF_STATUS_NO_MEMORY;
+          return;
+        }
+      
+      /* Need to copy old contents? */
+      if (NULL != OutBuf->Buffer)
+        {
+          DPRINT("Copying %u bytes from old content\n",
+                 (UINT)(OutBuf->TotalSize - OutBuf->FreeSize));
+          MEMCPY(NewBuf, OutBuf->Buffer, OutBuf->TotalSize - OutBuf->FreeSize);
+          OutBuf->Current = NewBuf + (OutBuf->Current - OutBuf->Buffer);
+          FREE(OutBuf->Buffer);
+        }
+      else
+        {
+          OutBuf->Current = NewBuf;
+        }
+      OutBuf->Buffer = NewBuf;
+      OutBuf->FreeSize += NewSize - OutBuf->TotalSize;
+      OutBuf->TotalSize = NewSize;
+      DPRINT("After reallocation TotalSize %u FreeSize %u\n",
+             (UINT)OutBuf->TotalSize, (UINT)OutBuf->FreeSize);
+    }
+
+  /* We're guaranteed to have enough room now. Copy char by char because of
+     possible "conversion" from Unicode to Ansi */
+  while (Length--)
+    {
+      *OutBuf->Current++ = *Text++;
+      OutBuf->FreeSize--;
+    }
+  *OutBuf->Current = '\0';
+}
+
+INFSTATUS
+InfpBuildFileBuffer(PINFCACHE Cache,
+                    PWCHAR *Buffer,
+                    PULONG BufferSize)
+{
+  OUTPUTBUFFER OutBuf;
+  PINFCACHESECTION CacheSection;
+  PINFCACHELINE CacheLine;
+  PINFCACHEFIELD CacheField;
+  PWCHAR p;
+  BOOLEAN NeedQuotes;
+
+  OutBuf.Buffer = NULL;
+  OutBuf.Current = NULL;
+  OutBuf.FreeSize = 0;
+  OutBuf.TotalSize = 0;
+  OutBuf.Status = INF_STATUS_SUCCESS;
+
+  /* Iterate through list of sections */
+  CacheSection = Cache->FirstSection;
+  while (CacheSection != NULL)
+    {
+      DPRINT("Processing section %S\n", CacheSection->Name);
+      if (CacheSection != Cache->FirstSection)
+        {
+          Output(&OutBuf, EOL);
+        }
+      Output(&OutBuf, L"[");
+      Output(&OutBuf, CacheSection->Name);
+      Output(&OutBuf, L"]");
+      Output(&OutBuf, EOL);
+
+      /* Iterate through list of lines */
+      CacheLine = CacheSection->FirstLine;
+      while (CacheLine != NULL)
+        {
+          if (NULL != CacheLine->Key)
+            {
+              DPRINT("Line with key %S\n", CacheLine->Key);
+              Output(&OutBuf, CacheLine->Key);
+              Output(&OutBuf, L" = ");
+            }
+          else
+            {
+              DPRINT("Line without key\n");
+            }
+
+          /* Iterate through list of lines */
+          CacheField = CacheLine->FirstField;
+          while (CacheField != NULL)
+            {
+              if (CacheField != CacheLine->FirstField)
+                {
+                  Output(&OutBuf, L",");
+                }
+              p = CacheField->Data;
+              NeedQuotes = FALSE;
+              while (L'\0' != *p && ! NeedQuotes)
+                {
+                  NeedQuotes = (BOOLEAN)(L',' == *p || L';' == *p ||
+                                         L'\\' == *p);
+                  p++;
+                }
+              if (NeedQuotes)
+                {
+                  Output(&OutBuf, L"\"");
+                  Output(&OutBuf, CacheField->Data);
+                  Output(&OutBuf, L"\"");
+                }
+              else
+                {
+                  Output(&OutBuf, CacheField->Data);
+                }
+
+              /* Get the next field */
+              CacheField = CacheField->Next;
+            }
+
+          Output(&OutBuf, EOL);
+          /* Get the next line */
+          CacheLine = CacheLine->Next;
+        }
+
+      /* Get the next section */
+      CacheSection = CacheSection->Next;
+    }
+
+  if (INF_SUCCESS(OutBuf.Status))
+    {
+      *Buffer = OutBuf.Buffer;
+      *BufferSize = OutBuf.TotalSize - OutBuf.FreeSize;
+    }
+  else if (NULL != OutBuf.Buffer)
+    {
+      FREE(OutBuf.Buffer);
+    }
+
+  return INF_STATUS_SUCCESS;
+}
+
+INFSTATUS
+InfpFindOrAddSection(PINFCACHE Cache,
+                     PCWSTR Section,
+                     PINFCONTEXT *Context)
+{
+  DPRINT("InfpFindOrAddSection section %S\n", Section);
+
+  *Context = MALLOC(sizeof(INFCONTEXT));
+  if (NULL == *Context)
+    {
+      DPRINT1("MALLOC() failed\n");
+      return INF_STATUS_NO_MEMORY;
+    }
+
+  (*Context)->Inf = Cache;
+  (*Context)->Section = InfpFindSection(Cache, Section);
+  (*Context)->Line = NULL;
+  if (NULL == (*Context)->Section)
+    {
+      DPRINT("Section not found, creating it\n");
+      (*Context)->Section = InfpAddSection(Cache, Section);
+      if (NULL == (*Context)->Section)
+        {
+          DPRINT("Failed to create section\n");
+          FREE(*Context);
+          return INF_STATUS_NO_MEMORY;
+        }
+    }
+
+  return INF_STATUS_SUCCESS;
+}
+
+INFSTATUS
+InfpAddLineWithKey(PINFCONTEXT Context, PCWSTR Key)
+{
+  if (NULL == Context)
+    {
+      DPRINT1("Invalid parameter\n");
+      return INF_STATUS_INVALID_PARAMETER;
+    }
+
+  Context->Line = InfpAddLine(Context->Section);
+  if (NULL == Context->Line)
+    {
+      DPRINT("Failed to create line\n");
+      return INF_STATUS_NO_MEMORY;
+    }
+
+  if (NULL != Key && NULL == InfpAddKeyToLine(Context->Line, Key))
+    {
+      DPRINT("Failed to add key\n");
+      return INF_STATUS_NO_MEMORY;
+    }
+
+  return INF_STATUS_SUCCESS;
+}
+
+INFSTATUS
+InfpAddField(PINFCONTEXT Context, PCWSTR Data)
+{
+  if (NULL == Context || NULL == Context->Line)
+    {
+      DPRINT1("Invalid parameter\n");
+      return INF_STATUS_INVALID_PARAMETER;
+    }
+
+  if (NULL == InfpAddFieldToLine(Context->Line, Data))
+    {
+      DPRINT("Failed to add field\n");
+      return INF_STATUS_NO_MEMORY;
+    }
+
+  return INF_STATUS_SUCCESS;
+}
+
+/* EOF */
diff --git a/reactos/lib/newinflib/infros.h b/reactos/lib/newinflib/infros.h
new file mode 100644 (file)
index 0000000..c467af9
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * PROJECT:    .inf file parser
+ * LICENSE:    GPL - See COPYING in the top level directory
+ * PROGRAMMER: Royce Mitchell III
+ *             Eric Kohl
+ *             Ge van Geldorp <gvg@reactos.org>
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#include <infcommon.h>
+
+extern VOID InfSetHeap(PVOID Heap);
+extern NTSTATUS InfOpenBufferedFile(PHINF InfHandle,
+                                    PVOID Buffer,
+                                    ULONG BufferSize,
+                                    LCID LocaleId,
+                                    PULONG ErrorLine);
+extern NTSTATUS InfOpenFile(PHINF InfHandle,
+                            PUNICODE_STRING FileName,
+                            LCID LocaleId,
+                            PULONG ErrorLine);
+extern NTSTATUS InfWriteFile(HINF InfHandle,
+                             PUNICODE_STRING FileName,
+                             PUNICODE_STRING HeaderComment);
+extern VOID InfCloseFile(HINF InfHandle);
+extern BOOLEAN InfFindFirstLine(HINF InfHandle,
+                                PCWSTR Section,
+                                PCWSTR Key,
+                                PINFCONTEXT *Context);
+extern BOOLEAN InfFindNextLine(PINFCONTEXT ContextIn,
+                               PINFCONTEXT ContextOut);
+extern BOOLEAN InfFindFirstMatchLine(PINFCONTEXT ContextIn,
+                                     PCWSTR Key,
+                                     PINFCONTEXT ContextOut);
+extern BOOLEAN InfFindNextMatchLine(PINFCONTEXT ContextIn,
+                                    PCWSTR Key,
+                                    PINFCONTEXT ContextOut);
+extern LONG InfGetLineCount(HINF InfHandle,
+                            PCWSTR Section);
+extern LONG InfGetFieldCount(PINFCONTEXT Context);
+extern BOOLEAN InfGetBinaryField(PINFCONTEXT Context,
+                                 ULONG FieldIndex,
+                                 PUCHAR ReturnBuffer,
+                                 ULONG ReturnBufferSize,
+                                 PULONG RequiredSize);
+extern BOOLEAN InfGetIntField(PINFCONTEXT Context,
+                              ULONG FieldIndex,
+                              PLONG IntegerValue);
+extern BOOLEAN InfGetMultiSzField(PINFCONTEXT Context,
+                                  ULONG FieldIndex,
+                                  PWSTR ReturnBuffer,
+                                  ULONG ReturnBufferSize,
+                                  PULONG RequiredSize);
+extern BOOLEAN InfGetStringField(PINFCONTEXT Context,
+                                 ULONG FieldIndex,
+                                 PWSTR ReturnBuffer,
+                                 ULONG ReturnBufferSize,
+                                 PULONG RequiredSize);
+extern BOOLEAN InfGetData(PINFCONTEXT Context,
+                          PWCHAR *Key,
+                          PWCHAR *Data);
+extern BOOLEAN InfGetDataField(PINFCONTEXT Context,
+                               ULONG FieldIndex,
+                               PWCHAR *Data);
+extern BOOLEAN InfFindOrAddSection(HINF InfHandle,
+                                   PCWSTR Section,
+                                   PINFCONTEXT *Context);
+extern BOOLEAN InfAddLine(PINFCONTEXT Context, PCWSTR Key);
+extern BOOLEAN InfAddField(PINFCONTEXT Context, PCWSTR Data);
+extern VOID InfFreeContext(PINFCONTEXT Context);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+/* EOF */
diff --git a/reactos/lib/newinflib/infrosgen.c b/reactos/lib/newinflib/infrosgen.c
new file mode 100644 (file)
index 0000000..8ea53ae
--- /dev/null
@@ -0,0 +1,370 @@
+/*
+ * PROJECT:    .inf file parser
+ * LICENSE:    GPL - See COPYING in the top level directory
+ * PROGRAMMER: Royce Mitchell III
+ *             Eric Kohl
+ *             Ge van Geldorp <gvg@reactos.org>
+ */
+
+/* INCLUDES *****************************************************************/
+
+#include "inflib.h"
+#include "infros.h"
+
+#define NDEBUG
+#include <debug.h>
+
+/* PRIVATE FUNCTIONS ********************************************************/
+
+static int InfpHeapRefCount;
+
+static VOID
+CheckHeap()
+{
+  if (NULL == InfpHeap)
+    {
+      InfpHeap = RtlCreateHeap(HEAP_GROWABLE, NULL, 0, 0, NULL, NULL);
+    }
+  if (0 <= InfpHeapRefCount)
+    {
+      InfpHeapRefCount++;
+    }
+}
+
+
+/* PUBLIC FUNCTIONS *********************************************************/
+
+PVOID InfpHeap;
+
+VOID
+InfSetHeap(PVOID Heap)
+{
+  if (NULL == InfpHeap)
+    {
+      InfpHeap = Heap;
+      InfpHeapRefCount = -1;
+    }
+}
+
+
+NTSTATUS
+InfOpenBufferedFile(PHINF InfHandle,
+                    PVOID Buffer,
+                    ULONG BufferSize,
+                    LCID LocaleId,
+                    PULONG ErrorLine)
+{
+  INFSTATUS Status;
+  PINFCACHE Cache;
+  PCHAR FileBuffer;
+  ULONG FileBufferSize;
+
+  CheckHeap();
+
+  *InfHandle = NULL;
+  *ErrorLine = (ULONG)-1;
+
+  /* Allocate file buffer */
+  FileBufferSize = BufferSize + 2;
+  FileBuffer = MALLOC(FileBufferSize);
+  if (FileBuffer == NULL)
+    {
+      DPRINT1("MALLOC() failed\n");
+      return(INF_STATUS_INSUFFICIENT_RESOURCES);
+    }
+
+  MEMCPY(FileBuffer, Buffer, BufferSize);
+
+  /* Append string terminator */
+  FileBuffer[BufferSize] = 0;
+  FileBuffer[BufferSize + 1] = 0;
+
+  /* Allocate infcache header */
+  Cache = (PINFCACHE)MALLOC(sizeof(INFCACHE));
+  if (Cache == NULL)
+    {
+      DPRINT("MALLOC() failed\n");
+      FREE(FileBuffer);
+      return(INF_STATUS_INSUFFICIENT_RESOURCES);
+    }
+
+  /* Initialize inicache header */
+  ZEROMEMORY(Cache,
+             sizeof(INFCACHE));
+
+    Cache->LocaleId = LocaleId;
+
+    if (!RtlIsTextUnicode(FileBuffer, FileBufferSize, NULL))
+    {
+//        static const BYTE utf8_bom[3] = { 0xef, 0xbb, 0xbf };
+        WCHAR *new_buff;
+//        UINT codepage = CP_ACP;
+        UINT offset = 0;
+
+//        if (BufferSize > sizeof(utf8_bom) && !memcmp(FileBuffer, utf8_bom, sizeof(utf8_bom) ))
+//        {
+//            codepage = CP_UTF8;
+//            offset = sizeof(utf8_bom);
+//        }
+
+        new_buff = MALLOC(FileBufferSize * sizeof(WCHAR));
+        if (new_buff != NULL)
+        {
+//            DWORD len = MultiByteToWideChar( codepage, 0, (char *)FileBuffer + offset,
+//                                             FileBufferSize - offset, new_buff, FileBufferSize);
+
+            ULONG len;
+            Status = RtlMultiByteToUnicodeN(new_buff,
+                                            FileBufferSize * sizeof(WCHAR),
+                                            &len,
+                                            (char *)FileBuffer + offset,
+                                            FileBufferSize - offset);
+
+            Status = InfpParseBuffer(Cache,
+                                     new_buff,
+                                     new_buff + len,
+                                     ErrorLine);
+            FREE(new_buff);
+        }
+        else
+            Status = INF_STATUS_INSUFFICIENT_RESOURCES;
+    }
+    else
+    {
+        WCHAR *new_buff = (WCHAR *)FileBuffer;
+        /* UCS-16 files should start with the Unicode BOM; we should skip it */
+        if (*new_buff == 0xfeff)
+        {
+            new_buff++;
+            FileBufferSize -= sizeof(WCHAR);
+        }
+        Status = InfpParseBuffer(Cache,
+                                 new_buff,
+                                 (WCHAR*)((char*)new_buff + FileBufferSize),
+                                 ErrorLine);
+    }
+
+  if (!INF_SUCCESS(Status))
+    {
+      FREE(Cache);
+      Cache = NULL;
+    }
+
+  /* Free file buffer */
+  FREE(FileBuffer);
+
+  *InfHandle = (HINF)Cache;
+
+  return(Status);
+}
+
+
+NTSTATUS
+InfOpenFile(PHINF InfHandle,
+           PUNICODE_STRING FileName,
+           LCID LocaleId,
+           PULONG ErrorLine)
+{
+  OBJECT_ATTRIBUTES ObjectAttributes;
+  FILE_STANDARD_INFORMATION FileInfo;
+  IO_STATUS_BLOCK IoStatusBlock;
+  HANDLE FileHandle;
+  NTSTATUS Status;
+  PCHAR FileBuffer;
+  ULONG FileLength;
+  ULONG FileBufferLength;
+  LARGE_INTEGER FileOffset;
+  PINFCACHE Cache;
+
+  CheckHeap();
+
+  *InfHandle = NULL;
+  *ErrorLine = (ULONG)-1;
+
+  /* Open the inf file */
+  InitializeObjectAttributes(&ObjectAttributes,
+                            FileName,
+                            0,
+                            NULL,
+                            NULL);
+
+  Status = NtOpenFile(&FileHandle,
+                     GENERIC_READ | SYNCHRONIZE,
+                     &ObjectAttributes,
+                     &IoStatusBlock,
+                     FILE_SHARE_READ,
+                     FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE);
+  if (!INF_SUCCESS(Status))
+    {
+      DPRINT("NtOpenFile() failed (Status %lx)\n", Status);
+      return(Status);
+    }
+
+  DPRINT("NtOpenFile() successful\n");
+
+  /* Query file size */
+  Status = NtQueryInformationFile(FileHandle,
+                                 &IoStatusBlock,
+                                 &FileInfo,
+                                 sizeof(FILE_STANDARD_INFORMATION),
+                                 FileStandardInformation);
+  if (!INF_SUCCESS(Status))
+    {
+      DPRINT("NtQueryInformationFile() failed (Status %lx)\n", Status);
+      NtClose(FileHandle);
+      return(Status);
+    }
+
+  FileLength = FileInfo.EndOfFile.u.LowPart;
+
+  DPRINT("File size: %lu\n", FileLength);
+
+  /* Allocate file buffer */
+  FileBufferLength = FileLength + 2;
+  FileBuffer = MALLOC(FileBufferLength);
+  if (FileBuffer == NULL)
+    {
+      DPRINT1("MALLOC() failed\n");
+      NtClose(FileHandle);
+      return(INF_STATUS_INSUFFICIENT_RESOURCES);
+    }
+
+  /* Read file */
+  FileOffset.QuadPart = 0ULL;
+  Status = NtReadFile(FileHandle,
+                     NULL,
+                     NULL,
+                     NULL,
+                     &IoStatusBlock,
+                     FileBuffer,
+                     FileLength,
+                     &FileOffset,
+                     NULL);
+
+  /* Append string terminator */
+  FileBuffer[FileLength] = 0;
+  FileBuffer[FileLength + 1] = 0;
+
+  NtClose(FileHandle);
+
+  if (!INF_SUCCESS(Status))
+    {
+      DPRINT("NtReadFile() failed (Status %lx)\n", Status);
+      FREE(FileBuffer);
+      return(Status);
+    }
+
+  /* Allocate infcache header */
+  Cache = (PINFCACHE)MALLOC(sizeof(INFCACHE));
+  if (Cache == NULL)
+    {
+      DPRINT("MALLOC() failed\n");
+      FREE(FileBuffer);
+      return(INF_STATUS_INSUFFICIENT_RESOURCES);
+    }
+
+  /* Initialize inicache header */
+  ZEROMEMORY(Cache,
+             sizeof(INFCACHE));
+
+    Cache->LocaleId = LocaleId;
+
+    /* Parse the inf buffer */
+    if (!RtlIsTextUnicode(FileBuffer, FileBufferLength, NULL))
+    {
+//        static const BYTE utf8_bom[3] = { 0xef, 0xbb, 0xbf };
+        WCHAR *new_buff;
+//        UINT codepage = CP_ACP;
+        UINT offset = 0;
+
+//        if (FileLength > sizeof(utf8_bom) && !memcmp(FileBuffer, utf8_bom, sizeof(utf8_bom) ))
+//        {
+//            codepage = CP_UTF8;
+//            offset = sizeof(utf8_bom);
+//        }
+
+        new_buff = MALLOC(FileBufferLength * sizeof(WCHAR));
+        if (new_buff != NULL)
+        {
+//            DWORD len = MultiByteToWideChar( codepage, 0, (char *)FileBuffer + offset,
+//                                             FileLength - offset, new_buff, FileLength);
+
+            ULONG len;
+            Status = RtlMultiByteToUnicodeN(new_buff,
+                                            FileBufferLength * sizeof(WCHAR),
+                                            &len,
+                                            (char *)FileBuffer + offset,
+                                            FileBufferLength - offset);
+
+            Status = InfpParseBuffer(Cache,
+                                     new_buff,
+                                     new_buff + len,
+                                     ErrorLine);
+            FREE(new_buff);
+        }
+        else
+            Status = INF_STATUS_INSUFFICIENT_RESOURCES;
+    }
+    else
+    {
+        WCHAR *new_buff = (WCHAR *)FileBuffer;
+        /* UCS-16 files should start with the Unicode BOM; we should skip it */
+        if (*new_buff == 0xfeff)
+        {
+            new_buff++;
+            FileBufferLength -= sizeof(WCHAR);
+        }
+        Status = InfpParseBuffer(Cache,
+                                 new_buff,
+                                 (WCHAR*)((char*)new_buff + FileBufferLength),
+                                 ErrorLine);
+    }
+
+  if (!INF_SUCCESS(Status))
+    {
+      FREE(Cache);
+      Cache = NULL;
+    }
+
+  /* Free file buffer */
+  FREE(FileBuffer);
+
+  *InfHandle = (HINF)Cache;
+
+  return(Status);
+}
+
+
+VOID
+InfCloseFile(HINF InfHandle)
+{
+  PINFCACHE Cache;
+
+  Cache = (PINFCACHE)InfHandle;
+
+  if (Cache == NULL)
+    {
+      return;
+    }
+
+  while (Cache->FirstSection != NULL)
+    {
+      Cache->FirstSection = InfpFreeSection(Cache->FirstSection);
+    }
+  Cache->LastSection = NULL;
+
+  FREE(Cache);
+
+  if (0 < InfpHeapRefCount)
+    {
+      InfpHeapRefCount--;
+      if (0 == InfpHeapRefCount)
+        {
+          RtlDestroyHeap(InfpHeap);
+          InfpHeap = NULL;
+        }
+    }
+}
+
+
+/* EOF */
diff --git a/reactos/lib/newinflib/infrosget.c b/reactos/lib/newinflib/infrosget.c
new file mode 100644 (file)
index 0000000..9f3e7b0
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * PROJECT:    .inf file parser
+ * LICENSE:    GPL - See COPYING in the top level directory
+ * PROGRAMMER: Royce Mitchell III
+ *             Eric Kohl
+ *             Ge van Geldorp <gvg@reactos.org>
+ */
+
+/* INCLUDES *****************************************************************/
+
+#include "inflib.h"
+#include "infros.h"
+
+#define NDEBUG
+#include <debug.h>
+
+
+BOOLEAN
+InfFindFirstLine(HINF InfHandle,
+                 PCWSTR Section,
+                 PCWSTR Key,
+                 PINFCONTEXT *Context)
+{
+  return INF_SUCCESS(InfpFindFirstLine(InfHandle, Section, Key, Context));
+}
+
+
+BOOLEAN
+InfFindNextLine(PINFCONTEXT ContextIn,
+                 PINFCONTEXT ContextOut)
+{
+  return INF_SUCCESS(InfpFindNextLine(ContextIn, ContextOut));
+}
+
+
+BOOLEAN
+InfFindFirstMatchLine(PINFCONTEXT ContextIn,
+                      PCWSTR Key,
+                      PINFCONTEXT ContextOut)
+{
+  return INF_SUCCESS(InfpFindFirstMatchLine(ContextIn, Key, ContextOut));
+}
+
+
+BOOLEAN
+InfFindNextMatchLine(PINFCONTEXT ContextIn,
+                     PCWSTR Key,
+                     PINFCONTEXT ContextOut)
+{
+  return INF_SUCCESS(InfpFindNextMatchLine(ContextIn, Key, ContextOut));
+}
+
+
+LONG
+InfGetLineCount(HINF InfHandle,
+                PCWSTR Section)
+{
+  return InfpGetLineCount(InfHandle, Section);
+}
+
+
+/* InfGetLineText */
+
+
+LONG
+InfGetFieldCount(PINFCONTEXT Context)
+{
+  return InfpGetFieldCount(Context);
+}
+
+
+BOOLEAN
+InfGetBinaryField(PINFCONTEXT Context,
+                  ULONG FieldIndex,
+                  PUCHAR ReturnBuffer,
+                  ULONG ReturnBufferSize,
+                  PULONG RequiredSize)
+{
+  return INF_SUCCESS(InfpGetBinaryField(Context, FieldIndex, ReturnBuffer,
+                                        ReturnBufferSize, RequiredSize));
+}
+
+
+BOOLEAN
+InfGetIntField(PINFCONTEXT Context,
+               ULONG FieldIndex,
+               PLONG IntegerValue)
+{
+  return INF_SUCCESS(InfpGetIntField(Context, FieldIndex, IntegerValue));
+}
+
+
+BOOLEAN
+InfGetMultiSzField(PINFCONTEXT Context,
+                   ULONG FieldIndex,
+                   PWSTR ReturnBuffer,
+                   ULONG ReturnBufferSize,
+                   PULONG RequiredSize)
+{
+  return INF_SUCCESS(InfpGetMultiSzField(Context, FieldIndex, ReturnBuffer,
+                                         ReturnBufferSize, RequiredSize));
+}
+
+
+BOOLEAN
+InfGetStringField(PINFCONTEXT Context,
+                  ULONG FieldIndex,
+                  PWSTR ReturnBuffer,
+                  ULONG ReturnBufferSize,
+                  PULONG RequiredSize)
+{
+  return INF_SUCCESS(InfpGetStringField(Context, FieldIndex, ReturnBuffer,
+                                        ReturnBufferSize, RequiredSize));
+}
+
+
+BOOLEAN
+InfGetData(PINFCONTEXT Context,
+           PWCHAR *Key,
+           PWCHAR *Data)
+{
+  return INF_SUCCESS(InfpGetData(Context, Key, Data));
+}
+
+
+BOOLEAN
+InfGetDataField (PINFCONTEXT Context,
+                 ULONG FieldIndex,
+                 PWCHAR *Data)
+{
+  return INF_SUCCESS(InfpGetDataField(Context, FieldIndex, Data));
+}
+
+VOID
+InfFreeContext(PINFCONTEXT Context)
+{
+  InfpFreeContext(Context);
+}
+
+/* EOF */
diff --git a/reactos/lib/newinflib/infrosput.c b/reactos/lib/newinflib/infrosput.c
new file mode 100644 (file)
index 0000000..4c6ca5a
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * PROJECT:    .inf file parser
+ * LICENSE:    GPL - See COPYING in the top level directory
+ * COPYRIGHT:  Copyright 2005 Ge van Geldorp <gvg@reactos.org>
+ */
+
+/* INCLUDES *****************************************************************/
+
+#include "inflib.h"
+#include "infros.h"
+
+#define NDEBUG
+#include <debug.h>
+
+NTSTATUS
+InfWriteFile(HINF InfHandle,
+             PUNICODE_STRING FileName,
+             PUNICODE_STRING HeaderComment)
+{
+  OBJECT_ATTRIBUTES ObjectAttributes;
+  IO_STATUS_BLOCK IoStatusBlock;
+  HANDLE FileHandle;
+  NTSTATUS Status;
+  INFSTATUS InfStatus;
+  PWCHAR Buffer;
+  ULONG BufferSize;
+  PWCHAR HeaderBuffer;
+  ULONG HeaderBufferSize;
+  UINT Index;
+
+  InfStatus = InfpBuildFileBuffer((PINFCACHE) InfHandle, &Buffer, &BufferSize);
+  if (! INF_SUCCESS(InfStatus))
+    {
+      DPRINT("Failed to create buffer (Status 0x%lx)\n", InfStatus);
+      return InfStatus;
+    }
+
+  /* Open the inf file */
+  InitializeObjectAttributes(&ObjectAttributes,
+                             FileName,
+                             0,
+                             NULL,
+                             NULL);
+
+  Status = NtOpenFile(&FileHandle,
+                      GENERIC_WRITE | SYNCHRONIZE,
+                      &ObjectAttributes,
+                      &IoStatusBlock,
+                      0,
+                      FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE);
+  if (!INF_SUCCESS(Status))
+    {
+      DPRINT1("NtOpenFile() failed (Status %lx)\n", Status);
+      FREE(Buffer);
+      return Status;
+    }
+
+  DPRINT("NtOpenFile() successful\n");
+
+  if (NULL != HeaderComment && 0 != HeaderComment->Length)
+    {
+      /* This is just a comment header, don't abort on errors here */
+      HeaderBufferSize = HeaderComment->Length + 7 * sizeof(WCHAR);
+      HeaderBuffer = MALLOC(HeaderBufferSize);
+      if (NULL != HeaderBuffer)
+        {
+          wcscpy(HeaderBuffer, L"; ");
+          for (Index = 0; Index < HeaderComment->Length / sizeof(WCHAR); Index++)
+            {
+              HeaderBuffer[2 + Index] = HeaderComment->Buffer[Index];
+            }
+          wcscpy(HeaderBuffer + (2 + HeaderComment->Length / sizeof(WCHAR)),
+                 L"\r\n\r\n");
+          NtWriteFile(FileHandle,
+                      NULL,
+                      NULL,
+                      NULL,
+                      &IoStatusBlock,
+                      HeaderBuffer,
+                      HeaderBufferSize,
+                      NULL,
+                      NULL);
+          FREE(HeaderBuffer);
+        }
+    }
+
+  /* Write main contents */
+  Status = NtWriteFile(FileHandle,
+                       NULL,
+                       NULL,
+                       NULL,
+                       &IoStatusBlock,
+                       Buffer,
+                       BufferSize,
+                       NULL,
+                       NULL);
+
+  NtClose(FileHandle);
+  FREE(Buffer);
+
+  if (!INF_SUCCESS(Status))
+    {
+      DPRINT1("NtWriteFile() failed (Status %lx)\n", Status);
+      FREE(Buffer);
+      return(Status);
+    }
+
+  return STATUS_SUCCESS;
+}
+
+BOOLEAN
+InfFindOrAddSection(HINF InfHandle,
+                    PCWSTR Section,
+                    PINFCONTEXT *Context)
+{
+  return INF_SUCCESS(InfpFindOrAddSection((PINFCACHE) InfHandle,
+                                          Section, Context));
+}
+
+BOOLEAN
+InfHostAddLine(PINFCONTEXT Context, PCWSTR Key)
+{
+  return INF_SUCCESS(InfpAddLineWithKey(Context, Key));
+}
+
+BOOLEAN
+InfHostAddField(PINFCONTEXT Context, PCWSTR Data)
+{
+  return INF_SUCCESS(InfpAddField(Context, Data));
+}
+
+/* EOF */