/*
* 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
* .
*
*/
#include "ProgramDatabase.h"
#include "Util.h"
#include "xbox/xbeheader.h"
#include "windows/GUIWindowFileManager.h"
#include "FileItem.h"
#include "utils/Crc32.h"
#include "utils/URIUtils.h"
#include "utils/log.h"
using namespace XFILE;
//********************************************************************************************************************************
CProgramDatabase::CProgramDatabase(void)
{
m_strDatabaseFile=PROGRAM_DATABASE_NAME;
}
//********************************************************************************************************************************
CProgramDatabase::~CProgramDatabase(void)
{
}
//********************************************************************************************************************************
bool CProgramDatabase::CreateTables()
{
try
{
CDatabase::CreateTables();
CLog::Log(LOGINFO, "create files table");
m_pDS->exec("CREATE TABLE files ( idFile integer primary key, strFilename text, titleId integer, xbedescription text, iTimesPlayed integer, lastAccessed integer, iRegion integer, iSize integer)\n");
CLog::Log(LOGINFO, "create trainers table");
m_pDS->exec("CREATE TABLE trainers (idKey integer auto_increment primary key, idCRC integer, idTitle integer, strTrainerPath text, strSettings text, Active integer)\n");
CLog::Log(LOGINFO, "create files index");
m_pDS->exec("CREATE INDEX idxFiles ON files(strFilename)");
CLog::Log(LOGINFO, "create files - titleid index");
m_pDS->exec("CREATE INDEX idxTitleIdFiles ON files(titleId)");
}
catch (...)
{
CLog::Log(LOGERROR, "programdatabase::unable to create tables:%lu", GetLastError());
return false;
}
return true;
}
bool CProgramDatabase::UpdateOldVersion(int version)
{
if (NULL == m_pDB.get()) return false;
if (NULL == m_pDS.get()) return false;
if (NULL == m_pDS2.get()) return false;
try
{
}
catch (...)
{
CLog::Log(LOGERROR, "Error attempting to update the database version!");
return false;
}
return true;
}
int CProgramDatabase::GetRegion(const CStdString& strFilenameAndPath)
{
if (NULL == m_pDB.get()) return 0;
if (NULL == m_pDS.get()) return 0;
try
{
CStdString strSQL = PrepareSQL("select * from files where files.strFileName like '%s'", strFilenameAndPath.c_str());
if (!m_pDS->query(strSQL.c_str()))
return 0;
int iRowsFound = m_pDS->num_rows();
if (iRowsFound == 0)
{
m_pDS->close();
return 0;
}
int iRegion = m_pDS->fv("files.iRegion").get_asInt();
m_pDS->close();
return iRegion;
}
catch (...)
{
CLog::Log(LOGERROR, "CProgramDatabase:GetRegion(%s) failed", strFilenameAndPath.c_str());
}
return 0;
}
int CProgramDatabase::GetTitleId(const CStdString& strFilenameAndPath)
{
if (NULL == m_pDB.get()) return 0;
if (NULL == m_pDS.get()) return 0;
try
{
CStdString strSQL = PrepareSQL("select * from files where files.strFileName like '%s'", strFilenameAndPath.c_str());
if (!m_pDS->query(strSQL.c_str()))
return 0;
int iRowsFound = m_pDS->num_rows();
if (iRowsFound == 0)
{
m_pDS->close();
return 0;
}
int idTitle = m_pDS->fv("files.TitleId").get_asInt();
m_pDS->close();
return idTitle;
}
catch (...)
{
CLog::Log(LOGERROR, "CProgramDatabase:GetTitleId(%s) failed", strFilenameAndPath.c_str());
}
return 0;
}
bool CProgramDatabase::SetRegion(const CStdString& strFileName, int iRegion)
{
try
{
if (NULL == m_pDB.get()) return false;
if (NULL == m_pDS.get()) return false;
CStdString strSQL = PrepareSQL("select * from files where files.strFileName like '%s'", strFileName.c_str());
if (!m_pDS->query(strSQL.c_str())) return false;
int iRowsFound = m_pDS->num_rows();
if (iRowsFound == 0)
{
m_pDS->close();
return false;
}
int idFile = m_pDS->fv("files.idFile").get_asInt();
m_pDS->close();
CLog::Log(LOGDEBUG, "CProgramDatabase::SetRegion(%s), idFile=%i, region=%i",
strFileName.c_str(), idFile,iRegion);
strSQL=PrepareSQL("update files set iRegion=%i where idFile=%i",
iRegion, idFile);
m_pDS->exec(strSQL.c_str());
return true;
}
catch (...)
{
CLog::Log(LOGERROR, "CProgramDatabase:SetDescription(%s) failed", strFileName.c_str());
}
return false;
}
bool CProgramDatabase::SetTitleId(const CStdString& strFileName, int idTitle)
{
try
{
if (NULL == m_pDB.get()) return false;
if (NULL == m_pDS.get()) return false;
CStdString strSQL = PrepareSQL("select * from files where files.strFileName like '%s'", strFileName.c_str());
if (!m_pDS->query(strSQL.c_str())) return false;
int iRowsFound = m_pDS->num_rows();
if (iRowsFound == 0)
{
m_pDS->close();
return false;
}
int idFile = m_pDS->fv("files.idFile").get_asInt();
m_pDS->close();
CLog::Log(LOGDEBUG, "CProgramDatabase::SetTitle(%s), idFile=%i, region=%i",
strFileName.c_str(), idFile, idTitle);
strSQL=PrepareSQL("update files set titleId=%i where idFile=%i",
idTitle, idFile);
m_pDS->exec(strSQL.c_str());
return true;
}
catch (...)
{
CLog::Log(LOGERROR, "CProgramDatabase:SetDescription(%s) failed", strFileName.c_str());
}
return false;
}
bool CProgramDatabase::GetXBEPathByTitleId(const int idTitle, CStdString& strPathAndFilename)
{
try
{
if (NULL == m_pDB.get()) return false;
if (NULL == m_pDS.get()) return false;
CStdString strSQL=PrepareSQL("select files.strFilename from files where files.titleId=%i", idTitle);
m_pDS->query(strSQL.c_str());
if (m_pDS->num_rows() > 0)
{
strPathAndFilename = m_pDS->fv("files.strFilename").get_asString();
strPathAndFilename.Replace('/', '\\');
m_pDS->close();
return true;
}
m_pDS->close();
return false;
}
catch (...)
{
CLog::Log(LOGERROR, "CProgramDatabase::GetXBEPathByTitleId(%i) failed", idTitle);
}
return false;
}
bool CProgramDatabase::ItemHasTrainer(unsigned int iTitleId)
{
CStdString strSQL;
try
{
strSQL = PrepareSQL("select * from trainers where idTitle=%u", iTitleId);
if (!m_pDS->query(strSQL.c_str()))
return false;
if (m_pDS->num_rows())
return true;
return false;
}
catch (...)
{
CLog::Log(LOGERROR,"error checking for title's trainers (%s)",strSQL.c_str());
}
return false;
}
bool CProgramDatabase::HasTrainer(const CStdString& strTrainerPath)
{
CStdString strSQL;
Crc32 crc; crc.ComputeFromLowerCase(strTrainerPath);
try
{
strSQL = PrepareSQL("select * from trainers where idCRC=%u", (unsigned __int32) crc);
if (!m_pDS->query(strSQL.c_str()))
return false;
if (m_pDS->num_rows())
return true;
return false;
}
catch (...)
{
CLog::Log(LOGERROR,"error checking for trainer existance (%s)",strSQL.c_str());
}
return false;
}
bool CProgramDatabase::AddTrainer(int iTitleId, const CStdString& strTrainerPath)
{
CStdString strSQL;
Crc32 crc; crc.ComputeFromLowerCase(strTrainerPath);
try
{
char temp[101];
for( int i=0;i<100;++i)
temp[i] = '0';
temp[100] = '\0';
strSQL=PrepareSQL("insert into trainers (idKey,idCRC,idTitle,strTrainerPath,strSettings,Active) values(NULL,%u,%u,'%s','%s',%i)",(unsigned __int32)crc,iTitleId,strTrainerPath.c_str(),temp,0);
if (!m_pDS->exec(strSQL.c_str()))
return false;
return true;
}
catch (...)
{
CLog::Log(LOGERROR,"programdatabase: unable to add trainer (%s)",strSQL.c_str());
}
return false;
}
bool CProgramDatabase::RemoveTrainer(const CStdString& strTrainerPath)
{
CStdString strSQL;
Crc32 crc; crc.ComputeFromLowerCase(strTrainerPath);
try
{
strSQL=PrepareSQL("delete from trainers where idCRC=%u", (unsigned __int32)crc);
if (!m_pDS->exec(strSQL.c_str()))
return false;
return true;
}
catch (...)
{
CLog::Log(LOGERROR,"programdatabase: unable to remove trainer (%s)",strSQL.c_str());
}
return false;
}
bool CProgramDatabase::GetTrainers(unsigned int iTitleId, std::vector& vecTrainers)
{
vecTrainers.clear();
CStdString strSQL;
try
{
strSQL = PrepareSQL("select * from trainers where idTitle=%u", iTitleId);
if (!m_pDS->query(strSQL.c_str()))
return false;
while (!m_pDS->eof())
{
vecTrainers.push_back(m_pDS->fv("strTrainerPath").get_asString());
m_pDS->next();
}
return true;
}
catch (...)
{
CLog::Log(LOGERROR,"programdatabase: error reading trainers for %i (%s)",iTitleId,strSQL.c_str());
}
return false;
}
bool CProgramDatabase::GetAllTrainers(std::vector& vecTrainers)
{
vecTrainers.clear();
CStdString strSQL;
try
{
strSQL = PrepareSQL("select distinct strTrainerPath from trainers");//PrepareSQL("select * from trainers");
if (!m_pDS->query(strSQL.c_str()))
return false;
while (!m_pDS->eof())
{
vecTrainers.push_back(m_pDS->fv("strTrainerPath").get_asString());
m_pDS->next();
}
return true;
}
catch (...)
{
CLog::Log(LOGERROR,"programdatabase: error reading trainers (%s)",strSQL.c_str());
}
return false;
}
bool CProgramDatabase::SetTrainerOptions(const CStdString& strTrainerPath, unsigned int iTitleId, unsigned char* data, int numOptions)
{
CStdString strSQL;
Crc32 crc; crc.ComputeFromLowerCase(strTrainerPath);
try
{
char temp[101];
int i;
for (i=0;iexec(strSQL.c_str()))
return true;
return false;
}
catch (...)
{
CLog::Log(LOGERROR,"CProgramDatabase::SetTrainerOptions failed (%s)",strSQL.c_str());
}
return false;
}
void CProgramDatabase::SetTrainerActive(const CStdString& strTrainerPath, unsigned int iTitleId, bool bActive)
{
CStdString strSQL;
Crc32 crc; crc.ComputeFromLowerCase(strTrainerPath);
try
{
strSQL = PrepareSQL("update trainers set Active=%u where idCRC=%u and idTitle=%u", bActive?1:0, (unsigned __int32)crc, iTitleId);
m_pDS->exec(strSQL.c_str());
}
catch (...)
{
CLog::Log(LOGERROR,"CProgramDatabase::SetTrainerOptions failed (%s)",strSQL.c_str());
}
}
CStdString CProgramDatabase::GetActiveTrainer(unsigned int iTitleId)
{
CStdString strSQL;
try
{
strSQL = PrepareSQL("select * from trainers where idTitle=%u and Active=1", iTitleId);
if (!m_pDS->query(strSQL.c_str()))
return "";
if (!m_pDS->eof())
return m_pDS->fv("strTrainerPath").get_asString();
}
catch (...)
{
CLog::Log(LOGERROR,"programdatabase: error finding active trainer for %i (%s)",iTitleId,strSQL.c_str());
}
return "";
}
bool CProgramDatabase::GetTrainerOptions(const CStdString& strTrainerPath, unsigned int iTitleId, unsigned char* data, int numOptions)
{
CStdString strSQL;
Crc32 crc; crc.ComputeFromLowerCase(strTrainerPath);
try
{
strSQL = PrepareSQL("select * from trainers where idCRC=%u and idTitle=%u", (unsigned __int32)crc, iTitleId);
if (m_pDS->query(strSQL.c_str()))
{
CStdString strSettings = m_pDS->fv("strSettings").get_asString();
for (int i=0;iGetPath().c_str());
m_pDS->query(strSQL.c_str());
if (!m_pDS->eof())
{ // get info - only set the label if not preformatted
if (!item->IsLabelPreformated())
item->SetLabel(m_pDS->fv("xbedescription").get_asString());
item->m_iprogramCount = m_pDS->fv("iTimesPlayed").get_asInt();
item->m_strTitle = item->GetLabel(); // is this needed?
item->m_dateTime = TimeStampToLocalTime(_atoi64(m_pDS->fv("lastAccessed").get_asString().c_str()));
item->m_dwSize = _atoi64(m_pDS->fv("iSize").get_asString().c_str());
idTitle = m_pDS->fv("titleId").get_asInt();
if (item->m_dwSize == -1)
{
CStdString strPath;
URIUtils::GetDirectory(item->GetPath(),strPath);
__int64 iSize = CGUIWindowFileManager::CalculateFolderSize(strPath);
CStdString strSQL=PrepareSQL("update files set iSize=%I64u where strFileName like '%s'",iSize,item->GetPath().c_str());
m_pDS->exec(strSQL.c_str());
}
}
m_pDS->close();
}
catch (...)
{
CLog::Log(LOGERROR, "CProgramDatabase::GetProgramInfo(%s) failed", item->GetPath().c_str());
}
return idTitle;
}
bool CProgramDatabase::AddProgramInfo(CFileItem *item, unsigned int titleID)
{
try
{
if (NULL == m_pDB.get()) return false;
if (NULL == m_pDS.get()) return false;
int iRegion = -1;
if (g_guiSettings.GetBool("myprograms.gameautoregion"))
{
CXBE xbe;
iRegion = xbe.ExtractGameRegion(item->GetPath());
if (iRegion < 1 || iRegion > 7)
iRegion = 0;
}
FILETIME time;
item->m_dateTime=CDateTime::GetCurrentDateTime();
item->m_dateTime.GetAsTimeStamp(time);
ULARGE_INTEGER lastAccessed;
lastAccessed.u.LowPart = time.dwLowDateTime;
lastAccessed.u.HighPart = time.dwHighDateTime;
CStdString strPath, strParent;
URIUtils::GetDirectory(item->GetPath(),strPath);
// special case - programs in root of sources
bool bIsShare=false;
CUtil::GetMatchingSource(strPath,g_settings.m_programSources,bIsShare);
__int64 iSize=0;
if (bIsShare || !item->IsDefaultXBE())
{
__stat64 stat;
if (CFile::Stat(item->GetPath(),&stat) == 0)
iSize = stat.st_size;
}
else
iSize = CGUIWindowFileManager::CalculateFolderSize(strPath);
if (titleID == 0)
titleID = (unsigned int) -1;
CStdString strSQL=PrepareSQL("insert into files (idFile, strFileName, titleId, xbedescription, iTimesPlayed, lastAccessed, iRegion, iSize) values(NULL, '%s', %u, '%s', %i, %I64u, %i, %I64u)", item->GetPath().c_str(), titleID, item->GetLabel().c_str(), 0, lastAccessed.QuadPart, iRegion, iSize);
m_pDS->exec(strSQL.c_str());
item->m_dwSize = iSize;
}
catch (...)
{
CLog::Log(LOGERROR, "CProgramDatabase::AddProgramInfo(%s) failed", item->GetPath().c_str());
}
return true;
}
FILETIME CProgramDatabase::TimeStampToLocalTime( unsigned __int64 timeStamp )
{
FILETIME fileTime;
::FileTimeToLocalFileTime( (const FILETIME *)&timeStamp, &fileTime);
return fileTime;
}
bool CProgramDatabase::IncTimesPlayed(const CStdString& strFileName)
{
try
{
if (NULL == m_pDB.get()) return false;
if (NULL == m_pDS.get()) return false;
CStdString strSQL = PrepareSQL("select * from files where files.strFileName like '%s'", strFileName.c_str());
if (!m_pDS->query(strSQL.c_str())) return false;
int iRowsFound = m_pDS->num_rows();
if (iRowsFound == 0)
{
m_pDS->close();
return false;
}
int idFile = m_pDS->fv("files.idFile").get_asInt();
int iTimesPlayed = m_pDS->fv("files.iTimesPlayed").get_asInt();
m_pDS->close();
CLog::Log(LOGDEBUG, "CProgramDatabase::IncTimesPlayed(%s), idFile=%i, iTimesPlayed=%i",
strFileName.c_str(), idFile, iTimesPlayed);
strSQL=PrepareSQL("update files set iTimesPlayed=%i where idFile=%i",
++iTimesPlayed, idFile);
m_pDS->exec(strSQL.c_str());
return true;
}
catch (...)
{
CLog::Log(LOGERROR, "CProgramDatabase:IncTimesPlayed(%s) failed", strFileName.c_str());
}
return false;
}
bool CProgramDatabase::SetDescription(const CStdString& strFileName, const CStdString& strDescription)
{
try
{
if (NULL == m_pDB.get()) return false;
if (NULL == m_pDS.get()) return false;
CStdString strSQL = PrepareSQL("select * from files where files.strFileName like '%s'", strFileName.c_str());
if (!m_pDS->query(strSQL.c_str())) return false;
int iRowsFound = m_pDS->num_rows();
if (iRowsFound == 0)
{
m_pDS->close();
return false;
}
int idFile = m_pDS->fv("files.idFile").get_asInt();
m_pDS->close();
CLog::Log(LOGDEBUG, "CProgramDatabase::SetDescription(%s), idFile=%i, description=%s",
strFileName.c_str(), idFile,strDescription.c_str());
strSQL=PrepareSQL("update files set xbedescription='%s' where idFile=%i",
strDescription.c_str(), idFile);
m_pDS->exec(strSQL.c_str());
return true;
}
catch (...)
{
CLog::Log(LOGERROR, "CProgramDatabase:SetDescription(%s) failed", strFileName.c_str());
}
return false;
}
bool CProgramDatabase::GetArbitraryQuery(const CStdString& strQuery, const CStdString& strOpenRecordSet, const CStdString& strCloseRecordSet,
const CStdString& strOpenRecord, const CStdString& strCloseRecord, const CStdString& strOpenField,
const CStdString& strCloseField, CStdString& strResult)
{
try
{
strResult = "";
if (NULL == m_pDB.get()) return false;
if (NULL == m_pDS.get()) return false;
CStdString strSQL=strQuery;
if (!m_pDS->query(strSQL.c_str()))
{
strResult = m_pDB->getErrorMsg();
return false;
}
strResult=strOpenRecordSet;
while (!m_pDS->eof())
{
strResult += strOpenRecord;
for (int i=0; ifieldCount(); i++)
{
strResult += strOpenField + CStdString(m_pDS->fv(i).get_asString()) + strCloseField;
}
strResult += strCloseRecord;
m_pDS->next();
}
strResult += strCloseRecordSet;
m_pDS->close();
return true;
}
catch (...)
{
CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
}
try
{
if (NULL == m_pDB.get()) return false;
strResult = m_pDB->getErrorMsg();
}
catch (...)
{
}
return false;
}