chunkres.cpp

来自「symbian 下的helix player源代码」· C++ 代码 · 共 2,018 行 · 第 1/4 页

CPP
2,018
字号
//		CChunkyRes::~CChunkyRes()
//
//	Purpose:
//
//		Destructor for a chunky resource.
//
//	Parameters:
//
//		None.
//
//	Return:
//
//		N/A
//
CChunkyRes::~CChunkyRes()
{
	// If we are getting rid of the resource, then
	// we should discard all of the chunks...
	for (int ndx = 0; ndx < m_Chunks.GetSize(); ndx++)
	{
		CChunkyResChunk* pChunk = (CChunkyResChunk*)m_Chunks[ndx];
		if (pChunk)
		{
			delete pChunk;
		}
	}
	HX_RESULT theErr = DiscardDiskData();
	HX_ASSERT(theErr == HXR_OK);

	if(m_ChunksMemoryMRU)
	{
	    HX_ASSERT(m_ChunksMemoryMRU->GetCount() == 0);
	    delete m_ChunksMemoryMRU;
	    m_ChunksMemoryMRU = NULL;
	}
	
	if(m_ChunksDiskMRU)
	{
	    HX_ASSERT(m_ChunksDiskMRU->GetCount() == 0);
	    delete m_ChunksDiskMRU;
	    m_ChunksDiskMRU = NULL;
	}

	HX_DELETE(m_pMutex);
}


/////////////////////////////////////////////////////////////////////////////
//
//	Method:
//
//		CChunkyResChunk::MakeSureChunkIsInMemory()
//
//	Purpose:
//
//		Get a portion of the data for a chunk.
//
//	Parameters:
//
//		ULONG32 offset
//		char* buf
//		ULONG32 count
//		ULONG32* actual
//
//	Return:
//
//		HX_RESULT
//		Possible errors include: TBD.
//
HX_RESULT CChunkyResChunk::MakeSureChunkIsInMemory()
{
	HX_RESULT theErr = HXR_OK;

	// If we don't have a chunk pointer, then we aren't in
	// memory...
	if (!m_pChunkData)
	{
		// Find ourselves in the MRU list for Disk chunks...
		LISTPOSITION pos = m_pChunkRes->m_ChunksDiskMRU->Find(this);

		// If were found in the disk MRU list, then we have
		// some work to do...
		if (pos)
		{
			// First, remove ourselves from the disk list...
			m_pChunkRes->m_ChunksDiskMRU->RemoveAt(pos);

			// Load from disk...
			theErr = LoadFromDisk();
			if (theErr != HXR_OK)
			{
				goto exit;
			}
		}
		else
		{
			#ifdef _DEBUG
			{
				// We shouldn't find ourselves in the MRU list
				// for memory chunks... but we want to check!
				LISTPOSITION pos = m_pChunkRes->m_ChunksMemoryMRU->Find(this);

				// We shouldn't be in this list!!!!
				HX_ASSERT(pos == NULL);
			}
			#endif // end _DEBUG section

			m_pChunkData = new UCHAR[m_pChunkRes->m_ChunkSize];
			if (!m_pChunkData) theErr = HXR_OUTOFMEMORY;
			if (theErr != HXR_OK)
			{
				goto exit;
			}
 
			HX_ASSERT(GetValidLength() == 0);
		}

		// Add to the front of the Memory list...
		m_pChunkRes->m_ChunksMemoryMRU->AddHead(this);

		m_pChunkRes->m_CurMemUsage += GetSize();

		// Make sure we don't have to much info in memory...
		if (!m_bDisableDiskIO)
		{
		    m_pChunkRes->TrimDownMemoryMRU();
		    HX_ASSERT(m_pChunkData);
		}
	}
	// If we are already in memory, then make sure we are at the
	// top of the Memory MRU list!!!
	else
	{
		// We should find ourselves in the MRU list
		// for memory chunks... but we want to check!
		LISTPOSITION pos = m_pChunkRes->m_ChunksMemoryMRU->Find(this);

		// XXXNH: If we aren't in this list it means we were paged out,
		// so we only need to put ourselves at the top of the MRU list
		if (pos)
		{
		    // First, remove ourselves from wherever we are in the
		    // Memory MRU list...
		    m_pChunkRes->m_ChunksMemoryMRU->RemoveAt(pos);
		}

		// And add ourselves to the top of the list!
		m_pChunkRes->m_ChunksMemoryMRU->AddHead(this);
	}

exit:

	return theErr;
}

/////////////////////////////////////////////////////////////////////////////
//
//	Method:
//
//		CChunkyResChunk::GetValidLength()
//
//	Purpose:
//
//		Determines how much of a chunk is valid
//
//	Parameters:
//
//		ULONG32 offset
//
//	Return:
//
//		HX_RESULT
//		Possible errors include: TBD.
//
ULONG32 CChunkyResChunk::GetValidLength(ULONG32 offset /* = 0 */) const
{
    
    HX_ASSERT(offset < GetSize());
    
    ULONG32 ulValidLength = 0;
    
	LISTPOSITION rangePos = m_ValidRanges.GetHeadPosition();
	
	if (rangePos)
	{
		do
		{
			ValidRange* pRange = (ValidRange*)m_ValidRanges.GetNext(rangePos);

			HX_ASSERT(pRange);

			// see if the offset points into this particular range

			if (offset >= pRange->offset
				&& offset <= pRange->offset + pRange->length)
			{
			    ulValidLength = pRange->offset + pRange->length - offset;
			}
		}
		while (rangePos);
	}
	
    return ulValidLength;
}

/////////////////////////////////////////////////////////////////////////////
//
//	Method:
//
//		CChunkyResChunk::GetData()
//
//	Purpose:
//
//		Get a portion of the data for a chunk.
//
//	Parameters:
//
//		ULONG32 offset
//		char* buf
//		ULONG32 count
//		ULONG32* actual
//
//	Return:
//
//		HX_RESULT
//		Possible errors include: TBD.
//
HX_RESULT CChunkyResChunk::GetData(ULONG32 offset, char* buf, ULONG32 count, ULONG32* actual)
{
	HX_RESULT theErr;

	if(!count)
	{
		*actual = count;
		return HXR_OK;
	}

	// We should have a non-zero valid size
	if (!GetValidLength(offset))
	{
		// This chunk must have been discarded
		theErr = HXR_CHUNK_MISSING;
		goto exit;
	}

	// Make sure this chunk is in memory!
	theErr = MakeSureChunkIsInMemory();

	if (theErr != HXR_OK)
	{
		goto exit;
	}

	// You can't read 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);

	*actual = min(count,GetValidLength(offset));

	HX_ASSERT(*actual < UINT_MAX);

	memcpy(buf,m_pChunkData+offset,(int)(*actual)); /* Flawfinder: ignore */

exit:

	return theErr;
}

HX_RESULT 
CChunkyResChunk::GetContiguousDataPointer(ULONG32 offset, char*& buf, ULONG32 count)
{
    HX_RESULT theErr = HXR_OK;

    if(!count)
    {
	theErr = HXR_FAIL;
	goto exit;
    }

    // First, make sure this chunk is in memory!
    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());

    // Currently, you must write to chunks in order from the
    // start of the chunk first. Random access may come in the
    // future...
    HX_ASSERT(GetValidLength(offset) > 0); // needed still at all?

    // The call to MakeSureChunkIsInMemory() should have handled this!
    HX_ASSERT_VALID_PTR(m_pChunkData);

    AddValidRange(offset, count);
    
    HX_ASSERT(count < UINT_MAX);

    buf = (char*) (m_pChunkData+offset);

    m_bModified = TRUE;

exit:

    return theErr;
}

/////////////////////////////////////////////////////////////////////////////
//
//	Method:
//
//		CChunkyResChunk::AddValidRange()
//
//	Purpose:
//
//		Mark a part of this CChunkyResChunk as valid
//		Called from SetData.
//
//	Parameters:
//
//		ULONG32 offset
//		ULONG32 length
//		BOOL	bValid
//
//	Return:
//
//		HX_RESULT
//		Possible errors include: TBD.
//
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());

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?