diff options
Diffstat (limited to 'xbmc/filesystem/RarFile.cpp')
-rw-r--r-- | xbmc/filesystem/RarFile.cpp | 758 |
1 files changed, 0 insertions, 758 deletions
diff --git a/xbmc/filesystem/RarFile.cpp b/xbmc/filesystem/RarFile.cpp deleted file mode 100644 index 6016bc203a..0000000000 --- a/xbmc/filesystem/RarFile.cpp +++ /dev/null @@ -1,758 +0,0 @@ -/* - * 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 "RarFile.h" -#include <algorithm> -#include <sys/stat.h> -#include "Util.h" -#include "utils/CharsetConverter.h" -#include "utils/URIUtils.h" -#include "URL.h" -#include "Directory.h" -#include "RarManager.h" -#include "settings/AdvancedSettings.h" -#include "FileItem.h" -#include "utils/log.h" -#include "UnrarXLib/rar.hpp" -#include "utils/StringUtils.h" - -#ifndef TARGET_POSIX -#include <process.h> -#endif - -#ifdef TARGET_POSIX -#include "linux/XTimeUtils.h" -#endif - -using namespace XFILE; - -#define SEEKTIMOUT 30000 - -#ifdef HAS_FILESYSTEM_RAR -CRarFileExtractThread::CRarFileExtractThread() - : CThread("RarFileExtract") - , hRunning(true) - , hQuit(true) - , m_iSize(0) -{ - m_pArc = NULL; - m_pCmd = NULL; - m_pExtract = NULL; - StopThread(); - Create(); -} - -CRarFileExtractThread::~CRarFileExtractThread() -{ - hQuit.Set(); - AbortableWait(hRestart); - StopThread(); -} - -void CRarFileExtractThread::Start(Archive* pArc, CommandData* pCmd, CmdExtract* pExtract, int iSize) -{ - m_pArc = pArc; - m_pCmd = pCmd; - m_pExtract = pExtract; - m_iSize = iSize; - - m_pExtract->GetDataIO().hBufferFilled = new CEvent; - m_pExtract->GetDataIO().hBufferEmpty = new CEvent; - m_pExtract->GetDataIO().hSeek = new CEvent(true); - m_pExtract->GetDataIO().hSeekDone = new CEvent; - m_pExtract->GetDataIO().hQuit = new CEvent(true); - - hRunning.Set(); - hRestart.Set(); -} - -void CRarFileExtractThread::OnStartup() -{ -} - -void CRarFileExtractThread::OnExit() -{ -} - -void CRarFileExtractThread::Process() -{ - while (AbortableWait(hQuit,1) != WAIT_SIGNALED) - { - if (AbortableWait(hRestart,1) == WAIT_SIGNALED) - { - bool Repeat = false; - try - { - m_pExtract->ExtractCurrentFile(m_pCmd,*m_pArc,m_iSize,Repeat); - } - catch (int rarErrCode) - { - CLog::Log(LOGERROR,"filerar CFileRarExtractThread::Process failed. CmdExtract::ExtractCurrentFile threw a UnrarXLib error code of %d",rarErrCode); - } - catch (...) - { - CLog::Log(LOGERROR,"filerar CFileRarExtractThread::Process failed. CmdExtract::ExtractCurrentFile threw an Unknown exception"); - } - - hRunning.Reset(); - } - } - hRestart.Set(); -} -#endif - -CRarFile::CRarFile() -{ - m_strCacheDir.clear(); - m_strRarPath.clear(); - m_strPassword.clear(); - m_strPathInRar.clear(); - m_bFileOptions = 0; -#ifdef HAS_FILESYSTEM_RAR - m_pArc = NULL; - m_pCmd = NULL; - m_pExtract = NULL; - m_pExtractThread = NULL; -#endif - m_szBuffer = NULL; - m_szStartOfBuffer = NULL; - m_iDataInBuffer = 0; - m_bUseFile = false; - m_bOpen = false; - m_bSeekable = true; - m_iFilePosition = 0; - m_iFileSize = 0; - m_iBufferStart = 0; -} - -CRarFile::~CRarFile() -{ -#ifdef HAS_FILESYSTEM_RAR - if (!m_bOpen) - return; - - if (m_bUseFile) - { - m_File.Close(); - g_RarManager.ClearCachedFile(m_strRarPath,m_strPathInRar); - } - else - { - CleanUp(); - if (m_pExtractThread) - { - delete m_pExtractThread; - m_pExtractThread = NULL; - } - } -#endif -} - -bool CRarFile::Open(const CURL& url) -{ - InitFromUrl(url); - CFileItemList items; - g_RarManager.GetFilesInRar(items,m_strRarPath,false); - int i; - for (i=0;i<items.Size();++i) - { - if (items[i]->GetLabel() == m_strPathInRar) - break; - } - - if (i<items.Size()) - { - if (items[i]->m_idepth == 0x30) // stored - { - if (!OpenInArchive()) - return false; - - m_iFileSize = items[i]->m_dwSize; - m_bOpen = true; - - // perform 'noidx' check - CFileInfo* pFile = g_RarManager.GetFileInRar(m_strRarPath,m_strPathInRar); - if (pFile) - { - if (pFile->m_iIsSeekable == -1) - { - if (Seek(-1,SEEK_END) == -1) - { - m_bSeekable = false; - pFile->m_iIsSeekable = 0; - } - } - else - m_bSeekable = (pFile->m_iIsSeekable == 1); - } - return true; - } - else - { - CFileInfo* info = g_RarManager.GetFileInRar(m_strRarPath,m_strPathInRar); - if ((!info || !CFile::Exists(info->m_strCachedPath)) && m_bFileOptions & EXFILE_NOCACHE) - return false; - m_bUseFile = true; - std::string strPathInCache; - - if (!g_RarManager.CacheRarredFile(strPathInCache, m_strRarPath, m_strPathInRar, - EXFILE_AUTODELETE | m_bFileOptions, m_strCacheDir, - items[i]->m_dwSize)) - { - CLog::Log(LOGERROR,"filerar::open failed to cache file %s",m_strPathInRar.c_str()); - return false; - } - - if (!m_File.Open( strPathInCache )) - { - CLog::Log(LOGERROR,"filerar::open failed to open file in cache: %s",strPathInCache.c_str()); - return false; - } - - m_bOpen = true; - return true; - } - } - return false; -} - -bool CRarFile::Exists(const CURL& url) -{ - InitFromUrl(url); - - // First step: - // Make sure that the archive exists in the filesystem. - if (!CFile::Exists(m_strRarPath, false)) - return false; - - // Second step: - // Make sure that the requested file exists in the archive. - bool bResult; - - if (!g_RarManager.IsFileInRar(bResult, m_strRarPath, m_strPathInRar)) - return false; - - return bResult; -} - -int CRarFile::Stat(const CURL& url, struct __stat64* buffer) -{ - memset(buffer, 0, sizeof(struct __stat64)); - if (Open(url)) - { - buffer->st_size = GetLength(); - buffer->st_mode = _S_IFREG; - Close(); - errno = 0; - return 0; - } - - if (CDirectory::Exists(url.Get())) - { - buffer->st_mode = _S_IFDIR; - return 0; - } - - errno = ENOENT; - return -1; -} - -bool CRarFile::OpenForWrite(const CURL&, bool) -{ - return false; -} - -ssize_t CRarFile::Read(void *lpBuf, size_t uiBufSize) -{ -#ifdef HAS_FILESYSTEM_RAR - if (!m_bOpen) - return -1; - - if (uiBufSize > SSIZE_MAX) - uiBufSize = SSIZE_MAX; - - if (m_bUseFile) - return m_File.Read(lpBuf,uiBufSize); - - if (m_iFilePosition >= GetLength()) // we are done - return 0; - - if( !m_pExtract->GetDataIO().hBufferEmpty->WaitMSec(5000) ) - { - CLog::Log(LOGERROR, "%s - Timeout waiting for buffer to empty", __FUNCTION__); - return -1; - } - - - uint8_t* pBuf = (uint8_t*)lpBuf; - int64_t uicBufSize = uiBufSize; - if (m_iDataInBuffer > 0) - { - int64_t iCopy = std::min(static_cast<int64_t>(uiBufSize), m_iDataInBuffer); - memcpy(lpBuf,m_szStartOfBuffer,size_t(iCopy)); - m_szStartOfBuffer += iCopy; - m_iDataInBuffer -= int(iCopy); - pBuf += iCopy; - uicBufSize -= iCopy; - m_iFilePosition += iCopy; - } - - while ((uicBufSize > 0) && m_iFilePosition < GetLength() ) - { - if (m_iDataInBuffer <= 0) - { - m_pExtract->GetDataIO().SetUnpackToMemory(m_szBuffer,MAXWINMEMSIZE); - m_szStartOfBuffer = m_szBuffer; - m_iBufferStart = m_iFilePosition; - } - - m_pExtract->GetDataIO().hBufferFilled->Set(); - m_pExtract->GetDataIO().hBufferEmpty->Wait(); - - if (m_pExtract->GetDataIO().NextVolumeMissing) - break; - - m_iDataInBuffer = MAXWINMEMSIZE-m_pExtract->GetDataIO().UnpackToMemorySize; - - if (m_iDataInBuffer < 0 || - m_iDataInBuffer > MAXWINMEMSIZE - (m_szStartOfBuffer - m_szBuffer)) - { - // invalid data returned by UnrarXLib, prevent a crash - CLog::Log(LOGERROR, "CRarFile::Read - Data buffer in inconsistent state"); - m_iDataInBuffer = 0; - } - - if (m_iDataInBuffer == 0) - break; - - if (m_iDataInBuffer > uicBufSize) - { - memcpy(pBuf,m_szStartOfBuffer,int(uicBufSize)); - m_szStartOfBuffer += uicBufSize; - pBuf += int(uicBufSize); - m_iFilePosition += uicBufSize; - m_iDataInBuffer -= int(uicBufSize); - uicBufSize = 0; - } - else - { - memcpy(pBuf,m_szStartOfBuffer,size_t(m_iDataInBuffer)); - m_iFilePosition += m_iDataInBuffer; - m_szStartOfBuffer += m_iDataInBuffer; - uicBufSize -= m_iDataInBuffer; - pBuf += m_iDataInBuffer; - m_iDataInBuffer = 0; - } - } - - m_pExtract->GetDataIO().hBufferEmpty->Set(); - - return (ssize_t)(uiBufSize-uicBufSize); -#else - return 0; -#endif -} - -void CRarFile::Close() -{ -#ifdef HAS_FILESYSTEM_RAR - if (!m_bOpen) - return; - - if (m_bUseFile) - { - m_File.Close(); - g_RarManager.ClearCachedFile(m_strRarPath,m_strPathInRar); - m_bOpen = false; - } - else - { - CleanUp(); - if (m_pExtractThread) - { - delete m_pExtractThread; - m_pExtractThread = NULL; - } - m_bOpen = false; - } -#endif -} - -int64_t CRarFile::Seek(int64_t iFilePosition, int iWhence) -{ -#ifdef HAS_FILESYSTEM_RAR - if (!m_bOpen) - return -1; - - if (!m_bSeekable) - return -1; - - if (m_bUseFile) - return m_File.Seek(iFilePosition,iWhence); - - if( !m_pExtract->GetDataIO().hBufferEmpty->WaitMSec(SEEKTIMOUT) ) - { - CLog::Log(LOGERROR, "%s - Timeout waiting for buffer to empty", __FUNCTION__); - return -1; - } - - m_pExtract->GetDataIO().hBufferEmpty->Set(); - - switch (iWhence) - { - case SEEK_CUR: - if (iFilePosition == 0) - return m_iFilePosition; // happens sometimes - - iFilePosition += m_iFilePosition; - break; - case SEEK_END: - if (iFilePosition == 0) // do not seek to end - { - m_iFilePosition = this->GetLength(); - m_iDataInBuffer = 0; - m_iBufferStart = this->GetLength(); - - return this->GetLength(); - } - - iFilePosition += GetLength(); - case SEEK_SET: - break; - default: - return -1; - } - - if (iFilePosition > this->GetLength()) - return -1; - - if (iFilePosition == m_iFilePosition) // happens a lot - return m_iFilePosition; - - if ((iFilePosition >= m_iBufferStart) && (iFilePosition < m_iBufferStart+MAXWINMEMSIZE) - && (m_iDataInBuffer > 0)) // we are within current buffer - { - m_iDataInBuffer = MAXWINMEMSIZE-(iFilePosition-m_iBufferStart); - m_szStartOfBuffer = m_szBuffer+MAXWINMEMSIZE-m_iDataInBuffer; - m_iFilePosition = iFilePosition; - - return m_iFilePosition; - } - - if (iFilePosition < m_iBufferStart ) - { - CleanUp(); - if (!OpenInArchive()) - return -1; - - if( !m_pExtract->GetDataIO().hBufferEmpty->WaitMSec(SEEKTIMOUT) ) - { - CLog::Log(LOGERROR, "%s - Timeout waiting for buffer to empty", __FUNCTION__); - return -1; - } - m_pExtract->GetDataIO().hBufferEmpty->Set(); - m_pExtract->GetDataIO().m_iSeekTo = iFilePosition; - } - else - m_pExtract->GetDataIO().m_iSeekTo = iFilePosition; - - m_pExtract->GetDataIO().SetUnpackToMemory(m_szBuffer,MAXWINMEMSIZE); - m_pExtract->GetDataIO().hSeek->Set(); - m_pExtract->GetDataIO().hBufferFilled->Set(); - if( !m_pExtract->GetDataIO().hSeekDone->WaitMSec(SEEKTIMOUT)) - { - CLog::Log(LOGERROR, "%s - Timeout waiting for seek to finish", __FUNCTION__); - return -1; - } - - if (m_pExtract->GetDataIO().NextVolumeMissing) - { - m_iFilePosition = m_iFileSize; - return -1; - } - - if( !m_pExtract->GetDataIO().hBufferEmpty->WaitMSec(SEEKTIMOUT) ) - { - CLog::Log(LOGERROR, "%s - Timeout waiting for buffer to empty", __FUNCTION__); - return -1; - } - m_iDataInBuffer = m_pExtract->GetDataIO().m_iSeekTo; // keep data - m_iBufferStart = m_pExtract->GetDataIO().m_iStartOfBuffer; - - if (m_iDataInBuffer < 0 || m_iDataInBuffer > MAXWINMEMSIZE) - { - // invalid data returned by UnrarXLib, prevent a crash - CLog::Log(LOGERROR, "CRarFile::Seek - Data buffer in inconsistent state"); - m_iDataInBuffer = 0; - return -1; - } - - m_szStartOfBuffer = m_szBuffer+MAXWINMEMSIZE-m_iDataInBuffer; - m_iFilePosition = iFilePosition; - - return m_iFilePosition; -#else - return -1; -#endif -} - -int64_t CRarFile::GetLength() -{ - if (!m_bOpen) - return 0; - - if (m_bUseFile) - return m_File.GetLength(); - - return m_iFileSize; -} - -int64_t CRarFile::GetPosition() -{ - if (!m_bOpen) - return -1; - - if (m_bUseFile) - return m_File.GetPosition(); - - return m_iFilePosition; -} - -ssize_t CRarFile::Write(const void* lpBuf, size_t uiBufSize) -{ - return -1; -} - -void CRarFile::Flush() -{ - if (m_bUseFile) - m_File.Flush(); -} - -void CRarFile::InitFromUrl(const CURL& url) -{ - m_strCacheDir = g_advancedSettings.m_cachePath;//url.GetDomain(); - URIUtils::AddSlashAtEnd(m_strCacheDir); - m_strRarPath = url.GetHostName(); - m_strPassword = url.GetUserName(); - m_strPathInRar = url.GetFileName(); - - std::vector<std::string> options; - if (!url.GetOptions().empty()) - StringUtils::Tokenize(url.GetOptions().substr(1), options, "&"); - - m_bFileOptions = 0; - - for(std::vector<std::string>::iterator it = options.begin();it != options.end(); ++it) - { - size_t iEqual = (*it).find('='); - if(iEqual != std::string::npos) - { - std::string strOption = StringUtils::Left((*it), iEqual); - std::string strValue = StringUtils::Mid((*it), iEqual+1); - - if( strOption == "flags" ) - m_bFileOptions = atoi(strValue.c_str()); - else if( strOption == "cache" ) - m_strCacheDir = strValue; - } - } - -} - -void CRarFile::CleanUp() -{ -#ifdef HAS_FILESYSTEM_RAR - try - { - if (m_pExtractThread) - { - if (m_pExtractThread->hRunning.WaitMSec(1)) - { - m_pExtract->GetDataIO().hQuit->Set(); - while (m_pExtractThread->hRunning.WaitMSec(1)) - Sleep(1); - } - delete m_pExtract->GetDataIO().hBufferFilled; - delete m_pExtract->GetDataIO().hBufferEmpty; - delete m_pExtract->GetDataIO().hSeek; - delete m_pExtract->GetDataIO().hSeekDone; - delete m_pExtract->GetDataIO().hQuit; - } - if (m_pExtract) - { - delete m_pExtract; - m_pExtract = NULL; - } - if (m_pArc) - { - delete m_pArc; - m_pArc = NULL; - } - if (m_pCmd) - { - delete m_pCmd; - m_pCmd = NULL; - } - if (m_szBuffer) - { - delete[] m_szBuffer; - m_szBuffer = NULL; - m_szStartOfBuffer = NULL; - } - } - catch (int rarErrCode) - { - CLog::Log(LOGERROR,"filerar failed in UnrarXLib while deleting CFileRar with an UnrarXLib error code of %d",rarErrCode); - } - catch (...) - { - CLog::Log(LOGERROR,"filerar failed in UnrarXLib while deleting CFileRar with an Unknown exception"); - } -#endif -} - -bool CRarFile::OpenInArchive() -{ -#ifdef HAS_FILESYSTEM_RAR - try - { - int iHeaderSize; - - InitCRC(); - - m_pCmd = new CommandData; - if (!m_pCmd) - { - CleanUp(); - return false; - } - - // Set the arguments for the extract command - strcpy(m_pCmd->Command, "X"); - - m_pCmd->AddArcName(const_cast<char*>(m_strRarPath.c_str()),NULL); - - strncpy(m_pCmd->ExtrPath, m_strCacheDir.c_str(), sizeof (m_pCmd->ExtrPath) - 2); - m_pCmd->ExtrPath[sizeof (m_pCmd->ExtrPath) - 2] = 0; - AddEndSlash(m_pCmd->ExtrPath); - - // Set password for encrypted archives - if (m_strPassword.length() > MAXPASSWORD - 1) - CLog::Log(LOGWARNING,"OpenInArchive: Supplied password is too long %d", (int) m_strPassword.length()); - strncpy(m_pCmd->Password, m_strPassword.c_str(), sizeof (m_pCmd->Password) - 1); - m_pCmd->Password[sizeof (m_pCmd->Password) - 1] = 0; - - m_pCmd->ParseDone(); - - // Open the archive - m_pArc = new Archive(m_pCmd); - if (!m_pArc) - { - CleanUp(); - return false; - } - if (!m_pArc->WOpen(m_strRarPath.c_str(),NULL)) - { - CleanUp(); - return false; - } - if (!(m_pArc->IsOpened() && m_pArc->IsArchive(true))) - { - CleanUp(); - return false; - } - - m_pExtract = new CmdExtract; - if (!m_pExtract) - { - CleanUp(); - return false; - } - m_pExtract->GetDataIO().SetUnpackToMemory(m_szBuffer,0); - m_pExtract->GetDataIO().SetCurrentCommand(*(m_pCmd->Command)); - struct FindData FD; - if (FindFile::FastFind(m_strRarPath.c_str(),NULL,&FD)) - m_pExtract->GetDataIO().TotalArcSize+=FD.Size; - m_pExtract->ExtractArchiveInit(m_pCmd,*m_pArc); - - while (true) - { - if ((iHeaderSize = m_pArc->ReadHeader()) <= 0) - { - CleanUp(); - return false; - } - - if (m_pArc->GetHeaderType() == FILE_HEAD) - { - std::string strFileName; - - if (wcslen(m_pArc->NewLhd.FileNameW) > 0) - { - g_charsetConverter.wToUTF8(m_pArc->NewLhd.FileNameW, strFileName); - } - else - { - g_charsetConverter.unknownToUTF8(m_pArc->NewLhd.FileName, strFileName); - } - - /* replace back slashes into forward slashes */ - /* this could get us into troubles, file could two different files, one with / and one with \ */ - StringUtils::Replace(strFileName, '\\', '/'); - - if (strFileName == m_strPathInRar) - { - break; - } - } - - m_pArc->SeekToNext(); - } - - m_szBuffer = new uint8_t[MAXWINMEMSIZE]; - m_szStartOfBuffer = m_szBuffer; - m_pExtract->GetDataIO().SetUnpackToMemory(m_szBuffer,0); - m_iDataInBuffer = -1; - m_iFilePosition = 0; - m_iBufferStart = 0; - - delete m_pExtractThread; - m_pExtractThread = new CRarFileExtractThread(); - m_pExtractThread->Start(m_pArc,m_pCmd,m_pExtract,iHeaderSize); - - return true; - } - catch (int rarErrCode) - { - CLog::Log(LOGERROR,"filerar failed in UnrarXLib while CFileRar::OpenInArchive with an UnrarXLib error code of %d",rarErrCode); - return false; - } - catch (...) - { - CLog::Log(LOGERROR,"filerar failed in UnrarXLib while CFileRar::OpenInArchive with an Unknown exception"); - return false; - } -#else - return false; -#endif -} - |