Exemple #1
0
bool ThemeManager::IsThemeSelectable( const RString &sThemeName )
{
	if( !DoesThemeExist(sThemeName) )
		return false;

	return sThemeName.Left(1) != "_";
}
Exemple #2
0
bool Steps::MakeValidEditDescription( RString &sPreferredDescription )
{
	if( int(sPreferredDescription.size()) > MAX_STEPS_DESCRIPTION_LENGTH )
	{
		sPreferredDescription = sPreferredDescription.Left( MAX_STEPS_DESCRIPTION_LENGTH );
		return true;
	}
	return false;
}
Exemple #3
0
bool IniFile::ReadFile( RageFileBasic &f )
{
	RString keyname;
	while( 1 )
	{
		RString line;
		/* Read lines until we reach a line that doesn't end in a backslash */
		while( true )
		{
			RString s;
			switch( f.GetLine(s) )
			{
			case -1:
				m_sError = f.GetError();
				return false;
			case 0:
				return true; /* eof */
			}

			utf8_remove_bom( s );

			line += s;

			if( line.empty() || line[line.size()-1] != '\\' )
				break;

			line.erase( line.end()-1 );
		}


		if( line.size() == 0 )
			continue;
		if( line[0] == '#' )
			continue; /* comment */
		if( line.size() > 1 && line[0] == '/' && line[1] == '/' )
			continue; /* comment */

		if( line[0] == '[' && line[line.size()-1] == ']'  )
		{
			/* New section. */
			keyname = line.substr(1, line.size()-2);
		}
		else
		{
			/* New value. */
			size_t iEqualIndex = line.find("=");
			if( iEqualIndex != string::npos )
			{
				RString valuename = line.Left( (int) iEqualIndex );
				RString value = line.Right( line.size()-valuename.size()-1 );
				Trim( valuename );
				if( keyname.size() && valuename.size() )
					SetValue( keyname, valuename, value );
			}
		}
	}
}
Exemple #4
0
void Resume::ReadVlcResumeFile()
{

	Sleep(100); //wait for VLC to write file (TODO: make threaded)

	//get username
	TCHAR username[UNLEN + 1];
	DWORD username_len = UNLEN + 1;
	GetUserName(username, &username_len);

	RString strTemp;
	RString strVlcFile;

	//build path to vlc info file
	RString strFilePath = _T("C:\\Users\\");
	strFilePath += username;
	strFilePath += _T("\\AppData\\Roaming\\vlc\\vlc-qt-interface.ini");

	//read VLC resume file into str
	if (!FileToString(strFilePath, strVlcFile))
		return;

	if (GetFirstMatch(strVlcFile, _T("list=([^$]*?$)"), &strTemp))
	{
		strTemp.Replace(_T(" "), _T(""));
		RArray<const TCHAR*> moviesTemp = SplitString(strTemp, _T(","), true);
		size = moviesTemp.GetSize();
		if (size > MAX_SIZE) size = MAX_SIZE;

		for(int i=0; i<size; i++)
		{
			//remove % codes and turn + to space
			RString strTempMovie = URLDecode(moviesTemp[i]);

			//remove file:/// or file://
			if (strTempMovie.Left(8) == _T("file:///"))
				strTempMovie = strTempMovie.Right(strTempMovie.GetLength() - 8);
			else
				strTempMovie = strTempMovie.Right(strTempMovie.GetLength() - 5);

			strTempMovie.Replace(_T("/"), _T("\\\\"));
			movies[i] = strTempMovie;
		}
	}

	if (GetFirstMatch(strVlcFile, _T("times=([^$]*?$)"), &strTemp))
	{
		strTemp.Replace(_T(" "), _T(""));
		RArray<const TCHAR*> strTimes = SplitString(strTemp, _T(","), true);
		for(int i=0; i<strTimes.GetSize(); i++)
			times[i] = StringToNumber(strTimes[i])/1000;  //milliseconds to seconds
	}

	UpdateResumeTimes();
}
Exemple #5
0
static void FileNameToMetricsGroupAndElement( const RString &sFileName, RString &sMetricsGroupOut, RString &sElementOut )
{
	// split into class name and file name
	RString::size_type iIndexOfFirstSpace = sFileName.find(" ");
	if( iIndexOfFirstSpace == string::npos ) // no space
	{
		sMetricsGroupOut = "";
		sElementOut = sFileName;
	}
	else
	{
		sMetricsGroupOut = sFileName.Left( iIndexOfFirstSpace );
		sElementOut = sFileName.Right( sFileName.size() - iIndexOfFirstSpace - 1 );
	}
}
Exemple #6
0
bool ActorUtil::GetAttrPath( const XNode *pNode, const RString &sName, RString &sOut )
{
	if( !pNode->GetAttrValue(sName, sOut) )
		return false;

	bool bIsRelativePath = sOut.Left(1) != "/";
	if( bIsRelativePath )
	{
		RString sDir;
		if( !pNode->GetAttrValue("_Dir", sDir) )
		{
			LOG->Warn( "Relative path \"%s\", but path is unknown", sOut.c_str() );
			return false;
		}
		sOut = sDir+sOut;
	}

	return ActorUtil::ResolvePath( sOut, ActorUtil::GetWhere(pNode) );
}
void ParseFileName(RString_ strFileName, RString &strTitle, RString &strYear)
{
	INT_PTR m, n;
	RString strTemp;

	strTitle = strFileName;
	strYear.Empty();

	// only keep file name

	n = strTitle.ReverseFind(_T('\\'));
	if (n != -1)
		strTitle = strTitle.Mid(n + 1);
	//strTitle.MakeLower();

	// strip file extension (max 4 chars)

	n = strTitle.ReverseFind(_T('.'));
	if (n != -1 && strTitle.GetLength() - n < 6)
		strTitle = strTitle.Left(n);

	// replace []{} by ()

	strTitle.Replace(_T('['), _T('('));
	strTitle.Replace(_T(']'), _T(')'));
	strTitle.Replace(_T('{'), _T('('));
	strTitle.Replace(_T('}'), _T(')'));

	/*
	// replace anything not ,()0-9a-zA-Z by a space

	for (int i = 0; i < strTitle.GetLength(); i++)
		if (!(strTitle[i] == _T(',')) &&
			!(strTitle[i] == _T('\'')) &&
			!(strTitle[i] == _T('(')) &&
			!(strTitle[i] == _T(')')) &&
			!(strTitle[i] >= _T('0') && strTitle[i] <= _T('9')) &&
			!(strTitle[i] >= _T('A') && strTitle[i] <= _T('Z')) &&
			!(strTitle[i] >= _T('a') && strTitle[i] <= _T('z')))
			*((LPTSTR)(LPCTSTR)strTitle + i) = _T(' ');
	*/

	// replace ._ by a space

	strTitle.Replace(_T('.'), _T(' '));
	strTitle.Replace(_T('_'), _T(' '));

	// remove redundant space

	while (strTitle.Replace(_T("  "), _T(" ")));
	strTitle.Trim();

	// find year between (), strip anything following it

	for (n = 0; (n = strTitle.Find(_T('('), n)) != -1; n++)
	{
		if (n+5 < strTitle.GetLength() && strTitle[n+5] == _T(')'))
		{
			strTemp = strTitle.Mid(n+1, 4);
			if (StringToNumber(strTemp) > 1900)
			{
				strYear = strTemp;
				strTitle = strTitle.Left(n);
				break;
			}
		}
	}

	// remove anything between ()

	for (m = 0, n = 0; (m = strTitle.Find(_T('('), n)) != -1 &&
			(n = strTitle.Find(_T(')'), m)) != -1; m = 0, n = 0)
		strTitle = strTitle.Left(m) + strTitle.Mid(n+1);

	// find year not in (), but not as first word, strip anything following it

	strTitle.Replace(_T('('), _T(' '));
	strTitle.Replace(_T(')'), _T(' '));
	while (strTitle.Replace(_T("  "), _T(" ")));
	strTitle.Trim();

	if (strYear.IsEmpty())
	{
		m = 0;
		while (true)
		{
			if (m >= strTitle.GetLength())
				break;

			n = strTitle.Find(_T(' '), m);

			if (n == -1)
				n = strTitle.GetLength();

			if (m == n)
				{m = n + 1; continue;}

			if (n - m == 4)
			{
				strTemp = strTitle.Mid(m, n - m);
				if (StringToNumber(strTemp) > 1900 && m > 0)
				{
					strYear = strTemp;
					strTitle = strTitle.Left(m);
					break;
				}
			}

			m = n + 1;
		}
	}

	while (strTitle.Replace(_T("  "), _T(" ")));
	strTitle.Trim();

	// place some literals in front

	if (strTitle.GetLength() > 5 && strTitle.Right(5) == _T(", the"))
		strTitle = _T("the ") + strTitle.Left(strTitle.GetLength() - 5);
	if (strTitle.GetLength() > 5 && strTitle.Right(5) == _T(", The"))
		strTitle = _T("The ") + strTitle.Left(strTitle.GetLength() - 5);
	if (strTitle.GetLength() > 3 && strTitle.Right(3) == _T(", a"))
		strTitle = _T("a ") + strTitle.Left(strTitle.GetLength() - 3);
	if (strTitle.GetLength() > 3 && strTitle.Right(3) == _T(", A"))
		strTitle = _T("A ") + strTitle.Left(strTitle.GetLength() - 3);
	
	strTitle.Replace(_T(','), _T(' '));
	while (strTitle.Replace(_T("  "), _T(" ")));
	strTitle.Trim();

	//TRACE0(_T("ParseFileName\n  strFileName = ") + strFileName + _T("\n  strTitle = ") +
	//		strTitle + _T("\n  strYear = ") + strYear + _T("\n"));
}
/* mkdir -p.  Doesn't fail if Path already exists and is a directory. */
bool CreateDirectories( RString Path )
{
	/* XXX: handle "//foo/bar" paths in Windows */
	vector<RString> parts;
	RString curpath;

	/* If Path is absolute, add the initial slash ("ignore empty" will remove it). */
	if( Path.Left(1) == "/" )
		curpath = "/";

	/* Ignore empty, so eg. "/foo/bar//baz" doesn't try to create "/foo/bar" twice. */
	split( Path, "/", parts, true );

	for(unsigned i = 0; i < parts.size(); ++i)
	{
		if( i )
			curpath += "/";
		curpath += parts[i];

#if defined(WIN32)
		if( curpath.size() == 2 && curpath[1] == ':' )  /* C: */
		{
			/* Don't try to create the drive letter alone. */
			continue;
		}
#endif

		if( DoMkdir(curpath, 0777) == 0 )
			continue;

#if defined(WIN32)
		/* When creating a directory that already exists over Samba, Windows is
		 * returning ENOENT instead of EEXIST. */
		/* I can't reproduce this anymore.  If we get ENOENT, log it but keep
		 * going. */
		if( errno == ENOENT )
		{
			WARN( ssprintf("Couldn't create %s: %s", curpath.c_str(), strerror(errno)) );
			errno = EEXIST;
		}
#endif

		if( errno == EEXIST )
		{
			/* Make sure it's a directory. */
			struct stat st;
			if( DoStat(curpath, &st) != -1 && !(st.st_mode & S_IFDIR) )
			{
				WARN( ssprintf("Couldn't create %s: path exists and is not a directory", curpath.c_str()) );
				return false;
			}

			continue;		// we expect to see this error
		}

		WARN( ssprintf("Couldn't create %s: %s", curpath.c_str(), strerror(errno)) );
		return false;
	}
	
	return true;
}
Exemple #9
0
Actor *ActorUtil::LoadFromNode( const XNode* _pNode, Actor *pParentActor )
{
	ASSERT( _pNode != NULL );

	XNode node = *_pNode;

	// Remove this in favor of using conditionals in Lua. -Chris
	// There are a number of themes out there that depend on this (including
	// sm-ssc default). Probably for the best to leave this in. -aj
	{
		bool bCond;
		if( node.GetAttrValue("Condition", bCond) && !bCond )
			return NULL;
	}

	RString sClass;
	bool bHasClass = node.GetAttrValue( "Class", sClass );
	if( !bHasClass )
		bHasClass = node.GetAttrValue( "Type", sClass );

	bool bLegacy = (node.GetAttr( "_LegacyXml" ) != NULL);
	if( !bHasClass && bLegacy )
		sClass = GetLegacyActorClass( &node );

	map<RString,CreateActorFn>::iterator iter = g_pmapRegistrees->find( sClass );
	if( iter == g_pmapRegistrees->end() )
	{
		RString sFile;
		if (bLegacy && node.GetAttrValue("File", sFile) && sFile != "")
		{
			RString sPath;
			// Handle absolute paths correctly
			if (sFile.Left(1) == "/")
				sPath = sFile;
			else
				sPath = Dirname(GetSourcePath(&node)) + sFile;
			if (ResolvePath(sPath, GetWhere(&node)))
			{
				Actor *pNewActor = MakeActor(sPath, pParentActor);
				if (pNewActor == NULL)
					return NULL;
				if (pParentActor)
					pNewActor->SetParent(pParentActor);
				pNewActor->LoadFromNode(&node);
				return pNewActor;
			}
		}

		// sClass is invalid
		RString sError = ssprintf( "%s: invalid Class \"%s\"",
			ActorUtil::GetWhere(&node).c_str(), sClass.c_str() );
		LuaHelpers::ReportScriptError(sError);
		return new Actor;	// Return a dummy object so that we don't crash in AutoActor later.
	}

	const CreateActorFn &pfn = iter->second;
	Actor *pRet = pfn();

	if( pParentActor )
		pRet->SetParent( pParentActor );

	pRet->LoadFromNode( &node );
	return pRet;
}
void ScreenBookkeeping::UpdateView()
{
	BookkeepingView view = m_vBookkeepingViews[m_iViewIndex];


	{
		RString s;
		s += ALL_TIME.GetValue();
		s += ssprintf( " %i\n", BOOKKEEPER->GetCoinsTotal() );
		m_textAllTime.SetText( s );
	}

	switch( view )
	{
	case BookkeepingView_SongPlays:
		{
			Profile *pProfile = PROFILEMAN->GetMachineProfile();

			vector<Song*> vpSongs;
			int iCount = 0;
			FOREACH_CONST( Song *, SONGMAN->GetAllSongs(), s )
			{
				Song *pSong = *s;
				if( UNLOCKMAN->SongIsLocked(pSong) & ~LOCKED_DISABLED )
					continue;
				iCount += pProfile->GetSongNumTimesPlayed( pSong );
				vpSongs.push_back( pSong );
			}
			m_textTitle.SetText( ssprintf(SONG_PLAYS.GetValue(), iCount) );
			SongUtil::SortSongPointerArrayByNumPlays( vpSongs, pProfile, true );

			const int iSongPerCol = 15;
			
			int iSongIndex = 0;
			for( int i=0; i<NUM_BOOKKEEPING_COLS; i++ )
			{
				RString s;
				for( int j=0; j<iSongPerCol; j++ )
				{
					if( iSongIndex < (int)vpSongs.size() )
					{
						Song *pSong = vpSongs[iSongIndex];
						int iCount = pProfile->GetSongNumTimesPlayed( pSong );
						RString sTitle = ssprintf("%4d",iCount) + " " + pSong->GetDisplayFullTitle();
						if( sTitle.length() > 22 )
							sTitle = sTitle.Left(20) + "...";
						s += sTitle + "\n";
						iSongIndex++;
					}
				}
				m_textData[i].SetText( s );
				m_textData[i].SetHorizAlign( align_left );
			}
		}
		break;
	case BookkeepingView_LastDays:
		{
			m_textTitle.SetText( ssprintf(LAST_DAYS.GetValue(), NUM_LAST_DAYS) );

			int coins[NUM_LAST_DAYS];
			BOOKKEEPER->GetCoinsLastDays( coins );
			int iTotalLast = 0;
			
			RString sTitle, sData;
			for( int i=0; i<NUM_LAST_DAYS; i++ )
			{
				sTitle += LastDayToLocalizedString(i) + "\n";
				sData += ssprintf("%d",coins[i]) + "\n";
				iTotalLast += coins[i];
			}

			sTitle += ALL_TIME.GetValue()+"\n";
			sData += ssprintf("%i\n", iTotalLast);
			
			m_textData[0].SetText( "" );
			m_textData[1].SetHorizAlign( align_left );
			m_textData[1].SetText( sTitle );
			m_textData[2].SetText( "" );
			m_textData[3].SetHorizAlign( align_right );
			m_textData[3].SetText( sData );
		}
		break;
	case BookkeepingView_LastWeeks:
		{
			m_textTitle.SetText( ssprintf(LAST_WEEKS.GetValue(), NUM_LAST_WEEKS) );

			int coins[NUM_LAST_WEEKS];
			BOOKKEEPER->GetCoinsLastWeeks( coins );

			RString sTitle, sData;
			for( int col=0; col<4; col++ )
			{
				RString sTemp;
				for( int row=0; row<52/4; row++ )
				{
					int week = row*4+col;
					sTemp += LastWeekToLocalizedString(week) + ssprintf(": %d",coins[week]) + "\n";
				}

				m_textData[col].SetHorizAlign( align_left );
				m_textData[col].SetText( sTemp );
			}
		}
		break;
	case BookkeepingView_DayOfWeek:
		{
			m_textTitle.SetText( DAY_OF_WEEK );

			int coins[DAYS_IN_WEEK];
			BOOKKEEPER->GetCoinsByDayOfWeek( coins );

			RString sTitle, sData;
			for( int i=0; i<DAYS_IN_WEEK; i++ )
			{
				sTitle += DayOfWeekToString(i) + "\n";
				sData += ssprintf("%d",coins[i]) + "\n";
			}
			
			m_textData[0].SetText( "" );
			m_textData[1].SetHorizAlign( align_left );
			m_textData[1].SetText( sTitle );
			m_textData[2].SetText( "" );
			m_textData[3].SetHorizAlign( align_right );
			m_textData[3].SetText( sData );
		}
		break;
	case BookkeepingView_HourOfDay:
		{
			m_textTitle.SetText( HOUR_OF_DAY );

			int coins[HOURS_IN_DAY];
			BOOKKEEPER->GetCoinsByHour( coins );

			RString sTitle1, sData1;
			for( int i=0; i<HOURS_IN_DAY/2; i++ )
			{
				sTitle1 += HourInDayToLocalizedString(i) + "\n";
				sData1 += ssprintf("%d",coins[i]) + "\n";
			}
			
			RString sTitle2, sData2;
			for( int i=(HOURS_IN_DAY/2); i<HOURS_IN_DAY; i++ )
			{
				sTitle2 += HourInDayToLocalizedString(i) + "\n";
				sData2 += ssprintf("%d",coins[i]) + "\n";
			}
			
			m_textData[0].SetHorizAlign( align_left );
			m_textData[0].SetText( sTitle1 );
			m_textData[1].SetHorizAlign( align_right );
			m_textData[1].SetText( sData1 );
			m_textData[2].SetHorizAlign( align_left );
			m_textData[2].SetText( sTitle2 );
			m_textData[3].SetHorizAlign( align_right );
			m_textData[3].SetText( sData2 );
		}
		break;
	default:
		ASSERT(0);
	}
}
Exemple #11
0
int _tmain(int argc, _TCHAR* argv[])
{
	_tsetlocale(LC_ALL, _T("")); // fixes VS11DP quirk

	// open csv file

	RCSVFileRO file;

	if (argc == 2)
	{
		if (!file.Open(CorrectPath(argv[1])))
			{_putts(_T("Unable to open file: ") + CorrectPath(argv[1])); PAUSERETURN(-1);}
	}
	else if (argc == 1)
	{
		if (!file.Open(CorrectPath(_T("strings.csv"))))
			{_putts(_T("Please supply the name of CSV-file.")); PAUSERETURN(-2);}
	}
	else
		{_putts(_T("Invalid argument count.")); PAUSERETURN(-3);}

	if (file.GetLineCount() == 0)
		{_putts(_T("Empty file.")); PAUSERETURN(1);}

	if (file.GetLineCount() < 2)
		{_putts(_T("File must contain at least two lines.")); PAUSERETURN(-4);}

	if (file.GetFieldCount() < 2)
		{_putts(_T("File must contain at least two columns.")); PAUSERETURN(-5);}

	// generate header file contents

	RString str;
	str += _T("// strings.h : Defines the strings to be used throughout the application.\r\n");
	str += _T("//\r\n");
	str += _T("\r\n");

	int n = 1000;
	
	int i, j;
	for (i = 1; i < file.GetLineCount(); i++)
		if (_tcscmp(file.GetField(i, 0), _T("")) != 0)
			str += RString(_T("#define ")) + file.GetField(i, 0) + _T(" ") + NumberToString(n++) + _T("\r\n");

	str += _T("\r\n");
	str += _T("inline void LoadStrings()\r\n");
	str += _T("{\r\n");
	str += _T("\tINT_PTR nLanguage;\r\n");

	for (i = 1; i < file.GetFieldCount(); i++)
	{
		str += _T("\r\n");
		str += (RString)_T("\tnLanguage = GetLangMgr()->GetLanguage(_T(\"") + file.GetField(0, i) + _T("\"));\r\n");
		str += (RString)_T("\tif (nLanguage == -1)\r\n");
		str += (RString)_T("\t\tnLanguage = GetLangMgr()->AddLanguage(_T(\"") + file.GetField(0, i) + _T("\"), _T(\"") + file.GetField(1, i)
				+ _T("\"), _T(\"\"));\r\n\r\n");

		for (j = 1; j < file.GetLineCount(); j++)
		{
			if (_tcscmp(file.GetField(j, 0), _T("")) == 0)
				continue; // skip empty ids

			str += (RString)_T("\tGetLangMgr()->SetString(nLanguage, ") + NumberToString(j-1) + _T(", _T(\"") +
					file.GetField(j, i) + _T("\"), false);\r\n");
		}
	}

	str += _T("}\r\n");

	// write to file

	RString strFilePath = CorrectPath(argc == 2 ? argv[1] : _T("strings.csv"));
	strFilePath = strFilePath.Left(strFilePath.ReverseFind(_T('\\'))+1) + _T("strings.h");

	RArray<BYTE> data = StringToData(str, CHARSET_ANSI);
	if (!DataToFile(data, strFilePath))
		{_tprintf(_T("Failed to open %s for writing.\n"), (LPCTSTR)strFilePath); PAUSERETURN(-6);}

	_tprintf(_T("Created %s succesfully.\n"), (LPCTSTR)strFilePath);

	PAUSERETURN(0);
}
Exemple #12
0
bool ThemeManager::IsThemeNameValid(RString const& name)
{
	return name.Left(1) != "_";
}
void ParseFileName(RString_ strFileName, RString &strTitle, RString &strYear, INT_PTR &nSeason, INT_PTR &nEpisode, RString &strAirDate, BYTE &bType)
{
	INT_PTR m, n;
	RString strTemp, strSeason, strEpisode;
	RString strYearTmp, strMonthTmp, strDayTmp;

	strTitle = strFileName;
	strYear.Empty();

	// only keep file name

	n = strTitle.ReverseFind(_T('\\'));
	if (n != -1)
		strTitle = strTitle.Mid(n + 1);
	//strTitle.MakeLower();

	// strip file extension (max 4 chars)

	n = strTitle.ReverseFind(_T('.'));
	if (n != -1 && strTitle.GetLength() - n < 6)
		strTitle = strTitle.Left(n);

	// replace []{} by ()

	strTitle.Replace(_T('['), _T('('));
	strTitle.Replace(_T(']'), _T(')'));
	strTitle.Replace(_T('{'), _T('('));
	strTitle.Replace(_T('}'), _T(')'));

	/*
	// replace anything not ,()0-9a-zA-Z by a space

	for (int i = 0; i < strTitle.GetLength(); i++)
	if (!(strTitle[i] == _T(',')) &&
	!(strTitle[i] == _T('\'')) &&
	!(strTitle[i] == _T('(')) &&
	!(strTitle[i] == _T(')')) &&
	!(strTitle[i] >= _T('0') && strTitle[i] <= _T('9')) &&
	!(strTitle[i] >= _T('A') && strTitle[i] <= _T('Z')) &&
	!(strTitle[i] >= _T('a') && strTitle[i] <= _T('z')))
	*((LPTSTR)(LPCTSTR)strTitle + i) = _T(' ');
	*/

	// remove urls

	RString strUrl;
	if (GetFirstMatch(strTitle, _T("([wW][wW][wW]\\.[^\\.]*?\\.[cC][oO][mM])"), &strUrl, NULL))
	{
		m = strTitle.Find(strUrl, 0);
		if (m >= 0)
			strTitle = strTitle.Left(m) + strTitle.Right(strTitle.GetLength() - (m + strUrl.GetLength()));
	}

	// replace ._ -by a space

	strTitle.Replace(_T('.'), _T(' '));
	strTitle.Replace(_T('_'), _T(' '));
	strTitle.Replace(_T('-'), _T(' '));

	// remove redundant space

	while (strTitle.Replace(_T("  "), _T(" ")));
	strTitle.Trim();

	// find year between (), strip anything following it

	for (n = 0; (n = strTitle.Find(_T('('), n)) != -1; n++)
	{
		if (n + 5 < strTitle.GetLength() && strTitle[n + 5] == _T(')'))
		{
			strTemp = strTitle.Mid(n + 1, 4);
			if (StringToNumber(strTemp) > 1900)
			{
				strYear = strTemp;
				strTitle = strTitle.Left(n);
				break;
			}
		}
	}

	// remove anything between ()

	for (m = 0, n = 0; (m = strTitle.Find(_T('('), n)) != -1 &&
		(n = strTitle.Find(_T(')'), m)) != -1; m = 0, n = 0)
		strTitle = strTitle.Left(m) + strTitle.Mid(n + 1);

	// for TV shows. Find the season and episode and remove everything following it

	if (GetFirstMatch(strTitle, _T("([Ss]\\d?\\d[Ee]\\d?\\d)"), &strTemp, NULL))
	{
		m = strTitle.Find(strTemp, 0);
		if (GetFirstMatch(strTemp, _T("[Ss](\\d?\\d)[Ee](\\d?\\d)"), &strSeason, &strEpisode, NULL))
		{
			nSeason = StringToNumber(strSeason);
			nEpisode = StringToNumber(strEpisode);
			bType = DB_TYPE_TV;
		}

		if (m >= 0)
			strTitle = strTitle.Left(m);
	}

	// for TV shows by date and parse date aired

	if (GetFirstMatch(strTitle, _T("(\\d\\d\\d\\d) (\\d?\\d) (\\d?\\d)"), &strYearTmp, &strMonthTmp, &strDayTmp, NULL))
	{
		const RString Month[12] = { _T("Jan"), _T("Feb"), _T("Mar"), _T("Apr"),
			_T("May"), _T("Jun"), _T("Jul"), _T("Aug"), _T("Sep"), _T("Oct"), _T("Nov"), _T("Dec") };

		strAirDate = strDayTmp + _T(" ") + Month[StringToNumber(strMonthTmp) - 1] + _T(". ") + strYearTmp;
		bType = DB_TYPE_TV;
	}

	// find year not in (), but not as first word, strip anything following it

	strTitle.Replace(_T('('), _T(' '));
	strTitle.Replace(_T(')'), _T(' '));
	while (strTitle.Replace(_T("  "), _T(" ")));
	strTitle.Trim();

	if (strYear.IsEmpty())
	{
		m = 0;
		while (m < strTitle.GetLength())
		{
			n = strTitle.Find(_T(' '), m);

			if (n == -1)
				n = strTitle.GetLength();

			if (m == n)
			{
				m = n + 1; continue;
			}

			if (n - m == 4)
			{
				strTemp = strTitle.Mid(m, n - m);
				if (StringToNumber(strTemp) > 1900 && m > 0)
				{
					strYear = strTemp;
					strTitle = strTitle.Left(m);
					break;
				}
			}

			m = n + 1;
		}
	}

	// strip 'season[s] \\d' and anything following it
	RString strSeasons;
	if (GetFirstMatch(strTitle, _T("([Ss]eason[s]? ?\\d?\\d(?: ?- ?\\d?\\d)?)"), &strSeasons, NULL))
	{
		m = strTitle.Find(strSeasons, 0);
		if (m >= 0)
			strTitle = strTitle.Left(m);
		bType = DB_TYPE_TV;
	}

	//Remove episode numbers of the form XXofYY - TODO: process to return episode number

	RString strOf;
	if (GetFirstMatch(strTitle, _T("(\\d?\\d[oO][fF]\\d?\\d)"), &strOf, NULL))
	{
		m = strTitle.Find(strOf, 0);
		if (m > 0)
			strTitle = strTitle.Left(m);
		bType = DB_TYPE_TV;
	}

	// strip common movie descriptors and everything after

	static const RString strDescriptors[] = { _T("webrip"), _T("dvdrip"), _T("dvdscr"), _T("xvid"), _T("bdrip"),
		_T("brrip"), _T("hdtv"), _T("pdtv"), _T("box set"), _T("box-set"), _T("x264") };
	foreach(strDescriptors, strD)
	{
		m = strTitle.FindNoCase(strD, 0);
		if (m > 0)
			strTitle = strTitle.Left(m);
	}