📄 chunkres.cpp
字号:
/* ***** BEGIN LICENSE BLOCK ***** * Source last modified: $Id: chunkres.cpp,v 1.14.32.4 2004/07/09 01:44:51 hubbe Exp $ * * Portions Copyright (c) 1995-2004 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 (the "RPSL") available at * http://www.helixcommunity.org/content/rpsl unless you have licensed * the file under the current version of the RealNetworks Community * Source License (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. * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the * "GPL") in which case the provisions of the GPL are applicable * instead of those above. If you wish to allow use of your version of * this file only under the terms of the GPL, and not to allow others * to use your version of this file under the terms of either the RPSL * or RCSL, indicate your decision by deleting the provisions above * and replace them with the notice and other provisions required by * the GPL. If you do not delete the provisions above, a recipient may * use your version of this file under the terms of any one of the * RPSL, the RCSL or the GPL. * * 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_FILEstatic 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_RESULTHX_RESULTCChunkyResMgr::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:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -