1 // Copyright 2016 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "tracing/traced_value.h"
6
7 #if defined(NODE_HAVE_I18N_SUPPORT)
8 #include <unicode/utf8.h>
9 #include <unicode/utypes.h>
10 #endif
11
12 #include <cmath>
13 #include <cstdio>
14 #include <sstream>
15 #include <string>
16
17 #if defined(_STLP_VENDOR_CSTD)
18 // STLPort doesn't import fpclassify into the std namespace.
19 #define FPCLASSIFY_NAMESPACE
20 #else
21 #define FPCLASSIFY_NAMESPACE std
22 #endif
23
24 namespace node {
25 namespace tracing {
26
27 namespace {
28
EscapeString(const char * value)29 std::string EscapeString(const char* value) {
30 std::string result;
31 result += '"';
32 char number_buffer[10];
33 #if defined(NODE_HAVE_I18N_SUPPORT)
34 int32_t len = strlen(value);
35 int32_t p = 0;
36 int32_t i = 0;
37 for (; i < len; p = i) {
38 UChar32 c;
39 U8_NEXT_OR_FFFD(value, i, len, c);
40 switch (c) {
41 case '\b': result += "\\b"; break;
42 case '\f': result += "\\f"; break;
43 case '\n': result += "\\n"; break;
44 case '\r': result += "\\r"; break;
45 case '\t': result += "\\t"; break;
46 case '\\': result += "\\\\"; break;
47 case '"': result += "\\\""; break;
48 default:
49 if (c < 32 || c > 126) {
50 snprintf(
51 number_buffer, arraysize(number_buffer), "\\u%04X",
52 static_cast<uint16_t>(static_cast<uint16_t>(c)));
53 result += number_buffer;
54 } else {
55 result.append(value + p, i - p);
56 }
57 }
58 }
59 #else
60 // If we do not have ICU, use a modified version of the non-UTF8 aware
61 // code from V8's own TracedValue implementation. Note, however, This
62 // will not produce correctly serialized results for UTF8 values.
63 while (*value) {
64 char c = *value++;
65 switch (c) {
66 case '\b': result += "\\b"; break;
67 case '\f': result += "\\f"; break;
68 case '\n': result += "\\n"; break;
69 case '\r': result += "\\r"; break;
70 case '\t': result += "\\t"; break;
71 case '\\': result += "\\\\"; break;
72 case '"': result += "\\\""; break;
73 default:
74 if (c < '\x20') {
75 snprintf(
76 number_buffer, arraysize(number_buffer), "\\u%04X",
77 static_cast<unsigned>(static_cast<unsigned char>(c)));
78 result += number_buffer;
79 } else {
80 result += c;
81 }
82 }
83 }
84 #endif // defined(NODE_HAVE_I18N_SUPPORT)
85 result += '"';
86 return result;
87 }
88
DoubleToCString(double v)89 std::string DoubleToCString(double v) {
90 switch (FPCLASSIFY_NAMESPACE::fpclassify(v)) {
91 case FP_NAN: return "\"NaN\"";
92 case FP_INFINITE: return (v < 0.0 ? "\"-Infinity\"" : "\"Infinity\"");
93 case FP_ZERO: return "0";
94 default:
95 // This is a far less sophisticated version than the one used inside v8.
96 std::ostringstream stream;
97 stream.imbue(std::locale::classic()); // Ignore current locale
98 stream << v;
99 return stream.str();
100 }
101 }
102
103 } // namespace
104
Create()105 std::unique_ptr<TracedValue> TracedValue::Create() {
106 return std::unique_ptr<TracedValue>(new TracedValue(false));
107 }
108
CreateArray()109 std::unique_ptr<TracedValue> TracedValue::CreateArray() {
110 return std::unique_ptr<TracedValue>(new TracedValue(true));
111 }
112
TracedValue(bool root_is_array)113 TracedValue::TracedValue(bool root_is_array) :
114 first_item_(true), root_is_array_(root_is_array) {}
115
SetInteger(const char * name,int value)116 void TracedValue::SetInteger(const char* name, int value) {
117 WriteName(name);
118 data_ += std::to_string(value);
119 }
120
SetDouble(const char * name,double value)121 void TracedValue::SetDouble(const char* name, double value) {
122 WriteName(name);
123 data_ += DoubleToCString(value);
124 }
125
SetBoolean(const char * name,bool value)126 void TracedValue::SetBoolean(const char* name, bool value) {
127 WriteName(name);
128 data_ += value ? "true" : "false";
129 }
130
SetNull(const char * name)131 void TracedValue::SetNull(const char* name) {
132 WriteName(name);
133 data_ += "null";
134 }
135
SetString(const char * name,const char * value)136 void TracedValue::SetString(const char* name, const char* value) {
137 WriteName(name);
138 data_ += EscapeString(value);
139 }
140
BeginDictionary(const char * name)141 void TracedValue::BeginDictionary(const char* name) {
142 WriteName(name);
143 data_ += '{';
144 first_item_ = true;
145 }
146
BeginArray(const char * name)147 void TracedValue::BeginArray(const char* name) {
148 WriteName(name);
149 data_ += '[';
150 first_item_ = true;
151 }
152
AppendInteger(int value)153 void TracedValue::AppendInteger(int value) {
154 WriteComma();
155 data_ += std::to_string(value);
156 }
157
AppendDouble(double value)158 void TracedValue::AppendDouble(double value) {
159 WriteComma();
160 data_ += DoubleToCString(value);
161 }
162
AppendBoolean(bool value)163 void TracedValue::AppendBoolean(bool value) {
164 WriteComma();
165 data_ += value ? "true" : "false";
166 }
167
AppendNull()168 void TracedValue::AppendNull() {
169 WriteComma();
170 data_ += "null";
171 }
172
AppendString(const char * value)173 void TracedValue::AppendString(const char* value) {
174 WriteComma();
175 data_ += EscapeString(value);
176 }
177
BeginDictionary()178 void TracedValue::BeginDictionary() {
179 WriteComma();
180 data_ += '{';
181 first_item_ = true;
182 }
183
BeginArray()184 void TracedValue::BeginArray() {
185 WriteComma();
186 data_ += '[';
187 first_item_ = true;
188 }
189
EndDictionary()190 void TracedValue::EndDictionary() {
191 data_ += '}';
192 first_item_ = false;
193 }
194
EndArray()195 void TracedValue::EndArray() {
196 data_ += ']';
197 first_item_ = false;
198 }
199
WriteComma()200 void TracedValue::WriteComma() {
201 if (first_item_) {
202 first_item_ = false;
203 } else {
204 data_ += ',';
205 }
206 }
207
WriteName(const char * name)208 void TracedValue::WriteName(const char* name) {
209 WriteComma();
210 data_ += '"';
211 data_ += name;
212 data_ += "\":";
213 }
214
AppendAsTraceFormat(std::string * out) const215 void TracedValue::AppendAsTraceFormat(std::string* out) const {
216 *out += root_is_array_ ? '[' : '{';
217 *out += data_;
218 *out += root_is_array_ ? ']' : '}';
219 }
220
221 } // namespace tracing
222 } // namespace node
223