hxvalues.cpp
Upload User: zhongxx05
Upload Date: 2007-06-06
Package Size: 33641k
Code Size: 27k
Category:

Symbian

Development Platform:

C/C++

  1. /* ***** BEGIN LICENSE BLOCK ***** 
  2.  * Version: RCSL 1.0/RPSL 1.0 
  3.  *  
  4.  * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved. 
  5.  *      
  6.  * The contents of this file, and the files included with this file, are 
  7.  * subject to the current version of the RealNetworks Public Source License 
  8.  * Version 1.0 (the "RPSL") available at 
  9.  * http://www.helixcommunity.org/content/rpsl unless you have licensed 
  10.  * the file under the RealNetworks Community Source License Version 1.0 
  11.  * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl, 
  12.  * in which case the RCSL will apply. You may also obtain the license terms 
  13.  * directly from RealNetworks.  You may not use this file except in 
  14.  * compliance with the RPSL or, if you have a valid RCSL with RealNetworks 
  15.  * applicable to this file, the RCSL.  Please see the applicable RPSL or 
  16.  * RCSL for the rights, obligations and limitations governing use of the 
  17.  * contents of the file.  
  18.  *  
  19.  * This file is part of the Helix DNA Technology. RealNetworks is the 
  20.  * developer of the Original Code and owns the copyrights in the portions 
  21.  * it created. 
  22.  *  
  23.  * This file, and the files included with this file, is distributed and made 
  24.  * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
  25.  * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  26.  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS 
  27.  * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
  28.  * 
  29.  * Technology Compatibility Kit Test Suite(s) Location: 
  30.  *    http://www.helixcommunity.org/content/tck 
  31.  * 
  32.  * Contributor(s): 
  33.  *  
  34.  * ***** END LICENSE BLOCK ***** */ 
  35. //
  36. // The CKeyValueList is a strange class, because it has some backward  
  37. // compatibilities w/the old-style IHXValues.  It supports these interfaces:
  38. // 
  39. //    IHXKeyValueList - non-uniquely list of strings
  40. //    IHXValues       - uniquely keyed lists of strings, buffers, ulongs
  41. //
  42. // FAQ:
  43. // ====
  44. //
  45. // Q: How can CKeyValueList support a non-uniquely keyed list of strings, while 
  46. // also supporting a uniquely keyed list of strings?  
  47. // 
  48. // A: The class as a whole does not enforces uniqueness.  If you exclusively use 
  49. // GetPropertyCString/SetPropertyCString for any given key, though, you can be
  50. // sure that only one instance of that key exists.  Read on.
  51. // 
  52. // OVERVIEW OF CLASS INTERFACE:
  53. // ============================
  54. //
  55. // Basically, this class allows you to store three types of data:
  56. //
  57. //    strings  
  58. //    buffers
  59. //    ULONGs
  60. // 
  61. // The data types are stored in completely separate data structures.
  62. //
  63. // Buffers and ULONGS are always uniquely keyed.  Use these functions to 
  64. // get/set Buffer/ULONG values:
  65. // 
  66. //  SetPropertyULONG32/GetPropertyULONG32
  67. //  SetPropertyBuffer/GetPropertyBuffer
  68. //
  69. // Strings can be non-uniquely keyed.  If you add a string using AddKeyValue,
  70. // you're gonna create a new key/string tuple, even if that key had already been 
  71. // used for a string.  
  72. //
  73. //    AddKeyValue - add new tuple, even if key was already used
  74. //    GetIterOneKey - see "Iterating"
  75. //
  76. //    GetPropertyCString - fail if no strings for that key; otherwise, return
  77. //          first string inserted for that key
  78. //    SetPropertyCString - write new tuple if no strings for that key; otherwise,
  79. //          change first tuple for that key to use new string
  80. //    
  81. // Mixing and matching AddKeyValue calls w/SetPropertyCString calls is allowable,
  82. // but generally indicates a muddled understanding of the interfaces.  
  83. //
  84. // Iterating --
  85. // -------------
  86. // To iterate over all your ULONG keys, use these functions:
  87. //
  88. //   GetFirstPropertyULONG32/GetNextPropertyULONG32
  89. //
  90. // To iterate over all your buffer keys, use these functions:
  91. //
  92. //   GetFirstPropertyBuffer/GetNextPropertyBuffer
  93. //
  94. // To iterate over all your strings, use these functions:
  95. //
  96. //   GetIter ... while (GetNextPair == HXR_OK)
  97. //
  98. // These are preferred to GetFirstPropertyCString/GetNextPropertyCString, 
  99. // because they are reentrant.  You can use the old interface, though.
  100. //
  101. // To iterate all the strings for a key, use these functions:
  102. //
  103. //   GetIterOneKey ... while (GetNextString == HXR_OK)
  104. //
  105. // While iterating, you can replace the current string by calling ReplaceCurr.
  106. // This is particulary useful when you are replacing several strings for the 
  107. // same key, like for mangling all cookies.
  108. //
  109. // 
  110. // SOME HISTORY:
  111. // =============
  112. // The predecessor to this class was CKeyedIList, and various cousins that were 
  113. // never really used.  The classes were replaced, due to strange interfaces and 
  114. // abusive precompiler usage.
  115. //
  116. //
  117. // USAGE/PERFORMANCE CONSIDERATIONS:
  118. // =================================
  119. // Don't use this class if you know all your keys are always going to be unique.
  120. // You'd be better off using CHXHeader for that, or some other class that 
  121. // supports only IHXValues.  On the other hand, even w/the extra baggage of 
  122. // IHXKeyValueList, this class is simpler than most other IHXValue variants,
  123. // so it might be good to use if you don't have a lot of keys.  This class uses
  124. // linked lists, and linear seaches.  Most other classes use hashes.
  125. //
  126. // This class should have the exact behavior as CHXHeaders for buffers and ULONGs.
  127. // Most users of this class barely do anything w/buffers and ULONGs.  If, however,
  128. // this class ever becomes a performance bottleneck, a good thing to do may be to
  129. // steal the CHXHeader code that relates to buffers and ulongs.  You're probably
  130. // best off cutting-and-pasting CHXHeader code, or in a pinch, you can have this
  131. // class wrap an actual CHXHeader object, and the string methods just get ignored.
  132. // Another option is to add a hash table to this implementation to speed up lookups.
  133. // 
  134. #include "hxtypes.h"
  135. #include "hxcom.h"
  136. #include "hxstrutl.h"
  137. #include "hxstring.h"
  138. #include "hxvalue.h"
  139. #include "ihxpckts.h"
  140. #include "hxbuffer.h"
  141. #include "hxvalues.h"
  142. #include "hxheap.h"
  143. #ifdef _DEBUG
  144. #undef HX_THIS_FILE
  145. static const char HX_THIS_FILE[] = __FILE__;
  146. #endif
  147. // CKeyValueList is further down....
  148. /////////////// CSimpleUlongMap
  149. CSimpleUlongMap::CSimpleUlongMap()
  150. {
  151.     m_pHead = NULL;
  152.     m_pTail = NULL;
  153.     m_pCurr = NULL;
  154. }
  155.  
  156. CSimpleUlongMap::~CSimpleUlongMap()
  157. {
  158.     while (m_pHead)
  159.     {
  160. node *p = m_pHead;
  161. delete[] p->pKey;
  162. m_pHead = p->pNext;
  163. delete p;
  164.     }
  165.     m_pHead = NULL; // paranoid
  166.     m_pTail = NULL; // paranoid
  167. }
  168. HX_RESULT CSimpleUlongMap::SetProperty(const char* pKey, ULONG32 ulValue)
  169. {
  170.     for (node *p = m_pHead; p; p = p->pNext)
  171.     {
  172. if (!StrCmpFunc(p->pKey, pKey)) 
  173. {
  174.     p->ulValue = ulValue;
  175.     return HXR_OK;
  176. }
  177.     }
  178.     node *pNew    = new node;
  179.     pNew->pNext   = NULL;
  180.     pNew->pKey    = new_string(pKey);
  181.     pNew->ulValue = ulValue;
  182.     if (m_pTail)
  183.     {
  184. m_pTail->pNext = pNew;
  185.     }
  186.     else
  187.     {
  188. m_pHead = pNew;
  189.     }
  190.     m_pTail = pNew;
  191.     return HXR_OK;
  192. }
  193. HX_RESULT CSimpleUlongMap::GetProperty(const char* pKey, REF(ULONG32) ulValue)
  194. {
  195.     for (node *p = m_pHead; p; p = p->pNext)
  196.     {
  197. if (!StrCmpFunc(p->pKey, pKey))
  198. {
  199.     ulValue = p->ulValue;
  200.     return HXR_OK;
  201. }
  202.     }
  203.     return HXR_FAILED;
  204. }
  205.     
  206. HX_RESULT CSimpleUlongMap::GetFirstProperty(REF(const char*) pKey, REF(ULONG32) ulValue)
  207. {
  208.     m_pCurr = m_pHead;
  209.     if (m_pCurr)
  210.     {
  211. pKey    = m_pCurr->pKey;
  212. ulValue = m_pCurr->ulValue;
  213.      return HXR_OK;
  214.     }
  215.     else
  216.     {
  217. return HXR_FAILED;
  218.     }
  219. }
  220.     
  221. HX_RESULT CSimpleUlongMap::GetNextProperty(REF(const char*) pKey, REF(ULONG32) ulValue)
  222. {
  223.     if (!m_pCurr)
  224.     {
  225. HX_ASSERT(0);
  226. return HXR_FAILED;
  227.     }
  228.     m_pCurr = m_pCurr->pNext;
  229.     if (m_pCurr)
  230.     {
  231. pKey    = m_pCurr->pKey;
  232. ulValue = m_pCurr->ulValue;
  233.      return HXR_OK;
  234.     }
  235.     else
  236.     {
  237. return HXR_FAILED;
  238.     }
  239. }
  240.     
  241. void CSimpleUlongMap::Remove(const char* pKey)
  242. {
  243.     if (!m_pHead) 
  244.     {
  245. return;
  246.     }
  247.     if (m_pHead && !StrCmpFunc(pKey,m_pHead->pKey))
  248.     {
  249. node *pNext = m_pHead->pNext;
  250. delete[] m_pHead->pKey;
  251. delete m_pHead;
  252. m_pHead = pNext;
  253. if (pNext == NULL)
  254. {
  255.     m_pTail = NULL;
  256. }
  257. return;
  258.     }
  259.     node *p1 = m_pHead;
  260.     node *p2 = p1->pNext;
  261.     while (p2)
  262.     {
  263. if (!StrCmpFunc(pKey,p2->pKey))
  264. {
  265.     p1->pNext = p2->pNext;
  266.     if (p1->pNext == NULL)
  267.     {
  268. m_pTail = p1;
  269.     }
  270.     delete[] p2->pKey;
  271.     delete p2;
  272.     return;
  273. }
  274. p1 = p2;
  275. p2 = p2->pNext;
  276.     }
  277. }
  278. /////////////// CSimpleBufferMap
  279. CSimpleBufferMap::CSimpleBufferMap()
  280. {
  281.     m_pHead = NULL;
  282.     m_pTail = NULL;
  283.     m_pCurr = NULL;
  284. }
  285.  
  286. CSimpleBufferMap::~CSimpleBufferMap()
  287. {
  288.     while (m_pHead)
  289.     {
  290. node *p = m_pHead;
  291. delete[] p->pKey;
  292.         HX_RELEASE(p->pValue);
  293. m_pHead = p->pNext;
  294. delete p;
  295.     }
  296.     m_pHead = NULL; // paranoid
  297.     m_pTail = NULL; // paranoid
  298. }
  299. HX_RESULT CSimpleBufferMap::SetProperty(const char* pKey, IHXBuffer* pValue)
  300. {
  301.     if (!pValue)
  302.     {
  303. HX_ASSERT(0);
  304. return HXR_FAIL;
  305.     }
  306.     for (node *p = m_pHead; p; p = p->pNext)
  307.     {
  308. if (!StrCmpFunc(p->pKey, pKey))
  309. {
  310.     IHXBuffer* pOld = p->pValue;           
  311.     p->pValue = pValue;
  312.     p->pValue->AddRef();
  313.     HX_RELEASE(pOld);
  314.     return HXR_OK;
  315. }
  316.     }
  317.     node *pNew    = new node;
  318.     pNew->pNext   = NULL;
  319.     pNew->pKey    = new_string(pKey);
  320.     pNew->pValue = pValue;
  321.     pNew->pValue->AddRef();
  322.     if (m_pTail)
  323.     {
  324. m_pTail->pNext = pNew;
  325.     }
  326.     else
  327.     {
  328. m_pHead = pNew;
  329.     }
  330.     m_pTail = pNew;
  331.     return HXR_OK;
  332. }
  333. HX_RESULT CSimpleBufferMap::GetProperty(const char* pKey, REF(IHXBuffer*) pValue)
  334. {
  335.     for (node *p = m_pHead; p; p = p->pNext)
  336.     {
  337. if (!StrCmpFunc(p->pKey, pKey))
  338. {
  339.     pValue = p->pValue;
  340.     pValue->AddRef();
  341.     return HXR_OK;
  342. }
  343.     }
  344.     return HXR_FAILED;
  345. }
  346.     
  347. HX_RESULT CSimpleBufferMap::GetFirstProperty(REF(const char*) pKey, REF(IHXBuffer*) pValue)
  348. {
  349.     m_pCurr = m_pHead;
  350.     if (m_pCurr)
  351.     {
  352. pKey    = m_pCurr->pKey;
  353. pValue = m_pCurr->pValue;
  354. pValue->AddRef();
  355.      return HXR_OK;
  356.     }
  357.     else
  358.     {
  359. return HXR_FAILED;
  360.     }
  361. }
  362.     
  363. HX_RESULT CSimpleBufferMap::GetNextProperty(REF(const char*) pKey, REF(IHXBuffer*) pValue)
  364. {
  365.     if (!m_pCurr)
  366.     {
  367. HX_ASSERT(0);
  368. return HXR_FAILED;
  369.     }
  370.     m_pCurr = m_pCurr->pNext;
  371.     if (m_pCurr)
  372.     {
  373. pKey    = m_pCurr->pKey;
  374. pValue = m_pCurr->pValue;
  375. pValue->AddRef();
  376.      return HXR_OK;
  377.     }
  378.     else
  379.     {
  380. return HXR_FAILED;
  381.     }
  382. }
  383.     
  384. void CSimpleBufferMap::Remove(const char* pKey)
  385. {
  386.     if (!m_pHead) 
  387.     {
  388. return;
  389.     }
  390.     if (m_pHead && !StrCmpFunc(pKey,m_pHead->pKey))
  391.     {
  392. node *pNext = m_pHead->pNext;
  393.         HX_RELEASE(m_pHead->pValue);
  394. delete[] m_pHead->pKey;
  395. delete m_pHead;
  396. m_pHead = pNext;
  397. if (pNext == NULL)
  398. {
  399.     m_pTail = NULL;
  400. }
  401. return;
  402.     }
  403.     node *p1 = m_pHead;
  404.     node *p2 = p1->pNext;
  405.     while (p2)
  406.     {
  407. if (!StrCmpFunc(pKey,p2->pKey))
  408. {
  409.     p1->pNext = p2->pNext;
  410.     if (p1->pNext == NULL)
  411.     {
  412. m_pTail = p1;
  413.     }
  414.             HX_RELEASE(p2->pValue);
  415.     delete[] p2->pKey;
  416.     delete p2;
  417.     return;
  418. }
  419. p1 = p2;
  420. p2 = p2->pNext;
  421.     }
  422. }
  423. //////////////// CKeyValueList
  424. STDMETHODIMP CKeyValueList::QueryInterface(REFIID riid, void** ppvObj)
  425. {
  426. QInterfaceList qiList[] =
  427. {
  428. { GET_IIDHANDLE(IID_IUnknown), this },
  429. { GET_IIDHANDLE(IID_IHXKeyValueList), (IHXKeyValueList*) this },
  430. { GET_IIDHANDLE(IID_IHXValues), (IHXValues*) this },
  431. };
  432.     return QIFind(qiList, QILISTSIZE(qiList), riid, ppvObj);   
  433. }
  434. STDMETHODIMP_(ULONG32) CKeyValueList::AddRef()
  435. {
  436.     return InterlockedIncrement(&m_lRefCount);
  437. }
  438. STDMETHODIMP_(ULONG32) CKeyValueList::Release()
  439. {
  440.     if (InterlockedDecrement(&m_lRefCount) > 0)
  441.     {
  442. return m_lRefCount;
  443.     }
  444.     delete this;
  445.     return 0;
  446. }
  447. CKeyValueList::CKeyValueList() : m_pTail(NULL), m_lRefCount(0)
  448. {
  449.     m_pList = new list;
  450.     m_pList->AddRef();
  451. }
  452. CKeyValueList::~CKeyValueList()
  453. {
  454.     if (m_pList)
  455.     {
  456.         m_pList->Release();
  457.         m_pList = NULL;
  458.     }
  459.     m_pTail = NULL; // paranoid
  460. }
  461. STDMETHODIMP
  462. CKeyValueList::AddKeyValue(const char* pKey, IHXBuffer* pStr)
  463. {
  464.     node *pNew  = new node;
  465.     pNew->pNext = NULL;
  466.     pNew->pStr  = pStr;
  467.     pNew->pStr->AddRef();
  468.     pNew->pKey  = new_string(pKey);
  469.     if (m_pTail)
  470.     {
  471. m_pTail->pNext = pNew;
  472.     }
  473.     else
  474.     {
  475. m_pList->m_pHead = pNew;
  476.     }
  477.     m_pTail = pNew;
  478.     return HXR_OK;
  479. }
  480. STDMETHODIMP
  481. CKeyValueList::GetIterOneKey(const char* pKey, REF(IHXKeyValueListIterOneKey*) pIter)
  482. {
  483.     pIter = new CKeyValueListIterOneKey(pKey,m_pList);
  484.     pIter->AddRef();
  485.     return HXR_OK;
  486. }
  487. STDMETHODIMP
  488. CKeyValueList::GetIter(REF(IHXKeyValueListIter*) pIter)
  489. {
  490.     pIter = new CKeyValueListIter(m_pList);
  491.     pIter->AddRef();
  492.     return HXR_OK;
  493. }
  494. STDMETHODIMP 
  495. CKeyValueList::AppendAllListItems(IHXKeyValueList* pList)
  496. {
  497.     IHXKeyValueListIter *pListIter = NULL;
  498.     HX_RESULT rc = pList->GetIter(pListIter);
  499.     if (rc == HXR_OK)
  500.     {
  501. const char* pKey = NULL;
  502. IHXBuffer* pBuffer = NULL;
  503. while (pListIter->GetNextPair(pKey, pBuffer) == HXR_OK)
  504. {
  505.     this->AddKeyValue(pKey,pBuffer);
  506.     HX_RELEASE(pBuffer);
  507. }
  508. HX_RELEASE(pListIter);
  509.     }
  510.     return rc;
  511. }
  512.     
  513. STDMETHODIMP_(BOOL)
  514. CKeyValueList::KeyExists(const char* pKey)
  515. {
  516.     node *p;
  517.     for (p = m_pList->m_pHead; p; p = p->pNext)
  518.     {
  519. if (!strcasecmp(pKey,p->pKey))
  520. {
  521.     return TRUE;
  522. }
  523.     }
  524.     return FALSE;
  525. }
  526. STDMETHODIMP
  527. CKeyValueList::CreateObject(REF(IHXKeyValueList*) pNewList)
  528. {
  529.     pNewList = new CKeyValueList;
  530.     if (pNewList)
  531.     {
  532. pNewList->AddRef();
  533. return HXR_OK;
  534.     }
  535.     else
  536.     {
  537. return HXR_OUTOFMEMORY;
  538.     }
  539. }
  540. STDMETHODIMP 
  541. CKeyValueList::ImportValues(THIS_
  542.     IHXValues* pValues)
  543. {
  544.     HX_RESULT hResult = HXR_OK;
  545.     const char* pName  = NULL;
  546.     IHXBuffer* pBuffer = NULL;
  547.     // Copy all CStrings
  548.     hResult = pValues->GetFirstPropertyCString(pName, pBuffer);
  549.     while (hResult == HXR_OK)
  550.     {
  551. this->AddKeyValue(pName,pBuffer);
  552. HX_RELEASE(pBuffer);
  553. hResult = pValues->GetNextPropertyCString(pName, pBuffer);
  554.     }
  555.     // Copy all ULONGs
  556.     ULONG32 ul;
  557.     hResult = pValues->GetFirstPropertyULONG32(pName, ul);
  558.     while (hResult == HXR_OK)
  559.     {
  560. this->SetPropertyULONG32(pName,ul);
  561. hResult = pValues->GetNextPropertyULONG32(pName, ul);
  562.     }
  563.     // Copy all Buffers
  564.     hResult = pValues->GetFirstPropertyBuffer(pName, pBuffer);
  565.     while (hResult == HXR_OK)
  566.     {
  567. this->SetPropertyBuffer(pName,pBuffer);
  568. HX_RELEASE(pBuffer);
  569. hResult = pValues->GetNextPropertyBuffer(pName, pBuffer);
  570.     }
  571.     return HXR_OK;
  572. }
  573. ////////// Support IHXValues interface for CKeyValueList
  574. STDMETHODIMP
  575. CKeyValueList::SetPropertyULONG32(const char*      pPropertyName,
  576.   ULONG32          uPropertyValue)
  577. {
  578.     return m_UlongMap.SetProperty(pPropertyName,uPropertyValue);
  579. }
  580. STDMETHODIMP
  581. CKeyValueList::GetPropertyULONG32(const char*      pPropertyName,
  582.   REF(ULONG32)     uPropertyName)
  583. {
  584.     return m_UlongMap.GetProperty(pPropertyName,uPropertyName);
  585. }
  586. STDMETHODIMP
  587. CKeyValueList::GetFirstPropertyULONG32(REF(const char*) pPropertyName,
  588.        REF(ULONG32)     uPropertyValue)
  589. {
  590.     return m_UlongMap.GetFirstProperty(pPropertyName, uPropertyValue);
  591. }
  592. STDMETHODIMP
  593. CKeyValueList::GetNextPropertyULONG32(REF(const char*) pPropertyName,
  594.       REF(ULONG32)     uPropertyValue)
  595. {
  596.     return m_UlongMap.GetNextProperty(pPropertyName, uPropertyValue);
  597. }
  598. STDMETHODIMP
  599. CKeyValueList::SetPropertyBuffer(const char*      pPropertyName,
  600.  IHXBuffer*      pPropertyValue)
  601. {
  602.     return m_BufferMap.SetProperty(pPropertyName,pPropertyValue);
  603. }
  604. STDMETHODIMP
  605. CKeyValueList::GetPropertyBuffer(const char*      pPropertyName,
  606.  REF(IHXBuffer*) pPropertyValue)
  607. {
  608.     return m_BufferMap.GetProperty(pPropertyName,pPropertyValue);
  609. }
  610. STDMETHODIMP
  611. CKeyValueList::GetFirstPropertyBuffer(REF(const char*) pPropertyName,
  612.       REF(IHXBuffer*) pPropertyValue)
  613. {
  614.     return m_BufferMap.GetFirstProperty(pPropertyName,pPropertyValue);
  615. }
  616. STDMETHODIMP
  617. CKeyValueList::GetNextPropertyBuffer(REF(const char*) pPropertyName,
  618.      REF(IHXBuffer*) pPropertyValue)
  619. {
  620.     return m_BufferMap.GetNextProperty(pPropertyName,pPropertyValue);
  621. }
  622. STDMETHODIMP
  623. CKeyValueList::SetPropertyCString(const char*      pPropertyName,
  624.   IHXBuffer*      pPropertyValue)
  625. {
  626.     if (!pPropertyValue)
  627.     {
  628. HX_ASSERT(0);
  629. return HXR_FAIL;
  630.     }
  631.     // I am trying to preserve the semantics that Kirk had here.
  632.     // I replace the first instance of the key, if any, or if the
  633.     // key does not exist yet, I simply add to the list.
  634.     node *p;
  635.     for (p = m_pList->m_pHead; p; p = p->pNext)
  636.     {
  637. if (!strcasecmp(pPropertyName,p->pKey))
  638. {
  639.     IHXBuffer* pOldStr = p->pStr;
  640.     p->pStr = pPropertyValue;
  641.     p->pStr->AddRef();
  642.          HX_RELEASE(pOldStr);
  643.     return HXR_OK;
  644. }
  645.     }
  646.     
  647.     return AddKeyValue(pPropertyName,pPropertyValue);
  648. }
  649. STDMETHODIMP 
  650. CKeyValueList::GetPropertyCString(const char*      pPropertyName,
  651.   REF(IHXBuffer*) pPropertyValue)
  652. {
  653.     node *p;
  654.     for (p = m_pList->m_pHead; p; p = p->pNext)
  655.     {
  656. if (!strcasecmp(pPropertyName,p->pKey))
  657. {
  658.     pPropertyValue = p->pStr;
  659.     pPropertyValue->AddRef();
  660.     return HXR_OK;
  661. }
  662.     }
  663.     return HXR_FAIL;
  664. }
  665. STDMETHODIMP
  666. CKeyValueList::GetFirstPropertyCString(REF(const char*) pPropertyName,
  667.        REF(IHXBuffer*) pPropertyValue)
  668. {
  669.     m_NonReentrantIterator.m_pCurr = m_pList->m_pHead;
  670.     if (m_NonReentrantIterator.m_pCurr)
  671.     {
  672. pPropertyName  = m_NonReentrantIterator.m_pCurr->pKey;
  673. pPropertyValue = m_NonReentrantIterator.m_pCurr->pStr;
  674. pPropertyValue->AddRef();
  675. return HXR_OK;
  676.     }
  677.     else
  678.     {
  679. return HXR_FAIL;
  680.     }
  681. }
  682. STDMETHODIMP
  683. CKeyValueList::GetNextPropertyCString(REF(const char*) pPropertyName,
  684.            REF(IHXBuffer*) pPropertyValue)
  685. {
  686.     if (!m_NonReentrantIterator.m_pCurr)
  687.     {
  688. HX_ASSERT(0);
  689. return HXR_UNEXPECTED;
  690.     }
  691.     m_NonReentrantIterator.m_pCurr = m_NonReentrantIterator.m_pCurr->pNext;
  692.     if (m_NonReentrantIterator.m_pCurr)
  693.     {
  694. pPropertyName  = m_NonReentrantIterator.m_pCurr->pKey;
  695. pPropertyValue = m_NonReentrantIterator.m_pCurr->pStr;
  696. pPropertyValue->AddRef();
  697. return HXR_OK;
  698.     }
  699.     else
  700.     {
  701. return HXR_FAIL;
  702.     }
  703. }
  704. /////////  Implement CKeyValueList::list
  705. void CKeyValueList::list::AddRef()
  706. {
  707.     InterlockedIncrement(&m_lRefCount);
  708. }
  709. void CKeyValueList::list::Release()
  710. {
  711.     if (InterlockedDecrement(&m_lRefCount) > 0)
  712.     {
  713. return;
  714.     }
  715.     else
  716.     {
  717.      delete this;
  718.     }
  719. }
  720. CKeyValueList::list::list() : m_pHead(NULL), m_lRefCount(0) 
  721. {
  722. }
  723. CKeyValueList::list::~list()
  724. {
  725.     while (m_pHead)
  726.     {
  727. node *p = m_pHead;
  728. HX_RELEASE(p->pStr);
  729. delete[] p->pKey;
  730. m_pHead = p->pNext;
  731. delete p;
  732.     }
  733.     m_pHead = NULL; // paranoid
  734. }
  735. ///////////// Implement CKeyValueListIter
  736. STDMETHODIMP CKeyValueListIter::QueryInterface(REFIID riid, void** ppvObj)
  737. {
  738.     if (IsEqualIID(riid, IID_IHXKeyValueListIter))
  739.     {
  740. AddRef();
  741. *ppvObj = (IHXKeyValueListIter*)this;
  742. return HXR_OK;
  743.     }
  744.     else if (IsEqualIID(riid, IID_IUnknown))
  745.     {
  746. AddRef();
  747. *ppvObj = this;
  748. return HXR_OK;
  749.     }
  750.     *ppvObj = NULL;
  751.     return HXR_NOINTERFACE;
  752. }
  753. STDMETHODIMP_(ULONG32) CKeyValueListIter::AddRef()
  754. {
  755.     return InterlockedIncrement(&m_lRefCount);
  756. }
  757. STDMETHODIMP_(ULONG32) CKeyValueListIter::Release()
  758. {
  759.     if (InterlockedDecrement(&m_lRefCount) > 0)
  760.     {
  761. return m_lRefCount;
  762.     }
  763.     delete this;
  764.     return 0;
  765. }
  766. CKeyValueListIter::CKeyValueListIter(CKeyValueList::list* pList) 
  767.     : m_pList(pList), 
  768. m_pCurr(NULL),
  769. m_lRefCount(0) 
  770. {
  771.     m_pList->AddRef();
  772. }
  773.     
  774. CKeyValueListIter::~CKeyValueListIter() 
  775. {
  776.     if (m_pList)
  777.     {
  778.         m_pList->Release();
  779.         m_pList = NULL;
  780.     }
  781. }
  782. STDMETHODIMP 
  783. CKeyValueListIter::GetNextPair(REF(const char*) pKey, REF(IHXBuffer*) pStr)
  784. {
  785.     if (m_pCurr == NULL)
  786.     {
  787. m_pCurr = m_pList->m_pHead;
  788.     }
  789.     else
  790.     {
  791. m_pCurr = m_pCurr->pNext;
  792.     }
  793.     if (m_pCurr)
  794.     {
  795. pKey = m_pCurr->pKey;
  796. pStr = m_pCurr->pStr;
  797. pStr->AddRef();
  798. // important -- don't advance m_pCurr till next
  799. // call, or you'll break ReplaceCurr
  800. return HXR_OK;
  801.     }
  802.     else
  803.     {
  804. return HXR_FAILED;
  805.     }
  806. }
  807. STDMETHODIMP 
  808. CKeyValueListIter::ReplaceCurr(IHXBuffer* pStr)
  809. {
  810.     // overwrites string from last call to GetNextPair
  811.     if (!m_pCurr)
  812.     {
  813. HX_ASSERT(0);
  814. return HXR_UNEXPECTED;
  815.     }
  816.     else
  817.     {
  818. IHXBuffer *pOld = m_pCurr->pStr;
  819. m_pCurr->pStr = pStr;
  820. m_pCurr->pStr->AddRef();
  821. HX_RELEASE(pOld);
  822.     }
  823.     return HXR_OK;
  824. }
  825. ////////////////// Implement CKeyValueListIterOneKey
  826. STDMETHODIMP CKeyValueListIterOneKey::QueryInterface(REFIID riid, void** ppvObj)
  827. {
  828.     if (IsEqualIID(riid, IID_IHXKeyValueListIterOneKey))
  829.     {
  830. AddRef();
  831. *ppvObj = (IHXKeyValueListIterOneKey*)this;
  832. return HXR_OK;
  833.     }
  834.     else if (IsEqualIID(riid, IID_IUnknown))
  835.     {
  836. AddRef();
  837. *ppvObj = this;
  838. return HXR_OK;
  839.     }
  840.     *ppvObj = NULL;
  841.     return HXR_NOINTERFACE;
  842. }
  843. STDMETHODIMP_(ULONG32) CKeyValueListIterOneKey::AddRef()
  844. {
  845.     return InterlockedIncrement(&m_lRefCount);
  846. }
  847. STDMETHODIMP_(ULONG32) CKeyValueListIterOneKey::Release()
  848. {
  849.     if (InterlockedDecrement(&m_lRefCount) > 0)
  850.     {
  851. return m_lRefCount;
  852.     }
  853.     delete this;
  854.     return 0;
  855. }
  856. CKeyValueListIterOneKey::CKeyValueListIterOneKey(const char* pKey,
  857.  CKeyValueList::list* pList) 
  858.     : m_pList(pList), 
  859. m_pCurr(pList->m_pHead),
  860. m_pReplace(0),
  861. m_lRefCount(0) 
  862. {
  863.     m_pList->AddRef();
  864.     m_pKey = new_string(pKey);
  865. }
  866.     
  867. CKeyValueListIterOneKey::~CKeyValueListIterOneKey() 
  868. {
  869.     if (m_pList)
  870.     {
  871.         m_pList->Release();
  872.         m_pList = NULL;
  873.     }
  874.     delete[] m_pKey;
  875. }
  876. STDMETHODIMP 
  877. CKeyValueListIterOneKey::GetNextString(REF(IHXBuffer*) pStr)
  878. {
  879.     while (m_pCurr)
  880.     {
  881. if (!strcasecmp(m_pCurr->pKey,m_pKey))
  882. {
  883.     pStr = m_pCurr->pStr;
  884.     pStr->AddRef();
  885.     m_pReplace = m_pCurr;
  886.             m_pCurr = m_pCurr->pNext;
  887.     return HXR_OK;
  888. }
  889. m_pCurr = m_pCurr->pNext;
  890.     }
  891.     return HXR_FAILED;
  892. }
  893. STDMETHODIMP 
  894. CKeyValueListIterOneKey::ReplaceCurr(IHXBuffer* pStr)
  895. {
  896.     // overwrites string from last call to GetNextString
  897.     if (!m_pReplace)
  898.     {
  899. HX_ASSERT(0);
  900. return HXR_UNEXPECTED;
  901.     }
  902.     else
  903.     {
  904. IHXBuffer *pOld = m_pReplace->pStr;
  905. m_pReplace->pStr = pStr;
  906. m_pReplace->pStr->AddRef();
  907. HX_RELEASE(pOld);
  908.     }
  909.     return HXR_OK;
  910. }
  911. ////////////// CHXUniquelyKeyedList
  912. STDMETHODIMP CHXUniquelyKeyedList::QueryInterface(REFIID riid, void** ppvObj)
  913. {
  914. QInterfaceList qiList[] =
  915. {
  916. { GET_IIDHANDLE(IID_IUnknown), this },
  917. { GET_IIDHANDLE(IID_IHXValues), (IHXValues*) this },
  918. { GET_IIDHANDLE(IID_IHXValuesRemove), (IHXValuesRemove*) this },
  919. };
  920.     return QIFind(qiList, QILISTSIZE(qiList), riid, ppvObj);   
  921. }
  922. STDMETHODIMP_(ULONG32) CHXUniquelyKeyedList::AddRef()
  923. {
  924.     return InterlockedIncrement(&m_lRefCount);
  925. }
  926. STDMETHODIMP_(ULONG32) CHXUniquelyKeyedList::Release()
  927. {
  928.     if (InterlockedDecrement(&m_lRefCount) > 0)
  929.     {
  930. return m_lRefCount;
  931.     }
  932.     delete this;
  933.     return 0;
  934. }
  935. CHXUniquelyKeyedList::CHXUniquelyKeyedList() : m_lRefCount(0)
  936. {
  937.     // most members construct themselves
  938. }
  939. CHXUniquelyKeyedList::~CHXUniquelyKeyedList()
  940. {
  941.     // members destruct themselves
  942. }
  943. STDMETHODIMP
  944. CHXUniquelyKeyedList::SetPropertyULONG32(const char*      pPropertyName,
  945.           ULONG32          uPropertyValue)
  946. {
  947.     return m_UlongMap.SetProperty(pPropertyName,uPropertyValue);
  948. }
  949. STDMETHODIMP
  950. CHXUniquelyKeyedList::GetPropertyULONG32(const char*      pPropertyName,
  951.           REF(ULONG32)     uPropertyName)
  952. {
  953.     return m_UlongMap.GetProperty(pPropertyName,uPropertyName);
  954. }
  955. STDMETHODIMP
  956. CHXUniquelyKeyedList::GetFirstPropertyULONG32(REF(const char*) pPropertyName,
  957.                REF(ULONG32)     uPropertyValue)
  958. {
  959.     return m_UlongMap.GetFirstProperty(pPropertyName, uPropertyValue);
  960. }
  961. STDMETHODIMP
  962. CHXUniquelyKeyedList::GetNextPropertyULONG32(REF(const char*) pPropertyName,
  963.               REF(ULONG32)     uPropertyValue)
  964. {
  965.     return m_UlongMap.GetNextProperty(pPropertyName, uPropertyValue);
  966. }
  967. STDMETHODIMP
  968. CHXUniquelyKeyedList::SetPropertyBuffer(const char*      pPropertyName,
  969.          IHXBuffer*      pPropertyValue)
  970. {
  971.     return m_BufferMap.SetProperty(pPropertyName,pPropertyValue);
  972. }
  973. STDMETHODIMP
  974. CHXUniquelyKeyedList::GetPropertyBuffer(const char*      pPropertyName,
  975.          REF(IHXBuffer*) pPropertyValue)
  976. {
  977.     return m_BufferMap.GetProperty(pPropertyName,pPropertyValue);
  978. }
  979. STDMETHODIMP
  980. CHXUniquelyKeyedList::GetFirstPropertyBuffer(REF(const char*) pPropertyName,
  981.                    REF(IHXBuffer*) pPropertyValue)
  982. {
  983.     return m_BufferMap.GetFirstProperty(pPropertyName,pPropertyValue);
  984. }
  985. STDMETHODIMP
  986. CHXUniquelyKeyedList::GetNextPropertyBuffer(REF(const char*) pPropertyName,
  987.              REF(IHXBuffer*) pPropertyValue)
  988. {
  989.     return m_BufferMap.GetNextProperty(pPropertyName,pPropertyValue);
  990. }
  991. STDMETHODIMP
  992. CHXUniquelyKeyedList::SetPropertyCString(const char*      pPropertyName,
  993.          IHXBuffer*      pPropertyValue)
  994. {
  995.     return m_CStringMap.SetProperty(pPropertyName,pPropertyValue);
  996. }
  997. STDMETHODIMP
  998. CHXUniquelyKeyedList::GetPropertyCString(const char*      pPropertyName,
  999.           REF(IHXBuffer*) pPropertyValue)
  1000. {
  1001.     return m_CStringMap.GetProperty(pPropertyName,pPropertyValue);
  1002. }
  1003. STDMETHODIMP
  1004. CHXUniquelyKeyedList::GetFirstPropertyCString(REF(const char*) pPropertyName,
  1005.                    REF(IHXBuffer*) pPropertyValue)
  1006. {
  1007.     return m_CStringMap.GetFirstProperty(pPropertyName,pPropertyValue);
  1008. }
  1009. STDMETHODIMP
  1010. CHXUniquelyKeyedList::GetNextPropertyCString(REF(const char*) pPropertyName,
  1011.               REF(IHXBuffer*) pPropertyValue)
  1012. {
  1013.     return m_CStringMap.GetNextProperty(pPropertyName,pPropertyValue);
  1014. }
  1015. STDMETHODIMP
  1016. CHXUniquelyKeyedList::Remove(const char* pPropertyName)
  1017. {
  1018.     m_UlongMap.Remove(pPropertyName);
  1019.     m_BufferMap.Remove(pPropertyName);
  1020.     m_CStringMap.Remove(pPropertyName);
  1021.     return HXR_OK;
  1022. }
  1023. STDMETHODIMP
  1024. CHXUniquelyKeyedList::RemoveULONG32(const char* pPropertyName)
  1025. {
  1026.     m_UlongMap.Remove(pPropertyName);
  1027.     return HXR_OK;
  1028. }
  1029. STDMETHODIMP
  1030. CHXUniquelyKeyedList::RemoveBuffer(const char* pPropertyName)
  1031. {
  1032.     m_BufferMap.Remove(pPropertyName);
  1033.     return HXR_OK;
  1034. }
  1035. STDMETHODIMP
  1036. CHXUniquelyKeyedList::RemoveCString(const char* pPropertyName)
  1037. {
  1038.     m_CStringMap.Remove(pPropertyName);
  1039.     return HXR_OK;
  1040. }