Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "base/json/json_parser.h" | 5 #include "base/json/json_parser.h" |
| 6 | 6 |
| 7 #include <cmath> | 7 #include <cmath> |
| 8 #include <memory> | 8 #include <utility> |
| 9 | 9 |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| 11 #include "base/macros.h" | 11 #include "base/macros.h" |
| 12 #include "base/memory/ptr_util.h" | |
| 12 #include "base/strings/string_number_conversions.h" | 13 #include "base/strings/string_number_conversions.h" |
| 13 #include "base/strings/string_piece.h" | 14 #include "base/strings/string_piece.h" |
| 14 #include "base/strings/string_util.h" | 15 #include "base/strings/string_util.h" |
| 15 #include "base/strings/stringprintf.h" | 16 #include "base/strings/stringprintf.h" |
| 16 #include "base/strings/utf_string_conversion_utils.h" | 17 #include "base/strings/utf_string_conversion_utils.h" |
| 17 #include "base/strings/utf_string_conversions.h" | 18 #include "base/strings/utf_string_conversions.h" |
| 18 #include "base/third_party/icu/icu_utf.h" | 19 #include "base/third_party/icu/icu_utf.h" |
| 19 #include "base/values.h" | 20 #include "base/values.h" |
| 20 | 21 |
| 21 namespace base { | 22 namespace base { |
| 22 namespace internal { | 23 namespace internal { |
| 23 | 24 |
| 24 namespace { | 25 namespace { |
| 25 | 26 |
| 26 const int kStackMaxDepth = 100; | 27 const int kStackMaxDepth = 100; |
| 27 | 28 |
| 28 const int32_t kExtendedASCIIStart = 0x80; | 29 const int32_t kExtendedASCIIStart = 0x80; |
| 29 | 30 |
| 30 // This and the class below are used to own the JSON input string for when | 31 // DictionaryHiddenRootValue and ListHiddenRootValue are used in conjunction |
| 31 // string tokens are stored as StringPiece instead of std::string. This | 32 // with JSONStringValue as an optimization for reducing the number of string |
| 32 // optimization avoids about 2/3rds of string memory copies. The constructor | 33 // copies. When this optimization is active, the parser uses a hidden root to |
| 33 // takes ownership of the input string. The real root value is Swap()ed into | 34 // keep the original JSON input string live and creates JSONStringValue children |
| 34 // the new instance. | 35 // holding StringPiece references to the input string, avoiding about 2/3rds of |
| 36 // string memory copies. The real root value is Swap()ed into the new instance. | |
| 35 class DictionaryHiddenRootValue : public DictionaryValue { | 37 class DictionaryHiddenRootValue : public DictionaryValue { |
| 36 public: | 38 public: |
| 37 DictionaryHiddenRootValue(std::string* json, Value* root) : json_(json) { | 39 DictionaryHiddenRootValue(std::unique_ptr<std::string> json, |
| 40 std::unique_ptr<Value> root) | |
| 41 : json_(std::move(json)) { | |
| 38 DCHECK(root->IsType(Value::TYPE_DICTIONARY)); | 42 DCHECK(root->IsType(Value::TYPE_DICTIONARY)); |
| 39 DictionaryValue::Swap(static_cast<DictionaryValue*>(root)); | 43 DictionaryValue::Swap(static_cast<DictionaryValue*>(root.get())); |
|
danakj
2016/04/28 17:39:37
This should be passing the unique_ptr. Can you TOD
dcheng
2016/04/28 18:03:23
Should it though? It's not really moving/taking ow
danakj
2016/04/28 18:09:19
Oh I guess you're right yah, it's swapping stuff i
| |
| 40 } | 44 } |
| 41 | 45 |
| 42 void Swap(DictionaryValue* other) override { | 46 void Swap(DictionaryValue* other) override { |
| 43 DVLOG(1) << "Swap()ing a DictionaryValue inefficiently."; | 47 DVLOG(1) << "Swap()ing a DictionaryValue inefficiently."; |
| 44 | 48 |
| 45 // First deep copy to convert JSONStringValue to std::string and swap that | 49 // First deep copy to convert JSONStringValue to std::string and swap that |
| 46 // copy with |other|, which contains the new contents of |this|. | 50 // copy with |other|, which contains the new contents of |this|. |
| 47 std::unique_ptr<DictionaryValue> copy(DeepCopy()); | 51 std::unique_ptr<DictionaryValue> copy(CreateDeepCopy()); |
| 48 copy->Swap(other); | 52 copy->Swap(other); |
| 49 | 53 |
| 50 // Then erase the contents of the current dictionary and swap in the | 54 // Then erase the contents of the current dictionary and swap in the |
| 51 // new contents, originally from |other|. | 55 // new contents, originally from |other|. |
| 52 Clear(); | 56 Clear(); |
| 53 json_.reset(); | 57 json_.reset(); |
| 54 DictionaryValue::Swap(copy.get()); | 58 DictionaryValue::Swap(copy.get()); |
| 55 } | 59 } |
| 56 | 60 |
| 57 // Not overriding DictionaryValue::Remove because it just calls through to | 61 // Not overriding DictionaryValue::Remove because it just calls through to |
| 58 // the method below. | 62 // the method below. |
| 59 | 63 |
| 60 bool RemoveWithoutPathExpansion(const std::string& key, | 64 bool RemoveWithoutPathExpansion(const std::string& key, |
| 61 std::unique_ptr<Value>* out) override { | 65 std::unique_ptr<Value>* out) override { |
| 62 // If the caller won't take ownership of the removed value, just call up. | 66 // If the caller won't take ownership of the removed value, just call up. |
| 63 if (!out) | 67 if (!out) |
| 64 return DictionaryValue::RemoveWithoutPathExpansion(key, out); | 68 return DictionaryValue::RemoveWithoutPathExpansion(key, out); |
| 65 | 69 |
| 66 DVLOG(1) << "Remove()ing from a DictionaryValue inefficiently."; | 70 DVLOG(1) << "Remove()ing from a DictionaryValue inefficiently."; |
| 67 | 71 |
| 68 // Otherwise, remove the value while its still "owned" by this and copy it | 72 // Otherwise, remove the value while its still "owned" by this and copy it |
| 69 // to convert any JSONStringValues to std::string. | 73 // to convert any JSONStringValues to std::string. |
| 70 std::unique_ptr<Value> out_owned; | 74 std::unique_ptr<Value> out_owned; |
| 71 if (!DictionaryValue::RemoveWithoutPathExpansion(key, &out_owned)) | 75 if (!DictionaryValue::RemoveWithoutPathExpansion(key, &out_owned)) |
| 72 return false; | 76 return false; |
| 73 | 77 |
| 74 out->reset(out_owned->DeepCopy()); | 78 *out = out_owned->CreateDeepCopy(); |
| 75 | 79 |
| 76 return true; | 80 return true; |
| 77 } | 81 } |
| 78 | 82 |
| 79 private: | 83 private: |
| 80 std::unique_ptr<std::string> json_; | 84 std::unique_ptr<std::string> json_; |
| 81 | 85 |
| 82 DISALLOW_COPY_AND_ASSIGN(DictionaryHiddenRootValue); | 86 DISALLOW_COPY_AND_ASSIGN(DictionaryHiddenRootValue); |
| 83 }; | 87 }; |
| 84 | 88 |
| 85 class ListHiddenRootValue : public ListValue { | 89 class ListHiddenRootValue : public ListValue { |
| 86 public: | 90 public: |
| 87 ListHiddenRootValue(std::string* json, Value* root) : json_(json) { | 91 ListHiddenRootValue(std::unique_ptr<std::string> json, |
| 92 std::unique_ptr<Value> root) | |
| 93 : json_(std::move(json)) { | |
| 88 DCHECK(root->IsType(Value::TYPE_LIST)); | 94 DCHECK(root->IsType(Value::TYPE_LIST)); |
| 89 ListValue::Swap(static_cast<ListValue*>(root)); | 95 ListValue::Swap(static_cast<ListValue*>(root.get())); |
|
danakj
2016/04/28 17:39:37
ditto
dcheng
2016/04/28 18:03:23
See previous.
| |
| 90 } | 96 } |
| 91 | 97 |
| 92 void Swap(ListValue* other) override { | 98 void Swap(ListValue* other) override { |
| 93 DVLOG(1) << "Swap()ing a ListValue inefficiently."; | 99 DVLOG(1) << "Swap()ing a ListValue inefficiently."; |
| 94 | 100 |
| 95 // First deep copy to convert JSONStringValue to std::string and swap that | 101 // First deep copy to convert JSONStringValue to std::string and swap that |
| 96 // copy with |other|, which contains the new contents of |this|. | 102 // copy with |other|, which contains the new contents of |this|. |
| 97 std::unique_ptr<ListValue> copy(DeepCopy()); | 103 std::unique_ptr<ListValue> copy(CreateDeepCopy()); |
| 98 copy->Swap(other); | 104 copy->Swap(other); |
| 99 | 105 |
| 100 // Then erase the contents of the current list and swap in the new contents, | 106 // Then erase the contents of the current list and swap in the new contents, |
| 101 // originally from |other|. | 107 // originally from |other|. |
| 102 Clear(); | 108 Clear(); |
| 103 json_.reset(); | 109 json_.reset(); |
| 104 ListValue::Swap(copy.get()); | 110 ListValue::Swap(copy.get()); |
| 105 } | 111 } |
| 106 | 112 |
| 107 bool Remove(size_t index, std::unique_ptr<Value>* out) override { | 113 bool Remove(size_t index, std::unique_ptr<Value>* out) override { |
| 108 // If the caller won't take ownership of the removed value, just call up. | 114 // If the caller won't take ownership of the removed value, just call up. |
| 109 if (!out) | 115 if (!out) |
| 110 return ListValue::Remove(index, out); | 116 return ListValue::Remove(index, out); |
| 111 | 117 |
| 112 DVLOG(1) << "Remove()ing from a ListValue inefficiently."; | 118 DVLOG(1) << "Remove()ing from a ListValue inefficiently."; |
| 113 | 119 |
| 114 // Otherwise, remove the value while its still "owned" by this and copy it | 120 // Otherwise, remove the value while its still "owned" by this and copy it |
| 115 // to convert any JSONStringValues to std::string. | 121 // to convert any JSONStringValues to std::string. |
| 116 std::unique_ptr<Value> out_owned; | 122 std::unique_ptr<Value> out_owned; |
| 117 if (!ListValue::Remove(index, &out_owned)) | 123 if (!ListValue::Remove(index, &out_owned)) |
|
danakj
2016/04/28 17:39:37
heh, we should just have this return std::unique_p
dcheng
2016/04/28 18:03:23
Acknowledged.
| |
| 118 return false; | 124 return false; |
| 119 | 125 |
| 120 out->reset(out_owned->DeepCopy()); | 126 *out = out_owned->CreateDeepCopy(); |
| 121 | 127 |
| 122 return true; | 128 return true; |
| 123 } | 129 } |
| 124 | 130 |
| 125 private: | 131 private: |
| 126 std::unique_ptr<std::string> json_; | 132 std::unique_ptr<std::string> json_; |
| 127 | 133 |
| 128 DISALLOW_COPY_AND_ASSIGN(ListHiddenRootValue); | 134 DISALLOW_COPY_AND_ASSIGN(ListHiddenRootValue); |
| 129 }; | 135 }; |
| 130 | 136 |
| 131 // A variant on StringValue that uses StringPiece instead of copying the string | 137 // A variant on StringValue that uses StringPiece instead of copying the string |
| 132 // into the Value. This can only be stored in a child of hidden root (above), | 138 // into the Value. This can only be stored in a child of hidden root (above), |
| 133 // otherwise the referenced string will not be guaranteed to outlive it. | 139 // otherwise the referenced string will not be guaranteed to outlive it. |
| 134 class JSONStringValue : public Value { | 140 class JSONStringValue : public Value { |
| 135 public: | 141 public: |
| 136 explicit JSONStringValue(const StringPiece& piece) | 142 explicit JSONStringValue(StringPiece piece) |
| 137 : Value(TYPE_STRING), | 143 : Value(TYPE_STRING), string_piece_(piece) {} |
|
danakj
2016/04/28 17:39:37
nit: move piece? (i know its the same as copy atm)
dcheng
2016/04/28 18:03:23
Why though? copy on a StringPiece will be cheaper
jbroman
2016/04/28 18:06:18
nit-nit: base::StringPiece explicitly promises in
danakj
2016/04/28 18:09:19
Ah I see I see. #newtostrings. LGTM
| |
| 138 string_piece_(piece) { | |
| 139 } | |
| 140 | 144 |
| 141 // Overridden from Value: | 145 // Overridden from Value: |
| 142 bool GetAsString(std::string* out_value) const override { | 146 bool GetAsString(std::string* out_value) const override { |
| 143 string_piece_.CopyToString(out_value); | 147 string_piece_.CopyToString(out_value); |
| 144 return true; | 148 return true; |
| 145 } | 149 } |
| 146 bool GetAsString(string16* out_value) const override { | 150 bool GetAsString(string16* out_value) const override { |
| 147 *out_value = UTF8ToUTF16(string_piece_); | 151 *out_value = UTF8ToUTF16(string_piece_); |
| 148 return true; | 152 return true; |
| 149 } | 153 } |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 196 line_number_(0), | 200 line_number_(0), |
| 197 index_last_line_(0), | 201 index_last_line_(0), |
| 198 error_code_(JSONReader::JSON_NO_ERROR), | 202 error_code_(JSONReader::JSON_NO_ERROR), |
| 199 error_line_(0), | 203 error_line_(0), |
| 200 error_column_(0) { | 204 error_column_(0) { |
| 201 } | 205 } |
| 202 | 206 |
| 203 JSONParser::~JSONParser() { | 207 JSONParser::~JSONParser() { |
| 204 } | 208 } |
| 205 | 209 |
| 206 Value* JSONParser::Parse(const StringPiece& input) { | 210 std::unique_ptr<Value> JSONParser::Parse(StringPiece input) { |
| 207 std::unique_ptr<std::string> input_copy; | 211 std::unique_ptr<std::string> input_copy; |
| 208 // If the children of a JSON root can be detached, then hidden roots cannot | 212 // If the children of a JSON root can be detached, then hidden roots cannot |
| 209 // be used, so do not bother copying the input because StringPiece will not | 213 // be used, so do not bother copying the input because StringPiece will not |
| 210 // be used anywhere. | 214 // be used anywhere. |
| 211 if (!(options_ & JSON_DETACHABLE_CHILDREN)) { | 215 if (!(options_ & JSON_DETACHABLE_CHILDREN)) { |
| 212 input_copy.reset(new std::string(input.as_string())); | 216 input_copy = WrapUnique(new std::string(input.as_string())); |
| 213 start_pos_ = input_copy->data(); | 217 start_pos_ = input_copy->data(); |
| 214 } else { | 218 } else { |
| 215 start_pos_ = input.data(); | 219 start_pos_ = input.data(); |
| 216 } | 220 } |
| 217 pos_ = start_pos_; | 221 pos_ = start_pos_; |
| 218 end_pos_ = start_pos_ + input.length(); | 222 end_pos_ = start_pos_ + input.length(); |
| 219 index_ = 0; | 223 index_ = 0; |
| 220 line_number_ = 1; | 224 line_number_ = 1; |
| 221 index_last_line_ = 0; | 225 index_last_line_ = 0; |
| 222 | 226 |
| 223 error_code_ = JSONReader::JSON_NO_ERROR; | 227 error_code_ = JSONReader::JSON_NO_ERROR; |
| 224 error_line_ = 0; | 228 error_line_ = 0; |
| 225 error_column_ = 0; | 229 error_column_ = 0; |
| 226 | 230 |
| 227 // When the input JSON string starts with a UTF-8 Byte-Order-Mark | 231 // When the input JSON string starts with a UTF-8 Byte-Order-Mark |
| 228 // <0xEF 0xBB 0xBF>, advance the start position to avoid the | 232 // <0xEF 0xBB 0xBF>, advance the start position to avoid the |
| 229 // ParseNextToken function mis-treating a Unicode BOM as an invalid | 233 // ParseNextToken function mis-treating a Unicode BOM as an invalid |
| 230 // character and returning NULL. | 234 // character and returning NULL. |
| 231 if (CanConsume(3) && static_cast<uint8_t>(*pos_) == 0xEF && | 235 if (CanConsume(3) && static_cast<uint8_t>(*pos_) == 0xEF && |
| 232 static_cast<uint8_t>(*(pos_ + 1)) == 0xBB && | 236 static_cast<uint8_t>(*(pos_ + 1)) == 0xBB && |
| 233 static_cast<uint8_t>(*(pos_ + 2)) == 0xBF) { | 237 static_cast<uint8_t>(*(pos_ + 2)) == 0xBF) { |
| 234 NextNChars(3); | 238 NextNChars(3); |
| 235 } | 239 } |
| 236 | 240 |
| 237 // Parse the first and any nested tokens. | 241 // Parse the first and any nested tokens. |
| 238 std::unique_ptr<Value> root(ParseNextToken()); | 242 std::unique_ptr<Value> root(ParseNextToken()); |
| 239 if (!root.get()) | 243 if (!root) |
| 240 return NULL; | 244 return nullptr; |
| 241 | 245 |
| 242 // Make sure the input stream is at an end. | 246 // Make sure the input stream is at an end. |
| 243 if (GetNextToken() != T_END_OF_INPUT) { | 247 if (GetNextToken() != T_END_OF_INPUT) { |
| 244 if (!CanConsume(1) || (NextChar() && GetNextToken() != T_END_OF_INPUT)) { | 248 if (!CanConsume(1) || (NextChar() && GetNextToken() != T_END_OF_INPUT)) { |
| 245 ReportError(JSONReader::JSON_UNEXPECTED_DATA_AFTER_ROOT, 1); | 249 ReportError(JSONReader::JSON_UNEXPECTED_DATA_AFTER_ROOT, 1); |
| 246 return NULL; | 250 return nullptr; |
| 247 } | 251 } |
| 248 } | 252 } |
| 249 | 253 |
| 250 // Dictionaries and lists can contain JSONStringValues, so wrap them in a | 254 // Dictionaries and lists can contain JSONStringValues, so wrap them in a |
| 251 // hidden root. | 255 // hidden root. |
| 252 if (!(options_ & JSON_DETACHABLE_CHILDREN)) { | 256 if (!(options_ & JSON_DETACHABLE_CHILDREN)) { |
| 253 if (root->IsType(Value::TYPE_DICTIONARY)) { | 257 if (root->IsType(Value::TYPE_DICTIONARY)) { |
| 254 return new DictionaryHiddenRootValue(input_copy.release(), root.get()); | 258 return WrapUnique(new DictionaryHiddenRootValue(std::move(input_copy), |
| 259 std::move(root))); | |
| 255 } else if (root->IsType(Value::TYPE_LIST)) { | 260 } else if (root->IsType(Value::TYPE_LIST)) { |
| 256 return new ListHiddenRootValue(input_copy.release(), root.get()); | 261 return WrapUnique( |
| 262 new ListHiddenRootValue(std::move(input_copy), std::move(root))); | |
| 257 } else if (root->IsType(Value::TYPE_STRING)) { | 263 } else if (root->IsType(Value::TYPE_STRING)) { |
| 258 // A string type could be a JSONStringValue, but because there's no | 264 // A string type could be a JSONStringValue, but because there's no |
| 259 // corresponding HiddenRootValue, the memory will be lost. Deep copy to | 265 // corresponding HiddenRootValue, the memory will be lost. Deep copy to |
| 260 // preserve it. | 266 // preserve it. |
| 261 return root->DeepCopy(); | 267 return root->CreateDeepCopy(); |
| 262 } | 268 } |
| 263 } | 269 } |
| 264 | 270 |
| 265 // All other values can be returned directly. | 271 // All other values can be returned directly. |
| 266 return root.release(); | 272 return root; |
| 267 } | 273 } |
| 268 | 274 |
| 269 JSONReader::JsonParseError JSONParser::error_code() const { | 275 JSONReader::JsonParseError JSONParser::error_code() const { |
| 270 return error_code_; | 276 return error_code_; |
| 271 } | 277 } |
| 272 | 278 |
| 273 std::string JSONParser::GetErrorMessage() const { | 279 std::string JSONParser::GetErrorMessage() const { |
| 274 return FormatErrorMessage(error_line_, error_column_, | 280 return FormatErrorMessage(error_line_, error_column_, |
| 275 JSONReader::ErrorCodeToString(error_code_)); | 281 JSONReader::ErrorCodeToString(error_code_)); |
| 276 } | 282 } |
| (...skipping 697 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 974 const std::string& description) { | 980 const std::string& description) { |
| 975 if (line || column) { | 981 if (line || column) { |
| 976 return StringPrintf("Line: %i, column: %i, %s", | 982 return StringPrintf("Line: %i, column: %i, %s", |
| 977 line, column, description.c_str()); | 983 line, column, description.c_str()); |
| 978 } | 984 } |
| 979 return description; | 985 return description; |
| 980 } | 986 } |
| 981 | 987 |
| 982 } // namespace internal | 988 } // namespace internal |
| 983 } // namespace base | 989 } // namespace base |
| OLD | NEW |