Commit a39043f65eebdc24d98bdc29160ad489222c4ec3
1 parent
f2e46c20
In JSONParser::handleToken avoid creating JSON objects for dictionary keys
Showing
1 changed file
with
29 additions
and
30 deletions
libqpdf/JSON.cc
| ... | ... | @@ -1138,8 +1138,10 @@ JSONParser::handleToken() |
| 1138 | 1138 | std::string s_value; |
| 1139 | 1139 | std::shared_ptr<JSON> item; |
| 1140 | 1140 | auto tos = stack.empty() ? nullptr : stack.back(); |
| 1141 | + auto ls = lex_state; | |
| 1142 | + lex_state = ls_top; | |
| 1141 | 1143 | |
| 1142 | - switch (lex_state) { | |
| 1144 | + switch (ls) { | |
| 1143 | 1145 | case ls_begin_dict: |
| 1144 | 1146 | item = std::make_shared<JSON>(JSON::makeDictionary()); |
| 1145 | 1147 | break; |
| ... | ... | @@ -1156,7 +1158,6 @@ JSONParser::handleToken() |
| 1156 | 1158 | ": unexpected colon"); |
| 1157 | 1159 | } |
| 1158 | 1160 | parser_state = ps_dict_after_colon; |
| 1159 | - lex_state = ls_top; | |
| 1160 | 1161 | return; |
| 1161 | 1162 | |
| 1162 | 1163 | case ls_comma: |
| ... | ... | @@ -1175,7 +1176,6 @@ JSONParser::handleToken() |
| 1175 | 1176 | throw std::logic_error("JSONParser::handleToken: unexpected parser" |
| 1176 | 1177 | " state for comma"); |
| 1177 | 1178 | } |
| 1178 | - lex_state = ls_top; | |
| 1179 | 1179 | return; |
| 1180 | 1180 | |
| 1181 | 1181 | case ls_end_array: |
| ... | ... | @@ -1195,7 +1195,6 @@ JSONParser::handleToken() |
| 1195 | 1195 | if (parser_state != ps_done) { |
| 1196 | 1196 | stack.pop_back(); |
| 1197 | 1197 | } |
| 1198 | - lex_state = ls_top; | |
| 1199 | 1198 | return; |
| 1200 | 1199 | |
| 1201 | 1200 | case ls_end_dict: |
| ... | ... | @@ -1215,7 +1214,6 @@ JSONParser::handleToken() |
| 1215 | 1214 | if (parser_state != ps_done) { |
| 1216 | 1215 | stack.pop_back(); |
| 1217 | 1216 | } |
| 1218 | - lex_state = ls_top; | |
| 1219 | 1217 | return; |
| 1220 | 1218 | |
| 1221 | 1219 | case ls_number: |
| ... | ... | @@ -1243,7 +1241,15 @@ JSONParser::handleToken() |
| 1243 | 1241 | throw std::logic_error("JSON string length < 2"); |
| 1244 | 1242 | } |
| 1245 | 1243 | s_value = decode_string(token, token_start); |
| 1246 | - item = std::make_shared<JSON>(JSON::makeString(s_value)); | |
| 1244 | + if (parser_state == ps_dict_begin || | |
| 1245 | + parser_state == ps_dict_after_comma) { | |
| 1246 | + dict_key = s_value; | |
| 1247 | + dict_key_offset = token_start; | |
| 1248 | + parser_state = ps_dict_after_key; | |
| 1249 | + return; | |
| 1250 | + } else { | |
| 1251 | + item = std::make_shared<JSON>(JSON::makeString(s_value)); | |
| 1252 | + } | |
| 1247 | 1253 | break; |
| 1248 | 1254 | |
| 1249 | 1255 | default: |
| ... | ... | @@ -1260,16 +1266,10 @@ JSONParser::handleToken() |
| 1260 | 1266 | switch (parser_state) { |
| 1261 | 1267 | case ps_dict_begin: |
| 1262 | 1268 | case ps_dict_after_comma: |
| 1263 | - if (lex_state != ls_string) { | |
| 1264 | - QTC::TC("libtests", "JSON parse string as dict key"); | |
| 1265 | - throw std::runtime_error( | |
| 1266 | - "JSON: offset " + std::to_string(offset) + | |
| 1267 | - ": expect string as dictionary key"); | |
| 1268 | - } | |
| 1269 | - this->dict_key = s_value; | |
| 1270 | - this->dict_key_offset = item->getStart(); | |
| 1271 | - item = nullptr; | |
| 1272 | - next_state = ps_dict_after_key; | |
| 1269 | + QTC::TC("libtests", "JSON parse string as dict key"); | |
| 1270 | + throw std::runtime_error( | |
| 1271 | + "JSON: offset " + std::to_string(offset) + | |
| 1272 | + ": expect string as dictionary key"); | |
| 1273 | 1273 | break; |
| 1274 | 1274 | |
| 1275 | 1275 | case ps_dict_after_colon: |
| ... | ... | @@ -1320,7 +1320,7 @@ JSONParser::handleToken() |
| 1320 | 1320 | "JSONParser::handleToken: unexpected parser state"); |
| 1321 | 1321 | } |
| 1322 | 1322 | |
| 1323 | - if (reactor && item.get()) { | |
| 1323 | + if (reactor) { | |
| 1324 | 1324 | // Calling container start method is postponed until after |
| 1325 | 1325 | // adding the containers to their parent containers, if any. |
| 1326 | 1326 | // This makes it much easier to keep track of the current |
| ... | ... | @@ -1333,26 +1333,25 @@ JSONParser::handleToken() |
| 1333 | 1333 | } |
| 1334 | 1334 | |
| 1335 | 1335 | // Prepare for next token |
| 1336 | - if (item.get()) { | |
| 1337 | - if (item->isDictionary()) { | |
| 1338 | - stack.push_back(item); | |
| 1339 | - ps_stack.push_back(next_state); | |
| 1340 | - next_state = ps_dict_begin; | |
| 1341 | - } else if (item->isArray()) { | |
| 1342 | - stack.push_back(item); | |
| 1343 | - ps_stack.push_back(next_state); | |
| 1344 | - next_state = ps_array_begin; | |
| 1345 | - } else if (parser_state == ps_top) { | |
| 1346 | - stack.push_back(item); | |
| 1347 | - } | |
| 1336 | + | |
| 1337 | + if (item->isDictionary()) { | |
| 1338 | + stack.push_back(item); | |
| 1339 | + ps_stack.push_back(next_state); | |
| 1340 | + next_state = ps_dict_begin; | |
| 1341 | + } else if (item->isArray()) { | |
| 1342 | + stack.push_back(item); | |
| 1343 | + ps_stack.push_back(next_state); | |
| 1344 | + next_state = ps_array_begin; | |
| 1345 | + } else if (parser_state == ps_top) { | |
| 1346 | + stack.push_back(item); | |
| 1348 | 1347 | } |
| 1348 | + | |
| 1349 | 1349 | if (ps_stack.size() > 500) { |
| 1350 | 1350 | throw std::runtime_error( |
| 1351 | 1351 | "JSON: offset " + std::to_string(offset) + |
| 1352 | 1352 | ": maximum object depth exceeded"); |
| 1353 | 1353 | } |
| 1354 | 1354 | parser_state = next_state; |
| 1355 | - lex_state = ls_top; | |
| 1356 | 1355 | } |
| 1357 | 1356 | |
| 1358 | 1357 | std::shared_ptr<JSON> | ... | ... |