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.

1574 lines
41 KiB

  1. //
  2. // rdpfstore.cpp
  3. //
  4. // Implementation of CRdpFileStore, implements ISettingsStore
  5. //
  6. // CRdpFileStore implements a persistent settings store for
  7. // ts client settings.
  8. //
  9. //
  10. // Copyright(C) Microsoft Corporation 2000
  11. // Author: Nadim Abdo (nadima)
  12. //
  13. //
  14. // Notes for improvement:
  15. // Can add a hash lookup table to speedup FindRecord.
  16. // (FindRecord is called at least once for each property that
  17. // is read/written during OpenStore/SaveStore operations)
  18. // Most files contain maybe 5-10 records so speeding up
  19. // the find is probably not that important.
  20. //
  21. // Copyright(C) Microsoft Corporation 2000
  22. // Author: Nadim Abdo (nadima)
  23. //
  24. #include "stdafx.h"
  25. #define TRC_GROUP TRC_GROUP_UI
  26. #define TRC_FILE "rdpfstore.cpp"
  27. #include <atrcapi.h>
  28. #include "rdpfstore.h"
  29. #include "autil.h" //for StringToBinary/BinaryToString
  30. //
  31. // Index values must match RDPF_RECTYPE_*
  32. //
  33. LPCTSTR g_szTypeCodeMap[] =
  34. {
  35. TEXT(":i:"), //RDPF_RECTYPE_UINT
  36. TEXT(":s:"), //RDPF_RECTYPE_SZ
  37. TEXT(":b:") //RDPF_RECTYPE_BINARY
  38. };
  39. CRdpFileStore::CRdpFileStore()
  40. {
  41. _cRef = 1;
  42. _fReadOnly = FALSE;
  43. _fOpenForRead = FALSE;
  44. _fOpenForWrite = FALSE;
  45. _fIsDirty = FALSE;
  46. _pRecordListHead= NULL;
  47. _pRecordListTail= NULL;
  48. _szFileName[0] = 0;
  49. }
  50. CRdpFileStore::~CRdpFileStore()
  51. {
  52. DeleteRecords();
  53. }
  54. ULONG __stdcall CRdpFileStore::AddRef()
  55. {
  56. DC_BEGIN_FN("AddRef");
  57. ULONG cref = InterlockedIncrement(&_cRef);
  58. TRC_ASSERT(cref > 0, (TB,_T("AddRef: cref is not > 0!")));
  59. DC_END_FN();
  60. return cref;
  61. }
  62. ULONG __stdcall CRdpFileStore::Release()
  63. {
  64. DC_BEGIN_FN("Release");
  65. TRC_ASSERT(_cRef > 0, (TB,_T("AddRef: cref is not > 0!")));
  66. ULONG cref = InterlockedDecrement(&_cRef);
  67. if(0 == cref)
  68. {
  69. TRC_DBG((TB,_T("CRdpFileStore::Release deleting object")));
  70. delete this;
  71. }
  72. DC_END_FN();
  73. return cref;
  74. }
  75. STDMETHODIMP CRdpFileStore::QueryInterface(REFIID iid, void** p)
  76. {
  77. UNREFERENCED_PARAMETER(iid);
  78. UNREFERENCED_PARAMETER(p);
  79. return E_NOTIMPL;
  80. }
  81. //
  82. // OpenStore
  83. // opens the RDP file, creating one if one doesn't exist
  84. // The file existed it is parsed and readied for fast queries
  85. //
  86. // parameters:
  87. // szStoreMoniker - path to file
  88. // bReadyOnly - specifies if file is to be opened readonly
  89. //
  90. BOOL CRdpFileStore::OpenStore(LPCTSTR szStoreMoniker, BOOL bReadOnly)
  91. {
  92. DC_BEGIN_FN("OpenStore");
  93. TRC_ASSERT(szStoreMoniker, (TB, _T("szStoreMoniker parameter is NULL")));
  94. if(szStoreMoniker)
  95. {
  96. _fReadOnly = bReadOnly;
  97. HRESULT hr = StringCchCopy(_szFileName, SIZECHAR(_szFileName), szStoreMoniker);
  98. if (FAILED(hr)) {
  99. TRC_ERR((TB, _T("String copy failed: hr = 0x%x"), hr));
  100. memset(_szFileName, 0, sizeof(_szFileName));
  101. return FALSE;
  102. }
  103. //
  104. // Open the file, creating it if it doesn't exist
  105. //
  106. //
  107. // First try to open existing for rw
  108. //
  109. if (ERR_SUCCESS == _fs.OpenForRead( (LPTSTR)szStoreMoniker))
  110. {
  111. _fOpenForRead = _fs.IsOpenForRead();
  112. _fOpenForWrite = !bReadOnly;
  113. }
  114. else
  115. {
  116. TRC_DBG((TB, _T("OpenStore could not _tfopen: %s."),
  117. szStoreMoniker));
  118. return FALSE;
  119. }
  120. ParseFile();
  121. }
  122. else
  123. {
  124. return FALSE;
  125. }
  126. DC_END_FN();
  127. return TRUE;
  128. }
  129. //
  130. // CommitStore
  131. // commits the in memory representation of the file to the store
  132. // this overwrites any existing contents in the file.
  133. //
  134. // File MUST have been opened with OpenStore
  135. //
  136. BOOL CRdpFileStore::CommitStore()
  137. {
  138. DC_BEGIN_FN("CommitStore");
  139. PRDPF_RECORD node = NULL;
  140. TCHAR szBuf[LINEBUF_SIZE];
  141. int ret;
  142. if(_fOpenForWrite)
  143. {
  144. if(_fs.IsOpenForRead() || _fs.IsOpenForWrite())
  145. {
  146. _fs.Close();
  147. }
  148. //Reopen for write, nuking previous contents
  149. //Open as binary to allow UNICODE output
  150. if(ERR_SUCCESS == _fs.OpenForWrite(_szFileName, TRUE))
  151. {
  152. node = _pRecordListHead;
  153. while(node)
  154. {
  155. if(RecordToString(node, szBuf, LINEBUF_SIZE))
  156. {
  157. ret = _fs.Write(szBuf);
  158. if(ERR_SUCCESS != ret)
  159. {
  160. TRC_ABORT((TB,_T("Error writing to _fs: %d"),ret));
  161. return FALSE;
  162. }
  163. }
  164. else
  165. {
  166. return FALSE;
  167. }
  168. node = node->pNext;
  169. }
  170. return TRUE;
  171. }
  172. else
  173. {
  174. TRC_ERR((TB,_T("OpenForWrite failed on file:%s"),_szFileName));
  175. return FALSE;
  176. }
  177. }
  178. else
  179. {
  180. TRC_ERR((TB,_T("Files was not opened for write:%s"),_szFileName));
  181. return FALSE;
  182. }
  183. DC_END_FN();
  184. }
  185. //
  186. // CloseStore
  187. // Closes the file, does NOT do a commit.
  188. //
  189. BOOL CRdpFileStore::CloseStore()
  190. {
  191. DC_BEGIN_FN("CloseStore");
  192. if(_fs.IsOpenForRead() || _fs.IsOpenForWrite())
  193. {
  194. if(ERR_SUCCESS == _fs.Close())
  195. {
  196. _fReadOnly = FALSE;
  197. _fOpenForRead = FALSE;
  198. _fOpenForWrite = FALSE;
  199. return TRUE;
  200. }
  201. else
  202. {
  203. return FALSE;
  204. }
  205. }
  206. else
  207. {
  208. return FALSE;
  209. }
  210. DC_END_FN();
  211. }
  212. BOOL CRdpFileStore::IsOpenForRead()
  213. {
  214. return _fOpenForRead;
  215. }
  216. BOOL CRdpFileStore::IsOpenForWrite()
  217. {
  218. return _fOpenForWrite;
  219. }
  220. BOOL CRdpFileStore::IsDirty()
  221. {
  222. return _fIsDirty;
  223. }
  224. BOOL CRdpFileStore::SetDirtyFlag(BOOL bIsDirty)
  225. {
  226. _fIsDirty = bIsDirty;
  227. return _fIsDirty;
  228. }
  229. //
  230. // Typed read/write functions
  231. //
  232. BOOL CRdpFileStore::ReadString(LPCTSTR szName, LPTSTR szDefault,
  233. LPTSTR szOutBuf, UINT strLen)
  234. {
  235. PRDPF_RECORD node = NULL;
  236. HRESULT hr;
  237. DC_BEGIN_FN("ReadString");
  238. TRC_ASSERT(szName && szDefault && szOutBuf && strLen,
  239. (TB,_T("Invalid params to ReadString")));
  240. if(szName && szDefault && szOutBuf && strLen)
  241. {
  242. node = FindRecord(szName);
  243. if(node && node->recType == RDPF_RECTYPE_SZ)
  244. {
  245. hr = StringCchCopy(szOutBuf, strLen, node->u.szVal);
  246. if (SUCCEEDED(hr)) {
  247. return TRUE;
  248. } else {
  249. TRC_ERR((TB, _T("String copy failed: hr = 0x%x"), hr));
  250. return FALSE;
  251. }
  252. }
  253. else
  254. {
  255. //Fill with default
  256. hr = StringCchCopy(szOutBuf, strLen, szDefault);
  257. if (SUCCEEDED(hr)) {
  258. return TRUE;
  259. } else {
  260. TRC_ERR((TB, _T("String copy failed: hr = 0x%x"), hr));
  261. return FALSE;
  262. }
  263. }
  264. }
  265. else
  266. {
  267. return FALSE;
  268. }
  269. DC_END_FN();
  270. }
  271. //
  272. // Writes a string to the store
  273. // params
  274. // szName - key name
  275. // szDefault - default value (if writing default settings gets deleted)
  276. // szValue - value to write out
  277. // fIgnoreDefault - if set then always write ignoring szDefault
  278. //
  279. BOOL CRdpFileStore::WriteString(LPCTSTR szName, LPTSTR szDefault, LPTSTR szValue,
  280. BOOL fIgnoreDefault)
  281. {
  282. DC_BEGIN_FN("WriteString");
  283. TRC_ASSERT(szName && szValue,
  284. (TB,_T("Invalid params to WriteString")));
  285. if(szName && szValue)
  286. {
  287. if(szDefault && !fIgnoreDefault && !_tcscmp(szDefault,szValue))
  288. {
  289. //
  290. // Don't write out defaults
  291. //
  292. PRDPF_RECORD node = FindRecord(szName);
  293. if(node)
  294. {
  295. return DeleteRecord(node);
  296. }
  297. return TRUE;
  298. }
  299. else
  300. {
  301. BOOL bRet =
  302. InsertRecord(szName, RDPF_RECTYPE_SZ, szValue);
  303. return bRet;
  304. }
  305. }
  306. else
  307. {
  308. return FALSE;
  309. }
  310. DC_END_FN();
  311. }
  312. BOOL CRdpFileStore::ReadBinary(LPCTSTR szName, PBYTE pOutBuf, UINT cbBufLen)
  313. {
  314. PRDPF_RECORD node = NULL;
  315. DC_BEGIN_FN("ReadBinary");
  316. TRC_ASSERT(szName && pOutBuf && cbBufLen,
  317. (TB,_T("Invalid params to ReadBinary")));
  318. if(szName && pOutBuf && cbBufLen)
  319. {
  320. node = FindRecord(szName);
  321. if(node && node->recType == RDPF_RECTYPE_BINARY)
  322. {
  323. if(node->dwBinValLen <= cbBufLen)
  324. {
  325. memcpy(pOutBuf, node->u.pBinVal, node->dwBinValLen);
  326. return TRUE;
  327. }
  328. else
  329. {
  330. TRC_ERR((TB,_T("Insufficient space in outbuf buf")));
  331. return FALSE;
  332. }
  333. }
  334. else
  335. {
  336. return FALSE;
  337. }
  338. }
  339. else
  340. {
  341. return FALSE;
  342. }
  343. DC_END_FN();
  344. }
  345. BOOL CRdpFileStore::WriteBinary(LPCTSTR szName,PBYTE pBuf, UINT cbBufLen)
  346. {
  347. DC_BEGIN_FN("WriteInt");
  348. TRC_ASSERT(szName && pBuf,
  349. (TB,_T("Invalid params to WriteBinary")));
  350. if(!cbBufLen)
  351. {
  352. return TRUE;
  353. }
  354. if(szName && pBuf)
  355. {
  356. BOOL bRet =
  357. InsertBinaryRecord(szName, pBuf, (DWORD)cbBufLen);
  358. return bRet;
  359. }
  360. else
  361. {
  362. return FALSE;
  363. }
  364. DC_END_FN();
  365. }
  366. BOOL CRdpFileStore::ReadInt(LPCTSTR szName, UINT defaultVal, PUINT pval)
  367. {
  368. PRDPF_RECORD node = NULL;
  369. DC_BEGIN_FN("ReadInt");
  370. TRC_ASSERT(szName && pval,
  371. (TB,_T("Invalid params to ReadInt")));
  372. if(szName && pval)
  373. {
  374. node = FindRecord(szName);
  375. if(node && node->recType == RDPF_RECTYPE_UINT)
  376. {
  377. *pval = node->u.iVal;
  378. return TRUE;
  379. }
  380. else
  381. {
  382. *pval = defaultVal;
  383. return TRUE;
  384. }
  385. }
  386. else
  387. {
  388. return FALSE;
  389. }
  390. DC_END_FN();
  391. }
  392. //
  393. // Writes an int to the store
  394. // params
  395. // szName - key name
  396. // defaultVal - default value (if writing default settings gets deleted)
  397. // val - value to write out
  398. // fIgnoreDefault - if set then always write ignoring szDefault
  399. //
  400. BOOL CRdpFileStore::WriteInt(LPCTSTR szName, UINT defaultVal, UINT val,
  401. BOOL fIgnoreDefault)
  402. {
  403. DC_BEGIN_FN("WriteInt");
  404. TRC_ASSERT(szName,
  405. (TB,_T("Invalid params to WriteInt")));
  406. if(szName)
  407. {
  408. if(!fIgnoreDefault && defaultVal == val)
  409. {
  410. //
  411. // Don't write out default
  412. //
  413. PRDPF_RECORD node = FindRecord(szName);
  414. if(node)
  415. {
  416. return DeleteRecord(node);
  417. }
  418. return TRUE;
  419. }
  420. else
  421. {
  422. BOOL bRet =
  423. InsertIntRecord(szName, val);
  424. return bRet;
  425. }
  426. }
  427. else
  428. {
  429. return FALSE;
  430. }
  431. DC_END_FN();
  432. }
  433. BOOL CRdpFileStore::ReadBool(LPCTSTR szName, UINT defaultVal, PBOOL pbVal)
  434. {
  435. DC_BEGIN_FN("ReadBool");
  436. UINT val;
  437. TRC_ASSERT(szName && pbVal,
  438. (TB,_T("Invalid params to ReadBool")));
  439. if(szName && pbVal)
  440. {
  441. if(ReadInt(szName, defaultVal, &val))
  442. {
  443. *pbVal = (BOOL)val;
  444. return TRUE;
  445. }
  446. }
  447. else
  448. {
  449. return FALSE;
  450. }
  451. DC_END_FN();
  452. return TRUE;
  453. }
  454. //
  455. // Writes a bool to the store
  456. // params
  457. // szName - key name
  458. // defaultVal - default value (if writing default settings gets deleted)
  459. // bVal - value to write out
  460. // fIgnoreDefault - if set then always write ignoring szDefault
  461. //
  462. BOOL CRdpFileStore::WriteBool(LPCTSTR szName, UINT defaultVal,BOOL bVal,
  463. BOOL fIgnoreDefault)
  464. {
  465. DC_BEGIN_FN("WriteBool");
  466. UINT iVal = bVal;
  467. BOOL bRet =
  468. WriteInt( szName, defaultVal, iVal, fIgnoreDefault);
  469. return bRet;
  470. DC_END_FN();
  471. }
  472. //
  473. // ParseFile
  474. // parses the _hFile into a reclist and associated namemap hash
  475. //
  476. BOOL CRdpFileStore::ParseFile()
  477. {
  478. DC_BEGIN_FN("ParseFile");
  479. TRC_ASSERT(_fs.IsOpenForRead(), (TB,_T("Can't ParseFile on a closed FS")));
  480. if(!_fs.IsOpenForRead())
  481. {
  482. return FALSE;
  483. }
  484. //
  485. // Nuke any current in-memory state
  486. //
  487. DeleteRecords();
  488. //
  489. // Parse the file line by line into a RDPF_RECORD list
  490. //
  491. TCHAR szBuf[LINEBUF_SIZE];
  492. while(ERR_SUCCESS == _fs.ReadNextLine(szBuf, sizeof(szBuf)))
  493. {
  494. if(!InsertRecordFromLine(szBuf))
  495. {
  496. TRC_DBG((TB,_T("Parse error, aborting file parse")));
  497. return FALSE;
  498. }
  499. }
  500. _fs.Close();
  501. DC_END_FN();
  502. return TRUE;
  503. }
  504. //
  505. // InsertRecordFromLine
  506. // parses szLine into a record and adds to the record list
  507. //
  508. BOOL CRdpFileStore::InsertRecordFromLine(LPTSTR szLine)
  509. {
  510. DC_BEGIN_FN("InsertRecordFromLine");
  511. TCHAR szNameField[LINEBUF_SIZE];
  512. UINT typeCode;
  513. TCHAR szValueField[LINEBUF_SIZE];
  514. BOOL fParseOk = FALSE;
  515. memset(szNameField,0,sizeof(szNameField));
  516. memset(szValueField,0,sizeof(szValueField));
  517. fParseOk = ParseLine(szLine, &typeCode, szNameField, szValueField);
  518. TRC_DBG((TB,_T("Parsed line into fields- name:'%s', value:'%s', typecode:'%d'"),
  519. szNameField,
  520. szValueField,
  521. typeCode));
  522. TRC_ASSERT(IS_VALID_RDPF_TYPECODE(typeCode),
  523. (TB,_T("typeCode %d is invalid"), typeCode));
  524. if(IS_VALID_RDPF_TYPECODE(typeCode))
  525. {
  526. //Create a new record for this line
  527. //and insert it into the reclist
  528. if(typeCode == RDPF_RECTYPE_UNPARSED)
  529. {
  530. //Unparsed line: Value is the whole line. Name ignored
  531. HRESULT hr = StringCchCopy(szValueField, SIZECHAR(szValueField), szLine);
  532. if (FAILED(hr)) {
  533. TRC_ERR((TB, _T("String copy failed: hr = 0x%x"), hr));
  534. return FALSE;
  535. }
  536. }
  537. //names are always lower case
  538. if(InsertRecord(_tcslwr(szNameField), typeCode, szValueField))
  539. {
  540. return TRUE;
  541. }
  542. else
  543. {
  544. return FALSE;
  545. }
  546. }
  547. else
  548. {
  549. //
  550. // Invalid typecode
  551. //
  552. return FALSE;
  553. }
  554. DC_END_FN();
  555. return TRUE;
  556. }
  557. //
  558. // ParseLine
  559. // parses the lines into tokens, returns false
  560. // if the line does not match the expected format
  561. //
  562. // params
  563. // szLine - line to parse
  564. // pTypeCode - [OUT] typecode
  565. // szNameField - [OUT] name field. (must be at least LINEBUF_SIZE)
  566. // szValueField - [OUT] value field. (must be at least LINEBUF_SIZE)
  567. //
  568. //
  569. BOOL CRdpFileStore::ParseLine(LPTSTR szLine,
  570. PUINT pTypeCode,
  571. LPTSTR szNameField,
  572. LPTSTR szValueField)
  573. {
  574. PTCHAR szWrite = NULL;
  575. TCHAR szTypeCode;
  576. INT writeCount = 0;
  577. DC_BEGIN_FN("ParseLine");
  578. //
  579. // Try to parse the line, if unable to parse it return
  580. // false.
  581. //
  582. // Format is "fieldname:szTypeCode:value"
  583. // e.g "server:s:localhost"
  584. //
  585. // szTypeCodes are:
  586. // s - string
  587. // i - UINT
  588. // b - binary blob (encoded)
  589. //
  590. TRC_ASSERT(szLine, (TB,_T("szLine is null")));
  591. TRC_ASSERT(pTypeCode, (TB,_T("pTypeCode is null")));
  592. TRC_ASSERT(szNameField, (TB,_T("szNameField is null")));
  593. TRC_ASSERT(szValueField, (TB,_T("szValueField is null")));
  594. if(szLine && pTypeCode && szNameField && szValueField)
  595. {
  596. //
  597. // parse the whole line in one pass
  598. // goto used on error case to avoid horrible nesting
  599. //
  600. PTCHAR sz = szLine;
  601. while(*sz && *sz == TCHAR(' '))
  602. sz++; //eat leading whitespace
  603. if(!*sz)
  604. {
  605. goto parse_error;
  606. }
  607. //Copy field 1
  608. PTCHAR szWrite = szNameField;
  609. writeCount = 0;
  610. while(*sz && *sz != TCHAR(':'))
  611. {
  612. *szWrite++ = *sz++;
  613. if(++writeCount > LINEBUF_SIZE)
  614. {
  615. TRC_ERR((TB,_T("Field1 exceeds max size. size: %d"),
  616. writeCount));
  617. goto parse_error;
  618. }
  619. }
  620. *szWrite = NULL;
  621. if(*sz != TCHAR(':'))
  622. {
  623. goto parse_error;
  624. sz++;
  625. }
  626. sz++; //eat ':'
  627. while(*sz && *sz == TCHAR(' '))
  628. sz++; //eat whitespace
  629. if( *sz )
  630. {
  631. szTypeCode = isupper(*sz) ?
  632. #ifndef OS_WINCE
  633. _tolower(*sz++)
  634. #else
  635. towlower(*sz++)
  636. #endif
  637. : *sz++;
  638. switch(szTypeCode)
  639. {
  640. case TCHAR('s'):
  641. *pTypeCode = RDPF_RECTYPE_SZ;
  642. break;
  643. case TCHAR('i'):
  644. *pTypeCode = RDPF_RECTYPE_UINT;
  645. break;
  646. case TCHAR('b'):
  647. *pTypeCode = RDPF_RECTYPE_BINARY;
  648. break;
  649. default:
  650. TRC_ERR((TB,_T("Invalid szTypeCode in szLine '%s'"), szLine));
  651. *pTypeCode = RDPF_RECTYPE_UNPARSED;
  652. goto parse_error;
  653. break;
  654. }
  655. }
  656. else
  657. {
  658. TRC_ERR((TB,_T("Invalid szTypeCode in szLine '%s'"), szLine));
  659. goto parse_error;
  660. }
  661. while(*sz && *sz == TCHAR(' '))
  662. sz++; //eat whitespace
  663. if(*sz != TCHAR(':'))
  664. {
  665. goto parse_error;
  666. }
  667. sz++; //eat ':'
  668. while(*sz && *sz == TCHAR(' '))
  669. sz++; //eat leading whitespace
  670. //rest of line is field3
  671. szWrite = szValueField;
  672. writeCount = 0;
  673. while(*sz && *sz != TCHAR('\n'))
  674. {
  675. *szWrite++ = *sz++;
  676. if(++writeCount > LINEBUF_SIZE)
  677. {
  678. TRC_ERR((TB,_T("Field1 exceeds max size. size: %d"),
  679. writeCount));
  680. goto parse_error;
  681. }
  682. }
  683. *szWrite = NULL;
  684. return TRUE;
  685. }
  686. parse_error:
  687. TRC_ERR((TB,_T("Parse error in line")));
  688. //Add an unknown record..it will be persisted back out to
  689. //the file (it could be from a newer file version)
  690. *pTypeCode = RDPF_RECTYPE_UNPARSED;
  691. DC_END_FN();
  692. return FALSE;
  693. }
  694. //
  695. // InsertRecord
  696. // inserts new record, modifies existing record
  697. // if one exists with the same name field
  698. //
  699. BOOL CRdpFileStore::InsertRecord(LPCTSTR szName, UINT TypeCode, LPCTSTR szValue)
  700. {
  701. DC_BEGIN_FN("InsertRecord");
  702. TRC_ASSERT(IS_VALID_RDPF_TYPECODE(TypeCode),
  703. (TB,_T("typeCode %d is invalid"), TypeCode));
  704. TRC_ASSERT(szName && szValue,
  705. (TB,_T("Invalid szName or szValue")));
  706. if(szName && szValue)
  707. {
  708. PRDPF_RECORD node;
  709. node = FindRecord(szName);
  710. if(node)
  711. {
  712. if(node->recType == TypeCode)
  713. {
  714. //
  715. // Existing record found, modify it's contents
  716. // first free any allocated memory in the current
  717. // node.
  718. //
  719. switch(TypeCode)
  720. {
  721. case RDPF_RECTYPE_SZ:
  722. {
  723. if(node->u.szVal)
  724. {
  725. LocalFree(node->u.szVal);
  726. }
  727. }
  728. break;
  729. case RDPF_RECTYPE_BINARY:
  730. {
  731. if(node->u.pBinVal)
  732. {
  733. LocalFree(node->u.pBinVal);
  734. }
  735. }
  736. break;
  737. case RDPF_RECTYPE_UNPARSED:
  738. {
  739. if(node->u.szUnparsed)
  740. {
  741. LocalFree(node->u.szUnparsed);
  742. }
  743. }
  744. break;
  745. default:
  746. {
  747. return FALSE;
  748. }
  749. break;
  750. }
  751. //
  752. // Set the node value from the typecode
  753. //
  754. if(SetNodeValue(node, TypeCode, szValue))
  755. {
  756. return TRUE;
  757. }
  758. }
  759. else
  760. {
  761. //
  762. // dup record of differing type
  763. //
  764. TRC_ASSERT(FALSE,(TB,_T("found duplicate record of differing type")));
  765. return FALSE;
  766. }
  767. }
  768. else
  769. {
  770. PRDPF_RECORD node = NewRecord(szName, TypeCode);
  771. if(node)
  772. {
  773. if(SetNodeValue(node, TypeCode, szValue))
  774. {
  775. //Append the node to the end of the reclist
  776. if(AppendRecord(node))
  777. {
  778. return TRUE;
  779. }
  780. }
  781. }
  782. return FALSE;
  783. }
  784. }
  785. DC_END_FN();
  786. return FALSE;
  787. }
  788. //
  789. // Sets node value based on a typecode
  790. // this coaxes the value from the string form
  791. //
  792. // This function is the generic version that accepts the value as a string
  793. // parameter. Automatic conversion are done to the appropriate type.
  794. //
  795. inline BOOL CRdpFileStore::SetNodeValue(PRDPF_RECORD pNode,
  796. RDPF_RECTYPE TypeCode,
  797. LPCTSTR szValue)
  798. {
  799. DC_BEGIN_FN("SetNodeValue");
  800. TRC_ASSERT(pNode && szValue && IS_VALID_RDPF_TYPECODE(TypeCode),
  801. (TB,_T("Invalid SetNodeValue params")));
  802. if(pNode && szValue)
  803. {
  804. switch(TypeCode)
  805. {
  806. case RDPF_RECTYPE_UINT:
  807. {
  808. pNode->u.iVal = _ttol(szValue);
  809. return TRUE;
  810. }
  811. break;
  812. case RDPF_RECTYPE_SZ:
  813. {
  814. pNode->u.szVal = (LPTSTR)LocalAlloc(LPTR,
  815. sizeof(TCHAR)*(_tcslen(szValue)+1));
  816. if(pNode->u.szVal)
  817. {
  818. _tcscpy(pNode->u.szVal,szValue);
  819. return TRUE;
  820. }
  821. else
  822. {
  823. return FALSE;
  824. }
  825. }
  826. break;
  827. case RDPF_RECTYPE_BINARY:
  828. {
  829. //Convert from string form to actual binary bits
  830. UINT strLen = _tcslen(szValue);
  831. DWORD dwLen = 0;
  832. //
  833. // First get the buffer length
  834. // (binaryToString returns the wrong length when the
  835. // null parameter is passed in).
  836. dwLen = (strLen >> 1) + 2;
  837. pNode->u.pBinVal = (PBYTE) LocalAlloc(LPTR, dwLen);
  838. if(!pNode->u.pBinVal)
  839. {
  840. TRC_ERR((TB,_T("Failed to alloc %d bytes"), dwLen));
  841. return FALSE;
  842. }
  843. memset(pNode->u.pBinVal,0,dwLen);
  844. //
  845. // Do the conversion
  846. //
  847. if(!CUT::BinarytoString( strLen, (LPTSTR)szValue,
  848. (PBYTE)pNode->u.pBinVal, &dwLen))
  849. {
  850. TRC_ERR((TB,_T("BinaryToString conversion failed")));
  851. return FALSE;
  852. }
  853. pNode->dwBinValLen = dwLen;
  854. }
  855. break;
  856. case RDPF_RECTYPE_UNPARSED:
  857. {
  858. pNode->u.szUnparsed = (LPTSTR)LocalAlloc(LPTR,
  859. sizeof(TCHAR)*(_tcslen(szValue)+1));
  860. if(pNode->u.szUnparsed)
  861. {
  862. _tcscpy(pNode->u.szUnparsed,szValue);
  863. return TRUE;
  864. }
  865. else
  866. {
  867. return FALSE;
  868. }
  869. }
  870. break;
  871. default:
  872. {
  873. return FALSE;
  874. }
  875. break;
  876. }
  877. }
  878. else
  879. {
  880. return FALSE;
  881. }
  882. DC_END_FN();
  883. return TRUE;
  884. }
  885. //
  886. // Inserts an int record (RDPF_RECTYPE_UINT)
  887. // modifies existing record if one is found
  888. //
  889. BOOL CRdpFileStore::InsertIntRecord(LPCTSTR szName, UINT value)
  890. {
  891. DC_BEGIN_FN("InsertIntRecord");
  892. TRC_ASSERT(szName,
  893. (TB,_T("Invalid szName")));
  894. if(szName)
  895. {
  896. PRDPF_RECORD node;
  897. node = FindRecord(szName);
  898. if(node)
  899. {
  900. if(node->recType == RDPF_RECTYPE_UINT)
  901. {
  902. //
  903. // Existing record found, modify it's contents
  904. //
  905. node->u.iVal = value;
  906. return TRUE;
  907. }
  908. else
  909. {
  910. //
  911. // dup record of differing type
  912. //
  913. TRC_ASSERT(FALSE,(TB,_T("found duplicate record of differing type")));
  914. return FALSE;
  915. }
  916. }
  917. else
  918. {
  919. PRDPF_RECORD node = NewRecord(szName, RDPF_RECTYPE_UINT);
  920. if(node)
  921. {
  922. node->u.iVal = value;
  923. //Append the node to the end of the reclist
  924. if(AppendRecord(node))
  925. {
  926. return TRUE;
  927. }
  928. }
  929. return FALSE;
  930. }
  931. }
  932. else
  933. {
  934. return FALSE;
  935. }
  936. DC_END_FN();
  937. }
  938. //
  939. // Insert a binary buffer record (RDPF_RECTYPE_BINARY)
  940. // modifies existing record if one found
  941. //
  942. BOOL CRdpFileStore::InsertBinaryRecord(LPCTSTR szName, PBYTE pBuf, DWORD dwLen)
  943. {
  944. DC_BEGIN_FN("InsertBinaryRecord");
  945. TRC_ASSERT(szName && pBuf && dwLen,
  946. (TB,_T("Invalid szName or pBuf")));
  947. if(szName)
  948. {
  949. PRDPF_RECORD node;
  950. node = FindRecord(szName);
  951. if(node)
  952. {
  953. if(node->recType == RDPF_RECTYPE_BINARY)
  954. {
  955. //
  956. // Existing record found, modify its contents
  957. //
  958. if(node->u.pBinVal)
  959. {
  960. LocalFree(node->u.pBinVal);
  961. }
  962. node->u.pBinVal = (PBYTE) LocalAlloc(LPTR, dwLen);
  963. if(node->u.pBinVal)
  964. {
  965. memcpy(node->u.pBinVal, pBuf, dwLen);
  966. node->dwBinValLen = dwLen;
  967. return TRUE;
  968. }
  969. else
  970. {
  971. return FALSE;
  972. }
  973. return TRUE;
  974. }
  975. else
  976. {
  977. //
  978. // dup record of differing type
  979. //
  980. TRC_ASSERT(FALSE,(TB,_T("found duplicate record of differing type")));
  981. return FALSE;
  982. }
  983. }
  984. else
  985. {
  986. PRDPF_RECORD node = NewRecord(szName, RDPF_RECTYPE_BINARY);
  987. if(node)
  988. {
  989. node->u.pBinVal = (PBYTE) LocalAlloc(LPTR, dwLen);
  990. if(node->u.pBinVal)
  991. {
  992. memcpy(node->u.pBinVal, pBuf, dwLen);
  993. node->dwBinValLen = dwLen;
  994. if(AppendRecord(node))
  995. {
  996. return TRUE;
  997. }
  998. else
  999. {
  1000. return FALSE;
  1001. }
  1002. }
  1003. else
  1004. {
  1005. return FALSE;
  1006. }
  1007. }
  1008. return FALSE;
  1009. }
  1010. }
  1011. else
  1012. {
  1013. return FALSE;
  1014. }
  1015. DC_END_FN();
  1016. }
  1017. //
  1018. // A worker function to make life easier in RecordToString. This function
  1019. // takes a source string, cats it to a destination string, and then appends
  1020. // a carriage return and line-feed.
  1021. //
  1022. HRESULT StringCchCatCRLF(LPTSTR pszDest, size_t cchDest, LPCTSTR pszSrc)
  1023. {
  1024. HRESULT hr = E_FAIL;
  1025. DC_BEGIN_FN("StringCchCatCRLF");
  1026. hr = StringCchCat(pszDest, cchDest, pszSrc);
  1027. if (FAILED(hr)) {
  1028. DC_QUIT;
  1029. }
  1030. hr = StringCchCat(pszDest, cchDest, _T("\r\n"));
  1031. if (FAILED(hr)) {
  1032. DC_QUIT;
  1033. }
  1034. DC_EXIT_POINT:
  1035. DC_END_FN();
  1036. return hr;
  1037. }
  1038. //
  1039. // Flatten a record to a string (szBuf) using format:
  1040. // name:type:value\r\n
  1041. //
  1042. BOOL CRdpFileStore::RecordToString(PRDPF_RECORD pNode, LPTSTR szBuf, UINT strLen)
  1043. {
  1044. DC_BEGIN_FN("RecordToString");
  1045. TRC_ASSERT(pNode && szBuf && strLen,
  1046. (TB,_T("Invalid parameters to RecordToString")));
  1047. TCHAR szTemp[LINEBUF_SIZE];
  1048. INT lenRemain = strLen;
  1049. HRESULT hr;
  1050. if(pNode && szBuf && strLen)
  1051. {
  1052. TRC_ASSERT(IS_VALID_RDPF_TYPECODE(pNode->recType),
  1053. (TB,_T("Invalid typecode %d"),pNode->recType));
  1054. if(pNode->recType != RDPF_RECTYPE_UNPARSED)
  1055. {
  1056. // Space for name field, typecode, two delimiters and a NULL.
  1057. lenRemain -= _tcslen(pNode->szName) + 4;
  1058. if(lenRemain >= 0)
  1059. {
  1060. hr = StringCchPrintf(szBuf, strLen, _T("%s%s"),
  1061. pNode->szName,
  1062. g_szTypeCodeMap[pNode->recType]);
  1063. if (FAILED(hr)) {
  1064. TRC_ERR((TB, _T("String printf failed: hr = 0x%x"), hr));
  1065. return FALSE;
  1066. }
  1067. switch(pNode->recType)
  1068. {
  1069. case RDPF_RECTYPE_UINT:
  1070. {
  1071. _stprintf(szTemp,TEXT("%d"),pNode->u.iVal);
  1072. // Need space for a "\r\n" sequence.
  1073. lenRemain -= _tcslen(szTemp) + 2;
  1074. if(lenRemain >= 0)
  1075. {
  1076. hr = StringCchCatCRLF(szBuf, strLen, szTemp);
  1077. if (FAILED(hr)) {
  1078. TRC_ERR((TB, _T("String concatenation failed: hr = 0x%x"), hr));
  1079. return FALSE;
  1080. }
  1081. return TRUE;
  1082. }
  1083. else
  1084. {
  1085. return FALSE;
  1086. }
  1087. }
  1088. break;
  1089. case RDPF_RECTYPE_SZ:
  1090. {
  1091. // Need space for a "\r\n" sequence.
  1092. lenRemain -= _tcslen(pNode->u.szVal) + 2;
  1093. if(lenRemain >= 0)
  1094. {
  1095. hr = StringCchCatCRLF(szBuf, strLen, pNode->u.szVal);
  1096. if (FAILED(hr)) {
  1097. TRC_ERR((TB, _T("String concatenation failed: hr = 0x%x"), hr));
  1098. return FALSE;
  1099. }
  1100. return TRUE;
  1101. }
  1102. else
  1103. {
  1104. return FALSE;
  1105. }
  1106. }
  1107. break;
  1108. case RDPF_RECTYPE_BINARY:
  1109. {
  1110. DWORD dwLen;
  1111. //
  1112. // Convert the binary buffer to string form
  1113. //
  1114. //
  1115. // First get the buffer length
  1116. //
  1117. if(!CUT::StringtoBinary( pNode->dwBinValLen,
  1118. (PBYTE)pNode->u.pBinVal,
  1119. NULL, &dwLen))
  1120. {
  1121. TRC_ERR((TB,
  1122. _T("Failed to get StringtoBinary buffer len")));
  1123. return FALSE;
  1124. }
  1125. lenRemain -= dwLen;
  1126. if(lenRemain >= 0 && dwLen < LINEBUF_SIZE)
  1127. {
  1128. //
  1129. // Do the conversion
  1130. //
  1131. if(CUT::StringtoBinary( pNode->dwBinValLen,
  1132. (PBYTE)pNode->u.pBinVal,
  1133. (LPTSTR) szTemp, &dwLen))
  1134. {
  1135. //String to binary appends two trailing
  1136. //'0' characters. get rid of them.
  1137. szTemp[dwLen-2] = NULL;
  1138. hr = StringCchCatCRLF(szBuf, strLen, szTemp);
  1139. if (FAILED(hr)) {
  1140. TRC_ERR((TB, _T("String concatenation failed: hr = 0x%x"), hr));
  1141. return FALSE;
  1142. }
  1143. return TRUE;
  1144. }
  1145. else
  1146. {
  1147. TRC_ERR((TB,_T("StringtoBinary conversion failed")));
  1148. return FALSE;
  1149. }
  1150. }
  1151. else
  1152. {
  1153. return FALSE;
  1154. }
  1155. }
  1156. break;
  1157. }
  1158. return FALSE;
  1159. }
  1160. else
  1161. {
  1162. return FALSE;
  1163. }
  1164. }
  1165. else
  1166. {
  1167. //Unparsed record, just splat the value
  1168. hr = StringCchCopy(szBuf, strLen, pNode->u.szUnparsed);
  1169. if (SUCCEEDED(hr)) {
  1170. return TRUE;
  1171. } else {
  1172. TRC_ERR((TB, _T("String copy failed: hr = 0x%x"), hr));
  1173. return FALSE;
  1174. }
  1175. }
  1176. }
  1177. else
  1178. {
  1179. return FALSE;
  1180. }
  1181. DC_END_FN();
  1182. }
  1183. //
  1184. // Search the record list
  1185. // for the first record with the given name
  1186. //
  1187. PRDPF_RECORD CRdpFileStore::FindRecord(LPCTSTR szName)
  1188. {
  1189. DC_BEGIN_FN("FindRecord");
  1190. if(szName && _pRecordListHead)
  1191. {
  1192. TCHAR szCmpName[RDPF_NAME_LEN];
  1193. HRESULT hr = StringCchCopy(szCmpName, SIZECHAR(szCmpName), szName);
  1194. if (FAILED(hr)) {
  1195. TRC_ERR((TB, _T("String copy failed: hr = 0x%x"), hr));
  1196. return NULL;
  1197. }
  1198. _tcslwr(szCmpName);
  1199. PRDPF_RECORD node = _pRecordListHead;
  1200. while(node)
  1201. {
  1202. if(!_tcscmp(szCmpName, node->szName))
  1203. {
  1204. return node;
  1205. }
  1206. node=node->pNext;
  1207. }
  1208. return NULL;
  1209. }
  1210. else
  1211. {
  1212. return NULL;
  1213. }
  1214. DC_END_FN();
  1215. }
  1216. //
  1217. // Append record to the end of the record list
  1218. // for a record with the given name
  1219. //
  1220. BOOL CRdpFileStore::AppendRecord(PRDPF_RECORD node)
  1221. {
  1222. DC_BEGIN_FN("AppendRecord");
  1223. if(node)
  1224. {
  1225. node->pNext = NULL;
  1226. if(_pRecordListHead && _pRecordListTail)
  1227. {
  1228. node->pPrev = _pRecordListTail;
  1229. _pRecordListTail->pNext= node;
  1230. _pRecordListTail = node;
  1231. return TRUE;
  1232. }
  1233. else
  1234. {
  1235. _pRecordListHead = _pRecordListTail = node;
  1236. node->pPrev = NULL;
  1237. return TRUE;
  1238. }
  1239. }
  1240. else
  1241. {
  1242. return FALSE;
  1243. }
  1244. DC_END_FN();
  1245. }
  1246. //
  1247. // Create a new record with name szName
  1248. //
  1249. PRDPF_RECORD CRdpFileStore::NewRecord(LPCTSTR szName, UINT TypeCode)
  1250. {
  1251. DC_BEGIN_FN("NewRecord");
  1252. PRDPF_RECORD node = NULL;
  1253. if(szName)
  1254. {
  1255. //Need to insert new node
  1256. node = (PRDPF_RECORD)LocalAlloc(LPTR,
  1257. sizeof(RDPF_RECORD));
  1258. if(node)
  1259. {
  1260. node->recType = TypeCode;
  1261. HRESULT hr = StringCchCopy(node->szName, SIZECHAR(node->szName), szName);
  1262. if (FAILED(hr)) {
  1263. TRC_ERR((TB, _T("String copy failed: hr = 0x%x"), hr));
  1264. return NULL;
  1265. }
  1266. _tcslwr(node->szName);
  1267. node->pPrev= node->pNext= NULL;
  1268. }
  1269. }
  1270. DC_END_FN();
  1271. return node;
  1272. }
  1273. //
  1274. // DeleteRecords
  1275. // deletes and resets all inmemory record structures
  1276. //
  1277. BOOL CRdpFileStore::DeleteRecords()
  1278. {
  1279. DC_BEGIN_FN("DeleteRecords");
  1280. PRDPF_RECORD node = _pRecordListHead;
  1281. PRDPF_RECORD prev;
  1282. while(node)
  1283. {
  1284. prev = node;
  1285. node = node->pNext;
  1286. switch(prev->recType)
  1287. {
  1288. case RDPF_RECTYPE_SZ:
  1289. LocalFree(prev->u.szVal);
  1290. break;
  1291. case RDPF_RECTYPE_BINARY:
  1292. LocalFree(prev->u.pBinVal);
  1293. break;
  1294. case RDPF_RECTYPE_UNPARSED:
  1295. LocalFree(prev->u.szUnparsed);
  1296. break;
  1297. }
  1298. LocalFree(prev);
  1299. }
  1300. _pRecordListHead = NULL;
  1301. _pRecordListTail = NULL;
  1302. DC_END_FN();
  1303. return TRUE;
  1304. }
  1305. inline BOOL CRdpFileStore::DeleteRecord(PRDPF_RECORD node)
  1306. {
  1307. DC_BEGIN_FN("DeleteRecord");
  1308. TRC_ASSERT(node,(TB,_T("node is null")));
  1309. if(node)
  1310. {
  1311. if(_pRecordListTail == node)
  1312. {
  1313. _pRecordListTail = node->pPrev;
  1314. }
  1315. if(_pRecordListHead == node)
  1316. {
  1317. _pRecordListHead = node->pNext;
  1318. }
  1319. if(node->pPrev)
  1320. {
  1321. node->pPrev->pNext = node->pNext;
  1322. }
  1323. if(node->pNext)
  1324. {
  1325. node->pNext->pPrev = node->pPrev;
  1326. }
  1327. switch(node->recType)
  1328. {
  1329. case RDPF_RECTYPE_SZ:
  1330. LocalFree(node->u.szVal);
  1331. break;
  1332. case RDPF_RECTYPE_BINARY:
  1333. LocalFree(node->u.pBinVal);
  1334. break;
  1335. case RDPF_RECTYPE_UNPARSED:
  1336. LocalFree(node->u.szUnparsed);
  1337. break;
  1338. }
  1339. LocalFree(node);
  1340. return TRUE;
  1341. }
  1342. else
  1343. {
  1344. return FALSE;
  1345. }
  1346. DC_END_FN();
  1347. return FALSE;
  1348. }
  1349. BOOL CRdpFileStore::DeleteValueIfPresent(LPCTSTR szName)
  1350. {
  1351. DC_BEGIN_FN("DeleteValueIfPresent");
  1352. TRC_ASSERT(szName,(TB,_T("szName is null")));
  1353. if(szName)
  1354. {
  1355. PRDPF_RECORD node = FindRecord(szName);
  1356. if(node)
  1357. {
  1358. return DeleteRecord(node);
  1359. }
  1360. else
  1361. {
  1362. return TRUE;
  1363. }
  1364. }
  1365. else
  1366. {
  1367. return FALSE;
  1368. }
  1369. DC_END_FN();
  1370. }
  1371. //
  1372. // Initialize to a NULL store that is readable
  1373. //
  1374. BOOL CRdpFileStore::SetToNullStore()
  1375. {
  1376. DC_BEGIN_FN("SetToNullStore");
  1377. DeleteRecords();
  1378. _fOpenForRead = TRUE;
  1379. _fOpenForWrite = TRUE;
  1380. DC_END_FN();
  1381. return TRUE;
  1382. }
  1383. //
  1384. // Return TRUE if the record is present
  1385. //
  1386. BOOL CRdpFileStore::IsValuePresent(LPTSTR szName)
  1387. {
  1388. DC_BEGIN_FN("IsValuePresent");
  1389. if(szName)
  1390. {
  1391. PRDPF_RECORD node = FindRecord(szName);
  1392. if(node)
  1393. {
  1394. return TRUE;
  1395. }
  1396. else
  1397. {
  1398. return FALSE;
  1399. }
  1400. }
  1401. else
  1402. {
  1403. return FALSE;
  1404. }
  1405. DC_END_FN();
  1406. }
  1407. DWORD CRdpFileStore::GetDataLength(LPCTSTR szName)
  1408. {
  1409. if(szName)
  1410. {
  1411. PRDPF_RECORD node = FindRecord(szName);
  1412. if(node)
  1413. {
  1414. switch (node->recType)
  1415. {
  1416. case RDPF_RECTYPE_UINT:
  1417. return sizeof(UINT);
  1418. break;
  1419. case RDPF_RECTYPE_SZ:
  1420. return _tcslen(node->u.szVal) * sizeof(TCHAR);
  1421. break;
  1422. case RDPF_RECTYPE_BINARY:
  1423. return node->dwBinValLen;
  1424. break;
  1425. default:
  1426. return 0;
  1427. }
  1428. }
  1429. else
  1430. {
  1431. return 0;
  1432. }
  1433. }
  1434. else
  1435. {
  1436. return 0;
  1437. }
  1438. }