mirror of
https://github.com/Team-Resurgent/XBMC4Xbox.git
synced 2026-08-15 11:18:13 -07:00
If ever adding the XBMC4Xbox source to GitHub use "git add -f -A" or it wont add all the files.
254 lines
6.2 KiB
C++
254 lines
6.2 KiB
C++
/*
|
|
* Copyright (C) 2005-2013 Team XBMC
|
|
* http://xbmc.org
|
|
*
|
|
* This Program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2, or (at your option)
|
|
* any later version.
|
|
*
|
|
* This Program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with XBMC; see the file COPYING. If not, see
|
|
* <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
|
|
#include "system.h"
|
|
#include "CacheStrategy.h"
|
|
#ifdef _LINUX
|
|
#include "PlatformInclude.h"
|
|
#endif
|
|
#include "Util.h"
|
|
#include "utils/log.h"
|
|
#include "utils/SingleLock.h"
|
|
#include "SpecialProtocol.h"
|
|
|
|
namespace XFILE {
|
|
|
|
CCacheStrategy::CCacheStrategy() : m_bEndOfInput(false)
|
|
{
|
|
}
|
|
|
|
|
|
CCacheStrategy::~CCacheStrategy()
|
|
{
|
|
}
|
|
|
|
void CCacheStrategy::EndOfInput() {
|
|
m_bEndOfInput = true;
|
|
}
|
|
|
|
bool CCacheStrategy::IsEndOfInput()
|
|
{
|
|
return m_bEndOfInput;
|
|
}
|
|
|
|
void CCacheStrategy::ClearEndOfInput()
|
|
{
|
|
m_bEndOfInput = false;
|
|
}
|
|
|
|
CSimpleFileCache::CSimpleFileCache()
|
|
: m_hCacheFileRead(NULL)
|
|
, m_hCacheFileWrite(NULL)
|
|
, m_hDataAvailEvent(NULL)
|
|
, m_nStartPosition(0)
|
|
, m_nWritePosition(0)
|
|
, m_nReadPosition(0) {
|
|
}
|
|
|
|
CSimpleFileCache::~CSimpleFileCache()
|
|
{
|
|
Close();
|
|
}
|
|
|
|
int CSimpleFileCache::Open()
|
|
{
|
|
Close();
|
|
|
|
m_hDataAvailEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
|
|
CStdString fileName = CSpecialProtocol::TranslatePath(CUtil::GetNextFilename("special://temp/filecache%03d.cache", 999));
|
|
if(fileName.empty())
|
|
{
|
|
CLog::Log(LOGERROR, "%s - Unable to generate a new filename", __FUNCTION__);
|
|
Close();
|
|
return CACHE_RC_ERROR;
|
|
}
|
|
|
|
m_hCacheFileWrite = CreateFile(fileName.c_str()
|
|
, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_DELETE
|
|
, NULL
|
|
, CREATE_ALWAYS
|
|
, FILE_ATTRIBUTE_NORMAL
|
|
, NULL);
|
|
|
|
if(m_hCacheFileWrite == INVALID_HANDLE_VALUE)
|
|
{
|
|
CLog::Log(LOGERROR, "%s - failed to create file %s with error code %d", __FUNCTION__, fileName.c_str(), GetLastError());
|
|
Close();
|
|
return CACHE_RC_ERROR;
|
|
}
|
|
|
|
m_hCacheFileRead = CreateFile(fileName.c_str()
|
|
, GENERIC_READ, FILE_SHARE_WRITE
|
|
, NULL
|
|
, OPEN_EXISTING
|
|
, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE
|
|
, NULL);
|
|
|
|
if(m_hCacheFileRead == INVALID_HANDLE_VALUE)
|
|
{
|
|
CLog::Log(LOGERROR, "%s - failed to open file %s with error code %d", __FUNCTION__, fileName.c_str(), GetLastError());
|
|
Close();
|
|
return CACHE_RC_ERROR;
|
|
}
|
|
|
|
return CACHE_RC_OK;
|
|
}
|
|
|
|
void CSimpleFileCache::Close()
|
|
{
|
|
if (m_hDataAvailEvent)
|
|
CloseHandle(m_hDataAvailEvent);
|
|
|
|
m_hDataAvailEvent = NULL;
|
|
|
|
if (m_hCacheFileWrite)
|
|
CloseHandle(m_hCacheFileWrite);
|
|
|
|
m_hCacheFileWrite = NULL;
|
|
|
|
if (m_hCacheFileRead)
|
|
CloseHandle(m_hCacheFileRead);
|
|
|
|
m_hCacheFileRead = NULL;
|
|
}
|
|
|
|
int CSimpleFileCache::WriteToCache(const char *pBuffer, size_t iSize)
|
|
{
|
|
DWORD iWritten=0;
|
|
if (!WriteFile(m_hCacheFileWrite, pBuffer, iSize, &iWritten, NULL))
|
|
{
|
|
CLog::Log(LOGERROR, "%s - failed to write to file. err: %u",
|
|
__FUNCTION__, GetLastError());
|
|
return CACHE_RC_ERROR;
|
|
}
|
|
|
|
// when reader waits for data it will wait on the event.
|
|
SetEvent(m_hDataAvailEvent);
|
|
|
|
m_nWritePosition += iWritten;
|
|
return iWritten;
|
|
}
|
|
|
|
int64_t CSimpleFileCache::GetAvailableRead()
|
|
{
|
|
return m_nWritePosition - m_nReadPosition;
|
|
}
|
|
|
|
int CSimpleFileCache::ReadFromCache(char *pBuffer, size_t iMaxSize)
|
|
{
|
|
int64_t iAvailable = GetAvailableRead();
|
|
if ( iAvailable <= 0 ) {
|
|
return m_bEndOfInput? 0 : CACHE_RC_WOULD_BLOCK;
|
|
}
|
|
|
|
if (iMaxSize > iAvailable)
|
|
iMaxSize = (size_t)iAvailable;
|
|
|
|
DWORD iRead = 0;
|
|
if (!ReadFile(m_hCacheFileRead, pBuffer, iMaxSize, &iRead, NULL)) {
|
|
CLog::Log(LOGERROR,"CSimpleFileCache::ReadFromCache - failed to read %"PRIdS" bytes.", iMaxSize);
|
|
return CACHE_RC_ERROR;
|
|
}
|
|
m_nReadPosition += iRead;
|
|
|
|
if (iRead > 0)
|
|
m_space.PulseEvent();
|
|
|
|
return iRead;
|
|
}
|
|
|
|
int64_t CSimpleFileCache::WaitForData(unsigned int iMinAvail, unsigned int iMillis)
|
|
{
|
|
if( iMillis == 0 || IsEndOfInput() )
|
|
return GetAvailableRead();
|
|
|
|
DWORD dwTimeout = GetTickCount() + iMillis;
|
|
DWORD dwTime;
|
|
while ( !IsEndOfInput() && (dwTime = GetTickCount()) < dwTimeout )
|
|
{
|
|
int64_t iAvail = GetAvailableRead();
|
|
if (iAvail >= iMinAvail)
|
|
return iAvail;
|
|
|
|
// busy look (sleep max 1 sec each round)
|
|
DWORD dwRc = WaitForSingleObject(m_hDataAvailEvent, (dwTimeout - dwTime)>1000?(dwTimeout - dwTime):1000 );
|
|
if (dwRc == WAIT_FAILED || dwRc == WAIT_ABANDONED)
|
|
return CACHE_RC_ERROR;
|
|
}
|
|
|
|
if( IsEndOfInput() )
|
|
return GetAvailableRead();
|
|
|
|
return CACHE_RC_TIMEOUT;
|
|
}
|
|
|
|
int64_t CSimpleFileCache::Seek(int64_t iFilePosition)
|
|
{
|
|
|
|
CLog::Log(LOGDEBUG,"CSimpleFileCache::Seek, seeking to %"PRId64, iFilePosition);
|
|
|
|
int64_t iTarget = iFilePosition - m_nStartPosition;
|
|
|
|
if (iTarget < 0)
|
|
{
|
|
CLog::Log(LOGDEBUG,"CSimpleFileCache::Seek, request seek before start of cache.");
|
|
return CACHE_RC_ERROR;
|
|
}
|
|
|
|
int64_t nDiff = iTarget - m_nWritePosition;
|
|
if ( nDiff > 500000 || (nDiff > 0 && WaitForData((unsigned int)(iTarget - m_nReadPosition), 5000) == CACHE_RC_TIMEOUT) ) {
|
|
CLog::Log(LOGWARNING,"%s - attempt to seek pass read data (seek to %"PRId64". max: %"PRId64". reset read pointer. (%"PRId64")", __FUNCTION__, iTarget, m_nWritePosition, iFilePosition);
|
|
return CACHE_RC_ERROR;
|
|
}
|
|
|
|
LARGE_INTEGER pos;
|
|
pos.QuadPart = iTarget;
|
|
|
|
if(!SetFilePointerEx(m_hCacheFileRead, pos, NULL, FILE_BEGIN))
|
|
return CACHE_RC_ERROR;
|
|
|
|
m_nReadPosition = iTarget;
|
|
m_space.PulseEvent();
|
|
|
|
return iFilePosition;
|
|
}
|
|
|
|
void CSimpleFileCache::Reset(int64_t iSourcePosition)
|
|
{
|
|
LARGE_INTEGER pos;
|
|
pos.QuadPart = 0;
|
|
|
|
SetFilePointerEx(m_hCacheFileWrite, pos, NULL, FILE_BEGIN);
|
|
SetFilePointerEx(m_hCacheFileRead, pos, NULL, FILE_BEGIN);
|
|
m_nStartPosition = iSourcePosition;
|
|
m_nReadPosition = 0;
|
|
m_nWritePosition = 0;
|
|
}
|
|
|
|
void CSimpleFileCache::EndOfInput()
|
|
{
|
|
CCacheStrategy::EndOfInput();
|
|
SetEvent(m_hDataAvailEvent);
|
|
}
|
|
|
|
}
|