📄 chunkres.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 ***** */
#include "hxslist.h"
#include "chunkres.h"
#include "hlxclib/stdlib.h" // needed for MAX_PATH
#include "hlxclib/stdio.h" // for fopen(), etc.
#include "hlxclib/limits.h" // for INT_MAX, etc.
#include "hlxclib/fcntl.h" // for O_CREAT, etc.
#include "hlxclib/io.h"
#include "hlxclib/windows.h"
#include "chxdataf.h" // cross platform file object
#ifdef _MACINTOSH
#ifdef _MAC_MACHO
#include <unistd.h> // for unlink call
#else
#include <unix.h> // for unlink call
#undef _UNIX //defined in unixmac.h
#endif
#endif
#ifdef _UNIX
#include <unistd.h> // for unlink
#ifndef _MAX_PATH
#define _MAX_PATH 256
#endif
#endif
#ifdef _SYMBIAN
#include <unistd.h> //for unlink
#endif
#include "hxheap.h"
#ifdef _DEBUG
#undef HX_THIS_FILE
static const char HX_THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
//
// Method:
//
// CChunkyResMgr::OpenResource()
//
// Purpose:
//
// Opens an existing resource or creates a new resource.
//
// Parameters:
//
// CChunkyRes** ppChunkyRes
// Memory location that will be filled in on output with the pointer
// to the opened CChunkRes object.
//
// const char* pResName
// Unique name of the resource to open or create.
//
// Return:
//
// HX_RESULT
// Possible errors include: TBD.
//
HX_RESULT CChunkyResMgr::OpenResource(CChunkyRes** ppChunkyRes, const char* pResName)
{
HX_RESULT theErr = HXR_OK;
HX_ASSERT(ppChunkyRes && pResName);
void* pData;
if (m_OpenResources.Lookup(pResName, pData))
{
*ppChunkyRes = (CChunkyRes*)pData;
}
else if (m_ClosedResources.Lookup(pResName, pData))
{
*ppChunkyRes = (CChunkyRes*)pData;
HX_VERIFY(m_ClosedResources.RemoveKey(pResName));
m_OpenResources.SetAt(pResName, pData);
RemoveFromLRU(pResName);
}
else
{
*ppChunkyRes = new CChunkyRes;
if (*ppChunkyRes)
{
m_OpenResources.SetAt(pResName, (void*)*ppChunkyRes);
}
else
{
theErr = HXR_OUTOFMEMORY;
}
}
return theErr;
}
/////////////////////////////////////////////////////////////////////////////
//
// Method:
//
// CChunkyResMgr::CloseResource()
//
// Purpose:
//
// Closes an existing resource. Closed resources may be discarded.
//
// Parameters:
//
// CChunkyRes* pChunkyRes
// Pointer to a previously opened CChunkRes object.
//
// Return:
//
// HX_RESULT
// Possible errors include: TBD.
//
HX_RESULT CChunkyResMgr::CloseResource(CChunkyRes* pChunkyRes)
{
HX_RESULT theErr = HXR_FAIL;
POSITION pPos = m_OpenResources.GetStartPosition();
while (pPos)
{
CHXString key;
void* pData;
m_OpenResources.GetNextAssoc(pPos, key, pData);
if (pData == (void*)pChunkyRes)
{
HX_VERIFY(m_OpenResources.RemoveKey(key));
m_ClosedResources.SetAt(key, pData);
HX_ASSERT(!m_LRUResources.FindString(key));
m_LRUResources.AddTailString(key);
theErr = HXR_OK;
}
}
if (theErr == HXR_OK)
{
DiscardDiskData();
}
return theErr;
}
/////////////////////////////////////////////////////////////////////////////
//
// Method:
//
// CChunkyResMgr::CloseResource()
//
// Purpose:
//
// Closes an existing resource. Closed resources may be discarded.
//
// Parameters:
//
// const char* pResName
// Unique name of a previously opened resource.
//
// Return:
//
// HX_RESULT
// Possible errors include: TBD.
//
HX_RESULT CChunkyResMgr::CloseResource(const char* pResName)
{
HX_RESULT theErr = HXR_FAIL;
void* pData;
if (m_OpenResources.Lookup(pResName, pData))
{
HX_VERIFY(m_OpenResources.RemoveKey(pResName));
m_ClosedResources.SetAt(pResName, pData);
HX_ASSERT(!m_LRUResources.FindString(pResName));
m_LRUResources.AddTailString(pResName);
theErr = HXR_OK;
}
if (theErr == HXR_OK)
{
DiscardDiskData();
}
return theErr;
}
/////////////////////////////////////////////////////////////////////////////
//
// Method:
//
// CChunkyResMgr::DiscardResource()
//
// Purpose:
//
// Discards a resource. Closed resources may be discarded.
//
// Parameters:
//
// const char* pResName
// Unique name of a previously opened resource.
//
// Return:
//
// HX_RESULT
// Possible errors include: TBD.
//
HX_RESULT CChunkyResMgr::DiscardResource(const char* pResName)
{
HX_RESULT theErr = HXR_FAIL;
void* pData;
if (m_OpenResources.Lookup(pResName, pData))
{
HX_VERIFY(m_OpenResources.RemoveKey(pResName));
CChunkyRes* pRes = (CChunkyRes*)pData;
delete pRes;
theErr = HXR_OK;
}
if (m_ClosedResources.Lookup(pResName, pData))
{
HX_VERIFY(m_ClosedResources.RemoveKey(pResName));
RemoveFromLRU(pResName);
CChunkyRes* pRes = (CChunkyRes*)pData;
delete pRes;
theErr = HXR_OK;
}
return theErr;
}
/////////////////////////////////////////////////////////////////////////////
//
// Method:
//
// CChunkyResMgr::FindResource()
//
// Purpose:
//
// Looks to see if the resource exists.
//
// Parameters:
//
// const char* pResName
// Unique name of a previously opened resource.
//
// Return:
//
// HX_RESULT
HX_RESULT
CChunkyResMgr::FindResource(const char* pResName)
{
void* pData;
if (m_OpenResources.Lookup(pResName, pData) ||
m_ClosedResources.Lookup(pResName, pData))
{
return HXR_OK;
}
return HXR_FAIL;
}
/////////////////////////////////////////////////////////////////////////////
//
// Method:
//
// CChunkyResMgr::SetDiskUsageThreshold()
//
// Purpose:
//
// Sets the Disk Usage threshold for the chunky resource manager.
// If closed resources amount to more than the threshold, then they
// will be discarded.
//
// Parameters:
//
// ULONG32 diskUsage
// Disk usage in bytes which will be allowed for closed resources.
//
// Return:
//
// None.
//
void CChunkyResMgr::SetDiskUsageThreshold(ULONG32 diskUsage)
{
m_ulDiskUsage = diskUsage;
DiscardDiskData();
}
void CChunkyResMgr::DiscardDiskData()
{
void* pData = NULL;
CChunkyRes* pRes = NULL;
ULONG32 ulTotal = 0;
// Count the total disk usage
POSITION pPos = m_ClosedResources.GetStartPosition();
while (pPos)
{
CHXString key;
m_ClosedResources.GetNextAssoc(pPos, key, pData);
HX_ASSERT(pData);
pRes = (CChunkyRes*)pData;
ulTotal += pRes->GetDiskUsage();
}
// Trim as much as we need until we're under the disk usage threshold.
pPos = m_LRUResources.GetHeadPosition();
while (pPos && ulTotal > m_ulDiskUsage)
{
CHXString* pResName = m_LRUResources.GetNext(pPos);
HX_ASSERT(pResName);
if (m_ClosedResources.Lookup(*pResName, pData))
{
HX_ASSERT(pData);
pRes = (CChunkyRes*)pData;
ULONG32 ulSize = pRes->GetDiskUsage();
if (ulSize)
{
HX_ASSERT(ulSize <= ulTotal);
ulTotal -= ulSize;
m_ClosedResources.RemoveKey(*pResName);
RemoveFromLRU(*pResName);
delete pRes;
}
}
}
}
void CChunkyResMgr::RemoveFromLRU(const char* pResName)
{
POSITION pPos = m_LRUResources.GetHeadPosition();
POSITION pPrev;
while (pPos)
{
pPrev = pPos;
CHXString* pStr = m_LRUResources.GetNext(pPos);
if (!strcmp(*pStr, pResName))
{
m_LRUResources.RemoveAt(pPrev);
}
}
}
/////////////////////////////////////////////////////////////////////////////
//
// Method:
//
// CChunkyResMgr::CChunkyResMgr()
//
// Purpose:
//
// Construtor for chunky resource manager.
//
// Parameters:
//
// None.
//
// Return:
//
// N/A
//
CChunkyResMgr::CChunkyResMgr()
: m_ulDiskUsage(0)
{
}
/////////////////////////////////////////////////////////////////////////////
//
// Method:
//
// CChunkyResMgr::~CChunkyResMgr()
//
// Purpose:
//
// Destructor for chunky resource manager.
//
// Parameters:
//
// None.
//
// Return:
//
// N/A
//
CChunkyResMgr::~CChunkyResMgr()
{
CHXString key;
CChunkyRes* pRes;
POSITION p;
p = m_OpenResources.GetStartPosition();
while (p)
{
m_OpenResources.GetNextAssoc(p, key, (void*&)pRes);
HX_DELETE(pRes);
}
p = m_ClosedResources.GetStartPosition();
while (p)
{
m_ClosedResources.GetNextAssoc(p, key, (void*&)pRes);
HX_DELETE(pRes);
}
}
/////////////////////////////////////////////////////////////////////////////
//
// Method:
//
// CChunkyRes::DiscardRange()
//
// Purpose:
//
// Discards the specified range of the file.
//
// Parameters:
//
// The location and length of the range to be discarded.
//
// Return:
//
// HX_RESULT
// Possible errors include: TBD.
//
HX_RESULT CChunkyRes::DiscardRange( ULONG32 offset, ULONG32 count )
{
HX_RESULT theErr = HXR_OK;
// Big picture of this function is that it takes
// care of the end cases, where part of a chunk may
// be invalidated; then it totally removes all the
// chunks wholly contained by the range.
ULONG32 ulOffsetIntoChunk;
ULONG32 ulFirstChunk = offset/DEF_CHUNKYRES_CHUNK_SIZE;
ulOffsetIntoChunk = offset % DEF_CHUNKYRES_CHUNK_SIZE;
ULONG32 ulLastChunk = (offset+count)/DEF_CHUNKYRES_CHUNK_SIZE;
if (ulFirstChunk == ulLastChunk)
{
// if the range is all in one chunk, deal with that simplest
// case and ignore the more complicated scenarios.
CChunkyResChunk* pChunk = (CChunkyResChunk*)m_Chunks[ulFirstChunk];
HX_ASSERT(pChunk);
pChunk->AddValidRange(ulOffsetIntoChunk, count, FALSE);
return theErr;
}
if (ulOffsetIntoChunk)
{
// OK, we have a chunk that needs to be partially invalidated.
CChunkyResChunk* pChunk = (CChunkyResChunk*)m_Chunks[ulFirstChunk];
HX_ASSERT(pChunk);
pChunk->AddValidRange(ulOffsetIntoChunk, DEF_CHUNKYRES_CHUNK_SIZE - ulOffsetIntoChunk, FALSE);
ulFirstChunk++;
}
ulOffsetIntoChunk = (offset+count) % DEF_CHUNKYRES_CHUNK_SIZE;
if (ulOffsetIntoChunk)
{
// OK, the final chunk needs to be partially invalidated.
CChunkyResChunk* pChunk = (CChunkyResChunk*)m_Chunks[ulLastChunk];
HX_ASSERT(pChunk);
pChunk->AddValidRange(0, ulOffsetIntoChunk, FALSE);
}
for (ULONG32 ulWhichChunk = ulFirstChunk; ulWhichChunk < ulLastChunk; ulWhichChunk++)
{
CChunkyResChunk* pChunk = (CChunkyResChunk*)m_Chunks[ulWhichChunk];
// if the chunk doesn't (yet?) exist, then it's considered invalid.
if (pChunk)
{
ULONG32 ulTempOffset = pChunk->GetTempFileOffset();
if (ulTempOffset)
{
m_FreeDiskOffsets.AddHead((void*)ulTempOffset);
}
delete pChunk;
m_Chunks[ulWhichChunk] = NULL;
}
}
return theErr;
}
/////////////////////////////////////////////////////////////////////////////
//
// Method:
//
// CChunkyRes::GetDiskUsage()
//
// Purpose:
//
// Returns the entire disk usage of a resource.
//
// Parameters:
//
// None.
//
// Return:
//
// ULONG32
// Total amount of diskspace the resource's chunks consume.
//
ULONG32 CChunkyRes::GetDiskUsage() const
{
return (m_Chunks.GetSize() * DEF_CHUNKYRES_CHUNK_SIZE);
}
BOOL CChunkyRes::HasPartialData(ULONG32 length, ULONG32 offset /* = 0 */)
{
return (GetContiguousLength(offset) >= length);
}
ULONG32 CChunkyRes::GetContiguousLength(ULONG32 offset /* = 0 */)
{
ULONG32 contiguousLength = 0;
int ndx;
int startNdx = offset / DEF_CHUNKYRES_CHUNK_SIZE;
if (startNdx < m_Chunks.GetSize())
{
CChunkyResChunk* pChunk = (CChunkyResChunk*)m_Chunks[startNdx];
if (!pChunk) goto exit;
contiguousLength = pChunk->GetValidLength(offset % DEF_CHUNKYRES_CHUNK_SIZE);
if (contiguousLength != DEF_CHUNKYRES_CHUNK_SIZE - (offset % DEF_CHUNKYRES_CHUNK_SIZE))
{
goto exit;
}
}
startNdx++;
for (ndx = startNdx; ndx < m_Chunks.GetSize(); ndx++)
{
CChunkyResChunk* pChunk = (CChunkyResChunk*)m_Chunks[ndx];
// if there is no chunk then we are no longer contiguous.
if (!pChunk)
{
break;
}
ULONG32 chunkLength = pChunk->GetValidLength();
contiguousLength += chunkLength;
// if this chunk is not the max length then we are no longer contiguous
if (chunkLength < DEF_CHUNKYRES_CHUNK_SIZE)
{
break;
}
}
exit:
return contiguousLength;
}
/////////////////////////////////////////////////////////////////////////////
//
// Method:
//
// CChunkyRes::GetData()
//
// Purpose:
//
// Gets a block of data out of a resource.
//
// Parameters:
//
// ULONG32 offset
// char* buf
// ULONG32 count
// ULONG32* actual
//
// Return:
//
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -