📄 chunkres.cpp
字号:
if (bValid)
{
// I don't think we need to ensure that the chunk is in
// memory, although it always probably will be if this is
// called from SetData.
// Ensure that it's saying that a legal range is valid.
HX_ASSERT(offset+length <= GetSize());
// Create a new range element.
ValidRange* pNewRange = new ValidRange;
pNewRange->offset = offset;
pNewRange->length = length;
// Iterate through the valid ranges to ensure that
// none of them overlap the range we're adding now.
for (int i=0; i<nCount; i++)
{
ValidRange* pRange = (ValidRange*)m_ValidRanges.GetAt(pos);
BOOL bNeedToMerge = FALSE;
// See if this range element overlaps the front end of the
// new range element.
if (pRange->offset <= pNewRange->offset
&& pRange->offset + pRange->length >= pNewRange->offset)
{
bNeedToMerge = TRUE;
}
// see if this range element overlaps the back end of the
// new range element.
if (pRange->offset <= pNewRange->offset + pNewRange->length
&& pRange->offset + pRange->length >= pNewRange->offset + pNewRange->length)
{
bNeedToMerge = TRUE;
}
// if an overlap happened, make the new range element hold
// the union of both ranges.
if (bNeedToMerge)
{
ULONG32 ulStartOfRange = min(pNewRange->offset, pRange->offset);
ULONG32 ulEndOfRange = max(pNewRange->offset+pNewRange->length,
pRange->offset+pRange->length);
HX_ASSERT(ulEndOfRange >= ulStartOfRange);
pNewRange->offset = ulStartOfRange;
pNewRange->length = ulEndOfRange-ulStartOfRange;
// delete the one we overlap with since we've ensured
// that pNewRange's range covers both.
pos = m_ValidRanges.RemoveAt(pos);
delete pRange;
}
else
m_ValidRanges.GetAtNext(pos);
}
// Now that we're sure that nobody overlaps us, we can
// add this range.
m_ValidRanges.AddTail((void*)pNewRange);
}
else
{
// bValid is false, so we're INVALIDATING a range.
// iterate through the list of valid ranges, and for each of them
// that overlaps the incoming range, either trim it appropriately
// or delete it entirely.
for (int i=0; i<nCount; i++)
{
ValidRange* pRange = (ValidRange*)m_ValidRanges.GetAt(pos);
HX_ASSERT(pRange);
// see if it's totally covered by the incoming range
if (offset <= pRange->offset && offset+length >= pRange->offset + pRange->length)
{
pos = m_ValidRanges.RemoveAt(pos);
delete pRange;
}
else
{
// see if it needs to be trimmed
ULONG32 ulCurrentRangeEnd = pRange->offset + pRange->length;
ULONG32 ulRangeEnd = offset + length;
BOOL bNeedToTrimOffBackEnd = pRange->offset < offset && ulCurrentRangeEnd >= offset;
BOOL bNeedToTrimOffFrontEnd = pRange->offset < ulRangeEnd
&& ulCurrentRangeEnd > ulRangeEnd;
if (bNeedToTrimOffBackEnd)
{
pRange->length = offset - pRange->offset;
}
if (bNeedToTrimOffFrontEnd)
{
// if we've also trimmed off the back end
// then we need to create a new range element
// to hold this sans-front-end element.
if (bNeedToTrimOffBackEnd)
{
pRange = new ValidRange;
m_ValidRanges.AddHead(pRange);
}
pRange->offset = ulRangeEnd;
pRange->length = ulCurrentRangeEnd - pRange->offset;
}
m_ValidRanges.GetAtNext(pos);
}
}
}
return theErr;
}
/////////////////////////////////////////////////////////////////////////////
//
// Method:
//
// CChunkyResChunk::SetData()
//
// Purpose:
//
// Set a portion of the data for a chunk.
//
// Parameters:
//
// ULONG32 offset
// const char* buf
// ULONG32 count
//
// Return:
//
// HX_RESULT
// Possible errors include: TBD.
//
HX_RESULT CChunkyResChunk::SetData(ULONG32 offset, const char* buf, ULONG32 count)
{
// First, make sure this chunk is in memory!
HX_RESULT theErr = MakeSureChunkIsInMemory();
if (theErr != HXR_OK)
{
goto exit;
}
// You can't write more than there is room in this chunk.
// CChunkyRes should prevent this case...
HX_ASSERT(offset+count <= GetSize());
// The call to MakeSureChunkIsInMemory() should have handled this!
HX_ASSERT_VALID_PTR(m_pChunkData);
HX_ASSERT(count < UINT_MAX);
memcpy(m_pChunkData+offset,buf,(int)(offset+count <= GetSize() ? count : GetSize() - offset));
m_bModified = TRUE;
// Make sure that it remembers that this is now a valid
// range.
AddValidRange(offset, count);
exit:
return theErr;
}
/////////////////////////////////////////////////////////////////////////////
//
// Method:
//
// CChunkyResChunk::SpillToDisk()
//
// Purpose:
//
// Spills to disk the data of a chunk.
//
// Parameters:
//
// None.
//
// Return:
//
// HX_RESULT
// Possible errors include: TBD.
//
HX_RESULT CChunkyResChunk::SpillToDisk()
{
Lock();
HX_RESULT theErr = HXR_OK;
CHXDataFile* pFile = NULL;
ULONG32 actualCount = 0;
// Don't waste any time unless we are actually modified.
// And only actually spill, if there is something to spill
if (!m_bModified || !m_pChunkData)
{
goto exit;
}
// If we have never spilled to disk, then ask the ChunkyRes
// for the temp file name and a slot to spill to.
if (!m_bPreviouslySpilled)
{
theErr = m_pChunkRes->GetTempFileChunk(pFile,m_ulTempFileOffset);
}
// Otherwise, just get the temp file name.
else
{
theErr = m_pChunkRes->GetTempFile(pFile);
}
// If we failed to open the file, then set the valid
// size to 0. If the user wants to use the data, they
// will need to handle the case of not having the data!
if (theErr != HXR_OK)
{
HX_ASSERT(pFile == NULL);
theErr = HXR_TEMP_FILE;
goto exit;
}
theErr = pFile->Seek(m_ulTempFileOffset,SEEK_SET);
if (theErr != HXR_OK)
{
theErr = HXR_TEMP_FILE;
goto exit;
}
HX_ASSERT(m_pChunkData);
actualCount = pFile->Write((char *)m_pChunkData, m_pChunkRes->m_ChunkSize);
m_bPreviouslySpilled = TRUE;
if (actualCount != m_pChunkRes->m_ChunkSize)
{
theErr = HXR_TEMP_FILE;
}
exit:
// If we created a file, then clean it up!
if (pFile)
{
delete pFile;
}
// If we had an error then record that our size is now invalid.
if (theErr != HXR_OK)
{
AddValidRange(0, m_pChunkRes->m_ChunkSize, FALSE);
m_bPreviouslySpilled = FALSE;
}
// Never the less, we do get rid of the data!
if (m_pChunkData)
{
delete[] m_pChunkData;
m_pChunkData = NULL;
}
Unlock();
return theErr;
}
/////////////////////////////////////////////////////////////////////////////
//
// Method:
//
// CChunkyResChunk::LoadFromDisk()
//
// Purpose:
//
// Loads into memory the data from the chunk previously spilled to
// disk.
//
// Parameters:
//
// None.
//
// Return:
//
// HX_RESULT
// Possible errors include: TBD.
//
HX_RESULT CChunkyResChunk::LoadFromDisk()
{
Lock();
HX_RESULT theErr = HXR_OK;
CHXDataFile* pFile = NULL;
ULONG32 amountRead = 0;
// We shouldn't be here if we have memory already allocated!
HX_ASSERT(m_pChunkData == NULL);
// If we have never spilled to disk, then there is nothing to
// load from disk!
if (!m_bPreviouslySpilled)
{
// Even if we've never been spilled, we need to make
// sure we have memory available...
m_pChunkData = new UCHAR[m_pChunkRes->m_ChunkSize];
if(!m_pChunkData)
{
theErr = HXR_OUTOFMEMORY;
goto exit;
}
goto exit;
}
// Get the temp file name.
theErr = m_pChunkRes->GetTempFile(pFile);
// If we failed to open the file, then set the valid
// size to 0. If the user wants to use the data, they
// will need to handle the case of not having the data!
if (theErr != HXR_OK)
{
HX_ASSERT(pFile == NULL);
theErr = HXR_TEMP_FILE;
goto exit;
}
theErr = pFile->Seek(m_ulTempFileOffset,SEEK_SET);
if (theErr != HXR_OK)
{
theErr = HXR_TEMP_FILE;
goto exit;
}
m_pChunkData = new UCHAR[m_pChunkRes->m_ChunkSize];
if(!m_pChunkData)
{
theErr = HXR_OUTOFMEMORY;
goto exit;
}
amountRead = pFile->Read((char *)m_pChunkData, m_pChunkRes->m_ChunkSize);
if(amountRead != m_pChunkRes->m_ChunkSize)
{
theErr = HXR_TEMP_FILE;
delete[] m_pChunkData;
m_pChunkData = NULL;
goto exit;
}
exit:
// If we actually, loaded the data from disk, then
// we are not modified!
if (theErr == HXR_OK)
{
m_bModified = FALSE;
}
// If we created a file, then clean it up!
if (pFile)
{
delete pFile;
}
// If we had an error then record that our size is now invalid.
if (theErr != HXR_OK)
{
AddValidRange(0, m_pChunkRes->m_ChunkSize, FALSE);
m_bPreviouslySpilled = FALSE;
}
Unlock();
return theErr;
}
/////////////////////////////////////////////////////////////////////////////
//
// Method:
//
// CChunkyResChunk::CChunkyResChunk()
//
// Purpose:
//
// Constructor for CChunkyResChunk.
//
// Parameters:
//
// None.
//
// Return:
//
// N/A
//
CChunkyResChunk::CChunkyResChunk(CChunkyRes* pChunkyRes)
: m_ChunkOffset(0)
, m_pChunkData(NULL)
, m_ulTempFileOffset(0)
, m_bPreviouslySpilled(FALSE)
, m_bModified(FALSE)
, m_pChunkRes(pChunkyRes)
, m_bDisableDiskIO(FALSE)
{
HX_ASSERT(m_pChunkRes);
}
/////////////////////////////////////////////////////////////////////////////
//
// Method:
//
// CChunkyResChunk::~CChunkyResChunk()
//
// Purpose:
//
// Destructor for CChunkyResChunk.
//
// Parameters:
//
// N/A
//
// Return:
//
// N/A
//
CChunkyResChunk::~CChunkyResChunk()
{
HX_RESULT theErr = DiscardDiskData();
HX_ASSERT(theErr == HXR_OK);
if (m_pChunkData)
{
delete[] m_pChunkData;
m_pChunkData = NULL;
}
while (!m_ValidRanges.IsEmpty())
{
ValidRange* pRange = (ValidRange*)m_ValidRanges.RemoveHead();
delete pRange;
}
}
HX_RESULT CChunkyRes::GetTempFileChunk(CHXDataFile*& pFile,ULONG32& ulTempFileOffset)
{
// You should set this to NULL on input.
HX_ASSERT(pFile == NULL);
// Get the temporary file...
HX_RESULT theErr = GetTempFile(pFile);
if (theErr == HXR_OK)
{
// If there are free chunk spaces in the file, use those first
if (!m_FreeDiskOffsets.IsEmpty())
{
ulTempFileOffset = (UINT32)(PTR_INT)m_FreeDiskOffsets.GetTail();
m_FreeDiskOffsets.RemoveTail();
}
else
{
// return the previous next chunk offset...
ulTempFileOffset = m_ulNextTempFileChunk;
// bump the next chunk offset
m_ulNextTempFileChunk += m_ChunkSize;
}
}
return theErr;
}
/////////////////////////////////////////////////////////////////////////////
//
// Method:
//
// CChunkyResChunk::DiscardDiskData()
//
// Purpose:
//
// Discard the disk data for a chunk. This is normally done on
// destruction of the chunk when the resource associated with this
// chunk is discarded from disk, but can also be done when we
// are downloading a live stream and want to discard chunks that
// have already been served up to the user.
//
// Parameters:
//
// None.
//
// Return:
//
// HX_RESULT
// Possible errors include: TBD.
//
HX_RESULT CChunkyResChunk::DiscardDiskData()
{
HX_RESULT theErr = HXR_OK;
// Remove ourselves from the Memory MRU list...
LISTPOSITION posMem = m_pChunkRes->m_ChunksMemoryMRU->Find(this);
if (posMem)
{
m_pChunkRes->m_ChunksMemoryMRU->RemoveAt(posMem);
m_pChunkRes->m_CurMemUsage -= GetSize();
}
// Remove ourselves from the Disks MRU list...
LISTPOSITION posDisk = m_pChunkRes->m_ChunksDiskMRU->Find(this);
if (posDisk)
{
m_pChunkRes->m_ChunksDiskMRU->RemoveAt(posDisk);
}
// Reset a bunch of our members in case someone tries
// to access this chunk after its data has been discarded
m_ChunkOffset = 0;
AddValidRange(0, m_pChunkRes->m_ChunkSize, FALSE);
HX_VECTOR_DELETE(m_pChunkData);
m_ulTempFileOffset = 0;
m_bPreviouslySpilled = FALSE;
m_bModified = FALSE;
m_bDisableDiskIO = TRUE;
return theErr;
}
/////////////////////////////////////////////////////////////////////////////
//
// Method:
//
// CChunkyRes::DiscardDiskData()
//
// Purpose:
//
// Discard the disk data for a chunk. This is normally done on
// destruction of the chunk when the resource associated with this
// chunk is discarded from disk.
//
// Parameters:
//
// None.
//
// Return:
//
// HX_RESULT
// Possible errors include: TBD.
//
HX_RESULT CChunkyRes::DiscardDiskData()
{
HX_RESULT theErr = HXR_OK;
const char* pFileName = m_strTempFileName;
if (pFileName && *pFileName)
{
#if defined (_MACINTOSH) || defined (_UNIX) || defined(_SYMBIAN) || defined(_OPENWAVE)
int nRet = unlink(pFileName);
#else
int nRet = -1;
if (DeleteFile(OS_STRING(pFileName)))
nRet = 0;
#endif
HX_ASSERT(nRet == 0);
m_strTempFileName = "";
}
return theErr;
}
HX_RESULT CChunkyRes::GetTempFile(CHXDataFile*& pFile)
{
// You should set this to NULL on input.
HX_ASSERT(pFile == NULL);
HX_RESULT theErr = HXR_OK;
const char* pFileName = m_strTempFileName;
char szTempFileName[_MAX_PATH]; /* Flawfinder: ignore */
// Create the OS Specific File object...
pFile = CHXDataFile::Construct();
if (!pFile)
{
theErr = HXR_TEMP_FILE;
goto exit;
}
// If we don't have a filename, then we need to
// get a temp filename, and we know we are creating
// a file.
if (!pFileName || !*pFileName)
{
#if defined(_MAC_MACHO) || defined(_MAC_CFM) // GR 7/15/03 other platforms may want a clearer name here too, since 8.3 restrictions don't apply
if(!pFile->GetTemporaryFileName("Helix", szTempFileName, _MAX_PATH))
#else
if(!pFile->GetTemporaryFileName("PNX",szTempFileName, _MAX_PATH))
#endif
{
goto exit;
}
m_strTempFileName = szTempFileName;
pFileName = m_strTempFileName;
}
// Open the file...
if (!pFileName)
{
theErr = HXR_TEMP_FILE;
goto exit;
}
if (!m_bHasBeenOpened)
{
// Note: _O_RDWR does not work on the mac. O_RDWR is standard ANSI.
theErr = pFile->Open(pFileName,O_CREAT + O_RDWR);
if (!theErr)
{
m_bHasBeenOpened = TRUE;
}
}
else
{
// Note: _O_RDWR does not work on the mac. O_RDWR is standard ANSI.
theErr = pFile->Open(pFileName, O_RDWR);
}
exit:
return theErr;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -