1 // Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
2 // Distributed under MIT license, or public domain if desired and
3 // recognized in your jurisdiction.
4 // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
5 
6 #ifndef LIB_JSONCPP_JSON_TOOL_H_INCLUDED
7 #define LIB_JSONCPP_JSON_TOOL_H_INCLUDED
8 
9 #if !defined(JSON_IS_AMALGAMATION)
10 #include <json/config.h>
11 #endif
12 
13 // Also support old flag NO_LOCALE_SUPPORT
14 #ifdef NO_LOCALE_SUPPORT
15 #define JSONCPP_NO_LOCALE_SUPPORT
16 #endif
17 
18 #ifndef JSONCPP_NO_LOCALE_SUPPORT
19 #include <clocale>
20 #endif
21 
22 /* This header provides common string manipulation support, such as UTF-8,
23  * portable conversion from/to string...
24  *
25  * It is an internal header that must not be exposed.
26  */
27 
28 namespace Json {
getDecimalPoint()29 static inline char getDecimalPoint() {
30 #ifdef JSONCPP_NO_LOCALE_SUPPORT
31   return '\0';
32 #else
33   struct lconv* lc = localeconv();
34   return lc ? *(lc->decimal_point) : '\0';
35 #endif
36 }
37 
38 /// Converts a unicode code-point to UTF-8.
codePointToUTF8(unsigned int cp)39 static inline String codePointToUTF8(unsigned int cp) {
40   String result;
41 
42   // based on description from http://en.wikipedia.org/wiki/UTF-8
43 
44   if (cp <= 0x7f) {
45     result.resize(1);
46     result[0] = static_cast<char>(cp);
47   } else if (cp <= 0x7FF) {
48     result.resize(2);
49     result[1] = static_cast<char>(0x80 | (0x3f & cp));
50     result[0] = static_cast<char>(0xC0 | (0x1f & (cp >> 6)));
51   } else if (cp <= 0xFFFF) {
52     result.resize(3);
53     result[2] = static_cast<char>(0x80 | (0x3f & cp));
54     result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 6)));
55     result[0] = static_cast<char>(0xE0 | (0xf & (cp >> 12)));
56   } else if (cp <= 0x10FFFF) {
57     result.resize(4);
58     result[3] = static_cast<char>(0x80 | (0x3f & cp));
59     result[2] = static_cast<char>(0x80 | (0x3f & (cp >> 6)));
60     result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 12)));
61     result[0] = static_cast<char>(0xF0 | (0x7 & (cp >> 18)));
62   }
63 
64   return result;
65 }
66 
67 enum {
68   /// Constant that specify the size of the buffer that must be passed to
69   /// uintToString.
70   uintToStringBufferSize = 3 * sizeof(LargestUInt) + 1
71 };
72 
73 // Defines a char buffer for use with uintToString().
74 using UIntToStringBuffer = char[uintToStringBufferSize];
75 
76 /** Converts an unsigned integer to string.
77  * @param value Unsigned integer to convert to string
78  * @param current Input/Output string buffer.
79  *        Must have at least uintToStringBufferSize chars free.
80  */
uintToString(LargestUInt value,char * & current)81 static inline void uintToString(LargestUInt value, char*& current) {
82   *--current = 0;
83   do {
84     *--current = static_cast<char>(value % 10U + static_cast<unsigned>('0'));
85     value /= 10;
86   } while (value != 0);
87 }
88 
89 /** Change ',' to '.' everywhere in buffer.
90  *
91  * We had a sophisticated way, but it did not work in WinCE.
92  * @see https://github.com/open-source-parsers/jsoncpp/pull/9
93  */
fixNumericLocale(Iter begin,Iter end)94 template <typename Iter> Iter fixNumericLocale(Iter begin, Iter end) {
95   for (; begin != end; ++begin) {
96     if (*begin == ',') {
97       *begin = '.';
98     }
99   }
100   return begin;
101 }
102 
fixNumericLocaleInput(Iter begin,Iter end)103 template <typename Iter> void fixNumericLocaleInput(Iter begin, Iter end) {
104   char decimalPoint = getDecimalPoint();
105   if (decimalPoint == '\0' || decimalPoint == '.') {
106     return;
107   }
108   for (; begin != end; ++begin) {
109     if (*begin == '.') {
110       *begin = decimalPoint;
111     }
112   }
113 }
114 
115 /**
116  * Return iterator that would be the new end of the range [begin,end), if we
117  * were to delete zeros in the end of string, but not the last zero before '.'.
118  */
119 template <typename Iter>
fixZerosInTheEnd(Iter begin,Iter end,unsigned int precision)120 Iter fixZerosInTheEnd(Iter begin, Iter end, unsigned int precision) {
121   for (; begin != end; --end) {
122     if (*(end - 1) != '0') {
123       return end;
124     }
125     // Don't delete the last zero before the decimal point.
126     if (begin != (end - 1) && begin != (end - 2) && *(end - 2) == '.') {
127       if (precision) {
128         return end;
129       }
130       return end - 2;
131     }
132   }
133   return end;
134 }
135 
136 } // namespace Json
137 
138 #endif // LIB_JSONCPP_JSON_TOOL_H_INCLUDED
139