📄 pckunpck.cpp
字号:
/* ***** BEGIN LICENSE BLOCK *****
* Version: RCSL 1.0/RPSL 1.0
*
* Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved.
*
* The contents of this file, and the files included with this file, are
* subject to the current version of the RealNetworks Public Source License
* Version 1.0 (the "RPSL") available at
* http://www.helixcommunity.org/content/rpsl unless you have licensed
* the file under the RealNetworks Community Source License Version 1.0
* (the "RCSL") available at http://www.helixcommunity.org/content/rcsl,
* in which case the RCSL will apply. You may also obtain the license terms
* directly from RealNetworks. You may not use this file except in
* compliance with the RPSL or, if you have a valid RCSL with RealNetworks
* applicable to this file, the RCSL. Please see the applicable RPSL or
* RCSL for the rights, obligations and limitations governing use of the
* contents of the file.
*
* This file is part of the Helix DNA Technology. RealNetworks is the
* developer of the Original Code and owns the copyrights in the portions
* it created.
*
* This file, and the files included with this file, is distributed and made
* available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
*
* Technology Compatibility Kit Test Suite(s) Location:
* http://www.helixcommunity.org/content/tck
*
* Contributor(s):
*
* ***** END LICENSE BLOCK ***** */
// system
#include "hlxclib/stdarg.h" /* for va_arg */
#include "safestring.h"
#ifndef _SYMBIAN
#include "hlxclib/memory.h"
#endif
#include "hlxclib/string.h"
#include "hlxclib/stdlib.h"
#include "hlxclib/time.h"
// include
#include "hxtypes.h"
#include "hxwintyp.h"
#include "hxcom.h"
#include "hxcomm.h"
// pncont
#include "hxbuffer.h"
#include "chxpckts.h"
#include "rtsputil.h" /* for Base64 utils */
#include "hxslist.h"
#include "pckunpck.h"
/*
* constants
*/
// ascii string, buffer, pointer, uint, double, flag (BOOL), IHXValues
const char* const kFormatSpecs = "abpudfv";
// these types have implicit "parsability" so we omit the "x:" type specifier
// a string starts with '"', flag is a 'T' or 'F', uint is all decimal digits,
// and an IHXValues begins with '['
const char* const kOptTypes = "afuv";
// chars we need to escape/unescape (note they have 1:1 positioning)
const char* const kScaryChars = "\"\n\t\r\\";
const char* const kUnScaryChars = "\"ntr\\"; // these must correspond 1:1
// decimals
const char* const kDecimals = "1234567890";
/*
* PackBuffer
*
* USAGE:
*
* IHXBuffer* pBuffer;
* PackBuffer(pBuffer, "uu", 10, 20);
* PackBuffer(pBuffer, "a", "foobar");
* PackBuffer(pBuffer, "aua", 10, "foobar", 20);
*
* More advanced: (passing a buffer)
* IHXBuffer* pTheBuffer;
* PackBuffer(pBuffer, "uabu", 10, "foobar", pTheBuffer, 20);
*
* Still more advanced: (passing an IUnknown)
* IHXSomeObject* pObj;
* PackBuffer(pBuffer, "uap", 10, "foobar", (IUnknown*)pObj);
*/
HX_RESULT
PackBuffer(REF(IHXBuffer*) pBuffer, const char* pFormat, ...)
{
va_list vargs;
va_start(vargs, pFormat);
return PackBufferV(pBuffer, pFormat, vargs);
}
HX_RESULT
PackBufferV(REF(IHXBuffer*) pBuffer, const char* pFormat, va_list vargs)
{
// init the out param
pBuffer = NULL;
// automatically fail if we've no CCF or a bad formatter is passed
if (!pFormat || !*pFormat || !strpbrk(pFormat, kFormatSpecs))
{
return HXR_FAIL;
}
// calculate how much space we'll need for the buffer and
// make sure the formatter is valid
UINT32 uBufSize = 1; // null terminator
CHXStringList packedValuesList;
va_list vargsOrig;
va_copy(vargsOrig, vargs);
const char* pTemp = pFormat;
while (*pTemp)
{
switch (*pTemp)
{
case 'f':
{
BOOL bFlag = va_arg(vargs, BOOL);
// XXXNH: optimization... we only put one char for a flag/bool
uBufSize += 1;
}
break;
case 'd':
{
double dVal = va_arg(vargs, double);
// to preserve precision we base64-ize the double
uBufSize += (sizeof(double) * 4) / 3 + 10;
}
break;
case 'u':
{
UINT32 u = va_arg(vargs, UINT32);
// Compute number of hex digits in 'u' & add to uBufSize
if (u == 0) ++uBufSize;
else {
UINT32 leadingZeroes = 0;
if (u <= 0x0000ffff) {leadingZeroes += 4; u <<= 16;}
if (u <= 0x00ffffff) {leadingZeroes += 2; u <<= 8;}
if (u <= 0x0fffffff) {leadingZeroes += 1; u <<= 4;}
uBufSize += 8 - leadingZeroes;
}
}
break;
case 'a':
{
const char* pStr = va_arg(vargs, const char*);
int nLen = pStr ? strlen(pStr) + 2 : 2; // add on quotation marks
while (pStr && *pStr)
{
// double-count chars we'll have to escape
if (strchr(kScaryChars, *pStr))
nLen++;
pStr ++;
}
uBufSize += nLen;
}
break;
case 'b':
{
IHXBuffer* pBuf = va_arg(vargs, IHXBuffer*);
if (!pBuf)
{
HX_ASSERT(FALSE);
return HXR_FAIL;
}
// base64 uses roughly 33% more space, plus a couple extra
uBufSize += (pBuf->GetSize() * 4) / 3 + 10;
}
break;
case 'p':
{
IUnknown* pPointer = va_arg(vargs, IUnknown*);
uBufSize += 8; // 8 digits for a hex number
}
break;
case 'v':
{
IHXValues* pValues = va_arg(vargs, IHXValues*);
if (!pValues)
{
HX_ASSERT(FALSE);
return HXR_FAIL;
}
CHXString sTemp;
if (FAILED(PackValues(sTemp, pValues)))
{
HX_ASSERT(FALSE);
return HXR_FAIL;
}
packedValuesList.AddTailString(sTemp);
uBufSize += sTemp.GetLength();
}
break;
}
if (strchr(kOptTypes, *pTemp))
uBufSize++; // just the delimiter for "optimized" types
else
uBufSize += 3; // the size of type specifier and delimiter
// next!
pTemp++;
}
// now allocate our buffer
CHXBuffer* pCHXBuffer = new CHXBuffer;
if (!pCHXBuffer)
return HXR_OUTOFMEMORY;
pCHXBuffer->AddRef();
if (SUCCEEDED(pCHXBuffer->SetSize(uBufSize)))
{
pBuffer = (IHXBuffer*)pCHXBuffer;
}
else
{
HX_RELEASE(pCHXBuffer);
return HXR_OUTOFMEMORY;
}
// now pack the args into our buffer
char* pBufStr = (char*)pBuffer->GetBuffer();
vargs = vargsOrig;
pTemp = pFormat;
while (*pTemp)
{
// XXXNH: space optimization: omit the type & ':' for certain types
if (strchr(kOptTypes, *pTemp) == NULL)
{
// start the param
*pBufStr = *pTemp; // append the type
pBufStr++;
*pBufStr = ':'; // and a delimiter
pBufStr++;
}
// then format the data
switch (*pTemp)
{
case 'f':
{
BOOL bFlag = va_arg(vargs, BOOL);
*pBufStr = bFlag ? 'T' : 'F';
pBufStr++;
}
break;
case 'd':
{
double dVal = va_arg(vargs, double);
UINT32 uSize = (sizeof(double) * 4) / 3 + 10;
int nLen = BinTo64((UCHAR*)&dVal, sizeof(double), pBufStr);
HX_ASSERT(nLen >= 0);
pBufStr += nLen-1; // -1 because of null terminator
}
break;
case 'u':
{
UINT32 u = va_arg(vargs, UINT32);
char pNum[16]; /* Flawfinder: ignore */
SafeSprintf(pNum, sizeof(pNum), "%x", u);
*pBufStr = '\0';
strcat(pBufStr, pNum); /* Flawfinder: ignore */
pBufStr += strlen(pNum);
}
break;
case 'a':
{
*pBufStr = '"'; // begin quote
pBufStr++;
const char* pStr = va_arg(vargs, const char*);
while (pStr && *pStr)
{
// double-count chars we'll have to escape
const char* pScary = strchr(kScaryChars, *pStr);
if (pScary)
{
*pBufStr = '\\';
pBufStr++;
*pBufStr = kUnScaryChars[pScary - kScaryChars];
pBufStr++;
}
else
{
*pBufStr = *pStr;
pBufStr++;
}
pStr++;
}
*pBufStr = '"'; // end quote
pBufStr++;
}
break;
case 'b':
{
IHXBuffer* pBuf = va_arg(vargs, IHXBuffer*);
if (!pBuf)
{
HX_ASSERT(FALSE);
return HXR_FAIL;
}
// base64 uses roughly 33% more space, plus a couple extra
UINT32 uSize = pBuf->GetSize();
int nLen = BinTo64(pBuf->GetBuffer(), uSize, pBufStr);
HX_ASSERT(nLen >= 0);
pBufStr += nLen-1; // -1 because of null terminator
}
break;
case 'p':
{
IUnknown* pUnknown = va_arg(vargs, IUnknown*);
char pPointer[9]; /* Flawfinder: ignore */
SafeSprintf(pPointer, sizeof(pPointer), "%08x", pUnknown);
*pBufStr = '\0';
strcat(pBufStr, pPointer); /* Flawfinder: ignore */
pBufStr += 8;
}
break;
case 'v':
{
IHXValues* pIgnoreMe = va_arg(vargs, IHXValues*);
LISTPOSITION p = packedValuesList.GetHeadPosition();
CHXString* psPacked = packedValuesList.GetNext(p);
*pBufStr = '\0';
strcat(pBufStr, *psPacked); /* Flawfinder: ignore */
pBufStr += psPacked->GetLength();
packedValuesList.RemoveHeadString();
}
break;
}
// end the param
*pBufStr = ';';
pBufStr++;
// go to the next formatter
pTemp++;
}
// null terminate!
*pBufStr = '\0';
pBufStr++;
#ifdef _DEBUG
// XXXNH: some sanity checking
pBufStr -= uBufSize;
if (pBufStr > (char*)(pBuffer->GetBuffer()))
{
// XXXNH: we wrote past the end of the buffer!!!!! We must have
// miscalculated the space needed...
HX_ASSERT(FALSE);
HX_RELEASE(pBuffer);
return HXR_FAIL;
}
#endif
return HXR_OK;
}
/*
* UnpackBuffer
*
* works like PackBuffer & sscanf.
*/
int
UnpackBuffer(REF(const char*) pBuffer, const char* pFormat, ...)
{
va_list vargs;
va_start(vargs, pFormat);
return UnpackBufferV(pBuffer, pFormat, vargs);
}
int
UnpackBufferV(REF(const char*) pBufStr, const char* pFormat, va_list vargs)
{
// automatically fail if we've no CCF or a bad formatter is passed
if (!pFormat || !*pFormat || !strpbrk(pFormat, kFormatSpecs))
return -1;
if (!pBufStr)
return 0;
// iterate through the args and unpack them from the buffer
int nRead = 0;
const char* pTemp = pFormat;
while (*pTemp)
{
// XXXNH: space optimization: omit the type & ':' for certain types
if (!strchr(kOptTypes, *pTemp))
{
// make sure the types match
if (*pTemp != *pBufStr)
return nRead;
pBufStr++;
// read the type/value delimiter
if (*pBufStr != ':')
return nRead;
pBufStr++;
}
switch (*pTemp)
{
case 'f':
{
// XXXNH: optimization... we only put one char for a flag/bool
BOOL* pbFlag = va_arg(vargs, BOOL*);
if (*pBufStr == 'T')
*pbFlag = TRUE;
else
*pbFlag = FALSE;
pBufStr++;
}
break;
case 'd':
{
double* pdVal = va_arg(vargs, double*);
const char* pEnd = strchr(pBufStr, ';');
if (pEnd)
{
int nSize = pEnd - pBufStr;
int nLen = BinFrom64(pBufStr, nSize, (UCHAR*)pdVal);
HX_ASSERT(nLen == sizeof(double));
pBufStr = pEnd;
}
else
return nRead; // couldn't parse the end of the buffer
}
break;
case 'u':
{
UINT32* puInt = va_arg(vargs, UINT32*);
// XXXSAB Untested...
char* pEnd = NULL;
unsigned long val = strtoul(pBufStr, &pEnd, 16);
// if (sscanf(pBufStr, "%x", puInt) == 1)
if (pEnd && pEnd > pBufStr)
{
// advance to the next delimiter
pBufStr = strchr(pBufStr, ';');
}
else
return nRead; // couldn't parse an int!
}
break;
case 'a':
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -