Source code of Windows XP (NT5)
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.

1222 lines
32 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. setupapi.hpp
  5. Abstract:
  6. Wrapper class library for setup api
  7. Author:
  8. Vijay Jayaseelan (vijayj) 04 Aug 2000
  9. Revision History:
  10. None
  11. --*/
  12. #pragma once
  13. //
  14. // Disable the compiler warning for long names
  15. //
  16. #pragma warning( disable : 4786 )
  17. extern "C" {
  18. #include <windows.h>
  19. #include <setupapi.h>
  20. #include <spapip.h>
  21. }
  22. #include <iostream>
  23. #include <vector>
  24. #include <map>
  25. #include <string>
  26. //
  27. // Wide string output routine
  28. //
  29. std::string&
  30. ToAnsiString(std::string &lhs, const std::wstring &rhs);
  31. std::ostream&
  32. operator<<(std::ostream &lhs, const std::basic_string<WCHAR> &rhs);
  33. std::ostream&
  34. operator<<(std::ostream &lhs, PCWSTR rhs);
  35. //
  36. // Exception classes
  37. //
  38. template<class T>
  39. class BaseException {
  40. public:
  41. BaseException(){}
  42. BaseException(const std::basic_string<T> &Info)
  43. : ExceptionInfo(Info) {}
  44. virtual ~BaseException(){}
  45. virtual void Dump(std::ostream &os) = 0;
  46. protected:
  47. std::basic_string<T> ExceptionInfo;
  48. };
  49. template<class T>
  50. class InvalidValueIndex : public BaseException<T>{
  51. public:
  52. InvalidValueIndex(unsigned int Idx) : Index(Idx){}
  53. void Dump(std::ostream &os) {
  54. os << "Invalid value index : (" << std::dec
  55. << Index << ")" << std::endl;
  56. }
  57. private:
  58. unsigned int Index;
  59. };
  60. template<class T>
  61. class InvalidValueKey : public BaseException<T>{
  62. public:
  63. InvalidValueKey(const std::basic_string<T> &SecName,
  64. const std::basic_string<T> &Key) : SectionName(SecName), KeyName(Key){}
  65. void Dump(std::ostream &os) {
  66. os << "Invalid value key name (" << KeyName << ")"
  67. << " in " << SectionName << " section." << std::endl;
  68. }
  69. private:
  70. std::basic_string<T> SectionName, KeyName;
  71. };
  72. //
  73. // Abstracts a Win32 error
  74. //
  75. template <class T>
  76. class W32Exception : public BaseException<T> {
  77. public:
  78. W32Exception(DWORD ErrCode = GetLastError()) : ErrorCode(ErrCode){}
  79. void Dump(std::ostream &os) {
  80. T MsgBuffer[4096];
  81. MsgBuffer[0] = NULL;
  82. DWORD CharCount;
  83. if (sizeof(T) == sizeof(WCHAR)) {
  84. CharCount = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM,
  85. NULL,
  86. ErrorCode,
  87. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  88. (PWSTR)MsgBuffer,
  89. sizeof(MsgBuffer)/sizeof(WCHAR),
  90. NULL);
  91. if (CharCount) {
  92. std::wstring Msg((PWSTR)MsgBuffer);
  93. os << Msg;
  94. } else {
  95. os << std::hex << ErrorCode;
  96. }
  97. } else {
  98. CharCount = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM,
  99. NULL,
  100. ErrorCode,
  101. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  102. (PSTR)MsgBuffer,
  103. sizeof(MsgBuffer)/sizeof(CHAR),
  104. NULL);
  105. if (CharCount) {
  106. std::string Msg((PCSTR)MsgBuffer);
  107. os << Msg;
  108. } else {
  109. os << std::hex << ErrorCode;
  110. }
  111. }
  112. }
  113. DWORD GetErrorCode() const { return ErrorCode; }
  114. protected:
  115. DWORD ErrorCode;
  116. };
  117. template<class T>
  118. class Section;
  119. template<class T>
  120. class SectionValues {
  121. public:
  122. SectionValues(Section<T> &Sec, ULONG LineIdx, bool New = false);
  123. SectionValues(Section<T> &Sec, const std::basic_string<T> &Key,
  124. ULONG LineIdx, bool New = false);
  125. void PutValue(ULONG Index, const std::basic_string<T> &Val) {
  126. Values[Index] = Val;
  127. GetContainer().GetContainer().SetDirty();
  128. }
  129. const std::basic_string<T>& GetValue(ULONG Index) const {
  130. return Values[Index];
  131. }
  132. void AppendValue(const std::basic_string<T> &Val) {
  133. Values.push_back(Val);
  134. GetContainer().GetContainer().SetDirty();
  135. }
  136. void ClearValues() {
  137. Values.clear();
  138. GetContainer().GetContainer().SetDirty();
  139. }
  140. ULONG Count() const {
  141. return Values.size();
  142. }
  143. Section<T>& GetContainer() { return Container; }
  144. const std::basic_string<T>& GetName() const { return Name; }
  145. ULONG GetIndex() const { return Index; }
  146. friend std::ostream& operator<<(std::ostream &os, SectionValues<T> &rhs);
  147. protected:
  148. //
  149. // data members
  150. //
  151. ULONG Index;
  152. std::basic_string<T> Name;
  153. std::vector< std::basic_string<T> > Values;
  154. Section<T> &Container;
  155. };
  156. template<class T>
  157. struct InvalidInfSection : public BaseException<T> {
  158. public:
  159. InvalidInfSection(const std::basic_string<T> &SecName,
  160. const std::basic_string<T> &InfName)
  161. : Name(SecName), FileName(InfName){}
  162. std::basic_string<T> Name;
  163. std::basic_string<T> FileName;
  164. void Dump(std::ostream &os) {
  165. os << "InvalidInfSection : " << Name << " in "
  166. << FileName << std::endl;
  167. }
  168. };
  169. //
  170. // forward declaration
  171. //
  172. template<class T>
  173. class InfFile;
  174. template<class T>
  175. class Section {
  176. public:
  177. Section(InfFile<T> &file, const std::basic_string<T> &name);
  178. Section(InfFile<T> &file, const std::basic_string<T> &name, bool NoKey) :
  179. File(file), Name(name), Keyless(NoKey) {}
  180. ~Section(){}
  181. const std::basic_string<T>& GetName() const{
  182. return Name;
  183. }
  184. SectionValues<T>& GetValue(const std::basic_string<T> &Key) {
  185. std::vector< SectionValues<T> *>::iterator Iter = Lines.begin();
  186. SectionValues<T> *Values = NULL;
  187. while (Iter != Lines.end()) {
  188. Values = (*Iter);
  189. if (sizeof(T) == sizeof(CHAR)) {
  190. if (!_stricmp((PCSTR)Values->GetName().c_str(),
  191. (PCSTR)Key.c_str())) {
  192. break;
  193. }
  194. } else {
  195. if (!_wcsicmp((PCWSTR)Values->GetName().c_str(),
  196. (PCWSTR)Key.c_str())) {
  197. break;
  198. }
  199. }
  200. Iter++;
  201. }
  202. if (Iter == Lines.end()) {
  203. throw new InvalidValueKey<T>(Name, Key);
  204. }
  205. return *Values;
  206. }
  207. //
  208. // Note : For the following scenario
  209. //
  210. // [Section]
  211. // a
  212. // b,c
  213. //
  214. // a & b are treated as Keys i.e. for keyless sections
  215. // the first value is treated as a key
  216. //
  217. bool IsKeyPresent(const std::basic_string<T> &Key) const {
  218. bool Result = false;
  219. if (!IsKeyless()) {
  220. std::vector< SectionValues<T> *>::const_iterator Iter = Lines.begin();
  221. SectionValues<T> *Values = NULL;
  222. while (Iter != Lines.end()) {
  223. Values = (*Iter);
  224. if (sizeof(T) == sizeof(CHAR)) {
  225. if (!_stricmp((PCSTR)Values->GetName().c_str(),
  226. (PCSTR)Key.c_str())) {
  227. break;
  228. }
  229. } else {
  230. if (!_wcsicmp((PCWSTR)Values->GetName().c_str(),
  231. (PCWSTR)Key.c_str())) {
  232. break;
  233. }
  234. }
  235. Iter++;
  236. }
  237. Result = (Iter != Lines.end());
  238. } else {
  239. std::vector< SectionValues<T> *>::const_iterator Iter = KeylessLines.begin();
  240. SectionValues<T> *Values = NULL;
  241. while (Iter != KeylessLines.end()) {
  242. Values = (*Iter);
  243. if (sizeof(T) == sizeof(CHAR)) {
  244. if (!_stricmp((PCSTR)Values->GetValue(0).c_str(),
  245. (PCSTR)Key.c_str())) {
  246. break;
  247. }
  248. } else {
  249. if (!_wcsicmp((PCWSTR)Values->GetValue(0).c_str(),
  250. (PCWSTR)Key.c_str())) {
  251. break;
  252. }
  253. }
  254. Iter++;
  255. }
  256. Result = (Iter != KeylessLines.end());
  257. }
  258. return Result;
  259. }
  260. SectionValues<T>& GetValue(ULONG Index) {
  261. return *(KeylessLines[Index]);
  262. }
  263. InfFile<T>& GetContainer() { return File; }
  264. bool IsKeyless() const { return Keyless; }
  265. Section<T>& operator+=(Section<T> &rhs) {
  266. if (IsKeyless() == rhs.IsKeyless()) {
  267. //
  268. // add entries with key
  269. //
  270. std::vector< SectionValues<T> *>::iterator Iter = rhs.Lines.begin();
  271. while (Iter != rhs.Lines.end()) {
  272. Lines.push_back(*Iter);
  273. Iter++;
  274. }
  275. //
  276. // add entries without key
  277. //
  278. std::vector< SectionValues<T> *>::iterator KlIter = rhs.KeylessLines.begin();
  279. while (KlIter != rhs.KeylessLines.end()) {
  280. KeylessLines.push_back(*KlIter);
  281. KlIter++;
  282. }
  283. } else {
  284. throw new InvalidInfSection<T>(File.GetName(), rhs.GetName());
  285. }
  286. return *this;
  287. }
  288. SectionValues<T>* AddLine(const std::basic_string<T> &Key) {
  289. SectionValues<T> *Value = NULL;
  290. if (Key.length() && !IsKeyless()) {
  291. Value = new SectionValues<T>(*this, Key, 0, true);
  292. if (Value) {
  293. Lines.push_back(Value);
  294. }
  295. } else {
  296. Value = new SectionValues<T>(*this, KeylessLines.size(), true);
  297. if (Value) {
  298. KeylessLines.push_back(Value);
  299. }
  300. }
  301. File.SetDirty();
  302. return Value;
  303. }
  304. friend std::ostream& operator<<(std::ostream &os, Section<T> &rhs);
  305. //
  306. // Callback function pointer for
  307. // working on each section element
  308. //
  309. typedef void (*ELEMENT_WORKER)(
  310. SectionValues<T> &Values,
  311. void *ContextData
  312. );
  313. void DoForEach(ELEMENT_WORKER Worker, void *ContextData);
  314. //
  315. // Iterator
  316. //
  317. class Iterator{
  318. public:
  319. Iterator(std::vector< SectionValues<T> *> *Collect = NULL) {
  320. Collection = Collect;
  321. if (Collection) {
  322. Iter = (*Collection).begin();
  323. }
  324. }
  325. Iterator& begin() {
  326. if (Collection) {
  327. Iter = Collection->begin();
  328. }
  329. return *this;
  330. }
  331. bool end() {
  332. return Collection? (Iter == Collection->end()) : true;
  333. }
  334. Iterator& operator++(int) {
  335. if (Collection) {
  336. Iter++;
  337. }
  338. return *this;
  339. }
  340. friend SectionValues<T> * operator*(Iterator &lhs) {
  341. return lhs.Collection ? *(lhs.Iter): NULL;
  342. }
  343. friend Section<T>;
  344. protected:
  345. void Init(std::vector< SectionValues<T> *> *Collect) {
  346. Collection = Collect;
  347. Iter = (*Collection).begin();
  348. }
  349. private:
  350. //
  351. // data members
  352. //
  353. std::vector< SectionValues<T> * >::iterator Iter;
  354. std::vector< SectionValues<T> *> *Collection;
  355. };
  356. Iterator begin(void) {
  357. Iterator Iter;
  358. if (IsKeyless()) {
  359. if (KeylessLines.size()) {
  360. Iter.Init(&KeylessLines);
  361. }
  362. } else {
  363. if (Lines.size()) {
  364. Iter.Init(&Lines);
  365. }
  366. }
  367. return Iter;
  368. }
  369. protected:
  370. //
  371. // data members
  372. //
  373. InfFile<T> &File;
  374. std::basic_string<T> Name;
  375. std::vector< SectionValues<T> *> Lines;
  376. std::vector< SectionValues<T> *> KeylessLines;
  377. bool Keyless;
  378. };
  379. template<class T>
  380. class InvalidInfFile : public BaseException<T> {
  381. public:
  382. InvalidInfFile() : ErrorCode(0){}
  383. InvalidInfFile(const std::basic_string<T> &Name) :
  384. FileName(Name), ErrorCode(0) {}
  385. InvalidInfFile(const std::basic_string<T> &Name, DWORD ErrCode) :
  386. FileName(Name), ErrorCode(ErrCode) {}
  387. void Dump(std::ostream &os) {
  388. os << "Invalid INF file " << FileName;
  389. if (ErrorCode) {
  390. os << " (" << std::dec << ErrorCode << ") ";
  391. }
  392. os << std::endl;
  393. }
  394. protected:
  395. std::basic_string<T> FileName;
  396. DWORD ErrorCode;
  397. };
  398. template<class T>
  399. class InvalidInfFormat : public InvalidInfFile<T> {
  400. public:
  401. InvalidInfFormat(const std::basic_string<T> &Name, UINT Line) :
  402. InvalidInfFile<T>(Name), ErrorLine(Line) {}
  403. void Dump(std::ostream &os) {
  404. os << "Invalid INF format at " << std::dec
  405. << ErrorLine << " line of " << FileName << std::endl;
  406. }
  407. UINT ErrorLine;
  408. };
  409. //
  410. // Inf file abstraction
  411. //
  412. template <class T>
  413. class InfFile {
  414. public:
  415. InfFile(const std::basic_string<T> &name);
  416. virtual ~InfFile() {
  417. if (InfHandle && (InfHandle != INVALID_HANDLE_VALUE)) {
  418. SetupCloseInfFile(InfHandle);
  419. }
  420. if (Dirty) {
  421. //CommitChanges();
  422. }
  423. SetupApiUseCount--;
  424. if (!SetupApiUseCount) {
  425. FreeLibrary(SetupApiModuleHandle);
  426. GetInfSections = NULL;
  427. }
  428. }
  429. const std::basic_string<T>& GetName() const {
  430. return Name;
  431. }
  432. friend bool operator==(const InfFile<T> &lhs, const InfFile<T> &rhs) {
  433. return lhs.GetName() == rhs.GetName();
  434. }
  435. friend bool operator!=(const InfFile<T> &lhs, const InfFile<T> &rhs) {
  436. return !(lhs == rhs);
  437. }
  438. void GetLines(Section<T> &Sec,
  439. std::vector< SectionValues<T> *> &Lines,
  440. std::vector< SectionValues<T> *> &KeylessLines);
  441. void GetValues(Section<T> &Sec,
  442. SectionValues<T> &SecValues,
  443. std::vector< std::basic_string<T> > &Values);
  444. friend std::ostream& operator<<(std::ostream &os, InfFile<T> &rhs) {
  445. InfFile<T>::Iterator Iter = rhs.begin();
  446. while (!Iter.end()) {
  447. os << **Iter << std::endl;
  448. Iter++;
  449. }
  450. return os;
  451. }
  452. Section<T>* AddSection(const std::basic_string<T> &SecName, bool Keyless) {
  453. Section<T> *NewSection = NULL;
  454. try {
  455. NewSection = GetSection(SecName);
  456. } catch(...) {
  457. }
  458. if (!NewSection) {
  459. Sections[SecName] = NewSection =
  460. new Section<T>(*this, SecName, Keyless);
  461. SetDirty();
  462. }
  463. return NewSection;
  464. }
  465. Section<T>* GetSection(const std::basic_string<T> &SecName) {
  466. std::map< std::basic_string<T>, Section<T> *>::iterator Iter = Sections.find(SecName);
  467. Section<T>* Sec = NULL;
  468. if (Iter != Sections.end()) {
  469. Sec = (*Iter).second;
  470. }
  471. return Sec;
  472. }
  473. void GetSections(std::map< std::basic_string<T>, Section<T> *> &Secs) {
  474. Secs = Sections;
  475. }
  476. void SetDirty() { Dirty = true; }
  477. const HINF GetInfHandle() const { return InfHandle; }
  478. //
  479. // Callback function pointer for
  480. // working on each section
  481. //
  482. typedef void (*ELEMENT_WORKER)(
  483. Section<T> &Section,
  484. void *ContextData
  485. );
  486. void DoForEach(ELEMENT_WORKER Worker, void *ContextData);
  487. //
  488. // Iterator
  489. //
  490. class Iterator{
  491. public:
  492. Iterator(std::map< std::basic_string<T>, Section<T> *> *Collect = NULL) {
  493. Collection = Collect;
  494. if (Collection) {
  495. Iter = (*Collection).begin();
  496. }
  497. }
  498. Iterator& begin() {
  499. if (Collection) {
  500. Iter = Collection->begin();
  501. }
  502. return *this;
  503. }
  504. bool end() {
  505. return Collection? (Iter == Collection->end()) : true;
  506. }
  507. Iterator& operator++(int) {
  508. if (Collection) {
  509. Iter++;
  510. }
  511. return *this;
  512. }
  513. friend Section<T> * operator*(Iterator &lhs) {
  514. return lhs.Collection ? (*(lhs.Iter)).second: NULL;
  515. }
  516. friend Section<T>;
  517. protected:
  518. void Init(std::map< std::basic_string<T>, Section<T> *> *Collect) {
  519. Collection = Collect;
  520. Iter = (*Collection).begin();
  521. }
  522. private:
  523. //
  524. // data members
  525. //
  526. std::map< std::basic_string<T>, Section<T> *>::iterator Iter;
  527. std::map< std::basic_string<T>, Section<T> *> *Collection;
  528. };
  529. Iterator begin(void) {
  530. return Iterator(&(this->Sections));
  531. }
  532. protected:
  533. HINF OpenFile() {
  534. HINF InfHandle = NULL;
  535. UINT ErrorLine = 0;
  536. if (sizeof(T) == sizeof(CHAR)) {
  537. InfHandle = SetupOpenInfFileA((const CHAR*)(GetName().c_str()),
  538. NULL,
  539. INF_STYLE_WIN4,
  540. &ErrorLine);
  541. } else {
  542. InfHandle = SetupOpenInfFileW((const WCHAR*)(GetName().c_str()),
  543. NULL,
  544. INF_STYLE_WIN4,
  545. &ErrorLine);
  546. }
  547. if (InfHandle == INVALID_HANDLE_VALUE) {
  548. DWORD ErrorCode = ::GetLastError();
  549. if (ErrorLine) {
  550. throw new InvalidInfFormat<T>(GetName(), ErrorLine);
  551. } else {
  552. throw new InvalidInfFile<T>(GetName(), ErrorCode);
  553. }
  554. }
  555. return InfHandle;
  556. }
  557. typedef BOOL (* GetInfSectionsRoutine)(HINF, T*, UINT, UINT *);
  558. //
  559. // data members
  560. //
  561. std::basic_string<T> Name;
  562. HINF InfHandle;
  563. bool Dirty;
  564. static GetInfSectionsRoutine GetInfSections;
  565. static HMODULE SetupApiModuleHandle;
  566. static ULONG SetupApiUseCount;
  567. std::map< std::basic_string<T>, Section<T> *> Sections;
  568. };
  569. template <class T>
  570. SectionValues<T>::SectionValues(Section<T> &Sec,
  571. const std::basic_string<T> &Key, ULONG LineIdx, bool New)
  572. : Container(Sec), Name(Key), Index(LineIdx) {
  573. if (!New) {
  574. GetContainer().GetContainer().GetValues(Sec, *this, Values);
  575. }
  576. }
  577. template <class T>
  578. SectionValues<T>::SectionValues(Section<T> &Sec, ULONG LineIdx, bool New)
  579. : Container(Sec), Index(LineIdx) {
  580. BYTE Buffer[64] = {0};
  581. if (sizeof(T) == sizeof(CHAR)) {
  582. Name = std::basic_string<T>((const T*)_ltoa(Index, (char *)Buffer, 10));
  583. } else {
  584. Name = std::basic_string<T>((const T*)_ltow(Index, (wchar_t*)Buffer, 10));
  585. }
  586. if (!New) {
  587. GetContainer().GetContainer().GetValues(Sec, *this, Values);
  588. }
  589. }
  590. template <class T>
  591. std::ostream&
  592. operator<<(std::ostream &os, SectionValues<T> &rhs) {
  593. os << rhs.GetName() << " = ";
  594. std::vector< std::basic_string<T> >::iterator Iter = rhs.Values.begin();
  595. while (Iter != rhs.Values.end()) {
  596. os << *Iter << ", ";
  597. Iter++;
  598. }
  599. os << std::endl;
  600. return os;
  601. }
  602. template <class T>
  603. Section<T>::Section(InfFile<T> &file, const std::basic_string<T> &name)
  604. : Name(name), File(file), Keyless(false) {
  605. INFCONTEXT InfContext;
  606. BOOL Result;
  607. const HINF InfHandle = GetContainer().GetInfHandle();
  608. if (sizeof(T) == sizeof(CHAR)) {
  609. Result = SetupFindFirstLineA((HINF)InfHandle,
  610. (PCSTR)GetName().c_str(),
  611. NULL,
  612. &InfContext);
  613. } else {
  614. Result = SetupFindFirstLineW((HINF)InfHandle,
  615. (PCWSTR)GetName().c_str(),
  616. NULL,
  617. &InfContext);
  618. }
  619. //std::cout << Name << " is " << Keyless << std::endl;
  620. if (Result) {
  621. BYTE Buffer[4096], Buffer1[4096];
  622. bool KeyPresent = false;
  623. //
  624. // NOTE : singular values in section are treated as keys
  625. // by setupapi so take care of such cases correctly
  626. // as keyless entries
  627. //
  628. // ISSUE : because of the way we are trying to determine
  629. // keyless section a sections with first entry a = a will
  630. // be treated as keyless section wrongly.
  631. //
  632. if (sizeof(T) == sizeof(CHAR)) {
  633. *((PSTR)Buffer) = '\0';
  634. *((PSTR)Buffer1) = '\0';
  635. if (SetupGetStringFieldA(&InfContext,
  636. 0,
  637. (PSTR)Buffer,
  638. sizeof(Buffer) / sizeof(T),
  639. NULL) &&
  640. SetupGetStringFieldA(&InfContext,
  641. 1,
  642. (PSTR)Buffer1,
  643. sizeof(Buffer1) / sizeof(T),
  644. NULL)) {
  645. KeyPresent = (_stricmp((PCSTR)Buffer, (PCSTR)Buffer1) != 0);
  646. }
  647. } else {
  648. *((PWSTR)Buffer) = L'\0';
  649. *((PWSTR)Buffer1) = L'\0';
  650. if (SetupGetStringFieldW(&InfContext,
  651. 0,
  652. (PWSTR)Buffer,
  653. sizeof(Buffer) / sizeof(T),
  654. NULL) &&
  655. SetupGetStringFieldW(&InfContext,
  656. 1,
  657. (PWSTR)Buffer1,
  658. sizeof(Buffer1) / sizeof(T),
  659. NULL)) {
  660. KeyPresent = (_wcsicmp((PCWSTR)Buffer, (PCWSTR)Buffer1) != 0);
  661. }
  662. }
  663. // If we cannot read 0th value, then we
  664. // assume that the whole section is
  665. // doesnot have entries with key
  666. //
  667. Keyless = !KeyPresent;
  668. }
  669. GetContainer().GetLines(*this, Lines, KeylessLines);
  670. //std::cout << Name << " is " << Keyless << std::endl;
  671. }
  672. template <class T>
  673. std::ostream&
  674. operator<<(std::ostream &os, Section<T> &rhs){
  675. os << "[" << rhs.GetName() << "]" << std::endl;
  676. Section<T>::Iterator Iter = rhs.begin();
  677. SectionValues<T> *Values;
  678. while (!Iter.end()) {
  679. Values = *Iter;
  680. if (Values) {
  681. os << *Values;
  682. }
  683. Iter++;
  684. }
  685. return os;
  686. }
  687. template<class T>
  688. void
  689. Section<T>::DoForEach(Section<T>::ELEMENT_WORKER Worker,
  690. void *ContextData) {
  691. if (IsKeyless()) {
  692. std::vector< SectionValues<T> * >::iterator Iter = KeylessLines.begin();
  693. SectionValues<T> *Value;
  694. while (Iter != KeylessLines.end()) {
  695. Value = *Iter;
  696. if (Value) {
  697. Worker(*Value, ContextData);
  698. }
  699. Iter++;
  700. }
  701. } else {
  702. std::vector< SectionValues<T> *>::iterator Iter = Lines.begin();
  703. SectionValues<T> *Value;
  704. while (Iter != Lines.end()) {
  705. Value = *Iter;
  706. if (Value) {
  707. Worker(*Value, ContextData);
  708. }
  709. Iter++;
  710. }
  711. }
  712. }
  713. template <class T>
  714. InfFile<T>::InfFile(const std::basic_string<T> &name) : Name(name) {
  715. Dirty = false;
  716. InfHandle = OpenFile();
  717. if (!GetInfSections) {
  718. SetupApiModuleHandle = LoadLibrary(TEXT("setupapi.dll"));
  719. if (SetupApiModuleHandle) {
  720. GetInfSections = (GetInfSectionsRoutine)(GetProcAddress(SetupApiModuleHandle,
  721. "pSetupGetInfSections"));
  722. if (!GetInfSections) {
  723. GetInfSections = (GetInfSectionsRoutine)(GetProcAddress(SetupApiModuleHandle,
  724. "SetupGetInfSections"));
  725. }
  726. }
  727. if (!GetInfSections) {
  728. throw new W32Exception<T>();
  729. }
  730. }
  731. SetupApiUseCount++;
  732. //
  733. // get hold of all the sections
  734. //
  735. UINT CurrSize = 4096;
  736. UINT SizeNeeded = 0;
  737. DWORD LastError = 0;
  738. WCHAR *Buffer = new WCHAR[CurrSize];
  739. memset(Buffer, 0, CurrSize);
  740. BOOL Result = GetInfSections(InfHandle, Buffer, CurrSize, &SizeNeeded);
  741. if (!Result && (SizeNeeded > CurrSize)) {
  742. delete []Buffer;
  743. Buffer = new WCHAR[SizeNeeded];
  744. memset(Buffer, 0, SizeNeeded);
  745. CurrSize = SizeNeeded;
  746. Result = GetInfSections(InfHandle, Buffer, CurrSize, &SizeNeeded);
  747. }
  748. std::vector<std::basic_string<T> > SectionNames;
  749. if (Result) {
  750. while (Buffer && *Buffer) {
  751. std::basic_string<WCHAR> WNextSection((const WCHAR*)Buffer);
  752. if (sizeof(T) == sizeof(CHAR)) {
  753. std::basic_string<T> NextSection;
  754. ToAnsiString((std::basic_string<char> &)NextSection, WNextSection);
  755. SectionNames.push_back(NextSection);
  756. } else {
  757. std::basic_string<T> NextSection((const T *)WNextSection.c_str());
  758. SectionNames.push_back(NextSection);
  759. }
  760. Buffer += (WNextSection.length() + 1);
  761. }
  762. } else {
  763. LastError = ::GetLastError();
  764. }
  765. if (Result && SectionNames.size()) {
  766. std::vector<std::basic_string<T> >::iterator NameIter = SectionNames.begin();
  767. while (NameIter != SectionNames.end()) {
  768. // std::cout << *NameIter << std::endl;
  769. Sections[*NameIter] = new Section<T>(*this, *NameIter);
  770. NameIter++;
  771. }
  772. }
  773. if (!Result) {
  774. throw new InvalidInfFile<T>(GetName(), LastError);
  775. }
  776. }
  777. template<class T>
  778. void
  779. InfFile<T>::DoForEach(
  780. InfFile<T>::ELEMENT_WORKER Worker,
  781. void *ContextData
  782. )
  783. {
  784. std::map< std::basic_string<T>, Section<T> *>::iterator
  785. Iter = Sections.begin();
  786. while (Iter != Sections.end()) {
  787. Worker(*(*Iter).second, ContextData);
  788. Iter++;
  789. }
  790. }
  791. template <class T>
  792. void
  793. InfFile<T>::GetLines(
  794. Section<T> &Sec,
  795. std::vector< SectionValues<T> *> &Values,
  796. std::vector< SectionValues<T> *> &KeylessValues
  797. )
  798. {
  799. std::vector< SectionValues<T>* >::iterator MapIter = Values.begin();
  800. //
  801. // delete the old values (if any)
  802. //
  803. while (MapIter != Values.end()) {
  804. if (*MapIter) {
  805. delete (*MapIter);
  806. }
  807. MapIter++;
  808. }
  809. Values.clear();
  810. std::vector< SectionValues<T>* >::iterator KeylessIter = KeylessValues.begin();
  811. //
  812. // delete the old values (if any)
  813. //
  814. while (KeylessIter != KeylessValues.end()) {
  815. if (*KeylessIter) {
  816. delete (*KeylessIter);
  817. }
  818. KeylessIter++;
  819. }
  820. KeylessValues.clear();
  821. //
  822. // locate the first line
  823. //
  824. INFCONTEXT InfContext;
  825. BOOL Result;
  826. DWORD LineCount;
  827. if (sizeof(T) == sizeof(CHAR)) {
  828. LineCount = SetupGetLineCountA(InfHandle,
  829. (PCSTR)Sec.GetName().c_str());
  830. } else {
  831. LineCount = SetupGetLineCountW(InfHandle,
  832. (PCWSTR)Sec.GetName().c_str());
  833. }
  834. if (LineCount) {
  835. if (sizeof(T) == sizeof(CHAR)) {
  836. Result = SetupFindFirstLineA(InfHandle,
  837. (PCSTR)Sec.GetName().c_str(),
  838. NULL,
  839. &InfContext);
  840. } else {
  841. Result = SetupFindFirstLineW(InfHandle,
  842. (PCWSTR)Sec.GetName().c_str(),
  843. NULL,
  844. &InfContext);
  845. }
  846. if (Result) {
  847. BYTE Buffer[4096];
  848. bool Read = false;
  849. BOOL NextLine = TRUE;
  850. DWORD Index = 0;
  851. bool Keyless = Sec.IsKeyless();
  852. for (Index=0; (NextLine && (Index < LineCount)); Index++) {
  853. Buffer[0] = Buffer[1] = 0;
  854. Read = false;
  855. if (!Keyless) {
  856. if (sizeof(T) == sizeof(CHAR)) {
  857. if (SetupGetStringFieldA(&InfContext,
  858. 0,
  859. (PSTR)Buffer,
  860. sizeof(Buffer) / sizeof(T),
  861. NULL)) {
  862. Read = true;
  863. }
  864. } else {
  865. if (SetupGetStringFieldW(&InfContext,
  866. 0,
  867. (PWSTR)Buffer,
  868. sizeof(Buffer) / sizeof(T),
  869. NULL)) {
  870. Read = true;
  871. }
  872. }
  873. }
  874. if (Read) {
  875. std::basic_string<T> Key((const T *)Buffer);
  876. //std::cout << Key << std::endl;
  877. Values.push_back(new SectionValues<T>(Sec, Key, Index));
  878. } else {
  879. KeylessValues.push_back(new SectionValues<T>(Sec, Index));
  880. }
  881. NextLine = SetupFindNextLine(&InfContext, &InfContext);
  882. }
  883. if (!NextLine && (Index < LineCount)) {
  884. throw new InvalidInfSection<T>(Sec.GetName(), GetName());
  885. }
  886. } else {
  887. throw new InvalidInfSection<T>(Sec.GetName(), GetName());
  888. }
  889. }
  890. }
  891. template <class T>
  892. void
  893. InfFile<T>::GetValues(
  894. Section<T> &Sec,
  895. SectionValues<T> &SecValues,
  896. std::vector<std::basic_string<T> > &Values
  897. )
  898. {
  899. const std::basic_string<T> &SecName = Sec.GetName();
  900. const std::basic_string<T> &Key = SecValues.GetName();
  901. INFCONTEXT InfContext;
  902. BOOL Result = TRUE;
  903. ULONG Lines = 0;
  904. Values.clear();
  905. if (sizeof(T) == sizeof(CHAR)) {
  906. Lines = SetupGetLineCountA(InfHandle,
  907. (PCSTR)SecName.c_str());
  908. } else {
  909. Lines = SetupGetLineCountW(InfHandle,
  910. (PCWSTR)SecName.c_str());
  911. }
  912. if (Lines) {
  913. if (sizeof(T) == sizeof(CHAR)) {
  914. Result = SetupGetLineByIndexA(InfHandle,
  915. (PCSTR)SecName.c_str(),
  916. SecValues.GetIndex(),
  917. &InfContext);
  918. } else {
  919. Result = SetupGetLineByIndexW(InfHandle,
  920. (PCWSTR)SecName.c_str(),
  921. SecValues.GetIndex(),
  922. &InfContext);
  923. }
  924. if (Result) {
  925. DWORD FieldCount = SetupGetFieldCount(&InfContext);
  926. BYTE Buffer[2048];
  927. for (DWORD Index=0; Index < FieldCount; Index++) {
  928. Buffer[0] = Buffer[1] = 0;
  929. if (sizeof(T) == sizeof(CHAR)) {
  930. if (SetupGetStringFieldA(&InfContext,
  931. Index + 1,
  932. (PSTR)Buffer,
  933. sizeof(Buffer) / sizeof(T),
  934. NULL)) {
  935. Values.push_back((const T *)Buffer);
  936. }
  937. } else {
  938. if (SetupGetStringFieldW(&InfContext,
  939. Index + 1,
  940. (PWSTR)Buffer,
  941. sizeof(Buffer) / sizeof(T),
  942. NULL)) {
  943. Values.push_back((const T *)Buffer);
  944. }
  945. }
  946. }
  947. } else {
  948. throw new InvalidInfSection<T>(SecName, GetName());
  949. }
  950. }
  951. }
  952. typedef InfFile<CHAR> InfFileA;
  953. typedef InfFile<WCHAR> InfFileW;