[CMAKE]
[reactos.git] / base / setup / usetup / inicache.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2002 ReactOS Team
4 *
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.
9 *
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.
14 *
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.
18 */
19 /* $Id$
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
25 * Eric Kohl
26 */
27
28 /* INCLUDES *****************************************************************/
29
30 #include "usetup.h"
31
32 #define NDEBUG
33 #include <debug.h>
34
35 /* PRIVATE FUNCTIONS ********************************************************/
36
37 static PINICACHEKEY
38 IniCacheFreeKey(PINICACHEKEY Key)
39 {
40 PINICACHEKEY Next;
41
42 if (Key == NULL)
43 {
44 return(NULL);
45 }
46
47 Next = Key->Next;
48 if (Key->Name != NULL)
49 {
50 RtlFreeHeap(ProcessHeap,
51 0,
52 Key->Name);
53 Key->Name = NULL;
54 }
55
56 if (Key->Data != NULL)
57 {
58 RtlFreeHeap(ProcessHeap,
59 0,
60 Key->Data);
61 Key->Data = NULL;
62 }
63
64 RtlFreeHeap(ProcessHeap,
65 0,
66 Key);
67
68 return(Next);
69 }
70
71
72 static PINICACHESECTION
73 IniCacheFreeSection(PINICACHESECTION Section)
74 {
75 PINICACHESECTION Next;
76
77 if (Section == NULL)
78 {
79 return(NULL);
80 }
81
82 Next = Section->Next;
83 while (Section->FirstKey != NULL)
84 {
85 Section->FirstKey = IniCacheFreeKey(Section->FirstKey);
86 }
87 Section->LastKey = NULL;
88
89 if (Section->Name != NULL)
90 {
91 RtlFreeHeap(ProcessHeap,
92 0,
93 Section->Name);
94 Section->Name = NULL;
95 }
96
97 RtlFreeHeap(ProcessHeap,
98 0,
99 Section);
100
101 return(Next);
102 }
103
104
105 static PINICACHEKEY
106 IniCacheFindKey(PINICACHESECTION Section,
107 PWCHAR Name,
108 ULONG NameLength)
109 {
110 PINICACHEKEY Key;
111
112 Key = Section->FirstKey;
113 while (Key != NULL)
114 {
115 if (NameLength == wcslen(Key->Name))
116 {
117 if (_wcsnicmp(Key->Name, Name, NameLength) == 0)
118 break;
119 }
120
121 Key = Key->Next;
122 }
123
124 return(Key);
125 }
126
127
128 static PINICACHEKEY
129 IniCacheAddKey(PINICACHESECTION Section,
130 PCHAR Name,
131 ULONG NameLength,
132 PCHAR Data,
133 ULONG DataLength)
134 {
135 PINICACHEKEY Key;
136 ULONG i;
137
138 Key = NULL;
139
140 if (Section == NULL ||
141 Name == NULL ||
142 NameLength == 0 ||
143 Data == NULL ||
144 DataLength == 0)
145 {
146 DPRINT("Invalid parameter\n");
147 return(NULL);
148 }
149
150 Key = (PINICACHEKEY)RtlAllocateHeap(ProcessHeap,
151 0,
152 sizeof(INICACHEKEY));
153 if (Key == NULL)
154 {
155 DPRINT("RtlAllocateHeap() failed\n");
156 return(NULL);
157 }
158
159 RtlZeroMemory(Key,
160 sizeof(INICACHEKEY));
161
162
163 Key->Name = (WCHAR*) RtlAllocateHeap(ProcessHeap,
164 0,
165 (NameLength + 1) * sizeof(WCHAR));
166 if (Key->Name == NULL)
167 {
168 DPRINT("RtlAllocateHeap() failed\n");
169 RtlFreeHeap(ProcessHeap,
170 0,
171 Key);
172 return(NULL);
173 }
174
175 /* Copy value name */
176 for (i = 0; i < NameLength; i++)
177 {
178 Key->Name[i] = (WCHAR)Name[i];
179 }
180 Key->Name[NameLength] = 0;
181
182
183 Key->Data = (WCHAR*) RtlAllocateHeap(ProcessHeap,
184 0,
185 (DataLength + 1) * sizeof(WCHAR));
186 if (Key->Data == NULL)
187 {
188 DPRINT("RtlAllocateHeap() failed\n");
189 RtlFreeHeap(ProcessHeap,
190 0,
191 Key->Name);
192 RtlFreeHeap(ProcessHeap,
193 0,
194 Key);
195 return(NULL);
196 }
197
198 /* Copy value data */
199 for (i = 0; i < DataLength; i++)
200 {
201 Key->Data[i] = (WCHAR)Data[i];
202 }
203 Key->Data[DataLength] = 0;
204
205
206 if (Section->FirstKey == NULL)
207 {
208 Section->FirstKey = Key;
209 Section->LastKey = Key;
210 }
211 else
212 {
213 Section->LastKey->Next = Key;
214 Key->Prev = Section->LastKey;
215 Section->LastKey = Key;
216 }
217
218 return(Key);
219 }
220
221 #if 0
222 static PINICACHESECTION
223 IniCacheFindSection(PINICACHE Cache,
224 PWCHAR Name,
225 ULONG NameLength)
226 {
227 PINICACHESECTION Section = NULL;
228
229 if (Cache == NULL || Name == NULL || NameLength == 0)
230 {
231 return(NULL);
232 }
233
234 Section = Cache->FirstSection;
235
236 /* iterate through list of sections */
237 while (Section != NULL)
238 {
239 if (NameLength == wcslen(Section->Name))
240 {
241 /* are the contents the same too? */
242 if (_wcsnicmp(Section->Name, Name, NameLength) == 0)
243 break;
244 }
245
246 /* get the next section*/
247 Section = Section->Next;
248 }
249
250 return(Section);
251 }
252 #endif
253
254 static PINICACHESECTION
255 IniCacheAddSection(PINICACHE Cache,
256 PCHAR Name,
257 ULONG NameLength)
258 {
259 PINICACHESECTION Section = NULL;
260 ULONG i;
261
262 if (Cache == NULL || Name == NULL || NameLength == 0)
263 {
264 DPRINT("Invalid parameter\n");
265 return(NULL);
266 }
267
268 Section = (PINICACHESECTION)RtlAllocateHeap(ProcessHeap,
269 0,
270 sizeof(INICACHESECTION));
271 if (Section == NULL)
272 {
273 DPRINT("RtlAllocateHeap() failed\n");
274 return(NULL);
275 }
276 RtlZeroMemory(Section,
277 sizeof(INICACHESECTION));
278
279 /* Allocate and initialize section name */
280 Section->Name = (WCHAR*) RtlAllocateHeap(ProcessHeap,
281 0,
282 (NameLength + 1) * sizeof(WCHAR));
283 if (Section->Name == NULL)
284 {
285 DPRINT("RtlAllocateHeap() failed\n");
286 RtlFreeHeap(ProcessHeap,
287 0,
288 Section);
289 return(NULL);
290 }
291
292 /* Copy section name */
293 for (i = 0; i < NameLength; i++)
294 {
295 Section->Name[i] = (WCHAR)Name[i];
296 }
297 Section->Name[NameLength] = 0;
298
299 /* Append section */
300 if (Cache->FirstSection == NULL)
301 {
302 Cache->FirstSection = Section;
303 Cache->LastSection = Section;
304 }
305 else
306 {
307 Cache->LastSection->Next = Section;
308 Section->Prev = Cache->LastSection;
309 Cache->LastSection = Section;
310 }
311
312 return(Section);
313 }
314
315
316 static PCHAR
317 IniCacheSkipWhitespace(PCHAR Ptr)
318 {
319 while (*Ptr != 0 && isspace(*Ptr))
320 Ptr++;
321
322 return((*Ptr == 0) ? NULL : Ptr);
323 }
324
325
326 static PCHAR
327 IniCacheSkipToNextSection(PCHAR Ptr)
328 {
329 while (*Ptr != 0 && *Ptr != '[')
330 {
331 while (*Ptr != 0 && *Ptr != L'\n')
332 {
333 Ptr++;
334 }
335 Ptr++;
336 }
337
338 return((*Ptr == 0) ? NULL : Ptr);
339 }
340
341
342 static PCHAR
343 IniCacheGetSectionName(PCHAR Ptr,
344 PCHAR *NamePtr,
345 PULONG NameSize)
346 {
347 ULONG Size = 0;
348 CHAR Name[256];
349
350 *NamePtr = NULL;
351 *NameSize = 0;
352
353 /* skip whitespace */
354 while (*Ptr != 0 && isspace(*Ptr))
355 {
356 Ptr++;
357 }
358
359 *NamePtr = Ptr;
360
361 while (*Ptr != 0 && *Ptr != ']')
362 {
363 Size++;
364 Ptr++;
365 }
366
367 Ptr++;
368
369 while (*Ptr != 0 && *Ptr != L'\n')
370 {
371 Ptr++;
372 }
373 Ptr++;
374
375 *NameSize = Size;
376
377 strncpy(Name, *NamePtr, Size);
378 Name[Size] = 0;
379
380 DPRINT("SectionName: '%s'\n", Name);
381
382 return(Ptr);
383 }
384
385
386 static PCHAR
387 IniCacheGetKeyName(PCHAR Ptr,
388 PCHAR *NamePtr,
389 PULONG NameSize)
390 {
391 ULONG Size = 0;
392
393 *NamePtr = NULL;
394 *NameSize = 0;
395
396 while(Ptr && *Ptr)
397 {
398 *NamePtr = NULL;
399 *NameSize = 0;
400 Size = 0;
401
402 /* skip whitespace and empty lines */
403 while (isspace(*Ptr) || *Ptr == '\n' || *Ptr == '\r')
404 {
405 Ptr++;
406 }
407 if (*Ptr == 0)
408 {
409 continue;
410 }
411
412 *NamePtr = Ptr;
413
414 while (*Ptr != 0 && !isspace(*Ptr) && *Ptr != '=' && *Ptr != ';')
415 {
416 Size++;
417 Ptr++;
418 }
419 if (*Ptr == ';')
420 {
421 while (*Ptr != 0 && *Ptr != '\r' && *Ptr != '\n')
422 {
423 Ptr++;
424 }
425 }
426 else
427 {
428 *NameSize = Size;
429 break;
430 }
431 }
432
433 return(Ptr);
434 }
435
436
437 static PCHAR
438 IniCacheGetKeyValue(PCHAR Ptr,
439 PCHAR *DataPtr,
440 PULONG DataSize,
441 BOOLEAN String)
442 {
443 ULONG Size = 0;
444
445 *DataPtr = NULL;
446 *DataSize = 0;
447
448 /* Skip whitespace */
449 while (*Ptr != 0 && isspace(*Ptr))
450 {
451 Ptr++;
452 }
453
454 /* Check and skip '=' */
455 if (*Ptr != '=')
456 {
457 return(NULL);
458 }
459 Ptr++;
460
461 /* Skip whitespace */
462 while (*Ptr != 0 && isspace(*Ptr))
463 {
464 Ptr++;
465 }
466
467 if (*Ptr == '"' && String)
468 {
469 Ptr++;
470
471 /* Get data */
472 *DataPtr = Ptr;
473 while (*Ptr != '"')
474 {
475 Ptr++;
476 Size++;
477 }
478 Ptr++;
479 while (*Ptr && *Ptr != '\r' && *Ptr != '\n')
480 {
481 Ptr++;
482 }
483 }
484 else
485 {
486 /* Get data */
487 *DataPtr = Ptr;
488 while (*Ptr != 0 && *Ptr != '\r' && *Ptr != ';')
489 {
490 Ptr++;
491 Size++;
492 }
493 }
494
495 /* Skip to next line */
496 if (*Ptr == '\r')
497 Ptr++;
498 if (*Ptr == '\n')
499 Ptr++;
500
501 *DataSize = Size;
502
503 return(Ptr);
504 }
505
506
507
508
509 /* PUBLIC FUNCTIONS *********************************************************/
510
511 NTSTATUS
512 IniCacheLoad(PINICACHE *Cache,
513 PUNICODE_STRING FileName,
514 BOOLEAN String)
515 {
516 OBJECT_ATTRIBUTES ObjectAttributes;
517 FILE_STANDARD_INFORMATION FileInfo;
518 IO_STATUS_BLOCK IoStatusBlock;
519 HANDLE FileHandle;
520 NTSTATUS Status;
521 PCHAR FileBuffer;
522 ULONG FileLength;
523 PCHAR Ptr;
524 LARGE_INTEGER FileOffset;
525
526 PINICACHESECTION Section;
527 PINICACHEKEY Key;
528
529 PCHAR SectionName;
530 ULONG SectionNameSize;
531
532 PCHAR KeyName;
533 ULONG KeyNameSize;
534
535 PCHAR KeyValue;
536 ULONG KeyValueSize;
537
538 *Cache = NULL;
539
540 /* Open ini file */
541 InitializeObjectAttributes(&ObjectAttributes,
542 FileName,
543 0,
544 NULL,
545 NULL);
546
547 Status = NtOpenFile(&FileHandle,
548 GENERIC_READ | SYNCHRONIZE,
549 &ObjectAttributes,
550 &IoStatusBlock,
551 FILE_SHARE_READ,
552 FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE);
553 if (!NT_SUCCESS(Status))
554 {
555 DPRINT("NtOpenFile() failed (Status %lx)\n", Status);
556 return(Status);
557 }
558
559 DPRINT("NtOpenFile() successful\n");
560
561 /* Query file size */
562 Status = NtQueryInformationFile(FileHandle,
563 &IoStatusBlock,
564 &FileInfo,
565 sizeof(FILE_STANDARD_INFORMATION),
566 FileStandardInformation);
567 if (!NT_SUCCESS(Status))
568 {
569 DPRINT("NtQueryInformationFile() failed (Status %lx)\n", Status);
570 NtClose(FileHandle);
571 return(Status);
572 }
573
574 FileLength = FileInfo.EndOfFile.u.LowPart;
575
576 DPRINT("File size: %lu\n", FileLength);
577
578 /* Allocate file buffer */
579 FileBuffer = (CHAR*) RtlAllocateHeap(ProcessHeap,
580 0,
581 FileLength + 1);
582 if (FileBuffer == NULL)
583 {
584 DPRINT1("RtlAllocateHeap() failed\n");
585 NtClose(FileHandle);
586 return(STATUS_INSUFFICIENT_RESOURCES);
587 }
588
589 /* Read file */
590 FileOffset.QuadPart = 0ULL;
591 Status = NtReadFile(FileHandle,
592 NULL,
593 NULL,
594 NULL,
595 &IoStatusBlock,
596 FileBuffer,
597 FileLength,
598 &FileOffset,
599 NULL);
600
601 /* Append string terminator */
602 FileBuffer[FileLength] = 0;
603
604 NtClose(FileHandle);
605
606 if (!NT_SUCCESS(Status))
607 {
608 DPRINT("NtReadFile() failed (Status %lx)\n", Status);
609 RtlFreeHeap(ProcessHeap,
610 0,
611 FileBuffer);
612 return(Status);
613 }
614
615
616 /* Allocate inicache header */
617 *Cache = (PINICACHE)RtlAllocateHeap(ProcessHeap,
618 0,
619 sizeof(INICACHE));
620 if (*Cache == NULL)
621 {
622 DPRINT("RtlAllocateHeap() failed\n");
623 return(STATUS_INSUFFICIENT_RESOURCES);
624 }
625
626 /* Initialize inicache header */
627 RtlZeroMemory(*Cache,
628 sizeof(INICACHE));
629
630 /* Parse ini file */
631 Section = NULL;
632 Ptr = FileBuffer;
633 while (Ptr != NULL && *Ptr != 0)
634 {
635 Ptr = IniCacheSkipWhitespace(Ptr);
636 if (Ptr == NULL)
637 continue;
638
639 if (*Ptr == '[')
640 {
641 Section = NULL;
642 Ptr++;
643
644 Ptr = IniCacheGetSectionName(Ptr,
645 &SectionName,
646 &SectionNameSize);
647
648 DPRINT1("[%.*s]\n", SectionNameSize, SectionName);
649
650 Section = IniCacheAddSection(*Cache,
651 SectionName,
652 SectionNameSize);
653 if (Section == NULL)
654 {
655 DPRINT("IniCacheAddSection() failed\n");
656 Ptr = IniCacheSkipToNextSection(Ptr);
657 continue;
658 }
659 }
660 else
661 {
662 if (Section == NULL)
663 {
664 Ptr = IniCacheSkipToNextSection(Ptr);
665 continue;
666 }
667
668 Ptr = IniCacheGetKeyName(Ptr,
669 &KeyName,
670 &KeyNameSize);
671
672 Ptr = IniCacheGetKeyValue(Ptr,
673 &KeyValue,
674 &KeyValueSize,
675 String);
676
677 DPRINT1("'%.*s' = '%.*s'\n", KeyNameSize, KeyName, KeyValueSize, KeyValue);
678
679 Key = IniCacheAddKey(Section,
680 KeyName,
681 KeyNameSize,
682 KeyValue,
683 KeyValueSize);
684 if (Key == NULL)
685 {
686 DPRINT("IniCacheAddKey() failed\n");
687 }
688 }
689 }
690
691 /* Free file buffer */
692 RtlFreeHeap(ProcessHeap,
693 0,
694 FileBuffer);
695
696 return(Status);
697 }
698
699
700 VOID
701 IniCacheDestroy(PINICACHE Cache)
702 {
703 if (Cache == NULL)
704 {
705 return;
706 }
707
708 while (Cache->FirstSection != NULL)
709 {
710 Cache->FirstSection = IniCacheFreeSection(Cache->FirstSection);
711 }
712 Cache->LastSection = NULL;
713
714 RtlFreeHeap(ProcessHeap,
715 0,
716 Cache);
717 }
718
719
720 PINICACHESECTION
721 IniCacheGetSection(PINICACHE Cache,
722 PWCHAR Name)
723 {
724 PINICACHESECTION Section = NULL;
725
726 if (Cache == NULL || Name == NULL)
727 {
728 DPRINT("Invalid parameter\n");
729 return(NULL);
730 }
731
732 /* Iterate through list of sections */
733 Section = Cache->FirstSection;
734 while (Section != NULL)
735 {
736 DPRINT("Comparing '%S' and '%S'\n", Section->Name, Name);
737
738 /* Are the section names the same? */
739 if (_wcsicmp(Section->Name, Name) == 0)
740 return(Section);
741
742 /* Get the next section */
743 Section = Section->Next;
744 }
745
746 DPRINT("Section not found\n");
747
748 return(NULL);
749 }
750
751
752 NTSTATUS
753 IniCacheGetKey(PINICACHESECTION Section,
754 PWCHAR KeyName,
755 PWCHAR *KeyData)
756 {
757 PINICACHEKEY Key;
758
759 if (Section == NULL || KeyName == NULL || KeyData == NULL)
760 {
761 DPRINT("Invalid parameter\n");
762 return(STATUS_INVALID_PARAMETER);
763 }
764
765 *KeyData = NULL;
766
767 Key = IniCacheFindKey(Section, KeyName, wcslen(KeyName));
768 if (Key == NULL)
769 {
770 return(STATUS_INVALID_PARAMETER);
771 }
772
773 *KeyData = Key->Data;
774
775 return(STATUS_SUCCESS);
776 }
777
778
779 PINICACHEITERATOR
780 IniCacheFindFirstValue(PINICACHESECTION Section,
781 PWCHAR *KeyName,
782 PWCHAR *KeyData)
783 {
784 PINICACHEITERATOR Iterator;
785 PINICACHEKEY Key;
786
787 if (Section == NULL || KeyName == NULL || KeyData == NULL)
788 {
789 DPRINT("Invalid parameter\n");
790 return(NULL);
791 }
792
793 Key = Section->FirstKey;
794 if (Key == NULL)
795 {
796 DPRINT("Invalid parameter\n");
797 return(NULL);
798 }
799
800 *KeyName = Key->Name;
801 *KeyData = Key->Data;
802
803 Iterator = (PINICACHEITERATOR)RtlAllocateHeap(ProcessHeap,
804 0,
805 sizeof(INICACHEITERATOR));
806 if (Iterator == NULL)
807 {
808 DPRINT("RtlAllocateHeap() failed\n");
809 return(NULL);
810 }
811
812 Iterator->Section = Section;
813 Iterator->Key = Key;
814
815 return(Iterator);
816 }
817
818
819 BOOLEAN
820 IniCacheFindNextValue(PINICACHEITERATOR Iterator,
821 PWCHAR *KeyName,
822 PWCHAR *KeyData)
823 {
824 PINICACHEKEY Key;
825
826 if (Iterator == NULL || KeyName == NULL || KeyData == NULL)
827 {
828 DPRINT("Invalid parameter\n");
829 return(FALSE);
830 }
831
832 Key = Iterator->Key->Next;
833 if (Key == NULL)
834 {
835 DPRINT("No more entries\n");
836 return(FALSE);
837 }
838
839 *KeyName = Key->Name;
840 *KeyData = Key->Data;
841
842 Iterator->Key = Key;
843
844 return(TRUE);
845 }
846
847
848 VOID
849 IniCacheFindClose(PINICACHEITERATOR Iterator)
850 {
851 if (Iterator == NULL)
852 return;
853
854 RtlFreeHeap(ProcessHeap,
855 0,
856 Iterator);
857 }
858
859
860 PINICACHEKEY
861 IniCacheInsertKey(PINICACHESECTION Section,
862 PINICACHEKEY AnchorKey,
863 INSERTATION_TYPE InsertationType,
864 PWCHAR Name,
865 PWCHAR Data)
866 {
867 PINICACHEKEY Key;
868
869 Key = NULL;
870
871 if (Section == NULL ||
872 Name == NULL ||
873 *Name == 0 ||
874 Data == NULL ||
875 *Data == 0)
876 {
877 DPRINT("Invalid parameter\n");
878 return(NULL);
879 }
880
881 /* Allocate key buffer */
882 Key = (PINICACHEKEY)RtlAllocateHeap(ProcessHeap,
883 0,
884 sizeof(INICACHEKEY));
885 if (Key == NULL)
886 {
887 DPRINT("RtlAllocateHeap() failed\n");
888 return(NULL);
889 }
890 RtlZeroMemory(Key,
891 sizeof(INICACHEKEY));
892
893 /* Allocate name buffer */
894 Key->Name = (WCHAR*) RtlAllocateHeap(ProcessHeap,
895 0,
896 (wcslen(Name) + 1) * sizeof(WCHAR));
897 if (Key->Name == NULL)
898 {
899 DPRINT("RtlAllocateHeap() failed\n");
900 RtlFreeHeap(ProcessHeap,
901 0,
902 Key);
903 return(NULL);
904 }
905
906 /* Copy value name */
907 wcscpy(Key->Name, Name);
908
909 /* Allocate data buffer */
910 Key->Data = (WCHAR*) RtlAllocateHeap(ProcessHeap,
911 0,
912 (wcslen(Data) + 1) * sizeof(WCHAR));
913 if (Key->Data == NULL)
914 {
915 DPRINT("RtlAllocateHeap() failed\n");
916 RtlFreeHeap(ProcessHeap,
917 0,
918 Key->Name);
919 RtlFreeHeap(ProcessHeap,
920 0,
921 Key);
922 return(NULL);
923 }
924
925 /* Copy value data */
926 wcscpy(Key->Data, Data);
927
928 /* Insert key into section */
929 if (Section->FirstKey == NULL)
930 {
931 Section->FirstKey = Key;
932 Section->LastKey = Key;
933 }
934 else if ((InsertationType == INSERT_FIRST) ||
935 ((InsertationType == INSERT_BEFORE) && ((AnchorKey == NULL) || (AnchorKey == Section->FirstKey))))
936 {
937 /* Insert at the head of the list */
938 Section->FirstKey->Prev = Key;
939 Key->Next = Section->FirstKey;
940 Section->FirstKey = Key;
941 }
942 else if ((InsertationType == INSERT_BEFORE) && (AnchorKey != NULL))
943 {
944 /* Insert before the anchor key */
945 Key->Next = AnchorKey;
946 Key->Prev = AnchorKey->Prev;
947 AnchorKey->Prev->Next = Key;
948 AnchorKey->Prev = Key;
949 }
950 else if ((InsertationType == INSERT_LAST) ||
951 ((InsertationType == INSERT_AFTER) && ((AnchorKey == NULL) || (AnchorKey == Section->LastKey))))
952 {
953 Section->LastKey->Next = Key;
954 Key->Prev = Section->LastKey;
955 Section->LastKey = Key;
956 }
957 else if ((InsertationType == INSERT_AFTER) && (AnchorKey != NULL))
958 {
959 /* Insert before the anchor key */
960 Key->Next = AnchorKey->Next;
961 Key->Prev = AnchorKey;
962 AnchorKey->Next->Prev = Key;
963 AnchorKey->Next = Key;
964 }
965
966 return(Key);
967 }
968
969
970 PINICACHE
971 IniCacheCreate(VOID)
972 {
973 PINICACHE Cache;
974
975 /* Allocate inicache header */
976 Cache = (PINICACHE)RtlAllocateHeap(ProcessHeap,
977 0,
978 sizeof(INICACHE));
979 if (Cache == NULL)
980 {
981 DPRINT("RtlAllocateHeap() failed\n");
982 return(NULL);
983 }
984
985 /* Initialize inicache header */
986 RtlZeroMemory(Cache,
987 sizeof(INICACHE));
988
989 return(Cache);
990 }
991
992
993 NTSTATUS
994 IniCacheSave(PINICACHE Cache,
995 PWCHAR FileName)
996 {
997 UNICODE_STRING Name;
998 PINICACHESECTION Section;
999 PINICACHEKEY Key;
1000 ULONG BufferSize;
1001 PCHAR Buffer;
1002 PCHAR Ptr;
1003 ULONG Len;
1004 NTSTATUS Status;
1005
1006 OBJECT_ATTRIBUTES ObjectAttributes;
1007 IO_STATUS_BLOCK IoStatusBlock;
1008 LARGE_INTEGER Offset;
1009 HANDLE FileHandle;
1010
1011
1012 /* Calculate required buffer size */
1013 BufferSize = 0;
1014 Section = Cache->FirstSection;
1015 while (Section != NULL)
1016 {
1017 BufferSize += (Section->Name ? wcslen(Section->Name) : 0)
1018 + 4; /* "[]\r\n" */
1019
1020 Key = Section->FirstKey;
1021 while (Key != NULL)
1022 {
1023 BufferSize += wcslen(Key->Name)
1024 + (Key->Data ? wcslen(Key->Data) : 0)
1025 + 3; /* "=\r\n" */
1026 Key = Key->Next;
1027 }
1028
1029 Section = Section->Next;
1030 if (Section != NULL)
1031 BufferSize += 2; /* extra "\r\n" at end of each section */
1032 }
1033 BufferSize++; /* Null-terminator */
1034
1035 DPRINT("BufferSize: %lu\n", BufferSize);
1036
1037 /* Allocate file buffer */
1038 Buffer = (CHAR*) RtlAllocateHeap(ProcessHeap,
1039 0,
1040 BufferSize);
1041 if (Buffer == NULL)
1042 {
1043 DPRINT1("RtlAllocateHeap() failed\n");
1044 return(STATUS_INSUFFICIENT_RESOURCES);
1045 }
1046 RtlZeroMemory(Buffer, BufferSize);
1047
1048 /* Fill file buffer */
1049 Ptr = Buffer;
1050 Section = Cache->FirstSection;
1051 while (Section != NULL)
1052 {
1053 Len = sprintf(Ptr, "[%S]\r\n", Section->Name);
1054 Ptr += Len;
1055
1056 Key = Section->FirstKey;
1057 while (Key != NULL)
1058 {
1059 Len = sprintf(Ptr, "%S=%S\r\n", Key->Name, Key->Data);
1060 Ptr += Len;
1061 Key = Key->Next;
1062 }
1063
1064 Section = Section->Next;
1065 if (Section != NULL)
1066 {
1067 Len = sprintf(Ptr, "\r\n");
1068 Ptr += Len;
1069 }
1070 }
1071
1072 /* Create ini file */
1073 RtlInitUnicodeString(&Name,
1074 FileName);
1075
1076 InitializeObjectAttributes(&ObjectAttributes,
1077 &Name,
1078 0,
1079 NULL,
1080 NULL);
1081
1082 Status = NtCreateFile(&FileHandle,
1083 GENERIC_WRITE,
1084 &ObjectAttributes,
1085 &IoStatusBlock,
1086 NULL,
1087 FILE_ATTRIBUTE_NORMAL,
1088 0,
1089 FILE_SUPERSEDE,
1090 FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY,
1091 NULL,
1092 0);
1093 if (!NT_SUCCESS(Status))
1094 {
1095 DPRINT("NtCreateFile() failed (Status %lx)\n", Status);
1096 RtlFreeHeap(ProcessHeap,
1097 0,
1098 Buffer);
1099 return(Status);
1100 }
1101
1102 Offset.QuadPart = 0LL;
1103 Status = NtWriteFile(FileHandle,
1104 NULL,
1105 NULL,
1106 NULL,
1107 &IoStatusBlock,
1108 Buffer,
1109 BufferSize,
1110 &Offset,
1111 NULL);
1112 if (!NT_SUCCESS(Status))
1113 {
1114 DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
1115 NtClose(FileHandle);
1116 RtlFreeHeap(ProcessHeap,
1117 0,
1118 Buffer);
1119 return(Status);
1120 }
1121
1122 NtClose(FileHandle);
1123
1124 RtlFreeHeap(ProcessHeap,
1125 0,
1126 Buffer);
1127
1128 return(STATUS_SUCCESS);
1129 }
1130
1131
1132 PINICACHESECTION
1133 IniCacheAppendSection(PINICACHE Cache,
1134 PWCHAR Name)
1135 {
1136 PINICACHESECTION Section = NULL;
1137
1138 if (Cache == NULL || Name == NULL || *Name == 0)
1139 {
1140 DPRINT("Invalid parameter\n");
1141 return(NULL);
1142 }
1143
1144 Section = (PINICACHESECTION)RtlAllocateHeap(ProcessHeap,
1145 0,
1146 sizeof(INICACHESECTION));
1147 if (Section == NULL)
1148 {
1149 DPRINT("RtlAllocateHeap() failed\n");
1150 return(NULL);
1151 }
1152 RtlZeroMemory(Section,
1153 sizeof(INICACHESECTION));
1154
1155 /* Allocate and initialize section name */
1156 Section->Name = (WCHAR*) RtlAllocateHeap(ProcessHeap,
1157 0,
1158 (wcslen(Name) + 1) * sizeof(WCHAR));
1159 if (Section->Name == NULL)
1160 {
1161 DPRINT("RtlAllocateHeap() failed\n");
1162 RtlFreeHeap(ProcessHeap,
1163 0,
1164 Section);
1165 return(NULL);
1166 }
1167
1168 /* Copy section name */
1169 wcscpy(Section->Name, Name);
1170
1171 /* Append section */
1172 if (Cache->FirstSection == NULL)
1173 {
1174 Cache->FirstSection = Section;
1175 Cache->LastSection = Section;
1176 }
1177 else
1178 {
1179 Cache->LastSection->Next = Section;
1180 Section->Prev = Cache->LastSection;
1181 Cache->LastSection = Section;
1182 }
1183
1184 return(Section);
1185 }
1186
1187 /* EOF */