Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1649 lines
40 KiB

  1. /*++
  2. Copyright (c) 1993-2000 Microsoft Corporation
  3. Module Name:
  4. infvalue.c
  5. Abstract:
  6. Externally exposed INF routines for INF value retreival and manipulation.
  7. Author:
  8. Ted Miller (tedm) 20-Jan-1995
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. BOOL
  14. pAToI(
  15. IN PCTSTR Field,
  16. OUT PINT IntegerValue
  17. )
  18. /*++
  19. Routine Description:
  20. Arguments:
  21. Return Value:
  22. Remarks:
  23. Hexadecimal numbers are also supported. They must be prefixed by '0x' or '0X', with no
  24. space allowed between the prefix and the number.
  25. --*/
  26. {
  27. INT Value;
  28. UINT c;
  29. BOOL Neg;
  30. UINT Base;
  31. UINT NextDigitValue;
  32. INT OverflowCheck;
  33. BOOL b;
  34. if(!Field) {
  35. SetLastError(ERROR_INVALID_PARAMETER);
  36. return(FALSE);
  37. }
  38. if(*Field == TEXT('-')) {
  39. Neg = TRUE;
  40. Field++;
  41. } else {
  42. Neg = FALSE;
  43. if(*Field == TEXT('+')) {
  44. Field++;
  45. }
  46. }
  47. if((*Field == TEXT('0')) &&
  48. ((*(Field+1) == TEXT('x')) || (*(Field+1) == TEXT('X')))) {
  49. //
  50. // The number is in hexadecimal.
  51. //
  52. Base = 16;
  53. Field += 2;
  54. } else {
  55. //
  56. // The number is in decimal.
  57. //
  58. Base = 10;
  59. }
  60. for(OverflowCheck = Value = 0; *Field; Field++) {
  61. c = (UINT)*Field;
  62. if((c >= (UINT)'0') && (c <= (UINT)'9')) {
  63. NextDigitValue = c - (UINT)'0';
  64. } else if(Base == 16) {
  65. if((c >= (UINT)'a') && (c <= (UINT)'f')) {
  66. NextDigitValue = (c - (UINT)'a') + 10;
  67. } else if ((c >= (UINT)'A') && (c <= (UINT)'F')) {
  68. NextDigitValue = (c - (UINT)'A') + 10;
  69. } else {
  70. break;
  71. }
  72. } else {
  73. break;
  74. }
  75. Value *= Base;
  76. Value += NextDigitValue;
  77. //
  78. // Check for overflow. For decimal numbers, we check to see whether the
  79. // new value has overflowed into the sign bit (i.e., is less than the
  80. // previous value. For hexadecimal numbers, we check to make sure we
  81. // haven't gotten more digits than will fit in a DWORD.
  82. //
  83. if(Base == 16) {
  84. if(++OverflowCheck > (sizeof(INT) * 2)) {
  85. break;
  86. }
  87. } else {
  88. if(Value < OverflowCheck) {
  89. break;
  90. } else {
  91. OverflowCheck = Value;
  92. }
  93. }
  94. }
  95. if(*Field) {
  96. SetLastError(ERROR_INVALID_DATA);
  97. return(FALSE);
  98. }
  99. if(Neg) {
  100. Value = 0-Value;
  101. }
  102. b = TRUE;
  103. try {
  104. *IntegerValue = Value;
  105. } except(EXCEPTION_EXECUTE_HANDLER) {
  106. b = FALSE;
  107. }
  108. if(!b) {
  109. SetLastError(ERROR_INVALID_PARAMETER);
  110. }
  111. return(b);
  112. }
  113. DWORD
  114. SetupGetFieldCount(
  115. IN PINFCONTEXT Context
  116. )
  117. /*++
  118. Routine Description:
  119. Arguments:
  120. Return Value:
  121. --*/
  122. {
  123. PINF_LINE Line = NULL;
  124. DWORD rc = NO_ERROR;
  125. DWORD res = 0;
  126. try {
  127. if(!LockInf((PLOADED_INF)Context->Inf)) {
  128. rc = ERROR_INVALID_PARAMETER;
  129. }
  130. } except(EXCEPTION_EXECUTE_HANDLER) {
  131. rc = ERROR_INVALID_PARAMETER;
  132. }
  133. if(rc) {
  134. SetLastError(rc);
  135. return(0);
  136. }
  137. try {
  138. Line = InfLineFromContext(Context);
  139. if(!Line) {
  140. rc = ERROR_INVALID_PARAMETER;
  141. leave;
  142. }
  143. if(HASKEY(Line)) {
  144. res = Line->ValueCount - 2;
  145. } else {
  146. res = ISSEARCHABLE(Line) ? 1 : Line->ValueCount;
  147. }
  148. } except(EXCEPTION_EXECUTE_HANDLER) {
  149. rc = ERROR_INVALID_PARAMETER;
  150. res = 0;
  151. }
  152. try {
  153. UnlockInf((PLOADED_INF)Context->Inf);
  154. } except(EXCEPTION_EXECUTE_HANDLER) {
  155. }
  156. SetLastError(rc);
  157. return res;
  158. }
  159. #ifdef UNICODE
  160. //
  161. // ANSI version
  162. //
  163. BOOL
  164. SetupGetStringFieldA(
  165. IN PINFCONTEXT Context,
  166. IN DWORD FieldIndex,
  167. OUT PSTR ReturnBuffer, OPTIONAL
  168. IN DWORD ReturnBufferSize,
  169. OUT LPDWORD RequiredSize OPTIONAL
  170. )
  171. {
  172. PCWSTR Field;
  173. PCSTR field;
  174. UINT Len;
  175. DWORD rc, TmpRequiredSize;
  176. //
  177. // Context could be a bogus pointer -- guard access to it.
  178. //
  179. try {
  180. Field = pSetupGetField(Context, FieldIndex);
  181. } except(EXCEPTION_EXECUTE_HANDLER) {
  182. SetLastError(ERROR_INVALID_PARAMETER);
  183. return FALSE;
  184. }
  185. if(Field) {
  186. field = pSetupUnicodeToAnsi(Field);
  187. if(!field) {
  188. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  189. return FALSE;
  190. }
  191. } else {
  192. //
  193. // (last error already set by pSetupGetField)
  194. //
  195. return FALSE;
  196. }
  197. Len = lstrlenA(field) + 1;
  198. //
  199. // RequiredSize and ReturnBuffer could be bogus pointers;
  200. // guard access to them.
  201. //
  202. rc = NO_ERROR;
  203. try {
  204. if(RequiredSize) {
  205. *RequiredSize = Len;
  206. }
  207. if(ReturnBuffer) {
  208. if(ReturnBufferSize >= Len) {
  209. lstrcpyA(ReturnBuffer, field);
  210. } else {
  211. rc = ERROR_INSUFFICIENT_BUFFER;
  212. }
  213. }
  214. } except(EXCEPTION_EXECUTE_HANDLER) {
  215. rc = ERROR_INVALID_PARAMETER;
  216. }
  217. MyFree(field);
  218. SetLastError(rc);
  219. return(rc == NO_ERROR);
  220. }
  221. #else
  222. //
  223. // Unicode stub
  224. //
  225. BOOL
  226. SetupGetStringFieldW(
  227. IN PINFCONTEXT Context,
  228. IN DWORD FieldIndex,
  229. OUT PWSTR ReturnBuffer, OPTIONAL
  230. IN DWORD ReturnBufferSize,
  231. OUT LPDWORD RequiredSize OPTIONAL
  232. )
  233. {
  234. UNREFERENCED_PARAMETER(Context);
  235. UNREFERENCED_PARAMETER(FieldIndex);
  236. UNREFERENCED_PARAMETER(ReturnBuffer);
  237. UNREFERENCED_PARAMETER(ReturnBufferSize);
  238. UNREFERENCED_PARAMETER(RequiredSize);
  239. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  240. return(FALSE);
  241. }
  242. #endif
  243. BOOL
  244. SetupGetStringField(
  245. IN PINFCONTEXT Context,
  246. IN DWORD FieldIndex,
  247. OUT PTSTR ReturnBuffer, OPTIONAL
  248. IN DWORD ReturnBufferSize,
  249. OUT LPDWORD RequiredSize OPTIONAL
  250. )
  251. /*++
  252. Routine Description:
  253. Arguments:
  254. Return Value:
  255. --*/
  256. {
  257. PCTSTR Field;
  258. UINT Len;
  259. DWORD rc;
  260. //
  261. // Context could be a bogus pointer -- guard access to it.
  262. //
  263. try {
  264. Field = pSetupGetField(Context, FieldIndex);
  265. } except(EXCEPTION_EXECUTE_HANDLER) {
  266. SetLastError(ERROR_INVALID_PARAMETER);
  267. return FALSE;
  268. }
  269. if(!Field) {
  270. //
  271. // (last error already set by pSetupGetField)
  272. //
  273. return FALSE;
  274. }
  275. Len = lstrlen(Field) + 1;
  276. //
  277. // RequiredSize and ReturnBuffer could be bogus pointers;
  278. // guard access to them.
  279. //
  280. rc = NO_ERROR;
  281. try {
  282. if(RequiredSize) {
  283. *RequiredSize = Len;
  284. }
  285. if(ReturnBuffer) {
  286. if(ReturnBufferSize >= Len) {
  287. lstrcpy(ReturnBuffer, Field);
  288. } else {
  289. rc = ERROR_INSUFFICIENT_BUFFER;
  290. }
  291. }
  292. } except(EXCEPTION_EXECUTE_HANDLER) {
  293. rc = ERROR_INVALID_PARAMETER;
  294. }
  295. SetLastError(rc);
  296. return(rc == NO_ERROR);
  297. }
  298. BOOL
  299. SetupGetIntField(
  300. IN PINFCONTEXT Context,
  301. IN DWORD FieldIndex,
  302. OUT PINT IntegerValue
  303. )
  304. /*++
  305. Routine Description:
  306. Arguments:
  307. Return Value:
  308. Remarks:
  309. Hexadecimal numbers are also supported. They must be prefixed by '0x' or '0X', with no
  310. space allowed between the prefix and the number.
  311. --*/
  312. {
  313. PCTSTR Field;
  314. try {
  315. Field = pSetupGetField(Context,FieldIndex);
  316. } except(EXCEPTION_EXECUTE_HANDLER) {
  317. Field = NULL;
  318. }
  319. return (pAToI(Field, IntegerValue));
  320. }
  321. #ifdef UNICODE
  322. //
  323. // ANSI version
  324. //
  325. BOOL
  326. SetupGetLineTextA(
  327. IN PINFCONTEXT Context, OPTIONAL
  328. IN HINF InfHandle, OPTIONAL
  329. IN PCSTR Section, OPTIONAL
  330. IN PCSTR Key, OPTIONAL
  331. OUT PSTR ReturnBuffer, OPTIONAL
  332. IN DWORD ReturnBufferSize,
  333. OUT PDWORD RequiredSize OPTIONAL
  334. )
  335. {
  336. INFCONTEXT context;
  337. BOOL b;
  338. UINT FieldCount;
  339. UINT u;
  340. BOOL InsufficientBuffer;
  341. DWORD OldSize, TmpRequiredSize;
  342. PCWSTR Field;
  343. PCSTR field;
  344. PCWSTR section,key;
  345. //
  346. // Set up inf context.
  347. //
  348. if(Context) {
  349. u = NO_ERROR;
  350. try {
  351. context = *Context;
  352. } except(EXCEPTION_EXECUTE_HANDLER) {
  353. u = ERROR_INVALID_PARAMETER;
  354. }
  355. if(u != NO_ERROR) {
  356. SetLastError(u);
  357. return(FALSE);
  358. }
  359. } else {
  360. if(!InfHandle || !Section || !Key) {
  361. SetLastError(ERROR_INVALID_PARAMETER);
  362. return FALSE;
  363. }
  364. if(Section) {
  365. u = pSetupCaptureAndConvertAnsiArg(Section,&section);
  366. if(u != NO_ERROR) {
  367. SetLastError(u);
  368. return(FALSE);
  369. }
  370. } else {
  371. section = NULL;
  372. }
  373. if(Key) {
  374. u = pSetupCaptureAndConvertAnsiArg(Key,&key);
  375. if(u != NO_ERROR) {
  376. if(section) {
  377. MyFree(section);
  378. }
  379. SetLastError(u);
  380. return(FALSE);
  381. }
  382. } else {
  383. key = NULL;
  384. }
  385. b = SetupFindFirstLine(InfHandle,section,key,&context);
  386. u = GetLastError();
  387. if(section) {
  388. MyFree(section);
  389. }
  390. if(key) {
  391. MyFree(key);
  392. }
  393. if(!b) {
  394. SetLastError(u);
  395. return FALSE;
  396. }
  397. }
  398. //
  399. // Figure out how many fields are involved.
  400. //
  401. InsufficientBuffer = FALSE;
  402. if(FieldCount = SetupGetFieldCount(&context)) {
  403. TmpRequiredSize = 0;
  404. for(u=0; u<FieldCount; u++) {
  405. Field = pSetupGetField(&context, u+1);
  406. MYASSERT(Field);
  407. field = pSetupUnicodeToAnsi(Field);
  408. if(!field) {
  409. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  410. return(FALSE);
  411. }
  412. OldSize = TmpRequiredSize;
  413. TmpRequiredSize += lstrlenA(field)+1;
  414. if(ReturnBuffer) {
  415. if(TmpRequiredSize > ReturnBufferSize) {
  416. InsufficientBuffer = TRUE;
  417. } else {
  418. //
  419. // lstrcpy is safe even with bad pointers
  420. // (at least on NT)
  421. //
  422. lstrcpyA(ReturnBuffer+OldSize,field);
  423. ReturnBuffer[TmpRequiredSize - 1] = ',';
  424. }
  425. }
  426. MyFree(field);
  427. }
  428. //
  429. // 0-terminate the buffer by overwriting the final comma.
  430. //
  431. if(ReturnBuffer && !InsufficientBuffer) {
  432. ReturnBuffer[TmpRequiredSize - 1] = 0;
  433. }
  434. } else {
  435. //
  436. // Special case when no values -- need 1 byte for nul.
  437. //
  438. if (GetLastError() != NO_ERROR) {
  439. //
  440. // actually, something went wrong reading the data from our context...
  441. // bail out
  442. //
  443. return(FALSE);
  444. }
  445. TmpRequiredSize = 1;
  446. if(ReturnBuffer) {
  447. if(ReturnBufferSize) {
  448. *ReturnBuffer = 0;
  449. } else {
  450. InsufficientBuffer = TRUE;
  451. }
  452. }
  453. }
  454. if(RequiredSize) {
  455. u = NO_ERROR;
  456. try {
  457. *RequiredSize = TmpRequiredSize;
  458. } except(EXCEPTION_EXECUTE_HANDLER) {
  459. u = ERROR_INVALID_PARAMETER;
  460. }
  461. if(u != NO_ERROR) {
  462. SetLastError(u);
  463. return(FALSE);
  464. }
  465. }
  466. if(InsufficientBuffer) {
  467. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  468. return FALSE;
  469. }
  470. return TRUE;
  471. }
  472. #else
  473. //
  474. // Unicode stub
  475. //
  476. BOOL
  477. SetupGetLineTextW(
  478. IN PINFCONTEXT Context, OPTIONAL
  479. IN HINF InfHandle, OPTIONAL
  480. IN PCWSTR Section, OPTIONAL
  481. IN PCWSTR Key, OPTIONAL
  482. OUT PWSTR ReturnBuffer, OPTIONAL
  483. IN DWORD ReturnBufferSize,
  484. OUT PDWORD RequiredSize OPTIONAL
  485. )
  486. {
  487. UNREFERENCED_PARAMETER(Context);
  488. UNREFERENCED_PARAMETER(InfHandle);
  489. UNREFERENCED_PARAMETER(Section);
  490. UNREFERENCED_PARAMETER(Key);
  491. UNREFERENCED_PARAMETER(ReturnBuffer);
  492. UNREFERENCED_PARAMETER(ReturnBufferSize);
  493. UNREFERENCED_PARAMETER(RequiredSize);
  494. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  495. return(FALSE);
  496. }
  497. #endif
  498. BOOL
  499. SetupGetLineText(
  500. IN PINFCONTEXT Context, OPTIONAL
  501. IN HINF InfHandle, OPTIONAL
  502. IN PCTSTR Section, OPTIONAL
  503. IN PCTSTR Key, OPTIONAL
  504. OUT PTSTR ReturnBuffer, OPTIONAL
  505. IN DWORD ReturnBufferSize,
  506. OUT PDWORD RequiredSize OPTIONAL
  507. )
  508. /*++
  509. Routine Description:
  510. This function returns the contents of a line in a compact format.
  511. All extraneous whitespace is removed, and multi-line values are converted
  512. into a single contiguous string.
  513. For example, consider the following extract from an INF:
  514. HKLM, , Foo, 1, \
  515. ; This is a comment
  516. 01, 02, 03
  517. would be returned as:
  518. HKLM,,Foo,1,01,02,03
  519. Arguments:
  520. Context - Supplies context for an inf line whose text is to be retreived.
  521. If not specified, then InfHandle, Section, and Key must be.
  522. InfHandle - Supplies handle of the INF file to query.
  523. Only used if Context is NULL.
  524. Section - points to a null-terminated string that specifies the section
  525. containing the key nameof the line whose text is to be retreived.
  526. (Only used if InfLineHandle is NULL.)
  527. Key - Points to the null-terminated string containing the key name
  528. whose associated string is to be retrieved. (Only used if InfLineHandle is NULL.)
  529. ReturnBuffer - Points to the buffer that receives the retrieved string.
  530. ReturnBufferSize - Specifies the size, in characters, of the buffer pointed to
  531. by the ReturnBuffer parameter.
  532. RequiredSize - Receives the actual number of characters needed for the buffer
  533. pointed to by the ReturnBuffer parameter. If this value is larger than the
  534. value specified in the ReturnBufferSize parameter, the function fails and
  535. the function stores no data in the buffer.
  536. Return Value:
  537. If the function succeeds, the return value is TRUE.
  538. If the function fails, the return value is FALSE. To get extended error information,
  539. call GetLastError.
  540. --*/
  541. {
  542. INFCONTEXT context;
  543. BOOL b;
  544. UINT FieldCount;
  545. UINT u;
  546. BOOL InsufficientBuffer;
  547. DWORD OldSize, TmpRequiredSize;
  548. PCTSTR Field;
  549. //
  550. // Set up inf context.
  551. //
  552. if(Context) {
  553. u = NO_ERROR;
  554. try {
  555. context = *Context;
  556. } except(EXCEPTION_EXECUTE_HANDLER) {
  557. u = ERROR_INVALID_PARAMETER;
  558. }
  559. if(u != NO_ERROR) {
  560. SetLastError(u);
  561. return(FALSE);
  562. }
  563. } else {
  564. if(!InfHandle || !Section || !Key) {
  565. SetLastError(ERROR_INVALID_PARAMETER);
  566. return FALSE;
  567. }
  568. if(!SetupFindFirstLine(InfHandle, Section, Key, &context)) {
  569. return FALSE;
  570. }
  571. }
  572. //
  573. // Figure out how many fields are involved.
  574. //
  575. InsufficientBuffer = FALSE;
  576. if(FieldCount = SetupGetFieldCount(&context)) {
  577. TmpRequiredSize = 0;
  578. for(u=0; u<FieldCount; u++) {
  579. Field = pSetupGetField(&context, u+1);
  580. MYASSERT(Field);
  581. OldSize = TmpRequiredSize;
  582. TmpRequiredSize += lstrlen(Field)+1;
  583. if(ReturnBuffer) {
  584. if(TmpRequiredSize > ReturnBufferSize) {
  585. InsufficientBuffer = TRUE;
  586. } else {
  587. //
  588. // lstrcpy is safe even with bad pointers
  589. // (at least on NT)
  590. //
  591. lstrcpy(ReturnBuffer+OldSize, Field);
  592. ReturnBuffer[TmpRequiredSize - 1] = TEXT(',');
  593. }
  594. }
  595. }
  596. //
  597. // 0-terminate the buffer by overwriting the final comma.
  598. //
  599. if(ReturnBuffer && !InsufficientBuffer) {
  600. ReturnBuffer[TmpRequiredSize - 1] = TEXT('\0');
  601. }
  602. } else {
  603. //
  604. // Special case when no values -- need 1 byte for nul.
  605. //
  606. if (GetLastError() != NO_ERROR) {
  607. //
  608. // actually, something went wrong reading the data from our context...
  609. // bail out
  610. //
  611. return(FALSE);
  612. }
  613. TmpRequiredSize = 1;
  614. if(ReturnBuffer) {
  615. if(ReturnBufferSize) {
  616. *ReturnBuffer = TEXT('\0');
  617. } else {
  618. InsufficientBuffer = TRUE;
  619. }
  620. }
  621. }
  622. if(RequiredSize) {
  623. u = NO_ERROR;
  624. try {
  625. *RequiredSize = TmpRequiredSize;
  626. } except(EXCEPTION_EXECUTE_HANDLER) {
  627. u = ERROR_INVALID_PARAMETER;
  628. }
  629. if(u != NO_ERROR) {
  630. SetLastError(u);
  631. return(FALSE);
  632. }
  633. }
  634. if(InsufficientBuffer) {
  635. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  636. return FALSE;
  637. }
  638. return TRUE;
  639. }
  640. #ifdef UNICODE
  641. //
  642. // ANSI version
  643. //
  644. BOOL
  645. SetupGetMultiSzFieldA(
  646. IN PINFCONTEXT Context,
  647. IN DWORD FieldIndex,
  648. OUT PSTR ReturnBuffer, OPTIONAL
  649. IN DWORD ReturnBufferSize,
  650. OUT LPDWORD RequiredSize OPTIONAL
  651. )
  652. {
  653. PCTSTR Field;
  654. UINT FieldCount;
  655. UINT u;
  656. UINT Len;
  657. BOOL InsufficientBuffer;
  658. DWORD OldSize, TmpRequiredSize;
  659. DWORD rc;
  660. PCSTR field;
  661. rc = NO_ERROR;
  662. //
  663. // Disallow keys
  664. //
  665. if(FieldIndex == 0) {
  666. SetLastError(ERROR_INVALID_PARAMETER);
  667. return FALSE;
  668. }
  669. //
  670. // Figure out how many fields are involved.
  671. //
  672. FieldCount = SetupGetFieldCount(Context);
  673. if (FieldCount == 0 && GetLastError() != NO_ERROR) {
  674. return FALSE;
  675. }
  676. if(FieldCount > (FieldIndex-1)) {
  677. FieldCount -= FieldIndex - 1;
  678. } else {
  679. FieldCount = 0;
  680. }
  681. //
  682. // Need at least one byte for the terminating nul.
  683. //
  684. TmpRequiredSize = 1;
  685. InsufficientBuffer = FALSE;
  686. if(ReturnBuffer) {
  687. if(ReturnBufferSize) {
  688. try {
  689. *ReturnBuffer = 0;
  690. } except(EXCEPTION_EXECUTE_HANDLER) {
  691. rc = ERROR_INVALID_PARAMETER;
  692. }
  693. if(rc != NO_ERROR) {
  694. SetLastError(rc);
  695. return(FALSE);
  696. }
  697. } else {
  698. InsufficientBuffer = TRUE;
  699. }
  700. }
  701. for(u=0; u<FieldCount; u++) {
  702. try {
  703. Field = pSetupGetField(Context, u+FieldIndex);
  704. } except(EXCEPTION_EXECUTE_HANDLER) {
  705. rc = ERROR_INVALID_PARAMETER;
  706. }
  707. if(rc != NO_ERROR) {
  708. SetLastError(rc);
  709. return(FALSE);
  710. }
  711. MYASSERT(Field);
  712. field = pSetupUnicodeToAnsi(Field);
  713. if(!field) {
  714. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  715. return(FALSE);
  716. }
  717. if((Len = lstrlenA(field)+1) == 1) {
  718. //
  719. // Then we've encountered an empty field. Since multi-sz lists can't contain
  720. // an empty string, this terminates our list.
  721. //
  722. MyFree(field);
  723. goto clean0;
  724. }
  725. OldSize = TmpRequiredSize;
  726. TmpRequiredSize += Len;
  727. if(ReturnBuffer) {
  728. if(TmpRequiredSize > ReturnBufferSize) {
  729. InsufficientBuffer = TRUE;
  730. } else {
  731. //
  732. // lstrcpy is safe with bad pointers (at least on NT)
  733. //
  734. lstrcpyA(ReturnBuffer+OldSize-1,field);
  735. ReturnBuffer[TmpRequiredSize - 1] = 0;
  736. }
  737. }
  738. MyFree(field);
  739. }
  740. clean0:
  741. if(RequiredSize) {
  742. try {
  743. *RequiredSize = TmpRequiredSize;
  744. } except(EXCEPTION_EXECUTE_HANDLER) {
  745. rc = ERROR_INVALID_PARAMETER;
  746. }
  747. if(rc != NO_ERROR) {
  748. SetLastError(rc);
  749. return(FALSE);
  750. }
  751. }
  752. if(InsufficientBuffer) {
  753. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  754. return FALSE;
  755. }
  756. return TRUE;
  757. }
  758. #else
  759. //
  760. // Unicode stub
  761. //
  762. BOOL
  763. SetupGetMultiSzFieldW(
  764. IN PINFCONTEXT Context,
  765. IN DWORD FieldIndex,
  766. OUT PWSTR ReturnBuffer, OPTIONAL
  767. IN DWORD ReturnBufferSize,
  768. OUT LPDWORD RequiredSize OPTIONAL
  769. )
  770. {
  771. UNREFERENCED_PARAMETER(Context);
  772. UNREFERENCED_PARAMETER(FieldIndex);
  773. UNREFERENCED_PARAMETER(ReturnBuffer);
  774. UNREFERENCED_PARAMETER(ReturnBufferSize);
  775. UNREFERENCED_PARAMETER(RequiredSize);
  776. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  777. return(FALSE);
  778. }
  779. #endif
  780. BOOL
  781. SetupGetMultiSzField(
  782. IN PINFCONTEXT Context,
  783. IN DWORD FieldIndex,
  784. OUT PTSTR ReturnBuffer, OPTIONAL
  785. IN DWORD ReturnBufferSize,
  786. OUT LPDWORD RequiredSize OPTIONAL
  787. )
  788. /*++
  789. Routine Description:
  790. Arguments:
  791. Return Value:
  792. --*/
  793. {
  794. PCTSTR Field;
  795. UINT FieldCount;
  796. UINT u;
  797. UINT Len;
  798. BOOL InsufficientBuffer;
  799. DWORD OldSize, TmpRequiredSize;
  800. DWORD rc;
  801. rc = NO_ERROR;
  802. //
  803. // Disallow keys
  804. //
  805. if(FieldIndex == 0) {
  806. SetLastError(ERROR_INVALID_PARAMETER);
  807. return FALSE;
  808. }
  809. //
  810. // Figure out how many fields are involved.
  811. //
  812. FieldCount = SetupGetFieldCount(Context);
  813. if (FieldCount == 0 && GetLastError() != NO_ERROR) {
  814. return FALSE;
  815. }
  816. if(FieldCount > (FieldIndex-1)) {
  817. FieldCount -= FieldIndex - 1;
  818. } else {
  819. FieldCount = 0;
  820. }
  821. //
  822. // Need at least one byte for the terminating nul.
  823. //
  824. TmpRequiredSize = 1;
  825. InsufficientBuffer = FALSE;
  826. if(ReturnBuffer) {
  827. if(ReturnBufferSize) {
  828. try {
  829. *ReturnBuffer = 0;
  830. } except(EXCEPTION_EXECUTE_HANDLER) {
  831. rc = ERROR_INVALID_PARAMETER;
  832. }
  833. if(rc != NO_ERROR) {
  834. SetLastError(rc);
  835. return(FALSE);
  836. }
  837. } else {
  838. InsufficientBuffer = TRUE;
  839. }
  840. }
  841. for(u=0; u<FieldCount; u++) {
  842. try {
  843. Field = pSetupGetField(Context, u+FieldIndex);
  844. } except(EXCEPTION_EXECUTE_HANDLER) {
  845. rc = ERROR_INVALID_PARAMETER;
  846. }
  847. if(rc != NO_ERROR) {
  848. SetLastError(rc);
  849. return(FALSE);
  850. }
  851. MYASSERT(Field);
  852. if((Len = lstrlen(Field)+1) == 1) {
  853. //
  854. // Then we've encountered an empty field. Since multi-sz lists can't contain
  855. // an empty string, this terminates our list.
  856. //
  857. goto clean0;
  858. }
  859. OldSize = TmpRequiredSize;
  860. TmpRequiredSize += Len;
  861. if(ReturnBuffer) {
  862. if(TmpRequiredSize > ReturnBufferSize) {
  863. InsufficientBuffer = TRUE;
  864. } else {
  865. //
  866. // lstrcpy is safe with bad pointers (at least on NT)
  867. //
  868. lstrcpy(ReturnBuffer+OldSize-1, Field);
  869. ReturnBuffer[TmpRequiredSize - 1] = 0;
  870. }
  871. }
  872. }
  873. clean0:
  874. if(RequiredSize) {
  875. try {
  876. *RequiredSize = TmpRequiredSize;
  877. } except(EXCEPTION_EXECUTE_HANDLER) {
  878. rc = ERROR_INVALID_PARAMETER;
  879. }
  880. if(rc != NO_ERROR) {
  881. SetLastError(rc);
  882. return(FALSE);
  883. }
  884. }
  885. if(InsufficientBuffer) {
  886. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  887. return FALSE;
  888. }
  889. return TRUE;
  890. }
  891. BOOL
  892. SetupGetBinaryField(
  893. IN PINFCONTEXT Context,
  894. IN DWORD FieldIndex,
  895. OUT PBYTE ReturnBuffer, OPTIONAL
  896. IN DWORD ReturnBufferSize,
  897. OUT LPDWORD RequiredSize OPTIONAL
  898. )
  899. /*++
  900. Routine Description:
  901. Arguments:
  902. Return Value:
  903. --*/
  904. {
  905. PCTSTR Field;
  906. UINT FieldCount;
  907. UINT u;
  908. ULONG Value;
  909. BOOL Store;
  910. PTCHAR End;
  911. DWORD TmpRequiredSize;
  912. DWORD rc;
  913. rc = NO_ERROR;
  914. //
  915. // Disallow keys
  916. //
  917. if(FieldIndex == 0) {
  918. SetLastError(ERROR_INVALID_PARAMETER);
  919. return FALSE;
  920. }
  921. //
  922. // Figure out how many fields are involved.
  923. //
  924. FieldCount = SetupGetFieldCount(Context);
  925. if (FieldCount == 0 && GetLastError() != NO_ERROR) {
  926. return FALSE;
  927. }
  928. if(FieldCount > (FieldIndex-1)) {
  929. FieldCount -= FieldIndex - 1;
  930. } else {
  931. FieldCount = 0;
  932. }
  933. TmpRequiredSize = FieldCount;
  934. Store = (ReturnBuffer && (TmpRequiredSize <= ReturnBufferSize));
  935. //
  936. // Even though we know the required size,
  937. // go through the loop anyway to validate the data.
  938. //
  939. for(u=0; u<FieldCount; u++) {
  940. try {
  941. if(!(Field = pSetupGetField(Context,u+FieldIndex))) {
  942. rc = ERROR_INVALID_HANDLE;
  943. }
  944. } except(EXCEPTION_EXECUTE_HANDLER) {
  945. rc = ERROR_INVALID_PARAMETER;
  946. }
  947. if(rc != NO_ERROR) {
  948. SetLastError(rc);
  949. return(FALSE);
  950. }
  951. Value = _tcstoul(Field, &End, 16);
  952. //
  953. // Only the terminating nul should have caused the conversion
  954. // to stop. In any other case there were non-hex digits in the string.
  955. // Also disallow the empty string.
  956. //
  957. if((End == Field) || *End || (Value > 255)) {
  958. SetLastError(ERROR_INVALID_DATA);
  959. return FALSE;
  960. }
  961. if(Store) {
  962. try {
  963. *ReturnBuffer++ = (UCHAR)Value;
  964. } except(EXCEPTION_EXECUTE_HANDLER) {
  965. rc = ERROR_INVALID_PARAMETER;
  966. }
  967. if(rc != NO_ERROR) {
  968. SetLastError(rc);
  969. return(FALSE);
  970. }
  971. }
  972. }
  973. if(RequiredSize) {
  974. try {
  975. *RequiredSize = TmpRequiredSize;
  976. } except(EXCEPTION_EXECUTE_HANDLER) {
  977. rc = ERROR_INVALID_PARAMETER;
  978. }
  979. if(rc != NO_ERROR) {
  980. SetLastError(rc);
  981. return(FALSE);
  982. }
  983. }
  984. if(ReturnBuffer && (TmpRequiredSize > ReturnBufferSize)) {
  985. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  986. return FALSE;
  987. }
  988. return TRUE;
  989. }
  990. PINF_LINE
  991. InfLineFromContext(
  992. IN PINFCONTEXT Context
  993. )
  994. /*++
  995. Routine Description:
  996. Given an INF context, return a pointer to the inf line structure.
  997. Arguments:
  998. Context - supplies a pointer to the context structure that was filled
  999. in by one of the line-related INF APIs.
  1000. No validation is performed on any value in the context structure.
  1001. Return Value:
  1002. Pointer to the relevent inf line structure.
  1003. --*/
  1004. {
  1005. PLOADED_INF Inf;
  1006. PINF_SECTION Section;
  1007. PINF_LINE Line;
  1008. Inf = (PLOADED_INF)Context->CurrentInf;
  1009. if(!LockInf((PLOADED_INF)Context->Inf)) {
  1010. return(NULL);
  1011. }
  1012. Section = &Inf->SectionBlock[Context->Section];
  1013. Line = &Inf->LineBlock[Section->Lines + Context->Line];
  1014. UnlockInf((PLOADED_INF)Context->Inf);
  1015. return(Line);
  1016. }
  1017. /////////////////////////////////////////////////////////////////
  1018. //
  1019. // Internal routines
  1020. //
  1021. /////////////////////////////////////////////////////////////////
  1022. BOOL
  1023. pSetupGetSecurityInfo(
  1024. IN HINF Inf,
  1025. IN PCTSTR SectionName,
  1026. OUT PCTSTR *SecDesc )
  1027. {
  1028. BOOL b;
  1029. PTSTR SecuritySectionName;
  1030. INFCONTEXT LineContext;
  1031. DWORD rc;
  1032. SecuritySectionName = (PTSTR)MyMalloc( ((lstrlen(SectionName) + lstrlen((PCTSTR)L".Security"))*sizeof(TCHAR)) + 3l );
  1033. if( !SecuritySectionName ){
  1034. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1035. return( FALSE );
  1036. }
  1037. lstrcpy( SecuritySectionName, SectionName );
  1038. lstrcat( SecuritySectionName, (PCTSTR)(L".Security") );
  1039. b = SetupFindFirstLine(Inf,(PCTSTR)SecuritySectionName,NULL,&LineContext);
  1040. MyFree( SecuritySectionName );
  1041. if(!b)
  1042. return( FALSE ); // Section did not exist or other error
  1043. if( !(*SecDesc = pSetupGetField( &LineContext, 1 )) )
  1044. return( FALSE ); // Error code is present by checking GetLastError() if needed
  1045. else
  1046. return( TRUE );
  1047. }
  1048. PCTSTR
  1049. pSetupGetField(
  1050. IN PINFCONTEXT Context,
  1051. IN DWORD FieldIndex
  1052. )
  1053. /*++
  1054. Routine Description:
  1055. Retreive a field from a line.
  1056. Arguments:
  1057. Context - supplies inf context. No validation is performed
  1058. on the values contained in this structure.
  1059. FieldIndex - supplies 1-based index of field to retreive.
  1060. An index of 0 retreives the key, if it exists.
  1061. Return Value:
  1062. Pointer to string. The caller must not write into this buffer.
  1063. If the field index is not valid, the return value is NULL,
  1064. and SetLastError() will have been called.
  1065. --*/
  1066. {
  1067. PINF_LINE Line;
  1068. PTSTR p = NULL;
  1069. DWORD Err = NO_ERROR;
  1070. //
  1071. // InfLineFromContext does it's own INF locking, but the later call
  1072. // to InfGetField doesn't, so go ahead and grab the lock up front.
  1073. //
  1074. if(LockInf((PLOADED_INF)Context->Inf)) {
  1075. if(Line = InfLineFromContext(Context)) {
  1076. if((p = InfGetField(Context->CurrentInf,Line,FieldIndex,NULL)) == NULL) {
  1077. Err = ERROR_INVALID_PARAMETER;
  1078. }
  1079. } else {
  1080. Err = ERROR_INVALID_PARAMETER;
  1081. }
  1082. UnlockInf((PLOADED_INF)Context->Inf);
  1083. } else {
  1084. Err = ERROR_INVALID_HANDLE;
  1085. }
  1086. SetLastError(Err);
  1087. return p;
  1088. }
  1089. BOOL
  1090. pSetupGetDriverDate(
  1091. IN HINF InfHandle,
  1092. IN PCTSTR Section,
  1093. IN OUT PFILETIME pFileTime
  1094. )
  1095. /*++
  1096. Routine Description:
  1097. Retreive the date from a specified Section.
  1098. The Date specified in an INF section has the following format:
  1099. DriverVer=xx/yy/zzzz
  1100. or
  1101. DriverVer=xx-yy-zzzz
  1102. where xx is the month, yy is the day, and zzzz is the for digit year.
  1103. Note that the year MUST be 4 digits. A year of 98 will be considered
  1104. 0098 and not 1998!
  1105. This date should be the date of the Drivers and not for the INF itself.
  1106. So a single INF can have multiple driver install Sections and each can
  1107. have different dates depending on when the driver was last updated.
  1108. Arguments:
  1109. InfHandle - Supplies handle of the INF file to query.
  1110. Section - points to a null-terminated string that specifies the section
  1111. of the driver to get the FILETIME infomation.
  1112. pFileTime - points to a FILETIME structure that will receive the Date,
  1113. if it exists.
  1114. Return Value:
  1115. BOOL. TRUE if a valid date existed in the specified Section and FALSE otherwise.
  1116. --*/
  1117. {
  1118. DWORD rc;
  1119. SYSTEMTIME SystemTime;
  1120. INFCONTEXT InfContext;
  1121. TCHAR DriverDate[20];
  1122. PTSTR Convert, Temp;
  1123. DWORD Value;
  1124. rc = NO_ERROR;
  1125. try {
  1126. *DriverDate = 0;
  1127. ZeroMemory(&SystemTime, sizeof(SYSTEMTIME));
  1128. pFileTime->dwLowDateTime = 0;
  1129. pFileTime->dwHighDateTime = 0;
  1130. if(SetupFindFirstLine(InfHandle, Section, pszDriverVer, &InfContext)) {
  1131. if ((SetupGetStringField(&InfContext,
  1132. 1,
  1133. DriverDate,
  1134. SIZECHARS(DriverDate),
  1135. NULL)) &&
  1136. (*DriverDate)) {
  1137. Convert = DriverDate;
  1138. if (*Convert) {
  1139. Temp = DriverDate;
  1140. while (*Temp && (*Temp != TEXT('-')) && (*Temp != TEXT('/')))
  1141. Temp++;
  1142. if (*Temp == TEXT('\0')) {
  1143. //
  1144. // There is no day or year in this date, so just exit.
  1145. //
  1146. leave;
  1147. }
  1148. *Temp = 0;
  1149. //
  1150. //Convert the month
  1151. //
  1152. pAToI(Convert, (PINT)&Value);
  1153. SystemTime.wMonth = LOWORD(Value);
  1154. Convert = Temp+1;
  1155. if (*Convert) {
  1156. Temp = Convert;
  1157. while (*Temp && (*Temp != TEXT('-')) && (*Temp != TEXT('/')))
  1158. Temp++;
  1159. if (*Temp == TEXT('\0')) {
  1160. //
  1161. // There is no day or year in this date, so just exit.
  1162. //
  1163. leave;
  1164. }
  1165. *Temp = 0;
  1166. //
  1167. //Convert the day
  1168. //
  1169. pAToI(Convert, (PINT)&Value);
  1170. SystemTime.wDay = LOWORD(Value);
  1171. Convert = Temp+1;
  1172. if (*Convert) {
  1173. //
  1174. //Convert the year
  1175. //
  1176. pAToI(Convert, (PINT)&Value);
  1177. SystemTime.wYear = LOWORD(Value);
  1178. //
  1179. //Convert SYSTEMTIME into FILETIME
  1180. //
  1181. SystemTimeToFileTime(&SystemTime, pFileTime);
  1182. }
  1183. }
  1184. }
  1185. }
  1186. }
  1187. } except(EXCEPTION_EXECUTE_HANDLER) {
  1188. rc = ERROR_INVALID_PARAMETER;
  1189. SetLastError(rc);
  1190. return FALSE;
  1191. }
  1192. SetLastError(NO_ERROR);
  1193. return((pFileTime->dwLowDateTime != 0) || (pFileTime->dwHighDateTime != 0));
  1194. }
  1195. BOOL
  1196. pSetupGetDriverVersion(
  1197. IN HINF InfHandle,
  1198. IN PCTSTR Section,
  1199. OUT DWORDLONG *Version
  1200. )
  1201. /*++
  1202. Routine Description:
  1203. Retreive the driver version from a specified Section.
  1204. The driver version specified in an INF section has the following format:
  1205. DriverVer=xx/yy/zzzz, a.b.c.d
  1206. or
  1207. DriverVer=xx-yy-zzzz, a.b.c.d
  1208. a.b.c.d is the version of the driver, where a, b, c, and d are all WORD
  1209. decimal values.
  1210. The version is in the second field in the DriverVer INF value, the driver date
  1211. is in the first field.
  1212. Arguments:
  1213. InfHandle - Supplies handle of the INF file to query.
  1214. Section - points to a null-terminated string that specifies the section
  1215. of the driver to get the FILETIME infomation.
  1216. Version - points to a DWORDLONG value that will receive the version,
  1217. if it exists.
  1218. Return Value:
  1219. BOOL. TRUE if a valid driver version existed in the specified Section and FALSE otherwise.
  1220. --*/
  1221. {
  1222. DWORD rc;
  1223. INFCONTEXT InfContext;
  1224. TCHAR DriverVersion[LINE_LEN];
  1225. BOOL bEnd = FALSE;
  1226. INT MajorHiWord, MajorLoWord, MinorHiWord, MinorLoWord;
  1227. PTSTR Convert, Temp;
  1228. rc = NO_ERROR;
  1229. try {
  1230. *DriverVersion = 0;
  1231. *Version = 0;
  1232. MajorHiWord = MajorLoWord = MinorHiWord = MinorLoWord = 0;
  1233. if(SetupFindFirstLine(InfHandle, Section, pszDriverVer, &InfContext)) {
  1234. if ((SetupGetStringField(&InfContext,
  1235. 2,
  1236. DriverVersion,
  1237. SIZECHARS(DriverVersion),
  1238. NULL)) &&
  1239. (*DriverVersion)) {
  1240. Convert = DriverVersion;
  1241. if (*Convert) {
  1242. Temp = DriverVersion;
  1243. while (*Temp && (*Temp != TEXT('.'))) {
  1244. Temp++;
  1245. }
  1246. if (!*Temp) {
  1247. bEnd = TRUE;
  1248. }
  1249. *Temp = 0;
  1250. //
  1251. //Convert the HIWORD of the major version
  1252. //
  1253. if (pAToI(Convert, (PINT)&MajorHiWord)) {
  1254. Convert = Temp+1;
  1255. if (!bEnd && *Convert) {
  1256. Temp = Convert;
  1257. while (*Temp && (*Temp != TEXT('.'))) {
  1258. Temp++;
  1259. }
  1260. if (!*Temp) {
  1261. bEnd = TRUE;
  1262. }
  1263. *Temp = 0;
  1264. //
  1265. //Convert the LOWORD of the major version
  1266. //
  1267. if (pAToI(Convert, (PINT)&MajorLoWord)) {
  1268. Convert = Temp+1;
  1269. if (!bEnd && *Convert) {
  1270. Temp = Convert;
  1271. while (*Temp && (*Temp != TEXT('.'))) {
  1272. Temp++;
  1273. }
  1274. if (!*Temp) {
  1275. bEnd = TRUE;
  1276. }
  1277. *Temp = 0;
  1278. //
  1279. //Convert the HIWORD of the minor version
  1280. //
  1281. if (pAToI(Convert, (PINT)&MinorHiWord)) {
  1282. Convert = Temp+1;
  1283. if (!bEnd && *Convert) {
  1284. Temp = Convert;
  1285. while (*Temp && (*Temp != TEXT('.'))) {
  1286. Temp++;
  1287. }
  1288. *Temp = 0;
  1289. //
  1290. //Convert the LOWORD of the minor version
  1291. //
  1292. pAToI(Convert, (PINT)&MinorLoWord);
  1293. }
  1294. }
  1295. }
  1296. }
  1297. }
  1298. }
  1299. *Version = (((DWORDLONG)MajorHiWord << 48) +
  1300. ((DWORDLONG)MajorLoWord << 32) +
  1301. ((DWORDLONG)MinorHiWord << 16) +
  1302. (DWORDLONG)MinorLoWord);
  1303. }
  1304. }
  1305. }
  1306. } except(EXCEPTION_EXECUTE_HANDLER) {
  1307. rc = ERROR_INVALID_PARAMETER;
  1308. *Version = 0;
  1309. SetLastError(rc);
  1310. return FALSE;
  1311. }
  1312. SetLastError(NO_ERROR);
  1313. return(*Version != 0);
  1314. }