atomizer.cpp
字号:
/* ***** BEGIN LICENSE BLOCK *****
* Version: RCSL 1.0/RPSL 1.0
*
* Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved.
*
* The contents of this file, and the files included with this file, are
* subject to the current version of the RealNetworks Public Source License
* Version 1.0 (the "RPSL") available at
* http://www.helixcommunity.org/content/rpsl unless you have licensed
* the file under the RealNetworks Community Source License Version 1.0
* (the "RCSL") available at http://www.helixcommunity.org/content/rcsl,
* in which case the RCSL will apply. You may also obtain the license terms
* directly from RealNetworks. You may not use this file except in
* compliance with the RPSL or, if you have a valid RCSL with RealNetworks
* applicable to this file, the RCSL. Please see the applicable RPSL or
* RCSL for the rights, obligations and limitations governing use of the
* contents of the file.
*
* This file is part of the Helix DNA Technology. RealNetworks is the
* developer of the Original Code and owns the copyrights in the portions
* it created.
*
* This file, and the files included with this file, is distributed and made
* available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
*
* Technology Compatibility Kit Test Suite(s) Location:
* http://www.helixcommunity.org/content/tck
*
* Contributor(s):
*
* ***** END LICENSE BLOCK ***** */
/****************************************************************************
* Defines
*/
#define ATMZR_SEEK_RELATIVE TRUE
#define ATMZR_SEEK_ABSOLUTE FALSE
#define ATMZR_MAX_RECURSION_LEVEL 20
#ifdef HELIX_FEATURE_MIN_HEAP
#define ATMZR_PAGING_THRESHOLD 0x00000400 // 1K
#else // HELIX_FEATURE_MIN_HEAP
#define ATMZR_PAGING_THRESHOLD 0x0000FFFF // 64K
#endif // HELIX_FEATURE_MIN_HEAP
#define ATMZR_MAX_FILE_SIZE 0xFFFFFFFF
/****************************************************************************
* Includes
*/
#include "atomizer.h"
#include "qtatoms.h"
#include "mempager.h"
#include "qtffrefcounter.h"
/****************************************************************************
* Data Types
*/
struct QTHeader
{
UINT8 pSize[4];
UINT8 pType[4];
};
struct QTNewHeader
{
UINT8 pSize[4];
UINT8 pType[4];
UINT8 pAtomID[4];
UINT8 pRsvd1[2];
UINT8 pChildCount[2];
UINT8 pRsvd2[4];
};
/****************************************************************************
* Class CAtomizer
*/
/****************************************************************************
* Constructor/Destructor
*/
CAtomizer::CAtomizer(void)
: m_pFileSwitcher(NULL)
, m_pResponse(NULL)
, m_pCommander(NULL)
, m_pScheduler(NULL)
, m_pRoot(NULL)
, m_pCurrentRoot(NULL)
, m_pNewAtom(NULL)
, m_ulStartOffset(0)
, m_ulFinalOffset(0)
, m_ulCurrentOffset(0)
, m_ulNewAtomOffset(0)
, m_ulNewAtomDataSize(0)
, m_AtomType(0)
, m_ulTotalSize(0)
, m_State(ATMZR_Offline)
, m_bSyncAccessEnabled(FALSE)
, m_bPreferLinearAccess(FALSE)
, m_pRecursionCallback(NULL)
, m_ulRecursionCount(0)
, m_lRefCount(0)
{
g_nRefCount_qtff++;
}
CAtomizer::~CAtomizer()
{
Close();
g_nRefCount_qtff--;
}
/****************************************************************************
* Main Interface
*/
/****************************************************************************
* Init
*/
HX_RESULT CAtomizer::Init(IUnknown *pSource,
IUnknown *pResponse,
IUnknown *pCommander)
{
HX_RESULT retVal;
if ((m_State != ATMZR_Offline) &&
(m_State != ATMZR_Ready))
{
return HXR_UNEXPECTED;
}
HX_ASSERT(pSource);
HX_ASSERT(pResponse);
// Reset
HX_RELEASE(m_pFileSwitcher);
HX_RELEASE(m_pResponse);
HX_RELEASE(m_pCommander);
HX_RELEASE(m_pRoot);
HX_RELEASE(m_pNewAtom);
HX_RELEASE(m_pRecursionCallback);
m_ulCurrentOffset = 0;
m_ulRecursionCount = 0;
// Find Input Interface
retVal = pSource->QueryInterface(IID_IHXFileSwitcher, (void**) &m_pFileSwitcher);
// Find out if syncrhonous use of input is possible
if (SUCCEEDED(retVal))
{
if (SUCCEEDED(m_pFileSwitcher->Advise(HX_FILEADVISE_SYNCACCESS)))
{
m_bSyncAccessEnabled = TRUE;
m_pFileSwitcher->Advise(HX_FILEADVISE_ASYNCACCESS);
}
HX_RESULT adviseRes =
m_pFileSwitcher->Advise(HX_FILEADVISE_RANDOMACCESS);
if (HXR_ADVISE_PREFER_LINEAR == adviseRes)
{
m_bPreferLinearAccess = TRUE;
}
}
// Find Output Interface
if (SUCCEEDED(retVal))
{
retVal = pResponse->QueryInterface(IID_IHXAtomizerResponse, (void**) &m_pResponse);
}
// Find Scheduler Interface
if (SUCCEEDED(retVal))
{
retVal = pResponse->QueryInterface(IID_IHXScheduler, (void **) &m_pScheduler);
if (FAILED(retVal))
{
retVal = pSource->QueryInterface(IID_IHXScheduler, (void **) &m_pScheduler);
}
}
// See if the Atomization Commander is given
if (SUCCEEDED(retVal))
{
if (pCommander)
{
pCommander->QueryInterface(IID_IHXAtomizationCommander, (void**) &m_pCommander);
}
if (!m_pCommander)
{
// No commander given, Atomizer will command itself
m_pCommander = (IHXAtomizationCommander *) this;
m_pCommander->AddRef();
}
m_State = ATMZR_Ready;
}
// Allocate Recursion breaker callback
#ifdef QTCONFIG_RECURSION_PROTECTION
if (SUCCEEDED(retVal))
{
m_pRecursionCallback = new CRecursionCallback(this);
if (m_pRecursionCallback)
{
m_pRecursionCallback->AddRef();
}
else
{
retVal = HXR_OUTOFMEMORY;
}
}
#endif // QTCONFIG_RECURSION_PROTECTION
return retVal;
}
/****************************************************************************
* Close
*/
void CAtomizer::Close(void)
{
m_State = ATMZR_Offline;
HX_RELEASE(m_pFileSwitcher);
HX_RELEASE(m_pResponse);
HX_RELEASE(m_pCommander);
HX_RELEASE(m_pScheduler);
HX_RELEASE(m_pRoot);
HX_RELEASE(m_pNewAtom);
HX_RELEASE(m_pRecursionCallback);
}
/****************************************************************************
* Atomize
*/
HX_RESULT CAtomizer::Atomize(ULONG32 ulOffset, ULONG32 ulSize)
{
if (m_State != ATMZR_Ready)
{
return HXR_UNEXPECTED;
}
if ((m_pFileSwitcher == NULL) ||
(m_pResponse == NULL) ||
(m_pCommander == NULL))
{
return HXR_FAIL;
}
// Reset
HX_RELEASE(m_pRoot);
HX_RELEASE(m_pNewAtom);
m_ulCurrentOffset = 0;
// Take on parameters
m_ulStartOffset = ulOffset;
m_ulNewAtomOffset = ulOffset;
m_ulTotalSize = ulSize;
m_ulFinalOffset = (m_ulTotalSize == ATOMIZE_ALL) ? ATOMIZE_ALL : m_ulStartOffset + m_ulTotalSize;
// Prepare the root
m_pRoot = new CQTRootAtom();
if (m_pRoot == NULL)
{
return HXR_OUTOFMEMORY;
}
m_pRoot->AddRef();
m_pRoot->SetSize(m_ulTotalSize);
m_pRoot->SetOffset(m_ulStartOffset);
m_pCurrentRoot = m_pRoot;
// Start of the atomization process
m_State = ATMZR_ProcHeader;
SeekDataCB(m_ulStartOffset);
return HXR_OK;
}
/****************************************************************************
* Private Methods
*/
/****************************************************************************
* SeekData
*/
HX_RESULT CAtomizer::SeekData(ULONG32 ulOffset, BOOL bRelative)
{
if (m_State == ATMZR_Offline)
{
return HXR_UNEXPECTED;
}
if (bRelative)
{
m_ulCurrentOffset += ulOffset;
}
else
{
m_ulCurrentOffset = ulOffset;
}
if (IsOffsetInRange(m_ulCurrentOffset))
{
HX_RESULT retVal;
// Initiate the Seek
retVal = m_pFileSwitcher->Seek( ulOffset,
bRelative,
(IHXFileResponse *) this);
if (FAILED(retVal))
{
CompleteAtomization(retVal);
}
}
else
{
CompleteAtomization(HXR_OK);
}
return HXR_ABORT;
}
/****************************************************************************
* ReadData
*/
HX_RESULT CAtomizer::ReadData(ULONG32 ulSize)
{
HX_RESULT retVal = HXR_OK;
if (m_State == ATMZR_Offline)
{
return HXR_UNEXPECTED;
}
if (m_State == ATMZR_ProcHeader)
{
retVal = AdjustCurrentRoot();
if (FAILED(retVal))
{
if (retVal == HXR_CHUNK_MISSING)
{
// udta Atom terminator encountered, must skip over the
// terminator chunk
m_ulNewAtomOffset = m_ulCurrentOffset +
QT_UDTA_TERMINATOR_LENGTH;
return SeekDataCB(m_ulNewAtomOffset);
}
else
{
CompleteAtomization(retVal);
return HXR_ABORT;
}
}
}
m_ulCurrentOffset += ulSize;
if (IsOffsetInRange(m_ulCurrentOffset - 1))
{
HX_RESULT retVal;
// Initiate the Read
retVal = m_pFileSwitcher->Read( ulSize,
(IHXFileResponse *) this);
if (SUCCEEDED(retVal))
{
return retVal;
}
}
CompleteAtomization(retVal);
return HXR_ABORT;
}
/****************************************************************************
* ReadDataCB
*/
HX_RESULT CAtomizer::ReadDataCB(ULONG32 ulSize)
{
#ifdef QTCONFIG_RECURSION_PROTECTION
if (m_ulRecursionCount < ATMZR_MAX_RECURSION_LEVEL)
{
m_ulRecursionCount++;
return ReadData(ulSize);
}
else
{
CallbackHandle retVal;
m_ulRecursionCount = 0;
m_ulSize = ulSize;
m_CallbackStep = ATMZR_CBSTEP_Read;
retVal = m_pScheduler->RelativeEnter(m_pRecursionCallback, 0);
if (!retVal)
{
CompleteAtomization(HXR_FAIL);
}
return HXR_OK;
}
#else // QTCONFIG_RECURSION_PROTECTION
return ReadData(ulSize);
#endif // QTCONFIG_RECURSION_PROTECTION
}
/****************************************************************************
* SeekDataCB
*/
HX_RESULT CAtomizer::SeekDataCB(ULONG32 ulOffset, BOOL bRelative)
{
#ifdef QTCONFIG_RECURSION_PROTECTION
if (m_ulRecursionCount < ATMZR_MAX_RECURSION_LEVEL)
{
m_ulRecursionCount++;
return SeekData(ulOffset, bRelative);
}
else
{
CallbackHandle retVal;
m_ulRecursionCount = 0;
m_ulSize = ulOffset;
m_bRelative = bRelative;
m_CallbackStep = ATMZR_CBSTEP_Seek;
retVal = m_pScheduler->RelativeEnter(m_pRecursionCallback, 0);
if (!retVal)
{
CompleteAtomization(HXR_FAIL);
}
return HXR_OK;
}
#else // QTCONFIG_RECURSION_PROTECTION
return SeekData(ulOffset, bRelative);
#endif // QTCONFIG_RECURSION_PROTECTION
}
/****************************************************************************
* AdjustCurrentRoot
*/
HX_RESULT CAtomizer::AdjustCurrentRoot(void)
{
CQTAtom *pRootParent;
HX_ASSERT(m_pCurrentRoot);
while ((m_pCurrentRoot->GetSize() != ATOMIZE_ALL) &&
((m_pCurrentRoot->GetOffset() +
m_pCurrentRoot->GetSize() -
m_ulNewAtomOffset) <
QT_HEADER_SIZE))
{
if (m_ulNewAtomOffset ==
(m_pCurrentRoot->GetOffset() + m_pCurrentRoot->GetSize()))
{
// Current Atom is completed, move to the parent
pRootParent = m_pCurrentRoot->GetParent();
if (pRootParent)
{
m_pCurrentRoot = pRootParent;
continue;
}
else
{
// We are at the absolute root
break;
}
}
else
{
// Not enough room in current parent to read a header, but
// still some data left over
if ((m_pCurrentRoot->GetType() == QT_udta) &&
((m_ulNewAtomOffset + QT_UDTA_TERMINATOR_LENGTH) ==
(m_pCurrentRoot->GetOffset() + m_pCurrentRoot->GetSize())))
{
// Legacy udta Atom termination - need to skip over the
// terminator
return HXR_CHUNK_MISSING;
}
else
{
// Data is corrupted
return HXR_PARSE_ERROR;
}
}
}
return HXR_OK;
}
/****************************************************************************
* CompleteAtomization
*/
void CAtomizer::CompleteAtomization(HX_RESULT status)
{
CQTAtom* pRoot;
if (!m_pRoot)
{
return;
}
if (SUCCEEDED(status))
{
// Record the amount of data atomized
CQTAtom *pRoot = m_pCurrentRoot;
HX_ASSERT(pRoot);
// If we have the position of where next atom would be,
// compute unspecified atom sizes
if (m_ulNewAtomOffset != ATOMIZE_ALL)
{
while (pRoot)
{
if (pRoot->GetSize() == ATOMIZE_ALL)
{
pRoot->SetSize(m_ulNewAtomOffset - m_ulStartOffset);
}
// Move to the parent
pRoot = pRoot->GetParent();
}
m_pRoot->SetSize(m_ulNewAtomOffset - m_ulStartOffset);
}
status = AdjustCurrentRoot();
}
if (SUCCEEDED(status))
{
// See if parsing fully completed
if (((m_ulFinalOffset != ATOMIZE_ALL) &&
(m_ulFinalOffset != m_ulCurrentOffset)) ||
(m_pRoot != m_pCurrentRoot))
{
status = HXR_CORRUPT_FILE;
}
}
else
{
// Data compromizing failure occured during atomization
HX_RELEASE(m_pRoot);
}
HX_RELEASE(m_pNewAtom);
m_State = ATMZR_Ready;
pRoot = m_pRoot;
m_pRoot = NULL;
m_pCurrentRoot = NULL;
m_pResponse->AtomReady(status, pRoot);
if (pRoot)
{
pRoot->Release();
}
}
/****************************************************************************
* IHXFileResponse methods
*/
/////////////////////////////////////////////////////////////////////////
// Method:
// IHXFileResponse::ReadDone
// Purpose:
// Notification interface provided by users of the IHXFileObject
// interface. This method is called by the IHXFileObject when the
// last read from the file is complete and a buffer is available.
//
STDMETHODIMP CAtomizer::ReadDone
(
HX_RESULT status,
IHXBuffer* pBuffer
)
{
HX_RESULT retVal = HXR_OK;
QTAtomType AtomType = 0;
ULONG32 ulAtomSize = 0;
UINT8* pData = NULL;
ULONG32 ulDataLen = 0;
ULONG32 ulNormalizedLen = 0;
ULONG32 ulAtomID = 0;
UINT16 uChildCount = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -