source: cpp/common/Convert.cpp @ 1340

Last change on this file since 1340 was 1339, checked in by Maciej Komosinski, 2 days ago

Added two helper conversion functions: toDouble(), toUInt()

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