1 /* 2 * PROJECT: .inf file parser 3 * LICENSE: GPL - See COPYING in the top level directory 4 * PROGRAMMER: Royce Mitchell III 5 * Eric Kohl 6 * Ge van Geldorp <gvg@reactos.org> 7 */ 8 9 /* INCLUDES *****************************************************************/ 10 11 #include "inflib.h" 12 #include "infros.h" 13 14 #define NDEBUG 15 #include <debug.h> 16 17 /* PRIVATE FUNCTIONS ********************************************************/ 18 19 static int InfpHeapRefCount; 20 21 static VOID 22 CheckHeap(VOID) 23 { 24 if (NULL == InfpHeap) 25 { 26 InfpHeap = RtlCreateHeap(HEAP_GROWABLE, NULL, 0, 0, NULL, NULL); 27 } 28 if (0 <= InfpHeapRefCount) 29 { 30 InfpHeapRefCount++; 31 } 32 } 33 34 35 /* PUBLIC FUNCTIONS *********************************************************/ 36 37 PVOID InfpHeap; 38 39 VOID 40 InfSetHeap(PVOID Heap) 41 { 42 if (NULL == InfpHeap) 43 { 44 InfpHeap = Heap; 45 InfpHeapRefCount = -1; 46 } 47 } 48 49 50 NTSTATUS 51 InfOpenBufferedFile(PHINF InfHandle, 52 PVOID Buffer, 53 ULONG BufferSize, 54 LANGID LanguageId, 55 PULONG ErrorLine) 56 { 57 INFSTATUS Status; 58 PINFCACHE Cache; 59 PCHAR FileBuffer; 60 ULONG FileBufferSize; 61 62 CheckHeap(); 63 64 *InfHandle = NULL; 65 *ErrorLine = (ULONG)-1; 66 67 /* Allocate file buffer */ 68 FileBufferSize = BufferSize + 2; 69 FileBuffer = MALLOC(FileBufferSize); 70 if (FileBuffer == NULL) 71 { 72 DPRINT1("MALLOC() failed\n"); 73 return(INF_STATUS_INSUFFICIENT_RESOURCES); 74 } 75 76 MEMCPY(FileBuffer, Buffer, BufferSize); 77 78 /* Append string terminator */ 79 FileBuffer[BufferSize] = 0; 80 FileBuffer[BufferSize + 1] = 0; 81 82 /* Allocate infcache header */ 83 Cache = (PINFCACHE)MALLOC(sizeof(INFCACHE)); 84 if (Cache == NULL) 85 { 86 DPRINT("MALLOC() failed\n"); 87 FREE(FileBuffer); 88 return(INF_STATUS_INSUFFICIENT_RESOURCES); 89 } 90 91 /* Initialize inicache header */ 92 ZEROMEMORY(Cache, 93 sizeof(INFCACHE)); 94 95 Cache->LanguageId = LanguageId; 96 97 /* Parse the inf buffer */ 98 if (!RtlIsTextUnicode(FileBuffer, FileBufferSize, NULL)) 99 { 100 // static const BYTE utf8_bom[3] = { 0xef, 0xbb, 0xbf }; 101 WCHAR *new_buff; 102 // UINT codepage = CP_ACP; 103 UINT offset = 0; 104 105 // if (BufferSize > sizeof(utf8_bom) && !memcmp(FileBuffer, utf8_bom, sizeof(utf8_bom) )) 106 // { 107 // codepage = CP_UTF8; 108 // offset = sizeof(utf8_bom); 109 // } 110 111 new_buff = MALLOC(FileBufferSize * sizeof(WCHAR)); 112 if (new_buff != NULL) 113 { 114 ULONG len; 115 Status = RtlMultiByteToUnicodeN(new_buff, 116 FileBufferSize * sizeof(WCHAR), 117 &len, 118 (char *)FileBuffer + offset, 119 FileBufferSize - offset); 120 121 Status = InfpParseBuffer(Cache, 122 new_buff, 123 new_buff + len / sizeof(WCHAR), 124 ErrorLine); 125 FREE(new_buff); 126 } 127 else 128 Status = INF_STATUS_INSUFFICIENT_RESOURCES; 129 } 130 else 131 { 132 WCHAR *new_buff = (WCHAR *)FileBuffer; 133 /* UCS-16 files should start with the Unicode BOM; we should skip it */ 134 if (*new_buff == 0xfeff) 135 { 136 new_buff++; 137 FileBufferSize -= sizeof(WCHAR); 138 } 139 Status = InfpParseBuffer(Cache, 140 new_buff, 141 (WCHAR*)((char*)new_buff + FileBufferSize), 142 ErrorLine); 143 } 144 145 if (!INF_SUCCESS(Status)) 146 { 147 FREE(Cache); 148 Cache = NULL; 149 } 150 151 /* Free file buffer */ 152 FREE(FileBuffer); 153 154 *InfHandle = (HINF)Cache; 155 156 return(Status); 157 } 158 159 160 NTSTATUS 161 InfOpenFile(PHINF InfHandle, 162 PUNICODE_STRING FileName, 163 LANGID LanguageId, 164 PULONG ErrorLine) 165 { 166 OBJECT_ATTRIBUTES ObjectAttributes; 167 FILE_STANDARD_INFORMATION FileInfo; 168 IO_STATUS_BLOCK IoStatusBlock; 169 HANDLE FileHandle; 170 NTSTATUS Status; 171 PCHAR FileBuffer; 172 ULONG FileLength; 173 ULONG FileBufferLength; 174 LARGE_INTEGER FileOffset; 175 PINFCACHE Cache; 176 177 CheckHeap(); 178 179 *InfHandle = NULL; 180 *ErrorLine = (ULONG)-1; 181 182 /* Open the inf file */ 183 InitializeObjectAttributes(&ObjectAttributes, 184 FileName, 185 0, 186 NULL, 187 NULL); 188 189 Status = NtOpenFile(&FileHandle, 190 GENERIC_READ | SYNCHRONIZE, 191 &ObjectAttributes, 192 &IoStatusBlock, 193 FILE_SHARE_READ, 194 FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE); 195 if (!INF_SUCCESS(Status)) 196 { 197 DPRINT("NtOpenFile() failed (Status %lx)\n", Status); 198 return(Status); 199 } 200 201 DPRINT("NtOpenFile() successful\n"); 202 203 /* Query file size */ 204 Status = NtQueryInformationFile(FileHandle, 205 &IoStatusBlock, 206 &FileInfo, 207 sizeof(FILE_STANDARD_INFORMATION), 208 FileStandardInformation); 209 if (!INF_SUCCESS(Status)) 210 { 211 DPRINT("NtQueryInformationFile() failed (Status %lx)\n", Status); 212 NtClose(FileHandle); 213 return(Status); 214 } 215 216 FileLength = FileInfo.EndOfFile.u.LowPart; 217 218 DPRINT("File size: %lu\n", FileLength); 219 220 /* Allocate file buffer */ 221 FileBufferLength = FileLength + 2; 222 FileBuffer = MALLOC(FileBufferLength); 223 if (FileBuffer == NULL) 224 { 225 DPRINT1("MALLOC() failed\n"); 226 NtClose(FileHandle); 227 return(INF_STATUS_INSUFFICIENT_RESOURCES); 228 } 229 230 /* Read file */ 231 FileOffset.QuadPart = 0ULL; 232 Status = NtReadFile(FileHandle, 233 NULL, 234 NULL, 235 NULL, 236 &IoStatusBlock, 237 FileBuffer, 238 FileLength, 239 &FileOffset, 240 NULL); 241 242 /* Append string terminator */ 243 FileBuffer[FileLength] = 0; 244 FileBuffer[FileLength + 1] = 0; 245 246 NtClose(FileHandle); 247 248 if (!INF_SUCCESS(Status)) 249 { 250 DPRINT("NtReadFile() failed (Status %lx)\n", Status); 251 FREE(FileBuffer); 252 return(Status); 253 } 254 255 /* Allocate infcache header */ 256 Cache = (PINFCACHE)MALLOC(sizeof(INFCACHE)); 257 if (Cache == NULL) 258 { 259 DPRINT("MALLOC() failed\n"); 260 FREE(FileBuffer); 261 return(INF_STATUS_INSUFFICIENT_RESOURCES); 262 } 263 264 /* Initialize inicache header */ 265 ZEROMEMORY(Cache, 266 sizeof(INFCACHE)); 267 268 Cache->LanguageId = LanguageId; 269 270 /* Parse the inf buffer */ 271 if (!RtlIsTextUnicode(FileBuffer, FileBufferLength, NULL)) 272 { 273 // static const BYTE utf8_bom[3] = { 0xef, 0xbb, 0xbf }; 274 WCHAR *new_buff; 275 // UINT codepage = CP_ACP; 276 UINT offset = 0; 277 278 // if (FileLength > sizeof(utf8_bom) && !memcmp(FileBuffer, utf8_bom, sizeof(utf8_bom) )) 279 // { 280 // codepage = CP_UTF8; 281 // offset = sizeof(utf8_bom); 282 // } 283 284 new_buff = MALLOC(FileBufferLength * sizeof(WCHAR)); 285 if (new_buff != NULL) 286 { 287 ULONG len; 288 Status = RtlMultiByteToUnicodeN(new_buff, 289 FileBufferLength * sizeof(WCHAR), 290 &len, 291 (char *)FileBuffer + offset, 292 FileBufferLength - offset); 293 294 Status = InfpParseBuffer(Cache, 295 new_buff, 296 new_buff + len / sizeof(WCHAR), 297 ErrorLine); 298 FREE(new_buff); 299 } 300 else 301 Status = INF_STATUS_INSUFFICIENT_RESOURCES; 302 } 303 else 304 { 305 WCHAR *new_buff = (WCHAR *)FileBuffer; 306 /* UCS-16 files should start with the Unicode BOM; we should skip it */ 307 if (*new_buff == 0xfeff) 308 { 309 new_buff++; 310 FileBufferLength -= sizeof(WCHAR); 311 } 312 Status = InfpParseBuffer(Cache, 313 new_buff, 314 (WCHAR*)((char*)new_buff + FileBufferLength), 315 ErrorLine); 316 } 317 318 if (!INF_SUCCESS(Status)) 319 { 320 FREE(Cache); 321 Cache = NULL; 322 } 323 324 /* Free file buffer */ 325 FREE(FileBuffer); 326 327 *InfHandle = (HINF)Cache; 328 329 return(Status); 330 } 331 332 333 VOID 334 InfCloseFile(HINF InfHandle) 335 { 336 PINFCACHE Cache; 337 338 Cache = (PINFCACHE)InfHandle; 339 340 if (Cache == NULL) 341 { 342 return; 343 } 344 345 while (Cache->FirstSection != NULL) 346 { 347 Cache->FirstSection = InfpFreeSection(Cache->FirstSection); 348 } 349 Cache->LastSection = NULL; 350 351 FREE(Cache); 352 353 if (0 < InfpHeapRefCount) 354 { 355 InfpHeapRefCount--; 356 if (0 == InfpHeapRefCount) 357 { 358 RtlDestroyHeap(InfpHeap); 359 InfpHeap = NULL; 360 } 361 } 362 } 363 364 365 /* EOF */ 366