static CString GetDirOfExecutable( CString argv0 )
{
#ifdef _XBOX
	return "D:\\";
#else
	/* argv[0] can be wrong in most OS's; try to avoid using it. */

	CString sPath;
#if defined(_WIN32)
	char buf[MAX_PATH];
	GetModuleFileName( NULL, buf, sizeof(buf) );
	sPath = buf;
#else
	sPath = argv0;
#endif

	sPath.Replace( "\\", "/" );

	bool IsAbsolutePath = false;
	if( sPath.size() == 0 || sPath[0] == '/' )
		IsAbsolutePath = true;
#if defined(_WIN32)
	if( sPath.size() > 2 && sPath[1] == ':' && sPath[2] == '/' )
		IsAbsolutePath = true;
#endif

	// strip off executable name
	size_t n = sPath.find_last_of("/");
	if( n != sPath.npos )
		sPath.erase(n);
	else
		sPath.erase();

	if( !IsAbsolutePath )
	{
		sPath = GetCwd() + "/" + sPath;
		sPath.Replace( "\\", "/" );
	}

	return sPath;
#endif
}
Beispiel #2
0
CString Font::GetFontName( CString sFileName )
{
	CString sOrig = sFileName;

	CString sDir, sFName, sExt;
	splitpath( sFileName, sDir, sFName, sExt );
	sFileName = sFName;

	/* If it ends in an extension, remove it. */
	static Regex drop_ext( "\\....$" );
	if( drop_ext.Compare(sFileName) )
		sFileName.erase( sFileName.size()-4 );

	/* If it ends in a resolution spec, remove it. */
	CStringArray asMatch;
	static Regex ResSpec( "( \\(res [0-9]+x[0-9]+\\))$" );
	if( ResSpec.Compare(sFileName, asMatch) )
		sFileName.erase(sFileName.size()-asMatch[0].size());

	/* If it ends in a dimension spec, remove it. */
	static Regex DimSpec( "( [0-9]+x[0-9]+)$" );
	if( DimSpec.Compare(sFileName, asMatch) )
		sFileName.erase( sFileName.size()-asMatch[0].size() );

	/* If it ends in texture hints, remove them. */
	static Regex Hints( "( \\([^\\)]+\\))$" );
	if( Hints.Compare(sFileName, asMatch) )
		sFileName.erase( sFileName.size()-asMatch[0].size() );

	/* If it ends in a page name, remove it. */
	static Regex PageName("( \\[.+\\])$");
	if( PageName.Compare( sFileName, asMatch ) )
		sFileName.erase( sFileName.size()-asMatch[0].size() );

	TrimRight( sFileName );

	if( sFileName.empty() )
		RageException::Throw( "Can't parse font filename \"%s\"", sOrig.c_str() );

	sFileName.MakeLower();
	return sFileName;
}
CString
CMSWindowsClipboardUTF16Converter::doToIClipboard(const CString& data) const
{
    // convert and strip nul terminator
    CString dst          = CUnicode::UTF16ToUTF8(data);
    CString::size_type n = dst.find('\0');
    if (n != CString::npos) {
        dst.erase(n);
    }
    return dst;
}
Beispiel #4
0
CString SongUtil::MakeSortString( CString s )
{
	s.MakeUpper();

	// Make sure that non-alphanumeric strings are placed at the very end.
	if( s.size() > 0 )
	{
		if( s[0] == '.' )	// ".59"
			s.erase(s.begin());
		if( (s[0] < 'A' || s[0] > 'Z') && (s[0] < '0' || s[0] > '9') )
			s = char(126) + s;
	}

	return s;
}
Beispiel #5
0
void CDCCSock::ReadData(const char* data, size_t len) {
    if (!m_pFile) {
        DEBUG("File not open! closing get.");
        if (m_bSend) {
            m_pModule->PutModule(t_f("Sending [{1}] to [{2}]: File not open!")(
                m_sFileName, m_sRemoteNick));
        } else {
            m_pModule->PutModule(
                t_f("Receiving [{1}] from [{2}]: File not open!")(
                    m_sFileName, m_sRemoteNick));
        }
        Close();
        return;
    }

    // DCC specs says the receiving end sends the number of bytes it
    // received so far as a 4 byte integer in network byte order, so we need
    // uint32_t to do the job portably. This also means that the maximum
    // file that we can transfer is 4 GiB big (see OpenFile()).
    if (m_bSend) {
        m_sSendBuf.append(data, len);

        while (m_sSendBuf.size() >= 4) {
            uint32_t iRemoteSoFar;
            memcpy(&iRemoteSoFar, m_sSendBuf.data(), sizeof(iRemoteSoFar));
            iRemoteSoFar = ntohl(iRemoteSoFar);

            if ((iRemoteSoFar + 65536) >= m_uBytesSoFar) {
                SendPacket();
            }

            m_sSendBuf.erase(0, 4);
        }
    } else {
        m_pFile->Write(data, len);
        m_uBytesSoFar += len;
        uint32_t uSoFar = htonl((uint32_t)m_uBytesSoFar);
        Write((char*)&uSoFar, sizeof(uSoFar));

        if (m_uBytesSoFar >= m_uFileSize) {
            Close();
        }
    }
}
SongCreditDisplay::SongCreditDisplay()
{
	if( GAMESTATE->IsCourseMode() )
		return;

	this->LoadFromFont( THEME->GetPathF("SongCreditDisplay","text") );
	Song* pSong = GAMESTATE->m_pCurSong;
	ASSERT( pSong );

	CString s = pSong->GetFullDisplayTitle() + "\n" + pSong->GetDisplayArtist() + "\n";
	if( !pSong->m_sCredit.empty() )
		s += pSong->m_sCredit + "\n";

	// use a vector and not a set so that ordering is maintained
	vector<Steps*> vpStepsToShow;
	FOREACH_PlayerNumber( p )
	{
		if( !GAMESTATE->IsHumanPlayer(p) )
			continue;	// skip
		
		Steps* pSteps = GAMESTATE->m_pCurSteps[p];
		bool bAlreadyAdded = find( vpStepsToShow.begin(), vpStepsToShow.end(), pSteps ) != vpStepsToShow.end();
		if( !bAlreadyAdded )
			vpStepsToShow.push_back( pSteps );
	}
	for( unsigned i=0; i<vpStepsToShow.size(); i++ )
	{
		Steps* pSteps = vpStepsToShow[i];
		CString sDifficulty = DifficultyToThemedString( pSteps->GetDifficulty() );
		
		// HACK: reset capitalization
		sDifficulty.MakeLower();
		sDifficulty = Capitalize( sDifficulty );
		
		s += sDifficulty + " steps: " + pSteps->GetDescription() + "\n";
	}

	// erase the last newline
	s.erase( s.end()-1 );

	this->SetText( s );
}
	CString CDataStream::GetLine()
	{
		// keep looping while not hitting delimiter
		int nReadCount;
		char szTmpBuf[MAX_PATH];
		CString szRet;
		while ( (nReadCount = Read(szTmpBuf, MAX_PATH - 1)) != 0)
		{
			// Terminate string
			szTmpBuf[nReadCount] = '\0';

			char *p = strchr(szTmpBuf, '\n');
			if (p != 0)
			{
				// reposition backwards
				Skip((long)(p + 1 - szTmpBuf - nReadCount));
				*p = '\0';
			}

			szRet = szTmpBuf;

			if (p != 0)
			{
				// trim off trailing cr if this was a cr/lf entry
				if (szRet.length() && szRet[szRet.length() - 1] == '\r')
				{
					szRet.erase(szRet.length() - 1, 1);
				}

				// found terminator, break out
				break;
			}
		}

		CStringUtil::Trim(szRet);

		return szRet;
	}
Beispiel #8
0
CWebSock::EPageReqResult CWebSock::OnPageRequestInternal(const CString& sURI, CString& sPageRet) {
	// Check that their session really belongs to their IP address. IP-based
	// authentication is bad, but here it's just an extra layer that makes
	// stealing cookies harder to pull off.
	//
	// When their IP is wrong, we give them an invalid cookie. This makes
	// sure that they will get a new cookie on their next request.
	if (CZNC::Get().GetProtectWebSessions() && GetSession()->GetIP() != GetRemoteIP()) {
		DEBUG("Expected IP: " << GetSession()->GetIP());
		DEBUG("Remote IP:   " << GetRemoteIP());
		SendCookie("SessionId", "WRONG_IP_FOR_SESSION");
		PrintErrorPage(403, "Access denied", "This session does not belong to your IP.");
		return PAGE_DONE;
	}

	// Check that they really POSTed from one our forms by checking if they
	// know the "secret" CSRF check value. Don't do this for login since
	// CSRF against the login form makes no sense and the login form does a
	// cookies-enabled check which would break otherwise.
	if (IsPost() && GetParam("_CSRF_Check") != GetCSRFCheck() && sURI != "/login") {
		DEBUG("Expected _CSRF_Check: " << GetCSRFCheck());
		DEBUG("Actual _CSRF_Check:   " << GetParam("_CSRF_Check"));
		PrintErrorPage(403, "Access denied", "POST requests need to send "
				"a secret token to prevent cross-site request forgery attacks.");
		return PAGE_DONE;
	}

	SendCookie("SessionId", GetSession()->GetId());

	if (GetSession()->IsLoggedIn()) {
		m_sUser = GetSession()->GetUser()->GetUserName();
		m_bLoggedIn = true;
	}

	// Handle the static pages that don't require a login
	if (sURI == "/") {
		if(!m_bLoggedIn && GetParam("cookie_check", false).ToBool() && GetRequestCookie("SessionId").empty()) {
			GetSession()->AddError("Your browser does not have cookies enabled for this site!");
		}
		return PrintTemplate("index", sPageRet);
	} else if (sURI == "/favicon.ico") {
		return PrintStaticFile("/pub/favicon.ico", sPageRet);
	} else if (sURI == "/robots.txt") {
		return PrintStaticFile("/pub/robots.txt", sPageRet);
	} else if (sURI == "/logout") {
		GetSession()->SetUser(NULL);
		SetLoggedIn(false);
		Redirect("/");

		// We already sent a reply
		return PAGE_DONE;
	} else if (sURI == "/login") {
		if (GetParam("submitted").ToBool()) {
			m_sUser = GetParam("user");
			m_sPass = GetParam("pass");
			m_bLoggedIn = OnLogin(m_sUser, m_sPass);

			// AcceptedLogin()/RefusedLogin() will call Redirect()
			return PAGE_DEFERRED;
		}

		Redirect("/"); // the login form is here
		return PAGE_DONE;
	} else if (sURI.Left(5) == "/pub/") {
		return PrintStaticFile(sURI, sPageRet);
	} else if (sURI.Left(11) == "/skinfiles/") {
		CString sSkinName = sURI.substr(11);
		CString::size_type uPathStart = sSkinName.find("/");
		if (uPathStart != CString::npos) {
			CString sFilePath = sSkinName.substr(uPathStart + 1);
			sSkinName.erase(uPathStart);

			m_Template.ClearPaths();
			m_Template.AppendPath(GetSkinPath(sSkinName) + "pub");

			if (PrintFile(m_Template.ExpandFile(sFilePath))) {
				return PAGE_DONE;
			} else {
				return PAGE_NOTFOUND;
			}
		}
		return PAGE_NOTFOUND;
	} else if (sURI.Left(6) == "/mods/" || sURI.Left(10) == "/modfiles/") {
		// Make sure modules are treated as directories
		if (sURI.Right(1) != "/" && sURI.find(".") == CString::npos && sURI.TrimLeft_n("/mods/").TrimLeft_n("/").find("/") == CString::npos) {
			Redirect(sURI + "/");
			return PAGE_DONE;
		}

		// The URI looks like:
		// /mods/[type]/([network]/)?[module][/page][?arg1=val1&arg2=val2...]

		m_sPath = GetPath().TrimLeft_n("/");

		m_sPath.TrimPrefix("mods/");
		m_sPath.TrimPrefix("modfiles/");

		CString sType = m_sPath.Token(0, false, "/");
		m_sPath = m_sPath.Token(1, true, "/");

		CModInfo::EModuleType eModType;
		if (sType.Equals("global")) {
			eModType = CModInfo::GlobalModule;
		} else if (sType.Equals("user")) {
			eModType = CModInfo::UserModule;
		} else if (sType.Equals("network")) {
			eModType = CModInfo::NetworkModule;
		} else {
			PrintErrorPage(403, "Forbidden", "Unknown module type [" + sType + "]");
			return PAGE_DONE;
		}

		if ((eModType != CModInfo::GlobalModule) && !ForceLogin()) {
			// Make sure we have a valid user
			return PAGE_DONE;
		}

		CIRCNetwork *pNetwork = NULL;
		if (eModType == CModInfo::NetworkModule) {
			CString sNetwork = m_sPath.Token(0, false, "/");
			m_sPath = m_sPath.Token(1, true, "/");

			pNetwork = GetSession()->GetUser()->FindNetwork(sNetwork);

			if (!pNetwork) {
				PrintErrorPage(404, "Not Found", "Network [" + sNetwork + "] not found.");
				return PAGE_DONE;
			}
		}

		m_sModName = m_sPath.Token(0, false, "/");
		m_sPage = m_sPath.Token(1, true, "/");

		if (m_sPage.empty()) {
			m_sPage = "index";
		}

		DEBUG("Path [" + m_sPath + "], Module [" + m_sModName + "], Page [" + m_sPage + "]");

		CModule *pModule = NULL;

		switch (eModType) {
			case CModInfo::GlobalModule:
				pModule = CZNC::Get().GetModules().FindModule(m_sModName);
				break;
			case CModInfo::UserModule:
				pModule = GetSession()->GetUser()->GetModules().FindModule(m_sModName);
				break;
			case CModInfo::NetworkModule:
				pModule = pNetwork->GetModules().FindModule(m_sModName);
				break;
		}

		if (!pModule)
			return PAGE_NOTFOUND;

		m_Template["ModPath"] = pModule->GetWebPath();
		m_Template["ModFilesPath"] = pModule->GetWebFilesPath();

		if (pModule->WebRequiresLogin() && !ForceLogin()) {
			return PAGE_PRINT;
		} else if (pModule->WebRequiresAdmin() && !GetSession()->IsAdmin()) {
			PrintErrorPage(403, "Forbidden", "You need to be an admin to access this module");
			return PAGE_DONE;
		} else if (pModule->GetType() != CModInfo::GlobalModule && pModule->GetUser() != GetSession()->GetUser()) {
			PrintErrorPage(403, "Forbidden", "You must login as " + pModule->GetUser()->GetUserName() + " in order to view this page");
			return PAGE_DONE;
		} else if (pModule->OnWebPreRequest(*this, m_sPage)) {
			return PAGE_DEFERRED;
		}

		VWebSubPages& vSubPages = pModule->GetSubPages();

		for (unsigned int a = 0; a < vSubPages.size(); a++) {
			TWebSubPage& SubPage = vSubPages[a];

			bool bActive = (m_sModName == pModule->GetModName() && m_sPage == SubPage->GetName());

			if (bActive && SubPage->RequiresAdmin() && !GetSession()->IsAdmin()) {
				PrintErrorPage(403, "Forbidden", "You need to be an admin to access this page");
				return PAGE_DONE;
			}
		}

		if (pModule && pModule->GetType() != CModInfo::GlobalModule && (!IsLoggedIn() || pModule->GetUser() != GetSession()->GetUser())) {
			AddModLoop("UserModLoop", *pModule);
		}

		if (sURI.Left(10) == "/modfiles/") {
			m_Template.AppendPath(GetSkinPath(GetSkinName()) + "/mods/" + m_sModName + "/files/");
			m_Template.AppendPath(pModule->GetModDataDir() + "/files/");

			if (PrintFile(m_Template.ExpandFile(m_sPage.TrimLeft_n("/")))) {
				return PAGE_PRINT;
			} else {
				return PAGE_NOTFOUND;
			}
		} else {
			SetPaths(pModule, true);

			/* if a module returns false from OnWebRequest, it does not
			   want the template to be printed, usually because it did a redirect. */
			if (pModule->OnWebRequest(*this, m_sPage, m_Template)) {
				// If they already sent a reply, let's assume
				// they did what they wanted to do.
				if (SentHeader()) {
					return PAGE_DONE;
				}
				return PrintTemplate(m_sPage, sPageRet, pModule);
			}

			if (!SentHeader()) {
				PrintErrorPage(404, "Not Implemented", "The requested module does not acknowledge web requests");
			}
			return PAGE_DONE;
		}
	} else {
		CString sPage(sURI.Trim_n("/"));
		if (sPage.length() < 32) {
			for (unsigned int a = 0; a < sPage.length(); a++) {
				unsigned char c = sPage[a];

				if ((c < '0' || c > '9') && (c < 'a' || c > 'z') && (c < 'A' || c > 'Z') && c != '_') {
					return PAGE_NOTFOUND;
				}
			}

			return PrintTemplate(sPage, sPageRet);
		}
	}

	return PAGE_NOTFOUND;
}
Beispiel #9
0
CWebSock::EPageReqResult CWebSock::OnPageRequestInternal(const CString& sURI, CString& sPageRet) {
	if (CZNC::Get().GetProtectWebSessions() && GetSession()->GetIP() != GetRemoteIP()) {
		DEBUG("Expected IP: " << GetSession()->GetIP());
		DEBUG("Remote IP:   " << GetRemoteIP());
		PrintErrorPage(403, "Access denied", "This session does not belong to your IP.");
		return PAGE_DONE;
	}

	// Check that they really POSTed from one our forms by checking if they
	// know the "secret" CSRF check value. Don't do this for login since
	// CSRF against the login form makes no sense and the login form does a
	// cookies-enabled check which would break otherwise.
	if (IsPost() && GetParam("_CSRF_Check") != GetCSRFCheck() && sURI != "/login") {
		DEBUG("Expected _CSRF_Check: " << GetCSRFCheck());
		DEBUG("Actual _CSRF_Check:   " << GetParam("_CSRF_Check"));
		PrintErrorPage(403, "Access denied", "POST requests need to send "
				"a secret token to prevent cross-site request forgery attacks.");
		return PAGE_DONE;
	}

	SendCookie("SessionId", GetSession()->GetId());

	if (GetSession()->IsLoggedIn()) {
		m_sUser = GetSession()->GetUser()->GetUserName();
		m_bLoggedIn = true;
	}

	// Handle the static pages that don't require a login
	if (sURI == "/") {
		if(!m_bLoggedIn && GetParam("cookie_check", false).ToBool() && GetRequestCookie("SessionId").empty()) {
			GetSession()->AddError("Your browser does not have cookies enabled for this site!");
		}
		return PrintTemplate("index", sPageRet);
	} else if (sURI == "/favicon.ico") {
		return PrintStaticFile("/pub/favicon.ico", sPageRet);
	} else if (sURI == "/robots.txt") {
		return PrintStaticFile("/pub/robots.txt", sPageRet);
	} else if (sURI == "/logout") {
		GetSession()->SetUser(NULL);
		SetLoggedIn(false);
		Redirect("/");

		// We already sent a reply
		return PAGE_DONE;
	} else if (sURI == "/login") {
		if (GetParam("submitted").ToBool()) {
			m_sUser = GetParam("user");
			m_sPass = GetParam("pass");
			m_bLoggedIn = OnLogin(m_sUser, m_sPass);

			// AcceptedLogin()/RefusedLogin() will call Redirect()
			return PAGE_DEFERRED;
		}

		Redirect("/"); // the login form is here
		return PAGE_DONE;
	} else if (sURI.Left(5) == "/pub/") {
		return PrintStaticFile(sURI, sPageRet);
	} else if (sURI.Left(11) == "/skinfiles/") {
		CString sSkinName = sURI.substr(11);
		CString::size_type uPathStart = sSkinName.find("/");
		if (uPathStart != CString::npos) {
			CString sFilePath = sSkinName.substr(uPathStart + 1);
			sSkinName.erase(uPathStart);

			m_Template.ClearPaths();
			m_Template.AppendPath(GetSkinPath(sSkinName) + "pub");

			if (PrintFile(m_Template.ExpandFile(sFilePath))) {
				return PAGE_DONE;
			} else {
				return PAGE_NOTFOUND;
			}
		}
		return PAGE_NOTFOUND;
	} else if (sURI.Left(6) == "/mods/" || sURI.Left(10) == "/modfiles/") {
		ParsePath();
		// Make sure modules are treated as directories
		if (sURI.Right(1) != "/" && sURI.find(".") == CString::npos && sURI.TrimLeft_n("/mods/").TrimLeft_n("/").find("/") == CString::npos) {
			Redirect(sURI + "/");
			return PAGE_DONE;
		}

		CModule *pModule = CZNC::Get().GetModules().FindModule(m_sModName);
		if (!pModule) {
			// Check if GetSession()->GetUser() is NULL and display
			// an error in that case
			if (!ForceLogin())
				return PAGE_DONE;

			pModule = GetSession()->GetUser()->GetModules().FindModule(m_sModName);
		}

		if (!pModule) {
			return PAGE_NOTFOUND;
		} else if (pModule->WebRequiresLogin() && !ForceLogin()) {
			return PAGE_PRINT;
		} else if (pModule->WebRequiresAdmin() && !GetSession()->IsAdmin()) {
			PrintErrorPage(403, "Forbidden", "You need to be an admin to access this module");
			return PAGE_DONE;
		} else if (!pModule->IsGlobal() && pModule->GetUser() != GetSession()->GetUser()) {
			PrintErrorPage(403, "Forbidden", "You must login as " + pModule->GetUser()->GetUserName() + " in order to view this page");
			return PAGE_DONE;
		} else if (pModule->OnWebPreRequest(*this, m_sPage)) {
			return PAGE_DEFERRED;
		}

		VWebSubPages& vSubPages = pModule->GetSubPages();

		for (unsigned int a = 0; a < vSubPages.size(); a++) {
			TWebSubPage& SubPage = vSubPages[a];

			bool bActive = (m_sModName == pModule->GetModName() && m_sPage == SubPage->GetName());

			if (bActive && SubPage->RequiresAdmin() && !GetSession()->IsAdmin()) {
				PrintErrorPage(403, "Forbidden", "You need to be an admin to access this page");
				return PAGE_DONE;
			}
		}

		if (pModule && !pModule->IsGlobal() && (!IsLoggedIn() || pModule->GetUser() != GetSession()->GetUser())) {
			AddModLoop("UserModLoop", *pModule);
		}

		if (sURI.Left(10) == "/modfiles/") {
			m_Template.AppendPath(GetSkinPath(GetSkinName()) + "/mods/" + m_sModName + "/files/");
			m_Template.AppendPath(pModule->GetModDataDir() + "/files/");

			if (PrintFile(m_Template.ExpandFile(m_sPage.TrimLeft_n("/")))) {
				return PAGE_PRINT;
			} else {
				return PAGE_NOTFOUND;
			}
		} else {
			SetPaths(pModule, true);

			/* if a module returns false from OnWebRequest, it does not
			   want the template to be printed, usually because it did a redirect. */
			if (pModule->OnWebRequest(*this, m_sPage, m_Template)) {
				// If they already sent a reply, let's assume
				// they did what they wanted to do.
				if (SentHeader()) {
					return PAGE_DONE;
				}
				return PrintTemplate(m_sPage, sPageRet, pModule);
			}

			if (!SentHeader()) {
				PrintErrorPage(404, "Not Implemented", "The requested module does not acknowledge web requests");
			}
			return PAGE_DONE;
		}
	} else {
		CString sPage(sURI.Trim_n("/"));
		if (sPage.length() < 32) {
			for (unsigned int a = 0; a < sPage.length(); a++) {
				unsigned char c = sPage[a];

				if ((c < '0' || c > '9') && (c < 'a' || c > 'z') && (c < 'A' || c > 'Z') && c != '_') {
					return PAGE_NOTFOUND;
				}
			}

			return PrintTemplate(sPage, sPageRet);
		}
	}

	return PAGE_NOTFOUND;
}
void TitleSubst::Load(const CString &filename, const CString &section)
{
	RageFile f;
	if( !f.Open(filename) )
	{
		LOG->Trace("Error opening %s: %s", filename.c_str(), f.GetError().c_str() );
		return;
	}
	
	CString CurrentSection;
	TitleTrans tr;
	
	while (!f.AtEOF())
	{
		CString line;
		int ret = f.GetLine( line );
		if( ret == 0 )
			break;
		if( ret < 0 )
		{
			LOG->Trace("Error reading %s: %s", filename.c_str(), f.GetError().c_str() );
			break;
		}

		if(line.size() > 0 && utf8_get_char(line.c_str()) == 0xFEFF)
		{
			/* Annoying header that Windows puts on UTF-8 plaintext
			 * files; remove it. */
			line.erase(0, utf8_get_char_len(line[0]));
		}

		TrimLeft(line);
		TrimRight(line);

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

		if(!line.CompareNoCase("DontTransliterate"))
		{
			tr.translit = false;
			continue;
		}

		size_t pos = line.find_first_of(':');
		if(pos != string::npos)
		{
			/* x: y */
			CString id = line.substr(0, pos);
			CString txt = line.substr(pos+1);
			TrimLeft(txt);

			/* Surround each regex with ^(...)$, to force all comparisons to default
			 * to being a full-line match.  (Add ".*" manually if this isn't wanted.) */
			if(!id.CompareNoCase("TitleFrom")) tr.TitleFrom = "^(" + txt + ")$";
			else if(!id.CompareNoCase("ArtistFrom")) tr.ArtistFrom = "^(" + txt + ")$";
			else if(!id.CompareNoCase("SubtitleFrom")) tr.SubFrom = "^(" + txt + ")$";
			else if(!id.CompareNoCase("TitleTo")) tr.Dest.Title = txt;
			else if(!id.CompareNoCase("ArtistTo")) tr.Dest.Artist = txt;
			else if(!id.CompareNoCase("SubtitleTo")) tr.Dest.Subtitle = txt;
			else if(!id.CompareNoCase("TitleTransTo")) tr.Dest.TitleTranslit = txt;
			else if(!id.CompareNoCase("ArtistTransTo")) tr.Dest.ArtistTranslit = txt;
			else if(!id.CompareNoCase("SubtitleTransTo")) tr.Dest.SubtitleTranslit = txt;
			else
				LOG->Warn( "Unknown TitleSubst tag: \"%s\"", id.c_str() );
		}

		/* Add the translation if this is a terminator (*) or section
		 * marker ([foo]). */
		if(line[0] == '*' || line[0] == '[')
		{
			if(!CurrentSection.CompareNoCase(section))
				AddTrans(tr);
			
			/* Reset. */
			tr = TitleTrans();
		}

		if(line[0] == '[' && line[line.size()-1] == ']')
		{
			CurrentSection = line.substr(1, line.size()-2);
		}
	}
}
Beispiel #11
0
static CString StripHTML(const CString& sFrom)
{
	CString sResult = sFrom;

	// remove tags:
	CString::size_type pos = sResult.find('<');

	while(pos != CString::npos)
	{
		CString::size_type endPos = sResult.find('>', pos);

		if(endPos != CString::npos)
		{
			sResult.erase(pos, endPos - pos + 1);
			pos = sResult.find('<', pos);
		}
		else
		{
			sResult.erase(pos);
			break;
		}
	}

	// remove stupid legay HTML entities:
	pos = sResult.find('&');

	while(pos != CString::npos)
	{
		CString::size_type endPos = sResult.find(';', pos);

		if(endPos != CString::npos)
		{
			bool found = false;

			for(unsigned int c = 0; c < 256; c++)
			{
				if(g_szHTMLescapes[c] && !strncasecmp(g_szHTMLescapes[c], (char*)(sResult.c_str() + pos), endPos - pos + 1))
				{
					sResult.erase(pos, endPos - pos + 1);
					sResult.insert(pos, 1, (char)c);
					found = true;
					break;
				}
			}

			if(!found && sResult[pos + 1] != '#')
				sResult.erase(pos, endPos - pos + 1);

			pos = sResult.find('&', pos + 1);
		}
		else
			break;
	}

	// remove numerical and XML entities:
	sResult = sResult.Escape_n(CString::EHTML, CString::EASCII);

	// because entitiy decoding is being done in two steps,
	// this screws up in certain situations, e.g. &#38;gt;
	// produces '>' instead of '&gt;' ... but whatever.


	// normalize whitespace:
	RE("\\s+").GlobalReplace(" ", &sResult);
	sResult.Trim();

	return sResult;
}
Beispiel #12
0
/*
 * Each dwMaxSize, dwTextureColorDepth and iAlphaBits are maximums; we may
 * use less.  iAlphaBits must be 0, 1 or 4.
 *
 * XXX: change iAlphaBits == 4 to iAlphaBits == 8 to indicate "as much alpha
 * as needed", since that's what it really is; still only use 4 in 16-bit textures.
 *
 * Dither forces dithering when loading 16-bit textures.
 * Stretch forces the loaded image to fill the texture completely.
 */
void RageBitmapTexture::Create()
{
	RageTextureID actualID = GetID();

	ASSERT( actualID.filename != "" );

	/* Create (and return) a surface ready to be loaded to OpenGL */
	/* Load the image into a RageSurface. */
	CString error;
	RageSurface *img = RageSurfaceUtils::LoadFile( actualID.filename, error );

	/* Tolerate corrupt/unknown images. */
	if( img == NULL )
	{
		CString sWarning = ssprintf( "RageBitmapTexture: Couldn't load %s: %s", actualID.filename.c_str(), error.c_str() );
		Dialog::OK( sWarning );
		img = RageSurfaceUtils::MakeDummySurface( 64, 64 );
		ASSERT( img != NULL );
	}

	if( actualID.bHotPinkColorKey )
		RageSurfaceUtils::ApplyHotPinkColorKey( img );

	{
		/* Do this after setting the color key for paletted images; it'll also return
		 * TRAIT_NO_TRANSPARENCY if the color key is never used. */
		int traits = RageSurfaceUtils::FindSurfaceTraits(img);
		if( traits & RageSurfaceUtils::TRAIT_NO_TRANSPARENCY )
			actualID.iAlphaBits = 0;
		else if( traits & RageSurfaceUtils::TRAIT_BOOL_TRANSPARENCY )
			actualID.iAlphaBits = 1;
	}

	// look in the file name for a format hints
	CString HintString = GetID().filename + actualID.AdditionalTextureHints;
	HintString.MakeLower();

	if( HintString.find("32bpp") != CString::npos )			actualID.iColorDepth = 32;
	else if( HintString.find("16bpp") != CString::npos )		actualID.iColorDepth = 16;
	if( HintString.find("dither") != CString::npos )		actualID.bDither = true;
	if( HintString.find("stretch") != CString::npos )		actualID.bStretch = true;
	if( HintString.find("mipmaps") != CString::npos )		actualID.bMipMaps = true;
	if( HintString.find("nomipmaps") != CString::npos )		actualID.bMipMaps = false;	// check for "nomipmaps" after "mipmaps"

	/* If the image is marked grayscale, then use all bits not used for alpha
	 * for the intensity.  This way, if an image has no alpha, you get an 8-bit
	 * grayscale; if it only has boolean transparency, you get a 7-bit grayscale. */
	if( HintString.find("grayscale") != CString::npos )		actualID.iGrayscaleBits = 8-actualID.iAlphaBits;

	/* This indicates that the only component in the texture is alpha; assume all
	 * color is white. */
	if( HintString.find("alphamap") != CString::npos )		actualID.iGrayscaleBits = 0;

	/* No iGrayscaleBits for images that are already paletted.  We don't support
	 * that; and that hint is intended for use on images that are already grayscale,
	 * it's not intended to change a color image into a grayscale image. */
	if( actualID.iGrayscaleBits != -1 && img->format->BitsPerPixel == 8 )
		actualID.iGrayscaleBits = -1;

	/* Cap the max texture size to the hardware max. */
	actualID.iMaxSize = min( actualID.iMaxSize, DISPLAY->GetMaxTextureSize() );

	/* Save information about the source. */
	m_iSourceWidth = img->w;
	m_iSourceHeight = img->h;

	/* image size cannot exceed max size */
	m_iImageWidth = min( m_iSourceWidth, actualID.iMaxSize );
	m_iImageHeight = min( m_iSourceHeight, actualID.iMaxSize );

	/* Texture dimensions need to be a power of two; jump to the next. */
	m_iTextureWidth = power_of_two(m_iImageWidth);
	m_iTextureHeight = power_of_two(m_iImageHeight);

	/* If we're under 8x8, increase it, to avoid filtering problems on odd hardware. */
	if(m_iTextureWidth < 8 || m_iTextureHeight < 8)
	{
		actualID.bStretch = true;
		m_iTextureWidth = max(8, m_iTextureWidth);
		m_iTextureHeight = max(8, m_iTextureHeight);
	}

	ASSERT( m_iTextureWidth <= actualID.iMaxSize );
	ASSERT( m_iTextureHeight <= actualID.iMaxSize );

	if(actualID.bStretch)
	{
		/* The hints asked for the image to be stretched to the texture size,
		 * probably for tiling. */
		m_iImageWidth = m_iTextureWidth;
		m_iImageHeight = m_iTextureHeight;
	}

	if( img->w != m_iImageWidth || img->h != m_iImageHeight ) 
		RageSurfaceUtils::Zoom( img, m_iImageWidth, m_iImageHeight );

	// Format of the image that we will pass to OpenGL and that we want OpenGL to use
	RageDisplay::PixelFormat pixfmt;

	if( actualID.iGrayscaleBits != -1 && DISPLAY->SupportsTextureFormat(RageDisplay::FMT_PAL) )
	{
		RageSurface *dst = RageSurfaceUtils::PalettizeToGrayscale( img, actualID.iGrayscaleBits, actualID.iAlphaBits );

		delete img;
		img = dst;
	}

	/* Figure out which texture format to use. */
	// if the source is palleted, load palleted no matter what the prefs
	if(img->format->BitsPerPixel == 8 && DISPLAY->SupportsTextureFormat(RageDisplay::FMT_PAL))
	{
		pixfmt = RageDisplay::FMT_PAL;
	}
	else
	{
		// not paletted
		switch( actualID.iColorDepth )
		{
		case 16:
			{
				/* Bits of alpha in the source: */
				int src_alpha_bits = 8 - img->format->Loss[3];

				/* Don't use more than we were hinted to. */
				src_alpha_bits = min( actualID.iAlphaBits, src_alpha_bits );

				switch( src_alpha_bits ) {
				case 0:
				case 1:
					pixfmt = RageDisplay::FMT_RGB5A1;
					break;
				default:	
					pixfmt = RageDisplay::FMT_RGBA4;
					break;
				}
			}
			break;
		case 32:
			pixfmt = RageDisplay::FMT_RGBA8;
			break;
		default:
			RageException::Throw( "Invalid color depth: %d bits", actualID.iColorDepth );
		}
	}

	/* Make we're using a supported format. Every card supports either RGBA8 or RGBA4. */
	if( !DISPLAY->SupportsTextureFormat(pixfmt) )
	{
		pixfmt = RageDisplay::FMT_RGBA8;
		if( !DISPLAY->SupportsTextureFormat(pixfmt) )
			pixfmt = RageDisplay::FMT_RGBA4;
	}

	/* Dither if appropriate. XXX: This is a special case: don't bother dithering to
	 * RGBA8888.  We actually want to dither only if the destination has greater color
	 * depth on at least one color channel than the source.  For example, it doesn't
	 * make sense to do this when pixfmt is RGBA5551 if the image is only RGBA555. */
	if( actualID.bDither && 
		(pixfmt==RageDisplay::FMT_RGBA4 || pixfmt==RageDisplay::FMT_RGB5A1) )
	{
		/* Dither down to the destination format. */
		const RageDisplay::PixelFormatDesc *pfd = DISPLAY->GetPixelFormatDesc(pixfmt);
		RageSurface *dst = CreateSurface( img->w, img->h, pfd->bpp,
			pfd->masks[0], pfd->masks[1], pfd->masks[2], pfd->masks[3] );

		RageSurfaceUtils::ErrorDiffusionDither( img, dst );
		delete img;
		img = dst;
	}

	/* This needs to be done *after* the final resize, since that resize
	 * may introduce new alpha bits that need to be set.  It needs to be
	 * done *before* we set up the palette, since it might change it. */
	RageSurfaceUtils::FixHiddenAlpha(img);

	/* Convert the data to the destination format and dimensions 
	 * required by OpenGL if it's not in it already.  */
	/* We no longer need to do this; pixfmt and the format of img no longer have
	 * to match.  This means that if we have a paletted image, but the hardware
	 * doesn't support it, we can leave the data in the smaller paletted format
	 * and let OpenGL dereference it, as long as nothing else (such as dithering)
	 * ends up depalettizing it first.  We only have to scale it up to the texture
	 * size, which we won't have to do either if the image size is already a power
	 * of two. */
	// const RageDisplay::PixelFormatDesc *pfd = DISPLAY->GetPixelFormatDesc(pixfmt);
	RageSurfaceUtils::ConvertSurface( img, m_iTextureWidth, m_iTextureHeight,
		img->fmt.BitsPerPixel, img->fmt.Mask[0], img->fmt.Mask[1], img->fmt.Mask[2], img->fmt.Mask[3] );
	//	pfd->bpp, pfd->masks[0], pfd->masks[1], pfd->masks[2], pfd->masks[3] );
	
	m_uTexHandle = DISPLAY->CreateTexture( pixfmt, img, actualID.bMipMaps );

	CreateFrameRects();


	//
	// Enforce frames in the image have even dimensions.  Otherwise, 
	// pixel/texel alignment will be off.
	//
	bool bRunCheck = true;
	
	 // Don't check if the artist intentionally blanked the image by making it very tiny.
	if( this->GetSourceWidth()<=2 || this->GetSourceHeight()<=2 )
		 bRunCheck = false;
	
	// HACK: Don't check song graphics.  Many of them are weird dimensions.
	if( !TEXTUREMAN->GetOddDimensionWarning() )
		 bRunCheck = false;

	if( bRunCheck  )
	{
		float fFrameWidth = this->GetSourceWidth() / (float)this->GetFramesWide();
		float fFrameHeight = this->GetSourceHeight() / (float)this->GetFramesHigh();
		float fBetterFrameWidth = roundf((fFrameWidth+0.99f)/2)*2;
		float fBetterFrameHeight = roundf((fFrameHeight+0.99f)/2)*2;
		float fBetterSourceWidth = this->GetFramesWide() * fBetterFrameWidth;
		float fBetterSourceHeight = this->GetFramesHigh() * fBetterFrameHeight;
		if( fFrameWidth!=fBetterFrameWidth || fFrameHeight!=fBetterFrameHeight )
		{
			CString sWarning = ssprintf(
				"The graphic '%s' has frame dimensions that aren't even numbers.\n\n"
				"The entire image is %dx%d and frame size is %.1fx%.1f.\n\n"
				"Image quality will be much improved if you resize the graphic to %.0fx%.0f, which is a frame size of %.0fx%.0f.", 
				actualID.filename.c_str(), 
				this->GetSourceWidth(), this->GetSourceHeight(), 
				fFrameWidth, fFrameHeight,
				fBetterSourceWidth, fBetterSourceHeight,
				fBetterFrameWidth, fBetterFrameHeight );
			LOG->Warn( sWarning );
			Dialog::OK( sWarning, "FRAME_DIMENSIONS_WARNING" );
		}
	}



	delete img;

	/* See if the apparent "size" is being overridden. */
	GetResolutionFromFileName(actualID.filename, m_iSourceWidth, m_iSourceHeight);


	CString props;
	props += RageDisplay::PixelFormatToString( pixfmt ) + " ";
	if(actualID.iAlphaBits == 0) props += "opaque ";
	if(actualID.iAlphaBits == 1) props += "matte ";
	if(actualID.bStretch) props += "stretch ";
	if(actualID.bDither) props += "dither ";
	props.erase(props.size()-1);
	LOG->Trace( "RageBitmapTexture: Loaded '%s' (%ux%u); %s, source %d,%d;  image %d,%d.", 
		actualID.filename.c_str(), GetTextureWidth(), GetTextureHeight(),
		props.c_str(), m_iSourceWidth, m_iSourceHeight,
		m_iImageWidth,	m_iImageHeight);
}