/* ***** BEGIN LICENSE BLOCK *****
 * Source last modified: $Id: pxff2.cpp,v 1.1.26.1 2004/07/09 01:52:03 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 ***** */

// system

// include
#include "hxtypes.h"
#include "hxwintyp.h"
#include "hxcom.h"
#include "hxtypes.h"
#include "hxresult.h"
#include "hxcomm.h"
#include "ihxpckts.h"
#include "hxfiles.h"
#include "hxformt.h"
#include "hxplugn.h"
#include "hxprefs.h"
#include "hxformt.h"
#include "hxpends.h"
#include "hxengin.h"
#include "hxmon.h"
#include "hxver.h"
#include "defslice.h"
#include "hxupgrd.h"
#include "hxxres.h"
#include "hxxrsmg.h"
#include "hxerror.h"
#include "ihxfgbuf.h"
#include "hxxml.h"
#include "hxvsrc.h"
#include "hxcore.h"
#include "hxcache.h"

// pnmisc
#include "verutil.h"
#include "baseobj.h"
#include "unkimp.h"
#include "perplex.h"

// pncont
#include "hxstring.h"
#include "hxslist.h"
#include "hxmap.h"
#include "hxbuffer.h"
#include "carray.h"
#include "chxfgbuf.h"

// coreres
#include "pixres.h"

// pxcomlib
#include "pxcolor.h"
#include "pxrect.h"
#include "pxeffect.h"
#include "pxcmpmgr.h"
#include "pxffmcod.h"
#include "wirefmgr.h"
#include "rpfile.h"
#include "rpparser.h"
#include "pxerror.h"
#include "pxffcmgr.h"

// pxff
#include "rpfilobj.h" // Have to include for !()$*(#$($) old parser
#include "filehdlr.h"
#include "pxschedu.h"
#include "shadvsrc.h"
#include "pxff2.h"
#include "rpffdll.ver"

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

#ifdef _AIX
#include "dllpath.h"
ENABLE_MULTILOAD_DLLACCESS_PATHS(Pxff);
#endif

const IID    CRealPixFileFormat::m_IID                   = IID_IHXFileFormatObject;
const char * CRealPixFileFormat::m_pszDescription        = "Helix RealPix Format Plugin";
const char * CRealPixFileFormat::m_pszCopyright          = HXVER_COPYRIGHT;
const char * CRealPixFileFormat::m_pszMoreInfoURL        = HXVER_MOREINFO;
const char * CRealPixFileFormat::m_ppszFileMimeTypes[]   = {"application/vnd.rn-realpix", "image/vnd.rn-realpix", NULL};
const char * CRealPixFileFormat::m_ppszFileExtensions[]  = {"rp", NULL};
const char * CRealPixFileFormat::m_ppszFileOpenNames[]   = {"RealPix (*.rp)", NULL};
const char * CRealPixFileFormat::m_ppszStreamMimeTypes[] = {"application/vnd.rn-realpixstream2", NULL};
const UINT32 CRealPixFileFormat::m_ulStreamVersion       = HX_ENCODE_PROD_VERSION(0, 0, 0, 0);

CRealPixFileFormat::CRealPixFileFormat()
{
    m_lRefCount           = 0;
    m_pContext            = NULL;
    m_pCommonClassFactory = NULL;
    m_pRequest            = NULL;
    m_pFileFormatResponse = NULL;
    m_pRPFileObject       = NULL;
    m_pPoolPathAdjustment = NULL;
    m_pCodecManager       = NULL;
    m_pWireFormatManager  = NULL;
    m_pRPFileHandler      = NULL;
    m_pImageFileHandler   = NULL;
    m_pFileHandlerArray   = NULL;
    m_pPacketScheduler    = NULL;
    m_pRealPixFile        = NULL;
    m_pCodec              = NULL;
    m_ulSessionHandle     = 0;
    m_bImageParseActive   = FALSE;
    m_ulState             = kStateConstructed;
    m_bRealPixLicensed    = TRUE;
    m_ulStrictnessLevel   = REALPIX_STRICTNESS_LOW;
    m_bShutdownRPFile     = FALSE;
    m_pAcceptMetaInfoStr  = NULL;
}

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

void CRealPixFileFormat::Deallocate()
{
    ReleaseAllFileHandlers();
    HX_RELEASE(m_pContext);
    HX_RELEASE(m_pCommonClassFactory);
    HX_RELEASE(m_pRequest);
    HX_RELEASE(m_pFileFormatResponse);
    HX_RELEASE(m_pRPFileObject);
    HX_RELEASE(m_pPoolPathAdjustment);
    HX_RELEASE(m_pCodecManager);
    HX_RELEASE(m_pWireFormatManager);
    HX_RELEASE(m_pRPFileHandler);
    HX_RELEASE(m_pImageFileHandler);
    HX_DELETE(m_pFileHandlerArray);
    HX_RELEASE(m_pPacketScheduler);
    HX_RELEASE(m_pRealPixFile);
    HX_RELEASE(m_pCodec);
    HX_RELEASE(m_pAcceptMetaInfoStr);
}

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

    if (IsEqualIID(riid, IID_IUnknown))
    {
        AddRef();
        *ppvObj = (IUnknown*) (IHXPlugin*) this;
    }
    else if (IsEqualIID(riid, IID_IHXPlugin))
    {
        AddRef();
        *ppvObj = (IHXPlugin*) this;
    }
    else if (IsEqualIID(riid, IID_IHXFileFormatObject))
    {
        AddRef();
        *ppvObj = (IHXFileFormatObject*) this;
    }
    else if (IsEqualIID(riid, IID_IHXInterruptSafe))
    {
        AddRef();
        *ppvObj = (IHXInterruptSafe*) this;
    }
    else if (IsEqualIID(riid, IID_IHXFileViewSource))
    {
        CRPViewSource* pVsrc = new CRPViewSource(m_pContext, (IUnknown*)(IHXPlugin*)this);
        if (pVsrc)
        {
            retVal = pVsrc->QueryInterface(riid, ppvObj);
        }
        else
        {
            retVal = HXR_OUTOFMEMORY;
        }
    }
    else if (IsEqualIID(riid, IID_IHXThreadSafeMethods))
    {
        AddRef();
        *ppvObj = (IHXThreadSafeMethods*)this;
    }
    else
    {
        *ppvObj = NULL;
        retVal  = HXR_NOINTERFACE;
    }

    return retVal;
}

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

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

    delete this;

    return 0;
}

STDMETHODIMP CRealPixFileFormat::GetPluginInfo(REF(BOOL)        bMultipleLoad,
                                               REF(const char*) pDescription,
                                               REF(const char*) pCopyright,
                                               REF(const char*) pMoreInfoURL,
                                               REF(ULONG32)     ulVersionNumber)
{
    bMultipleLoad   = TRUE;
    pDescription    = m_pszDescription;
    pCopyright      = m_pszCopyright;
    pMoreInfoURL    = m_pszMoreInfoURL;
    ulVersionNumber = TARVER_ULONG32_VERSION;

    return HXR_OK;
}

STDMETHODIMP CRealPixFileFormat::InitPlugin(IUnknown* pContext)
{
    HX_RESULT retVal = HXR_FAIL;

    if (m_ulState == kStateConstructed)
    {
        if (pContext)
        {
            // Clear out everything
            Deallocate();

            // Save a copy of the context
            m_pContext = pContext;
            m_pContext->AddRef();

            // Get an IHXCommonClassFactory interface
            retVal = m_pContext->QueryInterface(IID_IHXCommonClassFactory,
                                                (void**) &m_pCommonClassFactory);
            if (SUCCEEDED(retVal))
            {
                // Change the state
                m_ulState = kStatePluginInitialized;
            }
        }
    }

    return retVal;
}

STDMETHODIMP CRealPixFileFormat::GetFileFormatInfo(REF(const char**) pFileMimeTypes,
                                                   REF(const char**) pFileExtensions,
                                                   REF(const char**) pFileOpenNames)
{
    pFileMimeTypes  = m_ppszFileMimeTypes;
    pFileExtensions = m_ppszFileExtensions;
    pFileOpenNames  = m_ppszFileOpenNames;

    return HXR_OK;
}

STDMETHODIMP CRealPixFileFormat::InitFileFormat(IHXRequest*        pRequest,
                                                IHXFormatResponse* pFormatResponse,
                                                IHXFileObject*     pFileObject)
{
#ifdef XXXMEH_DEBUG_LOG
    DEBUG_OUTF("c:\\pxff.log", (s, "CRealPixFileFormat::InitFileFormat(0x%08X,0x%08X,0x%08X,0x%08X)\n",
               this, pRequest, pFormatResponse, pFileObject));
#endif
    HX_RESULT retVal = HXR_FAIL;

    if (m_ulState == kStatePluginInitialized)
    {
        if (pRequest && pFormatResponse && pFileObject)
        {
            // Save a copy of the request
            m_pRequest = pRequest;
            m_pRequest->AddRef();

            // Save a copy of the file format response
            m_pFileFormatResponse = pFormatResponse;
            m_pFileFormatResponse->AddRef();

            // Save a copy of the file object
            m_pRPFileObject = pFileObject;
            m_pRPFileObject->AddRef();

            // Get the AcceptMetaInfo string, if one exists
            IHXValues* pRequestHeaders = NULL;
            pRequest->GetRequestHeaders(pRequestHeaders);
            if (pRequestHeaders)
            {
                HX_RELEASE(m_pAcceptMetaInfoStr);
                pRequestHeaders->GetPropertyCString("AcceptMetaInfo", m_pAcceptMetaInfoStr);
            }
            HX_RELEASE(pRequestHeaders);

            // Determine whether this file object is coming from a
	    // pool filesytem which wants to adjust absolute local paths.
            m_pRPFileObject->QueryInterface (IID_IHXPoolPathAdjustment,
			                     (void**) &m_pPoolPathAdjustment);

            // Create a codec manager
            retVal = PXFileFormatCodecManager::CreateObject(&m_pCodecManager);
            if (SUCCEEDED(retVal))
            {
                // AddRef the object
                m_pCodecManager->AddRef();
                // Init the codec manager
                retVal = m_pCodecManager->Init(m_pContext, IID_IHXRealPixFileFormatCodec);
                if (SUCCEEDED(retVal))
                {
                    // Create a wire format manager
                    retVal = PXWireFormatManager::CreateObject(&m_pWireFormatManager);
                    if (SUCCEEDED(retVal))
                    {
                        // Addref the manager
                        m_pWireFormatManager->AddRef();
                        // Initialize the wire format manager
                        retVal = m_pWireFormatManager->Init(m_pContext, m_ulStreamVersion);
                        if (SUCCEEDED(retVal))
                        {
                            // Get the registry settings
                            retVal = GetRegistrySettings(m_bRealPixLicensed, m_ulStrictnessLevel);
                            if (SUCCEEDED(retVal))
                            {
                                // Create a pointer array
                                HX_DELETE(m_pFileHandlerArray);
                                m_pFileHandlerArray = new CHXPtrArray();
                                if (m_pFileHandlerArray)
                                {
                                    // Create a file handler for the .rp file
                                    HX_RELEASE(m_pRPFileHandler);
                                    m_pRPFileHandler = new PXFileHandler();
                                    if (m_pRPFileHandler)
                                    {
                                        // Addref the object
                                        m_pRPFileHandler->AddRef();
                                        // Init the file handler
                                        retVal = m_pRPFileHandler->Init(m_pContext, m_pRPFileObject, this);
                                        if (SUCCEEDED(retVal))
                                        {
                                            // Set the state
                                            m_ulState = kStateReadingRPFile;
                                            // Read the .rp file
                                            retVal    = m_pRPFileHandler->ReadRPFile();
                                        }
                                    }
                                    else
                                    {
                                        retVal = HXR_OUTOFMEMORY;
                                    }
                                }
                                else
                                {
                                    retVal = HXR_OUTOFMEMORY;
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    if (FAILED(retVal))
    {
        if (pFormatResponse)
        {
            pFormatResponse->InitDone(retVal);
        }
    }

    return retVal;
}

STDMETHODIMP CRealPixFileFormat::Close()
{
#ifdef XXXMEH_DEBUG_LOG
    DEBUG_OUTF("c:\\pxff.log", (s, "CRealPixFileFormat::Close(0x%08X)\n", this));
#endif
    HX_RESULT retVal = HXR_OK;

    // If we currently had a parsed image held in memory by
    // a codec, then we need to tell the codec to drop it.
    if (m_bImageParseActive && m_pCodec)
    {
        // Tell the codec to release this image
        m_pCodec->ReleaseImage(m_ulSessionHandle);
        // Clear the flag
        m_bImageParseActive = FALSE;
        // Clear the handle
        m_ulSessionHandle   = 0;
        // Release the codec
        HX_RELEASE(m_pCodec);
    }

    // Set the state
    m_ulState = kStateShutdown;
    // Shutdown all file handlers - this is asynch - will
    // finish up in ShutdownDone().
    ShutdownAllFileHandlers(TRUE);

    return retVal;
}

STDMETHODIMP CRealPixFileFormat::GetFileHeader()
{
#ifdef XXXMEH_DEBUG_LOG
    DEBUG_OUTF("c:\\pxff.log", (s, "CRealPixFileFormat::GetFileHeader(0x%08X)\n", this));
#endif
    HX_RESULT retVal = HXR_OK;

    if (m_ulState == kStateFileFormatInitialized)
    {
        // Set the state
        m_ulState = kStateGetFileHeaderShutdown;
        // Shutdown all the file handlers
        ShutdownAllFileHandlers(FALSE);
    }
    else
    {
        retVal = HXR_UNEXPECTED;
    }

    return retVal;
}

STDMETHODIMP CRealPixFileFormat::GetStreamHeader(UINT16 usStreamNumber)
{
#ifdef XXXMEH_DEBUG_LOG
    DEBUG_OUTF("c:\\pxff.log", (s, "CRealPixFileFormat::GetStreamHeader(0x%08X)\n", this));
#endif
    HX_RESULT retVal = HXR_OK;

    /* If RealPix is not licensed, log an error and return */
    if (!m_bRealPixLicensed)
    {
        ReportError(IDS_ERR_PIX_NOTLICENSED,
                    NULL,
                    NULL,
                    HXLOG_ALERT,
                    HXR_NOT_LICENSED);

        m_pFileFormatResponse->StreamHeaderReady(HXR_NOT_LICENSED, NULL);
        return HXR_OK;
    }

    if (m_ulState == kStateFileHeaderSent)
    {
        if (m_bRealPixLicensed)
	{
            IHXValues* pStreamHeader = NULL;
            retVal                    = m_pWireFormatManager->GetStreamHeader(pStreamHeader);
            if (SUCCEEDED(retVal))
	    {
                // Set the state
                m_ulState = kStateAwaitingGetPacket;
                // Send the stream header
                m_pFileFormatResponse->StreamHeaderReady(HXR_OK, pStreamHeader);
	    }
            HX_RELEASE(pStreamHeader);
	}
	else
	{
	    retVal = HXR_NOT_LICENSED;
            ReportError(IDS_ERR_PIX_NOTLICENSED, NULL, NULL, HXLOG_ALERT, retVal);
	}

        if (FAILED(retVal))
        {
            m_pFileFormatResponse->StreamHeaderReady(retVal, NULL);
        }
    }
    else
    {
        retVal = HXR_UNEXPECTED;
    }

    return retVal;
}

STDMETHODIMP CRealPixFileFormat::GetPacket(UINT16 usStreamNumber)
{
#ifdef XXXMEH_DEBUG_LOG
    DEBUG_OUTF("c:\\pxff.log", (s, "CRealPixFileFormat::GetPacket(0x%08X,%u)\n", this, usStreamNumber));
#endif
    HX_RESULT retVal = HXR_OK;

    if (m_ulState == kStateAwaitingGetPacket)
    {
        if (usStreamNumber == 0)
        {
            // First check to see if the stream is done
            if (!m_pPacketScheduler->IsStreamDone())
            {
                // We still have packets to send - what is the next
                // type of packet to send
                UINT32 ulPacketType = 0;
                retVal              = m_pPacketScheduler->GetNextPacketInfo(ulPacketType);
                if (SUCCEEDED(retVal))
                {
                    if (ulPacketType == PXWireFormatManager::kPacketTypeImageHeader)
                    {
                        UINT32      ulHandle       = 0;
                        UINT32      ulSize         = 0;
                        IHXBuffer* pFileMimeStr   = NULL;
                        IHXBuffer* pStreamMimeStr = NULL;
                        IHXBuffer* pNameStr       = NULL;
                        UINT32      ulTime         = 0;
                        retVal = m_pPacketScheduler->GetImageHeaderInfo(ulHandle, ulSize, pFileMimeStr,
                                                                        pNameStr, pStreamMimeStr, ulTime);
                        if (SUCCEEDED(retVal))
                        {
                            AllowPoolPathAdjustment (pNameStr);

                            // Create an file handler object
                            HX_RELEASE(m_pImageFileHandler);
                            m_pImageFileHandler = new PXFileHandler();
                            if (m_pImageFileHandler)
                            {
                                // AddRef the object
                                m_pImageFileHandler->AddRef();
                                // Init the handler
                                retVal = m_pImageFileHandler->Init(m_pContext, m_pRPFileObject, this, ulSize + 1);
                                if (SUCCEEDED(retVal))
                                {
                                    // Set the state
                                    m_ulState = kStateReadingImageFile;
                                    // Read the image file
                                    retVal = m_pImageFileHandler->ReadImageFile(ulHandle, pNameStr);
                                }
                            }
                            else
                            {
                                retVal = HXR_OUTOFMEMORY;
                            }
                        }
                        HX_RELEASE(pFileMimeStr);
                        HX_RELEASE(pStreamMimeStr);
                        HX_RELEASE(pNameStr);
                    }
                    else if (ulPacketType == PXWireFormatManager::kPacketTypeImageData)
                    {
                        UINT32      ulHandle        = 0;
                        IHXBuffer* pStreamMimeStr  = NULL;
                        UINT32      ulSessionHandle = 0;
                        UINT32      ulPacketIndex   = 0;
                        UINT32      ulNumPackets    = 0;
                        UINT32      ulTimeStamp     = 0;
                        retVal = m_pPacketScheduler->GetImageDataInfo(ulHandle, pStreamMimeStr, ulSessionHandle,
                                                                      ulPacketIndex, ulNumPackets, ulTimeStamp);
                        if (SUCCEEDED(retVal))
                        {
                            // Make sure we have a codec
                            if (m_bImageParseActive && m_pCodec && ulSessionHandle == m_ulSessionHandle)
                            {
                                // Get the buffers from the codec
                                IHXBuffer* pImageData  = NULL;
                                IHXBuffer* pOpaqueData = NULL;
                                BOOL        bRequired   = FALSE;
                                retVal                  = m_pCodec->GetImagePacket(m_ulSessionHandle,
                                                                                   ulPacketIndex,
                                                                                   pImageData,
                                                                                   pOpaqueData,
                                                                                   bRequired);
                                if (SUCCEEDED(retVal))
                                {
                                    // If we've just gotten the last packet from the codec,
                                    // then we can release the session handle with the codec
                                    // and then release the codec interface
                                    if (ulPacketIndex == ulNumPackets - 1)
                                    {
                                        retVal = m_pCodec->ReleaseImage(m_ulSessionHandle);
                                        if (SUCCEEDED(retVal))
                                        {
                                            // Clear the active parse flag
                                            m_bImageParseActive = FALSE;
                                            // Clear the session handle
                                            m_ulSessionHandle   = 0;
                                            // Release the codec interface
                                            HX_RELEASE(m_pCodec);
                                        }
                                    }

                                    if (SUCCEEDED(retVal))
                                    {
                                        IHXPacket* pPacket = NULL;
                                        retVal              = m_pWireFormatManager->SetImageDataInfo(ulHandle,
                                                                                                     pImageData,
                                                                                                     pOpaqueData,
                                                                                                     ulPacketIndex,
                                                                                                     ulTimeStamp,
                                                                                                     bRequired,
                                                                                                     pPacket);
                                        if (SUCCEEDED(retVal))
                                        {
#ifdef XXXMEH_OUTPUT_DEBUG_STRING
                                            char szDbgStr[128]; /* Flawfinder: ignore */
                                            sprintf(szDbgStr, "Sending Image Data Packet %lu of %lu (handle=%lu)\n", /* Flawfinder: ignore */
                                                    ulPacketIndex, ulNumPackets, ulHandle);
                                            OutputDebugString(szDbgStr);
#endif
                                            // Tell the scheduler we've sent the packet
                                            m_pPacketScheduler->PacketSent(m_pWireFormatManager->GetPacketSize(pPacket));
                                            // Set the state (actually keep it the same)
                                            m_ulState = kStateAwaitingGetPacket;
                                            // Send the packet
                                            m_pFileFormatResponse->PacketReady(HXR_OK, pPacket);
                                        }
                                        HX_RELEASE(pPacket);
                                    }
                                }
                                HX_RELEASE(pImageData);
                                HX_RELEASE(pOpaqueData);
                            }
                            else
                            {
                                retVal = HXR_FAIL;
                            }
                        }
                        HX_RELEASE(pStreamMimeStr);
                    }
                    else if (ulPacketType == PXWireFormatManager::kPacketTypeEffect)
                    {
                        PXEffect* pEffect     = NULL;
                        UINT32    ulTimeStamp = 0;
                        retVal                = m_pPacketScheduler->GetEffectInfo(pEffect, ulTimeStamp);
                        if (SUCCEEDED(retVal))
                        {
                            IHXPacket* pPacket = NULL;
                            retVal              = m_pWireFormatManager->SetEffectInfo(pEffect,
                                                                                      ulTimeStamp,
                                                                                      pPacket);
                            if (SUCCEEDED(retVal))
                            {
#ifdef XXXMEH_OUTPUT_DEBUG_STRING
                                char szDbgStr[128]; /* Flawfinder: ignore */
                                sprintf(szDbgStr, "Sending Effect Packet (type=%lu,start=%lu,target=%lu)\n", /* Flawfinder: ignore */
                                        pEffect->GetEffectType(), pEffect->GetStart(), pEffect->GetTarget());
                                OutputDebugString(szDbgStr);
#endif
                                // Tell the scheduler we've sent the packet
                                m_pPacketScheduler->PacketSent(m_pWireFormatManager->GetPacketSize(pPacket));
                                // Set the state (actually keep it the same)
                                m_ulState = kStateAwaitingGetPacket;
                                // Send the packet
                                m_pFileFormatResponse->PacketReady(HXR_OK, pPacket);
                            }
                            HX_RELEASE(pPacket);
                        }
                        HX_RELEASE(pEffect);
                    }
                    else
                    {
                        retVal = HXR_FAIL;
                    }
                }
            }
            else
            {
                // Scheduler says stream is done, so set the state
                m_ulState = kStateStreamDone;
                // Call the response interface
                m_pFileFormatResponse->StreamDone(0);
            }
        }
        else
        {
            retVal = HXR_INVALID_PARAMETER;
        }

        if (FAILED(retVal))
        {
            SendFailPacket(retVal);
        }
    }
    else
    {
        retVal = HXR_UNEXPECTED;
    }

    return retVal;
}

STDMETHODIMP CRealPixFileFormat::Seek(UINT32 ulRequestedTime)
{
#ifdef XXXMEH_DEBUG_LOG
    DEBUG_OUTF("c:\\pxff.log", (s, "CRealPixFileFormat::Seek(0x%08X,%lu)\n", this, ulRequestedTime));
#endif
    HX_RESULT retVal = HXR_OK;

    if (m_ulState == kStateAwaitingGetPacket ||
        m_ulState == kStateReadingImageFile  ||
        m_ulState == kStateStreamDone)
    {
        retVal = m_pPacketScheduler->SeekSetup(ulRequestedTime);
        if (SUCCEEDED(retVal))
        {
            // Set the state
            m_ulState = kStateAwaitingGetPacket;
        }

        // Inform the response interface
        m_pFileFormatResponse->SeekDone(retVal);
    }
    else
    {
        retVal = HXR_UNEXPECTED;
    }

    return retVal;
}

STDMETHODIMP_(BOOL) CRealPixFileFormat::IsInterruptSafe()
{
    return TRUE;
}

STDMETHODIMP CRealPixFileFormat::ReadRPFileDone(HX_RESULT status, IHXBuffer* pBuffer)
{
#ifdef XXXMEH_DEBUG_LOG
    DEBUG_OUTF("c:\\pxff.log", (s, "CRealPixFileFormat::ReadRPFileDone(0x%08X,0x%08X,0x%08X)\n",
               this, status, pBuffer));
#endif
    HX_RESULT retVal = HXR_OK;

    if (m_ulState == kStateReadingRPFile)
    {
        if (SUCCEEDED(status))
        {
            // Create a PXRealPixFile object
            HX_RELEASE(m_pRealPixFile);
            retVal = PXRealPixFile::CreateObject(&m_pRealPixFile);
            if (SUCCEEDED(retVal))
            {
                // Addref the object
                m_pRealPixFile->AddRef();
                // Set the URL from the IHXRequest into the filename
                // of the PXRealPixFile
                const char* pszURL = NULL;
                m_pRequest->GetURL(pszURL);
                if (pszURL)
                {
                    m_pRealPixFile->SetFileName(pszURL);
                }
                // Parse the file
                retVal = ParseRealPixFile(pBuffer, m_pRealPixFile, m_ulStrictnessLevel);
                if (SUCCEEDED(retVal))
                {
                    // If we have all the sizes OK from the .rp file, then there's no
                    // reason to do the image stat()'s.
                    if (m_pRealPixFile->AllImageSizesInitialized() &&
                        m_pRealPixFile->AllImageSizesOK())
                    {
                        // We got all the image sizes from the .rp file, so we
                        // can go head and do the rest of our initialization.
                        retVal = InitFromRPFile();
                        if (SUCCEEDED(retVal))
                        {
                            // Set state
                            m_ulState = kStateFileFormatInitialized;
                            // Call back to the response interface
                            m_pFileFormatResponse->InitDone(HXR_OK);
                        }
                    }
                    else
                    {
                        // Set the size of pointer array
                        m_pFileHandlerArray->SetSize(m_pRealPixFile->GetNumImagesWithNoSize());
                        // NULL out all the pointers
                        UINT32 i             = 0;
                        UINT32 ulNumHandlers = (UINT32) m_pFileHandlerArray->GetSize();
                        for (i = 0; i < ulNumHandlers; i++)
                        {
                            m_pFileHandlerArray->SetAt(i, NULL);
                        }
                        // Set the state
                        m_ulState = kStateImageStat;
                        // Loop through the images, kicking off a stat for each
                        void*  pItr = NULL;
                        retVal      = m_pRealPixFile->GetImageIterator(pItr);
                        if (SUCCEEDED(retVal))
                        {
                            i                  = 0;
                            UINT32    ulHandle = 0;
                            HX_RESULT rv       = m_pRealPixFile->GetNextImageHandle(pItr, ulHandle);

                            while (SUCCEEDED(rv) && SUCCEEDED(retVal))
                            {
                                if (!m_pRealPixFile->IsImageSizeInitialized(ulHandle))
                                {
                                    // Create a file handler
                                    PXFileHandler* pHandler = new PXFileHandler();
                                    if (pHandler)
                                    {
                                        // AddRef the object
                                        pHandler->AddRef();
                                        // Init the handler
                                        retVal = pHandler->Init(m_pContext, m_pRPFileObject, this);
                                        if (SUCCEEDED(retVal))
                                        {
                                            // Get the name of this image
                                            IHXBuffer* pNameStr = NULL;
                                            retVal               = m_pRealPixFile->GetImageName(ulHandle, pNameStr);
                                            if (SUCCEEDED(retVal))
                                            {
                                                AllowPoolPathAdjustment (pNameStr);

                                                // Put the handler in the array
                                                pHandler->AddRef();
                                                m_pFileHandlerArray->SetAt(i, (void*) pHandler);
                                                // Increment the index
                                                i++;
                                                // Kick off a stat on this image
                                                retVal = pHandler->StatImageFile(ulHandle, pNameStr);
                                            }
                                            HX_RELEASE(pNameStr);
                                        }
                                    }
                                    else
                                    {
                                        retVal = HXR_OUTOFMEMORY;
                                    }
                                    HX_RELEASE(pHandler);
                                }
                                if (SUCCEEDED(retVal))
                                {
                                    // Get the next image
                                    rv = m_pRealPixFile->GetNextImageHandle(pItr, ulHandle);
                                }
                            }
                        }
                    }
                }
            }
        }
        else
        {
            m_ulState = kStateError;
            m_pFileFormatResponse->InitDone(status);
        }

        if (FAILED(retVal))
        {
            m_ulState = kStateError;
            m_pFileFormatResponse->InitDone(retVal);
        }
    }
    else
    {
        retVal = HXR_UNEXPECTED;
    }

    return retVal;
}


//
// IHXPoolPathAdjustment::AllowPoolPathAdjustment
//
// If the .rp file object came from a filesystem which 
// implements IHXPoolPathAdjustment, the filesystem may need
// to alter absolute local URLs opened from the same pool
// via IHXGetFileFromSamePool.  IHXPoolPathAdjustment::AdjustAbsolutePath()
// allows the filesystem to alter the path.
//
HX_RESULT CRealPixFileFormat::AllowPoolPathAdjustment (REF(IHXBuffer*) pNameStr)
{
    if (m_pPoolPathAdjustment)
    {
        IHXBuffer* pNewNameStr = NULL;
        m_pPoolPathAdjustment->AdjustAbsolutePath(pNameStr, pNewNameStr);
        if (pNewNameStr)
        {
            pNameStr->Release();
            pNameStr = pNewNameStr;
	    return HXR_OK;
        }
    }
    return HXR_FAIL;
}


STDMETHODIMP CRealPixFileFormat::StatImageFileDone(HX_RESULT status, UINT32 ulInstance,
                                                   UINT32 ulSize, IHXBuffer* pMimeTypeStr)
{
#ifdef XXXMEH_DEBUG_LOG
    DEBUG_OUTF("c:\\pxff.log", (s, "CRealPixFileFormat::StatImageFileDone(0x%08X,0x%08X,%lu,%lu,%s)\n",
               this, status, ulInstance, ulSize,
               (pMimeTypeStr ? (const char*) pMimeTypeStr->GetBuffer() : NULL)));
#endif
    HX_RESULT retVal = HXR_OK;

    if (m_ulState == kStateImageStat)
    {
        if (SUCCEEDED(status))
        {
            // Set the image size
            m_pRealPixFile->SetImageSize(ulInstance, ulSize);
            // Set the image file mime type
            if (pMimeTypeStr)
            {
                m_pRealPixFile->SetImageFileMimeType(ulInstance, pMimeTypeStr);
            }
        }
        else
        {
            // Set an error in the PXRealPixFile
            m_pRealPixFile->SetImageErrorStatus(ulInstance, status);
        }

        if (SUCCEEDED(retVal))
        {
            // Have all the stat's reported back yet?
            if (m_pRealPixFile->AllImageSizesInitialized())
            {
                // Now we check if there were any error in the stat's
                if (m_pRealPixFile->AllImageSizesOK())
                {
                    // None of the images were zero-sized. Therefore, all of
                    // the stats returned OK
                    retVal = InitFromRPFile();
                    if (SUCCEEDED(retVal))
                    {
                        // Set state
                        m_ulState = kStateFileFormatInitialized;
                        // Call back to the response interface
                        m_pFileFormatResponse->InitDone(HXR_OK);
                    }
                }
                else
                {
                    // Get the name of the image which failed
                    IHXBuffer* pFailedNameStr = NULL;
                    HX_RESULT   rv             = m_pRealPixFile->GetFailedImageName(pFailedNameStr);
                    if (SUCCEEDED(rv))
                    {
                        ReportError(IDS_ERR_PIX_MISSINGFILE,
                                    (const char*) pFailedNameStr->GetBuffer(),
                                    NULL,
                                    HXLOG_CRIT,
                                    HXR_FAIL);
                        retVal = HXR_FAIL;
                    }
                    HX_RELEASE(pFailedNameStr);
                }
            }
        }

        if (FAILED(retVal))
        {
            retVal = m_pFileFormatResponse->InitDone(retVal);
        }
    }
    else
    {
        retVal = HXR_UNEXPECTED;
    }

    return retVal;
}

STDMETHODIMP CRealPixFileFormat::ReadImageFileDone(HX_RESULT status, UINT32 ulInstance, IHXBuffer* pBuffer)
{
#ifdef XXXMEH_DEBUG_LOG
    DEBUG_OUTF("c:\\pxff.log", (s, "CRealPixFileFormat::ReadImageFileDone(0x%08X,0x%08X,%lu,0x%08X)\n",
               this, status, ulInstance, pBuffer));
#endif
    HX_RESULT retVal = HXR_OK;

    if (m_ulState == kStateReadingImageFile)
    {
        if (SUCCEEDED(status))
        {
            // Get the image header info again
            UINT32      ulHandle       = 0;
            UINT32      ulSize         = 0;
            IHXBuffer* pFileMimeStr   = NULL;
            IHXBuffer* pStreamMimeStr = NULL;
            IHXBuffer* pNameStr       = NULL;
            UINT32      ulTime         = 0;
            retVal = m_pPacketScheduler->GetImageHeaderInfo(ulHandle, ulSize, pFileMimeStr,
                                                            pNameStr, pStreamMimeStr, ulTime);
            if (SUCCEEDED(retVal))
            {
                AllowPoolPathAdjustment (pNameStr);

                // Get an interface to the proper codec to parse this buffer
                // Since we only parse one image at a time, then we will
                // save this pointer in a member variable.
                HX_RELEASE(m_pCodec);
                retVal = m_pCodecManager->GetCodec((const char*) (pFileMimeStr ? pFileMimeStr->GetBuffer() : NULL),
                                                   (const char*) (pNameStr     ? pNameStr->GetBuffer()     : NULL),
                                                   pBuffer,
                                                   m_pCodec);
                if (SUCCEEDED(retVal))
                {
                    // Parse the image
                    UINT32      ulNumPackets    = 0;
                    IHXValues* pParam          = NULL;
                    retVal                      = m_pCodec->ParseImage(pBuffer,
                                                                       ulNumPackets,
                                                                       pParam,
                                                                       m_ulSessionHandle);
                    if (SUCCEEDED(retVal))
                    {
                        // Set the flag saying we are holding packets in a codec
                        m_bImageParseActive = TRUE;
                        // Pass this info on to the scheduler
                        retVal = m_pPacketScheduler->SetImageDataInfo(ulNumPackets, m_ulSessionHandle);
                        if (SUCCEEDED(retVal))
                        {
                            // Get the packet info for the image header packet
                            IHXPacket* pPacket = NULL;
                            retVal = m_pWireFormatManager->SetImageHeaderInfo(ulHandle,       // image handle
                                                                              ulSize,         // image file size
                                                                              0,              // flags
                                                                              pStreamMimeStr, // stream mime
                                                                              ulTime,         // timestamp
                                                                              pPacket);
                            if (SUCCEEDED(retVal))
                            {
#ifdef XXXMEH_OUTPUT_DEBUG_STRING
                                char szDbgStr[128]; /* Flawfinder: ignore */
                                sprintf(szDbgStr, "Sending Image Header Packet (handle=%lu)\n", ulHandle); /* Flawfinder: ignore */
                                OutputDebugString(szDbgStr);
#endif
                                // Tell the scheduler we've sent the packet
                                m_pPacketScheduler->PacketSent(m_pWireFormatManager->GetPacketSize(pPacket));
                                // Set the state
                                m_ulState = kStateAwaitingGetPacket;
                                // Send the packet
                                m_pFileFormatResponse->PacketReady(HXR_OK, pPacket);
                            }
                            HX_RELEASE(pPacket);
                        }
                    }
                    HX_RELEASE(pParam);
                }
            }
            HX_RELEASE(pFileMimeStr);
            HX_RELEASE(pStreamMimeStr);
            HX_RELEASE(pNameStr);
        }
        else
        {
            retVal = status;
        }

        if (FAILED(retVal))
        {
            SendFailPacket(retVal);
        }
    }
    else
    {
        retVal = HXR_UNEXPECTED;
    }

    return retVal;
}

STDMETHODIMP CRealPixFileFormat::ShutdownDone(HX_RESULT status, UINT32 ulInstance)
{
#ifdef XXXMEH_DEBUG_LOG
    DEBUG_OUTF("c:\\pxff.log", (s, "CRealPixFileFormat::ShutdownDone(0x%08X,0x%08X,%lu) ",
               this, status, ulInstance));
#endif
    HX_RESULT retVal = HXR_OK;

    if (m_ulState == kStateShutdown ||
        m_ulState == kStateGetFileHeaderShutdown)
    {
        // Check to see if all the file handlers have been shutdown
        BOOL bAllShutdownDone = TRUE;
        if (m_pRPFileHandler && m_bShutdownRPFile)
        {
            bAllShutdownDone = m_pRPFileHandler->IsShutdownDone();
        }
        if (m_pImageFileHandler && bAllShutdownDone)
        {
            bAllShutdownDone = m_pImageFileHandler->IsShutdownDone();
        }
        if (m_pFileHandlerArray && bAllShutdownDone)
        {
            UINT32 ulNumHandlers = (UINT32) m_pFileHandlerArray->GetSize();
            for (UINT32 i = 0; i < ulNumHandlers && bAllShutdownDone; i++)
            {
                // Get the file handler
                PXFileHandler* pHandler = (PXFileHandler*) m_pFileHandlerArray->GetAt(i);
                // Find out if it's done
                if (pHandler)
                {
                    bAllShutdownDone = pHandler->IsShutdownDone();
                }
            }
        }
        // If all the file handlers have been shutdown, then deallocate
        if (bAllShutdownDone)
        {
            if (m_ulState == kStateShutdown)
            {
#ifdef XXXMEH_DEBUG_LOG
                DEBUG_OUTF("c:\\pxff.log", (s, "state = kStateShutdown - Calling Deallocate()"));
#endif
                Deallocate();
            }
            else if (m_ulState == kStateGetFileHeaderShutdown)
            {
#ifdef XXXMEH_DEBUG_LOG
                DEBUG_OUTF("c:\\pxff.log", (s, "state = kStateGetFileHeaderShutdown - Sending file header"));
#endif
                // Now we can release the .rp file handler if we shut it down
                if (m_bShutdownRPFile)
                {
                    HX_RELEASE(m_pRPFileHandler);
                }
                // Now we can release the individual image file handler
                HX_RELEASE(m_pImageFileHandler);
                // Now release all the image file handlers
                ReleaseAllFileHandlers();
                // Now get the file header from the wire format manager
                IHXValues* pFileHeader  = NULL;
                const char* pszAcceptStr = (m_pAcceptMetaInfoStr ? (const char*) m_pAcceptMetaInfoStr->GetBuffer() : NULL);
                retVal                   = m_pWireFormatManager->GetFileHeader(pFileHeader, pszAcceptStr);
                if (SUCCEEDED(retVal))
                {
                    // Set the state
                    m_ulState = kStateFileHeaderSent;
                    // Send the file header
                    m_pFileFormatResponse->FileHeaderReady(HXR_OK, pFileHeader);
                }
                HX_RELEASE(pFileHeader);
            }
        }
    }
    else
    {
        retVal = HXR_UNEXPECTED;
    }

#ifdef XXXMEH_DEBUG_LOG
    DEBUG_OUTF("c:\\pxff.log", (s, "\n"));
#endif
    return retVal;
}

HX_RESULT STDAPICALLTYPE CRealPixFileFormat::HXCreateInstance(IUnknown** ppIUnknown)
{
    HX_RESULT retVal = HXR_OK;

    if (ppIUnknown)
    {
        // Set default
        *ppIUnknown = NULL;
        // Create the object
        CRealPixFileFormat* pObj = new CRealPixFileFormat();
        if (pObj)
        {
            // QI for IUnknown
            retVal = pObj->QueryInterface(IID_IUnknown, (void**) ppIUnknown);
        }
        else
        {
            retVal = HXR_OUTOFMEMORY;
        }
        if (FAILED(retVal))
        {
            HX_DELETE(pObj);
        }
    }
    else
    {
        retVal = HXR_FAIL;
    }

    return HXR_OK;
}

HX_RESULT CRealPixFileFormat::InitFromRPFile()
{
    HX_RESULT retVal = HXR_OK;

    if (m_pRealPixFile && m_pCodecManager && m_pWireFormatManager)
    {
        IHXBuffer* pImageNameStr = NULL;
        retVal = CheckForCodecs(pImageNameStr);
        if (SUCCEEDED(retVal))
        {
            retVal = AddCodecsToWireFormatManager();
            if (SUCCEEDED(retVal))
            {
                // Now we can release inactive codecs
                retVal = m_pCodecManager->ReleaseInactiveComponents();
                if (SUCCEEDED(retVal))
                {
                    // Create a PXScheduler object
                    HX_RELEASE(m_pPacketScheduler);
                    retVal = PXScheduler::CreateObject(&m_pPacketScheduler);
                    if (SUCCEEDED(retVal))
                    {
                        // AddRef the object
                        m_pPacketScheduler->AddRef();
                        // Now since we know how big each of the images
                        // are, we can schedule our packets
                        retVal = m_pPacketScheduler->Init(m_pRealPixFile, m_pWireFormatManager);
                        if (SUCCEEDED(retVal))
                        {
                            // Now we need to set values in the wire format manager
                            UINT32 ulPreroll = (m_pRealPixFile->GetPreroll() > m_pPacketScheduler->GetMinimumPreroll() ?
                                                m_pRealPixFile->GetPreroll() : m_pPacketScheduler->GetMinimumPreroll());
                            m_pWireFormatManager->SetBitrate(m_pRealPixFile->GetBitrate());
                            m_pWireFormatManager->SetDisplayWidth(m_pRealPixFile->GetDisplayWidth());
                            m_pWireFormatManager->SetDisplayHeight(m_pRealPixFile->GetDisplayHeight());
                            m_pWireFormatManager->SetDuration(m_pRealPixFile->GetDuration());
                            m_pWireFormatManager->SetLive(FALSE);
                            m_pWireFormatManager->SetStreamMimeType(m_ppszStreamMimeTypes[0]);
                            m_pWireFormatManager->SetPreroll(ulPreroll);
                            m_pWireFormatManager->SetPreData(m_pRealPixFile->GetBitrate() * ulPreroll / 8000);
                            m_pWireFormatManager->SetPreDataAtStart(TRUE);
                            m_pWireFormatManager->SetPrerollAfterSeek(TRUE);
                            m_pWireFormatManager->SetBackgroundColor(m_pRealPixFile->GetBackgroundColor());
                            m_pWireFormatManager->SetBackgroundOpacity(m_pRealPixFile->GetBackgroundOpacity());

                            // Set the default URL into the wire format manager
                            IHXBuffer* pDefaultURLStr = NULL;
                            m_pRealPixFile->GetDefaultURL(&pDefaultURLStr);
                            if (pDefaultURLStr)
                            {
                                m_pWireFormatManager->SetDefaultURL(pDefaultURLStr);
                            }
                            HX_RELEASE(pDefaultURLStr);

                            // Set the wire format stream and content version. Right now, we are driven only
                            // by the content version of the .rp file. Therefore, we set both the
                            // stream and content version to the content version of the .rp file.
                            m_pWireFormatManager->SetStreamVersion(m_pRealPixFile->GetContentVersion());
                            m_pWireFormatManager->SetContentVersion(m_pRealPixFile->GetContentVersion());
                                
                            // Set the ASM rule book
                            char szASMRuleBook[256]; /* Flawfinder: ignore */
                            sprintf(szASMRuleBook, /* Flawfinder: ignore */
                                    "Priority=5,AverageBandwidth=%lu;Priority=10,AverageBandwidth=0;",
                                    m_pRealPixFile->GetBitrate());
                            m_pWireFormatManager->SetASMRuleBook(szASMRuleBook);
                        }
                    }
                }
            }
        }
        else
        {
            // Report error for no codec
            ReportError(IDS_ERR_PIX_NOCODEC,
                        (const char*) (pImageNameStr ? pImageNameStr->GetBuffer() : NULL),
                        NULL,
                        HXLOG_CRIT,
                        HXR_FAIL);
        }
        HX_RELEASE(pImageNameStr);
    }
    else
    {
        retVal = HXR_UNEXPECTED;
    }

    return retVal;
}

void CRealPixFileFormat::ShutdownAllFileHandlers(BOOL bShutdownRPFile)
{
    BOOL bShutdownCalled = FALSE;

    // Save whether or not we are shutting down the .rp file handler
    m_bShutdownRPFile = bShutdownRPFile;
    // Shutdown the .rp file handler
    if (m_pRPFileHandler && m_bShutdownRPFile)
    {
        bShutdownCalled = TRUE;
        m_pRPFileHandler->Shutdown();
    }
    // Shutdown the individual image file handler
    if (m_pImageFileHandler)
    {
        bShutdownCalled = TRUE;
        m_pImageFileHandler->Shutdown();
    }
    // Shutdown any file handler in the array
    if (m_pFileHandlerArray)
    {
        UINT32 ulNumHandlers = m_pFileHandlerArray->GetSize();
        for (UINT32 i = 0; i < ulNumHandlers; i++)
        {
            // Get the file handler
            PXFileHandler* pHandler = (PXFileHandler*) m_pFileHandlerArray->GetAt(i);
            // Call Shutdown on the file handler
            if (pHandler)
            {
                bShutdownCalled = TRUE;
                pHandler->Shutdown();
            }
        }
    }

    // If we are coming from GetFileHeader() and we had all the sizes of
    // all the images provided for us, then we might not be shutting down
    // any file handlers here. Therefore, if we didn't call Shutdown()
    // on any file handlers here, then we need to short-circuit the
    // async loop and call ShutdownDone() here.
    if (!bShutdownCalled)
    {
        ShutdownDone(HXR_OK, 0);
    }
}

void CRealPixFileFormat::ReleaseAllFileHandlers()
{
    if (m_pFileHandlerArray)
    {
        UINT32 ulNumHandlers = (UINT32) m_pFileHandlerArray->GetSize();
        for (UINT32 i = 0; i < ulNumHandlers; i++)
        {
            PXFileHandler* pHandler = (PXFileHandler*) m_pFileHandlerArray->GetAt(i);
            HX_RELEASE(pHandler);
        }
        m_pFileHandlerArray->RemoveAll();
    }
}

void CRealPixFileFormat::ReportError(UINT32 ulErrorID, const char* pszArg1, const char* pszArg2,
                                     const UINT8 ucSeverity, HX_RESULT ulHXCode)
{
    if (m_pContext)
    {
        IHXBuffer* pErrStr = NULL;
        PXError     cErr(m_pContext);
        cErr.SetError(ulErrorID, pszArg1, pszArg2, pErrStr);
        if (pErrStr)
        {
            ReportError(ucSeverity, ulHXCode, pErrStr);
        }
        HX_RELEASE(pErrStr);
    }
}

void CRealPixFileFormat::ReportError(const UINT8 ucSeverity,
                                     HX_RESULT   ulHXCode,
                                     IHXBuffer* pErrorStr)
{
    if (pErrorStr)
    {
        if (m_pContext)
        {
            IHXErrorMessages* pErrorMessages = NULL;
            m_pContext->QueryInterface(IID_IHXErrorMessages, (void**) &pErrorMessages);
            if (pErrorMessages)
            {
                pErrorMessages->Report(ucSeverity,                           // severity
                                       ulHXCode,                            // RMA result (i.e. - HXR_FAIL, HXR_OUTOFMEMORY, etc.)
                                       0,                                    // user code (not used here)
                                       (const char*) pErrorStr->GetBuffer(), // string to be displayed
                                       NULL);                                // more info string (not used here)
            }
            HX_RELEASE(pErrorMessages);
        }
    }
}

HX_RESULT CRealPixFileFormat::GetRegistrySettings(REF(BOOL)   rbLicensed,
                                                  REF(UINT32) rulStrictnessLevel)
{
    HX_RESULT retVal = HXR_OK;

    // Set defaults
    rbLicensed         = FALSE;
    rulStrictnessLevel = REALPIX_STRICTNESS_LOW;

    IHXRegistry* pRegistry = NULL;
    retVal                    = m_pContext->QueryInterface(IID_IHXRegistry, (void**) &pRegistry);
    if (SUCCEEDED(retVal))
    {
        // Figure out if RealPix is licensed
        IHXPlayer* pPlayer = NULL;
        m_pContext->QueryInterface(IID_IHXPlayer, (void**) &pPlayer);
        if (pPlayer)
        {
            // RealPix is always licensed on the player
            rbLicensed = TRUE;
        }
        else
        {
            // On the Server, check the license section of the registry
            INT32     lLicensed = 0;
            HX_RESULT rv        = pRegistry->GetIntByName(REGISTRY_REALPIX_ENABLED, lLicensed);
            if (FAILED(rv))
            {
                lLicensed = LICENSE_REALPIX_ENABLED;
            }
            rbLicensed = (lLicensed ? TRUE : FALSE);
        }
        HX_RELEASE(pPlayer);

        INT32     lLevel = 0;
        HX_RESULT rv     = pRegistry->GetIntByName("config.RealPixStrictnessLevel", lLevel);
        if (SUCCEEDED(rv))
        {
            rulStrictnessLevel = (UINT32) lLevel;
        }
    }
    HX_RELEASE(pRegistry);

    return retVal;
}

HX_RESULT CRealPixFileFormat::CheckForCodecs(REF(IHXBuffer*) rpImageNameStr)
{
    HX_RESULT retVal = HXR_OK;

    if (m_pRealPixFile && m_pCodecManager)
    {
        if (m_pRealPixFile->GetNumImages() > 0)
        {
            // Loop through all the images, checking to make sure
            // we have all the codecs we need
            IHXBuffer* pImageName         = NULL;
            IHXBuffer* pImageFileMimeType = NULL;
            void*       pItr               = NULL;
            retVal                         = m_pRealPixFile->GetImageIterator(pItr);
            if (SUCCEEDED(retVal))
            {
                UINT32    ulHandle = 0;
                HX_RESULT rv       = m_pRealPixFile->GetNextImageHandle(pItr, ulHandle);
                while (SUCCEEDED(rv) && SUCCEEDED(retVal))
                {
                    // Get the image name
                    HX_RELEASE(pImageName);
                    m_pRealPixFile->GetImageName(ulHandle, pImageName);
                    // Get the image file mime type
                    HX_RELEASE(pImageFileMimeType);
                    m_pRealPixFile->GetImageFileMimeType(ulHandle, pImageFileMimeType);
                    // Check if this codec is present
                    if (m_pCodecManager->IsCodecPresent((pImageFileMimeType ? (const char*) pImageFileMimeType->GetBuffer() : (const char *)NULL),
                                                        (pImageName ? (const char*) pImageName->GetBuffer() : (const char*)NULL),
                                                        NULL))
                    {
                        rv = m_pRealPixFile->GetNextImageHandle(pItr, ulHandle);
                    }
                    else
                    {
                        // Copy the bad image to the out param
                        if (pImageName)
                        {
                            HX_RELEASE(rpImageNameStr);
                            rpImageNameStr = pImageName;
                            rpImageNameStr->AddRef();
                        }
                        retVal = HXR_FAIL;
                    }
                }
            }
            HX_RELEASE(pImageName);
            HX_RELEASE(pImageFileMimeType);
        }
    }
    else
    {
        retVal = HXR_UNEXPECTED;
    }

    return retVal;
}

HX_RESULT CRealPixFileFormat::AddCodecsToWireFormatManager()
{
    HX_RESULT retVal = HXR_OK;

    if (m_pRealPixFile && m_pCodecManager && m_pWireFormatManager)
    {
        if (m_pRealPixFile->GetNumImages() > 0)
        {
            // Run through the list, adding codecs to the wire format manager
            void* pItr = NULL;
            retVal     = m_pRealPixFile->GetImageIterator(pItr);
            if (SUCCEEDED(retVal))
            {
                UINT32    ulHandle = 0;
                HX_RESULT rv       = m_pRealPixFile->GetNextImageHandle(pItr, ulHandle);
                while (SUCCEEDED(rv) && SUCCEEDED(retVal))
                {
                    IHXRealPixFileFormatCodec* pCodec = NULL;
                    retVal = m_pCodecManager->GetCodec(m_pRealPixFile->GetImageFileMimeType(ulHandle),
                                                       m_pRealPixFile->GetImageName(ulHandle),
                                                       NULL,
                                                       pCodec);
                    if (SUCCEEDED(retVal))
                    {
                        const char** ppszFileExt       = NULL;
                        const char** ppszFileMime      = NULL;
                        const char*  pszStreamMimeType = NULL;
                        UINT32       ulStreamVersion   = 0;
                        UINT32       ulMaxPerImg       = 0;
                        UINT32       ulMaxPerPckt      = 0;
                        retVal = pCodec->GetFileFormatCodecInfo(ppszFileExt, ppszFileMime,
                                                                pszStreamMimeType, ulStreamVersion,
                                                                ulMaxPerImg, ulMaxPerPckt);
                        if (SUCCEEDED(retVal))
                        {
                            // Set the stream mime back into the image
                            retVal = m_pRealPixFile->SetImageStreamMimeType(ulHandle, pszStreamMimeType);
                            if (SUCCEEDED(retVal))
                            {
                                // Add it to the wire format codec list
                                retVal = m_pWireFormatManager->AddCodecMime(pszStreamMimeType);
                                if (SUCCEEDED(retVal))
                                {
                                    // Tell the codec manager that this codec is active
                                    retVal = m_pCodecManager->SetActiveComponent(pszStreamMimeType);
                                    if (SUCCEEDED(retVal))
                                    {
                                        // Get the next image
                                        rv = m_pRealPixFile->GetNextImageHandle(pItr, ulHandle);
                                    }
                                }
                            }
                        }
                    }
                    HX_RELEASE(pCodec);
                }
            }
        }
    }
    else
    {
        retVal = HXR_UNEXPECTED;
    }

    return retVal;
}

HX_RESULT CRealPixFileFormat::ParseRealPixFile(IHXBuffer*    pBuffer,
                                               PXRealPixFile* pRealPixFile,
                                               UINT32         ulStrictnessLevel)
{
    HX_RESULT retVal = HXR_OK;

    if (pBuffer && pRealPixFile)
    {
#ifdef XXXMEH_USE_NEW_PARSER
        // Create a PXRealPixParser object
        PXRealPixParser* pParser = NULL;
        retVal                   = PXRealPixParser::CreateObject(&pParser);
        if (SUCCEEDED(retVal))
        {
            // AddRef the parser object
            pParser->AddRef();
            // Init the parser
            retVal = pParser->Init(m_pContext, m_pRealPixFile, ulStrictnessLevel);
            if (SUCCEEDED(retVal))
            {
                // Parse the file
                IHXBuffer* pErrorStr = NULL;
                retVal                = pParser->Parse(pBuffer, TRUE, pErrorStr);
                if (FAILED(retVal))
                {
                    ReportError(HXLOG_CRIT, retVal, pErrorStr);
                }
                HX_RELEASE(pErrorStr);
            }
        }
        HX_RELEASE(pParser);
#else
        // We found <imfl> so use the lax parser
        CIMFFileObject cOldParser;
        GString        cBuf((const char*) pBuffer->GetBuffer(),
                            pBuffer->GetSize(), GSTRING_REFMODE);
        UINT32         ulErrorID;
        CHXString      cErrorText;
        BOOL bRet = cOldParser.InitFromText(cBuf, ulErrorID, cErrorText);
        if (bRet)
        {
            retVal = cOldParser.ConvertToNewFileObject(m_pRealPixFile);
            if (SUCCEEDED(retVal))
            {
                retVal = m_pRealPixFile->PostParseInit();
            }
        }
        else
        {
            const char* pszErr = (const char*) cErrorText;
            const char* pszArg = (strlen(pszErr) > 0 ? pszErr : (const char*) NULL);
            ReportError(ulErrorID, pszArg, NULL, HXLOG_CRIT, HXR_FAIL);
            retVal = HXR_FAIL;
        }
#endif
    }
    else
    {
        retVal = HXR_INVALID_PARAMETER;
    }

    return retVal;
}

void CRealPixFileFormat::SendFailPacket(HX_RESULT retVal)
{
    if (m_pCommonClassFactory && m_pFileFormatResponse)
    {
        // Create an IHXPacket
        IHXPacket* pPacket = NULL;
        m_pCommonClassFactory->CreateInstance(CLSID_IHXPacket, (void**) &pPacket);
        if (pPacket)
        {
            // Set a NULL buffer and the stream number
            pPacket->Set(NULL, 0, 0, HX_ASM_SWITCH_ON, 0);
            // Call the response interface
            m_pFileFormatResponse->PacketReady(retVal, pPacket);
        }
        HX_RELEASE(pPacket);
    }
}
/************************************************************************
 *      Method:
 *          IHXThreadSafeMethods::IsThreadSafe
 */
STDMETHODIMP_(UINT32)
CRealPixFileFormat::IsThreadSafe()
{
    return HX_THREADSAFE_METHOD_FF_GETPACKET;
}

