aboutsummaryrefslogtreecommitdiff
path: root/xbmc/filesystem/RarFile.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'xbmc/filesystem/RarFile.cpp')
-rw-r--r--xbmc/filesystem/RarFile.cpp758
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
-}
-