source: cpp/common/Convert.cpp

Last change on this file was 1285, checked in by Maciej Komosinski, 5 months ago

Added toLowerCase/toUpperCase for UTF-8 strings

  • Property svn:eol-style set to native
File size: 6.1 KB
RevLine 
[286]1// This file is a part of Framsticks SDK.  http://www.framsticks.com/
[1285]2// Copyright (C) 1999-2023  Maciej Komosinski and Szymon Ulatowski.
[286]3// See LICENSE.txt for details.
[122]4
[109]5#include "Convert.h"
6#include <sstream>
[1130]7#include <algorithm>
[109]8
9#if defined __ANDROID__ || defined __BORLANDC__
[247]10#include <ctype.h> //toupper, tolower
[109]11#endif
12
13#ifdef SHP
[247]14#include <cstdlib>
[109]15#else
[247]16#include <stdlib.h>
[109]17#endif
18
19#include <stdio.h>
[1285]20#include <locale>
21#include <iostream>
22#ifndef IPHONE
23#include <codecvt>
24#endif
[109]25
[247]26int Convert::toInt(string s) { return atoi(s.c_str()); }
[1285]27int Convert::toInt_HexIf0x(string s) { return (s.size() > 2 && s[0] == '0' && s[1] == 'x') ? (int)hexToInt(s.substr(2)) : atoi(s.c_str()); }
[247]28float Convert::toFloat(string s) { return (float)atof(s.c_str()); }
29string Convert::toLowerCase(string s) { std::transform(s.begin(), s.end(), s.begin(), ::tolower);  return s; }
30string Convert::toUpperCase(string s) { std::transform(s.begin(), s.end(), s.begin(), ::toupper);  return s; }
[1285]31#if !defined IPHONE && !defined MACOS
32static string transformUTF8(string in, wint_t(*fun)(wint_t))
33{
34        static std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>, wchar_t> converter;
35        auto wstr = converter.from_bytes(in);
36        for (auto it = wstr.begin(); it != wstr.end(); it++)
37                *it = fun(*it);
38        return converter.to_bytes(wstr);
39}
40//does not seem to work in iPhone e.g. for Polish-specific letters, or a different locale settings should be used (but pl-PL did not work properly either) - so instead implemented this using NSString function in objc-interface.mm
41string Convert::toLowerCaseUTF8(string s) { return transformUTF8(s, towlower); }
42string Convert::toUpperCaseUTF8(string s) { return transformUTF8(s, towupper); }
43#endif
[247]44char Convert::toLowerCase(char c) { return (char)tolower(c); }
45char Convert::toUpperCase(char c) { return (char)toupper(c); }
[109]46
[247]47template<class T> const char* printf_format_for(const T& value) { return "unknown type"; }
48template<> const char* printf_format_for(const unsigned int& value) { return "%u"; }
49template<> const char* printf_format_for(const int& value) { return "%d"; }
50template<> const char* printf_format_for(const short& value) { return "%d"; }
51template<> const char* printf_format_for(const float& value) { return "%g"; }
52template<> const char* printf_format_for(const double& value) { return "%g"; }
[109]53
54template<class T> string Convert::_toString(const T& value)
55{
[247]56        char buf[30];
57        sprintf(buf, printf_format_for(value), value);
58        return string(buf);
59        /*
60        #ifndef MULTITHREADED
[109]61        static
[247]62        #endif
[109]63        std::ostringstream oss; //pod VS tworzenie go trwa dlugo nawet w wersji release (szczegolnie jak np konwertuje sie cos setki tysiecy razy)
64        //dlatego robimy go raz (static) i potem tylko czyscimy
65        //ciekawostka: kiedy nie byl static, czasy wykonania bogatego w konwersje kawa³ka kodu oscylowa³y w trybie debug
66        //(5.5s lub 55s) a w release zawsze 57s. Po uzyciu static czas tego samego kodu jest zawsze debug: 0.72s release: 0.33s
67        oss.clear(); //clear error flag
68        oss.str(""); //set empty string
[247]69        oss << value;
70        return oss.str();
71        */
[109]72}
73
[247]74string Convert::toString(unsigned int v) { return _toString(v); }
75string Convert::toString(int v) { return _toString(v); }
76string Convert::toString(short v) { return _toString(v); }
77string Convert::toString(float v) { return _toString(v); }
78string Convert::toString(double v) { return _toString(v); }
[109]79
[247]80uint32_t Convert::hexToInt(const string& col)
81{
82        uint32_t value;
83        std::istringstream iss(col);
84        iss >> std::hex >> value;
85        return value;
86}
87
[109]88#ifdef MULTITHREADED
89//jezeli jest tu a nie jako static w funkcji, to inicjalizacja
90//nastapi na samym poczatku (w nieprzewidywalnym momencie, ale nie szkodzi(?))
91//gdyby byla w funkcji to teoretycznie dwa watki moglyby wejsc
92//do niej rownoczesnie i zaczac inicjalizacje po czym jeden korzystalby
93//z mutexa gdy drugi dalej by go inicjalizowal
[400]94#if ! ((defined LINUX) || (defined _WIN32 && !defined __BORLANDC__ ))
95// only for the "borland?" cases in localtime() and asctime() below
[109]96#include "threads.h"
[247]97static pthread_mutex_t fix_unsafe_mutex = PTHREAD_MUTEX_INITIALIZER;
[109]98#endif
[400]99#endif
[109]100
101struct tm Convert::localtime(const time_t &timep)
102{
103#ifndef MULTITHREADED
104
[247]105        return *::localtime(&timep);
[109]106
107#else
108
[247]109        struct tm ret;
[109]110#if defined LINUX // || android?
[1005]111        return *::localtime_r(&timep, &ret);
[257]112#elif defined _WIN32 && !defined __BORLANDC__
[247]113        ::localtime_s(&ret, &timep);
114        return ret;
[109]115#else //borland?
[247]116        pthread_mutex_lock(&fix_unsafe_mutex);
[1005]117        ret = *::localtime(&timep);
[247]118        pthread_mutex_unlock(&fix_unsafe_mutex);
119        return ret;
[109]120#endif
121
122#endif
123}
124
125string Convert::asctime(const struct tm &tm)
126{
[247]127        char *ret;
[109]128#ifndef MULTITHREADED
129
[1005]130        ret = ::asctime(&tm);
[109]131
132#else //MULTITHREADED
133
[247]134        char buf[26];
[109]135#if defined LINUX // || android?
[1005]136        ret = ::asctime_r(&tm, buf);
[257]137#elif defined _WIN32 && !defined __BORLANDC__
[247]138        asctime_s(buf, sizeof(buf), &tm);
139        ret = buf;
[109]140#else //borland?
[247]141        pthread_mutex_lock(&fix_unsafe_mutex);
[1005]142        strcpy(buf, ::asctime(&tm));
143        ret = buf;
[247]144        pthread_mutex_unlock(&fix_unsafe_mutex);
[109]145#endif
146#endif
147
[247]148        return string(ret, 24); //24 znaki z pominieciem ostatniego \n
[109]149}
[281]150
151string Convert::wstrToUtf8(const wchar_t *str)
152{
153        if (str == NULL) return "";
154        string res;
155        wchar_t *wcp = (wchar_t*)str;
156        while (*wcp != 0)
157        {
158                int c = *wcp;
159                if (c < 0x80) res += c;
160                else if (c < 0x800) { res += 192 + c / 64; res += 128 + c % 64; }
161                else if (c - 0xd800u < 0x800) res += "<ERROR-CHAR>";
162                else if (c < 0x10000) { res += 224 + c / 4096; res += 128 + c / 64 % 64; res += 128 + c % 64; }
163                else if (c < 0x110000) { res += 240 + c / 262144; res += 128 + c / 4096 % 64; res += 128 + c / 64 % 64; res += 128 + c % 64; }
164                else res += "<ERROR-CHAR>";
165                wcp++;
166        }
167        return res;
168}
169
170#ifdef _WIN32
171wstring Convert::utf8ToUtf16(const char *str)
172{
173        wstring wstr;
174        int nOffset = 0;
[1274]175        int nDataLen = (int)strlen(str); //ending \0 is not converted, but resize() below sets the proper length of wstr
[281]176        int nLenWide = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)(str + nOffset),
177                (int)(nDataLen - nOffset), NULL, 0);
178        wstr.resize(nLenWide);
179        if (MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)(str + nOffset),
180                (int)(nDataLen - nOffset),
181                &wstr[0], nLenWide) != nLenWide)
182        {
183                //ASSERT(false); //some conversion error
[294]184                return wstr + L"<UTF8_CONV_ERROR>";
[281]185        }
186        return wstr;
187}
188#endif
Note: See TracBrowser for help on using the repository browser.