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: 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 *****************************************************************/
35 /* PRIVATE FUNCTIONS ********************************************************/
38 IniCacheFreeKey(PINICACHEKEY Key
)
48 if (Key
->Name
!= NULL
)
50 RtlFreeHeap(ProcessHeap
,
56 if (Key
->Data
!= NULL
)
58 RtlFreeHeap(ProcessHeap
,
64 RtlFreeHeap(ProcessHeap
,
72 static PINICACHESECTION
73 IniCacheFreeSection(PINICACHESECTION Section
)
75 PINICACHESECTION Next
;
83 while (Section
->FirstKey
!= NULL
)
85 Section
->FirstKey
= IniCacheFreeKey(Section
->FirstKey
);
87 Section
->LastKey
= NULL
;
89 if (Section
->Name
!= NULL
)
91 RtlFreeHeap(ProcessHeap
,
97 RtlFreeHeap(ProcessHeap
,
106 IniCacheFindKey(PINICACHESECTION Section
,
112 Key
= Section
->FirstKey
;
115 if (NameLength
== wcslen(Key
->Name
))
117 if (_wcsnicmp(Key
->Name
, Name
, NameLength
) == 0)
129 IniCacheAddKey(PINICACHESECTION Section
,
140 if (Section
== NULL
||
146 DPRINT("Invalid parameter\n");
150 Key
= (PINICACHEKEY
)RtlAllocateHeap(ProcessHeap
,
152 sizeof(INICACHEKEY
));
155 DPRINT("RtlAllocateHeap() failed\n");
160 sizeof(INICACHEKEY
));
163 Key
->Name
= (WCHAR
*) RtlAllocateHeap(ProcessHeap
,
165 (NameLength
+ 1) * sizeof(WCHAR
));
166 if (Key
->Name
== NULL
)
168 DPRINT("RtlAllocateHeap() failed\n");
169 RtlFreeHeap(ProcessHeap
,
175 /* Copy value name */
176 for (i
= 0; i
< NameLength
; i
++)
178 Key
->Name
[i
] = (WCHAR
)Name
[i
];
180 Key
->Name
[NameLength
] = 0;
183 Key
->Data
= (WCHAR
*) RtlAllocateHeap(ProcessHeap
,
185 (DataLength
+ 1) * sizeof(WCHAR
));
186 if (Key
->Data
== NULL
)
188 DPRINT("RtlAllocateHeap() failed\n");
189 RtlFreeHeap(ProcessHeap
,
192 RtlFreeHeap(ProcessHeap
,
198 /* Copy value data */
199 for (i
= 0; i
< DataLength
; i
++)
201 Key
->Data
[i
] = (WCHAR
)Data
[i
];
203 Key
->Data
[DataLength
] = 0;
206 if (Section
->FirstKey
== NULL
)
208 Section
->FirstKey
= Key
;
209 Section
->LastKey
= Key
;
213 Section
->LastKey
->Next
= Key
;
214 Key
->Prev
= Section
->LastKey
;
215 Section
->LastKey
= Key
;
222 static PINICACHESECTION
223 IniCacheFindSection(PINICACHE Cache
,
227 PINICACHESECTION Section
= NULL
;
229 if (Cache
== NULL
|| Name
== NULL
|| NameLength
== 0)
234 Section
= Cache
->FirstSection
;
236 /* iterate through list of sections */
237 while (Section
!= NULL
)
239 if (NameLength
== wcslen(Section
->Name
))
241 /* are the contents the same too? */
242 if (_wcsnicmp(Section
->Name
, Name
, NameLength
) == 0)
246 /* get the next section*/
247 Section
= Section
->Next
;
254 static PINICACHESECTION
255 IniCacheAddSection(PINICACHE Cache
,
259 PINICACHESECTION Section
= NULL
;
262 if (Cache
== NULL
|| Name
== NULL
|| NameLength
== 0)
264 DPRINT("Invalid parameter\n");
268 Section
= (PINICACHESECTION
)RtlAllocateHeap(ProcessHeap
,
270 sizeof(INICACHESECTION
));
273 DPRINT("RtlAllocateHeap() failed\n");
276 RtlZeroMemory(Section
,
277 sizeof(INICACHESECTION
));
279 /* Allocate and initialize section name */
280 Section
->Name
= (WCHAR
*) RtlAllocateHeap(ProcessHeap
,
282 (NameLength
+ 1) * sizeof(WCHAR
));
283 if (Section
->Name
== NULL
)
285 DPRINT("RtlAllocateHeap() failed\n");
286 RtlFreeHeap(ProcessHeap
,
292 /* Copy section name */
293 for (i
= 0; i
< NameLength
; i
++)
295 Section
->Name
[i
] = (WCHAR
)Name
[i
];
297 Section
->Name
[NameLength
] = 0;
300 if (Cache
->FirstSection
== NULL
)
302 Cache
->FirstSection
= Section
;
303 Cache
->LastSection
= Section
;
307 Cache
->LastSection
->Next
= Section
;
308 Section
->Prev
= Cache
->LastSection
;
309 Cache
->LastSection
= Section
;
317 IniCacheSkipWhitespace(PCHAR Ptr
)
319 while (*Ptr
!= 0 && isspace(*Ptr
))
322 return((*Ptr
== 0) ? NULL
: Ptr
);
327 IniCacheSkipToNextSection(PCHAR Ptr
)
329 while (*Ptr
!= 0 && *Ptr
!= '[')
331 while (*Ptr
!= 0 && *Ptr
!= L
'\n')
338 return((*Ptr
== 0) ? NULL
: Ptr
);
343 IniCacheGetSectionName(PCHAR Ptr
,
353 /* skip whitespace */
354 while (*Ptr
!= 0 && isspace(*Ptr
))
361 while (*Ptr
!= 0 && *Ptr
!= ']')
369 while (*Ptr
!= 0 && *Ptr
!= L
'\n')
377 strncpy(Name
, *NamePtr
, Size
);
380 DPRINT("SectionName: '%s'\n", Name
);
387 IniCacheGetKeyName(PCHAR Ptr
,
402 /* skip whitespace and empty lines */
403 while (isspace(*Ptr
) || *Ptr
== '\n' || *Ptr
== '\r')
414 while (*Ptr
!= 0 && !isspace(*Ptr
) && *Ptr
!= '=' && *Ptr
!= ';')
421 while (*Ptr
!= 0 && *Ptr
!= '\r' && *Ptr
!= '\n')
438 IniCacheGetKeyValue(PCHAR Ptr
,
448 /* Skip whitespace */
449 while (*Ptr
!= 0 && isspace(*Ptr
))
454 /* Check and skip '=' */
461 /* Skip whitespace */
462 while (*Ptr
!= 0 && isspace(*Ptr
))
467 if (*Ptr
== '"' && String
)
479 while (*Ptr
&& *Ptr
!= '\r' && *Ptr
!= '\n')
488 while (*Ptr
!= 0 && *Ptr
!= '\r' && *Ptr
!= ';')
495 /* Skip to next line */
509 /* PUBLIC FUNCTIONS *********************************************************/
512 IniCacheLoad(PINICACHE
*Cache
,
513 PUNICODE_STRING FileName
,
516 OBJECT_ATTRIBUTES ObjectAttributes
;
517 FILE_STANDARD_INFORMATION FileInfo
;
518 IO_STATUS_BLOCK IoStatusBlock
;
524 LARGE_INTEGER FileOffset
;
526 PINICACHESECTION Section
;
530 ULONG SectionNameSize
;
541 InitializeObjectAttributes(&ObjectAttributes
,
547 Status
= NtOpenFile(&FileHandle
,
548 GENERIC_READ
| SYNCHRONIZE
,
552 FILE_SYNCHRONOUS_IO_NONALERT
| FILE_NON_DIRECTORY_FILE
);
553 if (!NT_SUCCESS(Status
))
555 DPRINT("NtOpenFile() failed (Status %lx)\n", Status
);
559 DPRINT("NtOpenFile() successful\n");
561 /* Query file size */
562 Status
= NtQueryInformationFile(FileHandle
,
565 sizeof(FILE_STANDARD_INFORMATION
),
566 FileStandardInformation
);
567 if (!NT_SUCCESS(Status
))
569 DPRINT("NtQueryInformationFile() failed (Status %lx)\n", Status
);
574 FileLength
= FileInfo
.EndOfFile
.u
.LowPart
;
576 DPRINT("File size: %lu\n", FileLength
);
578 /* Allocate file buffer */
579 FileBuffer
= (CHAR
*) RtlAllocateHeap(ProcessHeap
,
582 if (FileBuffer
== NULL
)
584 DPRINT1("RtlAllocateHeap() failed\n");
586 return(STATUS_INSUFFICIENT_RESOURCES
);
590 FileOffset
.QuadPart
= 0ULL;
591 Status
= NtReadFile(FileHandle
,
601 /* Append string terminator */
602 FileBuffer
[FileLength
] = 0;
606 if (!NT_SUCCESS(Status
))
608 DPRINT("NtReadFile() failed (Status %lx)\n", Status
);
609 RtlFreeHeap(ProcessHeap
,
616 /* Allocate inicache header */
617 *Cache
= (PINICACHE
)RtlAllocateHeap(ProcessHeap
,
622 DPRINT("RtlAllocateHeap() failed\n");
623 return(STATUS_INSUFFICIENT_RESOURCES
);
626 /* Initialize inicache header */
627 RtlZeroMemory(*Cache
,
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
,
701 IniCacheDestroy(PINICACHE Cache
)
708 while (Cache
->FirstSection
!= NULL
)
710 Cache
->FirstSection
= IniCacheFreeSection(Cache
->FirstSection
);
712 Cache
->LastSection
= NULL
;
714 RtlFreeHeap(ProcessHeap
,
721 IniCacheGetSection(PINICACHE Cache
,
724 PINICACHESECTION Section
= NULL
;
726 if (Cache
== NULL
|| Name
== NULL
)
728 DPRINT("Invalid parameter\n");
732 /* Iterate through list of sections */
733 Section
= Cache
->FirstSection
;
734 while (Section
!= NULL
)
736 DPRINT("Comparing '%S' and '%S'\n", Section
->Name
, Name
);
738 /* Are the section names the same? */
739 if (_wcsicmp(Section
->Name
, Name
) == 0)
742 /* Get the next section */
743 Section
= Section
->Next
;
746 DPRINT("Section not found\n");
753 IniCacheGetKey(PINICACHESECTION Section
,
759 if (Section
== NULL
|| KeyName
== NULL
|| KeyData
== NULL
)
761 DPRINT("Invalid parameter\n");
762 return(STATUS_INVALID_PARAMETER
);
767 Key
= IniCacheFindKey(Section
, KeyName
, wcslen(KeyName
));
770 return(STATUS_INVALID_PARAMETER
);
773 *KeyData
= Key
->Data
;
775 return(STATUS_SUCCESS
);
780 IniCacheFindFirstValue(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(PINICACHEITERATOR Iterator
,
826 if (Iterator
== NULL
|| KeyName
== NULL
|| KeyData
== NULL
)
828 DPRINT("Invalid parameter\n");
832 Key
= Iterator
->Key
->Next
;
835 DPRINT("No more entries\n");
839 *KeyName
= Key
->Name
;
840 *KeyData
= Key
->Data
;
849 IniCacheFindClose(PINICACHEITERATOR Iterator
)
851 if (Iterator
== NULL
)
854 RtlFreeHeap(ProcessHeap
,
861 IniCacheInsertKey(PINICACHESECTION Section
,
862 PINICACHEKEY AnchorKey
,
863 INSERTATION_TYPE InsertationType
,
871 if (Section
== NULL
||
877 DPRINT("Invalid parameter\n");
881 /* Allocate key buffer */
882 Key
= (PINICACHEKEY
)RtlAllocateHeap(ProcessHeap
,
884 sizeof(INICACHEKEY
));
887 DPRINT("RtlAllocateHeap() failed\n");
891 sizeof(INICACHEKEY
));
893 /* Allocate name buffer */
894 Key
->Name
= (WCHAR
*) RtlAllocateHeap(ProcessHeap
,
896 (wcslen(Name
) + 1) * sizeof(WCHAR
));
897 if (Key
->Name
== NULL
)
899 DPRINT("RtlAllocateHeap() failed\n");
900 RtlFreeHeap(ProcessHeap
,
906 /* Copy value name */
907 wcscpy(Key
->Name
, Name
);
909 /* Allocate data buffer */
910 Key
->Data
= (WCHAR
*) RtlAllocateHeap(ProcessHeap
,
912 (wcslen(Data
) + 1) * sizeof(WCHAR
));
913 if (Key
->Data
== NULL
)
915 DPRINT("RtlAllocateHeap() failed\n");
916 RtlFreeHeap(ProcessHeap
,
919 RtlFreeHeap(ProcessHeap
,
925 /* Copy value data */
926 wcscpy(Key
->Data
, Data
);
928 /* Insert key into section */
929 if (Section
->FirstKey
== NULL
)
931 Section
->FirstKey
= Key
;
932 Section
->LastKey
= Key
;
934 else if ((InsertationType
== INSERT_FIRST
) ||
935 ((InsertationType
== INSERT_BEFORE
) && ((AnchorKey
== NULL
) || (AnchorKey
== Section
->FirstKey
))))
937 /* Insert at the head of the list */
938 Section
->FirstKey
->Prev
= Key
;
939 Key
->Next
= Section
->FirstKey
;
940 Section
->FirstKey
= Key
;
942 else if ((InsertationType
== INSERT_BEFORE
) && (AnchorKey
!= NULL
))
944 /* Insert before the anchor key */
945 Key
->Next
= AnchorKey
;
946 Key
->Prev
= AnchorKey
->Prev
;
947 AnchorKey
->Prev
->Next
= Key
;
948 AnchorKey
->Prev
= Key
;
950 else if ((InsertationType
== INSERT_LAST
) ||
951 ((InsertationType
== INSERT_AFTER
) && ((AnchorKey
== NULL
) || (AnchorKey
== Section
->LastKey
))))
953 Section
->LastKey
->Next
= Key
;
954 Key
->Prev
= Section
->LastKey
;
955 Section
->LastKey
= Key
;
957 else if ((InsertationType
== INSERT_AFTER
) && (AnchorKey
!= NULL
))
959 /* Insert before the anchor key */
960 Key
->Next
= AnchorKey
->Next
;
961 Key
->Prev
= AnchorKey
;
962 AnchorKey
->Next
->Prev
= Key
;
963 AnchorKey
->Next
= Key
;
975 /* Allocate inicache header */
976 Cache
= (PINICACHE
)RtlAllocateHeap(ProcessHeap
,
981 DPRINT("RtlAllocateHeap() failed\n");
985 /* Initialize inicache header */
994 IniCacheSave(PINICACHE Cache
,
998 PINICACHESECTION Section
;
1006 OBJECT_ATTRIBUTES ObjectAttributes
;
1007 IO_STATUS_BLOCK IoStatusBlock
;
1008 LARGE_INTEGER Offset
;
1012 /* Calculate required buffer size */
1014 Section
= Cache
->FirstSection
;
1015 while (Section
!= NULL
)
1017 BufferSize
+= (Section
->Name
? wcslen(Section
->Name
) : 0)
1020 Key
= Section
->FirstKey
;
1023 BufferSize
+= wcslen(Key
->Name
)
1024 + (Key
->Data
? wcslen(Key
->Data
) : 0)
1029 Section
= Section
->Next
;
1030 if (Section
!= NULL
)
1031 BufferSize
+= 2; /* extra "\r\n" at end of each section */
1033 BufferSize
++; /* Null-terminator */
1035 DPRINT("BufferSize: %lu\n", BufferSize
);
1037 /* Allocate file buffer */
1038 Buffer
= (CHAR
*) RtlAllocateHeap(ProcessHeap
,
1043 DPRINT1("RtlAllocateHeap() failed\n");
1044 return(STATUS_INSUFFICIENT_RESOURCES
);
1046 RtlZeroMemory(Buffer
, BufferSize
);
1048 /* Fill file buffer */
1050 Section
= Cache
->FirstSection
;
1051 while (Section
!= NULL
)
1053 Len
= sprintf(Ptr
, "[%S]\r\n", Section
->Name
);
1056 Key
= Section
->FirstKey
;
1059 Len
= sprintf(Ptr
, "%S=%S\r\n", Key
->Name
, Key
->Data
);
1064 Section
= Section
->Next
;
1065 if (Section
!= NULL
)
1067 Len
= sprintf(Ptr
, "\r\n");
1072 /* Create ini file */
1073 RtlInitUnicodeString(&Name
,
1076 InitializeObjectAttributes(&ObjectAttributes
,
1082 Status
= NtCreateFile(&FileHandle
,
1087 FILE_ATTRIBUTE_NORMAL
,
1090 FILE_SYNCHRONOUS_IO_NONALERT
| FILE_SEQUENTIAL_ONLY
,
1093 if (!NT_SUCCESS(Status
))
1095 DPRINT("NtCreateFile() failed (Status %lx)\n", Status
);
1096 RtlFreeHeap(ProcessHeap
,
1102 Offset
.QuadPart
= 0LL;
1103 Status
= NtWriteFile(FileHandle
,
1112 if (!NT_SUCCESS(Status
))
1114 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
1115 NtClose(FileHandle
);
1116 RtlFreeHeap(ProcessHeap
,
1122 NtClose(FileHandle
);
1124 RtlFreeHeap(ProcessHeap
,
1128 return(STATUS_SUCCESS
);
1133 IniCacheAppendSection(PINICACHE Cache
,
1136 PINICACHESECTION Section
= NULL
;
1138 if (Cache
== NULL
|| Name
== NULL
|| *Name
== 0)
1140 DPRINT("Invalid parameter\n");
1144 Section
= (PINICACHESECTION
)RtlAllocateHeap(ProcessHeap
,
1146 sizeof(INICACHESECTION
));
1147 if (Section
== NULL
)
1149 DPRINT("RtlAllocateHeap() failed\n");
1152 RtlZeroMemory(Section
,
1153 sizeof(INICACHESECTION
));
1155 /* Allocate and initialize section name */
1156 Section
->Name
= (WCHAR
*) RtlAllocateHeap(ProcessHeap
,
1158 (wcslen(Name
) + 1) * sizeof(WCHAR
));
1159 if (Section
->Name
== NULL
)
1161 DPRINT("RtlAllocateHeap() failed\n");
1162 RtlFreeHeap(ProcessHeap
,
1168 /* Copy section name */
1169 wcscpy(Section
->Name
, Name
);
1171 /* Append section */
1172 if (Cache
->FirstSection
== NULL
)
1174 Cache
->FirstSection
= Section
;
1175 Cache
->LastSection
= Section
;
1179 Cache
->LastSection
->Next
= Section
;
1180 Section
->Prev
= Cache
->LastSection
;
1181 Cache
->LastSection
= Section
;