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.

506 lines
14 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. try {
  145. pChild->SetCaseSensitive(IsCaseSensitive());
  146. pChild->SetAllowRehashing(AllowRehashing());
  147. pChild->SetIndexed(IsIndexed());
  148. m_children->SetAt(seg,pChild);
  149. nCreated++; // we added a new node
  150. }
  151. catch(...) {
  152. delete pChild;
  153. pChild = NULL;
  154. m_cs.Unlock();
  155. throw;
  156. }
  157. }
  158. else
  159. {
  160. pChild = (CVarData*)pObj;
  161. }
  162. // strip off the first segment from the property name, and call SetData
  163. // recursively on the child item
  164. nCreated += pChild->SetData(key.Right(key.GetLength() - seg.GetLength()-1),var,bCoerce,&hr);
  165. m_cs.Unlock();
  166. }
  167. if ( pResult )
  168. {
  169. (*pResult) = hr;
  170. }
  171. return nCreated;
  172. }
  173. void
  174. CVarData::RemoveAll()
  175. {
  176. // remove all children from the map
  177. m_cs.Lock();
  178. if ( m_children && ! m_children->IsEmpty() )
  179. {
  180. // Enumerate the MAP and delete each object
  181. POSITION pos;
  182. CString key;
  183. CVarData * pObj;
  184. pos = m_children->GetStartPosition();
  185. while ( pos )
  186. {
  187. m_children->GetNextAssoc(pos,key,pObj);
  188. if ( pObj )
  189. {
  190. delete pObj;
  191. }
  192. }
  193. m_children->RemoveAll();
  194. }
  195. if ( m_children )
  196. {
  197. delete m_children;
  198. m_children = NULL;
  199. }
  200. m_cs.Unlock();
  201. }
  202. BOOL // ret- TRUE if key exists in the map
  203. CVarData::Lookup(
  204. LPCTSTR key, // in - key to search for
  205. CVarData *& rValue // out- value
  206. )
  207. {
  208. if ( m_children )
  209. {
  210. return m_children->Lookup(key,rValue);
  211. }
  212. else
  213. {
  214. return FALSE;
  215. }
  216. }
  217. BOOL // ret- TRUE if there are sub-items for this node
  218. CVarData::HasChildren()
  219. {
  220. return m_children && !m_children->IsEmpty();
  221. }
  222. void
  223. CVarData::SetAt(
  224. LPCTSTR key, // in - key
  225. CVarData * newValue // in - new value
  226. )
  227. {
  228. if ( ! m_children )
  229. {
  230. // create map to hold children if it doesn't already exist
  231. m_children = new CMapStringToVar(IsCaseSensitive(),IsIndexed(),AllowRehashing());
  232. if (!m_children)
  233. return;
  234. }
  235. m_children->SetAt(key,newValue);
  236. }
  237. void
  238. CVarData::SetIndexed(
  239. BOOL nVal
  240. )
  241. {
  242. if ( m_children )
  243. {
  244. m_children->SetIndexed(nVal);
  245. }
  246. if ( nVal )
  247. {
  248. m_options |= CVARDATA_INDEXED;
  249. }
  250. else
  251. {
  252. m_options &= ~CVARDATA_INDEXED;
  253. }
  254. }
  255. void
  256. CVarData::SetCaseSensitive(
  257. BOOL nVal // in - whether to make lookups case-sensitive
  258. )
  259. {
  260. if ( m_children )
  261. {
  262. m_children->SetCaseSensitive(nVal);
  263. }
  264. if ( nVal )
  265. {
  266. m_options |= CVARDATA_CASE_SENSITIVE;
  267. }
  268. else
  269. {
  270. m_options &= ~CVARDATA_CASE_SENSITIVE;
  271. }
  272. }
  273. void
  274. CVarData::SetAllowRehashing(
  275. BOOL nVal // in - whether to allow the table to be rehashed for better performance
  276. )
  277. {
  278. if ( m_children )
  279. {
  280. m_children->SetAllowRehash(nVal);
  281. }
  282. if ( nVal )
  283. {
  284. m_options |= CVARDATA_ALLOWREHASH;
  285. }
  286. else
  287. {
  288. m_options &= ~CVARDATA_ALLOWREHASH;
  289. }
  290. }
  291. HRESULT
  292. CVarData::WriteToStream(
  293. LPSTREAM pS // in - stream to write data to
  294. )
  295. {
  296. HRESULT hr = S_OK;
  297. BOOL hasChildren = (m_children != NULL);
  298. // save the variant
  299. hr = m_var.WriteToStream(pS);
  300. if (SUCCEEDED(hr) )
  301. {
  302. // save children, if any
  303. ULONG result;
  304. hr = pS->Write(&hasChildren,(sizeof hasChildren),&result);
  305. if ( SUCCEEDED(hr) )
  306. {
  307. if ( m_children )
  308. {
  309. hr = m_children->WriteToStream(pS);
  310. }
  311. }
  312. }
  313. return hr;
  314. }
  315. HRESULT
  316. CVarData::ReadFromStream(
  317. LPSTREAM pS // in - stream to read data from
  318. )
  319. {
  320. HRESULT hr = S_OK;
  321. BOOL hasChildren;
  322. ULONG result;
  323. // read the variant
  324. hr = m_var.ReadFromStream(pS);
  325. if ( SUCCEEDED(hr) )
  326. {
  327. hr = pS->Read(&hasChildren,(sizeof hasChildren),&result);
  328. if ( SUCCEEDED(hr) )
  329. {
  330. if ( hasChildren )
  331. {
  332. // create the child array
  333. m_children = new CMapStringToVar(IsCaseSensitive(),IsIndexed(),AllowRehashing());
  334. if (!m_children)
  335. return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
  336. hr = m_children->ReadFromStream(pS);
  337. }
  338. }
  339. }
  340. return hr;
  341. }
  342. DWORD // ret- Length, in bytes to write the data to a stream
  343. CVarData::CalculateStreamedLength()
  344. {
  345. HRESULT hr =S_OK;
  346. DWORD len = sizeof (VARTYPE);
  347. // Calculate size needed for root data value
  348. int cbWrite = 0;
  349. switch (m_var.vt)
  350. {
  351. case VT_UNKNOWN:
  352. case VT_DISPATCH:
  353. {
  354. CComQIPtr<IPersistStream> spStream = m_var.punkVal;
  355. if( spStream )
  356. {
  357. len += sizeof(CLSID);
  358. ULARGE_INTEGER uiSize = { 0 };
  359. hr = spStream->GetSizeMax(&uiSize);
  360. if (FAILED(hr))
  361. return hr;
  362. len += uiSize.LowPart;
  363. }
  364. }
  365. break;
  366. case VT_UI1:
  367. case VT_I1:
  368. cbWrite = sizeof(BYTE);
  369. break;
  370. case VT_I2:
  371. case VT_UI2:
  372. case VT_BOOL:
  373. cbWrite = sizeof(short);
  374. break;
  375. case VT_I4:
  376. case VT_UI4:
  377. case VT_R4:
  378. case VT_INT:
  379. case VT_UINT:
  380. case VT_ERROR:
  381. cbWrite = sizeof(long);
  382. break;
  383. case VT_R8:
  384. case VT_CY:
  385. case VT_DATE:
  386. cbWrite = sizeof(double);
  387. break;
  388. default:
  389. break;
  390. }
  391. CComBSTR bstrWrite;
  392. CComVariant varBSTR;
  393. if (m_var.vt != VT_BSTR)
  394. {
  395. hr = VariantChangeType(&varBSTR, &m_var, VARIANT_NOVALUEPROP, VT_BSTR);
  396. if (FAILED(hr))
  397. return hr;
  398. bstrWrite = varBSTR.bstrVal;
  399. }
  400. else
  401. {
  402. bstrWrite = m_var.bstrVal;
  403. }
  404. len += 4 + (static_cast<BSTR>(bstrWrite) ? SysStringByteLen(bstrWrite) : 0) + 2;
  405. if ( SUCCEEDED(hr) )
  406. {
  407. len += cbWrite;
  408. }
  409. // Add sizes of children
  410. len += (sizeof BOOL); // has children?
  411. if ( m_children )
  412. {
  413. len += m_children->CalculateStreamedLength();
  414. }
  415. return len;
  416. }
  417. long // ret- number of data items
  418. CVarData::CountItems()
  419. {
  420. long count = 1;
  421. if ( m_children )
  422. {
  423. count += m_children->CountItems();
  424. }
  425. return count;
  426. }
  427. void
  428. CVarData::McLogInternalDiagnostics(
  429. CString keyname // in - Key name for this subtree, so the complete name can be displayed
  430. )
  431. {
  432. CString value;
  433. switch ( m_var.vt )
  434. {
  435. case VT_EMPTY:
  436. value = _T("<Empty>");
  437. break;
  438. case VT_NULL:
  439. value = _T("<Null>");
  440. break;
  441. case VT_I2:
  442. case VT_I4:
  443. value.Format(_T("%ld"),m_var.iVal);
  444. break;
  445. case VT_BSTR:
  446. value = m_var.bstrVal;
  447. break;
  448. default:
  449. value.Format(_T("variant type=0x%lx"),m_var.vt);
  450. break;
  451. }
  452. MC_LOG(String(keyname) << "-->"<< String(value) << (m_children ? " (Has Children)" : " (No Children)") << " Options = " << makeStr(m_options) << " CaseSensitive=" << ( IsCaseSensitive()?"TRUE":"FALSE") << " Indexed=" << (IsIndexed()?"TRUE":"FALSE") );
  453. if ( m_children )
  454. {
  455. m_children->McLogInternalDiagnostics(keyname);
  456. }
  457. }