* Change newinflib to inflib.
[reactos.git] / reactos / lib / inflib / infput.c
diff --git a/reactos/lib/inflib/infput.c b/reactos/lib/inflib/infput.c
new file mode 100644 (file)
index 0000000..c049f3f
--- /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)strlenW(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 */