📄 chunkres.cpp
字号:
HX_RESULT CChunkyResChunk::AddValidRange(ULONG32 offset, ULONG32 length, BOOL bValid /* = TRUE */){ HX_RESULT theErr = HXR_OK; int nCount = m_ValidRanges.GetCount(); LISTPOSITION pos = m_ValidRanges.GetHeadPosition(); 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 + -