Merge pull request #308 from tomaz82/utils

Add String and FilesSystem utils
This commit is contained in:
Jools Wills 2017-11-16 18:38:15 +00:00 committed by GitHub
commit 094c9ccd09
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 388 additions and 147 deletions

View file

@ -69,6 +69,10 @@ set(CORE_HEADERS
${CMAKE_CURRENT_SOURCE_DIR}/src/resources/TextureData.h ${CMAKE_CURRENT_SOURCE_DIR}/src/resources/TextureData.h
${CMAKE_CURRENT_SOURCE_DIR}/src/resources/TextureDataManager.h ${CMAKE_CURRENT_SOURCE_DIR}/src/resources/TextureDataManager.h
# Utils
${CMAKE_CURRENT_SOURCE_DIR}/src/utils/FileSystemUtil.h
${CMAKE_CURRENT_SOURCE_DIR}/src/utils/StringUtil.h
# Embedded assets (needed by ResourceManager) # Embedded assets (needed by ResourceManager)
${emulationstation-all_SOURCE_DIR}/data/Resources.h ${emulationstation-all_SOURCE_DIR}/data/Resources.h
) )
@ -136,6 +140,10 @@ set(CORE_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/src/resources/TextureResource.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/resources/TextureResource.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/resources/TextureData.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/resources/TextureData.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/resources/TextureDataManager.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/resources/TextureDataManager.cpp
# Utils
${CMAKE_CURRENT_SOURCE_DIR}/src/utils/FileSystemUtil.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/utils/StringUtil.cpp
) )
set(EMBEDDED_ASSET_SOURCES set(EMBEDDED_ASSET_SOURCES

View file

@ -1,136 +0,0 @@
#pragma once
#ifndef ES_CORE_STRING_UTIL_H
#define ES_CORE_STRING_UTIL_H
namespace StringUtil
{
inline unsigned int chars2Unicode(const std::string& _string, size_t& _cursor)
{
const char& c = _string[_cursor];
unsigned int result = '?';
if((c & 0x80) == 0) // 0xxxxxxx, one byte character
{
// 0xxxxxxx
result = ((_string[_cursor++] ) );
}
else if((c & 0xE0) == 0xC0) // 110xxxxx, two byte character
{
// 110xxxxx 10xxxxxx
result = ((_string[_cursor++] & 0x1F) << 6) |
((_string[_cursor++] & 0x3F) );
}
else if((c & 0xF0) == 0xE0) // 1110xxxx, three byte character
{
// 1110xxxx 10xxxxxx 10xxxxxx
result = ((_string[_cursor++] & 0x0F) << 12) |
((_string[_cursor++] & 0x3F) << 6) |
((_string[_cursor++] & 0x3F) );
}
else if((c & 0xF8) == 0xF0) // 11110xxx, four byte character
{
// 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
result = ((_string[_cursor++] & 0x07) << 18) |
((_string[_cursor++] & 0x3F) << 12) |
((_string[_cursor++] & 0x3F) << 6) |
((_string[_cursor++] & 0x3F) );
}
else
{
// error, invalid unicode
++_cursor;
}
return result;
} // chars2Unicode
inline std::string unicode2Chars(const unsigned int _unicode)
{
std::string result;
if(_unicode < 0x80) // one byte character
{
result += ((_unicode ) );
}
else if(_unicode < 0x800) // two byte character
{
result += ((_unicode >> 6) ) | 0xC0;
result += ((_unicode ) & 0x3F) | 0x80;
}
else if(_unicode < 0xFFFF) // three byte character
{
result += ((_unicode >> 12) ) | 0xE0;
result += ((_unicode >> 6) & 0x3F) | 0x80;
result += ((_unicode ) & 0x3F) | 0x80;
}
else if(_unicode <= 0x1fffff) // four byte character
{
result += ((_unicode >> 18) ) | 0xF0;
result += ((_unicode >> 12) & 0x3F) | 0x80;
result += ((_unicode >> 6) & 0x3F) | 0x80;
result += ((_unicode ) & 0x3F) | 0x80;
}
else
{
// error, invalid unicode
result += '?';
}
return result;
} // unicode2Chars
inline size_t nextCursor(const std::string& _string, const size_t _cursor)
{
size_t result = _cursor;
while(result < _string.length())
{
++result;
if((_string[result] & 0xC0) != 0x80) // break if current character is not 10xxxxxx
break;
}
return result;
} // nextCursor
inline size_t prevCursor(const std::string& _string, const size_t _cursor)
{
size_t result = _cursor;
while(result > 0)
{
--result;
if((_string[result] & 0xC0) != 0x80) // break if current character is not 10xxxxxx
break;
}
return result;
} // prevCursor
inline size_t moveCursor(const std::string& _string, const size_t _cursor, const int _amount)
{
size_t result = _cursor;
if(_amount > 0)
{
for(int i = 0; i < _amount; ++i)
result = nextCursor(_string, result);
}
else if(_amount < 0)
{
for(int i = _amount; i < 0; ++i)
result = prevCursor(_string, result);
}
return result;
} // moveCursor
}
#endif // ES_CORE_STRING_UTIL_H

View file

@ -1,9 +1,9 @@
#include "components/TextComponent.h" #include "components/TextComponent.h"
#include "utils/StringUtil.h"
#include "Log.h" #include "Log.h"
#include "Renderer.h" #include "Renderer.h"
#include "Settings.h" #include "Settings.h"
#include "StringUtil.h"
#include "Util.h" #include "Util.h"
TextComponent::TextComponent(Window* window) : GuiComponent(window), TextComponent::TextComponent(Window* window) : GuiComponent(window),
@ -198,7 +198,7 @@ void TextComponent::onTextChanged()
while(text.size() && size.x() + abbrevSize.x() > mSize.x()) while(text.size() && size.x() + abbrevSize.x() > mSize.x())
{ {
size_t newSize = StringUtil::prevCursor(text, text.size()); size_t newSize = Utils::String::prevCursor(text, text.size());
text.erase(newSize, text.size() - newSize); text.erase(newSize, text.size() - newSize);
size = f->sizeText(text); size = f->sizeText(text);
} }

View file

@ -1,8 +1,8 @@
#include "components/TextEditComponent.h" #include "components/TextEditComponent.h"
#include "resources/Font.h" #include "resources/Font.h"
#include "utils/StringUtil.h"
#include "Renderer.h" #include "Renderer.h"
#include "StringUtil.h"
#define TEXT_PADDING_HORIZ 10 #define TEXT_PADDING_HORIZ 10
#define TEXT_PADDING_VERT 2 #define TEXT_PADDING_VERT 2
@ -60,7 +60,7 @@ void TextEditComponent::textInput(const char* text)
{ {
if(mCursor > 0) if(mCursor > 0)
{ {
size_t newCursor = StringUtil::prevCursor(mText, mCursor); size_t newCursor = Utils::String::prevCursor(mText, mCursor);
mText.erase(mText.begin() + newCursor, mText.begin() + mCursor); mText.erase(mText.begin() + newCursor, mText.begin() + mCursor);
mCursor = newCursor; mCursor = newCursor;
} }
@ -191,7 +191,7 @@ void TextEditComponent::updateCursorRepeat(int deltaTime)
void TextEditComponent::moveCursor(int amt) void TextEditComponent::moveCursor(int amt)
{ {
mCursor = StringUtil::moveCursor(mText, mCursor, amt); mCursor = Utils::String::moveCursor(mText, mCursor, amt);
onCursorChanged(); onCursorChanged();
} }

View file

@ -1,8 +1,8 @@
#include "resources/Font.h" #include "resources/Font.h"
#include "utils/StringUtil.h"
#include "Log.h" #include "Log.h"
#include "Renderer.h" #include "Renderer.h"
#include "StringUtil.h"
#include "Util.h" #include "Util.h"
FT_Library Font::sLibrary = NULL; FT_Library Font::sLibrary = NULL;
@ -448,7 +448,7 @@ Vector2f Font::sizeText(std::string text, float lineSpacing)
size_t i = 0; size_t i = 0;
while(i < text.length()) while(i < text.length())
{ {
unsigned int character = StringUtil::chars2Unicode(text, i); // advances i unsigned int character = Utils::String::chars2Unicode(text, i); // advances i
if(character == '\n') if(character == '\n')
{ {
@ -541,8 +541,8 @@ Vector2f Font::getWrappedTextCursorOffset(std::string text, float xLen, size_t s
size_t cursor = 0; size_t cursor = 0;
while(cursor < stop) while(cursor < stop)
{ {
unsigned int wrappedCharacter = StringUtil::chars2Unicode(wrappedText, wrapCursor); unsigned int wrappedCharacter = Utils::String::chars2Unicode(wrappedText, wrapCursor);
unsigned int character = StringUtil::chars2Unicode(text, cursor); unsigned int character = Utils::String::chars2Unicode(text, cursor);
if(wrappedCharacter == '\n' && character != '\n') if(wrappedCharacter == '\n' && character != '\n')
{ {
@ -551,7 +551,7 @@ Vector2f Font::getWrappedTextCursorOffset(std::string text, float xLen, size_t s
lineWidth = 0.0f; lineWidth = 0.0f;
y += getHeight(lineSpacing); y += getHeight(lineSpacing);
cursor = StringUtil::prevCursor(text, cursor); // unconsume cursor = Utils::String::prevCursor(text, cursor); // unconsume
continue; continue;
} }
@ -609,7 +609,7 @@ TextCache* Font::buildTextCache(const std::string& text, Vector2f offset, unsign
size_t cursor = 0; size_t cursor = 0;
while(cursor < text.length()) while(cursor < text.length())
{ {
unsigned int character = StringUtil::chars2Unicode(text, cursor); // also advances cursor unsigned int character = Utils::String::chars2Unicode(text, cursor); // also advances cursor
Glyph* glyph; Glyph* glyph;
// invalid character // invalid character

View file

@ -0,0 +1,168 @@
#include "utils/FileSystemUtil.h"
#include <sys/stat.h>
#include <string.h>
#if defined(WIN32)
// because windows...
#include <direct.h>
#define snprintf _snprintf
#define mkdir(x,y) _mkdir(x)
#endif // WIN32
namespace Utils
{
namespace FileSystem
{
bool createDirectory(const std::string& path)
{
// don't create if it already exists
if(exists(path))
return true;
// convert '\\' to '/'
fixSeparators(path);
// try to create directory
if(mkdir(path.c_str(), 0755) == 0)
return true;
// failed to create directory, try to create the parent
std::string parent = getParent(path);
// only try to create parent if it's not identical to path
if(parent != path)
createDirectory(parent);
// try to create directory again now that the parent should exist
return (mkdir(path.c_str(), 0755) == 0);
} // createDirectory
void fixSeparators(const std::string& path)
{
char* p = nullptr;
// convert '\\' to '/'
for(p = (char*)path.c_str() + 1; *p; ++p)
{
if(*p == '\\')
*p = '/';
}
} // fixSeparators
std::string escapePath(const std::string& path)
{
#ifdef WIN32
// windows escapes stuff by just putting everything in quotes
return '"' + path + '"';
#else // WIN32
// insert a backslash before most characters that would mess up a bash path
std::string escapedPath = path;
const char* invalidChars = "\\ '\"!$^&*(){}[]?;<>";
const char* invalidChar = invalidChars;
while(*invalidChar)
{
for(size_t i = 0; i < escapedPath.length(); ++i)
{
if(escapedPath[i] == *invalidChar)
{
escapedPath.insert(i, 1, '\\');
++i;
}
}
++invalidChar;
}
return escapedPath;
#endif // WIN32
} // escapePath
std::string getParent(const std::string& path)
{
// convert '\\' to '/'
fixSeparators(path);
// make a copy of the path
char temp[512];
size_t len = snprintf(temp, sizeof(temp), "%s", path.c_str());
// find last '/' and end the new path
while(len > 1)
{
if(temp[--len] == '/')
{
temp[len] = 0;
return temp;
}
}
// no parent found
return path;
} // getParent
std::string getFileName(const std::string& path)
{
// convert '\\' to '/'
fixSeparators(path);
// make a copy of the path
char temp[512];
size_t len = snprintf(temp, sizeof(temp), "%s", path.c_str());
// find last '/' and return the filename
while(len > 1)
{
// return "." if this is the end of the path, otherwise return filename
if(temp[--len] == '/')
return ((temp[len + 1] == 0) ? "." : (temp + len + 1));
}
// no '/' found, entire path is a filename
return path;
} // getFileName
std::string getStem(const std::string& path)
{
std::string fileName = getFileName(path);
// empty fileName
if(fileName == ".")
return fileName;
// make a copy of the filename
char temp[512];
size_t len = snprintf(temp, sizeof(temp), "%s", fileName.c_str());
// find last '.' and remove the extension
while(len > 1)
{
if(temp[--len] == '.')
{
temp[len] = 0;
return temp;
}
}
// no '.' found, filename has no extension
return fileName;
} // getStem
bool exists(const std::string& path)
{
struct stat info;
return (stat(path.c_str(), &info) == 0);
} // exists
} // FileSystem::
} // Utils::

View file

@ -0,0 +1,23 @@
#pragma once
#ifndef ES_CORE_FILE_SYSTEM_UTIL_H
#define ES_CORE_FILE_SYSTEM_UTIL_H
#include <string>
namespace Utils
{
namespace FileSystem
{
bool createDirectory(const std::string& path);
void fixSeparators(const std::string& path);
std::string escapePath(const std::string& path);
std::string getParent(const std::string& path);
std::string getFileName(const std::string& path);
std::string getStem(const std::string& path);
bool exists(const std::string& path);
} // FileSystem::
} // Utils::
#endif // ES_CORE_FILE_SYSTEM_UTIL_H

View file

@ -0,0 +1,156 @@
#include "utils/StringUtil.h"
namespace Utils
{
namespace String
{
unsigned int chars2Unicode(const std::string& _string, size_t& _cursor)
{
const char& c = _string[_cursor];
unsigned int result = '?';
if((c & 0x80) == 0) // 0xxxxxxx, one byte character
{
// 0xxxxxxx
result = ((_string[_cursor++] ) );
}
else if((c & 0xE0) == 0xC0) // 110xxxxx, two byte character
{
// 110xxxxx 10xxxxxx
result = ((_string[_cursor++] & 0x1F) << 6) |
((_string[_cursor++] & 0x3F) );
}
else if((c & 0xF0) == 0xE0) // 1110xxxx, three byte character
{
// 1110xxxx 10xxxxxx 10xxxxxx
result = ((_string[_cursor++] & 0x0F) << 12) |
((_string[_cursor++] & 0x3F) << 6) |
((_string[_cursor++] & 0x3F) );
}
else if((c & 0xF8) == 0xF0) // 11110xxx, four byte character
{
// 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
result = ((_string[_cursor++] & 0x07) << 18) |
((_string[_cursor++] & 0x3F) << 12) |
((_string[_cursor++] & 0x3F) << 6) |
((_string[_cursor++] & 0x3F) );
}
else
{
// error, invalid unicode
++_cursor;
}
return result;
} // chars2Unicode
std::string unicode2Chars(const unsigned int _unicode)
{
std::string result;
if(_unicode < 0x80) // one byte character
{
result += ((_unicode ) );
}
else if(_unicode < 0x800) // two byte character
{
result += ((_unicode >> 6) ) | 0xC0;
result += ((_unicode ) & 0x3F) | 0x80;
}
else if(_unicode < 0xFFFF) // three byte character
{
result += ((_unicode >> 12) ) | 0xE0;
result += ((_unicode >> 6) & 0x3F) | 0x80;
result += ((_unicode ) & 0x3F) | 0x80;
}
else if(_unicode <= 0x1fffff) // four byte character
{
result += ((_unicode >> 18) ) | 0xF0;
result += ((_unicode >> 12) & 0x3F) | 0x80;
result += ((_unicode >> 6) & 0x3F) | 0x80;
result += ((_unicode ) & 0x3F) | 0x80;
}
else
{
// error, invalid unicode
result += '?';
}
return result;
} // unicode2Chars
size_t nextCursor(const std::string& _string, const size_t _cursor)
{
size_t result = _cursor;
while(result < _string.length())
{
++result;
if((_string[result] & 0xC0) != 0x80) // break if current character is not 10xxxxxx
break;
}
return result;
} // nextCursor
size_t prevCursor(const std::string& _string, const size_t _cursor)
{
size_t result = _cursor;
while(result > 0)
{
--result;
if((_string[result] & 0xC0) != 0x80) // break if current character is not 10xxxxxx
break;
}
return result;
} // prevCursor
size_t moveCursor(const std::string& _string, const size_t _cursor, const int _amount)
{
size_t result = _cursor;
if(_amount > 0)
{
for(int i = 0; i < _amount; ++i)
result = nextCursor(_string, result);
}
else if(_amount < 0)
{
for(int i = _amount; i < 0; ++i)
result = prevCursor(_string, result);
}
return result;
} // moveCursor
void trim(std::string& _string)
{
if(_string.size())
{
size_t cursorB = 0;
size_t cursorE = _string.size();
while((cursorB < _string.size()) && _string[cursorB] == ' ')
++cursorB;
while((cursorE > 0) && _string[cursorE - 1] == ' ')
--cursorE;
_string.erase(_string.begin() + cursorE, _string.end());
_string.erase(_string.begin(), _string.begin() + cursorB);
}
} // trim
} // String::
} // Utils::

View file

@ -0,0 +1,22 @@
#pragma once
#ifndef ES_CORE_STRING_UTIL_H
#define ES_CORE_STRING_UTIL_H
#include <string>
namespace Utils
{
namespace String
{
unsigned int chars2Unicode(const std::string& _string, size_t& _cursor);
std::string unicode2Chars(const unsigned int _unicode);
size_t nextCursor(const std::string& _string, const size_t _cursor);
size_t prevCursor(const std::string& _string, const size_t _cursor);
size_t moveCursor(const std::string& _string, const size_t _cursor, const int _amount);
void trim(std::string& _string);
} // String::
} // Utils::
#endif // ES_CORE_STRING_UTIL_H