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