pckunpck.cpp
上传用户:zhongxx05
上传日期:2007-06-06
资源大小:33641k
文件大小:55k
源码类别:

Symbian

开发平台:

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. // system
  36. #include "hlxclib/stdarg.h" /* for va_arg */
  37. #include "safestring.h"
  38. #ifndef _SYMBIAN
  39. #include "hlxclib/memory.h"
  40. #endif
  41. #include "hlxclib/string.h"
  42. #include "hlxclib/stdlib.h"
  43. #include "hlxclib/time.h"
  44. // include
  45. #include "hxtypes.h"
  46. #include "hxwintyp.h"
  47. #include "hxcom.h"
  48. #include "hxcomm.h"
  49. // pncont
  50. #include "hxbuffer.h"
  51. #include "chxpckts.h"
  52. #include "rtsputil.h" /* for Base64 utils */
  53. #include "hxslist.h"
  54. #include "pckunpck.h"
  55. /*
  56.  * constants
  57.  */
  58. // ascii string, buffer, pointer, uint, double, flag (BOOL), IHXValues
  59. const char* const kFormatSpecs = "abpudfv";
  60. // these types have implicit "parsability" so we omit the "x:" type specifier
  61. // a string starts with '"', flag is a 'T' or 'F', uint is all decimal digits,
  62. // and an IHXValues begins with '['
  63. const char* const kOptTypes = "afuv";
  64. // chars we need to escape/unescape (note they have 1:1 positioning)
  65. const char* const kScaryChars = ""ntr\";
  66. const char* const kUnScaryChars = ""ntr\"; // these must correspond 1:1
  67. // decimals
  68. const char* const kDecimals = "1234567890";
  69. /*
  70.  * PackBuffer
  71.  *
  72.  * USAGE:
  73.  *
  74.  * IHXBuffer* pBuffer;
  75.  * PackBuffer(pBuffer, "uu", 10, 20);
  76.  * PackBuffer(pBuffer, "a", "foobar");
  77.  * PackBuffer(pBuffer, "aua", 10, "foobar", 20);
  78.  *
  79.  * More advanced: (passing a buffer)
  80.  * IHXBuffer* pTheBuffer;
  81.  * PackBuffer(pBuffer, "uabu", 10, "foobar", pTheBuffer, 20);
  82.  *
  83.  * Still more advanced: (passing an IUnknown)
  84.  * IHXSomeObject* pObj;
  85.  * PackBuffer(pBuffer, "uap", 10, "foobar", (IUnknown*)pObj);
  86.  */
  87. HX_RESULT
  88. PackBuffer(REF(IHXBuffer*) pBuffer, const char* pFormat, ...)
  89. {
  90.     va_list vargs;
  91.     va_start(vargs, pFormat);
  92.     return PackBufferV(pBuffer, pFormat, vargs);
  93. }
  94. HX_RESULT
  95. PackBufferV(REF(IHXBuffer*) pBuffer, const char* pFormat, va_list vargs)
  96. {
  97.     // init the out param
  98.     pBuffer = NULL;
  99.     // automatically fail if we've no CCF or a bad formatter is passed
  100.     if (!pFormat || !*pFormat || !strpbrk(pFormat, kFormatSpecs))
  101.     {
  102. return HXR_FAIL;
  103.     }
  104.     // calculate how much space we'll need for the buffer and
  105.     // make sure the formatter is valid
  106.     UINT32 uBufSize = 1; // null terminator
  107.     CHXStringList packedValuesList;
  108.     va_list vargsOrig;
  109.     va_copy(vargsOrig, vargs);
  110.     const char* pTemp = pFormat;
  111.     while (*pTemp)
  112.     {
  113. switch (*pTemp)
  114. {
  115.     case 'f':
  116.     {
  117. BOOL bFlag = va_arg(vargs, BOOL);
  118. // XXXNH: optimization... we only put one char for a flag/bool
  119. uBufSize += 1;
  120.     }
  121.     break;
  122.     case 'd':
  123.     {
  124. double dVal = va_arg(vargs, double);
  125. // to preserve precision we base64-ize the double
  126. uBufSize += (sizeof(double) * 4) / 3 + 10;
  127.     }
  128.     break;
  129.     
  130.     case 'u':
  131.     {
  132. UINT32 u = va_arg(vargs, UINT32);
  133.                 // Compute number of hex digits in 'u' & add to uBufSize
  134.                 if (u == 0) ++uBufSize;
  135.                 else {
  136.                     UINT32 leadingZeroes = 0;
  137.                     if (u <= 0x0000ffff) {leadingZeroes += 4; u <<= 16;}
  138.                     if (u <= 0x00ffffff) {leadingZeroes += 2; u <<= 8;}
  139.                     if (u <= 0x0fffffff) {leadingZeroes += 1; u <<= 4;}
  140.                     uBufSize += 8 - leadingZeroes;
  141.                 }
  142.     }
  143.     break; 
  144.     
  145.     case 'a':
  146.     {
  147. const char* pStr = va_arg(vargs, const char*);
  148. int nLen = pStr ? strlen(pStr) + 2 : 2; // add on quotation marks
  149. while (pStr && *pStr)
  150. {
  151.     // double-count chars we'll have to escape
  152.     if (strchr(kScaryChars, *pStr))
  153. nLen++;
  154.     
  155.     pStr ++;
  156. }
  157. uBufSize += nLen;
  158.     }
  159.     break;
  160.     case 'b':
  161.     {
  162. IHXBuffer* pBuf = va_arg(vargs, IHXBuffer*);
  163. if (!pBuf)
  164. {
  165.     HX_ASSERT(FALSE);
  166.     return HXR_FAIL;
  167. }
  168. // base64 uses roughly 33% more space, plus a couple extra
  169. uBufSize += (pBuf->GetSize() * 4) / 3 + 10;
  170.     }
  171.     break;
  172.     case 'p':
  173.     {
  174. IUnknown* pPointer = va_arg(vargs, IUnknown*);
  175. uBufSize += 8; // 8 digits for a hex number
  176.     }
  177.     break;
  178.     case 'v':
  179.     {
  180. IHXValues* pValues = va_arg(vargs, IHXValues*);
  181. if (!pValues)
  182. {
  183.     HX_ASSERT(FALSE);
  184.     return HXR_FAIL;
  185. }
  186. CHXString sTemp;
  187. if (FAILED(PackValues(sTemp, pValues)))
  188. {
  189.     HX_ASSERT(FALSE);
  190.     return HXR_FAIL;
  191. }
  192. packedValuesList.AddTailString(sTemp);
  193. uBufSize += sTemp.GetLength();
  194.     }
  195.     break;
  196. }
  197. if (strchr(kOptTypes, *pTemp))
  198.     uBufSize++; // just the delimiter for "optimized" types
  199. else
  200.     uBufSize += 3; // the size of type specifier and delimiter
  201. // next!
  202. pTemp++;
  203.     }
  204.     // now allocate our buffer
  205.     CHXBuffer* pCHXBuffer = new CHXBuffer;
  206.     if (!pCHXBuffer)
  207. return HXR_OUTOFMEMORY;
  208.     pCHXBuffer->AddRef();
  209.     if (SUCCEEDED(pCHXBuffer->SetSize(uBufSize)))
  210.     {
  211. pBuffer = (IHXBuffer*)pCHXBuffer;
  212.     }
  213.     else
  214.     {
  215. HX_RELEASE(pCHXBuffer);
  216. return HXR_OUTOFMEMORY;
  217.     }
  218.     // now pack the args into our buffer
  219.     char* pBufStr = (char*)pBuffer->GetBuffer();
  220.     
  221.     vargs = vargsOrig;
  222.     pTemp = pFormat;
  223.     while (*pTemp)
  224.     {
  225. // XXXNH: space optimization: omit the type & ':' for certain types
  226. if (strchr(kOptTypes, *pTemp) == NULL)
  227. {
  228.     // start the param
  229.     *pBufStr = *pTemp; // append the type
  230.     pBufStr++;
  231.     *pBufStr = ':'; // and a delimiter
  232.     pBufStr++;
  233. }
  234. // then format the data
  235. switch (*pTemp)
  236. {
  237.     case 'f':
  238.     {
  239. BOOL bFlag = va_arg(vargs, BOOL);
  240. *pBufStr = bFlag ? 'T' : 'F';
  241. pBufStr++;
  242.     }
  243.     break;
  244.     case 'd':
  245.     {
  246. double dVal = va_arg(vargs, double);
  247. UINT32 uSize = (sizeof(double) * 4) / 3 + 10;
  248. int nLen = BinTo64((UCHAR*)&dVal, sizeof(double), pBufStr);
  249. HX_ASSERT(nLen >= 0);
  250. pBufStr += nLen-1; // -1 because of null terminator
  251.     }
  252.     break;
  253.     
  254.     case 'u':
  255.     {
  256. UINT32 u = va_arg(vargs, UINT32);
  257. char pNum[16]; /* Flawfinder: ignore */
  258. SafeSprintf(pNum, sizeof(pNum), "%x", u);
  259. *pBufStr = '';
  260. strcat(pBufStr, pNum); /* Flawfinder: ignore */
  261. pBufStr += strlen(pNum);
  262.     }
  263.     break; 
  264.     
  265.     case 'a':
  266.     {
  267. *pBufStr = '"'; // begin quote
  268. pBufStr++;
  269. const char* pStr = va_arg(vargs, const char*);
  270. while (pStr && *pStr)
  271. {
  272.     // double-count chars we'll have to escape
  273.     const char* pScary = strchr(kScaryChars, *pStr);
  274.     if (pScary)
  275.     {
  276. *pBufStr = '\';
  277. pBufStr++;
  278. *pBufStr = kUnScaryChars[pScary - kScaryChars];
  279. pBufStr++;
  280.     }
  281.     else
  282.     {
  283. *pBufStr = *pStr;
  284. pBufStr++;
  285.     }
  286.     pStr++;
  287. }
  288. *pBufStr = '"'; // end quote
  289. pBufStr++;
  290.     }
  291.     break;
  292.     case 'b':
  293.     {
  294. IHXBuffer* pBuf = va_arg(vargs, IHXBuffer*);
  295. if (!pBuf)
  296. {
  297.     HX_ASSERT(FALSE);
  298.     return HXR_FAIL;
  299. }
  300. // base64 uses roughly 33% more space, plus a couple extra
  301. UINT32 uSize = pBuf->GetSize();
  302. int nLen = BinTo64(pBuf->GetBuffer(), uSize, pBufStr);
  303. HX_ASSERT(nLen >= 0);
  304. pBufStr += nLen-1; // -1 because of null terminator
  305.     }
  306.     break;
  307.     case 'p':
  308.     {
  309. IUnknown* pUnknown = va_arg(vargs, IUnknown*);
  310. char pPointer[9]; /* Flawfinder: ignore */
  311. SafeSprintf(pPointer, sizeof(pPointer), "%08x", pUnknown);
  312. *pBufStr = '';
  313. strcat(pBufStr, pPointer); /* Flawfinder: ignore */
  314. pBufStr += 8;
  315.     }
  316.     break;
  317.     case 'v':
  318.     {
  319. IHXValues* pIgnoreMe = va_arg(vargs, IHXValues*);
  320. LISTPOSITION p = packedValuesList.GetHeadPosition();
  321. CHXString* psPacked = packedValuesList.GetNext(p);
  322. *pBufStr = '';
  323. strcat(pBufStr, *psPacked); /* Flawfinder: ignore */
  324. pBufStr += psPacked->GetLength();
  325. packedValuesList.RemoveHeadString();
  326.     }
  327.     break;
  328. }
  329. // end the param
  330. *pBufStr = ';';
  331. pBufStr++;
  332. // go to the next formatter
  333. pTemp++;
  334.     }
  335.     // null terminate!
  336.     *pBufStr = '';
  337.     pBufStr++;
  338.     
  339. #ifdef _DEBUG
  340.     // XXXNH: some sanity checking
  341.     pBufStr -= uBufSize;
  342.     if (pBufStr > (char*)(pBuffer->GetBuffer()))
  343.     {
  344. // XXXNH: we wrote past the end of the buffer!!!!!  We must have
  345. // miscalculated the space needed...
  346. HX_ASSERT(FALSE);
  347. HX_RELEASE(pBuffer);
  348. return HXR_FAIL;
  349.     }
  350. #endif
  351.     
  352.     return HXR_OK;
  353. }
  354. /*
  355.  * UnpackBuffer
  356.  *
  357.  * works like PackBuffer & sscanf.
  358.  */
  359. int
  360. UnpackBuffer(REF(const char*) pBuffer, const char* pFormat, ...)
  361. {
  362.     va_list vargs;
  363.     va_start(vargs, pFormat);
  364.     return UnpackBufferV(pBuffer, pFormat, vargs);
  365. }
  366.   
  367. int
  368. UnpackBufferV(REF(const char*) pBufStr, const char* pFormat, va_list vargs)
  369. {
  370.     // automatically fail if we've no CCF or a bad formatter is passed
  371.     if (!pFormat || !*pFormat || !strpbrk(pFormat, kFormatSpecs))
  372. return -1;
  373.     if (!pBufStr)
  374. return 0;
  375.     // iterate through the args and unpack them from the buffer
  376.     int nRead = 0;
  377.     const char* pTemp = pFormat;
  378.     while (*pTemp)
  379.     {
  380. // XXXNH: space optimization: omit the type & ':' for certain types
  381. if (!strchr(kOptTypes, *pTemp))
  382. {
  383.     // make sure the types match
  384.     if (*pTemp != *pBufStr)
  385. return nRead;
  386.     pBufStr++;
  387.     // read the type/value delimiter
  388.     if (*pBufStr != ':')
  389. return nRead;
  390.     pBufStr++;
  391. }
  392. switch (*pTemp)
  393. {
  394.     case 'f':
  395.     {
  396. // XXXNH: optimization... we only put one char for a flag/bool
  397. BOOL* pbFlag = va_arg(vargs, BOOL*);
  398. if (*pBufStr == 'T')
  399.     *pbFlag = TRUE;
  400. else
  401.     *pbFlag = FALSE;
  402. pBufStr++;
  403.     }
  404.     break;
  405.     case 'd':
  406.     {
  407. double* pdVal = va_arg(vargs, double*);
  408. const char* pEnd = strchr(pBufStr, ';');
  409. if (pEnd)
  410. {
  411.     int nSize = pEnd - pBufStr;
  412.     int nLen = BinFrom64(pBufStr, nSize, (UCHAR*)pdVal);
  413.     HX_ASSERT(nLen == sizeof(double));
  414.     pBufStr = pEnd;
  415. }
  416. else
  417.     return nRead; // couldn't parse the end of the buffer
  418.     }
  419.     break;
  420.     case 'u':
  421.     {
  422. UINT32* puInt = va_arg(vargs, UINT32*);
  423.                 // XXXSAB Untested...
  424.                 char* pEnd = NULL;
  425.                 unsigned long val = strtoul(pBufStr, &pEnd, 16);
  426. // if (sscanf(pBufStr, "%x", puInt) == 1)
  427.                 if (pEnd && pEnd > pBufStr)
  428. {
  429.     // advance to the next delimiter
  430.     pBufStr = strchr(pBufStr, ';');
  431. }
  432. else
  433.     return nRead; // couldn't parse an int!
  434.     }
  435.     break;
  436.     
  437.     case 'a':
  438.     {
  439. CHXString* pTemp = va_arg(vargs, CHXString*);
  440. HX_ASSERT(pTemp);
  441. if (!pTemp)
  442.     return nRead; // invalid CHXString*?
  443. pTemp->Empty();
  444. // read the begin quote
  445. if (*pBufStr != '"')
  446.     return nRead;
  447. pBufStr++;
  448. // read till we run out of buffer OR hit the end quote
  449. BOOL bEscaped = FALSE;
  450. while (*pBufStr && (bEscaped || *pBufStr != '"'))
  451. {
  452.     if (bEscaped)
  453.     {
  454. const char* pScary = strchr(kUnScaryChars, *pBufStr);
  455. HX_ASSERT(pScary);
  456. if (pScary)
  457. {
  458.     *pTemp += kScaryChars[pScary - kUnScaryChars];
  459. }
  460.     }
  461.     else
  462.     {
  463. if (*pBufStr == '\')
  464. {
  465.     bEscaped = TRUE;
  466. }
  467. else
  468. {
  469.     *pTemp += *pBufStr;
  470. }
  471.     }
  472.     pBufStr++;
  473. }
  474. // read the end quote!
  475. if (*pBufStr != '"')
  476.     return nRead;
  477. pBufStr++;
  478.     }
  479.     break;
  480.     case 'b':
  481.     {
  482. IHXBuffer** ppBuf = va_arg(vargs, IHXBuffer**);
  483. HX_ASSERT(ppBuf);
  484. if (!ppBuf)
  485.     return nRead;
  486. CHXBuffer* pCHXBuffer = new CHXBuffer;
  487. if (!pCHXBuffer)
  488.     return nRead;
  489. pCHXBuffer->AddRef();
  490. *ppBuf = (IHXBuffer*)pCHXBuffer;
  491. HX_RESULT res = HXR_FAIL;
  492. const char* pEnd = strchr(pBufStr, ';');
  493. if (pEnd)
  494. {
  495.     UINT32 uSize = pEnd - pBufStr;
  496.     CHXString sTemp(pBufStr, uSize);
  497.     uSize = (uSize * 3) / 4; // we need 75% the space
  498.     
  499.     res = (*ppBuf)->SetSize(uSize);
  500.     if (SUCCEEDED(res))
  501.     {
  502. UCHAR* pDecodeBuf = (*ppBuf)->GetBuffer();
  503. HX_ASSERT(pDecodeBuf);
  504. UINT32 nLen = BinFrom64(sTemp,
  505.                                                 sTemp.GetLength()+1,
  506.                                                 pDecodeBuf);
  507. HX_ASSERT(nLen <= uSize);
  508. (*ppBuf)->SetSize(nLen);
  509. // go the the end of the buffer
  510. pBufStr = pEnd;
  511.     }
  512. }
  513. if (FAILED(res))
  514. {
  515.     HX_RELEASE(*ppBuf);
  516.     return nRead;
  517. }
  518.     }
  519.     break;
  520.     case 'p':
  521.     {
  522. IUnknown** ppUnk = va_arg(vargs, IUnknown**);
  523. HX_ASSERT(ppUnk);
  524. if (!ppUnk)
  525.     return nRead;
  526.                 // XXXSAB untested...
  527.                 char* pEnd = NULL;
  528.                 char tmpBuf[9];
  529.                 SafeStrCpy(tmpBuf, pBufStr, 8);
  530.                 tmpBuf[9] = 0;
  531.                 unsigned long val = strtoul(tmpBuf, &pEnd, 16);
  532. // if (sscanf(pBufStr, "%08x", ppUnk) != 1)
  533.                 if (pEnd && pEnd > tmpBuf)
  534. {
  535.     *ppUnk = NULL;
  536.     return nRead;
  537. }
  538. pBufStr = strchr(pBufStr, ';');
  539.     }
  540.     break;
  541.     case 'v':
  542.     {
  543. IHXValues** ppValues = va_arg(vargs, IHXValues**);
  544. if (!ppValues)
  545. {
  546.     HX_ASSERT(FALSE);
  547.     return nRead;
  548. }
  549. if (FAILED(UnpackValues(pBufStr, *ppValues)))
  550. {
  551.     HX_RELEASE(*ppValues);
  552.     return nRead;
  553. }
  554.     }
  555.     break;
  556. }
  557. // mark another param read
  558. nRead++;
  559. // find the next delimiter
  560. if (!pBufStr || *pBufStr != ';')
  561.     return nRead;
  562. pBufStr++;
  563. pTemp++;
  564.     }
  565.     
  566.     return nRead;
  567. }
  568. HX_RESULT
  569. PackValues(REF(CHXString) sBuffer, IHXValues* pValues)
  570. {
  571.     if (!pValues)
  572. return HXR_FAIL;
  573.     
  574.     sBuffer = '[';
  575.     
  576.     ULONG32 uVal = 0;
  577.     const char* pName = NULL;
  578.     HX_RESULT res = pValues->GetFirstPropertyULONG32(pName, uVal);
  579.     while (SUCCEEDED(res))
  580.     {
  581. sBuffer += pName;
  582. sBuffer += '=';
  583. sBuffer.AppendULONG(uVal);
  584. sBuffer += ',';
  585. res = pValues->GetNextPropertyULONG32(pName, uVal);
  586.     }
  587.     IHXBuffer* pValBuf = NULL;
  588.     res = pValues->GetFirstPropertyCString(pName, pValBuf);
  589.     while (SUCCEEDED(res))
  590.     {
  591. sBuffer += pName;
  592. sBuffer += "="";
  593. const char* pStr = (const char*)pValBuf->GetBuffer();
  594. while (*pStr)
  595. {
  596.     // double-count chars we'll have to escape
  597.     const char* pScary = strchr(kScaryChars, *pStr);
  598.     if (pScary)
  599.     {
  600. sBuffer += '\';
  601. sBuffer += kUnScaryChars[pScary - kScaryChars];
  602.     }
  603.     else
  604.     {
  605. sBuffer += *pStr;
  606.     }
  607.     pStr++;
  608. }
  609. sBuffer += "",";
  610. HX_RELEASE(pValBuf);
  611. res = pValues->GetNextPropertyCString(pName, pValBuf);
  612.     }
  613.     res = pValues->GetFirstPropertyBuffer(pName, pValBuf);
  614.     while (SUCCEEDED(res))
  615.     {
  616. sBuffer += pName;
  617. sBuffer += '=';
  618. CHXString sTemp;
  619. UINT32 uSize = (pValBuf->GetSize() * 4) / 3 + 10;
  620. char* pTemp = (char*)sTemp.GetBuffer(uSize);
  621. if (pTemp)
  622. {
  623. //     int nLen = BinTo64(pValBuf->GetBuffer(), uSize, pTemp);
  624.     int nLen = BinTo64(pValBuf->GetBuffer(), pValBuf->GetSize(), pTemp);
  625.     sTemp.ReleaseBuffer();
  626.     
  627.     HX_ASSERT(nLen >= 0);
  628. }
  629. HX_RELEASE(pValBuf);
  630. sBuffer += sTemp;
  631. sBuffer += ',';
  632. res = pValues->GetNextPropertyBuffer(pName, pValBuf);
  633.     }
  634.     UINT32 uSize = sBuffer.GetLength();
  635.     sBuffer.SetAt(uSize-1, ']');
  636.     return HXR_OK;
  637. }
  638. HX_RESULT
  639. Bufferize(REF(IHXBuffer*) pBuffer, void* pData, UINT32 uSize)
  640. {
  641.     CHXBuffer* pCHXBuffer = new CHXBuffer;
  642.     if (!pCHXBuffer)
  643. return HXR_OUTOFMEMORY;
  644.     pCHXBuffer->AddRef();
  645.     HX_RESULT res = pCHXBuffer->Set((UCHAR*)pData, uSize);
  646.     if (SUCCEEDED(res))
  647.     {
  648. pBuffer = (IHXBuffer*)pCHXBuffer;
  649.     }
  650.     else
  651.     {
  652. HX_RELEASE(pCHXBuffer);
  653.     }
  654.     
  655.     return res;
  656. }
  657. HX_RESULT
  658. UnpackValues(REF(const char*) pBuffer, REF(IHXValues*) pValues,
  659.              BOOL bCreateValues)
  660. {
  661.     HX_ASSERT(pBuffer);
  662.     if (!pBuffer)
  663. return HXR_POINTER;
  664.     
  665.     if (*pBuffer != '[')
  666. return HXR_FAIL;
  667.     if (bCreateValues)
  668.     {
  669.         CHXHeader* pCHXHeader = new CHXHeader;
  670.         if (!pCHXHeader)
  671.     return HXR_OUTOFMEMORY;
  672.         pCHXHeader->AddRef();
  673.         pValues = (IHXValues*)pCHXHeader;
  674.     }
  675.     else
  676.     {
  677.         // The input said to NOT create the IHXValues,
  678.         // but use the passed-in one, so if we don't
  679.         // *have* a passed-in one, then that's an error.
  680.         if (!pValues)
  681.         {
  682.             return HXR_FAIL;
  683.         }
  684.     }
  685.     // eat the '['
  686.     pBuffer++;
  687.     HX_RESULT res = HXR_FAIL;
  688.     while (*pBuffer)
  689.     {
  690. res = HXR_FAIL;
  691. // find the end of the property name
  692. const char* pEnd = strchr(pBuffer, '=');
  693. HX_ASSERT(pEnd);
  694. if (!pEnd)
  695.     break;
  696. // parse the name
  697. CHXString sName(pBuffer, pEnd - pBuffer);
  698. pBuffer = pEnd+1;
  699. if (*pBuffer == '"')
  700. {
  701.     pBuffer++;
  702.     // looks like a string
  703.     CHXString sValue;
  704.     
  705.     BOOL bEscaped = FALSE;
  706.     while (*pBuffer != '"' && !bEscaped && *pBuffer)
  707.     {
  708. if (bEscaped)
  709. {
  710.     const char* pScary = strchr(kUnScaryChars, *pBuffer);
  711.     HX_ASSERT(pScary);
  712.     if (pScary)
  713.     {
  714. sValue += kScaryChars[pScary - kUnScaryChars];
  715.     }
  716. }
  717. else
  718. {
  719.     if (*pBuffer == '\')
  720.     {
  721. bEscaped = TRUE;
  722.     }
  723.     else
  724.     {
  725. sValue += *pBuffer;
  726.     }
  727. }
  728. pBuffer++;
  729.     }
  730.     
  731.     // read the end quote!
  732.     if (*pBuffer == '"')
  733.     {
  734. pBuffer++;
  735. IHXBuffer* pStrBuf = NULL;
  736. res = Bufferize(pStrBuf,
  737. (void*)(const char*)sValue,
  738. sValue.GetLength()+1);
  739. if (SUCCEEDED(res))
  740. {
  741.     res = pValues->SetPropertyCString(sName, pStrBuf);
  742.     HX_RELEASE(pStrBuf);
  743. }
  744.     }
  745. }
  746. else
  747. {
  748.     // is it an int or base64 buffer?
  749.     // how many digits do we have?
  750.     size_t sz = strspn(pBuffer, kDecimals);
  751.     
  752.     // where does the next property begin?
  753.     pEnd = strpbrk(pBuffer, ",]");
  754.     HX_ASSERT(pEnd);
  755.     if (!pEnd)
  756. break;
  757.     // so were there *only* decimal digits?
  758.     if (pBuffer + sz == pEnd)
  759.     {
  760. CHXString sNumber(pBuffer, sz);
  761.                 ULONG32 uValue = strtoul((const char*) sNumber, NULL, 10);
  762. res = pValues->SetPropertyULONG32(sName, uValue);
  763.     }
  764.     else
  765.     {
  766. // nope-- looks like a base64 buffer
  767. UINT32 uSize = pEnd - pBuffer;
  768. UINT32 uBinSize = (uSize * 3) / 4 + 10;
  769. res = HXR_OUTOFMEMORY;
  770. CHXBuffer* pTempBuf = new CHXBuffer;
  771. if (!pTempBuf)
  772.     break;
  773. pTempBuf->AddRef();
  774. res = pTempBuf->SetSize(uBinSize);
  775. if (SUCCEEDED(res))
  776. {
  777.     UCHAR* pTemp = pTempBuf->GetBuffer();
  778.     UINT32 nLen = BinFrom64(pBuffer, uSize, pTemp);
  779.     HX_ASSERT(nLen <= uBinSize && nLen > 0);
  780.     pTempBuf->SetSize(nLen);
  781.     res = pValues->SetPropertyBuffer(sName, pTempBuf);
  782. }
  783. HX_RELEASE(pTempBuf);
  784.     }
  785.     // advance to the end
  786.     pBuffer = pEnd;
  787. }
  788. // did we fail during the property parsing?
  789. if (FAILED(res))
  790.     break;
  791. // are we done?
  792. if (*pBuffer == ']')
  793. {
  794.     pBuffer++;
  795.     break;
  796. }
  797. // ready for next?
  798. if (*pBuffer != ',')
  799. {
  800.     res = HXR_FAIL;
  801.     break;
  802. }
  803. pBuffer++;
  804.     }
  805.     if (FAILED(res))
  806. HX_RELEASE(pValues);
  807.     return res;
  808. }
  809. #ifdef _DEBUG
  810. void
  811. TestBufferPacking()
  812. {
  813.     IHXBuffer* pParams = NULL;
  814.     HX_RESULT res = PackBuffer(pParams, "uuuuuu", 0, 1, 2, 3, 4, 5);
  815.     HX_ASSERT(SUCCEEDED(res));
  816.     if (SUCCEEDED(res))
  817.     {
  818. int nums[6];
  819. const char* pTemp = (const char*)pParams->GetBuffer();
  820. int nCount = UnpackBuffer(pTemp, "uuuuuu", nums, nums+1, nums+2, nums+3, nums+4, nums+5);
  821. HX_ASSERT(nCount == 6);
  822. HX_ASSERT(*pTemp == '');
  823. for (int i = 0; i < 6; i++)
  824. {
  825.     HX_ASSERT(nums[i] == i);
  826. }
  827. HX_RELEASE(pParams);
  828.     }
  829.     res = PackBuffer(pParams, "uauau", 10, "foo", 20, "bar", 50);
  830.     HX_ASSERT(SUCCEEDED(res));
  831.     if (SUCCEEDED(res))
  832.     {
  833. CHXString sArg2, sArg4;
  834. UINT32 nArg1, nArg3, nArg5;
  835. const char* pTemp = (const char*)pParams->GetBuffer();
  836. int nCount = UnpackBuffer(pTemp, "uauau", &nArg1, &sArg2, &nArg3, &sArg4, &nArg5);
  837. HX_ASSERT(nCount == 5);
  838. HX_ASSERT(*pTemp == '');
  839. HX_ASSERT(nArg1 == 10 && nArg3 == 20 && nArg5 == 50);
  840. HX_ASSERT(sArg2 == "foo" && sArg4 == "bar");
  841. HX_RELEASE(pParams);
  842.     }
  843.     res = PackBuffer(pParams, "fuda", TRUE, 666, 12.3456789, "foobar");
  844.     HX_ASSERT(SUCCEEDED(res));
  845.     if (SUCCEEDED(res))
  846.     {
  847. BOOL bArg1;
  848. UINT32 nArg2;
  849. double dArg3;
  850. CHXString sArg4;
  851. const char* pTemp = (const char*)pParams->GetBuffer();
  852. int nCount = UnpackBuffer(pTemp, "fuda", &bArg1, &nArg2, &dArg3, &sArg4);
  853. HX_ASSERT(nCount == 4);
  854. HX_ASSERT(*pTemp == '');
  855. HX_ASSERT(bArg1 == TRUE && nArg2 == 666 && dArg3 == 12.3456789);
  856. HX_ASSERT(sArg4 == "foobar");
  857. HX_RELEASE(pParams);
  858.     }
  859.     CHXBuffer* pTempBuf = new CHXBuffer;
  860.     HX_ASSERT(pTempBuf);
  861.     if (pTempBuf)
  862.     {
  863. HX_ADDREF(pTempBuf);
  864. res = pTempBuf->SetSize(4096);
  865. HX_ASSERT(SUCCEEDED(res));
  866. if (SUCCEEDED(res))
  867. {
  868.     // fill up the buffer
  869.     UCHAR* pData = pTempBuf->GetBuffer();
  870.     int i;
  871.     for (i = 0; i < 4096; i++)
  872.     {
  873. pData[i] = i & 0xff;
  874.     }
  875.     
  876.     res = PackBuffer(pParams, "ufbau", 69, FALSE, pTempBuf, "foobar", 666);
  877.     HX_ASSERT(SUCCEEDED(res));
  878.     if (SUCCEEDED(res))
  879.     {
  880. UINT32 nArg1, nArg5;
  881. BOOL bArg2;
  882. IHXBuffer* pArg3;
  883. CHXString sArg4;
  884. const char* pTemp = (const char*)pParams->GetBuffer();
  885. int nCount = UnpackBuffer(pTemp, "ufbau", &nArg1, &bArg2, &pArg3, &sArg4, &nArg5);
  886. HX_ASSERT(nCount == 5);
  887. HX_ASSERT(*pTemp == '');
  888. HX_ASSERT(nArg1 == 69 && bArg2 == FALSE && nArg5 == 666);
  889. HX_ASSERT(sArg4 == "foobar");
  890. HX_ASSERT(pArg3 && pArg3->GetSize() == 4096);
  891. if (pArg3 && pArg3->GetSize() == 4096)
  892. {
  893.     pData = pArg3->GetBuffer();
  894.     for (i = 0; i < 4096; i++)
  895.     {
  896. HX_ASSERT(pData[i] == (i & 0xff));
  897.     }
  898. }
  899. HX_RELEASE(pArg3);
  900.     }
  901. }
  902. HX_RELEASE(pTempBuf);
  903.     }
  904. }
  905. #endif
  906. UINT32 GetBinaryPackedSize(IHXValues* pValues)
  907. {
  908.     UINT32 ulRet = 0;
  909.     if (pValues)
  910.     {
  911.         // Run through the ULONG32 properties
  912.         const char* pszName = NULL;
  913.         UINT32      ulValue = 0;
  914.         HX_RESULT rv = pValues->GetFirstPropertyULONG32(pszName, ulValue);
  915.         while (SUCCEEDED(rv))
  916.         {
  917.             // Add size of name/value type character: 'u'
  918.             ulRet += 1;
  919.             // Add size of name string plus NULL terminator
  920.             ulRet += (UINT32) strlen(pszName) + 1;
  921.             // Add 4 bytes for packing ULONG32
  922.             ulRet += 4;
  923.             // Get next ULONG32 prop
  924.             rv = pValues->GetNextPropertyULONG32(pszName, ulValue);
  925.         }
  926.         // Run through the CString properties
  927.         IHXBuffer* pValue = NULL;
  928.         rv = pValues->GetFirstPropertyCString(pszName, pValue);
  929.         while (SUCCEEDED(rv))
  930.         {
  931.             // Add size of name/value type character: 'c'
  932.             ulRet += 1;
  933.             // Add size of name string plus NULL terminator
  934.             ulRet += (UINT32) strlen(pszName) + 1;
  935.             // Add size of value string plus NULL terminator
  936.             ulRet += strlen((const char*) pValue->GetBuffer()) + 1;
  937.             // Get next CString prop
  938.             HX_RELEASE(pValue);
  939.             rv = pValues->GetNextPropertyCString(pszName, pValue);
  940.         }
  941.         // Run through the Buffer properties
  942.         rv = pValues->GetFirstPropertyBuffer(pszName, pValue);
  943.         while (SUCCEEDED(rv))
  944.         {
  945.             // Add size of name/value type character: 'b'
  946.             ulRet += 1;
  947.             // Add size of name string plus NULL terminator
  948.             ulRet += (UINT32) strlen(pszName) + 1;
  949.             // Add size of value buffer size (4 bytes)
  950.             ulRet += 4;
  951.             // Add size of value buffer
  952.             ulRet += pValue->GetSize();
  953.             // Get next Buffer prop
  954.             HX_RELEASE(pValue);
  955.             rv = pValues->GetNextPropertyBuffer(pszName, pValue);
  956.         }
  957.     }
  958.     return ulRet;
  959. }
  960. HX_RESULT PackValuesBinary(IHXBuffer* pBuffer,
  961.                            IHXValues* pValues)
  962. {
  963.     HX_RESULT retVal = HXR_FAIL;
  964.     if (pValues && pBuffer)
  965.     {
  966.         // Make sure the buffer is big enough
  967.         UINT32 ulMinSize = GetBinaryPackedSize(pValues);
  968.         // Is our buffer big enough?
  969.         if (ulMinSize && pBuffer->GetSize() >= ulMinSize)
  970.         {
  971.             // Ok, pack that puppy
  972.             BYTE* pBuf = pBuffer->GetBuffer();
  973.             if (pBuf)
  974.             {
  975.                 // Clear the return value
  976.                 retVal = HXR_OK;
  977.                 // Run through the ULONG32 properties
  978.                 const char* pszName = NULL;
  979.                 UINT32      ulValue = 0;
  980.                 HX_RESULT rv = pValues->GetFirstPropertyULONG32(pszName, ulValue);
  981.                 while (SUCCEEDED(rv))
  982.                 {
  983.                     // Copy name/value type character: 'u'
  984.                     *pBuf++ = (BYTE) 'u';
  985.                     // Copy name string plus NULL terminator
  986.                     UINT32 ulBytes = (UINT32) strlen(pszName) + 1;
  987.                     memcpy(pBuf, pszName, ulBytes);
  988.                     pBuf += ulBytes;
  989.                     // Copy ULONG32 in big-endian format (high byte first)
  990.                     *pBuf++ = (BYTE) ((ulValue >> 24) & 0x000000FF);
  991.                     *pBuf++ = (BYTE) ((ulValue >> 16) & 0x000000FF);
  992.                     *pBuf++ = (BYTE) ((ulValue >>  8) & 0x000000FF);
  993.                     *pBuf++ = (BYTE) ( ulValue        & 0x000000FF);
  994.                     // Get next ULONG32 prop
  995.                     rv = pValues->GetNextPropertyULONG32(pszName, ulValue);
  996.                 }
  997.                 // Run through the CString properties
  998.                 IHXBuffer* pValue = NULL;
  999.                 rv = pValues->GetFirstPropertyCString(pszName, pValue);
  1000.                 while (SUCCEEDED(rv))
  1001.                 {
  1002.                     // Copy name/value type character: 'c'
  1003.                     *pBuf++ = (BYTE) 'c';
  1004.                     // Copy name string plus NULL terminator
  1005.                     UINT32 ulBytes = (UINT32) strlen(pszName) + 1;
  1006.                     memcpy(pBuf, pszName, ulBytes);
  1007.                     pBuf += ulBytes;
  1008.                     // Copy value string plus NULL terminator
  1009.                     const char* pszValue = (const char*) pValue->GetBuffer();
  1010.                     ulBytes = (UINT32) strlen(pszValue) + 1;
  1011.                     memcpy(pBuf, pszValue, ulBytes);
  1012.                     pBuf += ulBytes;
  1013.                     // Get next CString prop
  1014.                     HX_RELEASE(pValue);
  1015.                     rv = pValues->GetNextPropertyCString(pszName, pValue);
  1016.                 }
  1017.                 // Run through the Buffer properties
  1018.                 rv = pValues->GetFirstPropertyBuffer(pszName, pValue);
  1019.                 while (SUCCEEDED(rv))
  1020.                 {
  1021.                     // Copy name/value type character: 'b'
  1022.                     *pBuf++ = (BYTE) 'b';
  1023.                     // Copy name string plus NULL terminator
  1024.                     UINT32 ulBytes = (UINT32) strlen(pszName) + 1;
  1025.                     memcpy(pBuf, pszName, ulBytes);
  1026.                     pBuf += ulBytes;
  1027.                     // Copy value buffer size in big-endian format
  1028.                     UINT32 ulSize = pValue->GetSize();
  1029.                     *pBuf++ = (BYTE) ((ulSize >> 24) & 0x000000FF);
  1030.                     *pBuf++ = (BYTE) ((ulSize >> 16) & 0x000000FF);
  1031.                     *pBuf++ = (BYTE) ((ulSize >>  8) & 0x000000FF);
  1032.                     *pBuf++ = (BYTE) ( ulSize        & 0x000000FF);
  1033.                     // Copy value buffer
  1034.                     memcpy(pBuf, pValue->GetBuffer(), ulSize);
  1035.                     pBuf += ulSize;
  1036.                     // Get next Buffer prop
  1037.                     HX_RELEASE(pValue);
  1038.                     rv = pValues->GetNextPropertyBuffer(pszName, pValue);
  1039.                 }
  1040.             }
  1041.         }
  1042.     }
  1043.     return retVal;
  1044. }
  1045. HX_RESULT CreateBuffer(REF(IHXBuffer*) rpBuffer,
  1046.                        IUnknown*        pContext)
  1047. {
  1048.     HX_RESULT retVal = HXR_FAIL;
  1049.     // Were we given a context?
  1050.     if (pContext)
  1051.     {
  1052.         // Yes, we have a context, use it to create the buffer
  1053.         //
  1054.         // Get the CCF
  1055.         IHXCommonClassFactory* pCCF = NULL;
  1056.         retVal = pContext->QueryInterface(IID_IHXCommonClassFactory,
  1057.                                           (void**) &pCCF);
  1058.         if (SUCCEEDED(retVal))
  1059.         {
  1060.             // Create a buffer
  1061.             HX_RELEASE(rpBuffer);
  1062.             retVal = pCCF->CreateInstance(CLSID_IHXBuffer,
  1063.                                           (void**) &rpBuffer);
  1064.         }
  1065.         HX_RELEASE(pCCF);
  1066.     }
  1067.     else
  1068.     {
  1069.         // No, we don't have a context, so use CHXBuffer
  1070.         CHXBuffer* pBuffer = new CHXBuffer();
  1071.         if (pBuffer)
  1072.         {
  1073.             // Assign the out parameter
  1074.             HX_RELEASE(rpBuffer);
  1075.             rpBuffer = (IHXBuffer*) pBuffer;
  1076.             rpBuffer->AddRef();
  1077.             // Clear the return value
  1078.             retVal = HXR_OK;
  1079.         }
  1080.     }
  1081.     return retVal;
  1082. }
  1083. HX_RESULT CreateValues(REF(IHXValues*) rpValues,
  1084.                        IUnknown*        pContext)
  1085. {
  1086.     HX_RESULT retVal = HXR_FAIL;
  1087.     // Were we given a context?
  1088.     if (pContext)
  1089.     {
  1090.         // Yes, we have a context, use it to create the IHXValues
  1091.         //
  1092.         // Get the CCF
  1093.         IHXCommonClassFactory* pCCF = NULL;
  1094.         retVal = pContext->QueryInterface(IID_IHXCommonClassFactory,
  1095.                                           (void**) &pCCF);
  1096.         if (SUCCEEDED(retVal))
  1097.         {
  1098.             // Create an IHXValues
  1099.             HX_RELEASE(rpValues);
  1100.             retVal = pCCF->CreateInstance(CLSID_IHXValues,
  1101.                                           (void**) &rpValues);
  1102.         }
  1103.         HX_RELEASE(pCCF);
  1104.     }
  1105.     else
  1106.     {
  1107.         // No, we don't have a context, so use CHXBuffer
  1108.         CHXHeader* pValues = new CHXHeader();
  1109.         if (pValues)
  1110.         {
  1111.             // Assign the out parameter
  1112.             HX_RELEASE(rpValues);
  1113.             rpValues = (IHXValues*) pValues;
  1114.             rpValues->AddRef();
  1115.             // Clear the return value
  1116.             retVal = HXR_OK;
  1117.         }
  1118.     }
  1119.     return retVal;
  1120. }
  1121. HX_RESULT CreateStringBuffer(REF(IHXBuffer*) rpBuffer,
  1122.                              const char*      pszStr,
  1123.                              IUnknown*        pContext)
  1124. {
  1125.     HX_RESULT retVal = HXR_FAIL;
  1126.     if (pszStr)
  1127.     {
  1128.         // Create a buffer
  1129.         IHXBuffer* pBuffer = NULL;
  1130.         retVal = CreateBuffer(pBuffer, pContext);
  1131.         if (SUCCEEDED(retVal))
  1132.         {
  1133.             // Set the string into the buffer
  1134.             retVal = pBuffer->Set((const UCHAR*) pszStr, strlen(pszStr) + 1);
  1135.             if (SUCCEEDED(retVal))
  1136.             {
  1137.                 // Assign the out parameters
  1138.                 HX_RELEASE(rpBuffer);
  1139.                 rpBuffer = pBuffer;
  1140.                 rpBuffer->AddRef();
  1141.             }
  1142.         }
  1143.         HX_RELEASE(pBuffer);
  1144.     }
  1145.     return retVal;
  1146. }
  1147. HX_RESULT SetCStringProperty(IHXValues* pValues,
  1148.                              const char* pszName,
  1149.                              const char* pszValue,
  1150.                              IUnknown*   pContext,
  1151.                              BOOL        bSetAsBufferProp)
  1152. {
  1153.     HX_RESULT retVal = HXR_FAIL;
  1154.     if (pValues && pszName && pszValue)
  1155.     {
  1156.         // Create value buffer
  1157.         IHXBuffer* pValue = NULL;
  1158.         retVal = CreateStringBuffer(pValue, pszValue, pContext);
  1159.         if (SUCCEEDED(retVal))
  1160.         {
  1161.             // Set the property
  1162.             if (bSetAsBufferProp)
  1163.             {
  1164.                 retVal = pValues->SetPropertyBuffer(pszName, pValue);
  1165.             }
  1166.             else
  1167.             {
  1168.                 retVal = pValues->SetPropertyCString(pszName, pValue);
  1169.             }
  1170.         }
  1171.         HX_RELEASE(pValue);
  1172.     }
  1173.     return retVal;
  1174. }
  1175. HX_RESULT SetCStringPropertyWithNullTerm(IHXValues*  pValues,
  1176.                                          const char* pszName,
  1177.                                          BYTE*       pBuf,
  1178.                                          UINT32      ulLen,
  1179.                                          IUnknown*   pContext,
  1180.                                          BOOL        bSetAsBufferProp)
  1181. {
  1182.     HX_RESULT retVal = HXR_FAIL;
  1183.     if (pValues && pszName && pBuf && ulLen)
  1184.     {
  1185.         // Create value buffer
  1186.         IHXBuffer* pValue = NULL;
  1187.         retVal = CreateBuffer(pValue, pContext);
  1188.         if (SUCCEEDED(retVal))
  1189.         {
  1190.             // Set the buffer size
  1191.             retVal = pValue->SetSize(ulLen + 1);
  1192.             if (SUCCEEDED(retVal))
  1193.             {
  1194.                 // Get the buffer pointer
  1195.                 BYTE* pValBuf = pValue->GetBuffer();
  1196.                 if (pValBuf)
  1197.                 {
  1198.                     // memcpy the buffer
  1199.                     memcpy(pValBuf, pBuf, ulLen); /* Flawfinder: ignore */
  1200.                     // Add the NULL-terminator
  1201.                     pValBuf[ulLen] = (BYTE) '';
  1202.                     // Are we setting as a buffer property?
  1203.                     if (bSetAsBufferProp)
  1204.                     {
  1205.                         retVal = pValues->SetPropertyBuffer(pszName, pValue);
  1206.                     }
  1207.                     else
  1208.                     {
  1209.                         retVal = pValues->SetPropertyCString(pszName, pValue);
  1210.                     }
  1211.                 }
  1212.                 else
  1213.                 {
  1214.                     retVal = HXR_OUTOFMEMORY;
  1215.                 }
  1216.             }
  1217.         }
  1218.         HX_RELEASE(pValue);
  1219.     }
  1220.     return retVal;
  1221. }
  1222. HX_RESULT CreateNullTermBuffer(BYTE*  pBuf,
  1223.                                UINT32 ulLen,
  1224.                                char** ppNTBuf)
  1225. {
  1226.     HX_RESULT retVal = HXR_FAIL;
  1227.     if (pBuf && ulLen && ppNTBuf)
  1228.     {
  1229.         char* pTmp = new char [ulLen+1];
  1230.         if (pTmp)
  1231.         {
  1232.             // Copy pBuf into the new buf
  1233.             memcpy(pTmp, pBuf, ulLen); /* Flawfinder: ignore */
  1234.             // NULL-terminate the new buf
  1235.             pTmp[ulLen] = '';
  1236.             // Set the out parameter
  1237.             *ppNTBuf = pTmp;
  1238.             // Clear the return value
  1239.             retVal = HXR_OK;
  1240.         }
  1241.     }
  1242.     return retVal;
  1243. }
  1244. HX_RESULT SetBufferProperty(IHXValues* pValues,
  1245.                             const char* pszName,
  1246.                             BYTE*       pBuf,
  1247.                             UINT32      ulLen,
  1248.                             IUnknown*   pContext)
  1249. {
  1250.     HX_RESULT retVal = HXR_FAIL;
  1251.     if (pValues && pszName && pBuf && ulLen)
  1252.     {
  1253.         // Create value buffer
  1254.         IHXBuffer* pValue = NULL;
  1255.         retVal = CreateBuffer(pValue, pContext);
  1256.         if (SUCCEEDED(retVal))
  1257.         {
  1258.             // Set the buffer
  1259.             retVal = pValue->Set(pBuf, ulLen);
  1260.             if (SUCCEEDED(retVal))
  1261.             {
  1262.                 // Set the property
  1263.                 retVal = pValues->SetPropertyBuffer(pszName, pValue);
  1264.             }
  1265.         }
  1266.         HX_RELEASE(pValue);
  1267.     }
  1268.     return retVal;
  1269. }
  1270. HX_RESULT UnpackPropertyULONG32(IHXValues* pValues,
  1271.                                 REF(BYTE*)  rpBuf,
  1272.                                 BYTE*       pLimit,
  1273.                                 IUnknown*   pContext)
  1274. {
  1275.     HX_RESULT retVal = HXR_FAIL;
  1276.     if (pValues && rpBuf && pLimit &&
  1277.         rpBuf < pLimit && rpBuf[0] == 'u')
  1278.     {
  1279.         // Skip the 'u' type character
  1280.         rpBuf++;
  1281.         // Save the beginning of the string
  1282.         const char* pszName = (const char*) rpBuf;
  1283.         // Search until we find either a NULL or 
  1284.         // the end of the buffer
  1285.         while (rpBuf < pLimit && *rpBuf != 0) ++rpBuf;
  1286.         // Did we get a NULL terminator?
  1287.         if (rpBuf < pLimit && *rpBuf == 0)
  1288.         {
  1289.             // We know now that pszName is a valid string
  1290.             //
  1291.             // Skip the NULL terminator
  1292.             ++rpBuf;
  1293.             // Now get the ULONG32
  1294.             if (rpBuf + 4 <= pLimit)
  1295.             {
  1296.                 // Unpack in big-endian form
  1297.                 UINT32 ulValue = ((rpBuf[0] << 24) & 0xFF000000) |
  1298.                                  ((rpBuf[1] << 16) & 0x00FF0000) |
  1299.                                  ((rpBuf[2] <<  8) & 0x0000FF00) |
  1300.                                  ( rpBuf[3]        & 0x000000FF);
  1301.                 // Skip the ULONG32
  1302.                 rpBuf += 4;
  1303.                 // Set the property
  1304.                 retVal = pValues->SetPropertyULONG32(pszName, ulValue);
  1305.             }
  1306.         }
  1307.     }
  1308.     return retVal;
  1309. }
  1310. HX_RESULT UnpackPropertyCString(IHXValues* pValues,
  1311.                                 REF(BYTE*)  rpBuf,
  1312.                                 BYTE*       pLimit,
  1313.                                 IUnknown*   pContext)
  1314. {
  1315.     HX_RESULT retVal = HXR_FAIL;
  1316.     if (pValues && rpBuf && pLimit &&
  1317.         rpBuf < pLimit && rpBuf[0] == 'c')
  1318.     {
  1319.         // Skip the 'c' type character
  1320.         rpBuf++;
  1321.         // Save the beginning of the string
  1322.         const char* pszName = (const char*) rpBuf;
  1323.         // Search until we find either a NULL or 
  1324.         // the end of the buffer
  1325.         while (rpBuf < pLimit && *rpBuf != 0) ++rpBuf;
  1326.         // Did we get a NULL terminator?
  1327.         if (rpBuf < pLimit && *rpBuf == 0)
  1328.         {
  1329.             // We know now that pszName is a valid string
  1330.             //
  1331.             // Skip the NULL terminator
  1332.             ++rpBuf;
  1333.             // Save the beginning of the value string
  1334.             const char* pszValue = (const char*) rpBuf;
  1335.             // Search until we find either a NULL or 
  1336.             // the end of the buffer
  1337.             while (rpBuf < pLimit && *rpBuf != 0) ++rpBuf;
  1338.             // Did we get a NULL terminator?
  1339.             if (rpBuf < pLimit && *rpBuf == 0)
  1340.             {
  1341.                 // Skip the NULL terminator
  1342.                 ++rpBuf;
  1343.                 // We know now that pszValue is a valid string, so
  1344.                 // make an IHXBuffer out of it
  1345.                 IHXBuffer* pValue = NULL;
  1346.                 retVal = CreateStringBuffer(pValue, pszValue, pContext);
  1347.                 if (SUCCEEDED(retVal))
  1348.                 {
  1349.                     // Set the property
  1350.                     retVal = pValues->SetPropertyCString(pszName, pValue);
  1351.                 }
  1352.                 HX_RELEASE(pValue);
  1353.             }
  1354.         }
  1355.     }
  1356.     return retVal;
  1357. }
  1358. HX_RESULT UnpackPropertyBuffer(IHXValues* pValues,
  1359.                                REF(BYTE*)  rpBuf,
  1360.                                BYTE*       pLimit,
  1361.                                IUnknown*   pContext)
  1362. {
  1363.     HX_RESULT retVal = HXR_FAIL;
  1364.     if (pValues && rpBuf && pLimit &&
  1365.         rpBuf < pLimit && rpBuf[0] == 'b')
  1366.     {
  1367.         // Skip the 'b' type character
  1368.         rpBuf++;
  1369.         // Save the beginning of the string
  1370.         const char* pszName = (const char*) rpBuf;
  1371.         // Search until we find either a NULL or 
  1372.         // the end of the buffer
  1373.         while (rpBuf < pLimit && *rpBuf != 0) ++rpBuf;
  1374.         // Did we get a NULL terminator?
  1375.         if (rpBuf < pLimit && *rpBuf == 0)
  1376.         {
  1377.             // We know now that pszName is a valid string
  1378.             //
  1379.             // Skip the NULL terminator
  1380.             ++rpBuf;
  1381.             // Do we have enough bytes to get the buffer length?
  1382.             if (rpBuf + 4 <= pLimit)
  1383.             {
  1384.                 // Unpack the buffer length in big-endian form
  1385.                 UINT32 ulLen = ((rpBuf[0] << 24) & 0xFF000000) |
  1386.                                ((rpBuf[1] << 16) & 0x00FF0000) |
  1387.                                ((rpBuf[2] <<  8) & 0x0000FF00) |
  1388.                                ( rpBuf[3]        & 0x000000FF);
  1389.                 // Skip the buffer length
  1390.                 rpBuf += 4;
  1391.                 // Do we have enough bytes to get the buffer?
  1392.                 if (rpBuf + ulLen <= pLimit)
  1393.                 {
  1394.                     // Create a buffer
  1395.                     IHXBuffer* pValue = NULL;
  1396.                     retVal = CreateBuffer(pValue, pContext);
  1397.                     if (SUCCEEDED(retVal))
  1398.                     {
  1399.                         // Set the buffer
  1400.                         retVal = pValue->Set(rpBuf, ulLen);
  1401.                         if (SUCCEEDED(retVal))
  1402.                         {
  1403.                             // Skip the buffer bytes
  1404.                             rpBuf += ulLen;
  1405.                             // Set the property
  1406.                             retVal = pValues->SetPropertyBuffer(pszName,
  1407.                                                                 pValue);
  1408.                         }
  1409.                     }
  1410.                     HX_RELEASE(pValue);
  1411.                 }
  1412.             }
  1413.         }
  1414.     }
  1415.     return retVal;
  1416. }
  1417. HX_RESULT UnpackValuesBinary(IHXValues* pValues,
  1418.                              IHXBuffer* pBuffer,
  1419.                              IUnknown*   pContext)
  1420. {
  1421.     HX_RESULT retVal = HXR_FAIL;
  1422.     if (pValues && pBuffer)
  1423.     {
  1424.         retVal = UnpackValuesBinary(pValues,
  1425.                                     pBuffer->GetBuffer(),
  1426.                                     pBuffer->GetSize(),
  1427.                                     pContext);
  1428.     }
  1429.     return retVal;
  1430. }
  1431. HX_RESULT UnpackValuesBinary(IHXValues* pValues,
  1432.                              BYTE*       pBuf,
  1433.                              UINT32      ulLen,
  1434.                              IUnknown*   pContext)
  1435. {
  1436.     HX_RESULT retVal = HXR_FAIL;
  1437.     if (pBuf && ulLen)
  1438.     {
  1439.         // Get the pointer limit
  1440.         BYTE* pLimit = pBuf + ulLen;
  1441.         // Make sure this is not string format
  1442.         if (pBuf[0] != '[')
  1443.         {
  1444.             // Clear the return value
  1445.             retVal = HXR_OK;
  1446.             // Loop through the buffer, unpacking name/value pairs
  1447.             while (pBuf < pLimit && SUCCEEDED(retVal))
  1448.             {
  1449.                 // Get a property type code
  1450.                 char c = (char) pBuf[0];
  1451.                 // Save the buffer pointer
  1452.                 BYTE* pCur = pBuf;
  1453.                 // Switch based on type
  1454.                 switch (c)
  1455.                 {
  1456.                     case 'u':
  1457.                         retVal = UnpackPropertyULONG32(pValues, pBuf,
  1458.                                                        pLimit, pContext);
  1459.                         break;
  1460.                     case 'c':
  1461.                         retVal = UnpackPropertyCString(pValues, pBuf,
  1462.                                                        pLimit, pContext);
  1463.                         break;
  1464.                     case 'b':
  1465.                         retVal = UnpackPropertyBuffer(pValues, pBuf,
  1466.                                                       pLimit, pContext);
  1467.                         break;
  1468.                     default:
  1469.                         retVal = HXR_FAIL;
  1470.                         break;
  1471.                 }
  1472.                 // Do a sanity check: if we succeeded,
  1473.                 // then we must have advanced the pointer.
  1474.                 // This will prevent an infinite loop.
  1475.                 if (SUCCEEDED(retVal) && pCur == pBuf)
  1476.                 {
  1477.                     retVal = HXR_FAIL;
  1478.                 }
  1479.             }
  1480.         }
  1481.     }
  1482.     return retVal;
  1483. }
  1484. HX_RESULT PackValues(REF(IHXBuffer*) rpBuffer,
  1485.                      IHXValues*      pValues,
  1486.                      BOOL             bPackBinary,
  1487.                      IUnknown*        pContext)
  1488. {
  1489.     HX_RESULT retVal = HXR_FAIL;
  1490.     if (pValues)
  1491.     {
  1492.         // Create an output IHXBuffer
  1493.         IHXBuffer* pBuffer = NULL;
  1494.         retVal = CreateBuffer(pBuffer, pContext);
  1495.         if (SUCCEEDED(retVal))
  1496.         {
  1497.             // Are we supposed to pack this in binary form?
  1498.             if (bPackBinary)
  1499.             {
  1500.                 // Pack in binary form
  1501.                 //
  1502.                 // First get the size necessary to pack it in binary form
  1503.                 UINT32 ulBinPackSize = GetBinaryPackedSize(pValues);
  1504.                 if (ulBinPackSize)
  1505.                 {
  1506.                     // Make the buffer this size
  1507.                     retVal = pBuffer->SetSize(ulBinPackSize);
  1508.                     if (SUCCEEDED(retVal))
  1509.                     {
  1510.                         // Binary pack the buffer
  1511.                         retVal = PackValuesBinary(pBuffer, pValues);
  1512.                         if (SUCCEEDED(retVal))
  1513.                         {
  1514.                             // Copy the out parameter
  1515.                             HX_RELEASE(rpBuffer);
  1516.                             rpBuffer = pBuffer;
  1517.                             rpBuffer->AddRef();
  1518.                         }
  1519.                     }
  1520.                 }
  1521.                 else
  1522.                 {
  1523.                     retVal = HXR_FAIL;
  1524.                 }
  1525.             }
  1526.             else
  1527.             {
  1528.                 // Pack in a string
  1529.                 CHXString cTmp;
  1530.                 retVal = PackValues(cTmp, pValues);
  1531.                 if (SUCCEEDED(retVal))
  1532.                 {
  1533.                     // Now just copy the string into the IHXBuffer
  1534.                     retVal = pBuffer->Set((const UCHAR*) (const char*) cTmp,
  1535.                                           cTmp.GetLength() + 1);
  1536.                     if (SUCCEEDED(retVal))
  1537.                     {
  1538.                         // Set the out parameter
  1539.                         HX_RELEASE(rpBuffer);
  1540.                         rpBuffer = pBuffer;
  1541.                         rpBuffer->AddRef();
  1542.                     }
  1543.                 }
  1544.             }
  1545.         }
  1546.         HX_RELEASE(pBuffer);
  1547.     }
  1548.     return retVal;
  1549. }
  1550. HX_RESULT UnpackValues(REF(IHXValues*) rpValues,
  1551.                        IHXBuffer*      pBuffer,
  1552.                        IUnknown*        pContext)
  1553. {
  1554.     HX_RESULT retVal = HXR_FAIL;
  1555.     if (pBuffer)
  1556.     {
  1557.         retVal = UnpackValues(rpValues,
  1558.                               pBuffer->GetBuffer(),
  1559.                               pBuffer->GetSize(),
  1560.                               pContext);
  1561.     }
  1562.     return retVal;
  1563. }
  1564. HX_RESULT UnpackValues(REF(IHXValues*) rpValues,
  1565.                        BYTE*            pBuf,
  1566.                        UINT32           ulLen,
  1567.                        IUnknown*        pContext)
  1568. {
  1569.     HX_RESULT retVal = HXR_FAIL;
  1570.     if (pBuf && ulLen)
  1571.     {
  1572.         // Create an output IHXValues
  1573.         IHXValues* pValues = NULL;
  1574.         retVal = CreateValues(pValues, pContext);
  1575.         if (SUCCEEDED(retVal))
  1576.         {
  1577.             // Get the string
  1578.             const char* pszBuffer = (const char*) pBuf;
  1579.             // Is this packed in binary or text? If it's in text
  1580.             // form, then it will have a '[' as the first character
  1581.             if (pszBuffer[0] != '[')
  1582.             {
  1583.                 // The buffer is binary packed
  1584.                 retVal = UnpackValuesBinary(pValues, pBuf, ulLen, pContext);
  1585.             }
  1586.             else
  1587.             {
  1588.                 // The buffer is text packed
  1589.                 retVal = UnpackValues(pszBuffer, pValues, FALSE);
  1590.             }
  1591.             if (SUCCEEDED(retVal))
  1592.             {
  1593.                 // Assign the out parameter
  1594.                 HX_RELEASE(rpValues);
  1595.                 rpValues = pValues;
  1596.                 rpValues->AddRef();
  1597.             }
  1598.         }
  1599.         HX_RELEASE(pValues);
  1600.     }
  1601.     return retVal;
  1602. }
  1603. // This method checks to see if all the properties
  1604. // in pValues1 are in pValues2 and that the value
  1605. // of these properties is indentical. pValues2,
  1606. // however, could still have properties that pValues1
  1607. // doesn't have. AreValuesIdentical() calls
  1608. // AreValuesInclusiveIdentical() in both directions,
  1609. // which establishes absolute equality if both
  1610. // are true.
  1611. BOOL AreValuesInclusiveIdentical(IHXValues* pValues1,
  1612.                                  IHXValues* pValues2)
  1613. {
  1614.     BOOL bRet = FALSE;
  1615.     if (pValues1 && pValues2)
  1616.     {
  1617.         // Assume that they are equal, and breakout
  1618.         // at the first inequality
  1619.         bRet = TRUE;
  1620.         // Check the ULONG32 properties
  1621.         const char* pszName  = NULL;
  1622.         UINT32      ulValue1 = 0;
  1623.         HX_RESULT rv = pValues1->GetFirstPropertyULONG32(pszName, ulValue1);
  1624.         while (SUCCEEDED(rv) && bRet)
  1625.         {
  1626.             // Lookup this property in pValues2
  1627.             UINT32 ulValue2 = 0;
  1628.             HX_RESULT rv2 = pValues2->GetPropertyULONG32(pszName, ulValue2);
  1629.             // Check for a match
  1630.             if (FAILED(rv2) || ulValue1 != ulValue2)
  1631.             {
  1632.                 bRet = FALSE;
  1633.             }
  1634.             // Get next ULONG32 property
  1635.             rv = pValues1->GetNextPropertyULONG32(pszName, ulValue1);
  1636.         }
  1637.         if (bRet)
  1638.         {
  1639.             // Check the CString properties
  1640.             IHXBuffer* pValue1 = NULL;
  1641.             rv = pValues1->GetFirstPropertyCString(pszName, pValue1);
  1642.             while (SUCCEEDED(rv) && bRet)
  1643.             {
  1644.                 // Lookup this property in pValues2
  1645.                 IHXBuffer* pValue2 = NULL;
  1646.                 HX_RESULT rv2 = pValues2->GetPropertyCString(pszName, pValue2);
  1647.                 if (FAILED(rv2) ||
  1648.                     strcmp((const char*) pValue1->GetBuffer(),
  1649.                            (const char*) pValue2->GetBuffer()) != 0)
  1650.                 {
  1651.                     bRet = FALSE;
  1652.                 }
  1653.                 HX_RELEASE(pValue2);
  1654.                 // Get next CString prop
  1655.                 HX_RELEASE(pValue1);
  1656.                 rv = pValues1->GetNextPropertyCString(pszName, pValue1);
  1657.             }
  1658.             if (bRet)
  1659.             {
  1660.                 // Check the buffer properties
  1661.                 rv = pValues1->GetFirstPropertyBuffer(pszName, pValue1);
  1662.                 while (SUCCEEDED(rv) && bRet)
  1663.                 {
  1664.                     // Lookup this property in pValues2
  1665.                     IHXBuffer* pValue2 = NULL;
  1666.                     HX_RESULT rv2 = pValues2->GetPropertyBuffer(pszName, pValue2);
  1667.                     if (FAILED(rv2)                              ||
  1668.                         pValue1->GetSize() != pValue2->GetSize() ||
  1669.                         memcmp((const void*) pValue1->GetBuffer(),
  1670.                                (const void*) pValue2->GetBuffer(),
  1671.                                pValue1->GetSize()) != 0)
  1672.                     {
  1673.                         bRet = FALSE;
  1674.                     }
  1675.                     HX_RELEASE(pValue2);
  1676.                     // Get next Buffer prop
  1677.                     HX_RELEASE(pValue1);
  1678.                     rv = pValues1->GetNextPropertyBuffer(pszName, pValue1);
  1679.                 }
  1680.             }
  1681.         }
  1682.     }
  1683.     return bRet;
  1684. }
  1685. BOOL AreValuesIdentical(IHXValues* pValues1,
  1686.                         IHXValues* pValues2)
  1687. {
  1688.     BOOL bRet = FALSE;
  1689.     // Check if all the properties in pValues1 are
  1690.     // in pValues2 and are identical
  1691.     bRet = AreValuesInclusiveIdentical(pValues1, pValues2);
  1692.     if (bRet)
  1693.     {
  1694.         // Check if all the properties in pValues2 are
  1695.         // in pValues1 and are identical
  1696.         bRet = AreValuesInclusiveIdentical(pValues2, pValues1);
  1697.     }
  1698.     return bRet;
  1699. }
  1700. #ifdef _DEBUG
  1701. HX_RESULT TestValuesPacking(IUnknown* pContext)
  1702. {
  1703.     HX_RESULT retVal = HXR_OK;
  1704.     // Create an IHXValues
  1705.     IHXValues* pValues = NULL;
  1706.     retVal = CreateValues(pValues, pContext);
  1707.     if (SUCCEEDED(retVal))
  1708.     {
  1709.         // Populate this IHXValues
  1710.         pValues->SetPropertyULONG32("ulong1", 42);
  1711.         pValues->SetPropertyULONG32("ulong2", 0xbaadf00d);
  1712.         SetCStringProperty(pValues, "cstring1",
  1713.                            "Rock the Casbah", pContext);
  1714.         SetCStringProperty(pValues, "cstring2",
  1715.                            "Sandinista", pContext);
  1716.         UINT32 ulBuf1Len = 128;
  1717.         BYTE*  pBuf1     = new BYTE [ulBuf1Len];
  1718.         if (pBuf1)
  1719.         {
  1720.             // Fill the buffer with random byte values
  1721.             srand(time(NULL));
  1722.             for (UINT32 i = 0; i < ulBuf1Len; i++)
  1723.             {
  1724.                 UINT32 ulVal = (UINT32) rand();
  1725.                 pBuf1[i]     = (BYTE) (ulVal & 0x000000FF);
  1726.             }
  1727.             SetBufferProperty(pValues, "buffer1", pBuf1, ulBuf1Len, pContext);
  1728.             // Pack it as text
  1729.             IHXBuffer* pBufferText = NULL;
  1730.             retVal = PackValues(pBufferText, pValues, FALSE, pContext);
  1731.             if (SUCCEEDED(retVal))
  1732.             {
  1733.                 // Now unpack it
  1734.                 IHXValues* pValuesTextOut = NULL;
  1735.                 retVal = UnpackValues(pValuesTextOut, pBufferText, pContext);
  1736.                 if (SUCCEEDED(retVal))
  1737.                 {
  1738.                     // Compare them
  1739.                     if (AreValuesIdentical(pValues, pValuesTextOut))
  1740.                     {
  1741.                         // Now pack as binary
  1742.                         IHXBuffer* pBufferBinary = NULL;
  1743.                         retVal = PackValues(pBufferBinary, pValues,
  1744.                                             TRUE, pContext);
  1745.                         if (SUCCEEDED(retVal))
  1746.                         {
  1747.                             // Now unpack it
  1748.                             IHXValues* pValuesBinaryOut = NULL;
  1749.                             retVal = UnpackValues(pValuesBinaryOut,
  1750.                                                   pBufferBinary, pContext);
  1751.                             if (SUCCEEDED(retVal))
  1752.                             {
  1753.                                 // Compare them
  1754.                                 if (!AreValuesIdentical(pValues,
  1755.                                                         pValuesBinaryOut))
  1756.                                 {
  1757.                                     // Oops - they are not the same
  1758.                                     retVal = HXR_FAIL;
  1759.                                 }
  1760.                             }
  1761.                             HX_RELEASE(pValuesBinaryOut);
  1762.                         }
  1763.                         HX_RELEASE(pBufferBinary);
  1764.                     }
  1765.                     else
  1766.                     {
  1767.                         // Oops - they are not the same
  1768.                         retVal = HXR_FAIL;
  1769.                     }
  1770.                 }
  1771.                 HX_RELEASE(pValuesTextOut);
  1772.             }
  1773.             HX_RELEASE(pBufferText);
  1774.         }
  1775.         HX_VECTOR_DELETE(pBuf1);
  1776.     }
  1777.     HX_RELEASE(pValues);
  1778.     return retVal;
  1779. }
  1780. #endif