1 /* 2 * PROJECT: .inf file parser 3 * LICENSE: GPL - See COPYING in the top level directory 4 * COPYRIGHT: Copyright 2005 Ge van Geldorp <gvg@reactos.org> 5 */ 6 7 /* INCLUDES *****************************************************************/ 8 9 #include "inflib.h" 10 11 #define NDEBUG 12 #include <debug.h> 13 14 #define EOL L"\r\n" 15 #define SIZE_INC 1024 16 17 typedef struct _OUTPUTBUFFER 18 { 19 PWCHAR Buffer; 20 PWCHAR Current; 21 ULONG TotalSize; 22 ULONG FreeSize; 23 INFSTATUS Status; 24 } OUTPUTBUFFER, *POUTPUTBUFFER; 25 26 static void 27 Output(POUTPUTBUFFER OutBuf, PCWSTR Text) 28 { 29 ULONG Length; 30 PWCHAR NewBuf; 31 ULONG NewSize; 32 33 /* Skip mode? */ 34 if (! INF_SUCCESS(OutBuf->Status)) 35 { 36 return; 37 } 38 39 /* Doesn't fit? */ 40 Length = (ULONG)strlenW(Text) * sizeof(WCHAR); 41 if (OutBuf->FreeSize < Length + 1 && INF_SUCCESS(OutBuf->Status)) 42 { 43 DPRINT("Out of free space. TotalSize %u FreeSize %u Length %u\n", 44 (UINT)OutBuf->TotalSize, (UINT)OutBuf->FreeSize, (UINT)Length); 45 /* Round up to next SIZE_INC */ 46 NewSize = OutBuf->TotalSize + 47 (((Length + 1) - OutBuf->FreeSize + (SIZE_INC - 1)) / 48 SIZE_INC) * SIZE_INC; 49 DPRINT("NewSize %u\n", (UINT)NewSize); 50 NewBuf = MALLOC(NewSize); 51 /* Abort if failed */ 52 if (NULL == NewBuf) 53 { 54 DPRINT1("MALLOC() failed\n"); 55 OutBuf->Status = INF_STATUS_NO_MEMORY; 56 return; 57 } 58 59 /* Need to copy old contents? */ 60 if (NULL != OutBuf->Buffer) 61 { 62 DPRINT("Copying %u bytes from old content\n", 63 (UINT)(OutBuf->TotalSize - OutBuf->FreeSize)); 64 MEMCPY(NewBuf, OutBuf->Buffer, OutBuf->TotalSize - OutBuf->FreeSize); 65 OutBuf->Current = NewBuf + (OutBuf->Current - OutBuf->Buffer); 66 FREE(OutBuf->Buffer); 67 } 68 else 69 { 70 OutBuf->Current = NewBuf; 71 } 72 OutBuf->Buffer = NewBuf; 73 OutBuf->FreeSize += NewSize - OutBuf->TotalSize; 74 OutBuf->TotalSize = NewSize; 75 DPRINT("After reallocation TotalSize %u FreeSize %u\n", 76 (UINT)OutBuf->TotalSize, (UINT)OutBuf->FreeSize); 77 } 78 79 /* We're guaranteed to have enough room now. Copy char by char because of 80 possible "conversion" from Unicode to Ansi */ 81 while (Length--) 82 { 83 *OutBuf->Current++ = *Text++; 84 OutBuf->FreeSize--; 85 } 86 *OutBuf->Current = '\0'; 87 } 88 89 INFSTATUS 90 InfpBuildFileBuffer(PINFCACHE Cache, 91 PWCHAR *Buffer, 92 PULONG BufferSize) 93 { 94 OUTPUTBUFFER OutBuf; 95 PINFCACHESECTION CacheSection; 96 PINFCACHELINE CacheLine; 97 PINFCACHEFIELD CacheField; 98 PWCHAR p; 99 BOOLEAN NeedQuotes; 100 101 OutBuf.Buffer = NULL; 102 OutBuf.Current = NULL; 103 OutBuf.FreeSize = 0; 104 OutBuf.TotalSize = 0; 105 OutBuf.Status = INF_STATUS_SUCCESS; 106 107 /* Iterate through list of sections */ 108 CacheSection = Cache->FirstSection; 109 while (CacheSection != NULL) 110 { 111 DPRINT("Processing section %S\n", CacheSection->Name); 112 if (CacheSection != Cache->FirstSection) 113 { 114 Output(&OutBuf, EOL); 115 } 116 Output(&OutBuf, L"["); 117 Output(&OutBuf, CacheSection->Name); 118 Output(&OutBuf, L"]"); 119 Output(&OutBuf, EOL); 120 121 /* Iterate through list of lines */ 122 CacheLine = CacheSection->FirstLine; 123 while (CacheLine != NULL) 124 { 125 if (NULL != CacheLine->Key) 126 { 127 DPRINT("Line with key %S\n", CacheLine->Key); 128 Output(&OutBuf, CacheLine->Key); 129 Output(&OutBuf, L" = "); 130 } 131 else 132 { 133 DPRINT("Line without key\n"); 134 } 135 136 /* Iterate through list of lines */ 137 CacheField = CacheLine->FirstField; 138 while (CacheField != NULL) 139 { 140 if (CacheField != CacheLine->FirstField) 141 { 142 Output(&OutBuf, L","); 143 } 144 p = CacheField->Data; 145 NeedQuotes = FALSE; 146 while (L'\0' != *p && ! NeedQuotes) 147 { 148 NeedQuotes = (BOOLEAN)(L',' == *p || L';' == *p || 149 L'\\' == *p); 150 p++; 151 } 152 if (NeedQuotes) 153 { 154 Output(&OutBuf, L"\""); 155 Output(&OutBuf, CacheField->Data); 156 Output(&OutBuf, L"\""); 157 } 158 else 159 { 160 Output(&OutBuf, CacheField->Data); 161 } 162 163 /* Get the next field */ 164 CacheField = CacheField->Next; 165 } 166 167 Output(&OutBuf, EOL); 168 /* Get the next line */ 169 CacheLine = CacheLine->Next; 170 } 171 172 /* Get the next section */ 173 CacheSection = CacheSection->Next; 174 } 175 176 if (INF_SUCCESS(OutBuf.Status)) 177 { 178 *Buffer = OutBuf.Buffer; 179 *BufferSize = OutBuf.TotalSize - OutBuf.FreeSize; 180 } 181 else if (NULL != OutBuf.Buffer) 182 { 183 FREE(OutBuf.Buffer); 184 } 185 186 return INF_STATUS_SUCCESS; 187 } 188 189 INFSTATUS 190 InfpFindOrAddSection(PINFCACHE Cache, 191 PCWSTR Section, 192 PINFCONTEXT *Context) 193 { 194 PINFCACHESECTION CacheSection; 195 DPRINT("InfpFindOrAddSection section %S\n", Section); 196 197 *Context = MALLOC(sizeof(INFCONTEXT)); 198 if (NULL == *Context) 199 { 200 DPRINT1("MALLOC() failed\n"); 201 return INF_STATUS_NO_MEMORY; 202 } 203 204 (*Context)->Inf = Cache; 205 (*Context)->Line = 0; 206 CacheSection = InfpFindSection(Cache, Section); 207 if (NULL == CacheSection) 208 { 209 DPRINT("Section not found, creating it\n"); 210 CacheSection = InfpAddSection(Cache, Section); 211 if (NULL == CacheSection) 212 { 213 DPRINT("Failed to create section\n"); 214 FREE(*Context); 215 return INF_STATUS_NO_MEMORY; 216 } 217 } 218 219 (*Context)->Section = CacheSection->Id; 220 return INF_STATUS_SUCCESS; 221 } 222 223 INFSTATUS 224 InfpAddLineWithKey(PINFCONTEXT Context, PCWSTR Key) 225 { 226 PINFCACHESECTION Section; 227 PINFCACHELINE Line; 228 229 if (NULL == Context) 230 { 231 DPRINT1("Invalid parameter\n"); 232 return INF_STATUS_INVALID_PARAMETER; 233 } 234 235 Section = InfpGetSectionForContext(Context); 236 Line = InfpAddLine(Section); 237 if (NULL == Line) 238 { 239 DPRINT("Failed to create line\n"); 240 return INF_STATUS_NO_MEMORY; 241 } 242 Context->Line = Line->Id; 243 244 if (NULL != Key && NULL == InfpAddKeyToLine(Line, Key)) 245 { 246 DPRINT("Failed to add key\n"); 247 return INF_STATUS_NO_MEMORY; 248 } 249 250 return INF_STATUS_SUCCESS; 251 } 252 253 INFSTATUS 254 InfpAddField(PINFCONTEXT Context, PCWSTR Data) 255 { 256 PINFCACHELINE Line; 257 258 if (NULL == Context) 259 { 260 DPRINT1("Invalid parameter\n"); 261 return INF_STATUS_INVALID_PARAMETER; 262 } 263 264 Line = InfpGetLineForContext(Context); 265 if (NULL == InfpAddFieldToLine(Line, Data)) 266 { 267 DPRINT("Failed to add field\n"); 268 return INF_STATUS_NO_MEMORY; 269 } 270 271 return INF_STATUS_SUCCESS; 272 } 273 274 /* EOF */ 275