From f65bfe87103f58f97353a78e2e908ea0ebd28f88 Mon Sep 17 00:00:00 2001 From: Mark Vejvoda Date: Wed, 8 Jun 2011 07:18:06 +0000 Subject: [PATCH] - added some bug fixes to check if lng files are utf-8 or not and deal with it appropriately --- source/glest_game/global/core_data.cpp | 58 +- source/glest_game/global/core_data.h | 15 + source/glest_game/global/lang.cpp | 13 +- source/glest_game/global/lang.h | 8 +- source/glest_game/graphics/renderer.cpp | 172 ++++- source/glest_game/graphics/renderer.h | 10 + source/glest_game/main/main.cpp | 17 + source/glest_game/menu/main_menu.cpp | 5 +- source/shared_lib/include/graphics/font.h | 32 +- .../shared_lib/include/graphics/font_text.h | 10 +- .../include/graphics/gl/font_textFTGL.h | 5 +- .../include/graphics/gl/text_renderer_gl.h | 8 +- .../include/graphics/text_renderer.h | 2 +- .../include/platform/common/platform_common.h | 2 + source/shared_lib/include/util/string_utils.h | 615 ++++++++++++++++ source/shared_lib/include/util/utf8.h | 34 + source/shared_lib/include/util/utf8/checked.h | 327 +++++++++ source/shared_lib/include/util/utf8/core.h | 358 +++++++++ .../shared_lib/include/util/utf8/unchecked.h | 228 ++++++ source/shared_lib/sources/graphics/font.cpp | 89 ++- .../shared_lib/sources/graphics/font_text.cpp | 4 +- .../sources/graphics/gl/font_gl.cpp | 16 + .../sources/graphics/gl/font_textFTGL.cpp | 29 +- .../sources/graphics/gl/text_renderer_gl.cpp | 58 +- .../platform/common/platform_common.cpp | 28 + .../sources/platform/unix/gl_wrap.cpp | 3 + source/shared_lib/sources/util/conversion.cpp | 6 +- source/shared_lib/sources/util/properties.cpp | 309 +++++++- .../shared_lib/sources/util/string_utils.cpp | 694 ++++++++++++++++++ 29 files changed, 3072 insertions(+), 83 deletions(-) create mode 100644 source/shared_lib/include/util/string_utils.h create mode 100644 source/shared_lib/include/util/utf8.h create mode 100644 source/shared_lib/include/util/utf8/checked.h create mode 100755 source/shared_lib/include/util/utf8/core.h create mode 100755 source/shared_lib/include/util/utf8/unchecked.h create mode 100644 source/shared_lib/sources/util/string_utils.cpp diff --git a/source/glest_game/global/core_data.cpp b/source/glest_game/global/core_data.cpp index ad06b356..d9d0c1f8 100644 --- a/source/glest_game/global/core_data.cpp +++ b/source/glest_game/global/core_data.cpp @@ -133,6 +133,8 @@ void CoreData::load() { string displayFontNamePostfix = config.getString("FontDisplayPostfix"); int displayFontSize = computeFontSize(config.getInt("FontDisplayBaseSize")); + //printf("Checking if langfile has custom FontDisplayPostfix\n"); + if(lang.hasString("FontDisplayPrefix") == true) { displayFontNamePrefix = lang.get("FontDisplayPrefix"); } @@ -143,11 +145,19 @@ void CoreData::load() { displayFontSize = strToInt(lang.get("FontDisplayBaseSize")); } - string displayFontName=displayFontNamePrefix+intToStr(displayFontSize)+displayFontNamePostfix; + //printf("displayFontNamePostfix [%s]\n",displayFontNamePostfix.c_str()); + + string displayFontName = displayFontNamePrefix + intToStr(displayFontSize) + displayFontNamePostfix; displayFont= renderer.newFont(rsGlobal); displayFont->setType(displayFontName,config.getString("FontDisplay","")); displayFont->setSize(displayFontSize); + displayFont->setYOffsetFactor(config.getFloat("FontDisplayYOffsetFactor",floatToStr(FontMetrics::DEFAULT_Y_OFFSET_FACTOR).c_str())); + + displayFont3D= renderer.newFont3D(rsGlobal); + displayFont3D->setType(displayFontName,config.getString("FontDisplay","")); + displayFont3D->setSize(displayFontSize); + displayFont3D->setYOffsetFactor(config.getFloat("FontDisplayYOffsetFactor",floatToStr(FontMetrics::DEFAULT_Y_OFFSET_FACTOR).c_str())); if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] displayFontName = [%s] displayFontSize = %d\n",__FILE__,__FUNCTION__,__LINE__,displayFontName.c_str(),displayFontSize); @@ -166,10 +176,17 @@ void CoreData::load() { displayFontNameSmallSize = strToInt(lang.get("FontDisplaySmallBaseSize")); } - string displayFontNameSmall=displayFontNameSmallPrefix+intToStr(displayFontNameSmallSize)+displayFontNameSmallPostfix; + string displayFontNameSmall = displayFontNameSmallPrefix + intToStr(displayFontNameSmallSize) + displayFontNameSmallPostfix; + displayFontSmall= renderer.newFont(rsGlobal); - displayFontSmall->setType(displayFontNameSmall,config.getString("FontDisplay","")); + displayFontSmall->setType(displayFontNameSmall,config.getString("FontSmallDisplay","")); displayFontSmall->setSize(displayFontNameSmallSize); + displayFontSmall->setYOffsetFactor(config.getFloat("FontSmallDisplayYOffsetFactor",floatToStr(FontMetrics::DEFAULT_Y_OFFSET_FACTOR).c_str())); + + displayFontSmall3D= renderer.newFont3D(rsGlobal); + displayFontSmall3D->setType(displayFontNameSmall,config.getString("FontSmallDisplay","")); + displayFontSmall3D->setSize(displayFontNameSmallSize); + displayFontSmall3D->setYOffsetFactor(config.getFloat("FontSmallDisplayYOffsetFactor",floatToStr(FontMetrics::DEFAULT_Y_OFFSET_FACTOR).c_str())); if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] displayFontSmallName = [%s] displayFontSmallNameSize = %d\n",__FILE__,__FUNCTION__,__LINE__,displayFontNameSmall.c_str(),displayFontNameSmallSize); @@ -187,11 +204,19 @@ void CoreData::load() { menuFontNameNormalSize = strToInt(lang.get("FontMenuNormalBaseSize")); } - string menuFontNameNormal= menuFontNameNormalPrefix+intToStr(menuFontNameNormalSize)+menuFontNameNormalPostfix; + string menuFontNameNormal= menuFontNameNormalPrefix + intToStr(menuFontNameNormalSize) + menuFontNameNormalPostfix; + menuFontNormal= renderer.newFont(rsGlobal); menuFontNormal->setType(menuFontNameNormal,config.getString("FontMenuNormal","")); menuFontNormal->setSize(menuFontNameNormalSize); menuFontNormal->setWidth(Font::wBold); + menuFontNormal->setYOffsetFactor(config.getFloat("FontMenuNormalYOffsetFactor",floatToStr(FontMetrics::DEFAULT_Y_OFFSET_FACTOR).c_str())); + + menuFontNormal3D= renderer.newFont3D(rsGlobal); + menuFontNormal3D->setType(menuFontNameNormal,config.getString("FontMenuNormal","")); + menuFontNormal3D->setSize(menuFontNameNormalSize); + menuFontNormal3D->setWidth(Font::wBold); + menuFontNormal3D->setYOffsetFactor(config.getFloat("FontMenuNormalYOffsetFactor",floatToStr(FontMetrics::DEFAULT_Y_OFFSET_FACTOR).c_str())); if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] menuFontNormalName = [%s] menuFontNormalNameSize = %d\n",__FILE__,__FUNCTION__,__LINE__,menuFontNameNormal.c_str(),menuFontNameNormalSize); @@ -214,6 +239,12 @@ void CoreData::load() { menuFontBig= renderer.newFont(rsGlobal); menuFontBig->setType(menuFontNameBig,config.getString("FontMenuBig","")); menuFontBig->setSize(menuFontNameBigSize); + menuFontBig->setYOffsetFactor(config.getFloat("FontMenuBigYOffsetFactor",floatToStr(FontMetrics::DEFAULT_Y_OFFSET_FACTOR).c_str())); + + menuFontBig3D= renderer.newFont3D(rsGlobal); + menuFontBig3D->setType(menuFontNameBig,config.getString("FontMenuBig","")); + menuFontBig3D->setSize(menuFontNameBigSize); + menuFontBig3D->setYOffsetFactor(config.getFloat("FontMenuBigYOffsetFactor",floatToStr(FontMetrics::DEFAULT_Y_OFFSET_FACTOR).c_str())); if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] menuFontNameBig = [%s] menuFontNameBigSize = %d\n",__FILE__,__FUNCTION__,__LINE__,menuFontNameBig.c_str(),menuFontNameBigSize); @@ -231,11 +262,17 @@ void CoreData::load() { menuFontNameVeryBigSize = strToInt(lang.get("FontMenuVeryBigBaseSize")); } - string menuFontNameVeryBig= menuFontNameVeryBigPrefix+intToStr(menuFontNameVeryBigSize)+menuFontNameVeryBigPostfix; + string menuFontNameVeryBig= menuFontNameVeryBigPrefix + intToStr(menuFontNameVeryBigSize) + menuFontNameVeryBigPostfix; menuFontVeryBig= renderer.newFont(rsGlobal); - menuFontVeryBig->setType(menuFontNameVeryBig,config.getString("FontMenuBig","")); + menuFontVeryBig->setType(menuFontNameVeryBig,config.getString("FontMenuVeryBig","")); menuFontVeryBig->setSize(menuFontNameVeryBigSize); + menuFontVeryBig->setYOffsetFactor(config.getFloat("FontMenuVeryBigYOffsetFactor",floatToStr(FontMetrics::DEFAULT_Y_OFFSET_FACTOR).c_str())); + + menuFontVeryBig3D= renderer.newFont3D(rsGlobal); + menuFontVeryBig3D->setType(menuFontNameVeryBig,config.getString("FontMenuVeryBig","")); + menuFontVeryBig3D->setSize(menuFontNameVeryBigSize); + menuFontVeryBig3D->setYOffsetFactor(config.getFloat("FontMenuVeryBigYOffsetFactor",floatToStr(FontMetrics::DEFAULT_Y_OFFSET_FACTOR).c_str())); if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] menuFontNameVeryBig = [%s] menuFontNameVeryBigSize = %d\n",__FILE__,__FUNCTION__,__LINE__,menuFontNameVeryBig.c_str(),menuFontNameVeryBigSize); @@ -254,11 +291,17 @@ void CoreData::load() { consoleFontNameSize = strToInt(lang.get("FontConsoleBaseSize")); } - string consoleFontName= consoleFontNamePrefix+intToStr(consoleFontNameSize)+consoleFontNamePostfix; + string consoleFontName= consoleFontNamePrefix + intToStr(consoleFontNameSize) + consoleFontNamePostfix; consoleFont= renderer.newFont(rsGlobal); consoleFont->setType(consoleFontName,config.getString("FontConsole","")); consoleFont->setSize(consoleFontNameSize); + consoleFont->setYOffsetFactor(config.getFloat("FontConsoleYOffsetFactor",floatToStr(FontMetrics::DEFAULT_Y_OFFSET_FACTOR).c_str())); + + consoleFont3D= renderer.newFont3D(rsGlobal); + consoleFont3D->setType(consoleFontName,config.getString("FontConsole","")); + consoleFont3D->setSize(consoleFontNameSize); + consoleFont3D->setYOffsetFactor(config.getFloat("FontConsoleYOffsetFactor",floatToStr(FontMetrics::DEFAULT_Y_OFFSET_FACTOR).c_str())); if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] consoleFontName = [%s] consoleFontNameSize = %d\n",__FILE__,__FUNCTION__,__LINE__,consoleFontName.c_str(),consoleFontNameSize); @@ -273,6 +316,7 @@ void CoreData::load() { menuMusic.open(dir+"/menu/music/menu_music.ogg"); menuMusic.setNext(&menuMusic); waterSounds.resize(6); + for(int i=0; i<6; ++i){ waterSounds[i]= new StaticSound(); waterSounds[i]->load(dir+"/water_sounds/water"+intToStr(i)+".wav"); diff --git a/source/glest_game/global/core_data.h b/source/glest_game/global/core_data.h index 1a42005a..51875bd5 100644 --- a/source/glest_game/global/core_data.h +++ b/source/glest_game/global/core_data.h @@ -25,6 +25,7 @@ namespace Glest{ namespace Game{ using Shared::Graphics::Texture2D; using Shared::Graphics::Texture3D; using Shared::Graphics::Font2D; +using Shared::Graphics::Font3D; using Shared::Sound::StrSound; using Shared::Sound::StaticSound; @@ -67,6 +68,13 @@ private: Font2D *menuFontVeryBig; Font2D *consoleFont; + Font3D *displayFont3D; + Font3D *menuFontNormal3D; + Font3D *displayFontSmall3D; + Font3D *menuFontBig3D; + Font3D *menuFontVeryBig3D; + Font3D *consoleFont3D; + public: static CoreData &getInstance(); ~CoreData(); @@ -107,6 +115,13 @@ public: Font2D *getMenuFontVeryBig() const {return menuFontVeryBig;} Font2D *getConsoleFont() const {return consoleFont;} + Font3D *getDisplayFont3D() const {return displayFont3D;} + Font3D *getDisplayFontSmall3D() const {return displayFontSmall3D;} + Font3D *getMenuFontNormal3D() const {return menuFontNormal3D;} + Font3D *getMenuFontBig3D() const {return menuFontBig3D;} + Font3D *getMenuFontVeryBig3D() const {return menuFontVeryBig3D;} + Font3D *getConsoleFont3D() const {return consoleFont3D;} + private: CoreData(){}; diff --git a/source/glest_game/global/lang.cpp b/source/glest_game/global/lang.cpp index a123830c..93292445 100644 --- a/source/glest_game/global/lang.cpp +++ b/source/glest_game/global/lang.cpp @@ -18,6 +18,7 @@ #include "platform_util.h" #include "game_constants.h" #include "game_util.h" +#include "platform_common.h" #include "leak_dumper.h" using namespace std; @@ -30,7 +31,12 @@ namespace Glest{ namespace Game{ // class Lang // ===================================================== -Lang &Lang::getInstance(){ +Lang::Lang() { + language = ""; + is_utf8_language = false; +} + +Lang &Lang::getInstance() { static Lang lang; return lang; } @@ -47,9 +53,14 @@ void Lang::loadStrings(const string &language, Properties &properties, bool file if(fileMustExist == false && fileExists(languageFile) == false) { return; } + is_utf8_language = valid_utf8_file(languageFile.c_str()); properties.load(languageFile); } +bool Lang::isUTF8Language() const { + return is_utf8_language; +} + void Lang::loadScenarioStrings(const string &scenarioDir, const string &scenarioName){ if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] scenarioDir = [%s] scenarioName = [%s]\n",__FILE__,__FUNCTION__,__LINE__,scenarioDir.c_str(),scenarioName.c_str()); diff --git a/source/glest_game/global/lang.h b/source/glest_game/global/lang.h index 9bb6da96..57ca46c3 100644 --- a/source/glest_game/global/lang.h +++ b/source/glest_game/global/lang.h @@ -28,24 +28,30 @@ using Shared::Util::Properties; class Lang { private: string language; + bool is_utf8_language; + Properties strings; Properties scenarioStrings; std::map otherLanguageStrings; private: - Lang(){}; + Lang(); void loadStrings(const string &language, Properties &properties, bool fileMustExist); public: static Lang &getInstance(); + void loadStrings(const string &language); void loadScenarioStrings(const string &scenarioDir, const string &scenarioName); + string get(const string &s,string language=""); bool hasString(const string &s, string language=""); string getScenarioString(const string &s); + string getLanguage() const { return language; } bool isLanguageLocal(string compareLanguage) const; + bool isUTF8Language() const; }; }}//end namespace diff --git a/source/glest_game/graphics/renderer.cpp b/source/glest_game/graphics/renderer.cpp index c2cbb9d7..aa47dde4 100644 --- a/source/glest_game/graphics/renderer.cpp +++ b/source/glest_game/graphics/renderer.cpp @@ -159,6 +159,7 @@ Renderer::Renderer() { showDebugUILevel = debugui_fps; modelRenderer = NULL; textRenderer = NULL; + textRenderer3D = NULL; particleRenderer = NULL; saveScreenShotThread = NULL; mapSurfaceData.clear(); @@ -191,6 +192,7 @@ Renderer::Renderer() { modelRenderer= graphicsFactory->newModelRenderer(); textRenderer= graphicsFactory->newTextRenderer2D(); + textRenderer3D = graphicsFactory->newTextRenderer3D(); particleRenderer= graphicsFactory->newParticleRenderer(); //resources @@ -238,6 +240,8 @@ Renderer::~Renderer() { modelRenderer = NULL; delete textRenderer; textRenderer = NULL; + delete textRenderer3D; + textRenderer3D = NULL; delete particleRenderer; particleRenderer = NULL; @@ -579,6 +583,10 @@ Font2D *Renderer::newFont(ResourceScope rs){ return fontManager[rs]->newFont2D(); } +Font3D *Renderer::newFont3D(ResourceScope rs){ + return fontManager[rs]->newFont3D(); +} + void Renderer::manageParticleSystem(ParticleSystem *particleSystem, ResourceScope rs){ particleManager[rs]->manage(particleSystem); } @@ -687,9 +695,11 @@ void Renderer::loadGameCameraMatrix() { glMatrixMode(GL_MODELVIEW); glLoadIdentity(); - glRotatef(gameCamera->getVAng(), -1, 0, 0); - glRotatef(gameCamera->getHAng(), 0, 1, 0); - glTranslatef(-gameCamera->getPos().x, -gameCamera->getPos().y, -gameCamera->getPos().z); + if(gameCamera != NULL) { + glRotatef(gameCamera->getVAng(), -1, 0, 0); + glRotatef(gameCamera->getHAng(), 0, 1, 0); + glTranslatef(-gameCamera->getPos().x, -gameCamera->getPos().y, -gameCamera->getPos().z); + } } void Renderer::loadCameraMatrix(const Camera *camera) { @@ -1229,7 +1239,43 @@ Vec2i computeCenteredPos(const string &text, Font2D *font, int x, int y) { return textPos; } -void Renderer::renderText(const string &text, Font2D *font, float alpha, int x, int y, bool centered){ +Vec2i computeCenteredPos(const string &text, Font3D *font, int x, int y) { + if(font == NULL) { + throw runtime_error("font == NULL"); + } + const Metrics &metrics= Metrics::getInstance(); + FontMetrics *fontMetrics= font->getMetrics(); + + if(fontMetrics == NULL) { + throw runtime_error("fontMetrics == NULL"); + } + + int virtualX = (fontMetrics->getTextWidth(text) > 0 ? static_cast(fontMetrics->getTextWidth(text) / 2.f) : 5); + int virtualY = (fontMetrics->getHeight() > 0 ? static_cast(fontMetrics->getHeight() / 2.f) : 5); + + Vec2i textPos( + x-metrics.toVirtualX(virtualX), + y-metrics.toVirtualY(virtualY)); + + return textPos; +} + +void Renderer::renderText3D(const string &text, Font3D *font, float alpha, int x, int y, bool centered) { + glPushAttrib(GL_ENABLE_BIT | GL_CURRENT_BIT); + glEnable(GL_BLEND); + glColor4fv(Vec4f(1.f, 1.f, 1.f, alpha).ptr()); + + Vec2i pos= centered? computeCenteredPos(text, font, x, y): Vec2i(x, y); + //Vec2i pos= Vec2i(x, y); + + textRenderer3D->begin(font); + textRenderer3D->render(text, pos.x, pos.y, font->getSize()); + textRenderer3D->end(); + + glPopAttrib(); +} + +void Renderer::renderText(const string &text, Font2D *font, float alpha, int x, int y, bool centered) { glPushAttrib(GL_ENABLE_BIT | GL_CURRENT_BIT); glEnable(GL_BLEND); glColor4fv(Vec4f(1.f, 1.f, 1.f, alpha).ptr()); @@ -1243,6 +1289,19 @@ void Renderer::renderText(const string &text, Font2D *font, float alpha, int x, glPopAttrib(); } +void Renderer::renderText3D(const string &text, Font3D *font, const Vec3f &color, int x, int y, bool centered) { + glPushAttrib(GL_CURRENT_BIT); + glColor3fv(color.ptr()); + + Vec2i pos= centered? computeCenteredPos(text, font, x, y): Vec2i(x, y); + + textRenderer3D->begin(font); + textRenderer3D->render(text, pos.x, pos.y); + textRenderer3D->end(); + + glPopAttrib(); +} + void Renderer::renderText(const string &text, Font2D *font, const Vec3f &color, int x, int y, bool centered){ glPushAttrib(GL_CURRENT_BIT); glColor3fv(color.ptr()); @@ -1256,6 +1315,20 @@ void Renderer::renderText(const string &text, Font2D *font, const Vec3f &color, glPopAttrib(); } +void Renderer::renderText3D(const string &text, Font3D *font, const Vec4f &color, int x, int y, bool centered) { + glPushAttrib(GL_ENABLE_BIT | GL_CURRENT_BIT); + glEnable(GL_BLEND); + glColor4fv(color.ptr()); + + Vec2i pos= centered? computeCenteredPos(text, font, x, y): Vec2i(x, y); + + textRenderer3D->begin(font); + textRenderer3D->render(text, pos.x, pos.y); + textRenderer3D->end(); + + glPopAttrib(); +} + void Renderer::renderText(const string &text, Font2D *font, const Vec4f &color, int x, int y, bool centered){ glPushAttrib(GL_ENABLE_BIT | GL_CURRENT_BIT); glEnable(GL_BLEND); @@ -1270,6 +1343,29 @@ void Renderer::renderText(const string &text, Font2D *font, const Vec4f &color, glPopAttrib(); } +void Renderer::renderTextShadow3D(const string &text, Font3D *font,const Vec4f &color, int x, int y, bool centered) { + if(font == NULL) { + throw runtime_error("font == NULL"); + } + + glPushAttrib(GL_CURRENT_BIT); + + Vec2i pos= centered? computeCenteredPos(text, font, x, y): Vec2i(x, y); + + textRenderer3D->begin(font); + if(color.w < 0.5) { + glColor3f(0.0f, 0.0f, 0.0f); + + textRenderer3D->render(text, pos.x-1.0f, pos.y-1.0f); + } + glColor3f(color.x,color.y,color.z); + + textRenderer3D->render(text, pos.x, pos.y); + textRenderer3D->end(); + + glPopAttrib(); +} + void Renderer::renderTextShadow(const string &text, Font2D *font,const Vec4f &color, int x, int y, bool centered){ if(font == NULL) { throw runtime_error("font == NULL"); @@ -1280,11 +1376,13 @@ void Renderer::renderTextShadow(const string &text, Font2D *font,const Vec4f &co Vec2i pos= centered? computeCenteredPos(text, font, x, y): Vec2i(x, y); textRenderer->begin(font); - if(color.w<0.5) { + if(color.w < 0.5) { glColor3f(0.0f, 0.0f, 0.0f); + textRenderer->render(text, pos.x-1.0f, pos.y-1.0f); } glColor3f(color.x,color.y,color.z); + textRenderer->render(text, pos.x, pos.y); textRenderer->end(); @@ -1460,9 +1558,16 @@ void Renderer::renderButton(GraphicButton *button, const Vec4f *fontColorOverrid Vec2i textPos= Vec2i(x+w/2, y+h/2); if(button->getEditable()) { + Font2D *font = button->getFont(); + //Font3D *font3d = ConvertFont2DTo3D(button->getFont()); renderText( - button->getText(), button->getFont(), color, + button->getText(), font, color, x+w/2, y+h/2, true); + //delete font3d; + +// renderText( +// button->getText(), button->getFont(), color, +// x+w/2, y+h/2, true); } else { renderText( @@ -4676,6 +4781,60 @@ void Renderer::renderArrow(const Vec3f &pos1, const Vec3f &pos2, glEnd(); } +void Renderer::renderProgressBar3D(int size, int x, int y, Font3D *font, int customWidth, + string prefixLabel,bool centeredText) { + + int currentSize = size; + int maxSize = maxProgressBar; + string renderText = intToStr(static_cast(size)) + "%"; + if(customWidth > 0) { + if(size > 0) { + currentSize = (int)((double)customWidth * ((double)size / 100.0)); + } + maxSize = customWidth; + if(maxSize <= 0) { + maxSize = maxProgressBar; + } + } + if(prefixLabel != "") { + renderText = prefixLabel + renderText; + } + + //bar + glBegin(GL_QUADS); + glColor4fv(progressBarFront2.ptr()); + glVertex2i(x, y); + glVertex2i(x, y+10); + glColor4fv(progressBarFront1.ptr()); + glVertex2i(x + currentSize, y+10); + glVertex2i(x + currentSize, y); + glEnd(); + + //transp bar + glEnable(GL_BLEND); + glBegin(GL_QUADS); + glColor4fv(progressBarBack2.ptr()); + glVertex2i(x + currentSize, y); + glVertex2i(x + currentSize, y+10); + glColor4fv(progressBarBack1.ptr()); + glVertex2i(x + maxSize, y+10); + glVertex2i(x + maxSize, y); + glEnd(); + glDisable(GL_BLEND); + + //text + glColor3fv(defColor.ptr()); + + textRenderer3D->begin(font); + if(centeredText == true) { + textRenderer3D->render(renderText.c_str(), x + maxSize / 2, y, centeredText); + } + else { + textRenderer3D->render(renderText.c_str(), x, y, centeredText); + } + textRenderer3D->end(); +} + void Renderer::renderProgressBar(int size, int x, int y, Font2D *font, int customWidth, string prefixLabel,bool centeredText) { @@ -4719,6 +4878,7 @@ void Renderer::renderProgressBar(int size, int x, int y, Font2D *font, int custo //text glColor3fv(defColor.ptr()); + textRenderer->begin(font); if(centeredText == true) { textRenderer->render(renderText.c_str(), x + maxSize / 2, y, centeredText); diff --git a/source/glest_game/graphics/renderer.h b/source/glest_game/graphics/renderer.h index 101cc693..14f0bd33 100644 --- a/source/glest_game/graphics/renderer.h +++ b/source/glest_game/graphics/renderer.h @@ -221,6 +221,7 @@ private: //renderers ModelRenderer *modelRenderer; TextRenderer2D *textRenderer; + TextRenderer3D *textRenderer3D; ParticleRenderer *particleRenderer; //texture managers @@ -322,6 +323,8 @@ public: Texture2D *newTexture2D(ResourceScope rs); Texture3D *newTexture3D(ResourceScope rs); Font2D *newFont(ResourceScope rs); + Font3D *newFont3D(ResourceScope rs); + TextRenderer2D *getTextRenderer() const {return textRenderer;} void manageParticleSystem(ParticleSystem *particleSystem, ResourceScope rs); void cleanupParticleSystems(vector &particleSystems,ResourceScope rs); @@ -352,6 +355,13 @@ public: void renderText(const string &text, Font2D *font, const Vec4f &color, int x, int y, bool centered=false); void renderTextShadow(const string &text, Font2D *font,const Vec4f &color, int x, int y, bool centered= false); + void renderText3D(const string &text, Font3D *font, float alpha, int x, int y, bool centered); + void renderText3D(const string &text, Font3D *font, const Vec3f &color, int x, int y, bool centered); + void renderText3D(const string &text, Font3D *font, const Vec4f &color, int x, int y, bool centered); + void renderTextShadow3D(const string &text, Font3D *font,const Vec4f &color, int x, int y, bool centered); + void renderProgressBar3D(int size, int x, int y, Font3D *font, int customWidth, + string prefixLabel,bool centeredText); + //components void renderLabel(GraphicLabel *label); void renderLabel(GraphicLabel *label,const Vec3f *color); diff --git a/source/glest_game/main/main.cpp b/source/glest_game/main/main.cpp index e1d2f370..bd087345 100644 --- a/source/glest_game/main/main.cpp +++ b/source/glest_game/main/main.cpp @@ -125,6 +125,7 @@ const char *GAME_ARGS[] = { "--disable-backtrace", "--disable-vbo", "--disable-sound", + "--enable-legacyfonts", "--verbose" }; @@ -159,6 +160,7 @@ enum GAME_ARG_TYPE { GAME_ARG_DISABLE_BACKTRACE, GAME_ARG_DISABLE_VBO, GAME_ARG_DISABLE_SOUND, + GAME_ARG_ENABLE_LEGACYFONTS, GAME_ARG_VERBOSE_MODE }; @@ -1059,6 +1061,8 @@ void printParameterHelp(const char *argv0, bool foundInvalidArgs) { printf("\n%s\t\t\tdisables trying to use Vertex Buffer Objects.",GAME_ARGS[GAME_ARG_DISABLE_VBO]); printf("\n%s\t\t\tdisables the sound system.",GAME_ARGS[GAME_ARG_DISABLE_SOUND]); + printf("\n%s\t\t\tenables using the legacy font system.",GAME_ARGS[GAME_ARG_ENABLE_LEGACYFONTS]); + printf("\n%s\t\t\tdisplays verbose information in the console.",GAME_ARGS[GAME_ARG_VERBOSE_MODE]); printf("\n\n"); @@ -2445,6 +2449,11 @@ int glestMain(int argc, char** argv) { TextureGl::setEnableATIHacks(enableATIHacks); } + if(config.getBool("EnableLegacyFonts","false") == true || hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_ENABLE_LEGACYFONTS]) == true) { + Font::forceLegacyFonts = true; + if(SystemFlags::VERBOSE_MODE_ENABLED) printf("**WARNING** Forcing Legacy Fonts Enabled\n"); + } + // Set some statics based on ini entries SystemFlags::ENABLE_THREADED_LOGGING = config.getBool("ThreadedLogging","true"); FontGl::setDefault_fontType(config.getString("DefaultFont",FontGl::getDefault_fontType().c_str())); @@ -2573,6 +2582,10 @@ int glestMain(int argc, char** argv) { #endif } + if( lang.hasString("FONT_YOFFSET_FACTOR")) { + FontMetrics::DEFAULT_Y_OFFSET_FACTOR = strToFloat(lang.get("FONT_YOFFSET_FACTOR")); + } + #if defined(WIN32) // Win32 overrides for fonts (just in case they must be different) if( lang.hasString("FONT_CHARCOUNT_WINDOWS")) { @@ -2598,6 +2611,10 @@ int glestMain(int argc, char** argv) { _putenv(newEnvValue.c_str()); } + if( lang.hasString("FONT_YOFFSET_FACTOR_WINDOWS")) { + FontMetrics::DEFAULT_Y_OFFSET_FACTOR = strToFloat(lang.get("FONT_YOFFSET_FACTOR_WINDOWS")); + } + // end win32 #endif SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] Font::charCount = %d, Font::fontTypeName [%s] Shared::Platform::charSet = %d, Font::fontIsMultibyte = %d\n",__FILE__,__FUNCTION__,__LINE__,Font::charCount,Font::fontTypeName.c_str(),Shared::Platform::charSet,Font::fontIsMultibyte); diff --git a/source/glest_game/menu/main_menu.cpp b/source/glest_game/menu/main_menu.cpp index 05ededf0..44a6a889 100644 --- a/source/glest_game/menu/main_menu.cpp +++ b/source/glest_game/menu/main_menu.cpp @@ -82,12 +82,12 @@ MainMenu::~MainMenu() { if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s %d]\n",__FILE__,__FUNCTION__,__LINE__); } -void MainMenu::init(){ +void MainMenu::init() { Renderer::getInstance().initMenu(this); } //asynchronus render update -void MainMenu::render(){ +void MainMenu::render() { Config &config= Config::getInstance(); Renderer &renderer= Renderer::getInstance(); @@ -110,7 +110,6 @@ void MainMenu::render(){ state->render(); renderer.renderMouse2d(mouseX, mouseY, mouse2dAnim); - //if(config.getBool("DebugMode")){ if(renderer.getShowDebugUI() == true) { renderer.renderText( "FPS: " + intToStr(lastFps), diff --git a/source/shared_lib/include/graphics/font.h b/source/shared_lib/include/graphics/font.h index 2faefa53..a0ddef90 100644 --- a/source/shared_lib/include/graphics/font.h +++ b/source/shared_lib/include/graphics/font.h @@ -13,11 +13,12 @@ #define _SHARED_GRAPHICS_FONT_H_ #include +#include "font_text.h" #include "leak_dumper.h" using std::string; -class Text; +//class Text; namespace Shared { namespace Graphics { @@ -26,15 +27,23 @@ namespace Shared { namespace Graphics { // ===================================================== class FontMetrics { + private: float *widths; float height; + + float yOffsetFactor; Text *textHandler; public: + static float DEFAULT_Y_OFFSET_FACTOR; + FontMetrics(Text *textHandler=NULL); ~FontMetrics(); + void setYOffsetFactor(float yOffsetFactor); + float getYOffsetFactor() const; + void setTextHandler(Text *textHandler); Text * getTextHandler(); @@ -54,6 +63,7 @@ public: static int charCount; static std::string fontTypeName; static bool fontIsMultibyte; + static bool forceLegacyFonts; public: enum Width { @@ -65,13 +75,14 @@ protected: string type; int width; bool inited; + int size; FontMetrics metrics; Text *textHandler; public: //constructor & destructor - Font(); + Font(FontTextHandlerType type); virtual ~Font(); virtual void init()=0; virtual void end()=0; @@ -81,10 +92,16 @@ public: int getWidth() const; FontMetrics *getMetrics() {return &metrics;} Text * getTextHandler() {return textHandler;} + float getYOffsetFactor() const; + string getType() const; //set + void setYOffsetFactor(float yOffsetFactor); void setType(string typeX11, string typeGeneric); void setWidth(int width); + + int getSize() const; + void setSize(int size); }; // ===================================================== @@ -93,14 +110,11 @@ public: class Font2D: public Font { protected: - int size; + //int size; public: - Font2D(); + Font2D(FontTextHandlerType type=ftht_2D); virtual ~Font2D() {}; - - int getSize() const; - void setSize(int size); }; // ===================================================== @@ -112,13 +126,15 @@ protected: float depth; public: - Font3D(); + Font3D(FontTextHandlerType type=ftht_3D); virtual ~Font3D() {}; float getDepth() const {return depth;} void setDepth(float depth) {this->depth= depth;} }; +Font3D *ConvertFont2DTo3D(Font2D *font); + }}//end namespace #endif diff --git a/source/shared_lib/include/graphics/font_text.h b/source/shared_lib/include/graphics/font_text.h index 04d71d67..668178ef 100644 --- a/source/shared_lib/include/graphics/font_text.h +++ b/source/shared_lib/include/graphics/font_text.h @@ -15,17 +15,25 @@ #include using std::string; + +enum FontTextHandlerType { + ftht_2D, + ftht_3D +}; + /** * Base class upon which all text rendering calls are made. */ //==================================================================== class Text { +protected: + FontTextHandlerType type; public: static std::string DEFAULT_FONT_PATH; - Text(); + Text(FontTextHandlerType type); virtual ~Text(); virtual void init(string fontName, int fontSize); diff --git a/source/shared_lib/include/graphics/gl/font_textFTGL.h b/source/shared_lib/include/graphics/gl/font_textFTGL.h index 1fb54109..f6d95fad 100644 --- a/source/shared_lib/include/graphics/gl/font_textFTGL.h +++ b/source/shared_lib/include/graphics/gl/font_textFTGL.h @@ -18,7 +18,8 @@ #include "font_text.h" -namespace Shared{ namespace Graphics{ namespace Gl{ +namespace Shared { namespace Graphics { namespace Gl { + /** * Use FTGL for rendering text in OpenGL */ @@ -27,7 +28,7 @@ class TextFTGL : public Text { public: - TextFTGL(); + TextFTGL(FontTextHandlerType type); virtual ~TextFTGL(); virtual void init(string fontName, int fontSize); diff --git a/source/shared_lib/include/graphics/gl/text_renderer_gl.h b/source/shared_lib/include/graphics/gl/text_renderer_gl.h index e9f9bdba..b4055265 100644 --- a/source/shared_lib/include/graphics/gl/text_renderer_gl.h +++ b/source/shared_lib/include/graphics/gl/text_renderer_gl.h @@ -19,6 +19,7 @@ namespace Shared { namespace Graphics { namespace Gl { class Font2DGl; class Font3DGl; +class TextRenderer3DGl; // ===================================================== // class TextRenderer2DGl @@ -29,6 +30,9 @@ private: Font2DGl *font; bool rendering; + //Font3DGl *font3D; + //TextRenderer3DGl *tester; + public: TextRenderer2DGl(); virtual ~TextRenderer2DGl(); @@ -42,7 +46,7 @@ public: // class TextRenderer3DGl // ===================================================== -class TextRenderer3DGl: public TextRenderer3D{ +class TextRenderer3DGl: public TextRenderer3D { private: Font3DGl *font; bool rendering; @@ -52,7 +56,7 @@ public: virtual ~TextRenderer3DGl(); virtual void begin(Font3D *font); - virtual void render(const string &text, float x, float y, float size, bool centered); + virtual void render(const string &text, float x, float y, bool centered); virtual void end(); }; diff --git a/source/shared_lib/include/graphics/text_renderer.h b/source/shared_lib/include/graphics/text_renderer.h index d7a6ee25..54a660fa 100644 --- a/source/shared_lib/include/graphics/text_renderer.h +++ b/source/shared_lib/include/graphics/text_renderer.h @@ -43,7 +43,7 @@ public: virtual ~TextRenderer3D(){}; virtual void begin(Font3D *font)= 0; - virtual void render(const string &text, float x, float y, float size, bool centered= false)= 0; + virtual void render(const string &text, float x, float y, bool centered= false)= 0; virtual void end()= 0; }; diff --git a/source/shared_lib/include/platform/common/platform_common.h b/source/shared_lib/include/platform/common/platform_common.h index 9f9ed1a5..b037483d 100644 --- a/source/shared_lib/include/platform/common/platform_common.h +++ b/source/shared_lib/include/platform/common/platform_common.h @@ -213,6 +213,8 @@ string getFullFileArchiveExtractCommand(string fileArchiveExtractCommand, bool executeShellCommand(string cmd,int expectedResult=IGNORE_CMD_RESULT_VALUE); string executable_path(string exeName,bool includeExeNameInPath=false); +bool valid_utf8_file(const char* file_name); + class ValueCheckerVault { protected: diff --git a/source/shared_lib/include/util/string_utils.h b/source/shared_lib/include/util/string_utils.h new file mode 100644 index 00000000..d92968d3 --- /dev/null +++ b/source/shared_lib/include/util/string_utils.h @@ -0,0 +1,615 @@ +/* TA3D, a remake of Total Annihilation + Copyright (C) 2005 Roland BROCHARD + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA*/ + +#ifndef _SHARED_UTIL_W_STRING_H__ +#define _SHARED_UTIL_W_STRING_H__ + +# include +# include +# include +# include +# include +#include "types.h" + +/*! +** \brief Force the Use of the Boost functions +*/ +# define TA3D_USE_BOOST 0 + + + +//! \name Macros for Shared::Util::String +//@{ + +//! Macro to append some data to the string +# define TA3D_WSTR_APPEND std::stringstream out; \ + out << v; \ + append(out.str());\ + return *this + +//! Macro to convert the string into a given type +# define TA3D_WSTR_CAST_OP(X) X v; \ + fromString(v, *this); \ + return v; + +//! Macro to append the value of a boolean (true -> "true", false -> "false") +# define TA3D_WSTR_APPEND_BOOL(X) append(X ? "true" : "false") + +//@} // Macros for Shared::Util::String + + +# define TA3D_WSTR_SEPARATORS " \t\r\n" + +using namespace Shared::Platform; + +namespace Shared { namespace Util { + + /*! \class String + ** \brief A String implementation for `TA3D` + ** + ** \code + ** Shared::Util::String a("abcd"); + ** std::cout << a << std::endl; // display: `abcd` + ** Shared::Util::String b(10 + 2); + ** std::cout << b << std::endl; // display: `12` + ** Shared::Util::String c(10.3); + ** std::cout << c << std::endl; // display: `10.3` + ** + ** // The same with the operator `<<` + ** Shared::Util::String d; + ** d << "Value : " << 42; + ** std::cout << d << std::endl; // display: `Value : 42` + ** \endcode + ** + ** Here is an example to show when to use static methods : + ** \code + ** Shared::Util::String s = "HelLo wOrLd"; + ** std::cout << Shared::Util::String::ToLower(s) << std::endl; // `hello world` + ** std::cout << s << std::endl; // `HelLo wOrLd` + ** std::cout << s.toLower() << std::endl; // `hello world` + ** std::cout << s << std::endl; // `hello world` + ** \endcode + */ + class String : public std::string + { + public: + //! A String list + typedef std::list List; + //! A String vector + typedef std::vector Vector; + + //! Char Case + enum CharCase + { + //! The string should remain untouched + soCaseSensitive, + //! The string should be converted to lowercase + soIgnoreCase + }; + + public: + /*! + ** \brief Copy then Convert the case (lower case) of characters in the string using the UTF8 charset + ** \param s The string to convert + ** \return A new string + */ + static String ToLower(const char* s) {return String(s).toLower();} + /*! + ** \brief Copy then Convert the case (lower case) of characters in the string using the UTF8 charset + ** \param s The string to convert + ** \return A new string + */ + static String ToLower(const wchar_t* s) {return String(s).toLower();} + /*! + ** \brief Copy then Convert the case (lower case) of characters in the string using the UTF8 charset + ** \param s The string to convert + ** \return A new string + */ + static String ToLower(const String& s) {return String(s).toLower();} + + /*! + ** \brief Copy then Convert the case (upper case) of characters in the string using the UTF8 charset + ** \param s The string to convert + ** \return A new string + */ + static String ToUpper(const char* s) {return String(s).toUpper();} + /*! + ** \brief Copy then Convert the case (upper case) of characters in the string using the UTF8 charset + ** \param s The string to convert + ** \return A new string + */ + static String ToUpper(const wchar_t* s) {return String(s).toUpper();} + /*! + ** \brief Copy then Convert the case (upper case) of characters in the string using the UTF8 charset + ** \param s The string to convert + ** \return A new string + */ + static String ToUpper(const String& s) {return String(s).toUpper();} + + /*! + ** \brief Remove trailing and leading spaces + ** \param s The string to convert + ** \param trimChars The chars to remove + ** \return A new string + */ + static String Trim(const char* s, const String& trimChars = TA3D_WSTR_SEPARATORS) {return String(s).trim(trimChars);} + /*! + ** \brief Remove trailing and leading spaces + ** \param s The string to convert + ** \param trimChars The chars to remove + ** \return A new string + */ + static String Trim(const wchar_t* s, const String& trimChars = TA3D_WSTR_SEPARATORS) {return String(s).trim(trimChars);} + /*! + ** \brief Remove trailing and leading spaces + ** \param s The string to convert + ** \param trimChars The chars to remove + ** \return A new string + */ + static String Trim(const String& s, const String& trimChars = TA3D_WSTR_SEPARATORS) {return String(s).trim(trimChars);} + + /*! + ** \brief Convert all antislashes into slashes + ** \param s The string to convert + ** \return A new string + */ + static String ConvertAntiSlashesIntoSlashes(const String& s) {return String(s).convertAntiSlashesIntoSlashes();} + + /*! + ** \brief Convert all slashes into antislashes + ** \param s The string to convert + ** \return A new string + */ + static String ConvertSlashesIntoAntiSlashes(const String& s) {return String(s).convertSlashesIntoAntiSlashes();} + + /*! + ** \brief Extract the key and its value from a string (mainly provided by TDF files) + ** + ** \param s A line (ex: ` category=core vtol ctrl_v level1 weapon notsub ;`) + ** \param[out] key The key that has been found + ** \param[out] value The associated value + ** \param chcase The key will be converted to lowercase if equals to `soIgnoreCase` + ** + ** \code + ** String k, v; + ** + ** // -> k='category' + ** // -> v='core vtol ctrl_v level1 weapon notsub' + ** String::ToKeyValue(" category=core vtol ctrl_v level1 weapon notsub ;", k, v) + ** + ** // -> k='foo' + ** // -> v='bar' + ** String::ToKeyValue(" foo = bar ; "); + ** + ** // -> k='}' v='' + ** String::ToKeyValue(" } ", k, v); + ** + ** // -> k='[' v='Example of Section' + ** String::ToKeyValue(" [Example of Section] ", k, v); + ** + ** // -> k='foo' v='bar' + ** String::ToKeyValue(" foo=bar; // comment", k, v); + ** + ** // -> k='foo' v='bar' + ** String::ToKeyValue(" foo=bar; // comments here; ", k, v); + ** \endcode + */ + static void ToKeyValue(const String& s, String& key, String& value, const enum CharCase chcase = soCaseSensitive); + + /*! + ** \brief Find the index of a string in a vector + ** \param l The vector + ** \param s The string to look for + ** \return The index of the string found, -1 otherwise + */ + static int FindInList(const String::Vector& l, const char* s); + static int FindInList(const String::Vector& l, const String& s); + + + /*! + ** \brief Convert a string from ASCII to UTF8 + ** \param s The string to convert + ** \return A new Null-terminated String (must be deleted with the keyword `delete[]`), even if s is NULL + */ + static char* ConvertToUTF8(const char* s); + /*! + ** \brief Convert a string from ASCII to UTF8 + ** \param s The string to convert + ** \param len The length of the string + ** \param[out] The new size + ** \return A new Null-terminated String (must be deleted with the keyword `delete[]`), even if s is NULL + */ + static char* ConvertToUTF8(const char* s, const uint32 len); + static char* ConvertToUTF8(const char* s, const uint32 len, uint32& newSize); + + /*! + ** \brief Convert a string from ASCII to UTF8 + ** \param s The string to convert + ** \return A new String + */ + static String ConvertToUTF8(const String& s); + + /*! + ** \brief Formatted string + ** \param format The format of the new string + ** \return A new string + */ + static String Format(const String& f, ...); + static String Format(const char* f, ...); + + public: + //! \name Constructors and Destructor + //@{ + //! Default constructor + String() :std::string() {} + //! Constructor by copy + String(const String& v, size_type pos = 0, size_type n = npos) :std::string(v, pos, n) {} + //! Constructor with a default value from a std::string + String(const std::string& v) :std::string(v) {} + //! Constructor with a default value from a wide string (wchar_t*) + String(const wchar_t* v) :std::string() {if (v) *this << v;} + //! Constructor with a default value from a string (char*) + String(const char* v) :std::string() { if (v) append(v); } + //! Constructor with a default value from a string (char*) and a length + String(const char* v, String::size_type n) :std::string(v, n) {} + //! Constructor with a default value from a single char + String(const char v) :std::string() {*this += v;} + //! Constructor with a default value from an int (8 bits) + String(const int8_t v) :std::string() {*this << v;} + //! Constructor with a default value from an int (16 bits) + String(const int16_t v) :std::string() {*this << v;} + //! Constructor with a default value from an int (32 bits) + String(const int32_t v) :std::string() {*this << v;} + //! Constructor with a default value from an int (64 bits) + String(const int64_t v) :std::string() {*this << v;} + //! Constructor with a default value from an unsigned int (8 bits) + String(const uint8_t v) :std::string() {*this << v;} + //! Constructor with a default value from an unsigned int (16 bits) + String(const uint16_t v) :std::string() {*this << v;} + //! Constructor with a default value from an unsigned int (32 bits) + String(const uint32_t v) :std::string() {*this << v;} + //! Constructor with a default value from an unsigned int (64 bits) + String(const uint64_t v) :std::string() {*this << v;} + //! Constructor with a default value from a float + String(const float v) :std::string() {*this << v;} + //! Constructor with a default value from a double + String(const double v) :std::string() {*this << v;} + //! Destructor + ~String() {} + //@} + + + //! \name The operator `<<` + //@{ + //! Append a string (char*) + String& operator << (const char* v) {append(v);return *this;} + //! Append a string (stl) + String& operator << (const std::string& v) {append(v);return *this;} + //! Append a string (Shared::Util::String) + String& operator << (const String& v) {append(v);return *this;} + //! Append a single char + String& operator << (const char v) {*(static_cast(this)) += v; return *this;} + //! Append a wide string (wchar_t*) + String& operator << (const wchar_t* v); + //! Append an int (8 bits) + String& operator << (const int8_t v) {TA3D_WSTR_APPEND;} + //! Append an unsigned int (8 bits) + String& operator << (const uint8_t v) {TA3D_WSTR_APPEND;} + //! Append an int (16 bits) + String& operator << (const int16_t v) {TA3D_WSTR_APPEND;} + //! Append an unsigned int (16 bits) + String& operator << (const uint16_t v) {TA3D_WSTR_APPEND;} + //! Append an int (32 bits) + String& operator << (const int32_t v) {TA3D_WSTR_APPEND;} + //! Append an unsigned int (32 bits) + String& operator << (const uint32_t v) {TA3D_WSTR_APPEND;} + //! Append an int (64 bits) + String& operator << (const int64_t v) {TA3D_WSTR_APPEND;} + //! Append an unsigned int (64 bits) + String& operator << (const uint64_t v) {TA3D_WSTR_APPEND;} + //! Convert then Append a float + String& operator << (const float v) {TA3D_WSTR_APPEND;} + //! Convert then Append a double + String& operator << (const double v) {TA3D_WSTR_APPEND;} + //! Convert then Append a boolean (will be converted into "true" or "false") + String& operator << (const bool v) {TA3D_WSTR_APPEND_BOOL(v);return *this;} + //@} + + + //! \name Convertions + //@{ + //! Convert this string into an int (8 bits) + int8_t toInt8() const {TA3D_WSTR_CAST_OP(int8_t);} + //! Convert this string into an int (16 bits) + int16_t toInt16() const {TA3D_WSTR_CAST_OP(int16_t);} + //! Convert this string into an int (32 bits) + int32_t toInt32() const {TA3D_WSTR_CAST_OP(int32_t);} + //! Convert this string into an int (64 bits) + int64_t toInt64() const {TA3D_WSTR_CAST_OP(int64_t);} + //! Convert this string into an unsigned int (8 bits) + uint8_t toUInt8() const {TA3D_WSTR_CAST_OP(uint8_t);} + //! Convert this string into an unsigned int (16 bits) + uint16_t toUInt16() const {TA3D_WSTR_CAST_OP(uint16_t);} + //! Convert this string into an unsigned int (32 bits) + uint32_t toUInt32() const {TA3D_WSTR_CAST_OP(uint32_t);} + //! Convert this string into an unsigned int (64 bits) + uint64_t toUInt64() const {TA3D_WSTR_CAST_OP(uint64_t);} + //! Convert this string into a float + float toFloat() const {TA3D_WSTR_CAST_OP(float);} + //! Convert this string into a float with a default value if empty + float toFloat(const float def) const {if (empty()) return def;TA3D_WSTR_CAST_OP(float);} + //! Convert this string into a double + double toDouble() const {TA3D_WSTR_CAST_OP(double);} + //! Convert this string into a bool (true if the lower case value is equals to "true", "1" or "on") + bool toBool() const; + + //! \name The operator `+=` (with the same abilities than the operator `<<`) + //@{ + //! Append a string (char*) + String& operator += (const char* v) {append(v); return *this;} + //! Append a string (stl) + String& operator += (const std::string& v) {append(v); return *this;} + //! Append a string (Shared::Util::String) + String& operator += (const Shared::Util::String& v) {append(v); return *this; } + //! Append a single char + String& operator += (const char v) {*(static_cast(this)) += (char)v; return *this;} + //! Append a wide string (wchar_t*) + String& operator += (const wchar_t* v) {*this << v; return *this;} + //! Append an int (8 bits) + String& operator += (const int8_t v) {*this << v; return *this;} + //! Append an unsigned int (8 bits) + String& operator += (const uint8_t v) {*this << v; return *this;} + //! Append an int (16 bits) + String& operator += (const int16_t v) {*this << v; return *this; } + //! Append an unsigned int (16 bits) + String& operator += (const uint16_t v) {*this << v; return *this; } + //! Append an int (32 bits) + String& operator += (const int32_t v) {*this << v; return *this; } + //! Append an unsigned int (32 bits) + String& operator += (const uint32_t v) {*this << v; return *this; } + //! Append an int (64 bits) + String& operator += (const int64_t v) {*this << v; return *this; } + //! Append an unsigned int (64 bits) + String& operator += (const uint64_t v) {*this << v; return *this; } + //! Convert then Append a float + String& operator += (const float v) {*this << v; return *this; } + //! Convert then Append a double + String& operator += (const double v) {*this << v; return *this; } + //! Convert then Append a boolean (will be converted into "true" or "false") + String& operator += (const bool v) {TA3D_WSTR_APPEND_BOOL(v); return *this; } + //@} + + + //! \name The operator `+` + //@{ + //! Create a new String from the concatenation of *this and a string + const String operator + (const String& rhs) { return String(*this) += rhs; } + //! Create a new String from the concatenation of *this and a char + const String operator + (const char rhs) { return String(*this) += rhs; } + //! Create a new String from the concatenation of *this and a widechar + const String operator + (const wchar_t rhs) { return String(*this) += rhs; } + //! Create a new String from the concatenation of *this and a const char* + const String operator + (const char* rhs) { return String(*this) += rhs; } + //! Create a new String from the concatenation of *this and a wide string + const String operator + (const wchar_t* rhs) { return String(*this) += rhs; } + //! Create a new String from the concatenation of *this and a signed int (8 bits) + const String operator + (const int8_t rhs) { return String(*this) += rhs; } + //! Create a new String from the concatenation of *this and a signed int (16 bits) + const String operator + (const int16_t rhs) { return String(*this) += rhs; } + //! Create a new String from the concatenation of *this and a signed int (32 bits) + const String operator + (const int32_t rhs) { return String(*this) += rhs; } + //! Create a new String from the concatenation of *this and a signed int (64 bits) + const String operator + (const int64_t rhs) { return String(*this) += rhs; } + //! Create a new String from the concatenation of *this and an unsigned int (8 bits) + const String operator + (const uint8_t rhs) { return String(*this) += rhs; } + //! Create a new String from the concatenation of *this and an unsigned int (16 bits) + const String operator + (const uint16_t rhs) { return String(*this) += rhs; } + //! Create a new String from the concatenation of *this and an unsigned int (32 bits) + const String operator + (const uint32_t rhs) { return String(*this) += rhs; } + //! Create a new String from the concatenation of *this and an unsigned int (64 bits) + const String operator + (const uint64_t rhs) { return String(*this) += rhs; } + //! Create a new String from the concatenation of *this and a float + const String operator + (const float rhs) { return String(*this) += rhs; } + //! Create a new String from the concatenation of *this and a double + const String operator + (const double rhs) { return String(*this) += rhs; } + //@} + + + //! \name Case convertion + //@{ + /*! + ** \brief Convert the case (lower case) of characters in the string using the UTF8 charset + ** \return Returns *this + */ + String& toLower(); + /*! + ** \brief Convert the case (upper case) of characters in the string using the UTF8 charset + ** \return Returns *this + */ + String& toUpper(); + //@} Case convertion + + + /*! + ** \brief Remove trailing and leading spaces + ** \param trimChars The chars to remove + ** \return Returns *this + */ + String& trim(const String& trimChars = TA3D_WSTR_SEPARATORS); + + + //! \name Split + //@{ + + /*! + ** \brief Divide a string into several parts + ** \param[out] All found parts + ** \param sepearators Sequence of chars considered as a separator + ** \param emptyBefore True to clear the vector before fulfill it + ** \warning Do not take care of string representation (with `'` or `"`) + */ + void split(String::Vector& out, const String& separators = TA3D_WSTR_SEPARATORS, const bool emptyBefore = true) const; + /*! + ** \brief Divide a string into several parts + ** \param[out] All found parts + ** \param sepearators Sequence of chars considered as a separator + ** \param emptyBefore True to clear the list before fulfill it + ** \warning Do not take care of string representation (with `'` or `"`) + */ + void split(String::List& out, const String& separators = TA3D_WSTR_SEPARATORS, const bool emptyBefore = true) const; + + //@} Split + + + /*! + ** \brief Extract the key and its value from a string (mainly provided by TDF files) + ** + ** \param[out] key The key that has been found + ** \param[out] value The associated value + ** + ** \see String::ToKeyValue() + */ + void toKeyValue(String& key, String& value, const enum CharCase chcase = soCaseSensitive) const + {ToKeyValue(*this, key, value, chcase);} + + /*! + ** \brief Convert all antislashes into slashes + ** \return Returns *this + */ + String& convertAntiSlashesIntoSlashes(); + + /*! + ** \brief Convert all slashes into antislashes + ** \return Returns *this + */ + String& convertSlashesIntoAntiSlashes(); + + /*! + ** \brief Get the hash value of this string + */ + uint32 hashValue() const; + + /*! + ** \brief Convert the string from ASCII to UTF8 + ** \return Always *this + */ + String& convertToUTF8() {*this = ConvertToUTF8(*this); return *this;} + + /*! + ** \brief Replace a substr by another one + ** \param toSearch The string to look for + ** \param replaceWith The string replacement + ** \param option Option when looking for the string `toSearch` + ** \return Always *this + */ + String& findAndReplace(const String& toSearch, const String& replaceWith, const enum String::CharCase option = soCaseSensitive); + String& findAndReplace(char toSearch, const char replaceWith, const enum String::CharCase option = soCaseSensitive); + + /*! + ** \brief Reset the current value with a formatted string + ** \param f The format of the new string + ** \return Always *this + */ + String& format(const String& f, ...); + String& format(const char* f, ...); + + /*! + ** \brief Append a formatted string + ** \param f The format of the new string + ** \return Always *this + */ + String& appendFormat(const String& f, ...); + String& appendFormat(const char* f, ...); + String& vappendFormat(const char* f, va_list parg); + + + /*! + ** \brief Detect if the string matches the given pattern + ** \param pattern + ** \return true if match + */ + bool match(const String &pattern); + + /*! + ** \brief returns a substring assuming current string is an UTF8 String + ** \param pos + ** \param len + ** \return the substring + */ + String substrUTF8(int pos = 0, int len = -1) const; + + /*! + ** \brief returns the String size assuming it's in UTF8 + ** \return the number of UTF8 symbols + */ + int sizeUTF8() const; + + private: + /*! + ** \brief Convert a string into another type, given by the template parameter `T` + ** \param[out] t The destination variable + ** \param s The string to convert + ** \param f The base to use for the convertion (std::hex, std::dec, ...) + ** \return True if the operation succeeded, False otherwise + */ + template + bool fromString(T& t, const String& s) const + { + std::istringstream iss(s); + if (s.size() > 2) + { + if(s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) + iss >> std::hex; + else if (s[0] == '0' && s[1] != 'x' && s[1] != 'X') + iss >> std::oct; + else + iss >> std::dec; + } + else + iss >> std::dec; + return !(iss >> t).fail(); + } + + static int ASCIItoUTF8(const byte c, byte *out); + }; // class String + + + +//int ASCIItoUTF8(const byte c, byte *out); + + /*! + ** \brief Convert an UTF-8 String into a WideChar String + ** \todo This class must be removed as soon as possible and is only here to prevent against + ** stange bugs with the previous implementation + */ + struct WString + { + public: + WString(const char* s); + WString(const String& str); + + void fromUtf8(const char* s, size_t length); + const wchar_t* cw_str() const {return pBuffer;} + + private: + wchar_t pBuffer[5120]; + }; + + +}} // namespace TA3D + +#endif // _SHARED_UTIL_W_STRING_H__ diff --git a/source/shared_lib/include/util/utf8.h b/source/shared_lib/include/util/utf8.h new file mode 100644 index 00000000..4e445140 --- /dev/null +++ b/source/shared_lib/include/util/utf8.h @@ -0,0 +1,34 @@ +// Copyright 2006 Nemanja Trifunovic + +/* +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + + +#ifndef UTF8_FOR_CPP_2675DCD0_9480_4c0c_B92A_CC14C027B731 +#define UTF8_FOR_CPP_2675DCD0_9480_4c0c_B92A_CC14C027B731 + +#include "utf8/checked.h" +#include "utf8/unchecked.h" + +#endif // header guard diff --git a/source/shared_lib/include/util/utf8/checked.h b/source/shared_lib/include/util/utf8/checked.h new file mode 100644 index 00000000..9cb8d2c7 --- /dev/null +++ b/source/shared_lib/include/util/utf8/checked.h @@ -0,0 +1,327 @@ +// Copyright 2006 Nemanja Trifunovic + +/* +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + + +#ifndef UTF8_FOR_CPP_CHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 +#define UTF8_FOR_CPP_CHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 + +#include "core.h" +#include + +namespace utf8 +{ + // Base for the exceptions that may be thrown from the library + class exception : public std::exception { + }; + + // Exceptions that may be thrown from the library functions. + class invalid_code_point : public exception { + uint32_t cp; + public: + invalid_code_point(uint32_t cp) : cp(cp) {} + virtual const char* what() const throw() { return "Invalid code point"; } + uint32_t code_point() const {return cp;} + }; + + class invalid_utf8 : public exception { + uint8_t u8; + public: + invalid_utf8 (uint8_t u) : u8(u) {} + virtual const char* what() const throw() { return "Invalid UTF-8"; } + uint8_t utf8_octet() const {return u8;} + }; + + class invalid_utf16 : public exception { + uint16_t u16; + public: + invalid_utf16 (uint16_t u) : u16(u) {} + virtual const char* what() const throw() { return "Invalid UTF-16"; } + uint16_t utf16_word() const {return u16;} + }; + + class not_enough_room : public exception { + public: + virtual const char* what() const throw() { return "Not enough space"; } + }; + + /// The library API - functions intended to be called by the users + + template + output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out, uint32_t replacement) + { + while (start != end) { + octet_iterator sequence_start = start; + internal::utf_error err_code = internal::validate_next(start, end); + switch (err_code) { + case internal::UTF8_OK : + for (octet_iterator it = sequence_start; it != start; ++it) + *out++ = *it; + break; + case internal::NOT_ENOUGH_ROOM: + throw not_enough_room(); + case internal::INVALID_LEAD: + append (replacement, out); + ++start; + break; + case internal::INCOMPLETE_SEQUENCE: + case internal::OVERLONG_SEQUENCE: + case internal::INVALID_CODE_POINT: + append (replacement, out); + ++start; + // just one replacement mark for the sequence + while (internal::is_trail(*start) && start != end) + ++start; + break; + } + } + return out; + } + + template + inline output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out) + { + static const uint32_t replacement_marker = internal::mask16(0xfffd); + return replace_invalid(start, end, out, replacement_marker); + } + + template + octet_iterator append(uint32_t cp, octet_iterator result) + { + if (!internal::is_code_point_valid(cp)) + throw invalid_code_point(cp); + + if (cp < 0x80) // one octet + *(result++) = static_cast(cp); + else if (cp < 0x800) { // two octets + *(result++) = static_cast((cp >> 6) | 0xc0); + *(result++) = static_cast((cp & 0x3f) | 0x80); + } + else if (cp < 0x10000) { // three octets + *(result++) = static_cast((cp >> 12) | 0xe0); + *(result++) = static_cast(((cp >> 6) & 0x3f) | 0x80); + *(result++) = static_cast((cp & 0x3f) | 0x80); + } + else { // four octets + *(result++) = static_cast((cp >> 18) | 0xf0); + *(result++) = static_cast(((cp >> 12) & 0x3f) | 0x80); + *(result++) = static_cast(((cp >> 6) & 0x3f) | 0x80); + *(result++) = static_cast((cp & 0x3f) | 0x80); + } + return result; + } + + template + uint32_t next(octet_iterator& it, octet_iterator end) + { + uint32_t cp = 0; + internal::utf_error err_code = internal::validate_next(it, end, &cp); + switch (err_code) { + case internal::UTF8_OK : + break; + case internal::NOT_ENOUGH_ROOM : + throw not_enough_room(); + case internal::INVALID_LEAD : + case internal::INCOMPLETE_SEQUENCE : + case internal::OVERLONG_SEQUENCE : + throw invalid_utf8(*it); + case internal::INVALID_CODE_POINT : + throw invalid_code_point(cp); + } + return cp; + } + + template + uint32_t peek_next(octet_iterator it, octet_iterator end) + { + return next(it, end); + } + + template + uint32_t prior(octet_iterator& it, octet_iterator start) + { + // can't do much if it == start + if (it == start) + throw not_enough_room(); + + octet_iterator end = it; + // Go back until we hit either a lead octet or start + while (internal::is_trail(*(--it))) + if (it == start) + throw invalid_utf8(*it); // error - no lead byte in the sequence + return peek_next(it, end); + } + + /// Deprecated in versions that include "prior" + template + uint32_t previous(octet_iterator& it, octet_iterator pass_start) + { + octet_iterator end = it; + while (internal::is_trail(*(--it))) + if (it == pass_start) + throw invalid_utf8(*it); // error - no lead byte in the sequence + octet_iterator temp = it; + return next(temp, end); + } + + template + void advance (octet_iterator& it, distance_type n, octet_iterator end) + { + for (distance_type i = 0; i < n; ++i) + next(it, end); + } + + template + typename std::iterator_traits::difference_type + distance (octet_iterator first, octet_iterator last) + { + typename std::iterator_traits::difference_type dist; + for (dist = 0; first < last; ++dist) + next(first, last); + return dist; + } + + template + octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result) + { + while (start != end) { + uint32_t cp = internal::mask16(*start++); + // Take care of surrogate pairs first + if (internal::is_lead_surrogate(cp)) { + if (start != end) { + uint32_t trail_surrogate = internal::mask16(*start++); + if (internal::is_trail_surrogate(trail_surrogate)) + cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET; + else + throw invalid_utf16(static_cast(trail_surrogate)); + } + else + throw invalid_utf16(static_cast(cp)); + + } + // Lone trail surrogate + else if (internal::is_trail_surrogate(cp)) + throw invalid_utf16(static_cast(cp)); + + result = append(cp, result); + } + return result; + } + + template + u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result) + { + while (start != end) { + uint32_t cp = next(start, end); + if (cp > 0xffff) { //make a surrogate pair + *result++ = static_cast((cp >> 10) + internal::LEAD_OFFSET); + *result++ = static_cast((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN); + } + else + *result++ = static_cast(cp); + } + return result; + } + + template + octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result) + { + while (start != end) + result = append(*(start++), result); + + return result; + } + + template + u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result) + { + while (start != end) + (*result++) = next(start, end); + + return result; + } + + // The iterator class + template + class iterator : public std::iterator { + octet_iterator it; + octet_iterator range_start; + octet_iterator range_end; + public: + iterator () {}; + explicit iterator (const octet_iterator& octet_it, + const octet_iterator& range_start, + const octet_iterator& range_end) : + it(octet_it), range_start(range_start), range_end(range_end) + { + if (it < range_start || it > range_end) + throw std::out_of_range("Invalid utf-8 iterator position"); + } + // the default "big three" are OK + octet_iterator base () const { return it; } + uint32_t operator * () const + { + octet_iterator temp = it; + return next(temp, range_end); + } + bool operator == (const iterator& rhs) const + { + if (range_start != rhs.range_start || range_end != rhs.range_end) + throw std::logic_error("Comparing utf-8 iterators defined with different ranges"); + return (it == rhs.it); + } + bool operator != (const iterator& rhs) const + { + return !(operator == (rhs)); + } + iterator& operator ++ () + { + next(it, range_end); + return *this; + } + iterator operator ++ (int) + { + iterator temp = *this; + next(it, range_end); + return temp; + } + iterator& operator -- () + { + prior(it, range_start); + return *this; + } + iterator operator -- (int) + { + iterator temp = *this; + prior(it, range_start); + return temp; + } + }; // class iterator + +} // namespace utf8 + +#endif //header guard + + diff --git a/source/shared_lib/include/util/utf8/core.h b/source/shared_lib/include/util/utf8/core.h new file mode 100755 index 00000000..268cf7cd --- /dev/null +++ b/source/shared_lib/include/util/utf8/core.h @@ -0,0 +1,358 @@ +// Copyright 2006 Nemanja Trifunovic + +/* +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + + +#ifndef UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 +#define UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 + +#include + +namespace utf8 +{ + // The typedefs for 8-bit, 16-bit and 32-bit unsigned integers + // You may need to change them to match your system. + // These typedefs have the same names as ones from cstdint, or boost/cstdint + typedef unsigned char uint8_t; + typedef unsigned short uint16_t; + typedef unsigned int uint32_t; + +// Helper code - not intended to be directly called by the library users. May be changed at any time +namespace internal +{ + // Unicode constants + // Leading (high) surrogates: 0xd800 - 0xdbff + // Trailing (low) surrogates: 0xdc00 - 0xdfff + const uint16_t LEAD_SURROGATE_MIN = 0xd800u; + const uint16_t LEAD_SURROGATE_MAX = 0xdbffu; + const uint16_t TRAIL_SURROGATE_MIN = 0xdc00u; + const uint16_t TRAIL_SURROGATE_MAX = 0xdfffu; + const uint16_t LEAD_OFFSET = LEAD_SURROGATE_MIN - (0x10000 >> 10); + const uint32_t SURROGATE_OFFSET = 0x10000u - (LEAD_SURROGATE_MIN << 10) - TRAIL_SURROGATE_MIN; + + // Maximum valid value for a Unicode code point + const uint32_t CODE_POINT_MAX = 0x0010ffffu; + + template + inline uint8_t mask8(octet_type oc) + { + return static_cast(0xff & oc); + } + template + inline uint16_t mask16(u16_type oc) + { + return static_cast(0xffff & oc); + } + template + inline bool is_trail(octet_type oc) + { + return ((mask8(oc) >> 6) == 0x2); + } + + template + inline bool is_lead_surrogate(u16 cp) + { + return (cp >= LEAD_SURROGATE_MIN && cp <= LEAD_SURROGATE_MAX); + } + + template + inline bool is_trail_surrogate(u16 cp) + { + return (cp >= TRAIL_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX); + } + + template + inline bool is_surrogate(u16 cp) + { + return (cp >= LEAD_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX); + } + + template + inline bool is_code_point_valid(u32 cp) + { + return (cp <= CODE_POINT_MAX && !is_surrogate(cp)); + } + + template + inline typename std::iterator_traits::difference_type + sequence_length(octet_iterator lead_it) + { + uint8_t lead = mask8(*lead_it); + if (lead < 0x80) + return 1; + else if ((lead >> 5) == 0x6) + return 2; + else if ((lead >> 4) == 0xe) + return 3; + else if ((lead >> 3) == 0x1e) + return 4; + else + return 0; + } + + template + inline bool is_overlong_sequence(uint32_t cp, octet_difference_type length) + { + if (cp < 0x80) { + if (length != 1) + return true; + } + else if (cp < 0x800) { + if (length != 2) + return true; + } + else if (cp < 0x10000) { + if (length != 3) + return true; + } + + return false; + } + + enum utf_error {UTF8_OK, NOT_ENOUGH_ROOM, INVALID_LEAD, INCOMPLETE_SEQUENCE, OVERLONG_SEQUENCE, INVALID_CODE_POINT}; + + /// get_sequence_x functions decode utf-8 sequences of the length x + + template + utf_error get_sequence_1(octet_iterator& it, octet_iterator end, uint32_t* code_point) + { + if (it != end) { + if (code_point) + *code_point = mask8(*it); + return UTF8_OK; + } + return NOT_ENOUGH_ROOM; + } + + template + utf_error get_sequence_2(octet_iterator& it, octet_iterator end, uint32_t* code_point) + { + utf_error ret_code = NOT_ENOUGH_ROOM; + + if (it != end) { + uint32_t cp = mask8(*it); + if (++it != end) { + if (is_trail(*it)) { + cp = ((cp << 6) & 0x7ff) + ((*it) & 0x3f); + + if (code_point) + *code_point = cp; + ret_code = UTF8_OK; + } + else + ret_code = INCOMPLETE_SEQUENCE; + } + else + ret_code = NOT_ENOUGH_ROOM; + } + + return ret_code; + } + + template + utf_error get_sequence_3(octet_iterator& it, octet_iterator end, uint32_t* code_point) + { + utf_error ret_code = NOT_ENOUGH_ROOM; + + if (it != end) { + uint32_t cp = mask8(*it); + if (++it != end) { + if (is_trail(*it)) { + cp = ((cp << 12) & 0xffff) + ((mask8(*it) << 6) & 0xfff); + if (++it != end) { + if (is_trail(*it)) { + cp += (*it) & 0x3f; + + if (code_point) + *code_point = cp; + ret_code = UTF8_OK; + } + else + ret_code = INCOMPLETE_SEQUENCE; + } + else + ret_code = NOT_ENOUGH_ROOM; + } + else + ret_code = INCOMPLETE_SEQUENCE; + } + else + ret_code = NOT_ENOUGH_ROOM; + } + + return ret_code; + } + + template + utf_error get_sequence_4(octet_iterator& it, octet_iterator end, uint32_t* code_point) + { + utf_error ret_code = NOT_ENOUGH_ROOM; + + if (it != end) { + uint32_t cp = mask8(*it); + if (++it != end) { + if (is_trail(*it)) { + cp = ((cp << 18) & 0x1fffff) + ((mask8(*it) << 12) & 0x3ffff); + if (++it != end) { + if (is_trail(*it)) { + cp += (mask8(*it) << 6) & 0xfff; + if (++it != end) { + if (is_trail(*it)) { + cp += (*it) & 0x3f; + + if (code_point) + *code_point = cp; + ret_code = UTF8_OK; + } + else + ret_code = INCOMPLETE_SEQUENCE; + } + else + ret_code = NOT_ENOUGH_ROOM; + } + else + ret_code = INCOMPLETE_SEQUENCE; + } + else + ret_code = NOT_ENOUGH_ROOM; + } + else + ret_code = INCOMPLETE_SEQUENCE; + } + else + ret_code = NOT_ENOUGH_ROOM; + } + + return ret_code; + } + + template + utf_error validate_next(octet_iterator& it, octet_iterator end, uint32_t* code_point) + { + // Save the original value of it so we can go back in case of failure + // Of course, it does not make much sense with i.e. stream iterators + octet_iterator original_it = it; + + uint32_t cp = 0; + // Determine the sequence length based on the lead octet + typedef typename std::iterator_traits::difference_type octet_difference_type; + octet_difference_type length = sequence_length(it); + if (length == 0) + return INVALID_LEAD; + + // Now that we have a valid sequence length, get trail octets and calculate the code point + utf_error err = UTF8_OK; + switch (length) { + case 1: + err = get_sequence_1(it, end, &cp); + break; + case 2: + err = get_sequence_2(it, end, &cp); + break; + case 3: + err = get_sequence_3(it, end, &cp); + break; + case 4: + err = get_sequence_4(it, end, &cp); + break; + } + + if (err == UTF8_OK) { + // Decoding succeeded. Now, security checks... + if (is_code_point_valid(cp)) { + if (!is_overlong_sequence(cp, length)){ + // Passed! Return here. + if (code_point) + *code_point = cp; + ++it; + return UTF8_OK; + } + else + err = OVERLONG_SEQUENCE; + } + else + err = INVALID_CODE_POINT; + } + + // Failure branch - restore the original value of the iterator + it = original_it; + return err; + } + + template + inline utf_error validate_next(octet_iterator& it, octet_iterator end) { + return validate_next(it, end, 0); + } + +} // namespace internal + + /// The library API - functions intended to be called by the users + + // Byte order mark + const uint8_t bom[] = {0xef, 0xbb, 0xbf}; + + template + octet_iterator find_invalid(octet_iterator start, octet_iterator end) + { + octet_iterator result = start; + while (result != end) { + internal::utf_error err_code = internal::validate_next(result, end); + if (err_code != internal::UTF8_OK) + return result; + } + return result; + } + + template + inline bool is_valid(octet_iterator start, octet_iterator end) + { + return (find_invalid(start, end) == end); + } + + template + inline bool starts_with_bom (octet_iterator it, octet_iterator end) + { + return ( + ((it != end) && (internal::mask8(*it++)) == bom[0]) && + ((it != end) && (internal::mask8(*it++)) == bom[1]) && + ((it != end) && (internal::mask8(*it)) == bom[2]) + ); + } + + //Deprecated in release 2.3 + template + inline bool is_bom (octet_iterator it) + { + return ( + (internal::mask8(*it++)) == bom[0] && + (internal::mask8(*it++)) == bom[1] && + (internal::mask8(*it)) == bom[2] + ); + } +} // namespace utf8 + +#endif // header guard + + diff --git a/source/shared_lib/include/util/utf8/unchecked.h b/source/shared_lib/include/util/utf8/unchecked.h new file mode 100755 index 00000000..2f3eb4d1 --- /dev/null +++ b/source/shared_lib/include/util/utf8/unchecked.h @@ -0,0 +1,228 @@ +// Copyright 2006 Nemanja Trifunovic + +/* +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + + +#ifndef UTF8_FOR_CPP_UNCHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 +#define UTF8_FOR_CPP_UNCHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 + +#include "core.h" + +namespace utf8 +{ + namespace unchecked + { + template + octet_iterator append(uint32_t cp, octet_iterator result) + { + if (cp < 0x80) // one octet + *(result++) = static_cast(cp); + else if (cp < 0x800) { // two octets + *(result++) = static_cast((cp >> 6) | 0xc0); + *(result++) = static_cast((cp & 0x3f) | 0x80); + } + else if (cp < 0x10000) { // three octets + *(result++) = static_cast((cp >> 12) | 0xe0); + *(result++) = static_cast(((cp >> 6) & 0x3f) | 0x80); + *(result++) = static_cast((cp & 0x3f) | 0x80); + } + else { // four octets + *(result++) = static_cast((cp >> 18) | 0xf0); + *(result++) = static_cast(((cp >> 12) & 0x3f)| 0x80); + *(result++) = static_cast(((cp >> 6) & 0x3f) | 0x80); + *(result++) = static_cast((cp & 0x3f) | 0x80); + } + return result; + } + + template + uint32_t next(octet_iterator& it) + { + uint32_t cp = internal::mask8(*it); + typename std::iterator_traits::difference_type length = utf8::internal::sequence_length(it); + switch (length) { + case 1: + break; + case 2: + it++; + cp = ((cp << 6) & 0x7ff) + ((*it) & 0x3f); + break; + case 3: + ++it; + cp = ((cp << 12) & 0xffff) + ((internal::mask8(*it) << 6) & 0xfff); + ++it; + cp += (*it) & 0x3f; + break; + case 4: + ++it; + cp = ((cp << 18) & 0x1fffff) + ((internal::mask8(*it) << 12) & 0x3ffff); + ++it; + cp += (internal::mask8(*it) << 6) & 0xfff; + ++it; + cp += (*it) & 0x3f; + break; + } + ++it; + return cp; + } + + template + uint32_t peek_next(octet_iterator it) + { + return next(it); + } + + template + uint32_t prior(octet_iterator& it) + { + while (internal::is_trail(*(--it))) ; + octet_iterator temp = it; + return next(temp); + } + + // Deprecated in versions that include prior, but only for the sake of consistency (see utf8::previous) + template + inline uint32_t previous(octet_iterator& it) + { + return prior(it); + } + + template + void advance (octet_iterator& it, distance_type n) + { + for (distance_type i = 0; i < n; ++i) + next(it); + } + + template + typename std::iterator_traits::difference_type + distance (octet_iterator first, octet_iterator last) + { + typename std::iterator_traits::difference_type dist; + for (dist = 0; first < last; ++dist) + next(first); + return dist; + } + + template + octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result) + { + while (start != end) { + uint32_t cp = internal::mask16(*start++); + // Take care of surrogate pairs first + if (internal::is_lead_surrogate(cp)) { + uint32_t trail_surrogate = internal::mask16(*start++); + cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET; + } + result = append(cp, result); + } + return result; + } + + template + u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result) + { + while (start < end) { + uint32_t cp = next(start); + if (cp > 0xffff) { //make a surrogate pair + *result++ = static_cast((cp >> 10) + internal::LEAD_OFFSET); + *result++ = static_cast((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN); + } + else + *result++ = static_cast(cp); + } + return result; + } + + template + octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result) + { + while (start != end) + result = append(*(start++), result); + + return result; + } + + template + u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result) + { + while (start < end) + (*result++) = next(start); + + return result; + } + + // The iterator class + template + class iterator : public std::iterator { + octet_iterator it; + public: + iterator () {}; + explicit iterator (const octet_iterator& octet_it): it(octet_it) {} + // the default "big three" are OK + octet_iterator base () const { return it; } + uint32_t operator * () const + { + octet_iterator temp = it; + return next(temp); + } + bool operator == (const iterator& rhs) const + { + return (it == rhs.it); + } + bool operator != (const iterator& rhs) const + { + return !(operator == (rhs)); + } + iterator& operator ++ () + { + std::advance(it, internal::sequence_length(it)); + return *this; + } + iterator operator ++ (int) + { + iterator temp = *this; + std::advance(it, internal::sequence_length(it)); + return temp; + } + iterator& operator -- () + { + prior(it); + return *this; + } + iterator operator -- (int) + { + iterator temp = *this; + prior(it); + return temp; + } + }; // class iterator + + } // namespace utf8::unchecked +} // namespace utf8 + + +#endif // header guard + diff --git a/source/shared_lib/sources/graphics/font.cpp b/source/shared_lib/sources/graphics/font.cpp index 0220e617..7dc9655e 100644 --- a/source/shared_lib/sources/graphics/font.cpp +++ b/source/shared_lib/sources/graphics/font.cpp @@ -13,16 +13,17 @@ #include #include "conversion.h" -#include "font_text.h" #ifdef USE_FTGL + #include "font_textFTGL.h" #include #include -//#include "string_utils.h" using namespace Shared::Util; using namespace Shared::Graphics::Gl; + #endif +#include "util.h" #include "leak_dumper.h" using namespace std; @@ -31,9 +32,11 @@ using namespace Shared::Util; namespace Shared { namespace Graphics { // Init statics -int Font::charCount = 256; -std::string Font::fontTypeName = "Times New Roman"; -bool Font::fontIsMultibyte = false; +int Font::charCount = 256; +std::string Font::fontTypeName = "Times New Roman"; +bool Font::fontIsMultibyte = false; +bool Font::forceLegacyFonts = false; +float FontMetrics::DEFAULT_Y_OFFSET_FACTOR = 8.0f; // // ===================================================== @@ -44,6 +47,7 @@ FontMetrics::FontMetrics(Text *textHandler) { this->textHandler = textHandler; this->widths = new float[Font::charCount]; this->height = 0; + this->yOffsetFactor = FontMetrics::DEFAULT_Y_OFFSET_FACTOR; for(int i=0; i < Font::charCount; ++i) { widths[i]= 0; @@ -55,6 +59,14 @@ FontMetrics::~FontMetrics() { widths = NULL; } +void FontMetrics::setYOffsetFactor(float yOffsetFactor) { + this->yOffsetFactor = yOffsetFactor; +} + +float FontMetrics::getYOffsetFactor() const { + return this->yOffsetFactor; +} + void FontMetrics::setTextHandler(Text *textHandler) { this->textHandler = textHandler; } @@ -100,15 +112,27 @@ float FontMetrics::getHeight() const { // class Font // =============================================== -Font::Font() { +Font::Font(FontTextHandlerType type) { inited = false; - type = fontTypeName; + this->type = fontTypeName; width = 400; + size = 10; textHandler = NULL; #ifdef USE_FTGL - textHandler = new TextFTGL(); - metrics.setTextHandler(this->textHandler); + + if(Font::forceLegacyFonts == false) { + try { + textHandler = NULL; + textHandler = new TextFTGL(type); + metrics.setTextHandler(this->textHandler); + } + catch(exception &ex) { + SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",__FILE__,__FUNCTION__,__LINE__,ex.what()); + textHandler = NULL; + } + } + #endif } @@ -119,12 +143,32 @@ Font::~Font() { textHandler = NULL; } +void Font::setYOffsetFactor(float yOffsetFactor) { + metrics.setYOffsetFactor(yOffsetFactor); +} + +float Font::getYOffsetFactor() const { + return metrics.getYOffsetFactor(); +} + +string Font::getType() const { + return this->type; +} + void Font::setType(string typeX11, string typeGeneric) { if(textHandler) { - textHandler->init(typeGeneric,textHandler->GetFaceSize()); + try { + this->type= typeGeneric; + textHandler->init(typeGeneric,textHandler->GetFaceSize()); + metrics.setTextHandler(this->textHandler); + } + catch(exception &ex) { + SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",__FILE__,__FUNCTION__,__LINE__,ex.what()); + textHandler = NULL; + } } - else { - this->type= type; + if(textHandler == NULL) { + this->type= typeX11; } } @@ -136,15 +180,7 @@ int Font::getWidth() const { return width; } -// =============================================== -// class Font2D -// =============================================== - -Font2D::Font2D() { - size = 10; -} - -int Font2D::getSize() const { +int Font::getSize() const { if(textHandler) { return textHandler->GetFaceSize(); } @@ -152,7 +188,7 @@ int Font2D::getSize() const { return size; } } -void Font2D::setSize(int size) { +void Font::setSize(int size) { if(textHandler) { return textHandler->SetFaceSize(size); } @@ -161,11 +197,18 @@ void Font2D::setSize(int size) { } } +// =============================================== +// class Font2D +// =============================================== + +Font2D::Font2D(FontTextHandlerType type) : Font(type) { +} + // =============================================== // class Font3D // =============================================== -Font3D::Font3D() { +Font3D::Font3D(FontTextHandlerType type) : Font(type) { depth= 10.f; } diff --git a/source/shared_lib/sources/graphics/font_text.cpp b/source/shared_lib/sources/graphics/font_text.cpp index 7a2927b9..8cfd2373 100644 --- a/source/shared_lib/sources/graphics/font_text.cpp +++ b/source/shared_lib/sources/graphics/font_text.cpp @@ -15,7 +15,9 @@ using namespace std; std::string Text::DEFAULT_FONT_PATH = ""; //==================================================================== -Text::Text() {} +Text::Text(FontTextHandlerType type) { + this->type = type; +} Text::~Text() {} void Text::init(string fontName, int fontSize) {} void Text::Render(const char*, const int) {} diff --git a/source/shared_lib/sources/graphics/gl/font_gl.cpp b/source/shared_lib/sources/graphics/gl/font_gl.cpp index 2b1bc177..9016994a 100644 --- a/source/shared_lib/sources/graphics/gl/font_gl.cpp +++ b/source/shared_lib/sources/graphics/gl/font_gl.cpp @@ -79,3 +79,19 @@ void Font3DGl::end() { } }}}//end namespace + +namespace Shared { namespace Graphics { + + using namespace Gl; +Font3D * ConvertFont2DTo3D(Font2D *font) { + + Font3D *result = new Font3DGl(); + result->setSize(font->getSize()); + result->setType("",font->getType()); + result->setYOffsetFactor(font->getYOffsetFactor()); + result->setWidth(font->getWidth()); + result->init(); + return result; +} + +}} diff --git a/source/shared_lib/sources/graphics/gl/font_textFTGL.cpp b/source/shared_lib/sources/graphics/gl/font_textFTGL.cpp index a88e7419..cdd18967 100644 --- a/source/shared_lib/sources/graphics/gl/font_textFTGL.cpp +++ b/source/shared_lib/sources/graphics/gl/font_textFTGL.cpp @@ -29,12 +29,11 @@ using namespace std; using namespace Shared::Util; using namespace Shared::PlatformCommon; -namespace Shared{ namespace Graphics{ namespace Gl{ +namespace Shared { namespace Graphics { namespace Gl { //==================================================================== -TextFTGL::TextFTGL() { - +TextFTGL::TextFTGL(FontTextHandlerType type) : Text(type) { //setenv("MEGAGLEST_FONT","/usr/share/fonts/truetype/wqy/wqy-zenhei.ttc",0); //setenv("MEGAGLEST_FONT","/usr/share/fonts/truetype/arphic/uming.ttc",0); // Chinese @@ -56,7 +55,17 @@ TextFTGL::TextFTGL() { //ftFont = new FTGLPolygonFont("/usr/share/fonts/truetype/arphic/uming.ttc"); //ftFont = new FTGLPixmapFont("/usr/share/fonts/truetype/arphic/uming.ttc"); - ftFont = new FTGLPixmapFont(fontFile); + if(type == ftht_2D) { + ftFont = new FTGLPixmapFont(fontFile); + //printf("2D font [%s]\n",fontFile); + } + else if(type == ftht_3D) { + ftFont = new FTBufferFont(fontFile); + //printf("3D font [%s]\n",fontFile); + } + else { + throw runtime_error("font render type not set to a known value!"); + } if(ftFont->Error()) { printf("FTGL: error loading font: %s\n", fontFile); @@ -96,7 +105,17 @@ void TextFTGL::init(string fontName, int fontSize) { //ftFont = new FTGLPolygonFont("/usr/share/fonts/truetype/arphic/uming.ttc"); //ftFont = new FTGLPixmapFont("/usr/share/fonts/truetype/arphic/uming.ttc"); - ftFont = new FTGLPixmapFont(fontFile); + if(type == ftht_2D) { + ftFont = new FTGLPixmapFont(fontFile); + //printf("2D font [%s]\n",fontFile); + } + else if(type == ftht_3D) { + ftFont = new FTBufferFont(fontFile); + //printf("3D font [%s]\n",fontFile); + } + else { + throw runtime_error("font render type not set to a known value!"); + } if(ftFont->Error()) { printf("FTGL: error loading font: %s\n", fontFile); diff --git a/source/shared_lib/sources/graphics/gl/text_renderer_gl.cpp b/source/shared_lib/sources/graphics/gl/text_renderer_gl.cpp index 4362fcd2..7b6c2947 100644 --- a/source/shared_lib/sources/graphics/gl/text_renderer_gl.cpp +++ b/source/shared_lib/sources/graphics/gl/text_renderer_gl.cpp @@ -28,16 +28,33 @@ namespace Shared { namespace Graphics { namespace Gl { TextRenderer2DGl::TextRenderer2DGl() { rendering= false; this->font = NULL; + + //font3D = NULL; + //tester = new TextRenderer3DGl(); } TextRenderer2DGl::~TextRenderer2DGl() { + //delete font3D; + //font3D = NULL; + + //delete tester; + //tester = NULL; } void TextRenderer2DGl::begin(Font2D *font) { - assert(!rendering); - - rendering = true; this->font = static_cast(font); + +// if(font3D == NULL) { +// font3D = new Font3DGl(); +// font3D->setYOffsetFactor(this->font->getYOffsetFactor()); +// font3D->setType("", this->font->getType()); +// font3D->setDepth(this->font->getWidth()); +// } +// tester->begin(font3D); +// return; + + assert(!rendering); + rendering = true; } // Convert a narrow string to a wide string// @@ -56,6 +73,9 @@ void TextRenderer2DGl::begin(Font2D *font) { // Widen an individual character void TextRenderer2DGl::render(const string &text, int x, int y, bool centered, Vec3f *color) { + //tester->render(text, x, y, this->font->getWidth(),centered); + //return; + assert(rendering); assertGl(); @@ -68,7 +88,7 @@ void TextRenderer2DGl::render(const string &text, int x, int y, bool centered, V int line = 0; int size = font->getSize(); const unsigned char *utext = NULL; - FontMetrics *metrics = NULL; + FontMetrics *metrics = NULL; //printf("font->getTextHandler() [%p] centered = %d text [%s]\n",font->getTextHandler(),centered,text.c_str()); @@ -76,11 +96,11 @@ void TextRenderer2DGl::render(const string &text, int x, int y, bool centered, V if(font->getTextHandler() != NULL) { if(centered) { rasterPos.x= x - font->getTextHandler()->Advance(text.c_str()) / 2.f; - rasterPos.y= y + font->getTextHandler()->LineHeight(text.c_str()) / 2.f; + rasterPos.y= y + font->getTextHandler()->LineHeight(text.c_str()) / font->getYOffsetFactor(); } else { rasterPos= Vec2f(static_cast(x), static_cast(y)); - rasterPos.y= y + (font->getTextHandler()->LineHeight(text.c_str()) / 8.f); + rasterPos.y= y + (font->getTextHandler()->LineHeight(text.c_str()) / font->getYOffsetFactor()); } } else { @@ -96,6 +116,9 @@ void TextRenderer2DGl::render(const string &text, int x, int y, bool centered, V } glRasterPos2f(rasterPos.x, rasterPos.y); + //font->getTextHandler()->Render("Zurück"); + //return; + if(Font::fontIsMultibyte == true) { if(font->getTextHandler() != NULL) { //String str("資料"); @@ -143,12 +166,9 @@ void TextRenderer2DGl::render(const string &text, int x, int y, bool centered, V //fontFTGL->Render("testování slovanský jazyk"); // Czech Works! - - // This works //fontFTGL->Render(text.c_str()); - if(text.find("\n") == text.npos && text.find("\t") == text.npos) { font->getTextHandler()->Render(text.c_str()); } @@ -311,6 +331,9 @@ void TextRenderer2DGl::render(const string &text, int x, int y, bool centered, V } void TextRenderer2DGl::end() { + //tester->end(); + //return; + assert(rendering); rendering= false; } @@ -341,7 +364,7 @@ void TextRenderer3DGl::begin(Font3D *font) { assertGl(); } -void TextRenderer3DGl::render(const string &text, float x, float y, float size, bool centered) { +void TextRenderer3DGl::render(const string &text, float x, float y, bool centered) { assert(rendering); const unsigned char *utext= NULL; @@ -350,13 +373,17 @@ void TextRenderer3DGl::render(const string &text, float x, float y, float size, glMatrixMode(GL_MODELVIEW); glPushMatrix(); glPushAttrib(GL_POLYGON_BIT); - float scale= size / 10.f; + + int size = font->getSize(); + //float scale= size / 15.f; + float scale= 1.0f; + //float scale= size; Vec3f translatePos; if(font->getTextHandler() != NULL) { if(centered) { translatePos.x = x - scale * font->getTextHandler()->Advance(text.c_str()) / 2.f; - translatePos.y = y - scale * font->getTextHandler()->LineHeight(text.c_str()) / 2.f; + translatePos.y = y - scale * font->getTextHandler()->LineHeight(text.c_str()) / font->getYOffsetFactor(); translatePos.z = 0; } else { @@ -382,9 +409,12 @@ void TextRenderer3DGl::render(const string &text, float x, float y, float size, } } + //glScalef(scale, scale, scale); glTranslatef(translatePos.x, translatePos.y, translatePos.z); - glScalef(scale, scale, scale); + font->getTextHandler()->Render(text.c_str()); + +/* if(Font::fontIsMultibyte == true) { if(font->getTextHandler() != NULL) { if(text.find("\n") == text.npos && text.find("\t") == text.npos) { @@ -532,6 +562,8 @@ void TextRenderer3DGl::render(const string &text, float x, float y, float size, } } } +*/ + glPopMatrix(); glPopAttrib(); diff --git a/source/shared_lib/sources/platform/common/platform_common.cpp b/source/shared_lib/sources/platform/common/platform_common.cpp index e097d2d4..4db73804 100644 --- a/source/shared_lib/sources/platform/common/platform_common.cpp +++ b/source/shared_lib/sources/platform/common/platform_common.cpp @@ -57,6 +57,7 @@ #include "randomgen.h" #include #include "platform_util.h" +#include "utf8.h" #include "leak_dumper.h" using namespace Shared::Platform; @@ -1934,6 +1935,33 @@ void copyFileTo(string fromFileName, string toFileName) { #endif } +bool valid_utf8_file(const char* file_name) { +#if defined(WIN32) && !defined(__MINGW32__) + wstring wstr = utf8_decode(file_name); + FILE *fp = _wfopen(wstr.c_str(), L"r"); + ifstream ifs(fp); +#else + ifstream ifs(file_name); +#endif + + if (!ifs) { + return false; // even better, throw here + } + istreambuf_iterator it(ifs.rdbuf()); + istreambuf_iterator eos; + + bool result = utf8::is_valid(it, eos); + + ifs.close(); +#if defined(WIN32) && !defined(__MINGW32__) + if(fp) { + fclose(fp); + } +#endif + + return result; +} + // ===================================== // ModeInfo // ===================================== diff --git a/source/shared_lib/sources/platform/unix/gl_wrap.cpp b/source/shared_lib/sources/platform/unix/gl_wrap.cpp index 54b52168..cdd86df7 100644 --- a/source/shared_lib/sources/platform/unix/gl_wrap.cpp +++ b/source/shared_lib/sources/platform/unix/gl_wrap.cpp @@ -41,12 +41,15 @@ void createGlFontBitmaps(uint32 &base, const string &type, int size, int width, } if(SystemFlags::VERBOSE_MODE_ENABLED) printf("About to try font [%s]\n",type.c_str()); + printf("About to try font [%s]\n",type.c_str()); + XFontStruct* fontInfo = XLoadQueryFont(display, type.c_str()); if(fontInfo == NULL) { string default_font = FontGl::getDefault_fontType(); //throw std::runtime_error("Font not found: [" + type + "]"); SystemFlags::OutputDebug(SystemFlags::debugError,"Font not found [%s] trying to fallback to [%s]\n",type.c_str(),default_font.c_str()); + printf("Font not found [%s] trying to fallback to [%s]\n",type.c_str(),default_font.c_str()); fontInfo = XLoadQueryFont(display, default_font.c_str()); if(fontInfo == NULL) { diff --git a/source/shared_lib/sources/util/conversion.cpp b/source/shared_lib/sources/util/conversion.cpp index ebca5c00..c89d3e85 100644 --- a/source/shared_lib/sources/util/conversion.cpp +++ b/source/shared_lib/sources/util/conversion.cpp @@ -27,11 +27,11 @@ namespace Shared{ namespace Util{ const int strSize = 256; -bool strToBool(const string &s){ - if (s=="0" || s=="false"){ +bool strToBool(const string &s) { + if(s=="0" || s=="false") { return false; } - if (s=="1" || s=="true"){ + if(s=="1" || s=="true") { return true; } throw runtime_error("Error converting string to bool, expected 0 or 1, found: [" + s + "]"); diff --git a/source/shared_lib/sources/util/properties.cpp b/source/shared_lib/sources/util/properties.cpp index 8ad1d485..433770bc 100644 --- a/source/shared_lib/sources/util/properties.cpp +++ b/source/shared_lib/sources/util/properties.cpp @@ -25,11 +25,21 @@ #include #endif +#include "utf8.h" +#include "font.h" + +//#include +//#include +//#include +//#include +#include "string_utils.h" + #include "leak_dumper.h" using namespace std; using namespace Shared::PlatformCommon; using namespace Shared::Platform; +using namespace Shared::Graphics; namespace Shared{ namespace Util{ @@ -39,42 +49,329 @@ string Properties::applicationPath = ""; // class Properties // ===================================================== +//wstring widen( const string& str ) +//{ +// wostringstream wstm ; +// wstm.imbue(std::locale("en_US.UTF-8")); +// const ctype& ctfacet = +// use_facet< ctype >( wstm.getloc() ) ; +// for( size_t i=0 ; i= 0xC0) +// { +// wchar_t c = ((byte)str[i++]) - 0xC0; +// while(((byte)str[i]) >= 0x80) +// c = (c << 6) | (((byte)str[i++]) - 0x80); +// --i; +// result[len++] = c; +// continue; +// } +// } +// result[len] = 0; +// return result; +//} + +//string conv_utf8_iso8859_7(string s) { +// int len = s.size(); +// string out = ""; +// string curr_char = ""; +// for(int i=0; i < len; i++) { +// curr_char = curr_char + s[i]; +// if( ( (s[i]) & (128+64) ) == 128) { +// //character end found +// if ( curr_char.size() == 2) { +// // 2-byte character check for it is greek one and convert +// if ((curr_char[0])==205) out = out + (char)(curr_char[1]+16); +// else if ((curr_char[0])==206) out = out + (char)(curr_char[1]+48); +// else if ((curr_char[0])==207) out = out + (char)(curr_char[1]+112); +// else ; // non greek 2-byte character, discard character +// } else ;// n-byte character, n>2, discard character +// curr_char = ""; +// } +// else if ((s[i]) < 128) { +// // character is one byte (ascii) +// out = out + curr_char; +// curr_char = ""; +// } +// } +// return out; +//} + +// Map from the most-significant 6 bits of the first byte to the total number of bytes in a +// UTF-8 character. +//static char UTF8_2_ISO_8859_1_len[] = +//{ +// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* erroneous */ +// 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 5, 6 +//}; +// +//static char UTF8_2_ISO_8859_1_mask[] = {0x3F, 0x7F, 0x1F, 0x0F, 0x07, +//0x03, 0x01}; + + +/*---------------------------------------------------------------------- +------- + Convert a UTF-8 string to a ISO-8859-1 MultiByte string. + No more than 'count' bytes will be written to the output buffer. + Return the size of the converted string in bytes, excl null +terminator. +*/ +//int ldap_x_utf8s_to_iso_8859_1s( char *mbstr, const char *utf8str, size_t count ) +//{ +// int res = 0; +// +// while (*utf8str != '\0') +// { +// int len = UTF8_2_ISO_8859_1_len[(*utf8str >> 2) & 0x3F]; +// unsigned long u = *utf8str & UTF8_2_ISO_8859_1_mask[len]; +// +// // erroneous +// if (len == 0) +// len = 5; +// +// for (++utf8str; --len > 0 && (*utf8str != '\0'); ++utf8str) +// { +// // be sure this is not an unexpected start of a new character +// if ((*utf8str & 0xC0) != 0x80) +// break; +// +// u = (u << 6) | (*utf8str & 0x3F); +// } +// +// if (mbstr != 0 && count != 0) +// { +// // be sure there is enough space left in the destination buffer +// if (res >= count) +// return res; +// +// // add the mapped character to the destination string or '?'(0x1A, SUB) if character +// // can't be represented in ISO-8859-1 +// *mbstr++ = (u <= 0xFF ? (char)u : '?'); +// } +// ++res; +// } +// +// // add the terminating null character +// if (mbstr != 0 && count != 0) +// { +// // be sure there is enough space left in the destination buffer +// if (res >= count) +// return res; +// *mbstr = 0; +// } +// +// return res; +//} // ldap_x_utf8s_to_iso_8859_1s +// +// +///*---------------------------------------------------------------------- +//------- +// Convert a ISO-8859-1 MultiByte string to a UTF-8 string. +// No more than 'count' bytes will be written to the output buffer. +// Return the size of the converted string in bytes, excl null +//terminator. +//*/ +//int ldap_x_iso_8859_1s_to_utf8s(char *utf8str, const char *mbstr, size_t count) +//{ +// int res = 0; +// +// // loop until we reach the end of the mb string +// for (; *mbstr != '\0'; ++mbstr) +// { +// // the character needs no mapping if the highest bit is not set +// if ((*mbstr & 0x80) == 0) +// { +// if (utf8str != 0 && count != 0) +// { +// // be sure there is enough space left in the destination buffer +// if (res >= count) +// return res; +// +// *utf8str++ = *mbstr; +// } +// ++res; +// } +// +// // otherwise mapping is necessary +// else +// { +// if (utf8str != 0 && count != 0) +// { +// // be sure there is enough space left in the destination buffer +// if (res+1 >= count) +// return res; +// +// *utf8str++ = (0xC0 | (0x03 & (*mbstr >> 6))); +// *utf8str++ = (0x80 | (0x3F & *mbstr)); +// } +// res += 2; +// } +// } +// +// // add the terminating null character +// if (utf8str != 0 && count != 0) +// { +// // be sure there is enough space left in the destination buffer +// if (res >= count) +// return res; +// *utf8str = 0; +// } +// +// return res; +//} // ldap_x_iso_8859_1s_to_utf8s + void Properties::load(const string &path, bool clearCurrentProperties) { + //wchar_t lineBuffer[maxLine]=L""; char lineBuffer[maxLine]=""; string line, key, value; size_t pos=0; this->path= path; + //std::locale::global(std::locale("")); + bool is_utf8_language = valid_utf8_file(path.c_str()); + #if defined(WIN32) && !defined(__MINGW32__) wstring wstr = utf8_decode(path); FILE *fp = _wfopen(wstr.c_str(), L"r"); + //wifstream fileStream(fp); ifstream fileStream(fp); #else + //wifstream fileStream; ifstream fileStream; fileStream.open(path.c_str(), ios_base::in); #endif if(fileStream.is_open() == false){ if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] path = [%s]\n",__FILE__,__FUNCTION__,__LINE__,path.c_str()); - throw runtime_error("Can't open propertyMap file: " + path); + throw runtime_error("File NOT FOUND, can't open file: [" + path + "]"); } if(clearCurrentProperties == true) { propertyMap.clear(); } - while(!fileStream.eof()){ + + while(fileStream.eof() == false) { + lineBuffer[0]='\0'; fileStream.getline(lineBuffer, maxLine); lineBuffer[maxLine-1]='\0'; - //printf("\n[%s]\n",lineBuffer); + + //printf("\n[%ls]\n",lineBuffer); + //printf("\n[%s]\n",&lineBuffer[0]); + + // If the file is NOT in UTF-8 format convert each line + if(is_utf8_language == false && Font::forceLegacyFonts == false) { + char *utfStr = String::ConvertToUTF8(&lineBuffer[0]); + + //printf("\nBefore [%s] After [%s]\n",&lineBuffer[0],utfStr); + + memset(&lineBuffer[0],0,maxLine); + memcpy(&lineBuffer[0],&utfStr[0],strlen(utfStr)); + } + + //if(is_utf8_language == true && Font::forceLegacyFonts == true) { + //string line = lineBuffer; + //wstring wstr = fromUtf8(line.c_str(), line.size()); + + //vector utf16result; + //utf8::utf8to16(line.begin(), line.end(), back_inserter(utf16result)); + //vector utf16result; + //utf8::utf8to32(line.begin(), line.end(), back_inserter(utf16result)); + + //printf("\nConverted UTF-8 from [%s] to [%s]\n",line.c_str(),utf16result[0]); + + //char newBuf[4097]=""; + //int newSize = ldap_x_utf8s_to_iso_8859_1s( &newBuf[0], line.c_str(), 4096 ); + + //std::wstring wstr = widen(newBuf); + //String st(wstr.c_str()); + //String st(line.c_str()); + + //printf("\nConverted UTF-8 from [%s] to [%ls]\n",line.c_str(),wstr.c_str()); + + //const wchar_t *wBuf = &szPath[0]; + //setlocale(LC_ALL, "en_CA.ISO-8559-15"); + //std::locale::global(std::locale("en_CA.ISO-8559-15")); + //size_t size = 4096; + //char pMBBuffer[4096 + 1]=""; + //wcstombs(&pMBBuffer[0], &lineBuffer[0], (size_t)size);// Convert to char* from TCHAR[] + //string newStr=""; + //newStr.assign(&pMBBuffer[0]); // Now assign the char* to the string, and there you have it!!! :) + //printf("\nConverted UTF-8 from [%ls] to [%s]\n",&lineBuffer[0],newStr.c_str()); + //std::locale::global(std::locale("")); + + //char newBuf[4097]=""; + //int newSize = ldap_x_utf8s_to_iso_8859_1s( &newBuf[0], &pMBBuffer[0], 4096 ); + + //String st(&lineBuffer[0]); + //printf("\nConverted UTF-8 from [%ls] to [%s]\n",&lineBuffer[0],&newBuf[0]); + + //char newBuf[4097]=""; + //int newSize = ldap_x_utf8s_to_iso_8859_1s( &newBuf[0], line.c_str(), 4096 ); + + //string newStr = conv_utf8_iso8859_7(line); + //printf("\nConverted UTF-8 from [%s] to [%s]\n",line.c_str(),newBuf); +// for(int i = 0; i < line.size(); ++i) { +// printf("to [%c][%d]\n",line[i],line[i]); +// } + //for(int i = 0; i < newStr.size(); ++i) { + // printf("to [%c][%d]\n",newStr[i],newStr[i]); + //} + +// for(int i = 0; i < utf16result.size(); ++i) { +// printf("to [%c]\n",utf16result[i]); +// } +// + //memset(&lineBuffer[0],0,maxLine); + //memcpy(&lineBuffer[0],&newBuf[0],newSize); + //} + //else { + //string line = lineBuffer; + //printf("\nNON UTF-8 from [%s]\n",line.c_str()); + //for(int i = 0; i < line.size(); ++i) { + // printf("to [%c][%d]\n",line[i],line[i]); + //} + //} //process line if it it not a comment - if(lineBuffer[0]!=';'){ + if(lineBuffer[0] != ';') { + //wstring wstr = lineBuffer; + //line.assign(wstr.begin(),wstr.end()); // gracefully handle win32 \r\n line endings size_t len= strlen(lineBuffer); - if(len > 0 && lineBuffer[len-1] == '\r'){ - lineBuffer[len-1]= 0; + if(len > 0 && lineBuffer[len-1] == '\r') { + lineBuffer[len-1]= 0; } line= lineBuffer; diff --git a/source/shared_lib/sources/util/string_utils.cpp b/source/shared_lib/sources/util/string_utils.cpp new file mode 100644 index 00000000..94ac0261 --- /dev/null +++ b/source/shared_lib/sources/util/string_utils.cpp @@ -0,0 +1,694 @@ +/* TA3D, a remake of Total Annihilation + Copyright (C) 2005 Roland BROCHARD + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA*/ + +//#include "../stdafx.h" +#include "string_utils.h" + +#if TA3D_USE_BOOST == 1 +# include +# include +# include +#else +# include +#endif + +#include +//#include "../logs/logs.h" + + +namespace Shared { namespace Util { + + #if TA3D_USE_BOOST != 1 + namespace + { + int stdLowerCase (int c) + { + return tolower(c); + } + + int stdUpperCase (int c) + { + return toupper(c); + } + } + #endif + + String& + String::operator << (const wchar_t* v) + { + size_t l = wcslen(v); + char* b = new char[l + 1]; + #ifndef WINDOWS + wcstombs(&b[0], v, l); + #else + size_t i; + wcstombs_s(&i, &b[0], l, v, l); + #endif + append(b); + delete b; + return *this; + } + + String& + String::toLower() + { + #if TA3D_USE_BOOST == 1 + boost::to_lower(*this); + #else + std::transform (this->begin(), this->end(), this->begin(), stdLowerCase); + #endif + return *this; + } + + String& + String::toUpper() + { + #if TA3D_USE_BOOST == 1 + boost::to_upper(*this); + #else + std::transform (this->begin(), this->end(), this->begin(), stdUpperCase); + #endif + return *this; + } + + + bool String::toBool() const + { + if (empty() || "0" == *this) + return false; + if ("1" == *this) + return true; + String s(*this); + s.toLower(); + return ("true" == s || "on" == s); + } + + + String& + String::trim(const String& trimChars) + { + // Find the first character position after excluding leading blank spaces + std::string::size_type startpos = this->find_first_not_of(trimChars); + // Find the first character position from reverse af + std::string::size_type endpos = this->find_last_not_of(trimChars); + + // if all spaces or empty return an empty string + if ((std::string::npos == startpos) || (std::string::npos == endpos)) + *this = ""; + else + *this = this->substr(startpos, endpos - startpos + 1); + return *this; + } + + void + String::split(String::Vector& out, const String& separators, const bool emptyBefore) const + { + // Empty the container + if (emptyBefore) + out.clear(); + #if TA3D_USE_BOOST == 1 + // TODO : Avoid string duplication + // Split + std::vector v; + boost::algorithm::split(v, *this, boost::is_any_of(separators.c_str())); + // Copying + for(std::vector::const_iterator i = v.begin(); i != v.end(); ++i) + out.push_back(*i); + #else + // TODO This method should be rewritten for better performance + String s(*this); + while (!s.empty()) + { + String::size_type i = s.find_first_of(separators); + if (i == std::string::npos) + { + out.push_back(String::Trim(s)); + return; + } + else + { + out.push_back(String::Trim(s.substr(0, i))); + s = s.substr(i + 1, s.size() - i - 1); + } + } + #endif + } + + void + String::split(String::List& out, const String& separators, const bool emptyBefore) const + { + // Empty the container + if (emptyBefore) + out.clear(); + #if TA3D_USE_BOOST == 1 + // TODO : Avoid string duplication + // Split + std::vector v; + boost::algorithm::split(v, *this, boost::is_any_of(separators.c_str())); + // Copying + for(std::vector::const_iterator i = v.begin(); i != v.end(); ++i) + out.push_back(*i); + #else + // TODO This method should be rewritten for better performance + String s(*this); + while (!s.empty()) + { + String::size_type i = s.find_first_of(separators); + if (i == std::string::npos) + { + out.push_back(String::Trim(s)); + return; + } + else + { + out.push_back(String::Trim(s.substr(0, i))); + s = s.substr(i + 1, s.size() - i - 1); + } + } + #endif + } + + + void String::ToKeyValue(const String& s, String& key, String& value, const enum String::CharCase chcase) + { + // The first usefull character + String::size_type pos = s.find_first_not_of(TA3D_WSTR_SEPARATORS); + if (pos == String::npos) + { + // The string is empty + key.clear(); + value.clear(); + return; + } + // Begining of a section + if (s[pos] == '[') + { + key = "["; + pos = s.find_first_not_of(TA3D_WSTR_SEPARATORS, pos + 1); + String::size_type end = s.find_first_of(']', pos); + if (end != String::npos) + { + end = s.find_last_not_of(TA3D_WSTR_SEPARATORS, end - 1); + if (pos != String::npos && end != String::npos) + value = s.substr(pos, end - pos + 1); + } + return; + } + // The first `=` character + String::size_type equal = s.find_first_of('=', pos); + if (equal == String::npos) + { + // otherwise it is only a string + value.clear(); + // But it may be a comment + String::size_type slashes = s.find("//", pos); + if (pos == slashes) + { + key.clear(); + return; + } + String::size_type end = s.find_last_not_of(TA3D_WSTR_SEPARATORS, slashes - 1); + key = s.substr(pos, end - pos + 1); + return; + } + + // We can extract our key + String::size_type end = s.find_last_not_of(TA3D_WSTR_SEPARATORS, equal - 1); + key = s.substr(pos, 1 + end - pos); + String::size_type slashes = key.rfind("//"); + // Remove any comments + if (slashes != String::npos) + { + value.clear(); + if (slashes == 0) // the key is a comment actually + key.clear(); + else + { + // Get only the good part + slashes = key.find_last_not_of(TA3D_WSTR_SEPARATORS, slashes - 1); + key = key.substr(0, slashes + 1); + if (chcase == soIgnoreCase) + key.toLower(); + } + return; + } + if (chcase == soIgnoreCase) + key.toLower(); + + // Left-Trim for the value + equal = s.find_first_not_of(TA3D_WSTR_SEPARATORS, equal + 1); + if (String::npos == equal) + { + value.clear(); + return; + } + + // Looking for the first semicolon + bool needReplaceSemicolons(false); + String::size_type semicolon = s.find_first_of(';', equal); + while (semicolon != String::npos && s[semicolon - 1] == '\\') + { + semicolon = s.find_first_of(';', semicolon + 1); + needReplaceSemicolons = true; + } + if (semicolon == String::npos) + { + // if none is present, looks for a comment to strip it + slashes = s.find("//", equal); + slashes = s.find_last_not_of(TA3D_WSTR_SEPARATORS, slashes - 1); + value = s.substr(equal, 1 + slashes - equal); + value.findAndReplace("\\r", "", soCaseSensitive); + value.findAndReplace("\\n", "\n", soCaseSensitive); + if (needReplaceSemicolons) + value.findAndReplace("\\;", ";", soCaseSensitive); + return; + } + // Remove spaces before the semicolon and after the `=` + semicolon = s.find_last_not_of(TA3D_WSTR_SEPARATORS, semicolon - 1); + + // We can extract the value + if (semicolon >= equal) + { + value = s.substr(equal, 1 + semicolon - equal); + value.findAndReplace("\\r", "", soCaseSensitive); + value.findAndReplace("\\n", "\n", soCaseSensitive); + if (needReplaceSemicolons) + value.findAndReplace("\\;", ";", soCaseSensitive); + } + else + value.clear(); + } + + + String& String::convertAntiSlashesIntoSlashes() + { + for (String::iterator i = this->begin(); i != this->end(); ++i) + { + if (*i == '\\') + *i = '/'; + } + return *this; + } + + String& String::convertSlashesIntoAntiSlashes() + { + for (String::iterator i = this->begin(); i != this->end(); ++i) + { + if (*i == '/') + *i = '\\'; + } + return *this; + } + + uint32 String::hashValue() const + { + uint32 hash = 0; + for (String::const_iterator i = this->begin(); i != this->end(); ++i) + hash = (hash << 5) - hash + *i; + return hash; + } + + int String::FindInList(const String::Vector& l, const char* s) + { + int indx(0); + for (String::Vector::const_iterator i = l.begin(); i != l.end(); ++i, ++indx) + { + if(s == *i) + return indx; + } + return -1; + } + + + int String::FindInList(const String::Vector& l, const String& s) + { + int indx(0); + for (String::Vector::const_iterator i = l.begin(); i != l.end(); ++i, ++indx) + { + if(s == *i) + return indx; + } + return -1; + } + + + char* String::ConvertToUTF8(const char* s) + { + if (NULL != s && *s != '\0') + return ConvertToUTF8(s, strlen(s)); + char* ret = new char[1]; + //LOG_ASSERT(NULL != ret); + assert(NULL != ret); + *ret = '\0'; + return ret; + } + + char* String::ConvertToUTF8(const char* s, const uint32 len) + { + uint32 nws; + return ConvertToUTF8(s, len, nws); + } + + int String::ASCIItoUTF8(const byte c, byte *out) { + if (c < 0x80) + { + *out = c; + return 1; + } + else if(c < 0xC0) + { + out[0] = 0xC2; + out[1] = c; + return 2; + } + out[0] = 0xC3; + out[1] = c - 0x40; + return 2; + } + + char* String::ConvertToUTF8(const char* s, uint32 len, uint32& newSize) + { + if (NULL == s || '\0' == *s) + { + char* ret = new char[1]; + //LOG_ASSERT(NULL != ret); + assert(NULL != ret); + *ret = '\0'; + return ret; + } + byte tmp[4]; + newSize = 1; + for(byte *p = (byte*)s ; *p ; p++) + newSize += ASCIItoUTF8(*p, tmp); + + char* ret = new char[newSize]; + //LOG_ASSERT(NULL != ret); + assert(NULL != ret); + + byte *q = (byte*)ret; + for(byte *p = (byte*)s ; *p ; p++) + q += ASCIItoUTF8(*p, q); + *q = '\0'; // A bit paranoid + return ret; + } + + + String String::ConvertToUTF8(const String& s) + { + if (s.empty()) + return String(); + char* ret = ConvertToUTF8(s.c_str(), s.size()); + if (ret) + { + String s(ret); // TODO Find a way to not use a temporary string + delete[] ret; + return s; + } + return String(); + } + + + String& String::findAndReplace(char toSearch, const char replaceWith, const enum String::CharCase option) + { + if (option == soIgnoreCase) + { + toSearch = tolower(toSearch); + for (String::iterator i = this->begin(); i != this->end(); ++i) + { + if (tolower(*i) == toSearch) + *i = replaceWith; + } + } + else + { + for (String::iterator i = this->begin(); i != this->end(); ++i) + { + if (*i == toSearch) + *i = replaceWith; + } + + } + return *this; + } + + + String& String::findAndReplace(const String& toSearch, const String& replaceWith, const enum String::CharCase option) + { + if (soCaseSensitive == option) + { + String::size_type p = 0; + String::size_type siz = toSearch.size(); + while ((p = this->find(toSearch, p)) != String::npos) + this->replace(p, siz, replaceWith); + } + else + { + *this = String::ToLower(*this).findAndReplace(String::ToLower(toSearch), replaceWith, soCaseSensitive); + } + return *this; + } + + + String& String::format(const String& f, ...) + { + va_list parg; + va_start(parg, f); + + this->clear(); + vappendFormat(f.c_str(), parg); + + va_end(parg); + return *this; + } + + + String& String::format(const char* f, ...) + { + va_list parg; + va_start(parg, f); + + this->clear(); + vappendFormat(f, parg); + + va_end(parg); + return *this; + } + + + String& String::appendFormat(const String& f, ...) + { + va_list parg; + va_start(parg, f); + + vappendFormat(f.c_str(), parg); + + va_end(parg); + return *this; + } + + + String& String::appendFormat(const char* f, ...) + { + va_list parg; + va_start(parg, f); + + vappendFormat(f, parg); + + va_end(parg); + return *this; + } + + + String& String::vappendFormat(const char* f, va_list parg) + { + char* b; +#if defined TA3D_PLATFORM_WINDOWS + // Implement vasprintf() by hand with two calls to vsnprintf() + // Remove this when Microsoft adds support for vasprintf() +#if defined TA3D_PLATFORM_MSVC + int sizeneeded = _vsnprintf(NULL, 0, f, parg) + 1; +#else + int sizeneeded = vsnprintf(NULL, 0, f, parg) + 1; +#endif + if (sizeneeded < 0) + { + return *this; + } + b = new char[sizeneeded]; + if (b == NULL) + { + return *this; + } +#if defined TA3D_PLATFORM_MSVC + if (_vsnprintf(b, sizeneeded, f, parg) < 0) +#else + if (vsnprintf(b, sizeneeded, f, parg) < 0) +#endif + { + delete[] b; + return *this; + } +#else + if (vasprintf(&b, f, parg) < 0) + { + return *this; + } +#endif + this->append(b); + delete[] b; + return *this; + } + + + String String::Format(const String& f, ...) + { + va_list parg; + va_start(parg, f); + + String s; + s.vappendFormat(f.c_str(), parg); + + va_end(parg); + return s; + } + + String String::Format(const char* f, ...) + { + va_list parg; + va_start(parg, f); + + String s; + s.vappendFormat(f, parg); + + va_end(parg); + return s; + } + + bool String::match(const String &pattern) + { + if (pattern.empty()) + return empty(); + + int e = 0; + int prev = -1; + for(int i = 0 ; i < size() ; i++) + if (pattern[e] == '*') + { + if (e + 1 == pattern.size()) + return true; + while(pattern[e+1] == '*') e++; + if (e + 1 == pattern.size()) + return true; + + prev = e; + if (pattern[e+1] == (*this)[i]) + e+=2; + } + else if(pattern[e] == (*this)[i]) + e++; + else if(prev >= 0) + e = prev; + else + return false; + return e == pattern.size(); + } + + String String::substrUTF8(int pos, int len) const + { + if (len < 0) + len = sizeUTF8() - len + 1 - pos; + String res; + int utf8_pos = 0; + for(; pos > 0 ; pos--) + if (((byte)(*this)[utf8_pos]) >= 0xC0) + { + utf8_pos++; + while (((byte)(*this)[utf8_pos]) >= 0x80 && ((byte)(*this)[utf8_pos]) < 0xC0) + utf8_pos++; + } + else + utf8_pos++; + + for(; len > 0 ; len--) + { + if (((byte)(*this)[utf8_pos]) >= 0x80) + { + res << (char)(*this)[utf8_pos]; + utf8_pos++; + while (((byte)(*this)[utf8_pos]) >= 0x80 && ((byte)(*this)[utf8_pos]) < 0xC0) + { + res << (char)(*this)[utf8_pos]; + utf8_pos++; + } + } + else + { + res << ((char)(*this)[utf8_pos]); + utf8_pos++; + } + } + return res; + } + + int String::sizeUTF8() const + { + int len = 0; + for(int i = 0 ; i < this->size() ; i++) + if (((byte)(*this)[i]) >= 0xC0 || ((byte)(*this)[i]) < 0x80) + len++; + return len; + } + + WString::WString(const char* s) + { + if (s) + fromUtf8(s, strlen(s)); + else + pBuffer[0] = 0; + } + + WString::WString(const String& s) + { + fromUtf8(s.c_str(), s.size()); + } + + + + void WString::fromUtf8(const char* str, size_t length) + { + int len = 0; + for(int i = 0 ; i < length; i++) + { + if (((byte)str[i]) < 0x80) + { + pBuffer[len++] = ((byte)str[i]); + continue; + } + if (((byte)str[i]) >= 0xC0) + { + wchar_t c = ((byte)str[i++]) - 0xC0; + while(((byte)str[i]) >= 0x80) + c = (c << 6) | (((byte)str[i++]) - 0x80); + --i; + pBuffer[len++] = c; + continue; + } + } + pBuffer[len] = 0; + } + +}}