3 * Copyright (C) 2002 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 /* $Id: inicache.c,v 1.9 2004/08/15 22:29:50 chorns Exp $
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS text-mode setup
22 * FILE: subsys/system/usetup/inicache.c
23 * PURPOSE: INI file parser that caches contents of INI file in memory
24 * PROGRAMMER: Royce Mitchell III
28 /* INCLUDES *****************************************************************/
37 /* PRIVATE FUNCTIONS ********************************************************/
40 IniCacheFreeKey(PINICACHEKEY Key
)
50 if (Key
->Name
!= NULL
)
52 RtlFreeHeap(ProcessHeap
,
58 if (Key
->Data
!= NULL
)
60 RtlFreeHeap(ProcessHeap
,
66 RtlFreeHeap(ProcessHeap
,
74 static PINICACHESECTION
75 IniCacheFreeSection(PINICACHESECTION Section
)
77 PINICACHESECTION Next
;
85 while (Section
->FirstKey
!= NULL
)
87 Section
->FirstKey
= IniCacheFreeKey(Section
->FirstKey
);
89 Section
->LastKey
= NULL
;
91 if (Section
->Name
!= NULL
)
93 RtlFreeHeap(ProcessHeap
,
99 RtlFreeHeap(ProcessHeap
,
108 IniCacheFindKey(PINICACHESECTION Section
,
114 Key
= Section
->FirstKey
;
117 if (NameLength
== wcslen(Key
->Name
))
119 if (_wcsnicmp(Key
->Name
, Name
, NameLength
) == 0)
131 IniCacheAddKey(PINICACHESECTION Section
,
142 if (Section
== NULL
||
148 DPRINT("Invalid parameter\n");
152 Key
= (PINICACHEKEY
)RtlAllocateHeap(ProcessHeap
,
154 sizeof(INICACHEKEY
));
157 DPRINT("RtlAllocateHeap() failed\n");
162 sizeof(INICACHEKEY
));
165 Key
->Name
= RtlAllocateHeap(ProcessHeap
,
167 (NameLength
+ 1) * sizeof(WCHAR
));
168 if (Key
->Name
== NULL
)
170 DPRINT("RtlAllocateHeap() failed\n");
171 RtlFreeHeap(ProcessHeap
,
177 /* Copy value name */
178 for (i
= 0; i
< NameLength
; i
++)
180 Key
->Name
[i
] = (WCHAR
)Name
[i
];
182 Key
->Name
[NameLength
] = 0;
185 Key
->Data
= RtlAllocateHeap(ProcessHeap
,
187 (DataLength
+ 1) * sizeof(WCHAR
));
188 if (Key
->Data
== NULL
)
190 DPRINT("RtlAllocateHeap() failed\n");
191 RtlFreeHeap(ProcessHeap
,
194 RtlFreeHeap(ProcessHeap
,
200 /* Copy value data */
201 for (i
= 0; i
< DataLength
; i
++)
203 Key
->Data
[i
] = (WCHAR
)Data
[i
];
205 Key
->Data
[DataLength
] = 0;
208 if (Section
->FirstKey
== NULL
)
210 Section
->FirstKey
= Key
;
211 Section
->LastKey
= Key
;
215 Section
->LastKey
->Next
= Key
;
216 Key
->Prev
= Section
->LastKey
;
217 Section
->LastKey
= Key
;
224 static PINICACHESECTION
225 IniCacheFindSection(PINICACHE Cache
,
229 PINICACHESECTION Section
= NULL
;
231 if (Cache
== NULL
|| Name
== NULL
|| NameLength
== 0)
236 Section
= Cache
->FirstSection
;
238 /* iterate through list of sections */
239 while (Section
!= NULL
)
241 if (NameLength
== wcslen(Section
->Name
))
243 /* are the contents the same too? */
244 if (_wcsnicmp(Section
->Name
, Name
, NameLength
) == 0)
248 /* get the next section*/
249 Section
= Section
->Next
;
256 static PINICACHESECTION
257 IniCacheAddSection(PINICACHE Cache
,
261 PINICACHESECTION Section
= NULL
;
264 if (Cache
== NULL
|| Name
== NULL
|| NameLength
== 0)
266 DPRINT("Invalid parameter\n");
270 Section
= (PINICACHESECTION
)RtlAllocateHeap(ProcessHeap
,
272 sizeof(INICACHESECTION
));
275 DPRINT("RtlAllocateHeap() failed\n");
278 RtlZeroMemory(Section
,
279 sizeof(INICACHESECTION
));
281 /* Allocate and initialize section name */
282 Section
->Name
= RtlAllocateHeap(ProcessHeap
,
284 (NameLength
+ 1) * sizeof(WCHAR
));
285 if (Section
->Name
== NULL
)
287 DPRINT("RtlAllocateHeap() failed\n");
288 RtlFreeHeap(ProcessHeap
,
294 /* Copy section name */
295 for (i
= 0; i
< NameLength
; i
++)
297 Section
->Name
[i
] = (WCHAR
)Name
[i
];
299 Section
->Name
[NameLength
] = 0;
302 if (Cache
->FirstSection
== NULL
)
304 Cache
->FirstSection
= Section
;
305 Cache
->LastSection
= Section
;
309 Cache
->LastSection
->Next
= Section
;
310 Section
->Prev
= Cache
->LastSection
;
311 Cache
->LastSection
= Section
;
319 IniCacheSkipWhitespace(PCHAR Ptr
)
321 while (*Ptr
!= 0 && isspace(*Ptr
))
324 return((*Ptr
== 0) ? NULL
: Ptr
);
329 IniCacheSkipToNextSection(PCHAR Ptr
)
331 while (*Ptr
!= 0 && *Ptr
!= '[')
333 while (*Ptr
!= 0 && *Ptr
!= L
'\n')
340 return((*Ptr
== 0) ? NULL
: Ptr
);
345 IniCacheGetSectionName(PCHAR Ptr
,
355 /* skip whitespace */
356 while (*Ptr
!= 0 && isspace(*Ptr
))
363 while (*Ptr
!= 0 && *Ptr
!= ']')
371 while (*Ptr
!= 0 && *Ptr
!= L
'\n')
379 strncpy(Name
, *NamePtr
, Size
);
382 DPRINT("SectionName: '%s'\n", Name
);
389 IniCacheGetKeyName(PCHAR Ptr
,
404 /* skip whitespace and empty lines */
405 while (isspace(*Ptr
) || *Ptr
== '\n' || *Ptr
== '\r')
416 while (*Ptr
!= 0 && !isspace(*Ptr
) && *Ptr
!= '=' && *Ptr
!= ';')
423 while (*Ptr
!= 0 && *Ptr
!= '\r' && *Ptr
!= '\n')
440 IniCacheGetKeyValue(PCHAR Ptr
,
450 /* Skip whitespace */
451 while (*Ptr
!= 0 && isspace(*Ptr
))
456 /* Check and skip '=' */
463 /* Skip whitespace */
464 while (*Ptr
!= 0 && isspace(*Ptr
))
469 if (*Ptr
== '"' && String
)
481 while (*Ptr
&& *Ptr
!= '\r' && *Ptr
!= '\n')
490 while (*Ptr
!= 0 && *Ptr
!= '\r' && *Ptr
!= ';')
497 /* Skip to next line */
511 /* PUBLIC FUNCTIONS *********************************************************/
514 IniCacheLoad(PINICACHE
*Cache
,
515 PUNICODE_STRING FileName
,
518 OBJECT_ATTRIBUTES ObjectAttributes
;
519 FILE_STANDARD_INFORMATION FileInfo
;
520 IO_STATUS_BLOCK IoStatusBlock
;
526 LARGE_INTEGER FileOffset
;
528 PINICACHESECTION Section
;
532 ULONG SectionNameSize
;
543 InitializeObjectAttributes(&ObjectAttributes
,
549 Status
= NtOpenFile(&FileHandle
,
550 GENERIC_READ
| SYNCHRONIZE
,
554 FILE_SYNCHRONOUS_IO_NONALERT
| FILE_NON_DIRECTORY_FILE
);
555 if (!NT_SUCCESS(Status
))
557 DPRINT("NtOpenFile() failed (Status %lx)\n", Status
);
561 DPRINT("NtOpenFile() successful\n");
563 /* Query file size */
564 Status
= NtQueryInformationFile(FileHandle
,
567 sizeof(FILE_STANDARD_INFORMATION
),
568 FileStandardInformation
);
569 if (!NT_SUCCESS(Status
))
571 DPRINT("NtQueryInformationFile() failed (Status %lx)\n", Status
);
576 FileLength
= FileInfo
.EndOfFile
.u
.LowPart
;
578 DPRINT("File size: %lu\n", FileLength
);
580 /* Allocate file buffer */
581 FileBuffer
= RtlAllocateHeap(ProcessHeap
,
584 if (FileBuffer
== NULL
)
586 DPRINT1("RtlAllocateHeap() failed\n");
588 return(STATUS_INSUFFICIENT_RESOURCES
);
592 FileOffset
.QuadPart
= 0ULL;
593 Status
= NtReadFile(FileHandle
,
603 /* Append string terminator */
604 FileBuffer
[FileLength
] = 0;
608 if (!NT_SUCCESS(Status
))
610 DPRINT("NtReadFile() failed (Status %lx)\n", Status
);
611 RtlFreeHeap(ProcessHeap
,
618 /* Allocate inicache header */
619 *Cache
= (PINICACHE
)RtlAllocateHeap(ProcessHeap
,
624 DPRINT("RtlAllocateHeap() failed\n");
625 return(STATUS_INSUFFICIENT_RESOURCES
);
628 /* Initialize inicache header */
629 RtlZeroMemory(*Cache
,
635 while (Ptr
!= NULL
&& *Ptr
!= 0)
637 Ptr
= IniCacheSkipWhitespace(Ptr
);
646 Ptr
= IniCacheGetSectionName(Ptr
,
650 DPRINT1("[%.*s]\n", SectionNameSize
, SectionName
);
652 Section
= IniCacheAddSection(*Cache
,
657 DPRINT("IniCacheAddSection() failed\n");
658 Ptr
= IniCacheSkipToNextSection(Ptr
);
666 Ptr
= IniCacheSkipToNextSection(Ptr
);
670 Ptr
= IniCacheGetKeyName(Ptr
,
674 Ptr
= IniCacheGetKeyValue(Ptr
,
679 DPRINT1("'%.*s' = '%.*s'\n", KeyNameSize
, KeyName
, KeyValueSize
, KeyValue
);
681 Key
= IniCacheAddKey(Section
,
688 DPRINT("IniCacheAddKey() failed\n");
693 /* Free file buffer */
694 RtlFreeHeap(ProcessHeap
,
703 IniCacheDestroy(PINICACHE Cache
)
710 while (Cache
->FirstSection
!= NULL
)
712 Cache
->FirstSection
= IniCacheFreeSection(Cache
->FirstSection
);
714 Cache
->LastSection
= NULL
;
716 RtlFreeHeap(ProcessHeap
,
723 IniCacheGetSection(PINICACHE Cache
,
726 PINICACHESECTION Section
= NULL
;
728 if (Cache
== NULL
|| Name
== NULL
)
730 DPRINT("Invalid parameter\n");
734 /* Iterate through list of sections */
735 Section
= Cache
->FirstSection
;
736 while (Section
!= NULL
)
738 DPRINT("Comparing '%S' and '%S'\n", Section
->Name
, Name
);
740 /* Are the section names the same? */
741 if (_wcsicmp(Section
->Name
, Name
) == 0)
744 /* Get the next section */
745 Section
= Section
->Next
;
748 DPRINT("Section not found\n");
755 IniCacheGetKey(PINICACHESECTION Section
,
761 if (Section
== NULL
|| KeyName
== NULL
|| KeyData
== NULL
)
763 DPRINT("Invalid parameter\n");
764 return(STATUS_INVALID_PARAMETER
);
769 Key
= IniCacheFindKey(Section
, KeyName
, wcslen(KeyName
));
772 return(STATUS_INVALID_PARAMETER
);
775 *KeyData
= Key
->Data
;
777 return(STATUS_SUCCESS
);
782 IniCacheFindFirstValue(PINICACHESECTION Section
,
786 PINICACHEITERATOR Iterator
;
789 if (Section
== NULL
|| KeyName
== NULL
|| KeyData
== NULL
)
791 DPRINT("Invalid parameter\n");
795 Key
= Section
->FirstKey
;
798 DPRINT("Invalid parameter\n");
802 *KeyName
= Key
->Name
;
803 *KeyData
= Key
->Data
;
805 Iterator
= (PINICACHEITERATOR
)RtlAllocateHeap(ProcessHeap
,
807 sizeof(INICACHEITERATOR
));
808 if (Iterator
== NULL
)
810 DPRINT("RtlAllocateHeap() failed\n");
814 Iterator
->Section
= Section
;
822 IniCacheFindNextValue(PINICACHEITERATOR Iterator
,
828 if (Iterator
== NULL
|| KeyName
== NULL
|| KeyData
== NULL
)
830 DPRINT("Invalid parameter\n");
834 Key
= Iterator
->Key
->Next
;
837 DPRINT("No more entries\n");
841 *KeyName
= Key
->Name
;
842 *KeyData
= Key
->Data
;
851 IniCacheFindClose(PINICACHEITERATOR Iterator
)
853 if (Iterator
== NULL
)
856 RtlFreeHeap(ProcessHeap
,
863 IniCacheInsertKey(PINICACHESECTION Section
,
864 PINICACHEKEY AnchorKey
,
865 INSERTATION_TYPE InsertationType
,
873 if (Section
== NULL
||
879 DPRINT("Invalid parameter\n");
883 /* Allocate key buffer */
884 Key
= (PINICACHEKEY
)RtlAllocateHeap(ProcessHeap
,
886 sizeof(INICACHEKEY
));
889 DPRINT("RtlAllocateHeap() failed\n");
893 sizeof(INICACHEKEY
));
895 /* Allocate name buffer */
896 Key
->Name
= RtlAllocateHeap(ProcessHeap
,
898 (wcslen(Name
) + 1) * sizeof(WCHAR
));
899 if (Key
->Name
== NULL
)
901 DPRINT("RtlAllocateHeap() failed\n");
902 RtlFreeHeap(ProcessHeap
,
908 /* Copy value name */
909 wcscpy(Key
->Name
, Name
);
911 /* Allocate data buffer */
912 Key
->Data
= RtlAllocateHeap(ProcessHeap
,
914 (wcslen(Data
) + 1) * sizeof(WCHAR
));
915 if (Key
->Data
== NULL
)
917 DPRINT("RtlAllocateHeap() failed\n");
918 RtlFreeHeap(ProcessHeap
,
921 RtlFreeHeap(ProcessHeap
,
927 /* Copy value data */
928 wcscpy(Key
->Data
, Data
);
930 /* Insert key into section */
931 if (Section
->FirstKey
== NULL
)
933 Section
->FirstKey
= Key
;
934 Section
->LastKey
= Key
;
936 else if ((InsertationType
== INSERT_FIRST
) ||
937 ((InsertationType
== INSERT_BEFORE
) && ((AnchorKey
== NULL
) || (AnchorKey
== Section
->FirstKey
))))
939 /* Insert at the head of the list */
940 Section
->FirstKey
->Prev
= Key
;
941 Key
->Next
= Section
->FirstKey
;
942 Section
->FirstKey
= Key
;
944 else if ((InsertationType
== INSERT_BEFORE
) && (AnchorKey
!= NULL
))
946 /* Insert before the anchor key */
947 Key
->Next
= AnchorKey
;
948 Key
->Prev
= AnchorKey
->Prev
;
949 AnchorKey
->Prev
->Next
= Key
;
950 AnchorKey
->Prev
= Key
;
952 else if ((InsertationType
== INSERT_LAST
) ||
953 ((InsertationType
== INSERT_AFTER
) && ((AnchorKey
== NULL
) || (AnchorKey
== Section
->LastKey
))))
955 Section
->LastKey
->Next
= Key
;
956 Key
->Prev
= Section
->LastKey
;
957 Section
->LastKey
= Key
;
959 else if ((InsertationType
== INSERT_AFTER
) && (AnchorKey
!= NULL
))
961 /* Insert before the anchor key */
962 Key
->Next
= AnchorKey
->Next
;
963 Key
->Prev
= AnchorKey
;
964 AnchorKey
->Next
->Prev
= Key
;
965 AnchorKey
->Next
= Key
;
977 /* Allocate inicache header */
978 Cache
= (PINICACHE
)RtlAllocateHeap(ProcessHeap
,
983 DPRINT("RtlAllocateHeap() failed\n");
987 /* Initialize inicache header */
996 IniCacheSave(PINICACHE Cache
,
1000 PINICACHESECTION Section
;
1008 OBJECT_ATTRIBUTES ObjectAttributes
;
1009 IO_STATUS_BLOCK IoStatusBlock
;
1010 LARGE_INTEGER Offset
;
1014 /* Calculate required buffer size */
1016 Section
= Cache
->FirstSection
;
1017 while (Section
!= NULL
)
1019 BufferSize
+= (Section
->Name
? wcslen(Section
->Name
) : 0)
1022 Key
= Section
->FirstKey
;
1025 BufferSize
+= wcslen(Key
->Name
)
1026 + (Key
->Data
? wcslen(Key
->Data
) : 0)
1031 Section
= Section
->Next
;
1032 if (Section
!= NULL
)
1033 BufferSize
+= 2; /* extra "\r\n" at end of each section */
1035 BufferSize
++; /* Null-terminator */
1037 DPRINT1("BufferSize: %lu\n", BufferSize
);
1039 /* Allocate file buffer */
1040 Buffer
= RtlAllocateHeap(ProcessHeap
,
1045 DPRINT1("RtlAllocateHeap() failed\n");
1046 return(STATUS_INSUFFICIENT_RESOURCES
);
1048 RtlZeroMemory(Buffer
, BufferSize
);
1050 /* Fill file buffer */
1052 Section
= Cache
->FirstSection
;
1053 while (Section
!= NULL
)
1055 Len
= sprintf(Ptr
, "[%S]\r\n", Section
->Name
);
1058 Key
= Section
->FirstKey
;
1061 Len
= sprintf(Ptr
, "%S=%S\r\n", Key
->Name
, Key
->Data
);
1066 Section
= Section
->Next
;
1067 if (Section
!= NULL
)
1069 Len
= sprintf(Ptr
, "\r\n");
1074 /* Create ini file */
1075 RtlInitUnicodeString(&Name
,
1078 InitializeObjectAttributes(&ObjectAttributes
,
1084 Status
= NtCreateFile(&FileHandle
,
1089 FILE_ATTRIBUTE_NORMAL
,
1092 FILE_SYNCHRONOUS_IO_NONALERT
| FILE_SEQUENTIAL_ONLY
,
1095 if (!NT_SUCCESS(Status
))
1097 DPRINT("NtCreateFile() failed (Status %lx)\n", Status
);
1098 RtlFreeHeap(ProcessHeap
,
1104 Offset
.QuadPart
= 0LL;
1105 Status
= NtWriteFile(FileHandle
,
1114 if (!NT_SUCCESS(Status
))
1116 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
1117 NtClose(FileHandle
);
1118 RtlFreeHeap(ProcessHeap
,
1124 NtClose(FileHandle
);
1126 RtlFreeHeap(ProcessHeap
,
1130 return(STATUS_SUCCESS
);
1135 IniCacheAppendSection(PINICACHE Cache
,
1138 PINICACHESECTION Section
= NULL
;
1140 if (Cache
== NULL
|| Name
== NULL
|| *Name
== 0)
1142 DPRINT("Invalid parameter\n");
1146 Section
= (PINICACHESECTION
)RtlAllocateHeap(ProcessHeap
,
1148 sizeof(INICACHESECTION
));
1149 if (Section
== NULL
)
1151 DPRINT("RtlAllocateHeap() failed\n");
1154 RtlZeroMemory(Section
,
1155 sizeof(INICACHESECTION
));
1157 /* Allocate and initialize section name */
1158 Section
->Name
= RtlAllocateHeap(ProcessHeap
,
1160 (wcslen(Name
) + 1) * sizeof(WCHAR
));
1161 if (Section
->Name
== NULL
)
1163 DPRINT("RtlAllocateHeap() failed\n");
1164 RtlFreeHeap(ProcessHeap
,
1170 /* Copy section name */
1171 wcscpy(Section
->Name
, Name
);
1173 /* Append section */
1174 if (Cache
->FirstSection
== NULL
)
1176 Cache
->FirstSection
= Section
;
1177 Cache
->LastSection
= Section
;
1181 Cache
->LastSection
->Next
= Section
;
1182 Section
->Prev
= Cache
->LastSection
;
1183 Cache
->LastSection
= Section
;