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 "core/platform/JSONValues.h" 33 34#include "wtf/DecimalNumber.h" 35#include "wtf/dtoa.h" 36#include "wtf/text/StringBuilder.h" 37 38namespace WebCore { 39 40namespace { 41 42const char* const nullString = "null"; 43const char* const trueString = "true"; 44const char* const falseString = "false"; 45 46inline 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 62inline 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 85bool JSONValue::asBoolean(bool*) const 86{ 87 return false; 88} 89 90bool JSONValue::asNumber(double*) const 91{ 92 return false; 93} 94 95bool JSONValue::asNumber(long*) const 96{ 97 return false; 98} 99 100bool JSONValue::asNumber(int*) const 101{ 102 return false; 103} 104 105bool JSONValue::asNumber(unsigned long*) const 106{ 107 return false; 108} 109 110bool JSONValue::asNumber(unsigned*) const 111{ 112 return false; 113} 114 115bool JSONValue::asString(String*) const 116{ 117 return false; 118} 119 120bool JSONValue::asValue(RefPtr<JSONValue>* output) 121{ 122 *output = this; 123 return true; 124} 125 126bool JSONValue::asObject(RefPtr<JSONObject>*) 127{ 128 return false; 129} 130 131bool JSONValue::asArray(RefPtr<JSONArray>*) 132{ 133 return false; 134} 135 136PassRefPtr<JSONObject> JSONValue::asObject() 137{ 138 return 0; 139} 140 141PassRefPtr<JSONArray> JSONValue::asArray() 142{ 143 return 0; 144} 145 146String JSONValue::toJSONString() const 147{ 148 StringBuilder result; 149 result.reserveCapacity(512); 150 writeJSON(&result); 151 return result.toString(); 152} 153 154void JSONValue::writeJSON(StringBuilder* output) const 155{ 156 ASSERT(m_type == TypeNull); 157 output->append(nullString, 4); 158} 159 160bool JSONBasicValue::asBoolean(bool* output) const 161{ 162 if (type() != TypeBoolean) 163 return false; 164 *output = m_boolValue; 165 return true; 166} 167 168bool JSONBasicValue::asNumber(double* output) const 169{ 170 if (type() != TypeNumber) 171 return false; 172 *output = m_doubleValue; 173 return true; 174} 175 176bool 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 184bool 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 192bool 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 200bool 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 208void 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 239bool JSONString::asString(String* output) const 240{ 241 *output = m_stringValue; 242 return true; 243} 244 245void JSONString::writeJSON(StringBuilder* output) const 246{ 247 ASSERT(type() == TypeString); 248 doubleQuoteString(m_stringValue, output); 249} 250 251JSONObjectBase::~JSONObjectBase() 252{ 253} 254 255bool 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 262PassRefPtr<JSONObject> JSONObjectBase::asObject() 263{ 264 return openAccessors(); 265} 266 267JSONObject* JSONObjectBase::openAccessors() 268{ 269 COMPILE_ASSERT(sizeof(JSONObject) == sizeof(JSONObjectBase), cannot_cast); 270 return static_cast<JSONObject*>(this); 271} 272 273bool 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 281bool 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 289PassRefPtr<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 297PassRefPtr<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 305PassRefPtr<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 313void 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 324void 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(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 339JSONObjectBase::JSONObjectBase() 340 : JSONValue(TypeObject) 341 , m_data() 342 , m_order() 343{ 344} 345 346JSONArrayBase::~JSONArrayBase() 347{ 348} 349 350bool 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 357PassRefPtr<JSONArray> JSONArrayBase::asArray() 358{ 359 COMPILE_ASSERT(sizeof(JSONArrayBase) == sizeof(JSONArray), cannot_cast); 360 return static_cast<JSONArray*>(this); 361} 362 363void 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 374JSONArrayBase::JSONArrayBase() 375 : JSONValue(TypeArray) 376 , m_data() 377{ 378} 379 380PassRefPtr<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