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 ********************************************************/
48 if (Key
->Name
!= NULL
)
50 RtlFreeHeap(ProcessHeap
, 0, Key
->Name
);
54 if (Key
->Data
!= NULL
)
56 RtlFreeHeap(ProcessHeap
, 0, Key
->Data
);
60 RtlFreeHeap(ProcessHeap
, 0, Key
);
69 PINICACHESECTION Section
)
71 PINICACHESECTION Next
;
77 while (Section
->FirstKey
!= NULL
)
79 Section
->FirstKey
= IniCacheFreeKey(Section
->FirstKey
);
81 Section
->LastKey
= NULL
;
83 if (Section
->Name
!= NULL
)
85 RtlFreeHeap(ProcessHeap
, 0, Section
->Name
);
89 RtlFreeHeap(ProcessHeap
, 0, Section
);
98 PINICACHESECTION Section
,
104 Key
= Section
->FirstKey
;
107 if (NameLength
== wcslen(Key
->Name
))
109 if (_wcsnicmp(Key
->Name
, Name
, NameLength
) == 0)
123 PINICACHESECTION Section
,
134 if (Section
== NULL
||
140 DPRINT("Invalid parameter\n");
144 Key
= (PINICACHEKEY
)RtlAllocateHeap(ProcessHeap
,
146 sizeof(INICACHEKEY
));
149 DPRINT("RtlAllocateHeap() failed\n");
153 Key
->Name
= (WCHAR
*)RtlAllocateHeap(ProcessHeap
,
155 (NameLength
+ 1) * sizeof(WCHAR
));
156 if (Key
->Name
== NULL
)
158 DPRINT("RtlAllocateHeap() failed\n");
159 RtlFreeHeap(ProcessHeap
, 0, Key
);
163 /* Copy value name */
164 for (i
= 0; i
< NameLength
; i
++)
166 Key
->Name
[i
] = (WCHAR
)Name
[i
];
168 Key
->Name
[NameLength
] = 0;
170 Key
->Data
= (WCHAR
*)RtlAllocateHeap(ProcessHeap
,
172 (DataLength
+ 1) * sizeof(WCHAR
));
173 if (Key
->Data
== NULL
)
175 DPRINT("RtlAllocateHeap() failed\n");
176 RtlFreeHeap(ProcessHeap
, 0, Key
->Name
);
177 RtlFreeHeap(ProcessHeap
, 0, Key
);
181 /* Copy value data */
182 for (i
= 0; i
< DataLength
; i
++)
184 Key
->Data
[i
] = (WCHAR
)Data
[i
];
186 Key
->Data
[DataLength
] = 0;
189 if (Section
->FirstKey
== NULL
)
191 Section
->FirstKey
= Key
;
192 Section
->LastKey
= Key
;
196 Section
->LastKey
->Next
= Key
;
197 Key
->Prev
= Section
->LastKey
;
198 Section
->LastKey
= Key
;
212 PINICACHESECTION Section
= NULL
;
215 if (Cache
== NULL
|| Name
== NULL
|| NameLength
== 0)
217 DPRINT("Invalid parameter\n");
221 Section
= (PINICACHESECTION
)RtlAllocateHeap(ProcessHeap
,
223 sizeof(INICACHESECTION
));
226 DPRINT("RtlAllocateHeap() failed\n");
230 /* Allocate and initialize section name */
231 Section
->Name
= (WCHAR
*)RtlAllocateHeap(ProcessHeap
,
233 (NameLength
+ 1) * sizeof(WCHAR
));
234 if (Section
->Name
== NULL
)
236 DPRINT("RtlAllocateHeap() failed\n");
237 RtlFreeHeap(ProcessHeap
, 0, Section
);
241 /* Copy section name */
242 for (i
= 0; i
< NameLength
; i
++)
244 Section
->Name
[i
] = (WCHAR
)Name
[i
];
246 Section
->Name
[NameLength
] = 0;
249 if (Cache
->FirstSection
== NULL
)
251 Cache
->FirstSection
= Section
;
252 Cache
->LastSection
= Section
;
256 Cache
->LastSection
->Next
= Section
;
257 Section
->Prev
= Cache
->LastSection
;
258 Cache
->LastSection
= Section
;
267 IniCacheSkipWhitespace(
270 while (*Ptr
!= 0 && isspace(*Ptr
))
273 return (*Ptr
== 0) ? NULL
: Ptr
;
279 IniCacheSkipToNextSection(
282 while (*Ptr
!= 0 && *Ptr
!= '[')
284 while (*Ptr
!= 0 && *Ptr
!= L
'\n')
292 return (*Ptr
== 0) ? NULL
: Ptr
;
298 IniCacheGetSectionName(
309 /* Skip whitespace */
310 while (*Ptr
!= 0 && isspace(*Ptr
))
317 while (*Ptr
!= 0 && *Ptr
!= ']')
324 while (*Ptr
!= 0 && *Ptr
!= L
'\n')
332 strncpy(Name
, *NamePtr
, Size
);
335 DPRINT("SectionName: '%s'\n", Name
);
359 /* Skip whitespace and empty lines */
360 while (isspace(*Ptr
) || *Ptr
== '\n' || *Ptr
== '\r')
371 while (*Ptr
!= 0 && !isspace(*Ptr
) && *Ptr
!= '=' && *Ptr
!= ';')
378 while (*Ptr
!= 0 && *Ptr
!= '\r' && *Ptr
!= '\n')
407 /* Skip whitespace */
408 while (*Ptr
!= 0 && isspace(*Ptr
))
413 /* Check and skip '=' */
420 /* Skip whitespace */
421 while (*Ptr
!= 0 && isspace(*Ptr
))
426 if (*Ptr
== '"' && String
)
439 while (*Ptr
&& *Ptr
!= '\r' && *Ptr
!= '\n')
448 while (*Ptr
!= 0 && *Ptr
!= '\r' && *Ptr
!= ';')
455 /* Skip to next line */
467 /* PUBLIC FUNCTIONS *********************************************************/
476 OBJECT_ATTRIBUTES ObjectAttributes
;
477 FILE_STANDARD_INFORMATION FileInfo
;
478 IO_STATUS_BLOCK IoStatusBlock
;
484 LARGE_INTEGER FileOffset
;
486 PINICACHESECTION Section
;
490 ULONG SectionNameSize
;
501 RtlInitUnicodeString(&Name
, FileName
);
503 InitializeObjectAttributes(&ObjectAttributes
,
509 Status
= NtOpenFile(&FileHandle
,
510 GENERIC_READ
| SYNCHRONIZE
,
514 FILE_SYNCHRONOUS_IO_NONALERT
| FILE_NON_DIRECTORY_FILE
);
515 if (!NT_SUCCESS(Status
))
517 DPRINT("NtOpenFile() failed (Status %lx)\n", Status
);
521 DPRINT("NtOpenFile() successful\n");
523 /* Query file size */
524 Status
= NtQueryInformationFile(FileHandle
,
527 sizeof(FILE_STANDARD_INFORMATION
),
528 FileStandardInformation
);
529 if (!NT_SUCCESS(Status
))
531 DPRINT("NtQueryInformationFile() failed (Status %lx)\n", Status
);
536 FileLength
= FileInfo
.EndOfFile
.u
.LowPart
;
538 DPRINT("File size: %lu\n", FileLength
);
540 /* Allocate file buffer with NULL-terminator */
541 FileBuffer
= (CHAR
*)RtlAllocateHeap(ProcessHeap
,
544 if (FileBuffer
== NULL
)
546 DPRINT1("RtlAllocateHeap() failed\n");
548 return STATUS_INSUFFICIENT_RESOURCES
;
552 FileOffset
.QuadPart
= 0ULL;
553 Status
= NtReadFile(FileHandle
,
563 /* Append NULL-terminator */
564 FileBuffer
[FileLength
] = 0;
568 if (!NT_SUCCESS(Status
))
570 DPRINT("NtReadFile() failed (Status %lx)\n", Status
);
571 RtlFreeHeap(ProcessHeap
, 0, FileBuffer
);
575 /* Allocate inicache header */
576 *Cache
= (PINICACHE
)RtlAllocateHeap(ProcessHeap
,
581 DPRINT("RtlAllocateHeap() failed\n");
582 return STATUS_INSUFFICIENT_RESOURCES
;
588 while (Ptr
!= NULL
&& *Ptr
!= 0)
590 Ptr
= IniCacheSkipWhitespace(Ptr
);
599 Ptr
= IniCacheGetSectionName(Ptr
,
603 DPRINT1("[%.*s]\n", SectionNameSize
, SectionName
);
605 Section
= IniCacheAddSection(*Cache
,
610 DPRINT("IniCacheAddSection() failed\n");
611 Ptr
= IniCacheSkipToNextSection(Ptr
);
619 Ptr
= IniCacheSkipToNextSection(Ptr
);
623 Ptr
= IniCacheGetKeyName(Ptr
,
627 Ptr
= IniCacheGetKeyValue(Ptr
,
632 DPRINT1("'%.*s' = '%.*s'\n", KeyNameSize
, KeyName
, KeyValueSize
, KeyValue
);
634 Key
= IniCacheAddKey(Section
,
641 DPRINT("IniCacheAddKey() failed\n");
646 /* Free file buffer */
647 RtlFreeHeap(ProcessHeap
, 0, FileBuffer
);
660 while (Cache
->FirstSection
!= NULL
)
662 Cache
->FirstSection
= IniCacheFreeSection(Cache
->FirstSection
);
664 Cache
->LastSection
= NULL
;
666 RtlFreeHeap(ProcessHeap
, 0, Cache
);
675 PINICACHESECTION Section
= NULL
;
677 if (Cache
== NULL
|| Name
== NULL
)
679 DPRINT("Invalid parameter\n");
683 /* Iterate through list of sections */
684 Section
= Cache
->FirstSection
;
685 while (Section
!= NULL
)
687 DPRINT("Comparing '%S' and '%S'\n", Section
->Name
, Name
);
689 /* Are the section names the same? */
690 if (_wcsicmp(Section
->Name
, Name
) == 0)
693 /* Get the next section */
694 Section
= Section
->Next
;
697 DPRINT("Section not found\n");
705 PINICACHESECTION Section
,
711 if (Section
== NULL
|| KeyName
== NULL
|| KeyData
== NULL
)
713 DPRINT("Invalid parameter\n");
714 return STATUS_INVALID_PARAMETER
;
719 Key
= IniCacheFindKey(Section
, KeyName
, wcslen(KeyName
));
722 return STATUS_INVALID_PARAMETER
;
725 *KeyData
= Key
->Data
;
727 return STATUS_SUCCESS
;
732 IniCacheFindFirstValue(
733 PINICACHESECTION Section
,
737 PINICACHEITERATOR Iterator
;
740 if (Section
== NULL
|| KeyName
== NULL
|| KeyData
== NULL
)
742 DPRINT("Invalid parameter\n");
746 Key
= Section
->FirstKey
;
749 DPRINT("Invalid parameter\n");
753 *KeyName
= Key
->Name
;
754 *KeyData
= Key
->Data
;
756 Iterator
= (PINICACHEITERATOR
)RtlAllocateHeap(ProcessHeap
,
758 sizeof(INICACHEITERATOR
));
759 if (Iterator
== NULL
)
761 DPRINT("RtlAllocateHeap() failed\n");
765 Iterator
->Section
= Section
;
773 IniCacheFindNextValue(
774 PINICACHEITERATOR Iterator
,
780 if (Iterator
== NULL
|| KeyName
== NULL
|| KeyData
== NULL
)
782 DPRINT("Invalid parameter\n");
786 Key
= Iterator
->Key
->Next
;
789 DPRINT("No more entries\n");
793 *KeyName
= Key
->Name
;
794 *KeyData
= Key
->Data
;
804 PINICACHEITERATOR Iterator
)
806 if (Iterator
== NULL
)
809 RtlFreeHeap(ProcessHeap
, 0, Iterator
);
815 PINICACHESECTION Section
,
816 PINICACHEKEY AnchorKey
,
817 INSERTATION_TYPE InsertationType
,
825 if (Section
== NULL
||
831 DPRINT("Invalid parameter\n");
835 /* Allocate key buffer */
836 Key
= (PINICACHEKEY
)RtlAllocateHeap(ProcessHeap
,
838 sizeof(INICACHEKEY
));
841 DPRINT("RtlAllocateHeap() failed\n");
845 /* Allocate name buffer */
846 Key
->Name
= (WCHAR
*)RtlAllocateHeap(ProcessHeap
,
848 (wcslen(Name
) + 1) * sizeof(WCHAR
));
849 if (Key
->Name
== NULL
)
851 DPRINT("RtlAllocateHeap() failed\n");
852 RtlFreeHeap(ProcessHeap
, 0, Key
);
856 /* Copy value name */
857 wcscpy(Key
->Name
, Name
);
859 /* Allocate data buffer */
860 Key
->Data
= (WCHAR
*)RtlAllocateHeap(ProcessHeap
,
862 (wcslen(Data
) + 1) * sizeof(WCHAR
));
863 if (Key
->Data
== NULL
)
865 DPRINT("RtlAllocateHeap() failed\n");
866 RtlFreeHeap(ProcessHeap
, 0, Key
->Name
);
867 RtlFreeHeap(ProcessHeap
, 0, Key
);
871 /* Copy value data */
872 wcscpy(Key
->Data
, Data
);
874 /* Insert key into section */
875 if (Section
->FirstKey
== NULL
)
877 Section
->FirstKey
= Key
;
878 Section
->LastKey
= Key
;
880 else if ((InsertationType
== INSERT_FIRST
) ||
881 ((InsertationType
== INSERT_BEFORE
) && ((AnchorKey
== NULL
) || (AnchorKey
== Section
->FirstKey
))))
883 /* Insert at the head of the list */
884 Section
->FirstKey
->Prev
= Key
;
885 Key
->Next
= Section
->FirstKey
;
886 Section
->FirstKey
= Key
;
888 else if ((InsertationType
== INSERT_BEFORE
) && (AnchorKey
!= NULL
))
890 /* Insert before the anchor key */
891 Key
->Next
= AnchorKey
;
892 Key
->Prev
= AnchorKey
->Prev
;
893 AnchorKey
->Prev
->Next
= Key
;
894 AnchorKey
->Prev
= Key
;
896 else if ((InsertationType
== INSERT_LAST
) ||
897 ((InsertationType
== INSERT_AFTER
) && ((AnchorKey
== NULL
) || (AnchorKey
== Section
->LastKey
))))
899 Section
->LastKey
->Next
= Key
;
900 Key
->Prev
= Section
->LastKey
;
901 Section
->LastKey
= Key
;
903 else if ((InsertationType
== INSERT_AFTER
) && (AnchorKey
!= NULL
))
905 /* Insert after the anchor key */
906 Key
->Next
= AnchorKey
->Next
;
907 Key
->Prev
= AnchorKey
;
908 AnchorKey
->Next
->Prev
= Key
;
909 AnchorKey
->Next
= Key
;
921 /* Allocate inicache header */
922 Cache
= (PINICACHE
)RtlAllocateHeap(ProcessHeap
,
927 DPRINT("RtlAllocateHeap() failed\n");
941 PINICACHESECTION Section
;
949 OBJECT_ATTRIBUTES ObjectAttributes
;
950 IO_STATUS_BLOCK IoStatusBlock
;
951 LARGE_INTEGER Offset
;
955 /* Calculate required buffer size */
957 Section
= Cache
->FirstSection
;
958 while (Section
!= NULL
)
960 BufferSize
+= (Section
->Name
? wcslen(Section
->Name
) : 0)
963 Key
= Section
->FirstKey
;
966 BufferSize
+= wcslen(Key
->Name
)
967 + (Key
->Data
? wcslen(Key
->Data
) : 0)
972 Section
= Section
->Next
;
974 BufferSize
+= 2; /* Extra "\r\n" at end of each section */
977 DPRINT("BufferSize: %lu\n", BufferSize
);
979 /* Allocate file buffer with NULL-terminator */
980 Buffer
= (CHAR
*)RtlAllocateHeap(ProcessHeap
,
985 DPRINT1("RtlAllocateHeap() failed\n");
986 return STATUS_INSUFFICIENT_RESOURCES
;
989 /* Fill file buffer */
991 Section
= Cache
->FirstSection
;
992 while (Section
!= NULL
)
994 Len
= sprintf(Ptr
, "[%S]\r\n", Section
->Name
);
997 Key
= Section
->FirstKey
;
1000 Len
= sprintf(Ptr
, "%S=%S\r\n", Key
->Name
, Key
->Data
);
1005 Section
= Section
->Next
;
1006 if (Section
!= NULL
)
1008 Len
= sprintf(Ptr
, "\r\n");
1013 /* Create ini file */
1014 RtlInitUnicodeString(&Name
, FileName
);
1016 InitializeObjectAttributes(&ObjectAttributes
,
1022 Status
= NtCreateFile(&FileHandle
,
1023 GENERIC_WRITE
| SYNCHRONIZE
,
1027 FILE_ATTRIBUTE_NORMAL
,
1030 FILE_SYNCHRONOUS_IO_NONALERT
| FILE_SEQUENTIAL_ONLY
,
1033 if (!NT_SUCCESS(Status
))
1035 DPRINT("NtCreateFile() failed (Status %lx)\n", Status
);
1036 RtlFreeHeap(ProcessHeap
, 0, Buffer
);
1040 Offset
.QuadPart
= 0LL;
1041 Status
= NtWriteFile(FileHandle
,
1050 if (!NT_SUCCESS(Status
))
1052 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
1053 NtClose(FileHandle
);
1054 RtlFreeHeap(ProcessHeap
, 0, Buffer
);
1058 NtClose(FileHandle
);
1060 RtlFreeHeap(ProcessHeap
, 0, Buffer
);
1062 return STATUS_SUCCESS
;
1067 IniCacheAppendSection(
1071 PINICACHESECTION Section
= NULL
;
1073 if (Cache
== NULL
|| Name
== NULL
|| *Name
== 0)
1075 DPRINT("Invalid parameter\n");
1079 Section
= (PINICACHESECTION
)RtlAllocateHeap(ProcessHeap
,
1081 sizeof(INICACHESECTION
));
1082 if (Section
== NULL
)
1084 DPRINT("RtlAllocateHeap() failed\n");
1088 /* Allocate and initialize section name */
1089 Section
->Name
= (WCHAR
*)RtlAllocateHeap(ProcessHeap
,
1091 (wcslen(Name
) + 1) * sizeof(WCHAR
));
1092 if (Section
->Name
== NULL
)
1094 DPRINT("RtlAllocateHeap() failed\n");
1095 RtlFreeHeap(ProcessHeap
, 0, Section
);
1099 /* Copy section name */
1100 wcscpy(Section
->Name
, Name
);
1102 /* Append section */
1103 if (Cache
->FirstSection
== NULL
)
1105 Cache
->FirstSection
= Section
;
1106 Cache
->LastSection
= Section
;
1110 Cache
->LastSection
->Next
= Section
;
1111 Section
->Prev
= Cache
->LastSection
;
1112 Cache
->LastSection
= Section
;