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.

497 lines
13 KiB

  1. /*---------------------------------------------------------------------------
  2. File: VarData.cpp
  3. Comments: CVarData represents one level in the VarSet. It has a variant
  4. value, and a map containing one or more subvalues.
  5. (c) Copyright 1995-1998, Mission Critical Software, Inc., All Rights Reserved
  6. Proprietary and confidential to Mission Critical Software, Inc.
  7. REVISION LOG ENTRY
  8. Revision By: Christy Boles
  9. Revised on 11/19/98 17:24:56
  10. ---------------------------------------------------------------------------
  11. */
  12. #include "stdafx.h"
  13. #include "VarData.h"
  14. #include "VarMap.h"
  15. #include "DotStr.hpp"
  16. #ifdef STRIPPED_VARSET
  17. #include "Varset.h"
  18. #include "NoMcs.h"
  19. #else
  20. #include <VarSet.h>
  21. #include "McString.h"
  22. #include "McLog.h"
  23. using namespace McString;
  24. #endif
  25. #include "VSet.h"
  26. #include <comdef.h>
  27. #ifdef _DEBUG
  28. #define new DEBUG_NEW
  29. #undef THIS_FILE
  30. static char THIS_FILE[] = __FILE__;
  31. #endif
  32. int
  33. CVarData::SetData(
  34. CString key, // in - key value
  35. VARIANT * var, // in - data value
  36. BOOL bCoerce, // in - flag, whether to coerce to a persistable value
  37. HRESULT * pResult // out- optional return code
  38. )
  39. {
  40. int nCreated = 0;
  41. _variant_t newVal(var);
  42. HRESULT hr = S_OK;
  43. if ( key.IsEmpty() )
  44. {
  45. m_cs.Lock();
  46. // set my data value
  47. if ( ! bCoerce )
  48. {
  49. m_var.Copy(&newVal);
  50. }
  51. else
  52. {
  53. // need to coerce the value to an appropriate type
  54. if ( var->vt == VT_DISPATCH || var->vt == VT_UNKNOWN )
  55. {
  56. // if it's an IUnknown, see if it supports IDispatch
  57. IDispatchPtr pDisp;
  58. pDisp = newVal;
  59. if ( pDisp != NULL )
  60. {
  61. // the object supports IDispatch
  62. // try to get the default property
  63. _variant_t defPropVar;
  64. DISPPARAMS dispParamsNoArgs = {NULL, NULL, 0, 0};
  65. hr = pDisp->Invoke(0,
  66. IID_NULL,
  67. LOCALE_USER_DEFAULT,
  68. DISPATCH_PROPERTYGET,
  69. &dispParamsNoArgs,
  70. &defPropVar,
  71. NULL,
  72. NULL);
  73. if ( SUCCEEDED(hr) )
  74. {
  75. // we got the default property
  76. newVal = defPropVar;
  77. }
  78. else
  79. {
  80. MC_LOG("VarSet::put - unable to retrieve default property for IDispatch object. Put operation failed, hr=" << hr << "returning E_INVALIDARG");
  81. hr = E_INVALIDARG;
  82. }
  83. }
  84. }
  85. if ( SUCCEEDED(hr) )
  86. {
  87. if ( newVal.vt & VT_BYREF )
  88. {
  89. if ( newVal.vt == (VT_VARIANT | VT_BYREF) )
  90. {
  91. m_var.Copy(newVal.pvarVal);
  92. }
  93. else
  94. {
  95. hr = ::VariantChangeType(&newVal,&newVal,0,newVal.vt & ~VT_BYREF);
  96. if ( SUCCEEDED(hr) )
  97. {
  98. m_var.Copy(&newVal);
  99. }
  100. else
  101. {
  102. MC_LOG("VarSet::put - failed to dereference variant of type " << newVal.vt << ". Put operation failed, hr=" <<hr);
  103. hr = E_INVALIDARG;
  104. }
  105. }
  106. }
  107. else
  108. {
  109. m_var.Copy(&newVal);
  110. }
  111. }
  112. }
  113. m_cs.Unlock();
  114. }
  115. else
  116. {
  117. // set the value for a child
  118. CDottedString s(key);
  119. CString seg;
  120. CVarData * pObj;
  121. CVarData * pChild;
  122. s.GetSegment(0,seg);
  123. m_cs.Lock();
  124. if ( ! m_children )
  125. {
  126. // create the child map if it does not exist
  127. m_children = new CMapStringToVar(IsCaseSensitive(),IsIndexed(), AllowRehashing() );
  128. if (!m_children)
  129. {
  130. m_cs.Unlock();
  131. return nCreated;
  132. }
  133. }
  134. // look for the first segment of the entry in the child map
  135. if ( ! m_children->Lookup(seg,pObj) )
  136. {
  137. // add it if it doesn't exist
  138. pChild = new CVarData;
  139. if (!pChild)
  140. {
  141. m_cs.Unlock();
  142. return nCreated;
  143. }
  144. pChild->SetCaseSensitive(IsCaseSensitive());
  145. pChild->SetAllowRehashing(AllowRehashing());
  146. pChild->SetIndexed(IsIndexed());
  147. m_children->SetAt(seg,pChild);
  148. nCreated++; // we added a new node
  149. }
  150. else
  151. {
  152. pChild = (CVarData*)pObj;
  153. }
  154. // strip off the first segment from the property name, and call SetData
  155. // recursively on the child item
  156. nCreated += pChild->SetData(key.Right(key.GetLength() - seg.GetLength()-1),var,bCoerce,&hr);
  157. m_cs.Unlock();
  158. }
  159. if ( pResult )
  160. {
  161. (*pResult) = hr;
  162. }
  163. return nCreated;
  164. }
  165. void
  166. CVarData::RemoveAll()
  167. {
  168. // remove all children from the map
  169. m_cs.Lock();
  170. if ( m_children && ! m_children->IsEmpty() )
  171. {
  172. // Enumerate the MAP and delete each object
  173. POSITION pos;
  174. CString key;
  175. CVarData * pObj;
  176. pos = m_children->GetStartPosition();
  177. while ( pos )
  178. {
  179. m_children->GetNextAssoc(pos,key,pObj);
  180. if ( pObj )
  181. {
  182. delete pObj;
  183. }
  184. }
  185. m_children->RemoveAll();
  186. }
  187. if ( m_children )
  188. {
  189. delete m_children;
  190. m_children = NULL;
  191. }
  192. m_cs.Unlock();
  193. }
  194. BOOL // ret- TRUE if key exists in the map
  195. CVarData::Lookup(
  196. LPCTSTR key, // in - key to search for
  197. CVarData *& rValue // out- value
  198. )
  199. {
  200. if ( m_children )
  201. {
  202. return m_children->Lookup(key,rValue);
  203. }
  204. else
  205. {
  206. return FALSE;
  207. }
  208. }
  209. BOOL // ret- TRUE if there are sub-items for this node
  210. CVarData::HasChildren()
  211. {
  212. return m_children && !m_children->IsEmpty();
  213. }
  214. void
  215. CVarData::SetAt(
  216. LPCTSTR key, // in - key
  217. CVarData * newValue // in - new value
  218. )
  219. {
  220. if ( ! m_children )
  221. {
  222. // create map to hold children if it doesn't already exist
  223. m_children = new CMapStringToVar(IsCaseSensitive(),IsIndexed(),AllowRehashing());
  224. if (!m_children)
  225. return;
  226. }
  227. m_children->SetAt(key,newValue);
  228. }
  229. void
  230. CVarData::SetIndexed(
  231. BOOL nVal
  232. )
  233. {
  234. if ( m_children )
  235. {
  236. m_children->SetIndexed(nVal);
  237. }
  238. if ( nVal )
  239. {
  240. m_options |= CVARDATA_INDEXED;
  241. }
  242. else
  243. {
  244. m_options &= ~CVARDATA_INDEXED;
  245. }
  246. }
  247. void
  248. CVarData::SetCaseSensitive(
  249. BOOL nVal // in - whether to make lookups case-sensitive
  250. )
  251. {
  252. if ( m_children )
  253. {
  254. m_children->SetCaseSensitive(nVal);
  255. }
  256. if ( nVal )
  257. {
  258. m_options |= CVARDATA_CASE_SENSITIVE;
  259. }
  260. else
  261. {
  262. m_options &= ~CVARDATA_CASE_SENSITIVE;
  263. }
  264. }
  265. void
  266. CVarData::SetAllowRehashing(
  267. BOOL nVal // in - whether to allow the table to be rehashed for better performance
  268. )
  269. {
  270. if ( m_children )
  271. {
  272. m_children->SetAllowRehash(nVal);
  273. }
  274. if ( nVal )
  275. {
  276. m_options |= CVARDATA_ALLOWREHASH;
  277. }
  278. else
  279. {
  280. m_options &= ~CVARDATA_ALLOWREHASH;
  281. }
  282. }
  283. HRESULT
  284. CVarData::WriteToStream(
  285. LPSTREAM pS // in - stream to write data to
  286. )
  287. {
  288. HRESULT hr = S_OK;
  289. BOOL hasChildren = (m_children != NULL);
  290. // save the variant
  291. hr = m_var.WriteToStream(pS);
  292. if (SUCCEEDED(hr) )
  293. {
  294. // save children, if any
  295. ULONG result;
  296. hr = pS->Write(&hasChildren,(sizeof hasChildren),&result);
  297. if ( SUCCEEDED(hr) )
  298. {
  299. if ( m_children )
  300. {
  301. hr = m_children->WriteToStream(pS);
  302. }
  303. }
  304. }
  305. return 0;
  306. }
  307. HRESULT
  308. CVarData::ReadFromStream(
  309. LPSTREAM pS // in - stream to read data from
  310. )
  311. {
  312. HRESULT hr = S_OK;
  313. BOOL hasChildren;
  314. ULONG result;
  315. // read the variant
  316. hr = m_var.ReadFromStream(pS);
  317. if ( SUCCEEDED(hr) )
  318. {
  319. hr = pS->Read(&hasChildren,(sizeof hasChildren),&result);
  320. if ( SUCCEEDED(hr) )
  321. {
  322. if ( hasChildren )
  323. {
  324. // create the child array
  325. m_children = new CMapStringToVar(IsCaseSensitive(),IsIndexed(),AllowRehashing());
  326. if (!m_children)
  327. return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
  328. hr = m_children->ReadFromStream(pS);
  329. }
  330. }
  331. }
  332. return hr;
  333. }
  334. DWORD // ret- Length, in bytes to write the data to a stream
  335. CVarData::CalculateStreamedLength()
  336. {
  337. HRESULT hr =S_OK;
  338. DWORD len = sizeof (VARTYPE);
  339. // Calculate size needed for root data value
  340. int cbWrite = 0;
  341. switch (m_var.vt)
  342. {
  343. case VT_UNKNOWN:
  344. case VT_DISPATCH:
  345. {
  346. CComQIPtr<IPersistStream> spStream = m_var.punkVal;
  347. if( spStream )
  348. {
  349. len += sizeof(CLSID);
  350. ULARGE_INTEGER uiSize = { 0 };
  351. hr = spStream->GetSizeMax(&uiSize);
  352. if (FAILED(hr))
  353. return hr;
  354. len += uiSize.LowPart;
  355. }
  356. }
  357. break;
  358. case VT_UI1:
  359. case VT_I1:
  360. cbWrite = sizeof(BYTE);
  361. break;
  362. case VT_I2:
  363. case VT_UI2:
  364. case VT_BOOL:
  365. cbWrite = sizeof(short);
  366. break;
  367. case VT_I4:
  368. case VT_UI4:
  369. case VT_R4:
  370. case VT_INT:
  371. case VT_UINT:
  372. case VT_ERROR:
  373. cbWrite = sizeof(long);
  374. break;
  375. case VT_R8:
  376. case VT_CY:
  377. case VT_DATE:
  378. cbWrite = sizeof(double);
  379. break;
  380. default:
  381. break;
  382. }
  383. CComBSTR bstrWrite;
  384. CComVariant varBSTR;
  385. if (m_var.vt != VT_BSTR)
  386. {
  387. hr = VariantChangeType(&varBSTR, &m_var, VARIANT_NOVALUEPROP, VT_BSTR);
  388. if (FAILED(hr))
  389. return hr;
  390. bstrWrite = varBSTR.bstrVal;
  391. }
  392. else
  393. {
  394. bstrWrite = m_var.bstrVal;
  395. }
  396. len += 4 + (static_cast<BSTR>(bstrWrite) ? SysStringByteLen(bstrWrite) : 0) + 2;
  397. if ( SUCCEEDED(hr) )
  398. {
  399. len += cbWrite;
  400. }
  401. // Add sizes of children
  402. len += (sizeof BOOL); // has children?
  403. if ( m_children )
  404. {
  405. len += m_children->CalculateStreamedLength();
  406. }
  407. return len;
  408. }
  409. long // ret- number of data items
  410. CVarData::CountItems()
  411. {
  412. long count = 1;
  413. if ( m_children )
  414. {
  415. count += m_children->CountItems();
  416. }
  417. return count;
  418. }
  419. void
  420. CVarData::McLogInternalDiagnostics(
  421. CString keyname // in - Key name for this subtree, so the complete name can be displayed
  422. )
  423. {
  424. CString value;
  425. switch ( m_var.vt )
  426. {
  427. case VT_EMPTY:
  428. value = _T("<Empty>");
  429. break;
  430. case VT_NULL:
  431. value = _T("<Null>");
  432. break;
  433. case VT_I2:
  434. case VT_I4:
  435. value.Format(_T("%ld"),m_var.iVal);
  436. break;
  437. case VT_BSTR:
  438. value = m_var.bstrVal;
  439. break;
  440. default:
  441. value.Format(_T("variant type=0x%lx"),m_var.vt);
  442. break;
  443. }
  444. MC_LOG(String(keyname) << "-->"<< String(value) << (m_children ? " (Has Children)" : " (No Children)") << " Options = " << makeStr(m_options) << " CaseSensitive=" << ( IsCaseSensitive()?"TRUE":"FALSE") << " Indexed=" << (IsIndexed()?"TRUE":"FALSE") );
  445. if ( m_children )
  446. {
  447. m_children->McLogInternalDiagnostics(keyname);
  448. }
  449. }