reactos/base/setup/lib/utils/inicache.c
2019-01-01 10:08:02 +01:00

1139 lines
25 KiB
C

/*
* PROJECT: ReactOS Setup Library
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
* PURPOSE: INI file parser that caches contents of INI file in memory.
* COPYRIGHT: Copyright 2002-2018 Royce Mitchell III
*/
/* INCLUDES *****************************************************************/
#include "precomp.h"
#include "inicache.h"
#define NDEBUG
#include <debug.h>
/* PRIVATE FUNCTIONS ********************************************************/
static
PINICACHEKEY
IniCacheFreeKey(
PINICACHEKEY Key)
{
PINICACHEKEY Next;
if (Key == NULL)
return NULL;
Next = Key->Next;
if (Key->Name != NULL)
{
RtlFreeHeap(ProcessHeap, 0, Key->Name);
Key->Name = NULL;
}
if (Key->Data != NULL)
{
RtlFreeHeap(ProcessHeap, 0, Key->Data);
Key->Data = NULL;
}
RtlFreeHeap(ProcessHeap, 0, Key);
return Next;
}
static
PINICACHESECTION
IniCacheFreeSection(
PINICACHESECTION Section)
{
PINICACHESECTION Next;
if (Section == NULL)
return NULL;
Next = Section->Next;
while (Section->FirstKey != NULL)
{
Section->FirstKey = IniCacheFreeKey(Section->FirstKey);
}
Section->LastKey = NULL;
if (Section->Name != NULL)
{
RtlFreeHeap(ProcessHeap, 0, Section->Name);
Section->Name = NULL;
}
RtlFreeHeap(ProcessHeap, 0, Section);
return Next;
}
static
PINICACHEKEY
IniCacheFindKey(
PINICACHESECTION Section,
PWCHAR Name,
ULONG NameLength)
{
PINICACHEKEY Key;
Key = Section->FirstKey;
while (Key != NULL)
{
if (NameLength == wcslen(Key->Name))
{
if (_wcsnicmp(Key->Name, Name, NameLength) == 0)
break;
}
Key = Key->Next;
}
return Key;
}
static
PINICACHEKEY
IniCacheAddKey(
PINICACHESECTION Section,
PCHAR Name,
ULONG NameLength,
PCHAR Data,
ULONG DataLength)
{
PINICACHEKEY Key;
ULONG i;
Key = NULL;
if (Section == NULL ||
Name == NULL ||
NameLength == 0 ||
Data == NULL ||
DataLength == 0)
{
DPRINT("Invalid parameter\n");
return NULL;
}
Key = (PINICACHEKEY)RtlAllocateHeap(ProcessHeap,
HEAP_ZERO_MEMORY,
sizeof(INICACHEKEY));
if (Key == NULL)
{
DPRINT("RtlAllocateHeap() failed\n");
return NULL;
}
Key->Name = (WCHAR*)RtlAllocateHeap(ProcessHeap,
0,
(NameLength + 1) * sizeof(WCHAR));
if (Key->Name == NULL)
{
DPRINT("RtlAllocateHeap() failed\n");
RtlFreeHeap(ProcessHeap, 0, Key);
return NULL;
}
/* Copy value name */
for (i = 0; i < NameLength; i++)
{
Key->Name[i] = (WCHAR)Name[i];
}
Key->Name[NameLength] = 0;
Key->Data = (WCHAR*)RtlAllocateHeap(ProcessHeap,
0,
(DataLength + 1) * sizeof(WCHAR));
if (Key->Data == NULL)
{
DPRINT("RtlAllocateHeap() failed\n");
RtlFreeHeap(ProcessHeap, 0, Key->Name);
RtlFreeHeap(ProcessHeap, 0, Key);
return NULL;
}
/* Copy value data */
for (i = 0; i < DataLength; i++)
{
Key->Data[i] = (WCHAR)Data[i];
}
Key->Data[DataLength] = 0;
if (Section->FirstKey == NULL)
{
Section->FirstKey = Key;
Section->LastKey = Key;
}
else
{
Section->LastKey->Next = Key;
Key->Prev = Section->LastKey;
Section->LastKey = Key;
}
return Key;
}
static
PINICACHESECTION
IniCacheAddSection(
PINICACHE Cache,
PCHAR Name,
ULONG NameLength)
{
PINICACHESECTION Section = NULL;
ULONG i;
if (Cache == NULL || Name == NULL || NameLength == 0)
{
DPRINT("Invalid parameter\n");
return NULL;
}
Section = (PINICACHESECTION)RtlAllocateHeap(ProcessHeap,
HEAP_ZERO_MEMORY,
sizeof(INICACHESECTION));
if (Section == NULL)
{
DPRINT("RtlAllocateHeap() failed\n");
return NULL;
}
/* Allocate and initialize section name */
Section->Name = (WCHAR*)RtlAllocateHeap(ProcessHeap,
0,
(NameLength + 1) * sizeof(WCHAR));
if (Section->Name == NULL)
{
DPRINT("RtlAllocateHeap() failed\n");
RtlFreeHeap(ProcessHeap, 0, Section);
return NULL;
}
/* Copy section name */
for (i = 0; i < NameLength; i++)
{
Section->Name[i] = (WCHAR)Name[i];
}
Section->Name[NameLength] = 0;
/* Append section */
if (Cache->FirstSection == NULL)
{
Cache->FirstSection = Section;
Cache->LastSection = Section;
}
else
{
Cache->LastSection->Next = Section;
Section->Prev = Cache->LastSection;
Cache->LastSection = Section;
}
return Section;
}
static
PCHAR
IniCacheSkipWhitespace(
PCHAR Ptr)
{
while (*Ptr != 0 && isspace(*Ptr))
Ptr++;
return (*Ptr == 0) ? NULL : Ptr;
}
static
PCHAR
IniCacheSkipToNextSection(
PCHAR Ptr)
{
while (*Ptr != 0 && *Ptr != '[')
{
while (*Ptr != 0 && *Ptr != L'\n')
{
Ptr++;
}
Ptr++;
}
return (*Ptr == 0) ? NULL : Ptr;
}
static
PCHAR
IniCacheGetSectionName(
PCHAR Ptr,
PCHAR *NamePtr,
PULONG NameSize)
{
ULONG Size = 0;
CHAR Name[256];
*NamePtr = NULL;
*NameSize = 0;
/* Skip whitespace */
while (*Ptr != 0 && isspace(*Ptr))
{
Ptr++;
}
*NamePtr = Ptr;
while (*Ptr != 0 && *Ptr != ']')
{
Size++;
Ptr++;
}
Ptr++;
while (*Ptr != 0 && *Ptr != L'\n')
{
Ptr++;
}
Ptr++;
*NameSize = Size;
strncpy(Name, *NamePtr, Size);
Name[Size] = 0;
DPRINT("SectionName: '%s'\n", Name);
return Ptr;
}
static
PCHAR
IniCacheGetKeyName(
PCHAR Ptr,
PCHAR *NamePtr,
PULONG NameSize)
{
ULONG Size = 0;
*NamePtr = NULL;
*NameSize = 0;
while (Ptr && *Ptr)
{
*NamePtr = NULL;
*NameSize = 0;
Size = 0;
/* Skip whitespace and empty lines */
while (isspace(*Ptr) || *Ptr == '\n' || *Ptr == '\r')
{
Ptr++;
}
if (*Ptr == 0)
{
continue;
}
*NamePtr = Ptr;
while (*Ptr != 0 && !isspace(*Ptr) && *Ptr != '=' && *Ptr != ';')
{
Size++;
Ptr++;
}
if (*Ptr == ';')
{
while (*Ptr != 0 && *Ptr != '\r' && *Ptr != '\n')
{
Ptr++;
}
}
else
{
*NameSize = Size;
break;
}
}
return Ptr;
}
static
PCHAR
IniCacheGetKeyValue(
PCHAR Ptr,
PCHAR *DataPtr,
PULONG DataSize,
BOOLEAN String)
{
ULONG Size = 0;
*DataPtr = NULL;
*DataSize = 0;
/* Skip whitespace */
while (*Ptr != 0 && isspace(*Ptr))
{
Ptr++;
}
/* Check and skip '=' */
if (*Ptr != '=')
{
return NULL;
}
Ptr++;
/* Skip whitespace */
while (*Ptr != 0 && isspace(*Ptr))
{
Ptr++;
}
if (*Ptr == '"' && String)
{
Ptr++;
/* Get data */
*DataPtr = Ptr;
while (*Ptr != '"')
{
Ptr++;
Size++;
}
Ptr++;
while (*Ptr && *Ptr != '\r' && *Ptr != '\n')
{
Ptr++;
}
}
else
{
/* Get data */
*DataPtr = Ptr;
while (*Ptr != 0 && *Ptr != '\r' && *Ptr != ';')
{
Ptr++;
Size++;
}
}
/* Skip to next line */
if (*Ptr == '\r')
Ptr++;
if (*Ptr == '\n')
Ptr++;
*DataSize = Size;
return Ptr;
}
/* PUBLIC FUNCTIONS *********************************************************/
NTSTATUS
IniCacheLoadFromMemory(
PINICACHE *Cache,
PCHAR FileBuffer,
ULONG FileLength,
BOOLEAN String)
{
PCHAR Ptr;
PINICACHESECTION Section;
PINICACHEKEY Key;
PCHAR SectionName;
ULONG SectionNameSize;
PCHAR KeyName;
ULONG KeyNameSize;
PCHAR KeyValue;
ULONG KeyValueSize;
/* Allocate inicache header */
*Cache = (PINICACHE)RtlAllocateHeap(ProcessHeap,
HEAP_ZERO_MEMORY,
sizeof(INICACHE));
if (*Cache == NULL)
{
DPRINT("RtlAllocateHeap() failed\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
/* Parse ini file */
Section = NULL;
Ptr = FileBuffer;
while (Ptr != NULL && *Ptr != 0)
{
Ptr = IniCacheSkipWhitespace(Ptr);
if (Ptr == NULL)
continue;
if (*Ptr == '[')
{
Section = NULL;
Ptr++;
Ptr = IniCacheGetSectionName(Ptr,
&SectionName,
&SectionNameSize);
DPRINT("[%.*s]\n", SectionNameSize, SectionName);
Section = IniCacheAddSection(*Cache,
SectionName,
SectionNameSize);
if (Section == NULL)
{
DPRINT("IniCacheAddSection() failed\n");
Ptr = IniCacheSkipToNextSection(Ptr);
continue;
}
}
else
{
if (Section == NULL)
{
Ptr = IniCacheSkipToNextSection(Ptr);
continue;
}
Ptr = IniCacheGetKeyName(Ptr,
&KeyName,
&KeyNameSize);
Ptr = IniCacheGetKeyValue(Ptr,
&KeyValue,
&KeyValueSize,
String);
DPRINT("'%.*s' = '%.*s'\n", KeyNameSize, KeyName, KeyValueSize, KeyValue);
Key = IniCacheAddKey(Section,
KeyName,
KeyNameSize,
KeyValue,
KeyValueSize);
if (Key == NULL)
{
DPRINT("IniCacheAddKey() failed\n");
}
}
}
return STATUS_SUCCESS;
}
NTSTATUS
IniCacheLoadByHandle(
PINICACHE *Cache,
HANDLE FileHandle,
BOOLEAN String)
{
NTSTATUS Status;
IO_STATUS_BLOCK IoStatusBlock;
FILE_STANDARD_INFORMATION FileInfo;
PCHAR FileBuffer;
ULONG FileLength;
LARGE_INTEGER FileOffset;
*Cache = NULL;
/* Query file size */
Status = NtQueryInformationFile(FileHandle,
&IoStatusBlock,
&FileInfo,
sizeof(FILE_STANDARD_INFORMATION),
FileStandardInformation);
if (!NT_SUCCESS(Status))
{
DPRINT("NtQueryInformationFile() failed (Status %lx)\n", Status);
return Status;
}
FileLength = FileInfo.EndOfFile.u.LowPart;
DPRINT("File size: %lu\n", FileLength);
/* Allocate file buffer with NULL-terminator */
FileBuffer = (CHAR*)RtlAllocateHeap(ProcessHeap,
0,
FileLength + 1);
if (FileBuffer == NULL)
{
DPRINT1("RtlAllocateHeap() failed\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
/* Read file */
FileOffset.QuadPart = 0ULL;
Status = NtReadFile(FileHandle,
NULL,
NULL,
NULL,
&IoStatusBlock,
FileBuffer,
FileLength,
&FileOffset,
NULL);
/* Append NULL-terminator */
FileBuffer[FileLength] = 0;
if (!NT_SUCCESS(Status))
{
DPRINT("NtReadFile() failed (Status %lx)\n", Status);
goto Quit;
}
Status = IniCacheLoadFromMemory(Cache, FileBuffer, FileLength, String);
if (!NT_SUCCESS(Status))
{
DPRINT1("IniCacheLoadFromMemory() failed (Status %lx)\n", Status);
}
Quit:
/* Free the file buffer, and return */
RtlFreeHeap(ProcessHeap, 0, FileBuffer);
return Status;
}
NTSTATUS
IniCacheLoad(
PINICACHE *Cache,
PWCHAR FileName,
BOOLEAN String)
{
NTSTATUS Status;
UNICODE_STRING Name;
OBJECT_ATTRIBUTES ObjectAttributes;
IO_STATUS_BLOCK IoStatusBlock;
HANDLE FileHandle;
*Cache = NULL;
/* Open the INI file */
RtlInitUnicodeString(&Name, FileName);
InitializeObjectAttributes(&ObjectAttributes,
&Name,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = NtOpenFile(&FileHandle,
FILE_GENERIC_READ | SYNCHRONIZE,
&ObjectAttributes,
&IoStatusBlock,
FILE_SHARE_READ,
FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE);
if (!NT_SUCCESS(Status))
{
DPRINT("NtOpenFile() failed (Status %lx)\n", Status);
return Status;
}
DPRINT("NtOpenFile() successful\n");
Status = IniCacheLoadByHandle(Cache, FileHandle, String);
/* Close the INI file */
NtClose(FileHandle);
return Status;
}
VOID
IniCacheDestroy(
PINICACHE Cache)
{
if (Cache == NULL)
return;
while (Cache->FirstSection != NULL)
{
Cache->FirstSection = IniCacheFreeSection(Cache->FirstSection);
}
Cache->LastSection = NULL;
RtlFreeHeap(ProcessHeap, 0, Cache);
}
PINICACHESECTION
IniCacheGetSection(
PINICACHE Cache,
PWCHAR Name)
{
PINICACHESECTION Section = NULL;
if (Cache == NULL || Name == NULL)
{
DPRINT("Invalid parameter\n");
return NULL;
}
/* Iterate through list of sections */
Section = Cache->FirstSection;
while (Section != NULL)
{
DPRINT("Comparing '%S' and '%S'\n", Section->Name, Name);
/* Are the section names the same? */
if (_wcsicmp(Section->Name, Name) == 0)
return Section;
/* Get the next section */
Section = Section->Next;
}
DPRINT("Section not found\n");
return NULL;
}
NTSTATUS
IniCacheGetKey(
PINICACHESECTION Section,
PWCHAR KeyName,
PWCHAR *KeyData)
{
PINICACHEKEY Key;
if (Section == NULL || KeyName == NULL || KeyData == NULL)
{
DPRINT("Invalid parameter\n");
return STATUS_INVALID_PARAMETER;
}
*KeyData = NULL;
Key = IniCacheFindKey(Section, KeyName, wcslen(KeyName));
if (Key == NULL)
{
return STATUS_INVALID_PARAMETER;
}
*KeyData = Key->Data;
return STATUS_SUCCESS;
}
PINICACHEITERATOR
IniCacheFindFirstValue(
PINICACHESECTION Section,
PWCHAR *KeyName,
PWCHAR *KeyData)
{
PINICACHEITERATOR Iterator;
PINICACHEKEY Key;
if (Section == NULL || KeyName == NULL || KeyData == NULL)
{
DPRINT("Invalid parameter\n");
return NULL;
}
Key = Section->FirstKey;
if (Key == NULL)
{
DPRINT("Invalid parameter\n");
return NULL;
}
*KeyName = Key->Name;
*KeyData = Key->Data;
Iterator = (PINICACHEITERATOR)RtlAllocateHeap(ProcessHeap,
0,
sizeof(INICACHEITERATOR));
if (Iterator == NULL)
{
DPRINT("RtlAllocateHeap() failed\n");
return NULL;
}
Iterator->Section = Section;
Iterator->Key = Key;
return Iterator;
}
BOOLEAN
IniCacheFindNextValue(
PINICACHEITERATOR Iterator,
PWCHAR *KeyName,
PWCHAR *KeyData)
{
PINICACHEKEY Key;
if (Iterator == NULL || KeyName == NULL || KeyData == NULL)
{
DPRINT("Invalid parameter\n");
return FALSE;
}
Key = Iterator->Key->Next;
if (Key == NULL)
{
DPRINT("No more entries\n");
return FALSE;
}
*KeyName = Key->Name;
*KeyData = Key->Data;
Iterator->Key = Key;
return TRUE;
}
VOID
IniCacheFindClose(
PINICACHEITERATOR Iterator)
{
if (Iterator == NULL)
return;
RtlFreeHeap(ProcessHeap, 0, Iterator);
}
PINICACHEKEY
IniCacheInsertKey(
PINICACHESECTION Section,
PINICACHEKEY AnchorKey,
INSERTION_TYPE InsertionType,
PWCHAR Name,
PWCHAR Data)
{
PINICACHEKEY Key;
Key = NULL;
if (Section == NULL ||
Name == NULL ||
*Name == 0 ||
Data == NULL ||
*Data == 0)
{
DPRINT("Invalid parameter\n");
return NULL;
}
/* Allocate key buffer */
Key = (PINICACHEKEY)RtlAllocateHeap(ProcessHeap,
HEAP_ZERO_MEMORY,
sizeof(INICACHEKEY));
if (Key == NULL)
{
DPRINT("RtlAllocateHeap() failed\n");
return NULL;
}
/* Allocate name buffer */
Key->Name = (WCHAR*)RtlAllocateHeap(ProcessHeap,
0,
(wcslen(Name) + 1) * sizeof(WCHAR));
if (Key->Name == NULL)
{
DPRINT("RtlAllocateHeap() failed\n");
RtlFreeHeap(ProcessHeap, 0, Key);
return NULL;
}
/* Copy value name */
wcscpy(Key->Name, Name);
/* Allocate data buffer */
Key->Data = (WCHAR*)RtlAllocateHeap(ProcessHeap,
0,
(wcslen(Data) + 1) * sizeof(WCHAR));
if (Key->Data == NULL)
{
DPRINT("RtlAllocateHeap() failed\n");
RtlFreeHeap(ProcessHeap, 0, Key->Name);
RtlFreeHeap(ProcessHeap, 0, Key);
return NULL;
}
/* Copy value data */
wcscpy(Key->Data, Data);
/* Insert key into section */
if (Section->FirstKey == NULL)
{
Section->FirstKey = Key;
Section->LastKey = Key;
}
else if ((InsertionType == INSERT_FIRST) ||
((InsertionType == INSERT_BEFORE) && ((AnchorKey == NULL) || (AnchorKey == Section->FirstKey))))
{
/* Insert at the head of the list */
Section->FirstKey->Prev = Key;
Key->Next = Section->FirstKey;
Section->FirstKey = Key;
}
else if ((InsertionType == INSERT_BEFORE) && (AnchorKey != NULL))
{
/* Insert before the anchor key */
Key->Next = AnchorKey;
Key->Prev = AnchorKey->Prev;
AnchorKey->Prev->Next = Key;
AnchorKey->Prev = Key;
}
else if ((InsertionType == INSERT_LAST) ||
((InsertionType == INSERT_AFTER) && ((AnchorKey == NULL) || (AnchorKey == Section->LastKey))))
{
Section->LastKey->Next = Key;
Key->Prev = Section->LastKey;
Section->LastKey = Key;
}
else if ((InsertionType == INSERT_AFTER) && (AnchorKey != NULL))
{
/* Insert after the anchor key */
Key->Next = AnchorKey->Next;
Key->Prev = AnchorKey;
AnchorKey->Next->Prev = Key;
AnchorKey->Next = Key;
}
return Key;
}
PINICACHE
IniCacheCreate(VOID)
{
PINICACHE Cache;
/* Allocate inicache header */
Cache = (PINICACHE)RtlAllocateHeap(ProcessHeap,
HEAP_ZERO_MEMORY,
sizeof(INICACHE));
if (Cache == NULL)
{
DPRINT("RtlAllocateHeap() failed\n");
return NULL;
}
return Cache;
}
NTSTATUS
IniCacheSaveByHandle(
PINICACHE Cache,
HANDLE FileHandle)
{
NTSTATUS Status;
PINICACHESECTION Section;
PINICACHEKEY Key;
ULONG BufferSize;
PCHAR Buffer;
PCHAR Ptr;
ULONG Len;
IO_STATUS_BLOCK IoStatusBlock;
LARGE_INTEGER Offset;
/* Calculate required buffer size */
BufferSize = 0;
Section = Cache->FirstSection;
while (Section != NULL)
{
BufferSize += (Section->Name ? wcslen(Section->Name) : 0)
+ 4; /* "[]\r\n" */
Key = Section->FirstKey;
while (Key != NULL)
{
BufferSize += wcslen(Key->Name)
+ (Key->Data ? wcslen(Key->Data) : 0)
+ 3; /* "=\r\n" */
Key = Key->Next;
}
Section = Section->Next;
if (Section != NULL)
BufferSize += 2; /* Extra "\r\n" at end of each section */
}
DPRINT("BufferSize: %lu\n", BufferSize);
/* Allocate file buffer with NULL-terminator */
Buffer = (CHAR*)RtlAllocateHeap(ProcessHeap,
HEAP_ZERO_MEMORY,
BufferSize + 1);
if (Buffer == NULL)
{
DPRINT1("RtlAllocateHeap() failed\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
/* Fill file buffer */
Ptr = Buffer;
Section = Cache->FirstSection;
while (Section != NULL)
{
Len = sprintf(Ptr, "[%S]\r\n", Section->Name);
Ptr += Len;
Key = Section->FirstKey;
while (Key != NULL)
{
Len = sprintf(Ptr, "%S=%S\r\n", Key->Name, Key->Data);
Ptr += Len;
Key = Key->Next;
}
Section = Section->Next;
if (Section != NULL)
{
Len = sprintf(Ptr, "\r\n");
Ptr += Len;
}
}
/* Write to the INI file */
Offset.QuadPart = 0LL;
Status = NtWriteFile(FileHandle,
NULL,
NULL,
NULL,
&IoStatusBlock,
Buffer,
BufferSize,
&Offset,
NULL);
if (!NT_SUCCESS(Status))
{
DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
RtlFreeHeap(ProcessHeap, 0, Buffer);
return Status;
}
RtlFreeHeap(ProcessHeap, 0, Buffer);
return STATUS_SUCCESS;
}
NTSTATUS
IniCacheSave(
PINICACHE Cache,
PWCHAR FileName)
{
NTSTATUS Status;
UNICODE_STRING Name;
OBJECT_ATTRIBUTES ObjectAttributes;
IO_STATUS_BLOCK IoStatusBlock;
HANDLE FileHandle;
/* Create the INI file */
RtlInitUnicodeString(&Name, FileName);
InitializeObjectAttributes(&ObjectAttributes,
&Name,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = NtCreateFile(&FileHandle,
FILE_GENERIC_WRITE | SYNCHRONIZE,
&ObjectAttributes,
&IoStatusBlock,
NULL,
FILE_ATTRIBUTE_NORMAL,
0,
FILE_SUPERSEDE,
FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY | FILE_NON_DIRECTORY_FILE,
NULL,
0);
if (!NT_SUCCESS(Status))
{
DPRINT("NtCreateFile() failed (Status %lx)\n", Status);
return Status;
}
Status = IniCacheSaveByHandle(Cache, FileHandle);
/* Close the INI file */
NtClose(FileHandle);
return Status;
}
PINICACHESECTION
IniCacheAppendSection(
PINICACHE Cache,
PWCHAR Name)
{
PINICACHESECTION Section = NULL;
if (Cache == NULL || Name == NULL || *Name == 0)
{
DPRINT("Invalid parameter\n");
return NULL;
}
Section = (PINICACHESECTION)RtlAllocateHeap(ProcessHeap,
HEAP_ZERO_MEMORY,
sizeof(INICACHESECTION));
if (Section == NULL)
{
DPRINT("RtlAllocateHeap() failed\n");
return NULL;
}
/* Allocate and initialize section name */
Section->Name = (WCHAR*)RtlAllocateHeap(ProcessHeap,
0,
(wcslen(Name) + 1) * sizeof(WCHAR));
if (Section->Name == NULL)
{
DPRINT("RtlAllocateHeap() failed\n");
RtlFreeHeap(ProcessHeap, 0, Section);
return NULL;
}
/* 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;
}
/* EOF */