1 /*
2 * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved.
3
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10
11 * The above copyright notice and this permission notice shall be included in all
12 * copies or substantial portions of the Software.
13
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 * SOFTWARE.
21 */
22
23 #include "../../lv_conf_internal.h"
24 #if LV_USE_THORVG_INTERNAL
25
26 #include "config.h"
27 #include <cmath>
28 #include <cstring>
29 #include <memory.h>
30 #include "tvgMath.h"
31 #include "tvgStr.h"
32
33
34 /************************************************************************/
35 /* Internal Class Implementation */
36 /************************************************************************/
37
_floatExact(float a,float b)38 static inline bool _floatExact(float a, float b)
39 {
40 return memcmp(&a, &b, sizeof(float)) == 0;
41 }
42
43
44 /************************************************************************/
45 /* External Class Implementation */
46 /************************************************************************/
47
48 namespace tvg {
49
50 /*
51 * https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/strtof-strtof-l-wcstof-wcstof-l?view=msvc-160
52 *
53 * src should be one of the following form :
54 *
55 * [whitespace] [sign] {digits [radix digits] | radix digits} [{e | E} [sign] digits]
56 * [whitespace] [sign] {INF | INFINITY}
57 * [whitespace] [sign] NAN [sequence]
58 *
59 * No hexadecimal form supported
60 * no sequence supported after NAN
61 */
strToFloat(const char * nPtr,char ** endPtr)62 float strToFloat(const char *nPtr, char **endPtr)
63 {
64 if (endPtr) *endPtr = (char *) (nPtr);
65 if (!nPtr) return 0.0f;
66
67 auto a = nPtr;
68 auto iter = nPtr;
69 auto val = 0.0f;
70 unsigned long long integerPart = 0;
71 int minus = 1;
72
73 //ignore leading whitespaces
74 while (isspace(*iter)) iter++;
75
76 //signed or not
77 if (*iter == '-') {
78 minus = -1;
79 iter++;
80 } else if (*iter == '+') {
81 iter++;
82 }
83
84 if (tolower(*iter) == 'i') {
85 if ((tolower(*(iter + 1)) == 'n') && (tolower(*(iter + 2)) == 'f')) iter += 3;
86 else goto error;
87
88 if (tolower(*(iter)) == 'i') {
89 if ((tolower(*(iter + 1)) == 'n') && (tolower(*(iter + 2)) == 'i') && (tolower(*(iter + 3)) == 't') &&
90 (tolower(*(iter + 4)) == 'y'))
91 iter += 5;
92 else goto error;
93 }
94 if (endPtr) *endPtr = (char *) (iter);
95 return (minus == -1) ? -INFINITY : INFINITY;
96 }
97
98 if (tolower(*iter) == 'n') {
99 if ((tolower(*(iter + 1)) == 'a') && (tolower(*(iter + 2)) == 'n')) iter += 3;
100 else goto error;
101
102 if (endPtr) *endPtr = (char *) (iter);
103 return (minus == -1) ? -NAN : NAN;
104 }
105
106 //Optional: integer part before dot
107 if (isdigit(*iter)) {
108 for (; isdigit(*iter); iter++) {
109 integerPart = integerPart * 10ULL + (unsigned long long) (*iter - '0');
110 }
111 a = iter;
112 } else if (*iter != '.') {
113 goto success;
114 }
115
116 val = static_cast<float>(integerPart);
117
118 //Optional: decimal part after dot
119 if (*iter == '.') {
120 unsigned long long decimalPart = 0;
121 unsigned long long pow10 = 1;
122 int count = 0;
123
124 iter++;
125
126 if (isdigit(*iter)) {
127 for (; isdigit(*iter); iter++, count++) {
128 if (count < 19) {
129 decimalPart = decimalPart * 10ULL + +static_cast<unsigned long long>(*iter - '0');
130 pow10 *= 10ULL;
131 }
132 }
133 } else if (isspace(*iter)) { //skip if there is a space after the dot.
134 a = iter;
135 goto success;
136 }
137
138 val += static_cast<float>(decimalPart) / static_cast<float>(pow10);
139 a = iter;
140 }
141
142 //Optional: exponent
143 if (*iter == 'e' || *iter == 'E') {
144 ++iter;
145
146 //Exception: svg may have 'em' unit for fonts. ex) 5em, 10.5em
147 if ((*iter == 'm') || (*iter == 'M')) {
148 //TODO: We don't support font em unit now, but has to multiply val * font size later...
149 a = iter + 1;
150 goto success;
151 }
152
153 //signed or not
154 int minus_e = 1;
155
156 if (*iter == '-') {
157 minus_e = -1;
158 ++iter;
159 } else if (*iter == '+') {
160 iter++;
161 }
162
163 unsigned int exponentPart = 0;
164
165 if (isdigit(*iter)) {
166 while (*iter == '0') iter++;
167 for (; isdigit(*iter); iter++) {
168 exponentPart = exponentPart * 10U + static_cast<unsigned int>(*iter - '0');
169 }
170 } else if (!isdigit(*(a - 1))) {
171 a = nPtr;
172 goto success;
173 } else if (*iter == 0) {
174 goto success;
175 }
176
177 //if ((_floatExact(val, 2.2250738585072011f)) && ((minus_e * static_cast<int>(exponentPart)) <= -308)) {
178 if ((_floatExact(val, 1.175494351f)) && ((minus_e * static_cast<int>(exponentPart)) <= -38)) {
179 //val *= 1.0e-308f;
180 val *= 1.0e-38f;
181 a = iter;
182 goto success;
183 }
184
185 a = iter;
186 auto scale = 1.0f;
187
188 while (exponentPart >= 8U) {
189 scale *= 1E8;
190 exponentPart -= 8U;
191 }
192 while (exponentPart > 0U) {
193 scale *= 10.0f;
194 exponentPart--;
195 }
196 val = (minus_e == -1) ? (val / scale) : (val * scale);
197 } else if ((iter > nPtr) && !isdigit(*(iter - 1))) {
198 a = nPtr;
199 goto success;
200 }
201
202 success:
203 if (endPtr) *endPtr = (char *)(a);
204 if (!std::isfinite(val)) return 0.0f;
205
206 return minus * val;
207
208 error:
209 if (endPtr) *endPtr = (char *)(nPtr);
210 return 0.0f;
211 }
212
strDuplicate(const char * str,size_t n)213 char* strDuplicate(const char *str, size_t n)
214 {
215 auto len = strlen(str);
216 if (len < n) n = len;
217
218 auto ret = (char *) malloc(n + 1);
219 if (!ret) return nullptr;
220 ret[n] = '\0';
221
222 return (char *) memcpy(ret, str, n);
223 }
224
strAppend(char * lhs,const char * rhs,size_t n)225 char* strAppend(char* lhs, const char* rhs, size_t n)
226 {
227 if (!rhs) return lhs;
228 if (!lhs) return strDuplicate(rhs, n);
229 lhs = (char*)realloc(lhs, strlen(lhs) + n + 1);
230 return strncat(lhs, rhs, n);
231 }
232
strDirname(const char * path)233 char* strDirname(const char* path)
234 {
235 const char *ptr = strrchr(path, '/');
236 #ifdef _WIN32
237 if (ptr) ptr = strrchr(ptr + 1, '\\');
238 #endif
239 int len = int(ptr + 1 - path); // +1 to include '/'
240 return strDuplicate(path, len);
241 }
242
243 }
244
245 #endif /* LV_USE_THORVG_INTERNAL */
246
247