diff --git a/stepmania/src/Font.cpp b/stepmania/src/Font.cpp index b15d3a49c8..0292be6fe0 100644 --- a/stepmania/src/Font.cpp +++ b/stepmania/src/Font.cpp @@ -278,6 +278,13 @@ void Font::AddPage(FontPage *fp) void Font::MergeFont(Font &f) { + /* If we don't have a font page yet, and f does, grab the default font + * page. It'll usually be overridden later on by one of our own font + * pages; this will be used only if we don't have any font pages at + * all. */ + if(def == NULL) + def = f.def; + for(map::iterator it = f.m_iCharToGlyph.begin(); it != f.m_iCharToGlyph.end(); ++it) { @@ -358,42 +365,79 @@ bool Font::MatchesFont(CString FontName, CString FileName) return regex("^( \\[|\\.| [0-9]+x[0-9]+)", FileName); } -void Font::GetFontPaths(const CString &sFontOrTextureFilePath, +CString GetFontName(CString FileName) +{ + CString orig = FileName; + + /* If it ends in an extension, remove it. */ + if(regex("\\....", FileName)) + FileName.erase(FileName.size()-4); + + /* If it ends in a dimension spec, remove it. */ + CStringArray mat; + if(regex("( [0-9]+x[0-9]+)$", FileName, mat)) + FileName.erase(FileName.size()-mat[0].size()); + + /* If it ends in a page name, remove it. */ + if(regex("( \\[.+\\])$", FileName, mat)) + FileName.erase(FileName.size()-mat[0].size()); + + TrimRight(FileName); + + if(FileName.empty()) + RageException::Throw("Can't parse font filename \"%s\"", orig.GetString()); + + return FileName; +} + +/* Given a file in a font, find all of the files for the font. + * + * Possibilities: + * + * Normal 16x16.png + * Normal [other] 16x16.png + * Normal [more] 8x8.png + * Normal 16x16.ini + * Normal.ini + * + * Any of the above should find all of the above. Allow the + * extension to be omitted. */ +void Font::GetFontPaths(const CString &sFontOrTextureFilePath, CStringArray &TexturePaths, CString &IniPath) { - CString sDrive, sDir, sFName, sExt; - splitpath( false, sFontOrTextureFilePath, sDrive, sDir, sFName, sExt ); + CString sDir, sFName, sExt; + splitpath( sFontOrTextureFilePath, sDir, sFName, sExt ); - ASSERT(sExt.CompareNoCase("ini")); /* don't give us an INI! */ - ASSERT(sExt.CompareNoCase("redir")); /* don't give us a redir! */ + /* Don't give us a redir; resolve those before sending them here. */ + ASSERT(sExt.CompareNoCase("redir")); - if(!sExt.empty()) + /* sFName can't be empty, or we don't know what to search for. */ + ASSERT(!sFName.empty()); + + CString FontName = GetFontName(sFName); + + CStringArray Files; + GetDirListing( sDir+"/"+FontName + "*", Files, false, false ); + + for(unsigned i = 0; i < Files.size(); ++i) { - TexturePaths.push_back(sFontOrTextureFilePath); - return; + /* We now have a list of possibilities, but it may include false positives, + * such as "Normal2" when the font name is "Normal". Weed them. */ + if(GetFontName(Files[i]).CompareNoCase(FontName)) + continue; + + /* If it's an INI, and we don't already have an INI, use it. */ + if(!Files[i].Right(4).CompareNoCase(".ini")) + { + if(!IniPath.empty()) + RageException::Throw("More than one INI found\n%s\n%s", IniPath.GetString(), Files[i].GetString()); + + IniPath = sDir+"/"+Files[i]; + continue; + } + + TexturePaths.push_back(sDir+"/"+Files[i]); } - - /* If we have no extension, we need to search. */ - GetDirListing( sFontOrTextureFilePath + "*.png", TexturePaths, false, true ); - - CStringArray IniPaths; - GetDirListing( sFontOrTextureFilePath + "*.ini", IniPaths, false, true ); - - /* Filter out texture files that aren't actually for this font. */ - unsigned i = 0; - while(i < TexturePaths.size()) - { - if(!MatchesFont(sFontOrTextureFilePath, TexturePaths[i])) - TexturePaths.erase(TexturePaths.begin()+i); - else - i++; - } - - for(i = 0; i < IniPaths.size(); ++i) - if(MatchesFont(sFontOrTextureFilePath, IniPaths[i])) break; - if(i < IniPaths.size()) IniPath = IniPaths[i]; - - ASSERT(!TexturePaths.empty()); /* ThemeManager should have checked this */ } CString Font::GetPageNameFromFileName(const CString &fn) @@ -666,7 +710,11 @@ void Font::Load(const CString &sFontOrTextureFilePath, CString sChars) CStringArray TexturePaths; CString IniPath; GetFontPaths(sFontOrTextureFilePath, TexturePaths, IniPath); - + + /* If we don't have at least one INI or at least one texture path, + * we have nothing at all. */ + ASSERT(!IniPath.empty() || TexturePaths.size()); + bool CapitalsOnly = false; /* If we have an INI, load it. */ diff --git a/stepmania/src/RageTextureManager.cpp b/stepmania/src/RageTextureManager.cpp index 0572788932..060bc10510 100644 --- a/stepmania/src/RageTextureManager.cpp +++ b/stepmania/src/RageTextureManager.cpp @@ -91,8 +91,8 @@ RageTexture* RageTextureManager::LoadTexture( RageTextureID ID ) ID.iColorDepth = TEXTUREMAN->GetTextureColorDepth(); ID.iMaxSize = TEXTUREMAN->GetMaxTextureResolution(); - CString sDrive, sDir, sFName, sExt; - splitpath( false, ID.filename, sDrive, sDir, sFName, sExt ); + CString sDir, sFName, sExt; + splitpath( ID.filename, sDir, sFName, sExt ); RageTexture* pTexture; if( sExt == "avi" || sExt == "mpg" || sExt == "mpeg" ) diff --git a/stepmania/src/RageUtil.cpp b/stepmania/src/RageUtil.cpp index 955be9999d..2fe59c031d 100644 --- a/stepmania/src/RageUtil.cpp +++ b/stepmania/src/RageUtil.cpp @@ -184,69 +184,29 @@ void split( const lstring &Source, const lstring &Deliminator, vector & } -void splitpath( bool UsingDirsOnly, const CString &Path, CString& Drive, CString& Dir, CString& FName, CString& Ext ) +/* + * foo\fum\ -> "foo\fum\", "", "" + * c:\foo\bar.txt -> "c:\foo\", "bar", ".txt" + * \\foo\fum -> "\\foo\", "fum", "" + */ +void splitpath( CString Path, CString& Dir, CString& Filename, CString& Ext ) { - int nSecond; + Dir = Filename = Ext = ""; - // Look for a UNC filename. - if (Path.Left(2) == "\\\\") + CStringArray mat; + + /* One level of escapes for the regex, one for C. Ew. */ + ASSERT(regex("^(.*[\\\\/])?(.*)$", Path, mat)); + + Dir = mat[0]; + Path = mat[1]; + + if(regex("^(.*)(\\....)$", Path, mat)) { - int nFirst = Path.Find("\\",3); - nSecond = Path.Find("\\",nFirst + 1); - if (nSecond == -1) { - Drive = Path; - Dir = ""; - FName = ""; - Ext = ""; - } - else if (nSecond > nFirst) - Drive = Path.Left(nSecond); - } - else if (Path[1] == ':' ) // drive letter - { - nSecond = 2; - Drive = Path.Left(2); - } - else // no UNC or drive letter - { - nSecond = -1; - } - - - if (UsingDirsOnly) { - Dir = Path.Right((Path.GetLength() - nSecond) - 1); - FName = ""; - Ext = ""; - } - else { - int nDirEnd = Path.ReverseFind('\\'); - if (nDirEnd == Path.GetLength()) { - Dir = ""; - FName = ""; - Ext = ""; - } - else { - - Dir = Path.substr(nSecond + 1, (nDirEnd - nSecond) - 1); - - int nFileEnd = Path.ReverseFind('.'); - if (nFileEnd != -1) { - - if (nDirEnd > nFileEnd) { - FName = Path.Right(Path.GetLength() - nDirEnd); - Ext = ""; - } - else { - FName = Path.substr(nDirEnd + 1, (nFileEnd - nDirEnd) - 1); - Ext = Path.Right((Path.GetLength() - nFileEnd) - 1); - } - } - else { - FName = Path.Right((Path.GetLength() - nDirEnd) - 1); - Ext = ""; - } - } - } + Filename = mat[0]; + Ext = mat[1]; + } else + Filename = Path; } void splitrelpath( const CString &Path, CString& Dir, CString& FName, CString& Ext ) diff --git a/stepmania/src/RageUtil.h b/stepmania/src/RageUtil.h index 9096bed541..2fa24ab4cd 100644 --- a/stepmania/src/RageUtil.h +++ b/stepmania/src/RageUtil.h @@ -128,17 +128,12 @@ CString werr_ssprintf( int err, const char *fmt, ...); #endif // Splits a Path into 4 parts (Directory, Drive, Filename, Extention). Supports UNC path names. -// param1: Whether the Supplied Path (PARAM2) contains a directory name only -// or a file name (Reason: some directories will end with "aaa.bbb" -// which is like a file name). -// We should just make sure all pathnames end with a slash, not special case it here. -// -glenn +/* If Path is a directory (eg. c:\games\stepmania"), append a slash so the last + * element will end up in Dir, not FName: "c:\games\stepmania\". */ void splitpath( - bool UsingDirsOnly, - const CString &Path, - CString &Drive, - CString &Dir, - CString &FName, + CString Path, + CString &Dir, + CString &Filename, CString &Ext );