• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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