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
Line 
1// This file is a part of Framsticks SDK.  http://www.framsticks.com/
2// Copyright (C) 1999-2023  Maciej Komosinski and Szymon Ulatowski.
3// See LICENSE.txt for details.
4
5#include "Convert.h"
6#include <sstream>
7#include <algorithm>
8
9#if defined __ANDROID__ || defined __BORLANDC__
10#include <ctype.h> //toupper, tolower
11#endif
12
13#ifdef SHP
14#include <cstdlib>
15#else
16#include <stdlib.h>
17#endif
18
19#include <stdio.h>
20#include <locale>
21#include <iostream>
22#ifndef IPHONE
23#include <codecvt>
24#endif
25
26int Convert::toInt(string s) { return atoi(s.c_str()); }
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()); }
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; }
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
44char Convert::toLowerCase(char c) { return (char)tolower(c); }
45char Convert::toUpperCase(char c) { return (char)toupper(c); }
46
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"; }
53
54template<class T> string Convert::_toString(const T& value)
55{
56        char buf[30];
57        sprintf(buf, printf_format_for(value), value);
58        return string(buf);
59        /*
60        #ifndef MULTITHREADED
61        static
62        #endif
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
69        oss << value;
70        return oss.str();
71        */
72}
73
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); }
79
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
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
94#if ! ((defined LINUX) || (defined _WIN32 && !defined __BORLANDC__ ))
95// only for the "borland?" cases in localtime() and asctime() below
96#include "threads.h"
97static pthread_mutex_t fix_unsafe_mutex = PTHREAD_MUTEX_INITIALIZER;
98#endif
99#endif
100
101struct tm Convert::localtime(const time_t &timep)
102{
103#ifndef MULTITHREADED
104
105        return *::localtime(&timep);
106
107#else
108
109        struct tm ret;
110#if defined LINUX // || android?
111        return *::localtime_r(&timep, &ret);
112#elif defined _WIN32 && !defined __BORLANDC__
113        ::localtime_s(&ret, &timep);
114        return ret;
115#else //borland?
116        pthread_mutex_lock(&fix_unsafe_mutex);
117        ret = *::localtime(&timep);
118        pthread_mutex_unlock(&fix_unsafe_mutex);
119        return ret;
120#endif
121
122#endif
123}
124
125string Convert::asctime(const struct tm &tm)
126{
127        char *ret;
128#ifndef MULTITHREADED
129
130        ret = ::asctime(&tm);
131
132#else //MULTITHREADED
133
134        char buf[26];
135#if defined LINUX // || android?
136        ret = ::asctime_r(&tm, buf);
137#elif defined _WIN32 && !defined __BORLANDC__
138        asctime_s(buf, sizeof(buf), &tm);
139        ret = buf;
140#else //borland?
141        pthread_mutex_lock(&fix_unsafe_mutex);
142        strcpy(buf, ::asctime(&tm));
143        ret = buf;
144        pthread_mutex_unlock(&fix_unsafe_mutex);
145#endif
146#endif
147
148        return string(ret, 24); //24 znaki z pominieciem ostatniego \n
149}
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;
175        int nDataLen = (int)strlen(str); //ending \0 is not converted, but resize() below sets the proper length of wstr
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
184                return wstr + L"<UTF8_CONV_ERROR>";
185        }
186        return wstr;
187}
188#endif
Note: See TracBrowser for help on using the repository browser.