1 /* 2 * Copyright (C) 2010 Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include "config.h" 32 #include "platform/JSONValues.h" 33 34 #include "wtf/DecimalNumber.h" 35 #include "wtf/dtoa.h" 36 #include "wtf/text/StringBuilder.h" 37 38 namespace WebCore { 39 40 namespace { 41 42 const char* const nullString = "null"; 43 const char* const trueString = "true"; 44 const char* const falseString = "false"; 45 46 inline bool escapeChar(UChar c, StringBuilder* dst) 47 { 48 switch (c) { 49 case '\b': dst->append("\\b", 2); break; 50 case '\f': dst->append("\\f", 2); break; 51 case '\n': dst->append("\\n", 2); break; 52 case '\r': dst->append("\\r", 2); break; 53 case '\t': dst->append("\\t", 2); break; 54 case '\\': dst->append("\\\\", 2); break; 55 case '"': dst->append("\\\"", 2); break; 56 default: 57 return false; 58 } 59 return true; 60 } 61 62 inline void doubleQuoteString(const String& str, StringBuilder* dst) 63 { 64 dst->append('"'); 65 for (unsigned i = 0; i < str.length(); ++i) { 66 UChar c = str[i]; 67 if (!escapeChar(c, dst)) { 68 if (c < 32 || c > 126 || c == '<' || c == '>') { 69 // 1. Escaping <, > to prevent script execution. 70 // 2. Technically, we could also pass through c > 126 as UTF8, but this 71 // is also optional. It would also be a pain to implement here. 72 unsigned symbol = static_cast<unsigned>(c); 73 String symbolCode = String::format("\\u%04X", symbol); 74 dst->append(symbolCode); 75 } else { 76 dst->append(c); 77 } 78 } 79 } 80 dst->append('"'); 81 } 82 83 } // anonymous namespace 84 85 bool JSONValue::asBoolean(bool*) const 86 { 87 return false; 88 } 89 90 bool JSONValue::asNumber(double*) const 91 { 92 return false; 93 } 94 95 bool JSONValue::asNumber(long*) const 96 { 97 return false; 98 } 99 100 bool JSONValue::asNumber(int*) const 101 { 102 return false; 103 } 104 105 bool JSONValue::asNumber(unsigned long*) const 106 { 107 return false; 108 } 109 110 bool JSONValue::asNumber(unsigned*) const 111 { 112 return false; 113 } 114 115 bool JSONValue::asString(String*) const 116 { 117 return false; 118 } 119 120 bool JSONValue::asValue(RefPtr<JSONValue>* output) 121 { 122 *output = this; 123 return true; 124 } 125 126 bool JSONValue::asObject(RefPtr<JSONObject>*) 127 { 128 return false; 129 } 130 131 bool JSONValue::asArray(RefPtr<JSONArray>*) 132 { 133 return false; 134 } 135 136 PassRefPtr<JSONObject> JSONValue::asObject() 137 { 138 return 0; 139 } 140 141 PassRefPtr<JSONArray> JSONValue::asArray() 142 { 143 return 0; 144 } 145 146 String JSONValue::toJSONString() const 147 { 148 StringBuilder result; 149 result.reserveCapacity(512); 150 writeJSON(&result); 151 return result.toString(); 152 } 153 154 void JSONValue::writeJSON(StringBuilder* output) const 155 { 156 ASSERT(m_type == TypeNull); 157 output->append(nullString, 4); 158 } 159 160 bool JSONBasicValue::asBoolean(bool* output) const 161 { 162 if (type() != TypeBoolean) 163 return false; 164 *output = m_boolValue; 165 return true; 166 } 167 168 bool JSONBasicValue::asNumber(double* output) const 169 { 170 if (type() != TypeNumber) 171 return false; 172 *output = m_doubleValue; 173 return true; 174 } 175 176 bool JSONBasicValue::asNumber(long* output) const 177 { 178 if (type() != TypeNumber) 179 return false; 180 *output = static_cast<long>(m_doubleValue); 181 return true; 182 } 183 184 bool JSONBasicValue::asNumber(int* output) const 185 { 186 if (type() != TypeNumber) 187 return false; 188 *output = static_cast<int>(m_doubleValue); 189 return true; 190 } 191 192 bool JSONBasicValue::asNumber(unsigned long* output) const 193 { 194 if (type() != TypeNumber) 195 return false; 196 *output = static_cast<unsigned long>(m_doubleValue); 197 return true; 198 } 199 200 bool JSONBasicValue::asNumber(unsigned* output) const 201 { 202 if (type() != TypeNumber) 203 return false; 204 *output = static_cast<unsigned>(m_doubleValue); 205 return true; 206 } 207 208 void JSONBasicValue::writeJSON(StringBuilder* output) const 209 { 210 ASSERT(type() == TypeBoolean || type() == TypeNumber); 211 if (type() == TypeBoolean) { 212 if (m_boolValue) 213 output->append(trueString, 4); 214 else 215 output->append(falseString, 5); 216 } else if (type() == TypeNumber) { 217 NumberToLStringBuffer buffer; 218 if (!std::isfinite(m_doubleValue)) { 219 output->append(nullString, 4); 220 return; 221 } 222 DecimalNumber decimal = m_doubleValue; 223 unsigned length = 0; 224 if (decimal.bufferLengthForStringDecimal() > WTF::NumberToStringBufferLength) { 225 // Not enough room for decimal. Use exponential format. 226 if (decimal.bufferLengthForStringExponential() > WTF::NumberToStringBufferLength) { 227 // Fallback for an abnormal case if it's too little even for exponential. 228 output->append("NaN", 3); 229 return; 230 } 231 length = decimal.toStringExponential(buffer, WTF::NumberToStringBufferLength); 232 } else { 233 length = decimal.toStringDecimal(buffer, WTF::NumberToStringBufferLength); 234 } 235 output->append(buffer, length); 236 } 237 } 238 239 bool JSONString::asString(String* output) const 240 { 241 *output = m_stringValue; 242 return true; 243 } 244 245 void JSONString::writeJSON(StringBuilder* output) const 246 { 247 ASSERT(type() == TypeString); 248 doubleQuoteString(m_stringValue, output); 249 } 250 251 JSONObjectBase::~JSONObjectBase() 252 { 253 } 254 255 bool JSONObjectBase::asObject(RefPtr<JSONObject>* output) 256 { 257 COMPILE_ASSERT(sizeof(JSONObject) == sizeof(JSONObjectBase), cannot_cast); 258 *output = static_cast<JSONObject*>(this); 259 return true; 260 } 261 262 PassRefPtr<JSONObject> JSONObjectBase::asObject() 263 { 264 return openAccessors(); 265 } 266 267 JSONObject* JSONObjectBase::openAccessors() 268 { 269 COMPILE_ASSERT(sizeof(JSONObject) == sizeof(JSONObjectBase), cannot_cast); 270 return static_cast<JSONObject*>(this); 271 } 272 273 bool JSONObjectBase::getBoolean(const String& name, bool* output) const 274 { 275 RefPtr<JSONValue> value = get(name); 276 if (!value) 277 return false; 278 return value->asBoolean(output); 279 } 280 281 bool JSONObjectBase::getString(const String& name, String* output) const 282 { 283 RefPtr<JSONValue> value = get(name); 284 if (!value) 285 return false; 286 return value->asString(output); 287 } 288 289 PassRefPtr<JSONObject> JSONObjectBase::getObject(const String& name) const 290 { 291 RefPtr<JSONValue> value = get(name); 292 if (!value) 293 return 0; 294 return value->asObject(); 295 } 296 297 PassRefPtr<JSONArray> JSONObjectBase::getArray(const String& name) const 298 { 299 RefPtr<JSONValue> value = get(name); 300 if (!value) 301 return 0; 302 return value->asArray(); 303 } 304 305 PassRefPtr<JSONValue> JSONObjectBase::get(const String& name) const 306 { 307 Dictionary::const_iterator it = m_data.find(name); 308 if (it == m_data.end()) 309 return 0; 310 return it->value; 311 } 312 313 void JSONObjectBase::remove(const String& name) 314 { 315 m_data.remove(name); 316 for (size_t i = 0; i < m_order.size(); ++i) { 317 if (m_order[i] == name) { 318 m_order.remove(i); 319 break; 320 } 321 } 322 } 323 324 void JSONObjectBase::writeJSON(StringBuilder* output) const 325 { 326 output->append('{'); 327 for (size_t i = 0; i < m_order.size(); ++i) { 328 Dictionary::const_iterator it = m_data.find(m_order[i]); 329 ASSERT_WITH_SECURITY_IMPLICATION(it != m_data.end()); 330 if (i) 331 output->append(','); 332 doubleQuoteString(it->key, output); 333 output->append(':'); 334 it->value->writeJSON(output); 335 } 336 output->append('}'); 337 } 338 339 JSONObjectBase::JSONObjectBase() 340 : JSONValue(TypeObject) 341 , m_data() 342 , m_order() 343 { 344 } 345 346 JSONArrayBase::~JSONArrayBase() 347 { 348 } 349 350 bool JSONArrayBase::asArray(RefPtr<JSONArray>* output) 351 { 352 COMPILE_ASSERT(sizeof(JSONArrayBase) == sizeof(JSONArray), cannot_cast); 353 *output = static_cast<JSONArray*>(this); 354 return true; 355 } 356 357 PassRefPtr<JSONArray> JSONArrayBase::asArray() 358 { 359 COMPILE_ASSERT(sizeof(JSONArrayBase) == sizeof(JSONArray), cannot_cast); 360 return static_cast<JSONArray*>(this); 361 } 362 363 void JSONArrayBase::writeJSON(StringBuilder* output) const 364 { 365 output->append('['); 366 for (Vector<RefPtr<JSONValue> >::const_iterator it = m_data.begin(); it != m_data.end(); ++it) { 367 if (it != m_data.begin()) 368 output->append(','); 369 (*it)->writeJSON(output); 370 } 371 output->append(']'); 372 } 373 374 JSONArrayBase::JSONArrayBase() 375 : JSONValue(TypeArray) 376 , m_data() 377 { 378 } 379 380 PassRefPtr<JSONValue> JSONArrayBase::get(size_t index) 381 { 382 ASSERT_WITH_SECURITY_IMPLICATION(index < m_data.size()); 383 return m_data[index]; 384 } 385 386 } // namespace WebCore 387