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