⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 chunkres.cpp

📁 著名的 helix realplayer 基于手机 symbian 系统的 播放器全套源代码
💻 CPP
📖 第 1 页 / 共 3 页
字号:
    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 + -