mirror of
https://github.com/vcmi/vcmi.git
synced 2025-01-12 02:28:11 +02:00
renamed Unicode -> TextOperations, to use for all text processing
This commit is contained in:
parent
65c020ef34
commit
acdb8d6e06
21
Global.h
21
Global.h
@ -730,28 +730,7 @@ namespace vstd
|
|||||||
return a + (b - a) * f;
|
return a + (b - a) * f;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// converts number into string using metric system prefixes, e.g. 'k' or 'M' to keep resulting strings within specified size
|
|
||||||
/// Note that resulting string may have more symbols than digits: minus sign and prefix symbol
|
|
||||||
template<typename Arithmetic>
|
|
||||||
std::string formatMetric(Arithmetic number, int maxDigits)
|
|
||||||
{
|
|
||||||
Arithmetic max = std::pow(10, maxDigits);
|
|
||||||
if (std::abs(number) < max)
|
|
||||||
return std::to_string(number);
|
|
||||||
|
|
||||||
std::string symbols = " kMGTPE";
|
|
||||||
auto iter = symbols.begin();
|
|
||||||
|
|
||||||
while (std::abs(number) >= max)
|
|
||||||
{
|
|
||||||
number /= 1000;
|
|
||||||
iter++;
|
|
||||||
|
|
||||||
assert(iter != symbols.end());//should be enough even for int64
|
|
||||||
}
|
|
||||||
return std::to_string(number) + *iter;
|
|
||||||
}
|
|
||||||
|
|
||||||
///compile-time version of std::abs for ints for int3, in clang++15 std::abs is constexpr
|
///compile-time version of std::abs for ints for int3, in clang++15 std::abs is constexpr
|
||||||
static constexpr int abs(int i) {
|
static constexpr int abs(int i) {
|
||||||
if(i < 0) return -i;
|
if(i < 0) return -i;
|
||||||
|
@ -127,7 +127,7 @@ void CInGameConsole::keyPressed (const SDL_Keycode & key)
|
|||||||
{
|
{
|
||||||
if(enteredText.size() > 1)
|
if(enteredText.size() > 1)
|
||||||
{
|
{
|
||||||
Unicode::trimRight(enteredText,2);
|
TextOperations::trimRightUnicode(enteredText,2);
|
||||||
enteredText += '_';
|
enteredText += '_';
|
||||||
refreshEnteredText();
|
refreshEnteredText();
|
||||||
}
|
}
|
||||||
|
@ -47,6 +47,7 @@
|
|||||||
#include "../../lib/StartInfo.h"
|
#include "../../lib/StartInfo.h"
|
||||||
#include "../../lib/CondSh.h"
|
#include "../../lib/CondSh.h"
|
||||||
#include "../../lib/mapObjects/CGTownInstance.h"
|
#include "../../lib/mapObjects/CGTownInstance.h"
|
||||||
|
#include "../../lib/TextOperations.h"
|
||||||
|
|
||||||
void BattleConsole::showAll(SDL_Surface * to)
|
void BattleConsole::showAll(SDL_Surface * to)
|
||||||
{
|
{
|
||||||
@ -717,7 +718,7 @@ void StackQueue::StackBox::setUnit(const battle::Unit * unit, size_t turn)
|
|||||||
if (unit->unitType()->idNumber == CreatureID::ARROW_TOWERS)
|
if (unit->unitType()->idNumber == CreatureID::ARROW_TOWERS)
|
||||||
icon->setFrame(owner->getSiegeShooterIconID(), 1);
|
icon->setFrame(owner->getSiegeShooterIconID(), 1);
|
||||||
|
|
||||||
amount->setText(vstd::formatMetric(unit->getCount(), 4));
|
amount->setText(TextOperations::formatMetric(unit->getCount(), 4));
|
||||||
|
|
||||||
if(stateIcon)
|
if(stateIcon)
|
||||||
{
|
{
|
||||||
|
@ -36,6 +36,7 @@
|
|||||||
#include "../../lib/CGameState.h"
|
#include "../../lib/CGameState.h"
|
||||||
#include "../../lib/CStack.h"
|
#include "../../lib/CStack.h"
|
||||||
#include "../../lib/CondSh.h"
|
#include "../../lib/CondSh.h"
|
||||||
|
#include "../../lib/TextOperations.h"
|
||||||
|
|
||||||
static void onAnimationFinished(const CStack *stack, std::weak_ptr<CreatureAnimation> anim)
|
static void onAnimationFinished(const CStack *stack, std::weak_ptr<CreatureAnimation> anim)
|
||||||
{
|
{
|
||||||
@ -316,7 +317,7 @@ void BattleStacksController::showStackAmountBox(Canvas & canvas, const CStack *
|
|||||||
//blitting amount
|
//blitting amount
|
||||||
Point textPos = stackAnimation[stack->ID]->pos.topLeft() + amountBG->dimensions()/2 + Point(xAdd, yAdd);
|
Point textPos = stackAnimation[stack->ID]->pos.topLeft() + amountBG->dimensions()/2 + Point(xAdd, yAdd);
|
||||||
|
|
||||||
canvas.drawText(textPos, EFonts::FONT_TINY, Colors::WHITE, ETextAlignment::CENTER, vstd::formatMetric(stack->getCount(), 4));
|
canvas.drawText(textPos, EFonts::FONT_TINY, Colors::WHITE, ETextAlignment::CENTER, TextOperations::formatMetric(stack->getCount(), 4));
|
||||||
}
|
}
|
||||||
|
|
||||||
void BattleStacksController::showStack(Canvas & canvas, const CStack * stack)
|
void BattleStacksController::showStack(Canvas & canvas, const CStack * stack)
|
||||||
|
@ -19,7 +19,7 @@ size_t IFont::getStringWidth(const std::string & data) const
|
|||||||
{
|
{
|
||||||
size_t width = 0;
|
size_t width = 0;
|
||||||
|
|
||||||
for(size_t i=0; i<data.size(); i += Unicode::getCharacterSize(data[i]))
|
for(size_t i=0; i<data.size(); i += TextOperations::getUnicodeCharacterSize(data[i]))
|
||||||
{
|
{
|
||||||
width += getGlyphWidth(data.data() + i);
|
width += getGlyphWidth(data.data() + i);
|
||||||
}
|
}
|
||||||
|
@ -55,7 +55,7 @@ size_t CBitmapFont::getLineHeight() const
|
|||||||
|
|
||||||
size_t CBitmapFont::getGlyphWidth(const char * data) const
|
size_t CBitmapFont::getGlyphWidth(const char * data) const
|
||||||
{
|
{
|
||||||
std::string localChar = Unicode::fromUnicode(std::string(data, Unicode::getCharacterSize(data[0])));
|
std::string localChar = TextOperations::fromUnicode(std::string(data, TextOperations::getUnicodeCharacterSize(data[0])));
|
||||||
|
|
||||||
if (localChar.size() == 1)
|
if (localChar.size() == 1)
|
||||||
{
|
{
|
||||||
@ -131,9 +131,9 @@ void CBitmapFont::renderText(SDL_Surface * surface, const std::string & data, co
|
|||||||
|
|
||||||
SDL_LockSurface(surface);
|
SDL_LockSurface(surface);
|
||||||
|
|
||||||
for(size_t i=0; i<data.size(); i += Unicode::getCharacterSize(data[i]))
|
for(size_t i=0; i<data.size(); i += TextOperations::getUnicodeCharacterSize(data[i]))
|
||||||
{
|
{
|
||||||
std::string localChar = Unicode::fromUnicode(data.substr(i, Unicode::getCharacterSize(data[i])));
|
std::string localChar = TextOperations::fromUnicode(data.substr(i, TextOperations::getUnicodeCharacterSize(data[i])));
|
||||||
|
|
||||||
if (localChar.size() == 1)
|
if (localChar.size() == 1)
|
||||||
renderCharacter(surface, chars[ui8(localChar[0])], color, posX, posY);
|
renderCharacter(surface, chars[ui8(localChar[0])], color, posX, posY);
|
||||||
|
@ -83,9 +83,9 @@ void CBitmapHanFont::renderText(SDL_Surface * surface, const std::string & data,
|
|||||||
|
|
||||||
SDL_LockSurface(surface);
|
SDL_LockSurface(surface);
|
||||||
|
|
||||||
for(size_t i=0; i<data.size(); i += Unicode::getCharacterSize(data[i]))
|
for(size_t i=0; i<data.size(); i += TextOperations::getUnicodeCharacterSize(data[i]))
|
||||||
{
|
{
|
||||||
std::string localChar = Unicode::fromUnicode(data.substr(i, Unicode::getCharacterSize(data[i])));
|
std::string localChar = TextOperations::fromUnicode(data.substr(i, TextOperations::getUnicodeCharacterSize(data[i])));
|
||||||
|
|
||||||
if (localChar.size() == 1)
|
if (localChar.size() == 1)
|
||||||
fallback->renderCharacter(surface, fallback->chars[ui8(localChar[0])], color, posX, posY);
|
fallback->renderCharacter(surface, fallback->chars[ui8(localChar[0])], color, posX, posY);
|
||||||
@ -115,7 +115,7 @@ size_t CBitmapHanFont::getLineHeight() const
|
|||||||
|
|
||||||
size_t CBitmapHanFont::getGlyphWidth(const char * data) const
|
size_t CBitmapHanFont::getGlyphWidth(const char * data) const
|
||||||
{
|
{
|
||||||
std::string localChar = Unicode::fromUnicode(std::string(data, Unicode::getCharacterSize(data[0])));
|
std::string localChar = TextOperations::fromUnicode(std::string(data, TextOperations::getUnicodeCharacterSize(data[0])));
|
||||||
|
|
||||||
if (localChar.size() == 1)
|
if (localChar.size() == 1)
|
||||||
return fallback->getGlyphWidth(data);
|
return fallback->getGlyphWidth(data);
|
||||||
|
@ -66,7 +66,7 @@ size_t CTrueTypeFont::getLineHeight() const
|
|||||||
|
|
||||||
size_t CTrueTypeFont::getGlyphWidth(const char *data) const
|
size_t CTrueTypeFont::getGlyphWidth(const char *data) const
|
||||||
{
|
{
|
||||||
return getStringWidth(std::string(data, Unicode::getCharacterSize(*data)));
|
return getStringWidth(std::string(data, TextOperations::getUnicodeCharacterSize(*data)));
|
||||||
/*
|
/*
|
||||||
int advance;
|
int advance;
|
||||||
TTF_GlyphMetrics(font.get(), *data, nullptr, nullptr, nullptr, nullptr, &advance);
|
TTF_GlyphMetrics(font.get(), *data, nullptr, nullptr, nullptr, nullptr, &advance);
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
#include "../../lib/CGeneralTextHandler.h"
|
#include "../../lib/CGeneralTextHandler.h"
|
||||||
#include "../../lib/CCreatureHandler.h"
|
#include "../../lib/CCreatureHandler.h"
|
||||||
#include "../../lib/mapObjects/CGHeroInstance.h"
|
#include "../../lib/mapObjects/CGHeroInstance.h"
|
||||||
|
#include "../../lib/TextOperations.h"
|
||||||
|
|
||||||
#include "../../lib/CGameState.h"
|
#include "../../lib/CGameState.h"
|
||||||
|
|
||||||
@ -374,7 +375,7 @@ void CGarrisonSlot::update()
|
|||||||
creatureImage->setFrame(creature->getIconIndex());
|
creatureImage->setFrame(creature->getIconIndex());
|
||||||
|
|
||||||
stackCount->enable();
|
stackCount->enable();
|
||||||
stackCount->setText(vstd::formatMetric(myStack->count, 4));
|
stackCount->setText(TextOperations::formatMetric(myStack->count, 4));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -24,12 +24,13 @@
|
|||||||
|
|
||||||
#include "../../CCallback.h"
|
#include "../../CCallback.h"
|
||||||
|
|
||||||
#include "../../lib/mapObjects/CGHeroInstance.h"
|
#include "../../lib/CConfigHandler.h"
|
||||||
#include "../../lib/mapObjects/CGTownInstance.h"
|
#include "../../lib/CGameState.h"
|
||||||
#include "../../lib/CGeneralTextHandler.h"
|
#include "../../lib/CGeneralTextHandler.h"
|
||||||
#include "../../lib/CModHandler.h"
|
#include "../../lib/CModHandler.h"
|
||||||
#include "../../lib/CGameState.h"
|
#include "../../lib/TextOperations.h"
|
||||||
#include "../../lib/CConfigHandler.h"
|
#include "../../lib/mapObjects/CGHeroInstance.h"
|
||||||
|
#include "../../lib/mapObjects/CGTownInstance.h"
|
||||||
|
|
||||||
void CHoverableArea::hover (bool on)
|
void CHoverableArea::hover (bool on)
|
||||||
{
|
{
|
||||||
@ -251,7 +252,7 @@ void CArmyTooltip::init(const InfoAboutArmy &army)
|
|||||||
std::string subtitle;
|
std::string subtitle;
|
||||||
if(army.army.isDetailed)
|
if(army.army.isDetailed)
|
||||||
{
|
{
|
||||||
subtitle = vstd::formatMetric(slot.second.count, 4);
|
subtitle = TextOperations::formatMetric(slot.second.count, 4);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -570,12 +570,12 @@ void CTextInput::keyPressed(const SDL_Keycode & key)
|
|||||||
case SDLK_BACKSPACE:
|
case SDLK_BACKSPACE:
|
||||||
if(!newText.empty())
|
if(!newText.empty())
|
||||||
{
|
{
|
||||||
Unicode::trimRight(newText);
|
TextOperations::trimRightUnicode(newText);
|
||||||
redrawNeeded = true;
|
redrawNeeded = true;
|
||||||
}
|
}
|
||||||
else if(!text.empty())
|
else if(!text.empty())
|
||||||
{
|
{
|
||||||
Unicode::trimRight(text);
|
TextOperations::trimRightUnicode(text);
|
||||||
redrawNeeded = true;
|
redrawNeeded = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
#include "../../lib/CModHandler.h"
|
#include "../../lib/CModHandler.h"
|
||||||
#include "../../lib/CHeroHandler.h"
|
#include "../../lib/CHeroHandler.h"
|
||||||
#include "../../lib/CGameState.h"
|
#include "../../lib/CGameState.h"
|
||||||
|
#include "../../lib/TextOperations.h"
|
||||||
|
|
||||||
class CCreatureArtifactInstance;
|
class CCreatureArtifactInstance;
|
||||||
class CSelectableSkill;
|
class CSelectableSkill;
|
||||||
@ -582,7 +583,7 @@ CStackWindow::MainSection::MainSection(CStackWindow * owner, int yOffset, bool s
|
|||||||
}
|
}
|
||||||
expLabel = std::make_shared<CLabel>(
|
expLabel = std::make_shared<CLabel>(
|
||||||
pos.x + 21, pos.y + 52, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE,
|
pos.x + 21, pos.y + 52, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE,
|
||||||
vstd::formatMetric(stack->experience, 6));
|
TextOperations::formatMetric(stack->experience, 6));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(showArt)
|
if(showArt)
|
||||||
|
@ -133,7 +133,7 @@ std::vector<std::string> CMessage::breakText( std::string text, size_t maxLineWi
|
|||||||
// loops till line is full or end of text reached
|
// loops till line is full or end of text reached
|
||||||
while(currPos < text.length() && text[currPos] != 0x0a && lineWidth < maxLineWidth)
|
while(currPos < text.length() && text[currPos] != 0x0a && lineWidth < maxLineWidth)
|
||||||
{
|
{
|
||||||
symbolSize = Unicode::getCharacterSize(text[currPos]);
|
symbolSize = TextOperations::getUnicodeCharacterSize(text[currPos]);
|
||||||
glyphWidth = graphics->fonts[font]->getGlyphWidth(text.data() + currPos);
|
glyphWidth = graphics->fonts[font]->getGlyphWidth(text.data() + currPos);
|
||||||
|
|
||||||
// candidate for line break
|
// candidate for line break
|
||||||
|
@ -63,6 +63,7 @@
|
|||||||
#include "../lib/mapping/CMap.h"
|
#include "../lib/mapping/CMap.h"
|
||||||
#include "../lib/NetPacksBase.h"
|
#include "../lib/NetPacksBase.h"
|
||||||
#include "../lib/StartInfo.h"
|
#include "../lib/StartInfo.h"
|
||||||
|
#include "../lib/TextOperations.h"
|
||||||
|
|
||||||
#include <SDL_surface.h>
|
#include <SDL_surface.h>
|
||||||
|
|
||||||
@ -1066,8 +1067,8 @@ void CExchangeWindow::updateWidgets()
|
|||||||
secSkillIcons[leftRight][m]->setFrame(2 + id * 3 + level);
|
secSkillIcons[leftRight][m]->setFrame(2 + id * 3 + level);
|
||||||
}
|
}
|
||||||
|
|
||||||
expValues[leftRight]->setText(vstd::formatMetric(hero->exp, 3));
|
expValues[leftRight]->setText(TextOperations::formatMetric(hero->exp, 3));
|
||||||
manaValues[leftRight]->setText(vstd::formatMetric(hero->mana, 3));
|
manaValues[leftRight]->setText(TextOperations::formatMetric(hero->mana, 3));
|
||||||
|
|
||||||
morale[leftRight]->set(hero);
|
morale[leftRight]->set(hero);
|
||||||
luck[leftRight]->set(hero);
|
luck[leftRight]->set(hero);
|
||||||
|
@ -188,9 +188,9 @@ std::string CLegacyConfigParser::readString()
|
|||||||
{
|
{
|
||||||
// do not convert strings that are already in ASCII - this will only slow down loading process
|
// do not convert strings that are already in ASCII - this will only slow down loading process
|
||||||
std::string str = readRawString();
|
std::string str = readRawString();
|
||||||
if (Unicode::isValidASCII(str))
|
if (TextOperations::isValidASCII(str))
|
||||||
return str;
|
return str;
|
||||||
return Unicode::toUnicode(str);
|
return TextOperations::toUnicode(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
float CLegacyConfigParser::readNumber()
|
float CLegacyConfigParser::readNumber()
|
||||||
@ -285,17 +285,6 @@ void CGeneralTextHandler::registerStringOverride(const std::string & modContext,
|
|||||||
|
|
||||||
bool CGeneralTextHandler::validateTranslation(const std::string & language, const std::string & modContext, const JsonNode & config) const
|
bool CGeneralTextHandler::validateTranslation(const std::string & language, const std::string & modContext, const JsonNode & config) const
|
||||||
{
|
{
|
||||||
auto escapeString = [](std::string input)
|
|
||||||
{
|
|
||||||
boost::replace_all(input, "\\", "\\\\");
|
|
||||||
boost::replace_all(input, "\n", "\\n");
|
|
||||||
boost::replace_all(input, "\r", "\\r");
|
|
||||||
boost::replace_all(input, "\t", "\\t");
|
|
||||||
boost::replace_all(input, "\"", "\\\"");
|
|
||||||
|
|
||||||
return input;
|
|
||||||
};
|
|
||||||
|
|
||||||
bool allPresent = true;
|
bool allPresent = true;
|
||||||
|
|
||||||
for (auto const & string : stringsLocalizations)
|
for (auto const & string : stringsLocalizations)
|
||||||
@ -318,7 +307,7 @@ bool CGeneralTextHandler::validateTranslation(const std::string & language, cons
|
|||||||
else
|
else
|
||||||
currentText = string.second.overrideValue;
|
currentText = string.second.overrideValue;
|
||||||
|
|
||||||
logMod->warn(R"( "%s" : "%s",)", string.first, escapeString(currentText));
|
logMod->warn(R"( "%s" : "%s",)", string.first, TextOperations::escapeString(currentText));
|
||||||
allPresent = false;
|
allPresent = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -332,7 +321,7 @@ bool CGeneralTextHandler::validateTranslation(const std::string & language, cons
|
|||||||
if (allFound)
|
if (allFound)
|
||||||
logMod->warn("Translation into language '%s' in mod '%s' has unused lines:", language, modContext);
|
logMod->warn("Translation into language '%s' in mod '%s' has unused lines:", language, modContext);
|
||||||
|
|
||||||
logMod->warn(R"( "%s" : "%s",)", string.first, escapeString(string.second.String()));
|
logMod->warn(R"( "%s" : "%s",)", string.first, TextOperations::escapeString(string.second.String()));
|
||||||
allFound = false;
|
allFound = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -562,24 +551,13 @@ int32_t CGeneralTextHandler::pluralText(int32_t textIndex, int32_t count) const
|
|||||||
|
|
||||||
void CGeneralTextHandler::dumpAllTexts()
|
void CGeneralTextHandler::dumpAllTexts()
|
||||||
{
|
{
|
||||||
auto escapeString = [](std::string input)
|
|
||||||
{
|
|
||||||
boost::replace_all(input, "\\", "\\\\");
|
|
||||||
boost::replace_all(input, "\n", "\\n");
|
|
||||||
boost::replace_all(input, "\r", "\\r");
|
|
||||||
boost::replace_all(input, "\t", "\\t");
|
|
||||||
boost::replace_all(input, "\"", "\\\"");
|
|
||||||
|
|
||||||
return input;
|
|
||||||
};
|
|
||||||
|
|
||||||
logGlobal->info("BEGIN TEXT EXPORT");
|
logGlobal->info("BEGIN TEXT EXPORT");
|
||||||
for ( auto const & entry : stringsLocalizations)
|
for ( auto const & entry : stringsLocalizations)
|
||||||
{
|
{
|
||||||
if (!entry.second.overrideValue.empty())
|
if (!entry.second.overrideValue.empty())
|
||||||
logGlobal->info(R"("%s" : "%s",)", entry.first, escapeString(entry.second.overrideValue));
|
logGlobal->info(R"("%s" : "%s",)", entry.first, TextOperations::escapeString(entry.second.overrideValue));
|
||||||
else
|
else
|
||||||
logGlobal->info(R"("%s" : "%s",)", entry.first, escapeString(entry.second.baseValue));
|
logGlobal->info(R"("%s" : "%s",)", entry.first, TextOperations::escapeString(entry.second.baseValue));
|
||||||
}
|
}
|
||||||
|
|
||||||
logGlobal->info("END TEXT EXPORT");
|
logGlobal->info("END TEXT EXPORT");
|
||||||
|
@ -169,7 +169,7 @@ JsonNode JsonParser::parse(std::string fileName)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!Unicode::isValidString(&input[0], input.size()))
|
if (!TextOperations::isValidUnicodeString(&input[0], input.size()))
|
||||||
error("Not a valid UTF-8 file", false);
|
error("Not a valid UTF-8 file", false);
|
||||||
|
|
||||||
extractValue(root);
|
extractValue(root);
|
||||||
|
@ -16,39 +16,52 @@
|
|||||||
|
|
||||||
VCMI_LIB_NAMESPACE_BEGIN
|
VCMI_LIB_NAMESPACE_BEGIN
|
||||||
|
|
||||||
size_t Unicode::getCharacterSize(char firstByte)
|
size_t TextOperations::getUnicodeCharacterSize(char firstByte)
|
||||||
{
|
{
|
||||||
// length of utf-8 character can be determined from 1st byte by counting number of highest bits set to 1:
|
// length of utf-8 character can be determined from 1st byte by counting number of highest bits set to 1:
|
||||||
// 0xxxxxxx -> 1 - ASCII chars
|
// 0xxxxxxx -> 1 - ASCII chars
|
||||||
// 110xxxxx -> 2
|
// 110xxxxx -> 2
|
||||||
|
// 1110xxxx -> 3
|
||||||
// 11110xxx -> 4 - last allowed in current standard
|
// 11110xxx -> 4 - last allowed in current standard
|
||||||
// 1111110x -> 6 - last allowed in original standard
|
|
||||||
|
|
||||||
if ((ui8)firstByte < 0x80)
|
auto value = static_cast<uint8_t>(firstByte);
|
||||||
|
|
||||||
|
if ((value & 0b10000000) == 0)
|
||||||
return 1; // ASCII
|
return 1; // ASCII
|
||||||
|
|
||||||
size_t ret = 0;
|
if ((value & 0b11100000) == 0b11000000)
|
||||||
|
return 2;
|
||||||
|
|
||||||
for (size_t i=0; i<8; i++)
|
if ((value & 0b11110000) == 0b11100000)
|
||||||
{
|
return 3;
|
||||||
if (((ui8)firstByte & (0x80 >> i)) != 0)
|
|
||||||
ret++;
|
if ((value & 0b11111000) == 0b11110000)
|
||||||
else
|
return 4;
|
||||||
break;
|
|
||||||
}
|
assert(0);// invalid unicode sequence
|
||||||
return ret;
|
return 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Unicode::isValidCharacter(const char * character, size_t maxSize)
|
bool TextOperations::isValidUnicodeCharacter(const char * character, size_t maxSize)
|
||||||
{
|
{
|
||||||
// can't be first byte in UTF8
|
assert(maxSize > 0);
|
||||||
if ((ui8)character[0] >= 0x80 && (ui8)character[0] < 0xC0)
|
|
||||||
return false;
|
|
||||||
// first character must follow rules checked in getCharacterSize
|
|
||||||
size_t size = getCharacterSize((ui8)character[0]);
|
|
||||||
|
|
||||||
if ((ui8)character[0] > 0xF4)
|
auto value = static_cast<uint8_t>(character[0]);
|
||||||
return false; // above maximum allowed in standard (UTF codepoints are capped at 0x0010FFFF)
|
|
||||||
|
// ASCII
|
||||||
|
if ( value < 0b10000000)
|
||||||
|
return maxSize > 0;
|
||||||
|
|
||||||
|
// can't be first byte in UTF8
|
||||||
|
if (value < 0b11000000)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// above maximum allowed in standard (UTF codepoints are capped at 0x0010FFFF)
|
||||||
|
if (value > 0b11110000)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// first character must follow rules checked in getUnicodeCharacterSize
|
||||||
|
size_t size = getUnicodeCharacterSize(character[0]);
|
||||||
|
|
||||||
if (size > maxSize)
|
if (size > maxSize)
|
||||||
return false;
|
return false;
|
||||||
@ -56,69 +69,70 @@ bool Unicode::isValidCharacter(const char * character, size_t maxSize)
|
|||||||
// remaining characters must have highest bit set to 1
|
// remaining characters must have highest bit set to 1
|
||||||
for (size_t i = 1; i < size; i++)
|
for (size_t i = 1; i < size; i++)
|
||||||
{
|
{
|
||||||
if (((ui8)character[i] & 0x80) == 0)
|
auto characterValue = static_cast<uint8_t>(character[i]);
|
||||||
|
if (characterValue < 0b10000000)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Unicode::isValidASCII(const std::string & text)
|
bool TextOperations::isValidASCII(const std::string & text)
|
||||||
{
|
{
|
||||||
for (const char & ch : text)
|
for (const char & ch : text)
|
||||||
if (ui8(ch) >= 0x80 )
|
if (static_cast<uint8_t>(ch) >= 0x80 )
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Unicode::isValidASCII(const char * data, size_t size)
|
bool TextOperations::isValidASCII(const char * data, size_t size)
|
||||||
{
|
{
|
||||||
for (size_t i=0; i<size; i++)
|
for (size_t i=0; i<size; i++)
|
||||||
if (ui8(data[i]) >= 0x80 )
|
if (static_cast<uint8_t>(data[i]) >= 0x80 )
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Unicode::isValidString(const std::string & text)
|
bool TextOperations::isValidUnicodeString(const std::string & text)
|
||||||
{
|
{
|
||||||
for (size_t i=0; i<text.size(); i += getCharacterSize(text[i]))
|
for (size_t i=0; i<text.size(); i += getUnicodeCharacterSize(text[i]))
|
||||||
{
|
{
|
||||||
if (!isValidCharacter(text.data() + i, text.size() - i))
|
if (!isValidUnicodeCharacter(text.data() + i, text.size() - i))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Unicode::isValidString(const char * data, size_t size)
|
bool TextOperations::isValidUnicodeString(const char * data, size_t size)
|
||||||
{
|
{
|
||||||
for (size_t i=0; i<size; i += getCharacterSize(data[i]))
|
for (size_t i=0; i<size; i += getUnicodeCharacterSize(data[i]))
|
||||||
{
|
{
|
||||||
if (!isValidCharacter(data + i, size - i))
|
if (!isValidUnicodeCharacter(data + i, size - i))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Unicode::toUnicode(const std::string &text)
|
std::string TextOperations::toUnicode(const std::string &text)
|
||||||
{
|
{
|
||||||
return toUnicode(text, CGeneralTextHandler::getInstalledEncoding());
|
return toUnicode(text, CGeneralTextHandler::getInstalledEncoding());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Unicode::toUnicode(const std::string &text, const std::string &encoding)
|
std::string TextOperations::toUnicode(const std::string &text, const std::string &encoding)
|
||||||
{
|
{
|
||||||
return boost::locale::conv::to_utf<char>(text, encoding);
|
return boost::locale::conv::to_utf<char>(text, encoding);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Unicode::fromUnicode(const std::string & text)
|
std::string TextOperations::fromUnicode(const std::string & text)
|
||||||
{
|
{
|
||||||
return fromUnicode(text, CGeneralTextHandler::getInstalledEncoding());
|
return fromUnicode(text, CGeneralTextHandler::getInstalledEncoding());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Unicode::fromUnicode(const std::string &text, const std::string &encoding)
|
std::string TextOperations::fromUnicode(const std::string &text, const std::string &encoding)
|
||||||
{
|
{
|
||||||
return boost::locale::conv::from_utf<char>(text, encoding);
|
return boost::locale::conv::from_utf<char>(text, encoding);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Unicode::trimRight(std::string & text, const size_t amount)
|
void TextOperations::trimRightUnicode(std::string & text, const size_t amount)
|
||||||
{
|
{
|
||||||
if(text.empty())
|
if(text.empty())
|
||||||
return;
|
return;
|
||||||
@ -130,9 +144,9 @@ void Unicode::trimRight(std::string & text, const size_t amount)
|
|||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
while (b != e) {
|
while (b != e) {
|
||||||
lastLen = len;
|
lastLen = len;
|
||||||
size_t n = getCharacterSize(*b);
|
size_t n = getUnicodeCharacterSize(*b);
|
||||||
|
|
||||||
if(!isValidCharacter(&(*b),e-b))
|
if(!isValidUnicodeCharacter(&(*b),e-b))
|
||||||
{
|
{
|
||||||
logGlobal->error("Invalid UTF8 sequence");
|
logGlobal->error("Invalid UTF8 sequence");
|
||||||
break;//invalid sequence will be trimmed
|
break;//invalid sequence will be trimmed
|
||||||
@ -146,4 +160,15 @@ void Unicode::trimRight(std::string & text, const size_t amount)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string TextOperations::escapeString(std::string input)
|
||||||
|
{
|
||||||
|
boost::replace_all(input, "\\", "\\\\");
|
||||||
|
boost::replace_all(input, "\n", "\\n");
|
||||||
|
boost::replace_all(input, "\r", "\\r");
|
||||||
|
boost::replace_all(input, "\t", "\\t");
|
||||||
|
boost::replace_all(input, "\"", "\\\"");
|
||||||
|
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
|
||||||
VCMI_LIB_NAMESPACE_END
|
VCMI_LIB_NAMESPACE_END
|
||||||
|
@ -12,24 +12,25 @@
|
|||||||
VCMI_LIB_NAMESPACE_BEGIN
|
VCMI_LIB_NAMESPACE_BEGIN
|
||||||
|
|
||||||
/// Namespace that provides utilites for unicode support (UTF-8)
|
/// Namespace that provides utilites for unicode support (UTF-8)
|
||||||
namespace Unicode
|
namespace TextOperations
|
||||||
{
|
{
|
||||||
/// evaluates size of UTF-8 character
|
/// returns length (in bytes) of UTF-8 character starting from specified character
|
||||||
size_t DLL_LINKAGE getCharacterSize(char firstByte);
|
size_t DLL_LINKAGE getUnicodeCharacterSize(char firstByte);
|
||||||
|
|
||||||
/// test if character is a valid UTF-8 symbol
|
/// test if character is a valid UTF-8 symbol
|
||||||
/// maxSize - maximum number of bytes this symbol may consist from ( = remainer of string)
|
/// maxSize - maximum number of bytes this symbol may consist from ( = remainer of string)
|
||||||
bool DLL_LINKAGE isValidCharacter(const char * character, size_t maxSize);
|
bool DLL_LINKAGE isValidUnicodeCharacter(const char * character, size_t maxSize);
|
||||||
|
|
||||||
/// test if text contains ASCII-string (no need for unicode conversion)
|
/// returns true if text contains valid ASCII-string
|
||||||
|
/// Note that since UTF-8 extends ASCII, any ASCII string is also UTF-8 string
|
||||||
bool DLL_LINKAGE isValidASCII(const std::string & text);
|
bool DLL_LINKAGE isValidASCII(const std::string & text);
|
||||||
bool DLL_LINKAGE isValidASCII(const char * data, size_t size);
|
bool DLL_LINKAGE isValidASCII(const char * data, size_t size);
|
||||||
|
|
||||||
/// test if text contains valid UTF-8 sequence
|
/// test if text contains valid UTF-8 sequence
|
||||||
bool DLL_LINKAGE isValidString(const std::string & text);
|
bool DLL_LINKAGE isValidUnicodeString(const std::string & text);
|
||||||
bool DLL_LINKAGE isValidString(const char * data, size_t size);
|
bool DLL_LINKAGE isValidUnicodeString(const char * data, size_t size);
|
||||||
|
|
||||||
/// converts text to unicode from specified encoding or from one specified in settings
|
/// converts text to UTF-8 from specified encoding or from one specified in settings
|
||||||
std::string DLL_LINKAGE toUnicode(const std::string & text);
|
std::string DLL_LINKAGE toUnicode(const std::string & text);
|
||||||
std::string DLL_LINKAGE toUnicode(const std::string & text, const std::string & encoding);
|
std::string DLL_LINKAGE toUnicode(const std::string & text, const std::string & encoding);
|
||||||
|
|
||||||
@ -38,8 +39,38 @@ namespace Unicode
|
|||||||
std::string DLL_LINKAGE fromUnicode(const std::string & text);
|
std::string DLL_LINKAGE fromUnicode(const std::string & text);
|
||||||
std::string DLL_LINKAGE fromUnicode(const std::string & text, const std::string & encoding);
|
std::string DLL_LINKAGE fromUnicode(const std::string & text, const std::string & encoding);
|
||||||
|
|
||||||
///delete (amount) UTF characters from right
|
///delete specified amount of UTF-8 characters from right
|
||||||
DLL_LINKAGE void trimRight(std::string & text, size_t amount = 1);
|
DLL_LINKAGE void trimRightUnicode(std::string & text, size_t amount = 1);
|
||||||
|
|
||||||
|
/// converts number into string using metric system prefixes, e.g. 'k' or 'M' to keep resulting strings within specified size
|
||||||
|
/// Note that resulting string may have more symbols than digits: minus sign and prefix symbol
|
||||||
|
template<typename Arithmetic>
|
||||||
|
inline std::string formatMetric(Arithmetic number, int maxDigits);
|
||||||
|
|
||||||
|
/// replaces all symbols that normally need escaping with appropriate escape sequences
|
||||||
|
std::string escapeString(std::string input);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
template<typename Arithmetic>
|
||||||
|
inline std::string TextOperations::formatMetric(Arithmetic number, int maxDigits)
|
||||||
|
{
|
||||||
|
Arithmetic max = std::pow(10, maxDigits);
|
||||||
|
if (std::abs(number) < max)
|
||||||
|
return std::to_string(number);
|
||||||
|
|
||||||
|
std::string symbols = " kMGTPE";
|
||||||
|
auto iter = symbols.begin();
|
||||||
|
|
||||||
|
while (std::abs(number) >= max)
|
||||||
|
{
|
||||||
|
number /= 1000;
|
||||||
|
iter++;
|
||||||
|
|
||||||
|
assert(iter != symbols.end());//should be enough even for int64
|
||||||
|
}
|
||||||
|
return std::to_string(number) + *iter;
|
||||||
|
}
|
||||||
|
|
||||||
VCMI_LIB_NAMESPACE_END
|
VCMI_LIB_NAMESPACE_END
|
||||||
|
@ -96,9 +96,9 @@ std::string CBinaryReader::readString()
|
|||||||
ret.resize(len);
|
ret.resize(len);
|
||||||
read(reinterpret_cast<ui8*>(&ret[0]), len);
|
read(reinterpret_cast<ui8*>(&ret[0]), len);
|
||||||
//FIXME: any need to move this into separate "read localized string" method?
|
//FIXME: any need to move this into separate "read localized string" method?
|
||||||
if (Unicode::isValidASCII(ret))
|
if (TextOperations::isValidASCII(ret))
|
||||||
return ret;
|
return ret;
|
||||||
return Unicode::toUnicode(ret);
|
return TextOperations::toUnicode(ret);
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user