From e8947d9f70e2806bef93000eb83db1c80142eea1 Mon Sep 17 00:00:00 2001 From: Michael Votaw Date: Fri, 23 Feb 2024 19:26:58 -0600 Subject: [PATCH] Added a new SmEscape parameter to allow us to specify what characters to escape (defaults to '\\', ':', ';') Added new SmEscape function to handle escaping a vector of strings Added SmUnescape() to remove the '\\' preceding an escaped character. --- src/RageUtil.cpp | 40 +++++++++++++++++++++++++++++++--------- src/RageUtil.h | 8 ++++++-- 2 files changed, 37 insertions(+), 11 deletions(-) diff --git a/src/RageUtil.cpp b/src/RageUtil.cpp index 935bc3ee4f..b331702f5c 100644 --- a/src/RageUtil.cpp +++ b/src/RageUtil.cpp @@ -705,33 +705,55 @@ RString join( const RString &sDelimitor, std::vector::const_iterator be return sRet; } -RString SmEscape( const RString &sUnescaped ) +RString SmEscape( const RString &sUnescaped, const std::vector charsToEscape ) { - return SmEscape( sUnescaped.c_str(), sUnescaped.size() ); + return SmEscape(sUnescaped.c_str(), sUnescaped.size(), charsToEscape); } -RString SmEscape( const char *cUnescaped, int len ) +RString SmEscape ( const char *cUnescaped, int len, const std::vector charsToEscape ) { RString answer = ""; for( int i = 0; i < len; ++i ) { - // Other characters we could theoretically escape: - // NotesWriterSM.cpp used to claim ',' should be escaped, but there was no explanation why - // '#' is both a control character and a valid part of a parameter. The only way for there to be - // any confusion is in a misformatted .sm file, though, so it is unnecessary to escape it. if( cUnescaped[i] == '/' && i + 1 < len && cUnescaped[i + 1] == '/' ) { answer += "\\/\\/"; ++i; // increment here so we skip both //s continue; } - if( cUnescaped[i] == '\\' || cUnescaped[i] == ':' || cUnescaped[i] == ';' ) - answer += "\\"; + for(char escapeChar: charsToEscape) + { + if(cUnescaped[i] == escapeChar) + { + answer += "\\"; + break; + } + } + answer += cUnescaped[i]; } return answer; } +std::vector SmEscape(const std::vector &vUnescaped, const std::vector charsToEscape) +{ + std::vector escaped; + for(RString unescaped: vUnescaped) + { + escaped.push_back(SmEscape(unescaped, charsToEscape)); + } + return escaped; +} + +RString SmUnescape( const RString &sEscaped ) +{ + RString unescaped = sEscaped; + unescaped.Replace("\\\\", "||escaped-backslash||"); + unescaped.Replace("\\", ""); + unescaped.Replace("||escaped-backslash||", "\\"); + return unescaped; +} + RString DwiEscape( const RString &sUnescaped ) { return DwiEscape( sUnescaped.c_str(), sUnescaped.size() ); diff --git a/src/RageUtil.h b/src/RageUtil.h index b7d54eb3b2..1317dcae72 100644 --- a/src/RageUtil.h +++ b/src/RageUtil.h @@ -422,8 +422,12 @@ RString join( const RString &sDelimitor, const std::vector& sSource ); RString join( const RString &sDelimitor, std::vector::const_iterator begin, std::vector::const_iterator end ); // These methods escapes a string for saving in a .sm or .crs file -RString SmEscape( const RString &sUnescaped ); -RString SmEscape( const char *cUnescaped, int len ); +RString SmEscape(const RString &sUnescaped, const std::vector charsToEscape = {'\\', ':', ';'}); +RString SmEscape( const char *cUnescaped, int len, const std::vector charsToEscape = {'\\', ':', ';'} ); +// Escapes each element in a std::vector, returns a new vector +std::vector SmEscape(const std::vector &vUnescaped, const std::vector charsToEscape = {'\\', ':', ';'}); + +RString SmUnescape( const RString &sEscaped ); // These methods "escape" a string for .dwi by turning = into -, ] into I, etc. That is "lossy". RString DwiEscape( const RString &sUnescaped );