hxvalues.cpp
上传用户:dangjiwu
上传日期:2013-07-19
资源大小:42019k
文件大小:27k
源码类别:

Symbian

开发平台:

Visual C++

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