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

Symbian

开发平台:

Visual C++

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