1 #ifndef NUMBERTOSTRING_H
2 #define NUMBERTOSTRING_H
3 
4 #include <limits>
5 #include "JSONDebug.h"
6 #ifdef JSON_LESS_MEMORY
7     #include "JSONMemory.h"
8 #endif
9 #include "JSONSharedString.h"
10 #include <cstdio>
11 #ifdef JSON_STRICT
12     #include <cmath>
13 #endif
14 template <unsigned int GETLENSIZE>
15 struct getLenSize{
16     char tmp[GETLENSIZE == 16];  // compile time assertion
17     enum {GETLEN = 41};
18 };
19 
20 template<>
21 struct getLenSize<1>{
22     enum {GETLEN = 5};
23 };
24 
25 template <>
26 struct getLenSize<2>{
27     enum {GETLEN = 7};
28 };
29 
30 template <>
31 struct getLenSize<4>{
32     enum {GETLEN = 12};
33 };
34 
35 template <>
36 struct getLenSize<8>{
37     enum {GETLEN = 22};
38 };
39 
40 static inline bool _floatsAreEqual(const json_number & one, const json_number & two) json_pure;
41 static inline bool _floatsAreEqual(const json_number & one, const json_number & two) json_nothrow {
42     return (one > two) ? (one - two) < JSON_FLOAT_THRESHHOLD : (one - two) > -JSON_FLOAT_THRESHHOLD;
43 }
44 
45 #ifdef JSON_LESS_MEMORY
46     #define num_str_result s.ptr
47 #endif
48 
49 class NumberToString {
50 public:
51     template<typename T>
52     static json_string _itoa(T val) json_nothrow {
53 	   #ifdef JSON_LESS_MEMORY
54 		  json_auto<json_char> s(getLenSize<sizeof(T)>::GETLEN);
55 	   #else
56 		  json_char num_str_result[getLenSize<sizeof(T)>::GETLEN];
57 	   #endif
58 	   num_str_result[getLenSize<sizeof(T)>::GETLEN - 1] = JSON_TEXT('\0'); //null terminator
59 	   json_char * runner = &num_str_result[getLenSize<sizeof(T)>::GETLEN - 2];
60 	   bool negative;
61 
62 	   START_MEM_SCOPE
63 	   long value = (long)val;
64 	   //first thing, check if it's negative, if so, make it positive
65 	   if (value < 0){
66 		  value = -value;
67 		  negative = true;
68 	   } else {
69 		  negative = false;
70 	   }
71 
72 	   //create the string
73 	   do {
74 		  *runner-- = (json_char)(value % 10) + JSON_TEXT('0');
75 	   } while(value /= 10);
76 	   END_MEM_SCOPE
77 
78 	   //if it's negative, add the negation
79 	   if (negative){
80 		  *runner = JSON_TEXT('-');
81 		  return json_string(runner);
82 	   }
83 	   return json_string(runner + 1);
84     }
85 
86     #ifndef JSON_LIBRARY
87 	   template<typename T>
88 	   static json_string _uitoa(T val) json_nothrow {
89 		  #ifdef JSON_LESS_MEMORY
90 			 json_auto<json_char> s(getLenSize<sizeof(T)>::GETLEN);
91 		  #else
92 			 json_char num_str_result[getLenSize<sizeof(T)>::GETLEN];
93 		  #endif
94 		  num_str_result[getLenSize<sizeof(T)>::GETLEN - 1] = JSON_TEXT('\0'); //null terminator
95 		  json_char * runner = &num_str_result[getLenSize<sizeof(T)>::GETLEN - 2];
96 
97 		  //create the string
98 		  START_MEM_SCOPE
99 			 unsigned long value = (unsigned long)val;
100 			 do {
101 				*runner-- = (json_char)(value % 10) + JSON_TEXT('0');
102 			 } while(value /= 10);
103 		  END_MEM_SCOPE
104 
105 		  return json_string(runner + 1);
106 	   }
107     #endif
108 
109     #ifdef JSON_ISO_STRICT
110 	   #define EXTRA_LONG
111 	   #define FLOAT_STRING "%f"
112 	   #define LFLOAT_STRING L"%f"
113     #else
114 	   #define EXTRA_LONG long
115 	   #define FLOAT_STRING "%Lf"
116 	   #define LFLOAT_STRING L"%Lf"
117     #endif
118 
119     static json_string _ftoa(json_number value) json_nothrow {
120 	   #ifndef JSON_LIBRARY
121 			//ScopeCoverage(_ftoa_coverage, 6);
122 		  if (json_unlikely(value >= 0.0 && _floatsAreEqual(value, (json_number)((unsigned EXTRA_LONG long)value)))){
123 			 return _uitoa<unsigned EXTRA_LONG long>((unsigned EXTRA_LONG long)value);
124 		  } else
125 		#else
126 			  //ScopeCoverage(_ftoa_coverage, 5);
127 	   #endif
128 		  if (json_unlikely(_floatsAreEqual(value, (json_number)((long EXTRA_LONG)value)))){
129 			 return _itoa<long EXTRA_LONG>((long EXTRA_LONG)value);
130 		  }
131 
132 	   #ifdef JSON_LESS_MEMORY
133 		  json_auto<json_char> s(64);
134 	   #else
135 		  json_char num_str_result[64];
136 	   #endif
137 	   #ifdef JSON_UNICODE
138 		  std::swprintf(num_str_result, 63, LFLOAT_STRING, (EXTRA_LONG double)value);
139 	   #else
140 		  //Thanks to Salvor Hardin for this Visual C++ fix
141 		  #ifdef _MSC_VER
142 			 _snprintf_s(num_str_result, 63, 63, FLOAT_STRING, (EXTRA_LONG double)value); //yes, 63 appears twice using _snprintf_s()
143 		  #else
144 			 snprintf(num_str_result, 63, FLOAT_STRING, (EXTRA_LONG double)value);
145 		  #endif
146 	   #endif
147 	   //strip the trailing zeros
148 	   for(json_char * pos = &num_str_result[0]; *pos; ++pos){
149 		  if (json_unlikely(*pos == '.')){  //only care about after the decimal
150 			 for(json_char * runner = pos + 1; *runner; ++runner){
151 				 if (json_likely(*runner != JSON_TEXT('0'))){
152 					 pos = runner + 1;  //have to go to the end 1.0001
153 				 }
154 			 }
155 			 *pos = JSON_TEXT('\0');
156 			 break;
157 		  }
158 	   }
159 	   return json_string(num_str_result);
160     }
161 
162     #if defined(JSON_SAFE) || defined(JSON_DEBUG)
163 	   static bool isNumeric(const json_string & str) json_nothrow {
164 		  const json_char * p = str.c_str();
165 		  bool decimal = false;
166 		  bool scientific = false;
167 
168 			#ifdef JSON_STRICT
169 		   bool leadingzero = false;
170 			#endif
171 
172 		  //first letter is weird
173 		  switch(*p){
174 			 case JSON_TEXT('\0'):
175 				return false;
176 		  #ifndef JSON_STRICT
177 			 case JSON_TEXT('.'):
178 				decimal = true;
179 				break;
180 			 case JSON_TEXT('+'):
181 		  #endif
182 			 case JSON_TEXT('-'):
183 				  switch (*(p + 1)){
184 					  case JSON_TEXT('.'):
185 					  case JSON_TEXT('e'):
186 					  case JSON_TEXT('E'):
187 					  case JSON_TEXT('\0'):
188 						  return false;
189 					  case JSON_TEXT('0'):
190 						  #ifdef JSON_STRICT
191 						  switch(*(p + 2)){
192 							  case JSON_TEXT('.'):
193 							  case JSON_TEXT('e'):
194 							  case JSON_TEXT('E'):
195 								  leadingzero = false;
196 								  break;
197 							  case JSON_TEXT('\0'):
198 								  return true;
199 							  default:
200 								  leadingzero = true;
201 								  break;
202 						  }
203 						  #endif
204 						  ++p;
205 						  break;
206 					  default:
207 						  break;
208 				  }
209 				  break;
210 			 case JSON_TEXT('1'):
211 			 case JSON_TEXT('2'):
212 			 case JSON_TEXT('3'):
213 			 case JSON_TEXT('4'):
214 			 case JSON_TEXT('5'):
215 			 case JSON_TEXT('6'):
216 			 case JSON_TEXT('7'):
217 			 case JSON_TEXT('8'):
218 			 case JSON_TEXT('9'):
219 				break;
220 			 case JSON_TEXT('0'):
221 				++p;
222 				#ifdef JSON_STRICT
223 				leadingzero = true;
224 				#endif
225 				switch(*p){
226 				    case JSON_TEXT('.'):
227 					   decimal = true;
228 					   break;
229 				    case JSON_TEXT('e'):
230 				    case JSON_TEXT('E'):
231 						#ifdef JSON_STRICT
232 						leadingzero = false; //not leading, just a zero
233 						#endif
234 					   scientific = true;
235 					   ++p;
236 					   switch(*p){
237 						  case JSON_TEXT('\0'):
238 							 return false;
239 						  case JSON_TEXT('-'):
240 						  case JSON_TEXT('+'):
241 						  #ifndef JSON_STRICT
242 						  case JSON_TEXT('0'):  //cant have a leading zero in scrict
243 						  #endif
244 						  case JSON_TEXT('1'):
245 						  case JSON_TEXT('2'):
246 						  case JSON_TEXT('3'):
247 						  case JSON_TEXT('4'):
248 						  case JSON_TEXT('5'):
249 						  case JSON_TEXT('6'):
250 						  case JSON_TEXT('7'):
251 						  case JSON_TEXT('8'):
252 						  case JSON_TEXT('9'):
253 							 break;
254 						  default:
255 							 return false;
256 					   }
257 					   break;
258 				    #ifndef JSON_STRICT
259 					   case JSON_TEXT('x'):
260 						  return (str.find_first_not_of(JSON_TEXT("0123456789ABCDEFabcdef"), 2) == json_string::npos);
261 					   case JSON_TEXT('1'):
262 					   case JSON_TEXT('2'):
263 					   case JSON_TEXT('3'):
264 					   case JSON_TEXT('4'):
265 					   case JSON_TEXT('5'):
266 					   case JSON_TEXT('6'):
267 					   case JSON_TEXT('7'):
268 						  return (str.find_first_not_of(JSON_TEXT("01234567"), 1) == json_string::npos);
269 				    #endif
270 				    case JSON_TEXT('\0'):  //just 0
271 					   return true;
272 				    default:
273 					   return false;
274 				}
275 				break;
276 			 default:
277 				return false;
278 		  }
279 		  ++p;
280 
281 		  //next digits
282 		  while (*p){
283 			 switch(*p){
284 				case JSON_TEXT('.'):
285 					 if (json_unlikely(decimal)){
286 						 return false; //multiple decimals
287 					 }
288 
289 					 if (json_unlikely(scientific)){
290 						 return false;
291 					 }
292 				    decimal = true;
293 				    break;
294 				case JSON_TEXT('e'):
295 				case JSON_TEXT('E'):
296 					 if (json_unlikely(scientific)){
297 						 return false;
298 					 }
299 				    scientific = true;
300 				    ++p;
301 				    switch(*p){
302 					   case JSON_TEXT('\0'):
303 						  return false;
304 					   case JSON_TEXT('-'):
305 					   case JSON_TEXT('+'):
306 							if (!isdigit(*(p + 1))){
307 								return false;
308 							}
309 
310 							#ifdef JSON_STRICT
311 								if (*(p + 1) == JSON_TEXT('0')){  //no leading zeros on scientific notations
312 									return false;
313 								}
314 							#endif
315 							break;
316 						#ifndef JSON_STRICT
317 					   case JSON_TEXT('0'):  //cant have a leading zero in scrict
318 						#endif
319 					   case JSON_TEXT('1'):
320 					   case JSON_TEXT('2'):
321 					   case JSON_TEXT('3'):
322 					   case JSON_TEXT('4'):
323 					   case JSON_TEXT('5'):
324 					   case JSON_TEXT('6'):
325 					   case JSON_TEXT('7'):
326 					   case JSON_TEXT('8'):
327 					   case JSON_TEXT('9'):
328 						  break;
329 					   default:
330 						  return false;
331 				    }
332 				    break;
333 				case JSON_TEXT('0'):
334 				case JSON_TEXT('1'):
335 				case JSON_TEXT('2'):
336 				case JSON_TEXT('3'):
337 				case JSON_TEXT('4'):
338 				case JSON_TEXT('5'):
339 				case JSON_TEXT('6'):
340 				case JSON_TEXT('7'):
341 				case JSON_TEXT('8'):
342 				case JSON_TEXT('9'):
343 				    break;
344 				default:
345 				    return false;
346 			 }
347 			 ++p;
348 		  }
349 		#ifdef JSON_STRICT
350 		   if (leadingzero && !decimal){
351 			   return false;
352 		   }
353 		#endif
354 		  return true;
355 	   }
356     #endif
357 
358     #ifdef JSON_STRICT
359 	   //much faster because no octal or hex support
360 	   static json_number _atof (const json_char * num){
361 		  json_number sign = (json_number)1.0;
362 
363 		  //sign
364 		  if (*num==JSON_TEXT('-')){
365 			 sign = -1.0;
366 			 ++num;
367 		  } else {
368 		  }
369 
370 		  //skip leading zero if one
371 		  #if defined(JSON_SAFE) || defined(JSON_DEBUG)
372 			 bool _leadingzeros = *num == JSON_TEXT('0');
373 		     bool _leadingdigits = false;
374 		  #endif
375 		  if (*num == JSON_TEXT('0')){
376 			 ++num;
377 		  }
378 		  #ifdef JSON_STRICT
379 			else if (json_likely(*num < JSON_TEXT('1') || *num > JSON_TEXT('9'))){
380 				return std::numeric_limits<json_number>::signaling_NaN();
381 			}
382 		  #endif
383 
384 		   JSON_ASSERT_SAFE(*num != JSON_TEXT('0'), JSON_TEXT("multiple leading zeros"), return std::numeric_limits<json_number>::signaling_NaN(); );
385 
386 		  // Number
387 		   json_number n = (json_number)0.0;
388 		  if (json_likely(*num >= JSON_TEXT('1') && *num <= JSON_TEXT('9'))){
389 			  #if defined(JSON_SAFE) || defined(JSON_DEBUG)
390 				  _leadingdigits = true;
391 			  #endif
392 			 do {
393 				n = (n * 10.0) + (*num++ - JSON_TEXT('0'));
394 			 } while (*num >= JSON_TEXT('0') && *num <= JSON_TEXT('9'));
395 		  } else {
396 			  JSON_ASSERT_SAFE(
397 							   (*num) == JSON_TEXT('.') ||	 //.xxx
398 							   (*num) == JSON_TEXT('e') ||	 //0Exxx
399 							   (*num) == JSON_TEXT('E') ||	 //0exxx
400 							   (*num) == JSON_TEXT('\0')     //end of the number, just zero
401 							   , JSON_TEXT("first digit not a number, e, period, or terminator"), return std::numeric_limits<json_number>::signaling_NaN(); );
402 		  }
403 
404 		  // Fractional part
405 		  json_number scale = (json_number)0.0;
406 		  if (*num == JSON_TEXT('.')) {
407 			  JSON_ASSERT_SAFE(_leadingzeros || _leadingdigits, JSON_TEXT("period without leading anything"), return std::numeric_limits<json_number>::signaling_NaN(); );
408 			 ++num;
409 			  for(; *num >= JSON_TEXT('0') && *num <= JSON_TEXT('9');){
410 				n = (n * 10.0) + (*num++ - JSON_TEXT('0'));
411 				--scale;
412 			  };
413 		  } else {
414 			  JSON_ASSERT_SAFE(!_leadingzeros || n == 0, JSON_TEXT("leading zero on an int"), return std::numeric_limits<json_number>::signaling_NaN(); );
415 			  JSON_ASSERT_SAFE(
416 							   (*num) == JSON_TEXT('e') ||	 //0Exxx
417 							   (*num) == JSON_TEXT('E') ||	 //0exxx
418 							   (*num) == JSON_TEXT('\0')     //end of the number, just zero
419 							   , JSON_TEXT("next char not an e or terminator"), return std::numeric_limits<json_number>::signaling_NaN(); );
420 		  }
421 
422 		  // Exponent
423 		  int subscale = 0, signsubscale = 1;
424 		  if (json_unlikely(*num == JSON_TEXT('e') || *num == JSON_TEXT('E'))){
425 			 ++num;
426 			 switch(*num){
427 				case JSON_TEXT('+'):
428 				    ++num;
429 				    break;
430 				case JSON_TEXT('-'):
431 				    signsubscale = -1;
432 				    ++num;
433 					 JSON_ASSERT_SAFE(*num != JSON_TEXT('0'), JSON_TEXT("negative cant be followed by leading zero even after E"), return std::numeric_limits<json_number>::signaling_NaN(); );
434 				    break;
435 				 default:
436 					 break;
437 			 }
438 			 JSON_ASSERT_SAFE(*num != JSON_TEXT('\0'), JSON_TEXT("no exponent for scientific notation"), return std::numeric_limits<json_number>::signaling_NaN(); );
439 			 while (*num >= JSON_TEXT('0') && *num <= JSON_TEXT('9')){
440 				subscale=(subscale * 10) + (*num++ - JSON_TEXT('0'));
441 			 }
442 		  }
443 
444 		  JSON_ASSERT_SAFE(*num == JSON_TEXT('\0'), JSON_TEXT("done with number, not at terminator"), return std::numeric_limits<json_number>::signaling_NaN(); );
445 		  return sign * n * pow((json_number)10.0, scale + subscale * signsubscale);	// number = +/- number.fraction * 10^+/- exponent
446 	   }
447     #endif
448 };
449 
450 #endif
451