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 along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS text-mode setup
22 * FILE: base/setup/usetup/inicache.c
23 * PURPOSE: INI file parser that caches contents of INI file in memory
24 * PROGRAMMER: Royce Mitchell III
28 /* INCLUDES *****************************************************************/
35 /* PRIVATE FUNCTIONS ********************************************************/
50 if (Key
->Name
!= NULL
)
52 RtlFreeHeap(ProcessHeap
, 0, Key
->Name
);
56 if (Key
->Data
!= NULL
)
58 RtlFreeHeap(ProcessHeap
, 0, Key
->Data
);
62 RtlFreeHeap(ProcessHeap
, 0, Key
);
71 PINICACHESECTION Section
)
73 PINICACHESECTION Next
;
81 while (Section
->FirstKey
!= NULL
)
83 Section
->FirstKey
= IniCacheFreeKey(Section
->FirstKey
);
85 Section
->LastKey
= NULL
;
87 if (Section
->Name
!= NULL
)
89 RtlFreeHeap(ProcessHeap
, 0, Section
->Name
);
93 RtlFreeHeap(ProcessHeap
, 0, Section
);
102 PINICACHESECTION Section
,
108 Key
= Section
->FirstKey
;
111 if (NameLength
== wcslen(Key
->Name
))
113 if (_wcsnicmp(Key
->Name
, Name
, NameLength
) == 0)
127 PINICACHESECTION Section
,
138 if (Section
== NULL
||
144 DPRINT("Invalid parameter\n");
148 Key
= (PINICACHEKEY
)RtlAllocateHeap(ProcessHeap
,
150 sizeof(INICACHEKEY
));
153 DPRINT("RtlAllocateHeap() failed\n");
158 sizeof(INICACHEKEY
));
160 Key
->Name
= (WCHAR
*)RtlAllocateHeap(ProcessHeap
,
162 (NameLength
+ 1) * sizeof(WCHAR
));
163 if (Key
->Name
== NULL
)
165 DPRINT("RtlAllocateHeap() failed\n");
166 RtlFreeHeap(ProcessHeap
, 0, Key
);
170 /* Copy value name */
171 for (i
= 0; i
< NameLength
; i
++)
173 Key
->Name
[i
] = (WCHAR
)Name
[i
];
175 Key
->Name
[NameLength
] = 0;
177 Key
->Data
= (WCHAR
*)RtlAllocateHeap(ProcessHeap
,
179 (DataLength
+ 1) * sizeof(WCHAR
));
180 if (Key
->Data
== NULL
)
182 DPRINT("RtlAllocateHeap() failed\n");
183 RtlFreeHeap(ProcessHeap
, 0, Key
->Name
);
184 RtlFreeHeap(ProcessHeap
, 0, Key
);
188 /* Copy value data */
189 for (i
= 0; i
< DataLength
; i
++)
191 Key
->Data
[i
] = (WCHAR
)Data
[i
];
193 Key
->Data
[DataLength
] = 0;
196 if (Section
->FirstKey
== NULL
)
198 Section
->FirstKey
= Key
;
199 Section
->LastKey
= Key
;
203 Section
->LastKey
->Next
= Key
;
204 Key
->Prev
= Section
->LastKey
;
205 Section
->LastKey
= Key
;
220 PINICACHESECTION Section
= NULL
;
222 if (Cache
== NULL
|| Name
== NULL
|| NameLength
== 0)
227 Section
= Cache
->FirstSection
;
229 /* iterate through list of sections */
230 while (Section
!= NULL
)
232 if (NameLength
== wcslen(Section
->Name
))
234 /* are the contents the same too? */
235 if (_wcsnicmp(Section
->Name
, Name
, NameLength
) == 0)
239 /* get the next section*/
240 Section
= Section
->Next
;
255 PINICACHESECTION Section
= NULL
;
258 if (Cache
== NULL
|| Name
== NULL
|| NameLength
== 0)
260 DPRINT("Invalid parameter\n");
264 Section
= (PINICACHESECTION
)RtlAllocateHeap(ProcessHeap
,
266 sizeof(INICACHESECTION
));
269 DPRINT("RtlAllocateHeap() failed\n");
273 RtlZeroMemory(Section
, sizeof(INICACHESECTION
));
275 /* Allocate and initialize section name */
276 Section
->Name
= (WCHAR
*)RtlAllocateHeap(ProcessHeap
,
278 (NameLength
+ 1) * sizeof(WCHAR
));
279 if (Section
->Name
== NULL
)
281 DPRINT("RtlAllocateHeap() failed\n");
282 RtlFreeHeap(ProcessHeap
, 0, Section
);
286 /* Copy section name */
287 for (i
= 0; i
< NameLength
; i
++)
289 Section
->Name
[i
] = (WCHAR
)Name
[i
];
291 Section
->Name
[NameLength
] = 0;
294 if (Cache
->FirstSection
== NULL
)
296 Cache
->FirstSection
= Section
;
297 Cache
->LastSection
= Section
;
301 Cache
->LastSection
->Next
= Section
;
302 Section
->Prev
= Cache
->LastSection
;
303 Cache
->LastSection
= Section
;
312 IniCacheSkipWhitespace(
315 while (*Ptr
!= 0 && isspace(*Ptr
))
318 return (*Ptr
== 0) ? NULL
: Ptr
;
324 IniCacheSkipToNextSection(
327 while (*Ptr
!= 0 && *Ptr
!= '[')
329 while (*Ptr
!= 0 && *Ptr
!= L
'\n')
337 return (*Ptr
== 0) ? NULL
: Ptr
;
343 IniCacheGetSectionName(
354 /* skip whitespace */
355 while (*Ptr
!= 0 && isspace(*Ptr
))
362 while (*Ptr
!= 0 && *Ptr
!= ']')
369 while (*Ptr
!= 0 && *Ptr
!= L
'\n')
377 strncpy(Name
, *NamePtr
, Size
);
380 DPRINT("SectionName: '%s'\n", Name
);
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')
452 /* Skip whitespace */
453 while (*Ptr
!= 0 && isspace(*Ptr
))
458 /* Check and skip '=' */
465 /* Skip whitespace */
466 while (*Ptr
!= 0 && isspace(*Ptr
))
471 if (*Ptr
== '"' && String
)
484 while (*Ptr
&& *Ptr
!= '\r' && *Ptr
!= '\n')
493 while (*Ptr
!= 0 && *Ptr
!= '\r' && *Ptr
!= ';')
500 /* Skip to next line */
512 /* PUBLIC FUNCTIONS *********************************************************/
517 PUNICODE_STRING FileName
,
520 OBJECT_ATTRIBUTES ObjectAttributes
;
521 FILE_STANDARD_INFORMATION FileInfo
;
522 IO_STATUS_BLOCK IoStatusBlock
;
528 LARGE_INTEGER FileOffset
;
530 PINICACHESECTION Section
;
534 ULONG SectionNameSize
;
545 InitializeObjectAttributes(&ObjectAttributes
,
551 Status
= NtOpenFile(&FileHandle
,
552 GENERIC_READ
| SYNCHRONIZE
,
556 FILE_SYNCHRONOUS_IO_NONALERT
| FILE_NON_DIRECTORY_FILE
);
557 if (!NT_SUCCESS(Status
))
559 DPRINT("NtOpenFile() failed (Status %lx)\n", Status
);
563 DPRINT("NtOpenFile() successful\n");
565 /* Query file size */
566 Status
= NtQueryInformationFile(FileHandle
,
569 sizeof(FILE_STANDARD_INFORMATION
),
570 FileStandardInformation
);
571 if (!NT_SUCCESS(Status
))
573 DPRINT("NtQueryInformationFile() failed (Status %lx)\n", Status
);
578 FileLength
= FileInfo
.EndOfFile
.u
.LowPart
;
580 DPRINT("File size: %lu\n", FileLength
);
582 /* Allocate file buffer */
583 FileBuffer
= (CHAR
*)RtlAllocateHeap(ProcessHeap
,
586 if (FileBuffer
== NULL
)
588 DPRINT1("RtlAllocateHeap() failed\n");
590 return STATUS_INSUFFICIENT_RESOURCES
;
594 FileOffset
.QuadPart
= 0ULL;
595 Status
= NtReadFile(FileHandle
,
605 /* Append string terminator */
606 FileBuffer
[FileLength
] = 0;
610 if (!NT_SUCCESS(Status
))
612 DPRINT("NtReadFile() failed (Status %lx)\n", Status
);
613 RtlFreeHeap(ProcessHeap
, 0, FileBuffer
);
617 /* Allocate inicache header */
618 *Cache
= (PINICACHE
)RtlAllocateHeap(ProcessHeap
,
623 DPRINT("RtlAllocateHeap() failed\n");
624 return STATUS_INSUFFICIENT_RESOURCES
;
627 /* Initialize inicache header */
628 RtlZeroMemory(*Cache
, sizeof(INICACHE
));
633 while (Ptr
!= NULL
&& *Ptr
!= 0)
635 Ptr
= IniCacheSkipWhitespace(Ptr
);
644 Ptr
= IniCacheGetSectionName(Ptr
,
648 DPRINT1("[%.*s]\n", SectionNameSize
, SectionName
);
650 Section
= IniCacheAddSection(*Cache
,
655 DPRINT("IniCacheAddSection() failed\n");
656 Ptr
= IniCacheSkipToNextSection(Ptr
);
664 Ptr
= IniCacheSkipToNextSection(Ptr
);
668 Ptr
= IniCacheGetKeyName(Ptr
,
672 Ptr
= IniCacheGetKeyValue(Ptr
,
677 DPRINT1("'%.*s' = '%.*s'\n", KeyNameSize
, KeyName
, KeyValueSize
, KeyValue
);
679 Key
= IniCacheAddKey(Section
,
686 DPRINT("IniCacheAddKey() failed\n");
691 /* Free file buffer */
692 RtlFreeHeap(ProcessHeap
, 0, FileBuffer
);
707 while (Cache
->FirstSection
!= NULL
)
709 Cache
->FirstSection
= IniCacheFreeSection(Cache
->FirstSection
);
711 Cache
->LastSection
= NULL
;
713 RtlFreeHeap(ProcessHeap
, 0, Cache
);
722 PINICACHESECTION Section
= NULL
;
724 if (Cache
== NULL
|| Name
== NULL
)
726 DPRINT("Invalid parameter\n");
730 /* Iterate through list of sections */
731 Section
= Cache
->FirstSection
;
732 while (Section
!= NULL
)
734 DPRINT("Comparing '%S' and '%S'\n", Section
->Name
, Name
);
736 /* Are the section names the same? */
737 if (_wcsicmp(Section
->Name
, Name
) == 0)
740 /* Get the next section */
741 Section
= Section
->Next
;
744 DPRINT("Section not found\n");
752 PINICACHESECTION Section
,
758 if (Section
== NULL
|| KeyName
== NULL
|| KeyData
== NULL
)
760 DPRINT("Invalid parameter\n");
761 return STATUS_INVALID_PARAMETER
;
766 Key
= IniCacheFindKey(Section
, KeyName
, wcslen(KeyName
));
769 return STATUS_INVALID_PARAMETER
;
772 *KeyData
= Key
->Data
;
774 return STATUS_SUCCESS
;
779 IniCacheFindFirstValue(
780 PINICACHESECTION Section
,
784 PINICACHEITERATOR Iterator
;
787 if (Section
== NULL
|| KeyName
== NULL
|| KeyData
== NULL
)
789 DPRINT("Invalid parameter\n");
793 Key
= Section
->FirstKey
;
796 DPRINT("Invalid parameter\n");
800 *KeyName
= Key
->Name
;
801 *KeyData
= Key
->Data
;
803 Iterator
= (PINICACHEITERATOR
)RtlAllocateHeap(ProcessHeap
,
805 sizeof(INICACHEITERATOR
));
806 if (Iterator
== NULL
)
808 DPRINT("RtlAllocateHeap() failed\n");
812 Iterator
->Section
= Section
;
820 IniCacheFindNextValue(
821 PINICACHEITERATOR Iterator
,
827 if (Iterator
== NULL
|| KeyName
== NULL
|| KeyData
== NULL
)
829 DPRINT("Invalid parameter\n");
833 Key
= Iterator
->Key
->Next
;
836 DPRINT("No more entries\n");
840 *KeyName
= Key
->Name
;
841 *KeyData
= Key
->Data
;
851 PINICACHEITERATOR Iterator
)
853 if (Iterator
== NULL
)
856 RtlFreeHeap(ProcessHeap
, 0, Iterator
);
862 PINICACHESECTION Section
,
863 PINICACHEKEY AnchorKey
,
864 INSERTATION_TYPE InsertationType
,
872 if (Section
== NULL
||
878 DPRINT("Invalid parameter\n");
882 /* Allocate key buffer */
883 Key
= (PINICACHEKEY
)RtlAllocateHeap(ProcessHeap
,
885 sizeof(INICACHEKEY
));
888 DPRINT("RtlAllocateHeap() failed\n");
892 RtlZeroMemory(Key
, sizeof(INICACHEKEY
));
894 /* Allocate name buffer */
895 Key
->Name
= (WCHAR
*)RtlAllocateHeap(ProcessHeap
,
897 (wcslen(Name
) + 1) * sizeof(WCHAR
));
898 if (Key
->Name
== NULL
)
900 DPRINT("RtlAllocateHeap() failed\n");
901 RtlFreeHeap(ProcessHeap
, 0, Key
);
905 /* Copy value name */
906 wcscpy(Key
->Name
, Name
);
908 /* Allocate data buffer */
909 Key
->Data
= (WCHAR
*)RtlAllocateHeap(ProcessHeap
,
911 (wcslen(Data
) + 1) * sizeof(WCHAR
));
912 if (Key
->Data
== NULL
)
914 DPRINT("RtlAllocateHeap() failed\n");
915 RtlFreeHeap(ProcessHeap
, 0, Key
->Name
);
916 RtlFreeHeap(ProcessHeap
, 0, Key
);
920 /* Copy value data */
921 wcscpy(Key
->Data
, Data
);
923 /* Insert key into section */
924 if (Section
->FirstKey
== NULL
)
926 Section
->FirstKey
= Key
;
927 Section
->LastKey
= Key
;
929 else if ((InsertationType
== INSERT_FIRST
) ||
930 ((InsertationType
== INSERT_BEFORE
) && ((AnchorKey
== NULL
) || (AnchorKey
== Section
->FirstKey
))))
932 /* Insert at the head of the list */
933 Section
->FirstKey
->Prev
= Key
;
934 Key
->Next
= Section
->FirstKey
;
935 Section
->FirstKey
= Key
;
937 else if ((InsertationType
== INSERT_BEFORE
) && (AnchorKey
!= NULL
))
939 /* Insert before the anchor key */
940 Key
->Next
= AnchorKey
;
941 Key
->Prev
= AnchorKey
->Prev
;
942 AnchorKey
->Prev
->Next
= Key
;
943 AnchorKey
->Prev
= Key
;
945 else if ((InsertationType
== INSERT_LAST
) ||
946 ((InsertationType
== INSERT_AFTER
) && ((AnchorKey
== NULL
) || (AnchorKey
== Section
->LastKey
))))
948 Section
->LastKey
->Next
= Key
;
949 Key
->Prev
= Section
->LastKey
;
950 Section
->LastKey
= Key
;
952 else if ((InsertationType
== INSERT_AFTER
) && (AnchorKey
!= NULL
))
954 /* Insert after the anchor key */
955 Key
->Next
= AnchorKey
->Next
;
956 Key
->Prev
= AnchorKey
;
957 AnchorKey
->Next
->Prev
= Key
;
958 AnchorKey
->Next
= Key
;
970 /* Allocate inicache header */
971 Cache
= (PINICACHE
)RtlAllocateHeap(ProcessHeap
,
976 DPRINT("RtlAllocateHeap() failed\n");
980 /* Initialize inicache header */
981 RtlZeroMemory(Cache
, sizeof(INICACHE
));
993 PINICACHESECTION Section
;
1001 OBJECT_ATTRIBUTES ObjectAttributes
;
1002 IO_STATUS_BLOCK IoStatusBlock
;
1003 LARGE_INTEGER Offset
;
1007 /* Calculate required buffer size */
1009 Section
= Cache
->FirstSection
;
1010 while (Section
!= NULL
)
1012 BufferSize
+= (Section
->Name
? wcslen(Section
->Name
) : 0)
1015 Key
= Section
->FirstKey
;
1018 BufferSize
+= wcslen(Key
->Name
)
1019 + (Key
->Data
? wcslen(Key
->Data
) : 0)
1024 Section
= Section
->Next
;
1025 if (Section
!= NULL
)
1026 BufferSize
+= 2; /* extra "\r\n" at end of each section */
1028 BufferSize
++; /* Null-terminator */
1030 DPRINT("BufferSize: %lu\n", BufferSize
);
1032 /* Allocate file buffer */
1033 Buffer
= (CHAR
*)RtlAllocateHeap(ProcessHeap
,
1038 DPRINT1("RtlAllocateHeap() failed\n");
1039 return STATUS_INSUFFICIENT_RESOURCES
;
1042 RtlZeroMemory(Buffer
, BufferSize
);
1044 /* Fill file buffer */
1046 Section
= Cache
->FirstSection
;
1047 while (Section
!= NULL
)
1049 Len
= sprintf(Ptr
, "[%S]\r\n", Section
->Name
);
1052 Key
= Section
->FirstKey
;
1055 Len
= sprintf(Ptr
, "%S=%S\r\n", Key
->Name
, Key
->Data
);
1060 Section
= Section
->Next
;
1061 if (Section
!= NULL
)
1063 Len
= sprintf(Ptr
, "\r\n");
1068 /* Create ini file */
1069 RtlInitUnicodeString(&Name
,
1072 InitializeObjectAttributes(&ObjectAttributes
,
1078 Status
= NtCreateFile(&FileHandle
,
1079 GENERIC_WRITE
| SYNCHRONIZE
,
1083 FILE_ATTRIBUTE_NORMAL
,
1086 FILE_SYNCHRONOUS_IO_NONALERT
| FILE_SEQUENTIAL_ONLY
,
1089 if (!NT_SUCCESS(Status
))
1091 DPRINT("NtCreateFile() failed (Status %lx)\n", Status
);
1092 RtlFreeHeap(ProcessHeap
, 0, Buffer
);
1096 Offset
.QuadPart
= 0LL;
1097 Status
= NtWriteFile(FileHandle
,
1106 if (!NT_SUCCESS(Status
))
1108 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
1109 NtClose(FileHandle
);
1110 RtlFreeHeap(ProcessHeap
, 0, Buffer
);
1114 NtClose(FileHandle
);
1116 RtlFreeHeap(ProcessHeap
, 0, Buffer
);
1118 return STATUS_SUCCESS
;
1123 IniCacheAppendSection(
1127 PINICACHESECTION Section
= NULL
;
1129 if (Cache
== NULL
|| Name
== NULL
|| *Name
== 0)
1131 DPRINT("Invalid parameter\n");
1135 Section
= (PINICACHESECTION
)RtlAllocateHeap(ProcessHeap
,
1137 sizeof(INICACHESECTION
));
1138 if (Section
== NULL
)
1140 DPRINT("RtlAllocateHeap() failed\n");
1144 RtlZeroMemory(Section
, sizeof(INICACHESECTION
));
1146 /* Allocate and initialize section name */
1147 Section
->Name
= (WCHAR
*)RtlAllocateHeap(ProcessHeap
,
1149 (wcslen(Name
) + 1) * sizeof(WCHAR
));
1150 if (Section
->Name
== NULL
)
1152 DPRINT("RtlAllocateHeap() failed\n");
1153 RtlFreeHeap(ProcessHeap
, 0, Section
);
1157 /* Copy section name */
1158 wcscpy(Section
->Name
, Name
);
1160 /* Append section */
1161 if (Cache
->FirstSection
== NULL
)
1163 Cache
->FirstSection
= Section
;
1164 Cache
->LastSection
= Section
;
1168 Cache
->LastSection
->Next
= Section
;
1169 Section
->Prev
= Cache
->LastSection
;
1170 Cache
->LastSection
= Section
;