/* ***** BEGIN LICENSE BLOCK *****
 * Source last modified: $Id: wirefmgr.cpp,v 1.2.24.1 2004/07/09 01:54:51 hubbe Exp $
 * 
 * Portions Copyright (c) 1995-2004 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 (the "RPSL") available at
 * http://www.helixcommunity.org/content/rpsl unless you have licensed
 * the file under the current version of the RealNetworks Community
 * Source License (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.
 * 
 * Alternatively, the contents of this file may be used under the
 * terms of the GNU General Public License Version 2 or later (the
 * "GPL") in which case the provisions of the GPL are applicable
 * instead of those above. If you wish to allow use of your version of
 * this file only under the terms of the GPL, and not to allow others
 * to use your version of this file under the terms of either the RPSL
 * or RCSL, indicate your decision by deleting the provisions above
 * and replace them with the notice and other provisions required by
 * the GPL. If you do not delete the provisions above, a recipient may
 * use your version of this file under the terms of any one of the
 * RPSL, the RCSL or the GPL.
 * 
 * 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 ***** */

// include
#include "hxtypes.h"
#include "hxwintyp.h"
#include "hxresult.h"
#include "hxcom.h"
#include "ihxpckts.h"
#include "hxvsurf.h"
#include "hxfiles.h"
#include "hxcomm.h"
#include "hxerror.h"

// hxmisc
#include "unkimp.h"
#include "baseobj.h"

// hxcont
#include "hxstring.h"
#include "hxslist.h"
#include "hxmap.h"

// pxcomlib
#include "pxrect.h"
#include "pxcolor.h"
#include "pxeffect.h"
#include "hxslist.h"
#include "hxmap.h"
#include "gstring.h"
#include "pxutil.h"
#include "nestbuff.h"
#include "wirefmgr.h"

// hxdebug
#include "errdbg.h"
#include "hxheap.h"
#ifdef _DEBUG
#undef HX_THIS_FILE     
static char HX_THIS_FILE[] = __FILE__;
#endif

#define BASE_STREAM_VERSION      HX_ENCODE_PROD_VERSION(0, 0, 0, 0)
#define U2_STREAM_VERSION        HX_ENCODE_PROD_VERSION(1, 1, 0, 0)
#define COOKIE_STREAM_VERSION    HX_ENCODE_PROD_VERSION(1, 2, 0, 0)
#define CACHINGAD_STREAM_VERSION HX_ENCODE_PROD_VERSION(1, 3, 0, 0)
#define OPACITY_STREAM_VERSION   HX_ENCODE_PROD_VERSION(1, 4, 0, 0)

const UINT32 PXWireFormatManager::m_ulHighestSupportedStreamVersion = OPACITY_STREAM_VERSION;

PXWireFormatManager::PXWireFormatManager()
{
    Reset();
    m_lRefCount            = 0;
    m_pContext             = NULL;
    m_pCommonClassFactory  = NULL;
    m_pTitleStr            = NULL;
    m_pAuthorStr           = NULL;
    m_pCopyrightStr        = NULL;
    m_pDefaultURLStr       = NULL;
    m_pCodecMimeList       = NULL;
    m_pFXPackageMimeList   = NULL;
    m_pMapMimeToOpaqueSize = NULL;
    m_pASMRuleBook         = NULL;
    m_pStreamMimeType      = NULL;
}

PXWireFormatManager::~PXWireFormatManager()
{
    Deallocate();
}

HX_RESULT PXWireFormatManager::CreateObject(PXWireFormatManager** ppObj)
{
    HX_RESULT retVal = HXR_FAIL;

    if (ppObj)
    {
        PXWireFormatManager* pObj = new PXWireFormatManager();
        if (pObj)
        {
            *ppObj = pObj;
            retVal = HXR_OK;
        }
    }

    return retVal;
}

STDMETHODIMP PXWireFormatManager::QueryInterface(REFIID riid, void** ppvObj)
{
    HX_RESULT retVal = HXR_OK;

    if (IsEqualIID(riid, IID_IUnknown))
    {
        AddRef();
        *ppvObj = (IUnknown*) this;
    }
    else
    {
        *ppvObj = NULL;
        retVal  = HXR_NOINTERFACE;
    }

    return retVal;
}

STDMETHODIMP_(UINT32) PXWireFormatManager::AddRef()
{
    return InterlockedIncrement(&m_lRefCount);
}

STDMETHODIMP_(UINT32) PXWireFormatManager::Release()
{
    
    if (InterlockedDecrement(&m_lRefCount) > 0)
        return m_lRefCount;

    delete this;

    return 0;
}

HX_RESULT PXWireFormatManager::Init(IUnknown* pContext, UINT32 ulStreamVersion)
{
    HX_RESULT retVal = HXR_OK;

    // Clear out everything
    Deallocate();
    Reset();

    // Check to make sure the stream version is not too late
    if ((HX_GET_MAJOR_VERSION(ulStreamVersion) < HX_GET_MAJOR_VERSION(m_ulHighestSupportedStreamVersion) ||
         (HX_GET_MAJOR_VERSION(ulStreamVersion) == HX_GET_MAJOR_VERSION(m_ulHighestSupportedStreamVersion) &&
          HX_GET_MINOR_VERSION(ulStreamVersion) <= HX_GET_MINOR_VERSION(m_ulHighestSupportedStreamVersion))) &&
        pContext)
    {
        // Save the calling context
        m_pContext = pContext;
        m_pContext->AddRef();
        // Set the stream version
        m_ulStreamVersion = ulStreamVersion;
        // Create a list for the codec mimes
        HX_DELETE(m_pCodecMimeList);
        m_pCodecMimeList = new CHXSimpleList();
        if (m_pCodecMimeList)
        {
            // Create a list for the fx package mimes
            HX_DELETE(m_pFXPackageMimeList);
            m_pFXPackageMimeList = new CHXSimpleList();
            if (m_pFXPackageMimeList)
            {
                // Create a map
                HX_DELETE(m_pMapMimeToOpaqueSize);
                m_pMapMimeToOpaqueSize = new CHXMapStringToOb();
                if (m_pMapMimeToOpaqueSize)
                {
                    // Add the number of header bytes for the codecs we know about
                    // XXXMEH - this is a hack - there should be NO codec-specific
                    // code in here, since it attaches some dependence in between
                    // codecs and the renderer.
                    m_pMapMimeToOpaqueSize->SetAt("image/vndr.rn-realpix.jpeg", (void*) 12);
                    m_pMapMimeToOpaqueSize->SetAt("image/vnd.rn-realpix.gif",   (void*)  8);
                    m_pMapMimeToOpaqueSize->SetAt("image/vnd.rn-realpix.png",   (void*)  4);

                    // Get an IHXCommonClassFactory interface
                    retVal = m_pContext->QueryInterface(IID_IHXCommonClassFactory,
                                                        (void**) &m_pCommonClassFactory);
                }
                else
                {
                    retVal = HXR_OUTOFMEMORY;
                }
            }
            else
            {
                retVal = HXR_OUTOFMEMORY;
            }
        }
        else
        {
            retVal = HXR_OUTOFMEMORY;
        }
    }
    else
    {
        retVal = HXR_INVALID_PARAMETER;
    }

    if (FAILED(retVal))
    {
        Deallocate();
        Reset();
    }

    return retVal;
}

HX_RESULT PXWireFormatManager::GetFileHeader(REF(IHXValues*) rpFileHeader,
                                             const char* pszAcceptMetaInfo)
{
    HX_RESULT retVal = HXR_OK;

    // Create an IHXValues object
    IHXValues* pValues = NULL;
    retVal              = m_pCommonClassFactory->CreateInstance(CLSID_IHXValues,
                                                                (void**) &pValues);
    if (SUCCEEDED(retVal))
    {
        // Set properties
        pValues->SetPropertyULONG32("StreamCount",    1);
        pValues->SetPropertyULONG32("IsRealDataType", 1);
        // If there are TAC properties, then set them
        if (m_pTitleStr)
        {
            pValues->SetPropertyBuffer("Title", m_pTitleStr);
        }
        if (m_pAuthorStr)
        {
            pValues->SetPropertyBuffer("Author", m_pAuthorStr);
        }
        if (m_pCopyrightStr)
        {
            pValues->SetPropertyBuffer("Copyright", m_pCopyrightStr);
        }
        // Check if we need to set live stream flag
        if (m_bIsLive)
        {
            pValues->SetPropertyULONG32("LiveStream", 1);
        }
        // Check if we need to set the MinimizeLatency flag
        if (m_bMinimizeLatency)
        {
            pValues->SetPropertyULONG32("MinimizeLatency", 1);
        }
        // Add the requested meta info (if any)
        if (pszAcceptMetaInfo)
        {
            // Create the IHXValues of available meta info
            IHXValues* pMetaInfo = NULL;
            m_pCommonClassFactory->CreateInstance(CLSID_IHXValues, (void**) &pMetaInfo);
            if (pMetaInfo)
            {
                // Add the available meta info
                pMetaInfo->SetPropertyULONG32("Width",   m_ulDisplayWidth);
                pMetaInfo->SetPropertyULONG32("Height",  m_ulDisplayHeight);
                pMetaInfo->SetPropertyULONG32("Bitrate", m_ulBitrate);
                // Add any requested meta info the file header
                AddMetaInfo(pMetaInfo, pszAcceptMetaInfo, pValues);
            }
            HX_RELEASE(pMetaInfo);
        }

        // Assign to the out parameter
        HX_RELEASE(rpFileHeader);
        rpFileHeader = pValues;
        rpFileHeader->AddRef();
    }
    HX_RELEASE(pValues);

    return retVal;
}

HX_RESULT PXWireFormatManager::GetStreamHeader(REF(IHXValues*) rpStreamHeader)
{
    HX_RESULT retVal = HXR_FAIL;

    // Check to see if we have valid values for all the
    // required members
    if (m_pStreamMimeType && m_pASMRuleBook && m_ulBitrate &&
        m_ulDuration && m_pCommonClassFactory)
    {
        IHXValues* pValues = NULL;
        retVal              = m_pCommonClassFactory->CreateInstance(CLSID_IHXValues,
                                                                    (void**) &pValues);
        if (SUCCEEDED(retVal))
        {
            // Set some properties
            pValues->SetPropertyCString("MimeType",          m_pStreamMimeType);
            pValues->SetPropertyCString("ASMRuleBook",       m_pASMRuleBook);
            pValues->SetPropertyULONG32("StreamNumber",      0);
            pValues->SetPropertyULONG32("MaxBitRate",        m_ulBitrate);
            pValues->SetPropertyULONG32("AvgBitRate",        m_ulBitrate);
            pValues->SetPropertyULONG32("StartTime",         m_ulStart);
            pValues->SetPropertyULONG32("Preroll",           m_ulPreroll);
            pValues->SetPropertyULONG32("PreData",           m_ulPreData);
            pValues->SetPropertyULONG32("Duration",          m_ulDuration);
            pValues->SetPropertyULONG32("StreamVersion",     m_ulStreamVersion);
            pValues->SetPropertyULONG32("ContentVersion",    m_ulContentVersion);
            pValues->SetPropertyULONG32("RendererFlags",     m_ulRendererFlags);
            pValues->SetPropertyULONG32("BackgroundOpacity", m_ulBackgroundOpacity);
            if (m_bPreDataAtStart)
            {
                pValues->SetPropertyULONG32("PredataAtStart",   1);
            }
            if (m_bPrerollAfterSeek)
            {
                pValues->SetPropertyULONG32("PrerollAfterSeek", 1);
            }

            // Create an IHXBuffer
            IHXBuffer* pOpBuffer = NULL;
            retVal                = m_pCommonClassFactory->CreateInstance(CLSID_IHXBuffer,
                                                                          (void**) &pOpBuffer);
            if (SUCCEEDED(retVal))
            {
                // Compute the size. When we call PackStreamHeader(,FALSE), it
                // only computes the size and doesn't pack the stream header.
                BYTE*  pBuf   = NULL;
                UINT32 ulSize = PackStreamHeader(pBuf, FALSE);
                retVal        = pOpBuffer->SetSize(ulSize);
                if (SUCCEEDED(retVal))
                {
                    if (HX_GET_MAJOR_VERSION(m_ulStreamVersion) <=
                        HX_GET_MAJOR_VERSION(m_ulHighestSupportedStreamVersion) &&
                        HX_GET_MINOR_VERSION(m_ulStreamVersion) <=
                        HX_GET_MINOR_VERSION(m_ulHighestSupportedStreamVersion))
                    {
                        // Now we call PackStreamHeader(,TRUE), which actually
                        // packs the stream header
                        pBuf = pOpBuffer->GetBuffer();
                        PackStreamHeader(pBuf, TRUE);
                    }
                    else
                    {
                        retVal = HXR_FAIL;
                    }

                    if (SUCCEEDED(retVal))
                    {
                        // Set the opaque data property
                        pValues->SetPropertyBuffer("OpaqueData", pOpBuffer);
                        // Assign the out parameter
                        HX_RELEASE(rpStreamHeader);
                        rpStreamHeader = pValues;
                        rpStreamHeader->AddRef();
                    }
                }
            }
            HX_RELEASE(pOpBuffer);
        }
        HX_RELEASE(pValues);
    }

    return retVal;
}

HX_RESULT PXWireFormatManager::OnHeader(IHXValues* pHeader)
{
    HX_RESULT retVal = HXR_FAIL;

    if (pHeader)
    {
        pHeader->GetPropertyULONG32("Duration",          m_ulDuration);
        pHeader->GetPropertyULONG32("ContentVersion",    m_ulContentVersion);
        pHeader->GetPropertyULONG32("RendererFlags",     m_ulRendererFlags);
        pHeader->GetPropertyULONG32("BackgroundOpacity", m_ulBackgroundOpacity);

        IHXBuffer* pBuffer = NULL;
        retVal              = pHeader->GetPropertyBuffer("OpaqueData", pBuffer);
        if (SUCCEEDED(retVal))
        {
            if (m_ulStreamVersion <= m_ulHighestSupportedStreamVersion)
            {
                // Get the display width and display height
                BYTE *pBuf = pBuffer->GetBuffer();
                UnPack32(pBuf, m_ulDisplayWidth);
                UnPack32(pBuf, m_ulDisplayHeight);

                // Get default URL
                HX_RELEASE(m_pDefaultURLStr);
                retVal = UnPackStringBuffer(pBuf, &m_pDefaultURLStr);
                if (SUCCEEDED(retVal))
                {
                    // Unpack total mimes
                    UINT32 ulTotalMimes = 0;
                    UnPack32(pBuf, ulTotalMimes);

                    // Unpack codec mimes
                    UINT32 ulNumCodecs = 0;
                    UnPack32(pBuf, ulNumCodecs);
                    ReleaseAllCodecMimes();
                    if (ulNumCodecs > 0)
                    {
                        for (UINT32 i = 0; i < ulNumCodecs; i++)
                        {
                            IHXBuffer* pMime = NULL;
                            retVal            = UnPackStringBuffer(pBuf, &pMime);
                            if (SUCCEEDED(retVal))
                            {
                                retVal = AddCodecMime(pMime);
                            }
                            HX_RELEASE(pMime);

                            if (FAILED(retVal))
                            {
                                break;
                            }
                        }
                    }

                    if (SUCCEEDED(retVal))
                    {
                        // Unpack fxpackage mimes
                        UINT32 ulNumFXPackages = 0;
                        UnPack32(pBuf, ulNumFXPackages);
                        ReleaseAllFXPackageMimes();
                        if (ulNumFXPackages > 0)
                        {
                            for (UINT32 i = 0; i < ulNumFXPackages; i++)
                            {
                                IHXBuffer* pMime = NULL;
                                retVal            = UnPackStringBuffer(pBuf, &pMime);
                                if (SUCCEEDED(retVal))
                                {
                                    retVal = AddFXPackageMime(pMime);
                                }
                                HX_RELEASE(pMime);

                                if (FAILED(retVal))
                                {
                                    break;
                                }
                            }
                        }

                        if (SUCCEEDED(retVal))
                        {
                            // If the stream version is greater than or equal to 1.1.0.0,
                            // then get the background color
                            if (m_ulStreamVersion >= U2_STREAM_VERSION)
                            {
                                UnPack32(pBuf, m_ulBackgroundColor);
                            }
                        }
                    }
                }
            }
            else
            {
                retVal = HXR_FAIL;
            }
        }
        HX_RELEASE(pBuffer);
    }

    if (FAILED(retVal))
    {
        // We had an error, so reset the state
        m_ulDisplayWidth  = 0;
        m_ulDisplayHeight = 0;
        HX_RELEASE(m_pDefaultURLStr);
        ReleaseAllCodecMimes();
        ReleaseAllFXPackageMimes();
    }

    return retVal;
}

HX_RESULT PXWireFormatManager::GetPacketType(IHXPacket* pPacket, REF(UINT32) rulType)
{
    HX_RESULT retVal = HXR_OK;

    if (pPacket)
    {
        IHXBuffer* pBuffer = pPacket->GetBuffer();
        if (pBuffer)
        {
            BYTE* pBuf = pBuffer->GetBuffer();
            if (pBuf)
            {
                UnPack32(pBuf, rulType);
            }
            else
            {
                retVal = HXR_FAIL;
            }
        }
        else
        {
            retVal = HXR_FAIL;
        }
        HX_RELEASE(pBuffer);
    }
    else
    {
        retVal = HXR_INVALID_PARAMETER;
    }

    return retVal;
}

HX_RESULT PXWireFormatManager::GetImageHeaderInfo(IHXPacket* pPacket, REF(UINT32) rulHandle,
                                                  REF(UINT32) rulFileLength, REF(UINT32) rulFlags,
                                                  IHXBuffer** ppMimeStr, REF(UINT32) rulOpaqueSize)
{
    HX_RESULT retVal = HXR_OK;

    if (pPacket && ppMimeStr)
    {
        IHXBuffer* pBuffer = pPacket->GetBuffer();
        if (pBuffer)
        {
            BYTE* pBuf = pBuffer->GetBuffer();
            if (pBuf)
            {
                UINT32 ulType = 0xFFFFFFFF;
                UnPack32(pBuf, ulType);

                if (ulType == kPacketTypeImageHeader)
                {
                    UINT32      ulHandle = 0;
                    UINT32      ulLength = 0;
                    UINT32      ulFlags  = 0;
                    IHXBuffer* pMimeStr = NULL;

                    UnPack32(pBuf, ulHandle);
                    UnPack32(pBuf, ulLength);
                    UnPack32(pBuf, ulFlags);

                    retVal = UnPackStringBuffer(pBuf, &pMimeStr);
                    if (SUCCEEDED(retVal))
                    {
                        // Assign out parameters
                        rulHandle      = ulHandle;
                        rulFileLength  = ulLength;
                        rulFlags       = ulFlags;
                        *ppMimeStr     = pMimeStr;
                        (*ppMimeStr)->AddRef();
                        // XXXMEH - this SHOULD come from the image header data,
                        // instead of having it hard-coded in the renderer. Having it
                        // hard-coded introduces codec<->renderer dependencies where
                        // none should exist. However, the current wire format does
                        // not have this information.
                        rulOpaqueSize  = GetOpaqueSize((const char*) pMimeStr->GetBuffer());
                    }
                    HX_RELEASE(pMimeStr);
                }
                else
                {
                    retVal = HXR_FAIL;
                }
            }
            else
            {
                retVal = HXR_FAIL;
            }
        }
        else
        {
            retVal = HXR_FAIL;
        }
        HX_RELEASE(pBuffer);
    }
    else
    {
        retVal = HXR_INVALID_PARAMETER;
    }

    return retVal;
}

HX_RESULT PXWireFormatManager::SetImageHeaderInfo(UINT32 ulHandle, UINT32 ulFileLength, UINT32 ulFlags,
                                                  const char* pszMime, UINT32 ulTimeStamp, REF(IHXPacket*) rpPacket)
{
    HX_RESULT retVal = HXR_FAIL;

    if (pszMime)
    {
        IHXBuffer* pMimeStr = NULL;
        retVal               = SetString(pszMime, pMimeStr);
        if (SUCCEEDED(retVal))
        {
            retVal = SetImageHeaderInfo(ulHandle, ulFileLength, ulFlags, pMimeStr, ulTimeStamp, rpPacket);
        }
        HX_RELEASE(pMimeStr);
    }

    return retVal;
}

HX_RESULT PXWireFormatManager::SetImageHeaderInfo(UINT32 ulHandle, UINT32 ulFileLength, UINT32 ulFlags,
                                                  IHXBuffer* pMimeStr, UINT32 ulTimeStamp, REF(IHXPacket*) rpPacket)
{
    HX_RESULT retVal = HXR_FAIL;

    if (ulHandle && ulFileLength && pMimeStr)
    {
        // Create an IHXBuffer
        IHXBuffer* pBuffer = NULL;
        retVal              = m_pCommonClassFactory->CreateInstance(CLSID_IHXBuffer,
                                                                    (void**) &pBuffer);
        if (SUCCEEDED(retVal))
        {
            // Compute the size
            UINT32 ulSize = 0;
            ulSize       += 16; // packet type, handle, length, flags
            ulSize       += 2;  // mime type string length
            UINT32 ulLen  = strlen((const char*) pMimeStr->GetBuffer());
            if (ulLen)
            {
                ulSize += ulLen + 1;
            }

            // Set the size of the buffer
            retVal = pBuffer->SetSize(ulSize);
            if (SUCCEEDED(retVal))
            {
                // Pack the buffer
                BYTE* pBuf = pBuffer->GetBuffer();
                Pack32(pBuf,           kPacketTypeImageHeader);
                Pack32(pBuf,           ulHandle);
                Pack32(pBuf,           ulFileLength);
                Pack32(pBuf,           ulFlags);
                PackStringBuffer(pBuf, pMimeStr);

                // Create an IHXPacket
                IHXPacket* pPacket = NULL;
                retVal              = m_pCommonClassFactory->CreateInstance(CLSID_IHXPacket,
                                                                            (void**) &pPacket);
                if (SUCCEEDED(retVal))
                {
                    retVal = pPacket->Set(pBuffer,           // opaque data
                                          ulTimeStamp,       // time stamp
                                          0,                 // stream 0
                                          HX_ASM_SWITCH_ON, // ASM flag
                                          1);                // ASM rule 1
                    if (SUCCEEDED(retVal))
                    {
                        // Assign to out parameter
                        HX_RELEASE(rpPacket);
                        rpPacket = pPacket;
                        rpPacket->AddRef();
                    }
                }
                HX_RELEASE(pPacket);
            }
        }
        HX_RELEASE(pBuffer);
    }

    return retVal;
}

HX_RESULT PXWireFormatManager::GetImageDataHandle(IHXPacket* pPacket, REF(UINT32) rulHandle)
{
    HX_RESULT retVal = HXR_FAIL;

    if (pPacket)
    {
        IHXBuffer* pBuffer = pPacket->GetBuffer();
        if (pBuffer)
        {
            BYTE* pBuf = pBuffer->GetBuffer();
            if (pBuf)
            {
                // Make sure this is an image data packet
                UINT32 ulType = 0xFFFFFFFF;
                UnPack32(pBuf, ulType);

                if (ulType == kPacketTypeImageData)
                {
                    // Unpack the handle
                    UnPack32(pBuf, rulHandle);
                    retVal = HXR_OK;
                }
            }
        }
        HX_RELEASE(pBuffer);
    }

    return retVal;
}

HX_RESULT PXWireFormatManager::GetImageDataInfo(IHXPacket* pPacket, UINT32 ulOpaqueSize,
                                                REF(IHXBuffer*) rpOpaque, REF(IHXBuffer*) rpData)
{
    HX_RESULT retVal = HXR_FAIL;

    if (pPacket)
    {
        IHXBuffer* pBuffer = pPacket->GetBuffer();
        if (pBuffer)
        {
            BYTE* pBuf = pBuffer->GetBuffer();
            if (pBuf)
            {
                // Make sure this is an image data packet
                UINT32 ulType = 0xFFFFFFFF;
                UnPack32(pBuf, ulType);

                if (ulType == kPacketTypeImageData)
                {
                    // Create a nested buffer class
                    CHXNestedBuffer *pOpaque = NULL;
                    retVal = CHXNestedBuffer::CreateObject(&pOpaque);
                    if (SUCCEEDED(retVal))
                    {
                        // Addref the object
                        pOpaque->AddRef();
                        // Init the object
                        retVal = pOpaque->Init(pBuffer, 8, ulOpaqueSize);
                        if (SUCCEEDED(retVal))
                        {
                            // Create a nested buffer class
                            CHXNestedBuffer *pData = NULL;
                            retVal = CHXNestedBuffer::CreateObject(&pData);
                            if (SUCCEEDED(retVal))
                            {
                                // Addref the object
                                pData->AddRef();
                                // Init the object
                                UINT32 ulDataOffset = 8 + ulOpaqueSize;
                                retVal = pData->Init(pBuffer, ulDataOffset, pBuffer->GetSize() - ulDataOffset);
                                if (SUCCEEDED(retVal))
                                {
                                    // Assign the out parameters
                                    HX_RELEASE(rpOpaque);
                                    rpOpaque = pOpaque;
                                    rpOpaque->AddRef();
                                    HX_RELEASE(rpData);
                                    rpData   = pData;
                                    rpData->AddRef();
                                    retVal = HXR_OK;
                                }
                            }
                            HX_RELEASE(pData);
                        }
                    }
                    HX_RELEASE(pOpaque);
                }
            }
        }
        HX_RELEASE(pBuffer);
    }

    return retVal;
}

HX_RESULT PXWireFormatManager::SetImageDataInfo(UINT32 ulHandle, IHXBuffer* pData, IHXBuffer* pOpaque,
                                                UINT32 ulPacketIndex, UINT32 ulTimeStamp, BOOL bRequired,
                                                REF(IHXPacket*) rpPacket)
{
    HX_RESULT retVal = HXR_FAIL;

    if (ulHandle && pData)
    {
        // Create an IHXBuffer
        IHXBuffer* pBuffer = NULL;
        retVal              = m_pCommonClassFactory->CreateInstance(CLSID_IHXBuffer,
                                                                    (void**) &pBuffer);
        if (SUCCEEDED(retVal))
        {
            // Compute the size
// XXXMEH - move seq num into opaque temporarily
//            UINT32 ulSize = 12; // packet type, handle, seq num
            UINT32 ulSize = 8; // packet type, handle
            if (pOpaque)
            {
                ulSize += pOpaque->GetSize();
            }
            ulSize += pData->GetSize();

            // Set the size of the buffer
            retVal = pBuffer->SetSize(ulSize);
            if (SUCCEEDED(retVal))
            {
                // Pack the buffer
                //
                // First we pack the generic (codec-agnostic) header
                BYTE* pBuf = pBuffer->GetBuffer();
                Pack32(pBuf, kPacketTypeImageData);
                Pack32(pBuf, ulHandle);
// XXXMEH - move seq num into opaque temporarily
//                Pack32(pBuf, ulPacketIndex);
                // Now we pack the codec-specific per-packet opaque data
                if (pOpaque)
                {
                    memcpy(pBuf, pOpaque->GetBuffer(), pOpaque->GetSize()); /* Flawfinder: ignore */
                    pBuf += pOpaque->GetSize();
                }
                // Now we pack the codec-specific data straight from the file
                memcpy(pBuf, pData->GetBuffer(), pData->GetSize()); /* Flawfinder: ignore */
                pBuf += pData->GetSize();

                // Create an IHXPacket
                IHXPacket* pPacket = NULL;
                retVal              = m_pCommonClassFactory->CreateInstance(CLSID_IHXPacket,
                                                                            (void**) &pPacket);
                if (SUCCEEDED(retVal))
                {
                    retVal = pPacket->Set(pBuffer,              // opaque data
                                          ulTimeStamp,          // time stamp
                                          0,                    // stream 0
                                          HX_ASM_SWITCH_ON,    // ASM flag
                                          (bRequired ? 1 : 0)); // ASM rule (0 if not required, 1 if required)
                    if (SUCCEEDED(retVal))
                    {
                        // Assign to out parameter
                        HX_RELEASE(rpPacket);
                        rpPacket = pPacket;
                        rpPacket->AddRef();
                    }
                }
                HX_RELEASE(pPacket);
            }
        }
        HX_RELEASE(pBuffer);
    }

    return retVal;
}

HX_RESULT PXWireFormatManager::GetEffectType(IHXPacket* pPacket, REF(UINT32) rulType)
{
    HX_RESULT retVal = HXR_FAIL;

    if (pPacket)
    {
        IHXBuffer* pBuffer = pPacket->GetBuffer();
        if (pBuffer)
        {
            BYTE* pBuf = pBuffer->GetBuffer();
            if (pBuf)
            {
                UINT32 ulPacketType = 0;
                UnPack32(pBuf, ulPacketType);
                if (ulPacketType == PXWireFormatManager::kPacketTypeEffect)
                {
                    UINT32 ulFlags      = 0;
                    UINT32 ulEffectType = 0;
                    UnPack32(pBuf, ulFlags);
                    UnPack32(pBuf, rulType);
                    retVal = HXR_OK;
                }
            }
        }
        HX_RELEASE(pBuffer);
    }

    return retVal;
}

HX_RESULT PXWireFormatManager::GetEffectInfo(IHXPacket* pPacket, PXEffect** ppEffect)
{
    HX_RESULT retVal = HXR_OK;

    if (pPacket && ppEffect)
    {
        IHXBuffer* pBuffer = pPacket->GetBuffer();
        if (pBuffer)
        {
            BYTE* pBuf = pBuffer->GetBuffer();
            if (pBuf)
            {
                UINT32 ulType = 0xFFFFFFFF;
                UnPack32(pBuf, ulType);

                if (ulType == kPacketTypeEffect)
                {
                    // Create an effect object
                    PXEffect* pEffect = NULL;
                    retVal            = PXEffect::CreateObject(&pEffect);
                    if (SUCCEEDED(retVal))
                    {
                        // AddRef the object
                        pEffect->AddRef();

                        // Initialize it from the opaque data
                        pBuf -= 4; // back up to the beginning
                        pEffect->UnPack(pBuf, HX_GET_MAJOR_VERSION(m_ulStreamVersion),
                                              HX_GET_MINOR_VERSION(m_ulStreamVersion));
                        if (SUCCEEDED(retVal))
                        {
                            // Assign the out parameter
                            *ppEffect = pEffect;
                            (*ppEffect)->AddRef();
                        }
                    }
                    // Release our ref on the packet
                    HX_RELEASE(pEffect);
                }
                else
                {
                    retVal = HXR_FAIL;
                }
            }
            else
            {
                retVal = HXR_FAIL;
            }
        }
        else
        {
            retVal = HXR_FAIL;
        }
        HX_RELEASE(pBuffer);
    }
    else
    {
        retVal = HXR_INVALID_PARAMETER;
    }

    return retVal;
}

HX_RESULT PXWireFormatManager::SetEffectPacketParameters(IHXPacket* pPacket,
	UINT32 ulEffectType, UINT32 ulStart, UINT32 ulDuration)
{
    HX_RESULT retVal = HXR_FAIL;

    if (pPacket)
    {
        IHXBuffer* pOldBuffer    = NULL;
        UINT32      ulOldTime     = 0;
        UINT16      usOldStrNum   = 0;
        UINT8       ucOldASMFlags = 0;
        UINT16      usOldRuleNum  = 0;
        retVal = pPacket->Get(pOldBuffer, ulOldTime, usOldStrNum, ucOldASMFlags,
		    usOldRuleNum);

        if (SUCCEEDED(retVal))
        {
            PXEffect* pEffect = NULL;
            retVal            = PXEffect::CreateObject(&pEffect);
            if (SUCCEEDED(retVal))
            {
		pEffect->AddRef();
                BYTE* pBuf = pOldBuffer->GetBuffer();
                pEffect->UnPack(pBuf,
                                HX_GET_MAJOR_VERSION(m_ulStreamVersion),
                                HX_GET_MINOR_VERSION(m_ulStreamVersion));
                // Update the parameters
                pEffect->SetEffectType((BYTE) ulEffectType);
                pEffect->SetStart(ulStart);
                pEffect->SetDuration(ulDuration);

                // Get a new buffer for it
                IHXBuffer* pNewBuffer = NULL;
                retVal                 = m_pCommonClassFactory->CreateInstance(CLSID_IHXBuffer,
                                                                               (void**) &pNewBuffer);
                if (SUCCEEDED(retVal))
                {
                    // Set its size
                    retVal = pNewBuffer->SetSize(pEffect->PackedSize(HX_GET_MAJOR_VERSION(m_ulStreamVersion),
                                                                     HX_GET_MINOR_VERSION(m_ulStreamVersion)));
                    if (SUCCEEDED(retVal))
                    {
                        // Pack the new effect
                        BYTE* pBuf = pNewBuffer->GetBuffer();
                        pEffect->Pack(pBuf,
                                      HX_GET_MAJOR_VERSION(m_ulStreamVersion),
                                      HX_GET_MINOR_VERSION(m_ulStreamVersion));
                        // Set the new buffer into the packet
                        retVal = pPacket->Set(pNewBuffer, ulOldTime, usOldStrNum,
                                              ucOldASMFlags, usOldRuleNum);
                    }
                }
                HX_RELEASE(pNewBuffer);
            }
            HX_RELEASE(pEffect);
        }
        HX_RELEASE(pOldBuffer);
    }

    return retVal;
}

HX_RESULT PXWireFormatManager::SetEffectInfo(PXEffect* pEffect, UINT32 ulTimeStamp, REF(IHXPacket*) rpPacket)
{
    HX_RESULT retVal = HXR_FAIL;

    if (pEffect)
    {
        // Create an IHXBuffer
        IHXBuffer* pBuffer = NULL;
        retVal              = m_pCommonClassFactory->CreateInstance(CLSID_IHXBuffer,
                                                                    (void**) &pBuffer);
        if (SUCCEEDED(retVal))
        {
            // Compute the size
            UINT32 ulSize = pEffect->PackedSize(HX_GET_MAJOR_VERSION(m_ulStreamVersion),
                                                HX_GET_MINOR_VERSION(m_ulStreamVersion));

            // Set the size of the buffer
            retVal = pBuffer->SetSize(ulSize);
            if (SUCCEEDED(retVal))
            {
                // Pack the buffer
                BYTE* pBuf = pBuffer->GetBuffer();
                pEffect->Pack(pBuf,
                              HX_GET_MAJOR_VERSION(m_ulStreamVersion),
                              HX_GET_MINOR_VERSION(m_ulStreamVersion));

                // Create an IHXPacket
                IHXPacket* pPacket = NULL;
                retVal              = m_pCommonClassFactory->CreateInstance(CLSID_IHXPacket,
                                                                            (void**) &pPacket);
                if (SUCCEEDED(retVal))
                {
                    retVal = pPacket->Set(pBuffer,           // opaque data
                                          ulTimeStamp,       // time stamp
                                          0,                 // stream 0
                                          HX_ASM_SWITCH_ON, // ASM flag
                                          1);                // ASM rule 1
                    if (SUCCEEDED(retVal))
                    {
                        // Assign to out parameter
                        HX_RELEASE(rpPacket);
                        rpPacket = pPacket;
                        rpPacket->AddRef();
                    }
                }
                HX_RELEASE(pPacket);
            }
        }
        HX_RELEASE(pBuffer);
    }

    return retVal;
}

HX_RESULT PXWireFormatManager::SetCookieInfo(UINT32 ulNumCookies, IHXBuffer** ppURL, IHXBuffer** ppCookie,
                                             UINT32 ulTimeStamp, REF(IHXPacket*) rpPacket)
{
    HX_RESULT retVal = HXR_OK;

    if (ulNumCookies && ppURL && ppCookie)
    {
        // Compute size of packet
        UINT32 ulSize = 8;
        UINT32 i      = 0;
        for (i = 0; i < ulNumCookies; i++)
        {
            if (ppURL[i] && ppCookie[i])
            {
                ulSize += 4;                      // Size of URL
                ulSize += ppURL[i]->GetSize();    // URL
                ulSize += 4;                      // Size of Set-Cookie
                ulSize += ppCookie[i]->GetSize(); // Set-Cookie
            }
            else
            {
                retVal = HXR_FAIL;

            }
        }

        if (SUCCEEDED(retVal))
        {
            // Create opaque data buffer
            IHXBuffer* pBuffer = NULL;
            retVal              = m_pCommonClassFactory->CreateInstance(CLSID_IHXBuffer, (void**) &pBuffer);
            if (SUCCEEDED(retVal))
            {
                // Set its size
                retVal = pBuffer->SetSize(ulSize);
                if (SUCCEEDED(retVal))
                {
                    // Pack the buffer
                    BYTE* pBuf = pBuffer->GetBuffer();
                    Pack32(pBuf, kPacketTypeCookie);
                    Pack32(pBuf, ulNumCookies);
                    for (i = 0; i < ulNumCookies; i++)
                    {
                        Pack32(pBuf, ppURL[i]->GetSize());
                        memcpy(pBuf, ppURL[i]->GetBuffer(), ppURL[i]->GetSize()); /* Flawfinder: ignore */
                        pBuf += ppURL[i]->GetSize();
                        Pack32(pBuf, ppCookie[i]->GetSize());
                        memcpy(pBuf, ppCookie[i]->GetBuffer(), ppCookie[i]->GetSize()); /* Flawfinder: ignore */
                        pBuf += ppCookie[i]->GetSize();
                    }
                    // Create an IHXPacket object
                    IHXPacket* pPacket = NULL;
                    retVal              = m_pCommonClassFactory->CreateInstance(CLSID_IHXPacket, (void**) &pPacket);
                    if (SUCCEEDED(retVal))
                    {
                        // Set the packet parameters
                        retVal = pPacket->Set(pBuffer,           // opaque data
                                              ulTimeStamp,       // time stamp
                                              0,                 // stream 0
                                              HX_ASM_SWITCH_ON, // ASM flag
                                              0);                // ASM rule 0
                        if (SUCCEEDED(retVal))
                        {
                            // Assign the out parameters
                            HX_RELEASE(rpPacket);
                            rpPacket = pPacket;
                            rpPacket->AddRef();
                        }
                    }
                    HX_RELEASE(pPacket);
                }
            }
            HX_RELEASE(pBuffer);
        }
    }
    else
    {
        retVal = HXR_FAIL;
    }

    return retVal;
}

HX_RESULT PXWireFormatManager::GetNumCookies(IHXPacket* pPacket, REF(UINT32) rulNumCookies)
{
    HX_RESULT retVal = HXR_FAIL;

    if (pPacket)
    {
        IHXBuffer* pBuffer = pPacket->GetBuffer();
        if (pBuffer)
        {
            BYTE*  pBuf         = pBuffer->GetBuffer();
            UINT32 ulPacketType = 0;
            UINT32 ulNumCookies = 0;
            UnPack32(pBuf, ulPacketType);
            UnPack32(pBuf, ulNumCookies);

            if (ulPacketType == kPacketTypeCookie)
            {
                retVal        = HXR_OK;
                rulNumCookies = ulNumCookies;
            }
        }
        HX_RELEASE(pBuffer);
    }

    return retVal;
}

HX_RESULT PXWireFormatManager::GetCookie(IHXPacket* pPacket, UINT32 ulIndex,
                                         REF(IHXBuffer*) rpURL, REF(IHXBuffer*) rpBuffer)
{
    HX_RESULT retVal = HXR_FAIL;

    if (pPacket)
    {
        IHXBuffer* pBuffer = pPacket->GetBuffer();
        if (pBuffer)
        {
            BYTE*  pBuf         = pBuffer->GetBuffer();
            UINT32 ulPacketType = 0;
            UINT32 ulNumCookies = 0;
            UnPack32(pBuf, ulPacketType);
            UnPack32(pBuf, ulNumCookies);

            if (ulPacketType == kPacketTypeCookie &&
                ulIndex      <  ulNumCookies)
            {
                // Advance up to the proper cookie
                UINT32 ulURLSize    = 0;
                UINT32 ulCookieSize = 0;
                for (UINT32 i = 0; i < ulIndex; i++)
                {
                    UnPack32(pBuf, ulURLSize);
                    pBuf += ulURLSize;
                    UnPack32(pBuf, ulCookieSize);
                    pBuf += ulCookieSize;
                }
                // Get the size of the URL
                UnPack32(pBuf, ulURLSize);
                // Get the offset of the URL
                UINT32 ulURLOffset = pBuf - pBuffer->GetBuffer();
                // Advance to the cookie
                pBuf += ulURLSize;
                // Create a nested buffer class
                CHXNestedBuffer *pNestedURLBuffer = NULL;
                retVal = CHXNestedBuffer::CreateObject(&pNestedURLBuffer);
                if (SUCCEEDED(retVal))
                {
                    // Addref the object
                    pNestedURLBuffer->AddRef();
                    // Init the object
                    retVal = pNestedURLBuffer->Init(pBuffer, ulURLOffset, ulURLSize);
                    if (SUCCEEDED(retVal))
                    {
                        // Get the size of the cookie
                        UnPack32(pBuf, ulCookieSize);
                        // Get the offset of this cookie
                        UINT32 ulCookieOffset = pBuf - pBuffer->GetBuffer();
                        // Create a nested buffer class
                        CHXNestedBuffer *pNestedCookieBuffer = NULL;
                        retVal = CHXNestedBuffer::CreateObject(&pNestedCookieBuffer);
                        if (SUCCEEDED(retVal))
                        {
                            // Addref the object
                            pNestedCookieBuffer->AddRef();
                            // Init the object
                            retVal = pNestedCookieBuffer->Init(pBuffer, ulCookieOffset, ulCookieSize);
                            if (SUCCEEDED(retVal))
                            {
                                // Assign the nested buffer to the out parameter
                                HX_RELEASE(rpURL);
                                retVal = pNestedURLBuffer->QueryInterface(IID_IHXBuffer, (void**) &rpURL);
                                if (SUCCEEDED(retVal))
                                {
                                    HX_RELEASE(rpBuffer);
                                    retVal = pNestedCookieBuffer->QueryInterface(IID_IHXBuffer, (void**) &rpBuffer);
                                }
                            }
                        }
                        HX_RELEASE(pNestedCookieBuffer);
                    }
                }
                HX_RELEASE(pNestedURLBuffer);
            }
        }
        HX_RELEASE(pBuffer);
    }

    return retVal;
}

HX_RESULT PXWireFormatManager::SetNoOpInfo(UINT32 ulSize, UINT32 ulTimeStamp, REF(IHXPacket*) rpPacket)
{
    HX_RESULT retVal = HXR_FAIL;

    if (ulSize >= 4)
    {
        IHXBuffer* pBuffer = NULL;
        retVal              = m_pCommonClassFactory->CreateInstance(CLSID_IHXBuffer, (void**) &pBuffer);
        if (SUCCEEDED(retVal))
        {
            retVal = pBuffer->SetSize(ulSize);
            if (SUCCEEDED(retVal))
            {
                BYTE* pBuf = pBuffer->GetBuffer();
                Pack32(pBuf, 0xFFFFFFFF);
                
                IHXPacket* pPacket = NULL;
                retVal              = m_pCommonClassFactory->CreateInstance(CLSID_IHXPacket, (void**) &pPacket);
                if (SUCCEEDED(retVal))
                {
                    // Set the packet parameters
                    retVal = pPacket->Set(pBuffer,           // opaque data
                                          ulTimeStamp,       // time stamp
                                          0,                 // stream 0
                                          HX_ASM_SWITCH_ON, // ASM flag
                                          0);                // ASM rule 0
                    if (SUCCEEDED(retVal))
                    {
                        // Assign the out parameters
                        HX_RELEASE(rpPacket);
                        rpPacket = pPacket;
                        rpPacket->AddRef();
                    }
                }
                HX_RELEASE(pPacket);
            }
        }
        HX_RELEASE(pBuffer);
    }

    return retVal;
}

HX_RESULT PXWireFormatManager::GetBackChannelInfo(IHXPacket* pPacket, REF(UINT32) rulHandle,
                                                  REF(UINT32) rulTimeStopped)
{
    HX_RESULT retVal = HXR_FAIL;

    if (pPacket)
    {
        IHXBuffer* pBuffer = pPacket->GetBuffer();
        if (pBuffer)
        {
            BYTE* pBuf = pBuffer->GetBuffer();
            if (pBuf)
            {
                UINT32 ulOpCode = UnPackUINT32(pBuf);
                if (ulOpCode == 0x34414453) // "4ADS"
                {
                    rulHandle      = UnPackUINT32(pBuf);
                    rulTimeStopped = UnPackUINT32(pBuf);
                    retVal         = HXR_OK;
                }
            }
        }
        HX_RELEASE(pBuffer);
    }

    return retVal;
}

HX_RESULT PXWireFormatManager::SetBackChannelInfo(UINT32 ulHandle, UINT32 ulTimeStopped,
                                                  REF(IHXPacket*) rpPacket)
{
    HX_RESULT retVal = HXR_OK;

    if (ulHandle)
    {
        IHXBuffer* pBuffer = NULL;
        retVal              = m_pCommonClassFactory->CreateInstance(CLSID_IHXBuffer,
                                                                    (void**) &pBuffer);
        if (SUCCEEDED(retVal))
        {
            retVal = pBuffer->SetSize(12);
            if (SUCCEEDED(retVal))
            {
                // Pack the opaque buffer
                BYTE* pBuf = pBuffer->GetBuffer();
                PackUINT32(pBuf, 0x34414453);
                PackUINT32(pBuf, ulHandle);
                PackUINT32(pBuf, ulTimeStopped);
                // Create the packet
                IHXPacket* pPacket = NULL;
                retVal              = m_pCommonClassFactory->CreateInstance(CLSID_IHXPacket,
                                                                            (void**) &pPacket);
                if (SUCCEEDED(retVal))
                {
                    // Set the packet parameters
                    retVal = pPacket->Set(pBuffer,            // opaque data
                                          0,                  // time stamp
                                          0,                  // stream 0
                                          HX_ASM_SWITCH_OFF, // ASM flag
                                          0);                 // 
                    if (SUCCEEDED(retVal))
                    {
                        // Pass the packet back
                        HX_RELEASE(rpPacket);
                        rpPacket = pPacket;
                        rpPacket->AddRef();
                    }
                }
                HX_RELEASE(pPacket);
            }
        }
        HX_RELEASE(pBuffer);
    }
    else
    {
        retVal = HXR_INVALID_PARAMETER;
    }

    return retVal;
}

UINT32 PXWireFormatManager::GetEffectWireSize(PXEffect* pEffect)
{
    UINT32 ulRet = 0;

    if (pEffect)
    {
        ulRet += pEffect->PackedSize(HX_GET_MAJOR_VERSION(m_ulStreamVersion),
                                     HX_GET_MINOR_VERSION(m_ulStreamVersion));
        ulRet += kIHXPacketOverhead;
    }

    return ulRet;
}

UINT32 PXWireFormatManager::GetImageWireSize(IHXBuffer* pStreamMimeStr, UINT32 ulImageFileSize)
{
    UINT32 ulRet = 0;

    if (pStreamMimeStr && ulImageFileSize)
    {
        // First we add the image header packet
        //
        // Add fixed size of image header packet
        ulRet += 18;
        // Add stream mime type string length of image header packet
        UINT32 ulMimeLen = strlen((const char*) pStreamMimeStr->GetBuffer());
        if (ulMimeLen)
        {
            ulRet += ulMimeLen + 1;
        }
        // Add the IHXPacket overhead of the image header packet
        ulRet += kIHXPacketOverhead;

        // Now we make a worst-case estimate of the number of packets
        // for this image.
        UINT32 ulWorstCaseNumPackets = (ulImageFileSize + kMinImageDataPacketSize - 1) / kMinImageDataPacketSize;
        // Now, based on this estimated number of packets we can
        // compute the overhead
        UINT32 ulWorstCaseOverhead   = (kIHXPacketOverhead + 8 + GetOpaqueSize((const char*) pStreamMimeStr->GetBuffer())) *
                                       ulWorstCaseNumPackets;
        // Now add the wire size for the image data packets - this
        // is the file size plus the worst case overhead
        ulRet += ulImageFileSize;
        ulRet += ulWorstCaseOverhead;
    }

    return ulRet;
}

UINT32 PXWireFormatManager::GetPacketSize(IHXPacket* pPacket)
{
    UINT32 ulSize = 0;

    if (pPacket)
    {
        IHXBuffer* pBuffer = pPacket->GetBuffer();
        if (pBuffer)
        {
            ulSize = pBuffer->GetSize();
        }
        HX_RELEASE(pBuffer);
    }

    return ulSize;
}

UINT32 PXWireFormatManager::GetOpaqueSize(const char* pszMimeType)
{
    UINT32 ulRetVal = kDefaultOpaqueSize;
    if (m_pMapMimeToOpaqueSize)
    {
        void *pVoid = NULL;
        if (m_pMapMimeToOpaqueSize->Lookup(pszMimeType, pVoid))
        {
            ulRetVal = (UINT32) pVoid;
        }
    }
    return ulRetVal;
}

void PXWireFormatManager::ReleaseAllCodecMimes()
{
    if (m_pCodecMimeList)
    {
        LISTPOSITION pos = m_pCodecMimeList->GetHeadPosition();
        while (pos)
        {
            IHXBuffer* pBuffer = (IHXBuffer*) m_pCodecMimeList->GetNext(pos);
            HX_RELEASE(pBuffer);
        }
        m_pCodecMimeList->RemoveAll();
    }
}

void PXWireFormatManager::ReleaseAllFXPackageMimes()
{
    if (m_pFXPackageMimeList)
    {
        LISTPOSITION pos = m_pFXPackageMimeList->GetHeadPosition();
        while (pos)
        {
            IHXBuffer* pBuffer = (IHXBuffer*) m_pFXPackageMimeList->GetNext(pos);
            HX_RELEASE(pBuffer);
        }
        m_pFXPackageMimeList->RemoveAll();
    }
}

void PXWireFormatManager::Deallocate()
{
    HX_RELEASE(m_pContext);
    HX_RELEASE(m_pCommonClassFactory);
    HX_RELEASE(m_pTitleStr);
    HX_RELEASE(m_pAuthorStr);
    HX_RELEASE(m_pCopyrightStr);
    HX_RELEASE(m_pDefaultURLStr);
    ReleaseAllCodecMimes();
    HX_DELETE(m_pCodecMimeList);
    ReleaseAllFXPackageMimes();
    HX_DELETE(m_pFXPackageMimeList);
    HX_DELETE(m_pMapMimeToOpaqueSize);
    HX_RELEASE(m_pASMRuleBook);
    HX_RELEASE(m_pStreamMimeType);
}

void PXWireFormatManager::Reset()
{
    m_ulStreamVersion     = HX_ENCODE_PROD_VERSION(0, 0, 0, 0);
    m_ulStart             = 0;
    m_ulDuration          = 0;
    m_bIsLive             = FALSE;
    m_bMinimizeLatency    = FALSE;
    m_ulPreroll           = 0;
    m_bPrerollAfterSeek   = TRUE;
    m_ulPreData           = 0;
    m_bPreDataAtStart     = TRUE;
    m_ulBitrate           = 0;
    m_ulDisplayWidth      = 0;
    m_ulDisplayHeight     = 0;
    m_bDefaultAspectFlag  = TRUE;
    m_ulDefaultMaxFps     = 0;
    m_ulContentVersion    = HX_ENCODE_PROD_VERSION(0, 0, 0, 0);
    m_ulBackgroundColor   = 0x00000000;
    m_ulBackgroundOpacity = 255;
    m_pCodecListPos       = NULL;
    m_pFXPackageListPos   = NULL;
    m_ulRendererFlags     = 0;
}

UINT32 PXWireFormatManager::PackStreamHeader(BYTE*& rpBuf, BOOL bPack)
{
    UINT32 ulSize = 0;

    if (HX_GET_MAJOR_VERSION(m_ulStreamVersion) <=
        HX_GET_MAJOR_VERSION(m_ulHighestSupportedStreamVersion) &&
        HX_GET_MINOR_VERSION(m_ulStreamVersion) <=
        HX_GET_MINOR_VERSION(m_ulHighestSupportedStreamVersion))
    {
        // Pack/add display width and height
        ulSize += 8;
        if (bPack)
        {
            Pack32(rpBuf, m_ulDisplayWidth);
            Pack32(rpBuf, m_ulDisplayHeight);
        }
        
        // Pack/add size of default URL
        ulSize += 2; // default URL size
        if (m_pDefaultURLStr)
        {
            UINT32 ulLen = (UINT32) strlen((const char*) m_pDefaultURLStr->GetBuffer());
            if (ulLen > 0)
            {
                ulSize += ulLen + 1;
            }
        }
        if (bPack)
        {
            PackStringBuffer(rpBuf, m_pDefaultURLStr);
        }

        // Pack/add total mime count
        ulSize += 4;
        if (bPack)
        {
            Pack32(rpBuf, m_pCodecMimeList->GetCount() + m_pFXPackageMimeList->GetCount());
        }

        // Pack/add codec mime count
        ulSize += 4;
        if (bPack)
        {
            Pack32(rpBuf, m_pCodecMimeList->GetCount());
        }
        // Pack/add all the codec mime strings
        if (m_pCodecMimeList->GetCount() > 0)
        {
            // Loop through codec mime list and pack/add up strings
            LISTPOSITION pos = m_pCodecMimeList->GetHeadPosition();
            while (pos)
            {
                ulSize             += 2; // Add string size
                IHXBuffer* pBuffer = (IHXBuffer*) m_pCodecMimeList->GetNext(pos);
                if (pBuffer)
                {
                    UINT32 ulLen = (UINT32) strlen((const char*) pBuffer->GetBuffer());
                    if (ulLen > 0)
                    {
                        ulSize += ulLen + 1;
                    }
                }
                if (bPack)
                {
                    PackStringBuffer(rpBuf, pBuffer);
                }
            }
        }

        // Pack/add fxpackage mime count
        ulSize += 4;
        if (bPack)
        {
            Pack32(rpBuf, m_pFXPackageMimeList->GetCount());
        }
        // Pack/add all the fxpackage mime strings
        if (m_pFXPackageMimeList->GetCount() > 0)
        {
            // Loop through the fxpackage mime list and pack/add the strings
            LISTPOSITION pos = m_pFXPackageMimeList->GetHeadPosition();
            while (pos)
            {
                ulSize += 2; // Add string size
                IHXBuffer* pBuffer = (IHXBuffer*) m_pFXPackageMimeList->GetNext(pos);
                if (pBuffer)
                {
                    UINT32 ulLen = (UINT32) strlen((const char*) pBuffer->GetBuffer());
                    if (ulLen > 0)
                    {
                        ulSize += ulLen + 1;
                    }
                }
                if (bPack)
                {
                    PackStringBuffer(rpBuf, pBuffer);
                }
            }
        }
        // Add the size of the background color, if the
        // content version/stream version is 1.1.0.0
        if (m_ulContentVersion >= U2_STREAM_VERSION)
        {
            ulSize += 4;
            if (bPack)
            {
                Pack32(rpBuf, m_ulBackgroundColor);
            }
        }
    }

    return ulSize;
}

UINT32 PXWireFormatManager::UnPackUINT32(REF(BYTE*) rpBuffer)
{
    UINT32 ulRet = ((rpBuffer[0] << 24) & 0xFF000000) |
                   ((rpBuffer[1] << 16) & 0x00FF0000) |
                   ((rpBuffer[2] <<  8) & 0x0000FF00) |
                   ( rpBuffer[3]        & 0x000000FF);
    rpBuffer    += 4;
    return ulRet;
}

UINT32 PXWireFormatManager::UnPackUINT16(REF(BYTE*) rpBuffer)
{
    UINT32 ulRet = ((rpBuffer[0] << 8) & 0x0000FF00) |
                   ( rpBuffer[1]       & 0x000000FF);
    rpBuffer    += 2;
    return ulRet;
}

UINT32 PXWireFormatManager::UnPackUINT32_LE(REF(BYTE*) rpBuffer)
{
    UINT32 ulRet = ((rpBuffer[3] << 24) & 0xFF000000) |
                   ((rpBuffer[2] << 16) & 0x00FF0000) |
                   ((rpBuffer[1] <<  8) & 0x0000FF00) |
                   ( rpBuffer[0]        & 0x000000FF);
    rpBuffer    += 4;
    return ulRet;
}

UINT32 PXWireFormatManager::UnPackUINT16_LE(REF(BYTE*) rpBuffer)
{
    UINT32 ulRet = ((rpBuffer[1] << 8) & 0x0000FF00) |
                   ( rpBuffer[0]       & 0x000000FF);
    rpBuffer    += 2;
    return ulRet;
}

UINT32 PXWireFormatManager::UnPackBYTE(REF(BYTE*) rpBuffer)
{
    UINT32 ulRet = *rpBuffer++;
    return ulRet;
}

UINT32 PXWireFormatManager::UnPackVUINT(REF(BYTE*) rpBuffer)
{
    // Format of VUINT is:
    // 
    // 11bb bbbb  bbbb bbbb  bbbb bbbb  bbbb bbbb (value in range [0,0x3FFFFFFF])
    // 10bb bbbb  bbbb bbbb  (value in range [0,0x3FFF])
    // 0bbb bbbb (value in range [0,0x7F])
    //
    UINT32 ulRet       = 0;
    UINT32 ulFirstByte = rpBuffer[0];
    if (ulFirstByte & 0x00000080)
    {
        if (ulFirstByte & 0x00000040)
        {
            // This is a 4-byte value in range [0,0x3FFFFFFF]
            // but we have to mask out the highest two bits
            ulRet = UnPackUINT32(rpBuffer) & 0x3FFFFFFF;
        }
        else
        {
            // This is a 2-byte value in range [0,0x3FFF],
            // but we have to mask out the highest two bits
            ulRet = UnPackUINT16(rpBuffer) & 0x00003FFF;
        }
    }
    else
    {
        // This is a single byte value in range [0,0x7F]
        ulRet = UnPackBYTE(rpBuffer);
    }
    return ulRet;
}

void PXWireFormatManager::PackUINT32(REF(BYTE*) rpBuffer, UINT32 ulValue)
{
    rpBuffer[0] = (BYTE) ((ulValue >> 24) & 0x000000FF);
    rpBuffer[1] = (BYTE) ((ulValue >> 16) & 0x000000FF);
    rpBuffer[2] = (BYTE) ((ulValue >>  8) & 0x000000FF);
    rpBuffer[3] = (BYTE) ( ulValue        & 0x000000FF);
    rpBuffer   += 4;
}

void PXWireFormatManager::PackUINT16(REF(BYTE*) rpBuffer, UINT32 ulValue)
{
    HX_ASSERT(ulValue <= 0x0000FFFF);
    rpBuffer[0] = (BYTE) ((ulValue >> 8) & 0x000000FF);
    rpBuffer[1] = (BYTE) ( ulValue       & 0x000000FF);
    rpBuffer   += 2;
}

void PXWireFormatManager::PackBYTE(REF(BYTE*) rpBuffer, UINT32 ulValue)
{
    HX_ASSERT(ulValue <= 0x000000FF);
    rpBuffer[0] = (BYTE) ulValue;
    rpBuffer++;
}

void PXWireFormatManager::PackVUINT(REF(BYTE*) rpBuffer, UINT32 ulValue)
{
    // Format of VUINT is:
    // 
    // 11bb bbbb  bbbb bbbb  bbbb bbbb  bbbb bbbb (value in range [0,0x3FFFFFFF])
    // 10bb bbbb  bbbb bbbb  (value in range [0,0x3FFF])
    // 0bbb bbbb (value in range [0,0x7F])
    //
    HX_ASSERT(ulValue <= 0x3FFFFFFF);
    if (ulValue > 0x3FFF)
    {
        PackUINT32(rpBuffer, (ulValue | 0xC0000000));
    }
    else if (ulValue > 0x7F && ulValue <= 0x3FFF)
    {
        PackUINT16(rpBuffer, (ulValue | 0x00008000));
    }
    else
    {
        PackBYTE(rpBuffer, ulValue);
    }
}

UINT32 PXWireFormatManager::GetMask(UINT32 ulBitPos, UINT32 ulNumBits)
{
    UINT32 ulRet  = (1 << ulNumBits) - 1;
    INT32  lShift = (INT32) ulBitPos - ulNumBits + 1;
    if (lShift >= 0)
    {
        ulRet <<= lShift;
    }
    else
    {
        ulRet >>= -lShift;
    }
    return ulRet;
}

UINT32 PXWireFormatManager::GetUnsignedBits(REF(BYTE*) rpBuf, REF(UINT32) rulBitPos, UINT32 ulNumBits)
{
    UINT32 ulRet = 0;
    while (ulNumBits)
    {
        UINT32 ulBitsAvailable = rulBitPos + 1;
        if (ulNumBits >= ulBitsAvailable)
        {
            // We're gonna use the whole current byte and advance it
            ulRet     |= (*rpBuf & GetMask(rulBitPos, ulBitsAvailable)) << (ulNumBits - ulBitsAvailable);
            ulNumBits -= ulBitsAvailable;
            // Advance the buffer
            rpBuf++;
            rulBitPos = 7;
        }
        else
        {
            // We're only gonna use part of the current byte
            ulRet     |= (*rpBuf & GetMask(rulBitPos, ulNumBits)) >> (ulBitsAvailable - ulNumBits);
            // Advance the buffer
            rulBitPos -= ulNumBits;
            ulNumBits -= ulNumBits;
        }
    }

    return ulRet;
}

INT32 PXWireFormatManager::GetSignedBits(REF(BYTE*) rpBuf, REF(UINT32) rulBitPos, UINT32 ulNumBits)
{
    INT32 lRet = (INT32) GetUnsignedBits(rpBuf, rulBitPos, ulNumBits);
    if (lRet & (1L << (ulNumBits - 1)))
    {
        lRet |= (-1L << ulNumBits);
    }
    return lRet;
}

HX_RESULT PXWireFormatManager::SetTitle(const char* pszTitle)
{
    return SetString(pszTitle, m_pTitleStr);
}

HX_RESULT PXWireFormatManager::SetTitle(IHXBuffer* pTitleStr)
{
    return SetString(pTitleStr, m_pTitleStr);
}

HX_RESULT PXWireFormatManager::GetTitle(REF(IHXBuffer*) rpTitleStr)
{
    return SetString(m_pTitleStr, rpTitleStr);
}

HX_RESULT PXWireFormatManager::SetAuthor(const char* pszAuthor)
{
    return SetString(pszAuthor, m_pAuthorStr);
}

HX_RESULT PXWireFormatManager::SetAuthor(IHXBuffer* pAuthorStr)
{
    return SetString(pAuthorStr, m_pAuthorStr);
}

HX_RESULT PXWireFormatManager::GetAuthor(REF(IHXBuffer*) rpAuthorStr)
{
    return SetString(m_pAuthorStr, rpAuthorStr);
}

HX_RESULT PXWireFormatManager::SetCopyright(const char* pszCopyright)
{
    return SetString(pszCopyright, m_pCopyrightStr);
}

HX_RESULT PXWireFormatManager::SetCopyright(IHXBuffer* pCopyrightStr)
{
    return SetString(pCopyrightStr, m_pCopyrightStr);
}

HX_RESULT PXWireFormatManager::GetCopyright(REF(IHXBuffer*) rpCopyrightStr)
{
    return SetString(m_pCopyrightStr, rpCopyrightStr);
}

HX_RESULT PXWireFormatManager::SetDefaultURL(const char* pszDefaultURL)
{
    return SetString(pszDefaultURL, m_pDefaultURLStr);
}

HX_RESULT PXWireFormatManager::SetDefaultURL(IHXBuffer* pDefaultURLStr)
{
    return SetString(pDefaultURLStr, m_pDefaultURLStr);
}

HX_RESULT PXWireFormatManager::GetDefaultURL(REF(IHXBuffer*) rpDefaultURLStr)
{
    return SetString(m_pDefaultURLStr, rpDefaultURLStr);
}

HX_RESULT PXWireFormatManager::SetASMRuleBook(const char* pszRuleBook)
{
    return SetString(pszRuleBook, m_pASMRuleBook);
}

HX_RESULT PXWireFormatManager::SetASMRuleBook(IHXBuffer* pRuleBookStr)
{
    return SetString(pRuleBookStr, m_pASMRuleBook);
}

HX_RESULT PXWireFormatManager::GetASMRuleBook(REF(IHXBuffer*) rpRuleBookStr)
{
    return SetString(m_pASMRuleBook, rpRuleBookStr);
}

HX_RESULT PXWireFormatManager::SetStreamMimeType(const char* pszMime)
{
    return SetString(pszMime, m_pStreamMimeType);
}

HX_RESULT PXWireFormatManager::SetStreamMimeType(IHXBuffer* pMimeStr)
{
    return SetString(pMimeStr, m_pStreamMimeType);
}

HX_RESULT PXWireFormatManager::GetStreamMimeType(REF(IHXBuffer*) rpMimeStr)
{
    return SetString(m_pStreamMimeType, rpMimeStr);
}

HX_RESULT PXWireFormatManager::AddStringToList(const char* pszStr, CHXSimpleList* pList)
{
    HX_RESULT retVal = HXR_OK;

    if (pszStr && pList)
    {
        IHXBuffer* pBuffer = NULL;
        retVal              = SetString(pszStr, pBuffer);
        if (SUCCEEDED(retVal))
        {
            retVal = AddStringToList(pBuffer, pList);
        }
        HX_RELEASE(pBuffer);
    }
    else
    {
        retVal = HXR_INVALID_PARAMETER;
    }

    return retVal;
}

HX_RESULT PXWireFormatManager::AddStringToList(IHXBuffer* pBufferStr, CHXSimpleList* pList)
{
    HX_RESULT retVal = HXR_OK;

    if (pBufferStr && pList)
    {
        // Let's make sure the string is not already in the list
        BOOL         bFoundMatch = FALSE;
        LISTPOSITION pos         = pList->GetHeadPosition();
        while (pos)
        {
            IHXBuffer* pStr = (IHXBuffer*) pList->GetNext(pos);
            if (pStr)
            {
                if (!strcmp((const char*) pBufferStr->GetBuffer(),
                            (const char*) pStr->GetBuffer()))
                {
                    bFoundMatch = TRUE;
                }
            }
        }

        if (!bFoundMatch)
        {
            // AddRef the buffer before it goes on the list
            pBufferStr->AddRef();
            // Add the buffer to the tail of the list
            pList->AddTail((void*) pBufferStr);
        }
    }
    else
    {
        retVal = HXR_INVALID_PARAMETER;
    }

    return retVal;
}

HX_RESULT PXWireFormatManager::SetString(const char* pszStr, REF(IHXBuffer*) rpBufferStr)
{
    HX_RESULT retVal = HXR_FAIL;

    if (pszStr && m_pCommonClassFactory)
    {
        IHXBuffer* pBuffer = NULL;
        retVal              = m_pCommonClassFactory->CreateInstance(CLSID_IHXBuffer,
                                                                    (void**) &pBuffer);
        if (SUCCEEDED(retVal))
        {
            // Set the size
            retVal = pBuffer->Set((const BYTE*) pszStr, strlen(pszStr) + 1);
            if (SUCCEEDED(retVal))
            {
                // Assign the out parameter
                HX_RELEASE(rpBufferStr);
                rpBufferStr = pBuffer;
                rpBufferStr->AddRef();
            }
        }
        HX_RELEASE(pBuffer);
    }

    return retVal;
}

HX_RESULT PXWireFormatManager::SetString(IHXBuffer* pBuffer, REF(IHXBuffer*) rpBufferStr)
{
    HX_RESULT retVal = HXR_OK;

    if (pBuffer)
    {
        HX_RELEASE(rpBufferStr);
        rpBufferStr = pBuffer;
        rpBufferStr->AddRef();
    }
    else
    {
        retVal = HXR_FAIL;
    }

    return retVal;
}

HX_RESULT PXWireFormatManager::GetFirstString(REF(LISTPOSITION) rPos, CHXSimpleList* pList, IHXBuffer** ppBuffer)
{
    HX_RESULT retVal = HXR_OK;

    if (pList && ppBuffer)
    {
        // Set default
        *ppBuffer = NULL;

        rPos = pList->GetHeadPosition();
        if (rPos)
        {
            *ppBuffer = (IHXBuffer*) pList->GetNext(rPos);
            (*ppBuffer)->AddRef();
        }
        else
        {
            retVal = HXR_FAIL;
        }
    }
    else
    {
        retVal = HXR_INVALID_PARAMETER;
    }

    return retVal;
}

HX_RESULT PXWireFormatManager::GetNextString(REF(LISTPOSITION) rPos, CHXSimpleList* pList, IHXBuffer** ppBuffer)
{
    HX_RESULT retVal = HXR_OK;

    if (pList && ppBuffer)
    {
        // Set default
        *ppBuffer = NULL;

        if (rPos)
        {
            *ppBuffer = (IHXBuffer*) pList->GetNext(rPos);
            (*ppBuffer)->AddRef();
        }
        else
        {
            retVal = HXR_FAIL;
        }
    }
    else
    {
        retVal = HXR_INVALID_PARAMETER;
    }

    return retVal;
}

void PXWireFormatManager::SetBackgroundColor(BYTE ucRed, BYTE ucGreen, BYTE ucBlue)
{
    m_ulBackgroundColor = (ucRed << 16) | (ucGreen << 8) | ucBlue;
}

void PXWireFormatManager::SetBackgroundColor(UINT32 ulColor)
{
    m_ulBackgroundColor = ulColor;
}

void PXWireFormatManager::GetBackgroundColor(REF(BYTE) rucRed, REF(BYTE) rucGreen, REF(BYTE) rucBlue) const
{
    rucRed   = (BYTE) ((m_ulBackgroundColor & 0x00FF0000) >> 16);
    rucGreen = (BYTE) ((m_ulBackgroundColor & 0x0000FF00) >>  8);
    rucBlue  = (BYTE)  (m_ulBackgroundColor & 0x000000FF);
}

UINT32 PXWireFormatManager::GetBackgroundColor() const
{
    return m_ulBackgroundColor;
}

void PXWireFormatManager::SetRealPixAdsFlag(BOOL bFlag)
{
    if (bFlag)
    {
        m_ulRendererFlags |= kRealPixAdsFlagMask;
    }
    else
    {
        m_ulRendererFlags &= ~kRealPixAdsFlagMask;
    }
}

BOOL PXWireFormatManager::GetRealPixAdsFlag() const
{
    return (m_ulRendererFlags & kRealPixAdsFlagMask ? TRUE : FALSE);
}

void PXWireFormatManager::SetRPACachingAdFlag(BOOL bFlag)
{
    if (bFlag)
    {
        m_ulRendererFlags |= kRPACachingAdFlagMask;
    }
    else
    {
        m_ulRendererFlags &= ~kRPACachingAdFlagMask;
    }
}

BOOL PXWireFormatManager::GetRPACachingAdFlag() const
{
    return (m_ulRendererFlags & kRPACachingAdFlagMask ? TRUE : FALSE);
}

UINT32 PXWireFormatManager::GetNumCodecMimes() const
{
    return (m_pCodecMimeList ? m_pCodecMimeList->GetCount() : 0);
}

UINT32 PXWireFormatManager::GetNumFXPackageMimes() const
{
    return (m_pFXPackageMimeList ? m_pFXPackageMimeList->GetCount() : 0);
}

void PXWireFormatManager::SetLiveRealPixFlag(BOOL bFlag)
{
    if (bFlag)
    {
        m_ulRendererFlags |= kLiveRealPixMask;
    }
    else
    {
        m_ulRendererFlags &= ~kLiveRealPixMask;
    }
}

BOOL PXWireFormatManager::GetLiveRealPixAds() const
{
    return (m_ulRendererFlags & kLiveRealPixMask ? TRUE : FALSE);
}

void PXWireFormatManager::AddMetaInfo(IHXValues* pAvailableMetaInfo,
                                      const char* pszRequestedInfo,
                                      IHXValues* pFileHeader)
{
    if (pAvailableMetaInfo && pszRequestedInfo &&
        pFileHeader && m_pCommonClassFactory)
    {
        // Create a new string with the requested info
        char* pszReqInfo = new char [strlen(pszRequestedInfo) + 1];
        if (pszReqInfo)
        {
            // Copy the string
            strcpy(pszReqInfo, pszRequestedInfo); /* Flawfinder: ignore */
            // Identify the delimiters
            const char* pszDelimit = " ,\t\r\n";
            // Initialize the variables needed for iterating
            // through IHXValues properties
            HX_RESULT   rv      = HXR_OK;
            IHXBuffer* pValue  = NULL;
            UINT32      ulValue = 0;
            // Make the first call to strtok().
            char* pszToken = strtok(pszReqInfo, pszDelimit);
            while (pszToken)
            {
                // Did we get the instruction to add all meta info?
                if (*pszToken == '*')
                {
                    // We should add all meta info
                    //
                    // Loop through the Meta Info CStrings
                    const char* pszName = NULL;
                    rv = pAvailableMetaInfo->GetFirstPropertyCString(pszName, pValue);
                    while (SUCCEEDED(rv))
                    {
                        // Add it to the header
                        pFileHeader->SetPropertyCString(pszName, pValue);
                        HX_RELEASE(pValue);
                        rv = pAvailableMetaInfo->GetNextPropertyCString(pszName, pValue);
                    }
                    // Loop through the Meta Info ULONG32s
                    rv = pAvailableMetaInfo->GetFirstPropertyULONG32(pszName, ulValue);
                    while (SUCCEEDED(rv))
                    {
                        // Add it to the header
                        pFileHeader->SetPropertyULONG32(pszName, ulValue);
                        rv = pAvailableMetaInfo->GetNextPropertyULONG32(pszName, ulValue);
                    }
                    // Loop through the Meta Info Buffers
                    rv = pAvailableMetaInfo->GetFirstPropertyBuffer(pszName, pValue);
                    while (SUCCEEDED(rv))
                    {
                        // Add it to the header
                        pFileHeader->SetPropertyBuffer(pszName, pValue);
                        HX_RELEASE(pValue);
                        rv = pAvailableMetaInfo->GetNextPropertyBuffer(pszName, pValue);
                    }
                    // We've added all the meta info, so we can break out of
                    // this parsing loop
                    break;
                }
                // Now we have a particular meta info name. Therefore,
                // we look for it in our supplied list of meta
                // info. We don't know whether it's a ULONG32, CString,
                // or Buffer property, so we have to check all three.
                //
                // Is this property a CString property?
                rv = pAvailableMetaInfo->GetPropertyCString(pszToken, pValue);
                if (SUCCEEDED(rv))
                {
                    pFileHeader->SetPropertyCString(pszToken, pValue);
                }
                HX_RELEASE(pValue);
                if (FAILED(rv))
                {
                    // It wasn't a CString property, so is it a ULONG32 property?
                    rv = pAvailableMetaInfo->GetPropertyULONG32(pszToken, ulValue);
                    if (SUCCEEDED(rv))
                    {
                        pFileHeader->SetPropertyULONG32(pszToken, ulValue);
                    }
                    if (FAILED(rv))
                    {
                        // It wasn't a ULONG32 property, so was it a Buffer property?
                        rv = pAvailableMetaInfo->GetPropertyBuffer(pszToken, pValue);
                        if (SUCCEEDED(rv))
                        {
                            pFileHeader->SetPropertyBuffer(pszToken, pValue);
                        }
                        HX_RELEASE(pValue);
                    }
                }
                // Get the next token
                pszToken = strtok(NULL, pszDelimit);
            }
        }
	HX_VECTOR_DELETE(pszReqInfo);
    }
}

