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 13 #define NDEBUG 14 #include <debug.h> 15 16 static size_t 17 InfpSubstituteString(PINFCACHE Inf, 18 const WCHAR *text, 19 WCHAR *buffer, 20 size_t size); 21 22 static void 23 ShortToHex(PWCHAR Buffer, 24 USHORT Value) 25 { 26 WCHAR HexDigits[] = L"0123456789abcdef"; 27 28 Buffer[0] = HexDigits[Value >> 12 & 0xf]; 29 Buffer[1] = HexDigits[Value >> 8 & 0xf]; 30 Buffer[2] = HexDigits[Value >> 4 & 0xf]; 31 Buffer[3] = HexDigits[Value >> 0 & 0xf]; 32 } 33 34 /* retrieve the string substitution for a given string, or NULL if not found */ 35 /* if found, len is set to the substitution length */ 36 static PCWSTR 37 InfpGetSubstitutionString(PINFCACHE Inf, 38 PCWSTR str, 39 size_t *len, 40 BOOL no_trailing_slash) 41 { 42 static const WCHAR percent = '%'; 43 44 INFSTATUS Status = INF_STATUS_NOT_FOUND; 45 PINFCONTEXT Context = NULL; 46 PWCHAR Data = NULL; 47 WCHAR ValueName[MAX_INF_STRING_LENGTH +1]; 48 WCHAR StringLangId[] = L"Strings.XXXX"; 49 50 if (!*len) /* empty string (%%) is replaced by single percent */ 51 { 52 *len = 1; 53 return &percent; 54 } 55 56 memcpy(ValueName, str, *len * sizeof(WCHAR)); 57 ValueName[*len] = 0; 58 59 DPRINT("Value name: %S\n", ValueName); 60 61 if (Inf->LanguageId != 0) 62 { 63 ShortToHex(&StringLangId[sizeof("Strings.") - 1], 64 Inf->LanguageId); 65 66 Status = InfpFindFirstLine(Inf, 67 StringLangId, 68 ValueName, 69 &Context); 70 if (Status != INF_STATUS_SUCCESS) 71 { 72 ShortToHex(&StringLangId[sizeof("Strings.") - 1], 73 MAKELANGID(PRIMARYLANGID(Inf->LanguageId), SUBLANG_NEUTRAL)); 74 75 Status = InfpFindFirstLine(Inf, 76 StringLangId, 77 ValueName, 78 &Context); 79 if (Status != INF_STATUS_SUCCESS) 80 { 81 Status = InfpFindFirstLine(Inf, 82 L"Strings", 83 ValueName, 84 &Context); 85 } 86 } 87 } 88 else 89 { 90 Status = InfpFindFirstLine(Inf, 91 L"Strings", 92 ValueName, 93 &Context); 94 } 95 96 if (Status != INF_STATUS_SUCCESS || Context == NULL) 97 return NULL; 98 99 Status = InfpGetData(Context, 100 NULL, 101 &Data); 102 103 InfpFreeContext(Context); 104 105 if (Status == STATUS_SUCCESS) 106 { 107 *len = strlenW(Data); 108 DPRINT("Substitute: %S Length: %zu\n", Data, *len); 109 return Data; 110 } 111 112 return NULL; 113 } 114 115 116 /* do string substitutions on the specified text */ 117 /* the buffer is assumed to be large enough */ 118 /* returns necessary length not including terminating null */ 119 static size_t 120 InfpSubstituteString(PINFCACHE Inf, 121 PCWSTR text, 122 PWSTR buffer, 123 size_t size) 124 { 125 const WCHAR *start, *subst, *p; 126 size_t len, total = 0; 127 int inside = 0; 128 129 if (!buffer) size = MAX_INF_STRING_LENGTH + 1; 130 for (p = start = text; *p; p++) 131 { 132 if (*p != '%') continue; 133 inside = !inside; 134 if (inside) /* start of a %xx% string */ 135 { 136 len = (p - start); 137 if (len > size - 1) len = size - 1; 138 if (buffer) memcpy( buffer + total, start, len * sizeof(WCHAR) ); 139 total += len; 140 size -= len; 141 start = p; 142 } 143 else /* end of the %xx% string, find substitution */ 144 { 145 len = (p - start - 1); 146 subst = InfpGetSubstitutionString( Inf, start + 1, &len, p[1] == '\\' ); 147 if (!subst) 148 { 149 subst = start; 150 len = (p - start + 1); 151 } 152 if (len > size - 1) len = size - 1; 153 if (buffer) memcpy( buffer + total, subst, len * sizeof(WCHAR) ); 154 total += len; 155 size -= len; 156 start = p + 1; 157 } 158 } 159 160 if (start != p) /* unfinished string, copy it */ 161 { 162 len = (unsigned int)(p - start); 163 if (len > size - 1) len = size - 1; 164 if (buffer) memcpy( buffer + total, start, len * sizeof(WCHAR) ); 165 total += len; 166 } 167 if (buffer && size) buffer[total] = 0; 168 return total; 169 } 170 171 172 INFSTATUS 173 InfpFindFirstLine(PINFCACHE Cache, 174 PCWSTR Section, 175 PCWSTR Key, 176 PINFCONTEXT *Context) 177 { 178 PINFCACHESECTION CacheSection; 179 PINFCACHELINE CacheLine; 180 181 if (Cache == NULL || Section == NULL || Context == NULL) 182 { 183 DPRINT1("Invalid parameter\n"); 184 return INF_STATUS_INVALID_PARAMETER; 185 } 186 187 CacheSection = InfpFindSection(Cache, Section); 188 if (NULL == CacheSection) 189 { 190 DPRINT("Section not found\n"); 191 return INF_STATUS_NOT_FOUND; 192 } 193 194 if (Key != NULL) 195 { 196 CacheLine = InfpFindKeyLine(CacheSection, Key); 197 } 198 else 199 { 200 CacheLine = CacheSection->FirstLine; 201 } 202 203 if (NULL == CacheLine) 204 { 205 DPRINT("Key not found\n"); 206 return INF_STATUS_NOT_FOUND; 207 } 208 209 *Context = MALLOC(sizeof(INFCONTEXT)); 210 if (NULL == *Context) 211 { 212 DPRINT1("MALLOC() failed\n"); 213 return INF_STATUS_NO_MEMORY; 214 } 215 (*Context)->Inf = (PVOID)Cache; 216 (*Context)->Section = CacheSection->Id; 217 (*Context)->Line = CacheLine->Id; 218 219 return INF_STATUS_SUCCESS; 220 } 221 222 223 INFSTATUS 224 InfpFindNextLine(PINFCONTEXT ContextIn, 225 PINFCONTEXT ContextOut) 226 { 227 PINFCACHELINE CacheLine; 228 229 if (ContextIn == NULL || ContextOut == NULL) 230 return INF_STATUS_INVALID_PARAMETER; 231 232 CacheLine = InfpGetLineForContext(ContextIn); 233 if (CacheLine == NULL) 234 return INF_STATUS_INVALID_PARAMETER; 235 236 if (CacheLine->Next == NULL) 237 return INF_STATUS_NOT_FOUND; 238 239 if (ContextIn != ContextOut) 240 { 241 ContextOut->Inf = ContextIn->Inf; 242 ContextOut->Section = ContextIn->Section; 243 } 244 ContextOut->Line = CacheLine->Next->Id; 245 246 return INF_STATUS_SUCCESS; 247 } 248 249 250 INFSTATUS 251 InfpFindFirstMatchLine(PINFCONTEXT ContextIn, 252 PCWSTR Key, 253 PINFCONTEXT ContextOut) 254 { 255 PINFCACHESECTION Section; 256 PINFCACHELINE CacheLine; 257 258 if (ContextIn == NULL || ContextOut == NULL || Key == NULL || *Key == 0) 259 return INF_STATUS_INVALID_PARAMETER; 260 261 Section = InfpGetSectionForContext(ContextIn); 262 if (Section == NULL) 263 return INF_STATUS_INVALID_PARAMETER; 264 265 CacheLine = Section->FirstLine; 266 while (CacheLine != NULL) 267 { 268 if (CacheLine->Key != NULL && strcmpiW (CacheLine->Key, Key) == 0) 269 { 270 271 if (ContextIn != ContextOut) 272 { 273 ContextOut->Inf = ContextIn->Inf; 274 ContextOut->Section = ContextIn->Section; 275 } 276 ContextOut->Line = CacheLine->Id; 277 278 return INF_STATUS_SUCCESS; 279 } 280 281 CacheLine = CacheLine->Next; 282 } 283 284 return INF_STATUS_NOT_FOUND; 285 } 286 287 288 INFSTATUS 289 InfpFindNextMatchLine(PINFCONTEXT ContextIn, 290 PCWSTR Key, 291 PINFCONTEXT ContextOut) 292 { 293 PINFCACHESECTION Section; 294 PINFCACHELINE CacheLine; 295 296 if (ContextIn == NULL || ContextOut == NULL || Key == NULL || *Key == 0) 297 return INF_STATUS_INVALID_PARAMETER; 298 299 Section = InfpGetSectionForContext(ContextIn); 300 if (Section == NULL) 301 return INF_STATUS_INVALID_PARAMETER; 302 303 CacheLine = InfpGetLineForContext(ContextIn); 304 while (CacheLine != NULL) 305 { 306 if (CacheLine->Key != NULL && strcmpiW (CacheLine->Key, Key) == 0) 307 { 308 309 if (ContextIn != ContextOut) 310 { 311 ContextOut->Inf = ContextIn->Inf; 312 ContextOut->Section = ContextIn->Section; 313 } 314 ContextOut->Line = CacheLine->Id; 315 316 return INF_STATUS_SUCCESS; 317 } 318 319 CacheLine = CacheLine->Next; 320 } 321 322 return INF_STATUS_NOT_FOUND; 323 } 324 325 326 LONG 327 InfpGetLineCount(HINF InfHandle, 328 PCWSTR Section) 329 { 330 PINFCACHE Cache; 331 PINFCACHESECTION CacheSection; 332 333 if (InfHandle == NULL || Section == NULL) 334 { 335 DPRINT("Invalid parameter\n"); 336 return -1; 337 } 338 339 Cache = (PINFCACHE)InfHandle; 340 341 /* Iterate through list of sections */ 342 CacheSection = Cache->FirstSection; 343 while (CacheSection != NULL) 344 { 345 /* Are the section names the same? */ 346 if (strcmpiW(CacheSection->Name, Section) == 0) 347 { 348 return CacheSection->LineCount; 349 } 350 351 /* Get the next section */ 352 CacheSection = CacheSection->Next; 353 } 354 355 DPRINT("Section not found\n"); 356 357 return -1; 358 } 359 360 361 /* InfpGetLineText */ 362 363 364 LONG 365 InfpGetFieldCount(PINFCONTEXT Context) 366 { 367 PINFCACHELINE Line; 368 369 Line = InfpGetLineForContext(Context); 370 if (Line == NULL) 371 return 0; 372 return Line->FieldCount; 373 } 374 375 376 INFSTATUS 377 InfpGetBinaryField(PINFCONTEXT Context, 378 ULONG FieldIndex, 379 PUCHAR ReturnBuffer, 380 ULONG ReturnBufferSize, 381 PULONG RequiredSize) 382 { 383 PINFCACHELINE CacheLine; 384 PINFCACHEFIELD CacheField; 385 ULONG Index; 386 ULONG Size; 387 PUCHAR Ptr; 388 389 if (Context == NULL || FieldIndex == 0) 390 { 391 DPRINT("Invalid parameter\n"); 392 return INF_STATUS_INVALID_PARAMETER; 393 } 394 395 if (RequiredSize != NULL) 396 *RequiredSize = 0; 397 398 CacheLine = InfpGetLineForContext(Context); 399 400 if (FieldIndex > (ULONG)CacheLine->FieldCount) 401 return INF_STATUS_NOT_FOUND; 402 403 CacheField = CacheLine->FirstField; 404 for (Index = 1; Index < FieldIndex; Index++) 405 CacheField = CacheField->Next; 406 407 Size = (ULONG)CacheLine->FieldCount - FieldIndex + 1; 408 409 if (RequiredSize != NULL) 410 *RequiredSize = Size; 411 412 if (ReturnBuffer != NULL) 413 { 414 if (ReturnBufferSize < Size) 415 return INF_STATUS_BUFFER_OVERFLOW; 416 417 /* Copy binary data */ 418 Ptr = ReturnBuffer; 419 while (CacheField != NULL) 420 { 421 *Ptr = (UCHAR)strtoulW(CacheField->Data, NULL, 16); 422 423 Ptr++; 424 CacheField = CacheField->Next; 425 } 426 } 427 428 return INF_STATUS_SUCCESS; 429 } 430 431 432 INFSTATUS 433 InfpGetIntField(PINFCONTEXT Context, 434 ULONG FieldIndex, 435 INT *IntegerValue) 436 { 437 PINFCACHELINE CacheLine; 438 PINFCACHEFIELD CacheField; 439 ULONG Index; 440 PWCHAR Ptr; 441 442 if (Context == NULL || IntegerValue == NULL) 443 { 444 DPRINT("Invalid parameter\n"); 445 return INF_STATUS_INVALID_PARAMETER; 446 } 447 448 CacheLine = InfpGetLineForContext(Context); 449 450 if (FieldIndex > (ULONG)CacheLine->FieldCount) 451 { 452 DPRINT("Invalid parameter\n"); 453 return INF_STATUS_INVALID_PARAMETER; 454 } 455 456 if (FieldIndex == 0) 457 { 458 Ptr = CacheLine->Key; 459 } 460 else 461 { 462 CacheField = CacheLine->FirstField; 463 for (Index = 1; Index < FieldIndex; Index++) 464 CacheField = CacheField->Next; 465 466 Ptr = CacheField->Data; 467 } 468 469 *IntegerValue = (LONG)strtolW(Ptr, NULL, 0); 470 471 return INF_STATUS_SUCCESS; 472 } 473 474 475 INFSTATUS 476 InfpGetMultiSzField(PINFCONTEXT Context, 477 ULONG FieldIndex, 478 PWSTR ReturnBuffer, 479 ULONG ReturnBufferSize, 480 PULONG RequiredSize) 481 { 482 PINFCACHELINE CacheLine; 483 PINFCACHEFIELD CacheField; 484 PINFCACHEFIELD FieldPtr; 485 ULONG Index; 486 ULONG Size; 487 PWCHAR Ptr; 488 489 if (Context == NULL || FieldIndex == 0) 490 { 491 DPRINT("Invalid parameter\n"); 492 return INF_STATUS_INVALID_PARAMETER; 493 } 494 495 if (RequiredSize != NULL) 496 *RequiredSize = 0; 497 498 CacheLine = InfpGetLineForContext(Context); 499 500 if (FieldIndex > (ULONG)CacheLine->FieldCount) 501 return INF_STATUS_INVALID_PARAMETER; 502 503 CacheField = CacheLine->FirstField; 504 for (Index = 1; Index < FieldIndex; Index++) 505 CacheField = CacheField->Next; 506 507 /* Calculate the required buffer size */ 508 FieldPtr = CacheField; 509 Size = 0; 510 while (FieldPtr != NULL) 511 { 512 Size += ((ULONG)strlenW(FieldPtr->Data) + 1); 513 FieldPtr = FieldPtr->Next; 514 } 515 Size++; 516 517 if (RequiredSize != NULL) 518 *RequiredSize = Size; 519 520 if (ReturnBuffer != NULL) 521 { 522 if (ReturnBufferSize < Size) 523 return INF_STATUS_BUFFER_OVERFLOW; 524 525 /* Copy multi-sz string */ 526 Ptr = ReturnBuffer; 527 FieldPtr = CacheField; 528 while (FieldPtr != NULL) 529 { 530 Size = (ULONG)strlenW(FieldPtr->Data) + 1; 531 532 strcpyW(Ptr, FieldPtr->Data); 533 534 Ptr = Ptr + Size; 535 FieldPtr = FieldPtr->Next; 536 } 537 *Ptr = 0; 538 } 539 540 return INF_STATUS_SUCCESS; 541 } 542 543 544 INFSTATUS 545 InfpGetStringField(PINFCONTEXT Context, 546 ULONG FieldIndex, 547 PWSTR ReturnBuffer, 548 ULONG ReturnBufferSize, 549 PULONG RequiredSize) 550 { 551 PINFCACHELINE CacheLine; 552 PINFCACHEFIELD CacheField; 553 ULONG Index; 554 PWCHAR Ptr; 555 SIZE_T Size; 556 557 if (Context == NULL) 558 { 559 DPRINT("Invalid parameter\n"); 560 return INF_STATUS_INVALID_PARAMETER; 561 } 562 563 if (RequiredSize != NULL) 564 *RequiredSize = 0; 565 566 CacheLine = InfpGetLineForContext(Context); 567 568 if (FieldIndex > (ULONG)CacheLine->FieldCount) 569 return INF_STATUS_INVALID_PARAMETER; 570 571 if (FieldIndex == 0) 572 { 573 Ptr = CacheLine->Key; 574 } 575 else 576 { 577 CacheField = CacheLine->FirstField; 578 for (Index = 1; Index < FieldIndex; Index++) 579 CacheField = CacheField->Next; 580 581 Ptr = CacheField->Data; 582 } 583 584 // Size = (ULONG)strlenW(Ptr) + 1; 585 Size = InfpSubstituteString(Context->Inf, 586 Ptr, 587 NULL, 588 0); 589 590 if (RequiredSize != NULL) 591 *RequiredSize = (ULONG)Size + 1; 592 593 if (ReturnBuffer != NULL) 594 { 595 if (ReturnBufferSize <= Size) 596 return INF_STATUS_BUFFER_OVERFLOW; 597 598 // strcpyW(ReturnBuffer, Ptr); 599 InfpSubstituteString(Context->Inf, 600 Ptr, 601 ReturnBuffer, 602 ReturnBufferSize); 603 } 604 605 return INF_STATUS_SUCCESS; 606 } 607 608 609 INFSTATUS 610 InfpGetData(PINFCONTEXT Context, 611 PWCHAR *Key, 612 PWCHAR *Data) 613 { 614 PINFCACHELINE CacheKey; 615 616 if (Context == NULL || Data == NULL) 617 { 618 DPRINT("Invalid parameter\n"); 619 return INF_STATUS_INVALID_PARAMETER; 620 } 621 622 CacheKey = InfpGetLineForContext(Context); 623 if (Key != NULL) 624 *Key = CacheKey->Key; 625 626 if (Data != NULL) 627 { 628 if (CacheKey->FirstField == NULL) 629 { 630 *Data = NULL; 631 } 632 else 633 { 634 *Data = CacheKey->FirstField->Data; 635 } 636 } 637 638 return INF_STATUS_SUCCESS; 639 } 640 641 642 INFSTATUS 643 InfpGetDataField(PINFCONTEXT Context, 644 ULONG FieldIndex, 645 PWCHAR *Data) 646 { 647 PINFCACHELINE CacheLine; 648 PINFCACHEFIELD CacheField; 649 ULONG Index; 650 651 if (Context == NULL || Data == NULL) 652 { 653 DPRINT("Invalid parameter\n"); 654 return INF_STATUS_INVALID_PARAMETER; 655 } 656 657 CacheLine = InfpGetLineForContext(Context); 658 659 if (FieldIndex > (ULONG)CacheLine->FieldCount) 660 return INF_STATUS_INVALID_PARAMETER; 661 662 if (FieldIndex == 0) 663 { 664 *Data = CacheLine->Key; 665 } 666 else 667 { 668 CacheField = CacheLine->FirstField; 669 for (Index = 1; Index < FieldIndex; Index++) 670 CacheField = CacheField->Next; 671 672 *Data = CacheField->Data; 673 } 674 675 return INF_STATUS_SUCCESS; 676 } 677 678 VOID 679 InfpFreeContext(PINFCONTEXT Context) 680 { 681 FREE(Context); 682 } 683 684 /* EOF */ 685