diff options
author | Jacek Antonelli | 2008-08-15 23:45:34 -0500 |
---|---|---|
committer | Jacek Antonelli | 2008-08-15 23:45:34 -0500 |
commit | cd17687f01420952712a500107e0f93e7ab8d5f8 (patch) | |
tree | ce48c2b706f2c1176290e39fb555fbdf6648ce01 /linden/indra/llcommon/llsdserialize.cpp | |
parent | Second Life viewer sources 1.19.0.5 (diff) | |
download | meta-impy-cd17687f01420952712a500107e0f93e7ab8d5f8.zip meta-impy-cd17687f01420952712a500107e0f93e7ab8d5f8.tar.gz meta-impy-cd17687f01420952712a500107e0f93e7ab8d5f8.tar.bz2 meta-impy-cd17687f01420952712a500107e0f93e7ab8d5f8.tar.xz |
Second Life viewer sources 1.19.1.0
Diffstat (limited to 'linden/indra/llcommon/llsdserialize.cpp')
-rw-r--r-- | linden/indra/llcommon/llsdserialize.cpp | 763 |
1 files changed, 545 insertions, 218 deletions
diff --git a/linden/indra/llcommon/llsdserialize.cpp b/linden/indra/llcommon/llsdserialize.cpp index 7813cf0..a556d5d 100644 --- a/linden/indra/llcommon/llsdserialize.cpp +++ b/linden/indra/llcommon/llsdserialize.cpp | |||
@@ -45,26 +45,18 @@ | |||
45 | 45 | ||
46 | #include "lldate.h" | 46 | #include "lldate.h" |
47 | #include "llsd.h" | 47 | #include "llsd.h" |
48 | #include "llstring.h" | ||
48 | #include "lluri.h" | 49 | #include "lluri.h" |
49 | 50 | ||
50 | // File constants | 51 | // File constants |
51 | static const int MAX_HDR_LEN = 20; | 52 | static const int MAX_HDR_LEN = 20; |
52 | static const char LEGACY_NON_HEADER[] = "<llsd>"; | 53 | static const char LEGACY_NON_HEADER[] = "<llsd>"; |
54 | const std::string LLSD_BINARY_HEADER("LLSD/Binary"); | ||
55 | const std::string LLSD_XML_HEADER("LLSD/XML"); | ||
53 | 56 | ||
54 | //static | 57 | /** |
55 | const char* LLSDSerialize::LLSDBinaryHeader = "LLSD/Binary"; | 58 | * LLSDSerialize |
56 | 59 | */ | |
57 | //static | ||
58 | const char* LLSDSerialize::LLSDXMLHeader = "LLSD/XML"; | ||
59 | |||
60 | // virtual | ||
61 | LLSDParser::~LLSDParser() | ||
62 | { } | ||
63 | |||
64 | // virtual | ||
65 | LLSDNotationParser::~LLSDNotationParser() | ||
66 | { } | ||
67 | |||
68 | 60 | ||
69 | // static | 61 | // static |
70 | void LLSDSerialize::serialize(const LLSD& sd, std::ostream& str, ELLSD_Serialize type, U32 options) | 62 | void LLSDSerialize::serialize(const LLSD& sd, std::ostream& str, ELLSD_Serialize type, U32 options) |
@@ -74,12 +66,12 @@ void LLSDSerialize::serialize(const LLSD& sd, std::ostream& str, ELLSD_Serialize | |||
74 | switch (type) | 66 | switch (type) |
75 | { | 67 | { |
76 | case LLSD_BINARY: | 68 | case LLSD_BINARY: |
77 | str << "<? " << LLSDBinaryHeader << " ?>\n"; | 69 | str << "<? " << LLSD_BINARY_HEADER << " ?>\n"; |
78 | f = new LLSDBinaryFormatter; | 70 | f = new LLSDBinaryFormatter; |
79 | break; | 71 | break; |
80 | 72 | ||
81 | case LLSD_XML: | 73 | case LLSD_XML: |
82 | str << "<? " << LLSDXMLHeader << " ?>\n"; | 74 | str << "<? " << LLSD_XML_HEADER << " ?>\n"; |
83 | f = new LLSDXMLFormatter; | 75 | f = new LLSDXMLFormatter; |
84 | break; | 76 | break; |
85 | 77 | ||
@@ -94,7 +86,7 @@ void LLSDSerialize::serialize(const LLSD& sd, std::ostream& str, ELLSD_Serialize | |||
94 | } | 86 | } |
95 | 87 | ||
96 | // static | 88 | // static |
97 | bool LLSDSerialize::deserialize(LLSD& sd, std::istream& str) | 89 | bool LLSDSerialize::deserialize(LLSD& sd, std::istream& str, S32 max_bytes) |
98 | { | 90 | { |
99 | LLPointer<LLSDParser> p = NULL; | 91 | LLPointer<LLSDParser> p = NULL; |
100 | char hdr_buf[MAX_HDR_LEN + 1] = ""; /* Flawfinder: ignore */ | 92 | char hdr_buf[MAX_HDR_LEN + 1] = ""; /* Flawfinder: ignore */ |
@@ -102,8 +94,8 @@ bool LLSDSerialize::deserialize(LLSD& sd, std::istream& str) | |||
102 | int inbuf = 0; | 94 | int inbuf = 0; |
103 | bool legacy_no_header = false; | 95 | bool legacy_no_header = false; |
104 | bool fail_if_not_legacy = false; | 96 | bool fail_if_not_legacy = false; |
105 | std::string header = ""; | 97 | std::string header; |
106 | 98 | ||
107 | /* | 99 | /* |
108 | * Get the first line before anything. | 100 | * Get the first line before anything. |
109 | */ | 101 | */ |
@@ -155,15 +147,15 @@ bool LLSDSerialize::deserialize(LLSD& sd, std::istream& str) | |||
155 | */ | 147 | */ |
156 | if (legacy_no_header) | 148 | if (legacy_no_header) |
157 | { | 149 | { |
158 | LLSDXMLParser *x = new LLSDXMLParser; | 150 | LLSDXMLParser* x = new LLSDXMLParser; |
159 | x->parsePart(hdr_buf, inbuf); | 151 | x->parsePart(hdr_buf, inbuf); |
160 | p = x; | 152 | p = x; |
161 | } | 153 | } |
162 | else if (header == LLSDBinaryHeader) | 154 | else if (header == LLSD_BINARY_HEADER) |
163 | { | 155 | { |
164 | p = new LLSDBinaryParser; | 156 | p = new LLSDBinaryParser; |
165 | } | 157 | } |
166 | else if (header == LLSDXMLHeader) | 158 | else if (header == LLSD_XML_HEADER) |
167 | { | 159 | { |
168 | p = new LLSDXMLParser; | 160 | p = new LLSDXMLParser; |
169 | } | 161 | } |
@@ -174,7 +166,7 @@ bool LLSDSerialize::deserialize(LLSD& sd, std::istream& str) | |||
174 | 166 | ||
175 | if (p.notNull()) | 167 | if (p.notNull()) |
176 | { | 168 | { |
177 | p->parse(str, sd); | 169 | p->parse(str, sd, max_bytes); |
178 | return true; | 170 | return true; |
179 | } | 171 | } |
180 | 172 | ||
@@ -230,11 +222,71 @@ F64 ll_ntohd(F64 netdouble) | |||
230 | /** | 222 | /** |
231 | * Local functions. | 223 | * Local functions. |
232 | */ | 224 | */ |
233 | bool deserialize_string(std::istream& str, std::string& value); | 225 | /** |
234 | bool deserialize_string_delim(std::istream& str, std::string& value, char d); | 226 | * @brief Figure out what kind of string it is (raw or delimited) and handoff. |
235 | bool deserialize_string_raw(std::istream& str, std::string& value); | 227 | * |
228 | * @param istr The stream to read from. | ||
229 | * @param value [out] The string which was found. | ||
230 | * @param max_bytes The maximum possible length of the string. Passing in | ||
231 | * a negative value will skip this check. | ||
232 | * @return Returns number of bytes read off of the stream. Returns | ||
233 | * PARSE_FAILURE (-1) on failure. | ||
234 | */ | ||
235 | int deserialize_string(std::istream& istr, std::string& value, S32 max_bytes); | ||
236 | |||
237 | /** | ||
238 | * @brief Parse a delimited string. | ||
239 | * | ||
240 | * @param istr The stream to read from, with the delimiter already popped. | ||
241 | * @param value [out] The string which was found. | ||
242 | * @param d The delimiter to use. | ||
243 | * @return Returns number of bytes read off of the stream. Returns | ||
244 | * PARSE_FAILURE (-1) on failure. | ||
245 | */ | ||
246 | int deserialize_string_delim(std::istream& istr, std::string& value, char d); | ||
247 | |||
248 | /** | ||
249 | * @brief Read a raw string off the stream. | ||
250 | * | ||
251 | * @param istr The stream to read from, with the (len) parameter | ||
252 | * leading the stream. | ||
253 | * @param value [out] The string which was found. | ||
254 | * @param d The delimiter to use. | ||
255 | * @param max_bytes The maximum possible length of the string. Passing in | ||
256 | * a negative value will skip this check. | ||
257 | * @return Returns number of bytes read off of the stream. Returns | ||
258 | * PARSE_FAILURE (-1) on failure. | ||
259 | */ | ||
260 | int deserialize_string_raw( | ||
261 | std::istream& istr, | ||
262 | std::string& value, | ||
263 | S32 max_bytes); | ||
264 | |||
265 | /** | ||
266 | * @brief helper method for dealing with the different notation boolean format. | ||
267 | * | ||
268 | * @param istr The stream to read from with the leading character stripped. | ||
269 | * @param data [out] the result of the parse. | ||
270 | * @param compare The string to compare the boolean against | ||
271 | * @param vale The value to assign to data if the parse succeeds. | ||
272 | * @return Returns number of bytes read off of the stream. Returns | ||
273 | * PARSE_FAILURE (-1) on failure. | ||
274 | */ | ||
275 | int deserialize_boolean( | ||
276 | std::istream& istr, | ||
277 | LLSD& data, | ||
278 | const std::string& compare, | ||
279 | bool value); | ||
280 | |||
281 | /** | ||
282 | * @brief Do notation escaping of a string to an ostream. | ||
283 | * | ||
284 | * @param value The string to escape and serialize | ||
285 | * @param str The stream to serialize to. | ||
286 | */ | ||
236 | void serialize_string(const std::string& value, std::ostream& str); | 287 | void serialize_string(const std::string& value, std::ostream& str); |
237 | 288 | ||
289 | |||
238 | /** | 290 | /** |
239 | * Local constants. | 291 | * Local constants. |
240 | */ | 292 | */ |
@@ -244,20 +296,96 @@ static const std::string NOTATION_FALSE_SERIAL("false"); | |||
244 | static const char BINARY_TRUE_SERIAL = '1'; | 296 | static const char BINARY_TRUE_SERIAL = '1'; |
245 | static const char BINARY_FALSE_SERIAL = '0'; | 297 | static const char BINARY_FALSE_SERIAL = '0'; |
246 | 298 | ||
247 | static const S32 NOTATION_PARSE_FAILURE = -1; | ||
248 | 299 | ||
249 | /** | 300 | /** |
250 | * LLSDParser | 301 | * LLSDParser |
251 | */ | 302 | */ |
252 | LLSDParser::LLSDParser() | 303 | LLSDParser::LLSDParser() : mCheckLimits(true), mMaxBytesLeft(0) |
304 | { | ||
305 | } | ||
306 | |||
307 | // virtual | ||
308 | LLSDParser::~LLSDParser() | ||
309 | { } | ||
310 | |||
311 | S32 LLSDParser::parse(std::istream& istr, LLSD& data, S32 max_bytes) | ||
312 | { | ||
313 | mCheckLimits = (LLSDSerialize::SIZE_UNLIMITED == max_bytes) ? false : true; | ||
314 | mMaxBytesLeft = max_bytes; | ||
315 | return doParse(istr, data); | ||
316 | } | ||
317 | |||
318 | |||
319 | int LLSDParser::get(std::istream& istr) const | ||
320 | { | ||
321 | if(mCheckLimits) --mMaxBytesLeft; | ||
322 | return istr.get(); | ||
323 | } | ||
324 | |||
325 | std::istream& LLSDParser::get( | ||
326 | std::istream& istr, | ||
327 | char* s, | ||
328 | std::streamsize n, | ||
329 | char delim) const | ||
330 | { | ||
331 | istr.get(s, n, delim); | ||
332 | if(mCheckLimits) mMaxBytesLeft -= istr.gcount(); | ||
333 | return istr; | ||
334 | } | ||
335 | |||
336 | std::istream& LLSDParser::get( | ||
337 | std::istream& istr, | ||
338 | std::streambuf& sb, | ||
339 | char delim) const | ||
340 | { | ||
341 | istr.get(sb, delim); | ||
342 | if(mCheckLimits) mMaxBytesLeft -= istr.gcount(); | ||
343 | return istr; | ||
344 | } | ||
345 | |||
346 | std::istream& LLSDParser::ignore(std::istream& istr) const | ||
253 | { | 347 | { |
348 | istr.ignore(); | ||
349 | if(mCheckLimits) --mMaxBytesLeft; | ||
350 | return istr; | ||
254 | } | 351 | } |
255 | 352 | ||
353 | std::istream& LLSDParser::putback(std::istream& istr, char c) const | ||
354 | { | ||
355 | istr.putback(c); | ||
356 | if(mCheckLimits) ++mMaxBytesLeft; | ||
357 | return istr; | ||
358 | } | ||
359 | |||
360 | std::istream& LLSDParser::read( | ||
361 | std::istream& istr, | ||
362 | char* s, | ||
363 | std::streamsize n) const | ||
364 | { | ||
365 | istr.read(s, n); | ||
366 | if(mCheckLimits) mMaxBytesLeft -= istr.gcount(); | ||
367 | return istr; | ||
368 | } | ||
369 | |||
370 | void LLSDParser::account(S32 bytes) const | ||
371 | { | ||
372 | if(mCheckLimits) mMaxBytesLeft -= bytes; | ||
373 | } | ||
374 | |||
375 | |||
256 | /** | 376 | /** |
257 | * LLSDNotationParser | 377 | * LLSDNotationParser |
258 | */ | 378 | */ |
379 | LLSDNotationParser::LLSDNotationParser() | ||
380 | { | ||
381 | } | ||
382 | |||
383 | // virtual | ||
384 | LLSDNotationParser::~LLSDNotationParser() | ||
385 | { } | ||
386 | |||
259 | // virtual | 387 | // virtual |
260 | S32 LLSDNotationParser::parse(std::istream& istr, LLSD& data) const | 388 | S32 LLSDNotationParser::doParse(std::istream& istr, LLSD& data) const |
261 | { | 389 | { |
262 | // map: { string:object, string:object } | 390 | // map: { string:object, string:object } |
263 | // array: [ object, object, object ] | 391 | // array: [ object, object, object ] |
@@ -275,7 +403,7 @@ S32 LLSDNotationParser::parse(std::istream& istr, LLSD& data) const | |||
275 | while(isspace(c)) | 403 | while(isspace(c)) |
276 | { | 404 | { |
277 | // pop the whitespace. | 405 | // pop the whitespace. |
278 | c = istr.get(); | 406 | c = get(istr); |
279 | c = istr.peek(); | 407 | c = istr.peek(); |
280 | continue; | 408 | continue; |
281 | } | 409 | } |
@@ -287,107 +415,142 @@ S32 LLSDNotationParser::parse(std::istream& istr, LLSD& data) const | |||
287 | switch(c) | 415 | switch(c) |
288 | { | 416 | { |
289 | case '{': | 417 | case '{': |
290 | parse_count += parseMap(istr, data); | 418 | { |
291 | if(istr.fail()) | 419 | S32 child_count = parseMap(istr, data); |
420 | if((child_count == PARSE_FAILURE) || data.isUndefined()) | ||
292 | { | 421 | { |
293 | llinfos << "STREAM FAILURE reading map." << llendl; | 422 | parse_count = PARSE_FAILURE; |
294 | } | 423 | } |
295 | if(data.isUndefined()) | 424 | else |
296 | { | 425 | { |
297 | parse_count = NOTATION_PARSE_FAILURE; | 426 | parse_count += child_count; |
427 | } | ||
428 | if(istr.fail()) | ||
429 | { | ||
430 | llinfos << "STREAM FAILURE reading map." << llendl; | ||
431 | parse_count = PARSE_FAILURE; | ||
298 | } | 432 | } |
299 | break; | 433 | break; |
434 | } | ||
300 | 435 | ||
301 | case '[': | 436 | case '[': |
302 | parse_count += parseArray(istr, data); | 437 | { |
303 | if(istr.fail()) | 438 | S32 child_count = parseArray(istr, data); |
439 | if((child_count == PARSE_FAILURE) || data.isUndefined()) | ||
304 | { | 440 | { |
305 | llinfos << "STREAM FAILURE reading array." << llendl; | 441 | parse_count = PARSE_FAILURE; |
306 | } | 442 | } |
307 | if(data.isUndefined()) | 443 | else |
308 | { | 444 | { |
309 | parse_count = NOTATION_PARSE_FAILURE; | 445 | parse_count += child_count; |
446 | } | ||
447 | if(istr.fail()) | ||
448 | { | ||
449 | llinfos << "STREAM FAILURE reading array." << llendl; | ||
450 | parse_count = PARSE_FAILURE; | ||
310 | } | 451 | } |
311 | break; | 452 | break; |
453 | } | ||
312 | 454 | ||
313 | case '!': | 455 | case '!': |
314 | c = istr.get(); | 456 | c = get(istr); |
315 | data.clear(); | 457 | data.clear(); |
316 | break; | 458 | break; |
317 | 459 | ||
318 | case '0': | 460 | case '0': |
319 | c = istr.get(); | 461 | c = get(istr); |
320 | data = false; | 462 | data = false; |
321 | break; | 463 | break; |
322 | 464 | ||
323 | case 'F': | 465 | case 'F': |
324 | case 'f': | 466 | case 'f': |
325 | do | 467 | ignore(istr); |
468 | c = istr.peek(); | ||
469 | if(isalpha(c)) | ||
326 | { | 470 | { |
327 | istr.ignore(); | 471 | int cnt = deserialize_boolean( |
328 | c = istr.peek(); | 472 | istr, |
329 | } while (isalpha(c)); | 473 | data, |
330 | data = false; | 474 | NOTATION_FALSE_SERIAL, |
475 | false); | ||
476 | if(PARSE_FAILURE == cnt) parse_count = cnt; | ||
477 | else account(cnt); | ||
478 | } | ||
479 | else | ||
480 | { | ||
481 | data = false; | ||
482 | } | ||
331 | if(istr.fail()) | 483 | if(istr.fail()) |
332 | { | 484 | { |
333 | llinfos << "STREAM FAILURE reading boolean." << llendl; | 485 | llinfos << "STREAM FAILURE reading boolean." << llendl; |
486 | parse_count = PARSE_FAILURE; | ||
334 | } | 487 | } |
335 | break; | 488 | break; |
336 | 489 | ||
337 | case '1': | 490 | case '1': |
338 | c = istr.get(); | 491 | c = get(istr); |
339 | data = true; | 492 | data = true; |
340 | break; | 493 | break; |
341 | 494 | ||
342 | case 'T': | 495 | case 'T': |
343 | case 't': | 496 | case 't': |
344 | do | 497 | ignore(istr); |
498 | c = istr.peek(); | ||
499 | if(isalpha(c)) | ||
345 | { | 500 | { |
346 | istr.ignore(); | 501 | int cnt = deserialize_boolean(istr,data,NOTATION_TRUE_SERIAL,true); |
347 | c = istr.peek(); | 502 | if(PARSE_FAILURE == cnt) parse_count = cnt; |
348 | } while (isalpha(c)); | 503 | else account(cnt); |
349 | data = true; | 504 | } |
505 | else | ||
506 | { | ||
507 | data = true; | ||
508 | } | ||
350 | if(istr.fail()) | 509 | if(istr.fail()) |
351 | { | 510 | { |
352 | llinfos << "STREAM FAILURE reading boolean." << llendl; | 511 | llinfos << "STREAM FAILURE reading boolean." << llendl; |
512 | parse_count = PARSE_FAILURE; | ||
353 | } | 513 | } |
354 | break; | 514 | break; |
355 | 515 | ||
356 | case 'i': | 516 | case 'i': |
357 | { | 517 | { |
358 | c = istr.get(); | 518 | c = get(istr); |
359 | S32 integer = 0; | 519 | S32 integer = 0; |
360 | istr >> integer; | 520 | istr >> integer; |
361 | data = integer; | 521 | data = integer; |
362 | if(istr.fail()) | 522 | if(istr.fail()) |
363 | { | 523 | { |
364 | llinfos << "STREAM FAILURE reading integer." << llendl; | 524 | llinfos << "STREAM FAILURE reading integer." << llendl; |
525 | parse_count = PARSE_FAILURE; | ||
365 | } | 526 | } |
366 | break; | 527 | break; |
367 | } | 528 | } |
368 | 529 | ||
369 | case 'r': | 530 | case 'r': |
370 | { | 531 | { |
371 | c = istr.get(); | 532 | c = get(istr); |
372 | F64 real = 0.0; | 533 | F64 real = 0.0; |
373 | istr >> real; | 534 | istr >> real; |
374 | data = real; | 535 | data = real; |
375 | if(istr.fail()) | 536 | if(istr.fail()) |
376 | { | 537 | { |
377 | llinfos << "STREAM FAILURE reading real." << llendl; | 538 | llinfos << "STREAM FAILURE reading real." << llendl; |
539 | parse_count = PARSE_FAILURE; | ||
378 | } | 540 | } |
379 | break; | 541 | break; |
380 | } | 542 | } |
381 | 543 | ||
382 | case 'u': | 544 | case 'u': |
383 | { | 545 | { |
384 | c = istr.get(); | 546 | c = get(istr); |
385 | LLUUID id; | 547 | LLUUID id; |
386 | istr >> id; | 548 | istr >> id; |
387 | data = id; | 549 | data = id; |
388 | if(istr.fail()) | 550 | if(istr.fail()) |
389 | { | 551 | { |
390 | llinfos << "STREAM FAILURE reading uuid." << llendl; | 552 | llinfos << "STREAM FAILURE reading uuid." << llendl; |
553 | parse_count = PARSE_FAILURE; | ||
391 | } | 554 | } |
392 | break; | 555 | break; |
393 | } | 556 | } |
@@ -395,126 +558,144 @@ S32 LLSDNotationParser::parse(std::istream& istr, LLSD& data) const | |||
395 | case '\"': | 558 | case '\"': |
396 | case '\'': | 559 | case '\'': |
397 | case 's': | 560 | case 's': |
398 | parseString(istr, data); | 561 | if(!parseString(istr, data)) |
399 | if(istr.fail()) | ||
400 | { | 562 | { |
401 | llinfos << "STREAM FAILURE reading string." << llendl; | 563 | parse_count = PARSE_FAILURE; |
402 | } | 564 | } |
403 | if(data.isUndefined()) | 565 | if(istr.fail()) |
404 | { | 566 | { |
405 | parse_count = NOTATION_PARSE_FAILURE; | 567 | llinfos << "STREAM FAILURE reading string." << llendl; |
568 | parse_count = PARSE_FAILURE; | ||
406 | } | 569 | } |
407 | break; | 570 | break; |
408 | 571 | ||
409 | case 'l': | 572 | case 'l': |
410 | { | 573 | { |
411 | c = istr.get(); // pop the 'l' | 574 | c = get(istr); // pop the 'l' |
412 | c = istr.get(); // pop the delimiter | 575 | c = get(istr); // pop the delimiter |
413 | std::string str; | 576 | std::string str; |
414 | deserialize_string_delim(istr, str, c); | 577 | int cnt = deserialize_string_delim(istr, str, c); |
415 | data = LLURI(str); | 578 | if(PARSE_FAILURE == cnt) |
579 | { | ||
580 | parse_count = PARSE_FAILURE; | ||
581 | } | ||
582 | else | ||
583 | { | ||
584 | data = LLURI(str); | ||
585 | account(cnt); | ||
586 | } | ||
416 | if(istr.fail()) | 587 | if(istr.fail()) |
417 | { | 588 | { |
418 | llinfos << "STREAM FAILURE reading link." << llendl; | 589 | llinfos << "STREAM FAILURE reading link." << llendl; |
590 | parse_count = PARSE_FAILURE; | ||
419 | } | 591 | } |
420 | break; | 592 | break; |
421 | } | 593 | } |
422 | 594 | ||
423 | case 'd': | 595 | case 'd': |
424 | { | 596 | { |
425 | c = istr.get(); // pop the 'd' | 597 | c = get(istr); // pop the 'd' |
426 | c = istr.get(); // pop the delimiter | 598 | c = get(istr); // pop the delimiter |
427 | std::string str; | 599 | std::string str; |
428 | deserialize_string_delim(istr, str, c); | 600 | int cnt = deserialize_string_delim(istr, str, c); |
429 | data = LLDate(str); | 601 | if(PARSE_FAILURE == cnt) |
602 | { | ||
603 | parse_count = PARSE_FAILURE; | ||
604 | } | ||
605 | else | ||
606 | { | ||
607 | data = LLDate(str); | ||
608 | account(cnt); | ||
609 | } | ||
430 | if(istr.fail()) | 610 | if(istr.fail()) |
431 | { | 611 | { |
432 | llinfos << "STREAM FAILURE reading date." << llendl; | 612 | llinfos << "STREAM FAILURE reading date." << llendl; |
613 | parse_count = PARSE_FAILURE; | ||
433 | } | 614 | } |
434 | break; | 615 | break; |
435 | } | 616 | } |
436 | 617 | ||
437 | case 'b': | 618 | case 'b': |
438 | parseBinary(istr, data); | 619 | if(!parseBinary(istr, data)) |
439 | if(istr.fail()) | ||
440 | { | 620 | { |
441 | llinfos << "STREAM FAILURE reading data." << llendl; | 621 | parse_count = PARSE_FAILURE; |
442 | } | 622 | } |
443 | if(data.isUndefined()) | 623 | if(istr.fail()) |
444 | { | 624 | { |
445 | parse_count = NOTATION_PARSE_FAILURE; | 625 | llinfos << "STREAM FAILURE reading data." << llendl; |
626 | parse_count = PARSE_FAILURE; | ||
446 | } | 627 | } |
447 | break; | 628 | break; |
448 | 629 | ||
449 | default: | 630 | default: |
450 | data.clear(); | 631 | parse_count = PARSE_FAILURE; |
451 | parse_count = NOTATION_PARSE_FAILURE; | ||
452 | llinfos << "Unrecognized character while parsing: int(" << (int)c | 632 | llinfos << "Unrecognized character while parsing: int(" << (int)c |
453 | << ")" << llendl; | 633 | << ")" << llendl; |
454 | break; | 634 | break; |
455 | } | 635 | } |
636 | if(PARSE_FAILURE == parse_count) | ||
637 | { | ||
638 | data.clear(); | ||
639 | } | ||
456 | return parse_count; | 640 | return parse_count; |
457 | } | 641 | } |
458 | 642 | ||
459 | // static | ||
460 | LLSD LLSDNotationParser::parse(std::istream& istr) | ||
461 | { | ||
462 | LLSDNotationParser parser; | ||
463 | LLSD rv; | ||
464 | S32 count = parser.parse(istr, rv); | ||
465 | lldebugs << "LLSDNotationParser::parse parsed " << count << " objects." | ||
466 | << llendl; | ||
467 | return rv; | ||
468 | } | ||
469 | |||
470 | S32 LLSDNotationParser::parseMap(std::istream& istr, LLSD& map) const | 643 | S32 LLSDNotationParser::parseMap(std::istream& istr, LLSD& map) const |
471 | { | 644 | { |
472 | // map: { string:object, string:object } | 645 | // map: { string:object, string:object } |
473 | map = LLSD::emptyMap(); | 646 | map = LLSD::emptyMap(); |
474 | S32 parse_count = 0; | 647 | S32 parse_count = 0; |
475 | char c = istr.get(); | 648 | char c = get(istr); |
476 | if(c == '{') | 649 | if(c == '{') |
477 | { | 650 | { |
478 | // eat commas, white | 651 | // eat commas, white |
479 | bool found_name = false; | 652 | bool found_name = false; |
480 | std::string name; | 653 | std::string name; |
481 | c = istr.get(); | 654 | c = get(istr); |
482 | while(c != '}' && istr.good()) | 655 | while(c != '}' && istr.good()) |
483 | { | 656 | { |
484 | if(!found_name) | 657 | if(!found_name) |
485 | { | 658 | { |
486 | if((c == '\"') || (c == '\'') || (c == 's')) | 659 | if((c == '\"') || (c == '\'') || (c == 's')) |
487 | { | 660 | { |
488 | istr.putback(c); | 661 | putback(istr, c); |
489 | found_name = true; | 662 | found_name = true; |
490 | deserialize_string(istr, name); | 663 | int count = deserialize_string(istr, name, mMaxBytesLeft); |
664 | if(PARSE_FAILURE == count) return PARSE_FAILURE; | ||
665 | account(count); | ||
491 | } | 666 | } |
492 | c = istr.get(); | 667 | c = get(istr); |
493 | } | 668 | } |
494 | else | 669 | else |
495 | { | 670 | { |
496 | if(isspace(c) || (c == ':')) | 671 | if(isspace(c) || (c == ':')) |
497 | { | 672 | { |
498 | c = istr.get(); | 673 | c = get(istr); |
499 | continue; | 674 | continue; |
500 | } | 675 | } |
501 | istr.putback(c); | 676 | putback(istr, c); |
502 | LLSD child; | 677 | LLSD child; |
503 | S32 count = parse(istr, child); | 678 | S32 count = doParse(istr, child); |
504 | if(count > 0) | 679 | if(count > 0) |
505 | { | 680 | { |
681 | // There must be a value for every key, thus | ||
682 | // child_count must be greater than 0. | ||
506 | parse_count += count; | 683 | parse_count += count; |
507 | map.insert(name, child); | 684 | map.insert(name, child); |
508 | } | 685 | } |
509 | else | 686 | else |
510 | { | 687 | { |
511 | map.clear(); | 688 | return PARSE_FAILURE; |
512 | return NOTATION_PARSE_FAILURE; | ||
513 | } | 689 | } |
514 | found_name = false; | 690 | found_name = false; |
515 | c = istr.get(); | 691 | c = get(istr); |
516 | } | 692 | } |
517 | } | 693 | } |
694 | if(c != '}') | ||
695 | { | ||
696 | map.clear(); | ||
697 | return PARSE_FAILURE; | ||
698 | } | ||
518 | } | 699 | } |
519 | return parse_count; | 700 | return parse_count; |
520 | } | 701 | } |
@@ -524,52 +705,51 @@ S32 LLSDNotationParser::parseArray(std::istream& istr, LLSD& array) const | |||
524 | // array: [ object, object, object ] | 705 | // array: [ object, object, object ] |
525 | array = LLSD::emptyArray(); | 706 | array = LLSD::emptyArray(); |
526 | S32 parse_count = 0; | 707 | S32 parse_count = 0; |
527 | char c = istr.get(); | 708 | char c = get(istr); |
528 | if(c == '[') | 709 | if(c == '[') |
529 | { | 710 | { |
530 | // eat commas, white | 711 | // eat commas, white |
531 | c = istr.get(); | 712 | c = get(istr); |
532 | while((c != ']') && istr.good()) | 713 | while((c != ']') && istr.good()) |
533 | { | 714 | { |
534 | LLSD child; | 715 | LLSD child; |
535 | if(isspace(c) || (c == ',')) | 716 | if(isspace(c) || (c == ',')) |
536 | { | 717 | { |
537 | c = istr.get(); | 718 | c = get(istr); |
538 | continue; | 719 | continue; |
539 | } | 720 | } |
540 | istr.putback(c); | 721 | putback(istr, c); |
541 | S32 count = parse(istr, child); | 722 | S32 count = doParse(istr, child); |
542 | if(count > 0) | 723 | if(PARSE_FAILURE == count) |
543 | { | 724 | { |
544 | parse_count += count; | 725 | return PARSE_FAILURE; |
545 | array.append(child); | ||
546 | } | 726 | } |
547 | else | 727 | else |
548 | { | 728 | { |
549 | array.clear(); | 729 | parse_count += count; |
550 | return NOTATION_PARSE_FAILURE; | 730 | array.append(child); |
551 | } | 731 | } |
552 | c = istr.get(); | 732 | c = get(istr); |
733 | } | ||
734 | if(c != ']') | ||
735 | { | ||
736 | return PARSE_FAILURE; | ||
553 | } | 737 | } |
554 | } | 738 | } |
555 | return parse_count; | 739 | return parse_count; |
556 | } | 740 | } |
557 | 741 | ||
558 | void LLSDNotationParser::parseString(std::istream& istr, LLSD& data) const | 742 | bool LLSDNotationParser::parseString(std::istream& istr, LLSD& data) const |
559 | { | 743 | { |
560 | std::string value; | 744 | std::string value; |
561 | if(deserialize_string(istr, value)) | 745 | int count = deserialize_string(istr, value, mMaxBytesLeft); |
562 | { | 746 | if(PARSE_FAILURE == count) return false; |
563 | data = value; | 747 | account(count); |
564 | } | 748 | data = value; |
565 | else | 749 | return true; |
566 | { | ||
567 | // failed to parse. | ||
568 | data.clear(); | ||
569 | } | ||
570 | } | 750 | } |
571 | 751 | ||
572 | void LLSDNotationParser::parseBinary(std::istream& istr, LLSD& data) const | 752 | bool LLSDNotationParser::parseBinary(std::istream& istr, LLSD& data) const |
573 | { | 753 | { |
574 | // binary: b##"ff3120ab1" | 754 | // binary: b##"ff3120ab1" |
575 | // or: b(len)"..." | 755 | // or: b(len)"..." |
@@ -582,40 +762,44 @@ void LLSDNotationParser::parseBinary(std::istream& istr, LLSD& data) const | |||
582 | 762 | ||
583 | // need to read the base out. | 763 | // need to read the base out. |
584 | char buf[BINARY_BUFFER_SIZE]; /* Flawfinder: ignore */ | 764 | char buf[BINARY_BUFFER_SIZE]; /* Flawfinder: ignore */ |
585 | istr.get(buf, STREAM_GET_COUNT, '"'); | 765 | get(istr, buf, STREAM_GET_COUNT, '"'); |
586 | char c = istr.get(); | 766 | char c = get(istr); |
587 | if((c == '"') && (0 == strncmp("b(", buf, 2))) | 767 | if(c != '"') return false; |
768 | if(0 == strncmp("b(", buf, 2)) | ||
588 | { | 769 | { |
589 | // We probably have a valid raw binary stream. determine | 770 | // We probably have a valid raw binary stream. determine |
590 | // the size, and read it. | 771 | // the size, and read it. |
591 | // *FIX: Should we set a maximum size? | ||
592 | S32 len = strtol(buf + 2, NULL, 0); | 772 | S32 len = strtol(buf + 2, NULL, 0); |
773 | if(mCheckLimits && (len > mMaxBytesLeft)) return false; | ||
593 | std::vector<U8> value; | 774 | std::vector<U8> value; |
594 | if(len) | 775 | if(len) |
595 | { | 776 | { |
596 | value.resize(len); | 777 | value.resize(len); |
597 | fullread(istr, (char *)&value[0], len); | 778 | account(fullread(istr, (char *)&value[0], len)); |
598 | } | 779 | } |
599 | c = istr.get(); // strip off the trailing double-quote | 780 | c = get(istr); // strip off the trailing double-quote |
600 | data = value; | 781 | data = value; |
601 | } | 782 | } |
602 | else if((c == '"') && (0 == strncmp("b64", buf, 3))) | 783 | else if(0 == strncmp("b64", buf, 3)) |
603 | { | 784 | { |
604 | // *FIX: A bit inefficient, but works for now. To make the | 785 | // *FIX: A bit inefficient, but works for now. To make the |
605 | // format better, I would need to add a hint into the | 786 | // format better, I would need to add a hint into the |
606 | // serialization format that indicated how long it was. | 787 | // serialization format that indicated how long it was. |
607 | std::stringstream coded_stream; | 788 | std::stringstream coded_stream; |
608 | istr.get(*(coded_stream.rdbuf()), '\"'); | 789 | get(istr, *(coded_stream.rdbuf()), '\"'); |
609 | c = istr.get(); | 790 | c = get(istr); |
610 | std::string encoded(coded_stream.str()); | 791 | std::string encoded(coded_stream.str()); |
611 | S32 len = apr_base64_decode_len(encoded.c_str()); | 792 | S32 len = apr_base64_decode_len(encoded.c_str()); |
612 | std::vector<U8> value; | 793 | std::vector<U8> value; |
613 | value.resize(len); | 794 | if(len) |
614 | len = apr_base64_decode_binary(&value[0], encoded.c_str()); | 795 | { |
615 | value.resize(len); | 796 | value.resize(len); |
797 | len = apr_base64_decode_binary(&value[0], encoded.c_str()); | ||
798 | value.resize(len); | ||
799 | } | ||
616 | data = value; | 800 | data = value; |
617 | } | 801 | } |
618 | else if((c == '"') && (0 == strncmp("b16", buf, 3))) | 802 | else if(0 == strncmp("b16", buf, 3)) |
619 | { | 803 | { |
620 | // yay, base 16. We pop the next character which is either a | 804 | // yay, base 16. We pop the next character which is either a |
621 | // double quote or base 16 data. If it's a double quote, we're | 805 | // double quote or base 16 data. If it's a double quote, we're |
@@ -626,14 +810,14 @@ void LLSDNotationParser::parseBinary(std::istream& istr, LLSD& data) const | |||
626 | U8 byte_buffer[BINARY_BUFFER_SIZE]; | 810 | U8 byte_buffer[BINARY_BUFFER_SIZE]; |
627 | U8* write; | 811 | U8* write; |
628 | std::vector<U8> value; | 812 | std::vector<U8> value; |
629 | c = istr.get(); | 813 | c = get(istr); |
630 | while(c != '"') | 814 | while(c != '"') |
631 | { | 815 | { |
632 | istr.putback(c); | 816 | putback(istr, c); |
633 | read = buf; | 817 | read = buf; |
634 | write = byte_buffer; | 818 | write = byte_buffer; |
635 | istr.get(buf, STREAM_GET_COUNT, '"'); | 819 | get(istr, buf, STREAM_GET_COUNT, '"'); |
636 | c = istr.get(); | 820 | c = get(istr); |
637 | while(*read != '\0') /*Flawfinder: ignore*/ | 821 | while(*read != '\0') /*Flawfinder: ignore*/ |
638 | { | 822 | { |
639 | byte = hex_as_nybble(*read++); | 823 | byte = hex_as_nybble(*read++); |
@@ -648,8 +832,9 @@ void LLSDNotationParser::parseBinary(std::istream& istr, LLSD& data) const | |||
648 | } | 832 | } |
649 | else | 833 | else |
650 | { | 834 | { |
651 | data.clear(); | 835 | return false; |
652 | } | 836 | } |
837 | return true; | ||
653 | } | 838 | } |
654 | 839 | ||
655 | 840 | ||
@@ -666,7 +851,7 @@ LLSDBinaryParser::~LLSDBinaryParser() | |||
666 | } | 851 | } |
667 | 852 | ||
668 | // virtual | 853 | // virtual |
669 | S32 LLSDBinaryParser::parse(std::istream& istr, LLSD& data) const | 854 | S32 LLSDBinaryParser::doParse(std::istream& istr, LLSD& data) const |
670 | { | 855 | { |
671 | /** | 856 | /** |
672 | * Undefined: '!'<br> | 857 | * Undefined: '!'<br> |
@@ -685,7 +870,7 @@ S32 LLSDBinaryParser::parse(std::istream& istr, LLSD& data) const | |||
685 | * notation format. | 870 | * notation format. |
686 | */ | 871 | */ |
687 | char c; | 872 | char c; |
688 | c = istr.get(); | 873 | c = get(istr); |
689 | if(!istr.good()) | 874 | if(!istr.good()) |
690 | { | 875 | { |
691 | return 0; | 876 | return 0; |
@@ -694,20 +879,42 @@ S32 LLSDBinaryParser::parse(std::istream& istr, LLSD& data) const | |||
694 | switch(c) | 879 | switch(c) |
695 | { | 880 | { |
696 | case '{': | 881 | case '{': |
697 | parse_count += parseMap(istr, data); | 882 | { |
883 | S32 child_count = parseMap(istr, data); | ||
884 | if((child_count == PARSE_FAILURE) || data.isUndefined()) | ||
885 | { | ||
886 | parse_count = PARSE_FAILURE; | ||
887 | } | ||
888 | else | ||
889 | { | ||
890 | parse_count += child_count; | ||
891 | } | ||
698 | if(istr.fail()) | 892 | if(istr.fail()) |
699 | { | 893 | { |
700 | llinfos << "STREAM FAILURE reading binary map." << llendl; | 894 | llinfos << "STREAM FAILURE reading binary map." << llendl; |
895 | parse_count = PARSE_FAILURE; | ||
701 | } | 896 | } |
702 | break; | 897 | break; |
898 | } | ||
703 | 899 | ||
704 | case '[': | 900 | case '[': |
705 | parse_count += parseArray(istr, data); | 901 | { |
902 | S32 child_count = parseArray(istr, data); | ||
903 | if((child_count == PARSE_FAILURE) || data.isUndefined()) | ||
904 | { | ||
905 | parse_count = PARSE_FAILURE; | ||
906 | } | ||
907 | else | ||
908 | { | ||
909 | parse_count += child_count; | ||
910 | } | ||
706 | if(istr.fail()) | 911 | if(istr.fail()) |
707 | { | 912 | { |
708 | llinfos << "STREAM FAILURE reading binary array." << llendl; | 913 | llinfos << "STREAM FAILURE reading binary array." << llendl; |
914 | parse_count = PARSE_FAILURE; | ||
709 | } | 915 | } |
710 | break; | 916 | break; |
917 | } | ||
711 | 918 | ||
712 | case '!': | 919 | case '!': |
713 | data.clear(); | 920 | data.clear(); |
@@ -724,7 +931,7 @@ S32 LLSDBinaryParser::parse(std::istream& istr, LLSD& data) const | |||
724 | case 'i': | 931 | case 'i': |
725 | { | 932 | { |
726 | U32 value_nbo = 0; | 933 | U32 value_nbo = 0; |
727 | istr.read((char*)&value_nbo, sizeof(U32)); /*Flawfinder: ignore*/ | 934 | read(istr, (char*)&value_nbo, sizeof(U32)); /*Flawfinder: ignore*/ |
728 | data = (S32)ntohl(value_nbo); | 935 | data = (S32)ntohl(value_nbo); |
729 | if(istr.fail()) | 936 | if(istr.fail()) |
730 | { | 937 | { |
@@ -736,7 +943,7 @@ S32 LLSDBinaryParser::parse(std::istream& istr, LLSD& data) const | |||
736 | case 'r': | 943 | case 'r': |
737 | { | 944 | { |
738 | F64 real_nbo = 0.0; | 945 | F64 real_nbo = 0.0; |
739 | istr.read((char*)&real_nbo, sizeof(F64)); /*Flawfinder: ignore*/ | 946 | read(istr, (char*)&real_nbo, sizeof(F64)); /*Flawfinder: ignore*/ |
740 | data = ll_ntohd(real_nbo); | 947 | data = ll_ntohd(real_nbo); |
741 | if(istr.fail()) | 948 | if(istr.fail()) |
742 | { | 949 | { |
@@ -748,7 +955,7 @@ S32 LLSDBinaryParser::parse(std::istream& istr, LLSD& data) const | |||
748 | case 'u': | 955 | case 'u': |
749 | { | 956 | { |
750 | LLUUID id; | 957 | LLUUID id; |
751 | istr.read((char*)(&id.mData), UUID_BYTES); /*Flawfinder: ignore*/ | 958 | read(istr, (char*)(&id.mData), UUID_BYTES); /*Flawfinder: ignore*/ |
752 | data = id; | 959 | data = id; |
753 | if(istr.fail()) | 960 | if(istr.fail()) |
754 | { | 961 | { |
@@ -761,19 +968,40 @@ S32 LLSDBinaryParser::parse(std::istream& istr, LLSD& data) const | |||
761 | case '"': | 968 | case '"': |
762 | { | 969 | { |
763 | std::string value; | 970 | std::string value; |
764 | deserialize_string_delim(istr, value, c); | 971 | int cnt = deserialize_string_delim(istr, value, c); |
765 | data = value; | 972 | if(PARSE_FAILURE == cnt) |
973 | { | ||
974 | parse_count = PARSE_FAILURE; | ||
975 | } | ||
976 | else | ||
977 | { | ||
978 | data = value; | ||
979 | account(cnt); | ||
980 | } | ||
981 | if(istr.fail()) | ||
982 | { | ||
983 | llinfos << "STREAM FAILURE reading binary (notation-style) string." | ||
984 | << llendl; | ||
985 | parse_count = PARSE_FAILURE; | ||
986 | } | ||
766 | break; | 987 | break; |
767 | } | 988 | } |
768 | 989 | ||
769 | case 's': | 990 | case 's': |
770 | { | 991 | { |
771 | std::string value; | 992 | std::string value; |
772 | parseString(istr, value); | 993 | if(parseString(istr, value)) |
773 | data = value; | 994 | { |
995 | data = value; | ||
996 | } | ||
997 | else | ||
998 | { | ||
999 | parse_count = PARSE_FAILURE; | ||
1000 | } | ||
774 | if(istr.fail()) | 1001 | if(istr.fail()) |
775 | { | 1002 | { |
776 | llinfos << "STREAM FAILURE reading binary string." << llendl; | 1003 | llinfos << "STREAM FAILURE reading binary string." << llendl; |
1004 | parse_count = PARSE_FAILURE; | ||
777 | } | 1005 | } |
778 | break; | 1006 | break; |
779 | } | 1007 | } |
@@ -781,11 +1009,18 @@ S32 LLSDBinaryParser::parse(std::istream& istr, LLSD& data) const | |||
781 | case 'l': | 1009 | case 'l': |
782 | { | 1010 | { |
783 | std::string value; | 1011 | std::string value; |
784 | parseString(istr, value); | 1012 | if(parseString(istr, value)) |
785 | data = LLURI(value); | 1013 | { |
1014 | data = LLURI(value); | ||
1015 | } | ||
1016 | else | ||
1017 | { | ||
1018 | parse_count = PARSE_FAILURE; | ||
1019 | } | ||
786 | if(istr.fail()) | 1020 | if(istr.fail()) |
787 | { | 1021 | { |
788 | llinfos << "STREAM FAILURE reading binary link." << llendl; | 1022 | llinfos << "STREAM FAILURE reading binary link." << llendl; |
1023 | parse_count = PARSE_FAILURE; | ||
789 | } | 1024 | } |
790 | break; | 1025 | break; |
791 | } | 1026 | } |
@@ -793,11 +1028,12 @@ S32 LLSDBinaryParser::parse(std::istream& istr, LLSD& data) const | |||
793 | case 'd': | 1028 | case 'd': |
794 | { | 1029 | { |
795 | F64 real = 0.0; | 1030 | F64 real = 0.0; |
796 | istr.read((char*)&real, sizeof(F64)); /*Flawfinder: ignore*/ | 1031 | read(istr, (char*)&real, sizeof(F64)); /*Flawfinder: ignore*/ |
797 | data = LLDate(real); | 1032 | data = LLDate(real); |
798 | if(istr.fail()) | 1033 | if(istr.fail()) |
799 | { | 1034 | { |
800 | llinfos << "STREAM FAILURE reading binary date." << llendl; | 1035 | llinfos << "STREAM FAILURE reading binary date." << llendl; |
1036 | parse_count = PARSE_FAILURE; | ||
801 | } | 1037 | } |
802 | break; | 1038 | break; |
803 | } | 1039 | } |
@@ -806,75 +1042,94 @@ S32 LLSDBinaryParser::parse(std::istream& istr, LLSD& data) const | |||
806 | { | 1042 | { |
807 | // We probably have a valid raw binary stream. determine | 1043 | // We probably have a valid raw binary stream. determine |
808 | // the size, and read it. | 1044 | // the size, and read it. |
809 | // *FIX: Should we set a maximum size? | ||
810 | U32 size_nbo = 0; | 1045 | U32 size_nbo = 0; |
811 | istr.read((char*)&size_nbo, sizeof(U32)); /*Flawfinder: ignore*/ | 1046 | read(istr, (char*)&size_nbo, sizeof(U32)); /*Flawfinder: ignore*/ |
812 | S32 size = (S32)ntohl(size_nbo); | 1047 | S32 size = (S32)ntohl(size_nbo); |
813 | std::vector<U8> value; | 1048 | if(mCheckLimits && (size > mMaxBytesLeft)) |
814 | if(size) | ||
815 | { | 1049 | { |
816 | value.resize(size); | 1050 | parse_count = PARSE_FAILURE; |
817 | istr.read((char*)&value[0], size); /*Flawfinder: ignore*/ | 1051 | } |
1052 | else | ||
1053 | { | ||
1054 | std::vector<U8> value; | ||
1055 | if(size > 0) | ||
1056 | { | ||
1057 | value.resize(size); | ||
1058 | account(fullread(istr, (char*)&value[0], size)); | ||
1059 | } | ||
1060 | data = value; | ||
818 | } | 1061 | } |
819 | data = value; | ||
820 | if(istr.fail()) | 1062 | if(istr.fail()) |
821 | { | 1063 | { |
822 | llinfos << "STREAM FAILURE reading binary." << llendl; | 1064 | llinfos << "STREAM FAILURE reading binary." << llendl; |
1065 | parse_count = PARSE_FAILURE; | ||
823 | } | 1066 | } |
824 | break; | 1067 | break; |
825 | } | 1068 | } |
826 | 1069 | ||
827 | default: | 1070 | default: |
828 | --parse_count; | 1071 | parse_count = PARSE_FAILURE; |
829 | llinfos << "Unrecognized character while parsing: int(" << (int)c | 1072 | llinfos << "Unrecognized character while parsing: int(" << (int)c |
830 | << ")" << llendl; | 1073 | << ")" << llendl; |
831 | break; | 1074 | break; |
832 | } | 1075 | } |
1076 | if(PARSE_FAILURE == parse_count) | ||
1077 | { | ||
1078 | data.clear(); | ||
1079 | } | ||
833 | return parse_count; | 1080 | return parse_count; |
834 | } | 1081 | } |
835 | 1082 | ||
836 | // static | ||
837 | LLSD LLSDBinaryParser::parse(std::istream& istr) | ||
838 | { | ||
839 | LLSDBinaryParser parser; | ||
840 | LLSD rv; | ||
841 | S32 count = parser.parse(istr, rv); | ||
842 | lldebugs << "LLSDBinaryParser::parse parsed " << count << " objects." | ||
843 | << llendl; | ||
844 | return rv; | ||
845 | } | ||
846 | |||
847 | S32 LLSDBinaryParser::parseMap(std::istream& istr, LLSD& map) const | 1083 | S32 LLSDBinaryParser::parseMap(std::istream& istr, LLSD& map) const |
848 | { | 1084 | { |
849 | map = LLSD::emptyMap(); | 1085 | map = LLSD::emptyMap(); |
850 | U32 value_nbo = 0; | 1086 | U32 value_nbo = 0; |
851 | istr.read((char*)&value_nbo, sizeof(U32)); /*Flawfinder: ignore*/ | 1087 | read(istr, (char*)&value_nbo, sizeof(U32)); /*Flawfinder: ignore*/ |
852 | S32 size = (S32)ntohl(value_nbo); | 1088 | S32 size = (S32)ntohl(value_nbo); |
853 | S32 parse_count = 0; | 1089 | S32 parse_count = 0; |
854 | S32 count = 0; | 1090 | S32 count = 0; |
855 | char c = istr.get(); | 1091 | char c = get(istr); |
856 | while(c != '}' && (count < size) && istr.good()) | 1092 | while(c != '}' && (count < size) && istr.good()) |
857 | { | 1093 | { |
858 | std::string name; | 1094 | std::string name; |
859 | switch(c) | 1095 | switch(c) |
860 | { | 1096 | { |
861 | case 'k': | 1097 | case 'k': |
862 | parseString(istr, name); | 1098 | if(!parseString(istr, name)) |
1099 | { | ||
1100 | return PARSE_FAILURE; | ||
1101 | } | ||
863 | break; | 1102 | break; |
864 | case '\'': | 1103 | case '\'': |
865 | case '"': | 1104 | case '"': |
866 | deserialize_string_delim(istr, name, c); | 1105 | { |
1106 | int cnt = deserialize_string_delim(istr, name, c); | ||
1107 | if(PARSE_FAILURE == cnt) return PARSE_FAILURE; | ||
1108 | account(cnt); | ||
867 | break; | 1109 | break; |
868 | } | 1110 | } |
1111 | } | ||
869 | LLSD child; | 1112 | LLSD child; |
870 | S32 child_count = parse(istr, child); | 1113 | S32 child_count = doParse(istr, child); |
871 | if(child_count) | 1114 | if(child_count > 0) |
872 | { | 1115 | { |
1116 | // There must be a value for every key, thus child_count | ||
1117 | // must be greater than 0. | ||
873 | parse_count += child_count; | 1118 | parse_count += child_count; |
874 | map.insert(name, child); | 1119 | map.insert(name, child); |
875 | } | 1120 | } |
1121 | else | ||
1122 | { | ||
1123 | return PARSE_FAILURE; | ||
1124 | } | ||
876 | ++count; | 1125 | ++count; |
877 | c = istr.get(); | 1126 | c = get(istr); |
1127 | } | ||
1128 | if((c != '}') || (count < size)) | ||
1129 | { | ||
1130 | // Make sure it is correctly terminated and we parsed as many | ||
1131 | // as were said to be there. | ||
1132 | return PARSE_FAILURE; | ||
878 | } | 1133 | } |
879 | return parse_count; | 1134 | return parse_count; |
880 | } | 1135 | } |
@@ -883,7 +1138,7 @@ S32 LLSDBinaryParser::parseArray(std::istream& istr, LLSD& array) const | |||
883 | { | 1138 | { |
884 | array = LLSD::emptyArray(); | 1139 | array = LLSD::emptyArray(); |
885 | U32 value_nbo = 0; | 1140 | U32 value_nbo = 0; |
886 | istr.read((char*)&value_nbo, sizeof(U32)); /*Flawfinder: ignore*/ | 1141 | read(istr, (char*)&value_nbo, sizeof(U32)); /*Flawfinder: ignore*/ |
887 | S32 size = (S32)ntohl(value_nbo); | 1142 | S32 size = (S32)ntohl(value_nbo); |
888 | 1143 | ||
889 | // *FIX: This would be a good place to reserve some space in the | 1144 | // *FIX: This would be a good place to reserve some space in the |
@@ -895,7 +1150,11 @@ S32 LLSDBinaryParser::parseArray(std::istream& istr, LLSD& array) const | |||
895 | while((c != ']') && (count < size) && istr.good()) | 1150 | while((c != ']') && (count < size) && istr.good()) |
896 | { | 1151 | { |
897 | LLSD child; | 1152 | LLSD child; |
898 | S32 child_count = parse(istr, child); | 1153 | S32 child_count = doParse(istr, child); |
1154 | if(PARSE_FAILURE == child_count) | ||
1155 | { | ||
1156 | return PARSE_FAILURE; | ||
1157 | } | ||
899 | if(child_count) | 1158 | if(child_count) |
900 | { | 1159 | { |
901 | parse_count += child_count; | 1160 | parse_count += child_count; |
@@ -904,22 +1163,33 @@ S32 LLSDBinaryParser::parseArray(std::istream& istr, LLSD& array) const | |||
904 | ++count; | 1163 | ++count; |
905 | c = istr.peek(); | 1164 | c = istr.peek(); |
906 | } | 1165 | } |
907 | c = istr.get(); | 1166 | c = get(istr); |
1167 | if((c != ']') || (count < size)) | ||
1168 | { | ||
1169 | // Make sure it is correctly terminated and we parsed as many | ||
1170 | // as were said to be there. | ||
1171 | return PARSE_FAILURE; | ||
1172 | } | ||
908 | return parse_count; | 1173 | return parse_count; |
909 | } | 1174 | } |
910 | 1175 | ||
911 | void LLSDBinaryParser::parseString( | 1176 | bool LLSDBinaryParser::parseString( |
912 | std::istream& istr, | 1177 | std::istream& istr, |
913 | std::string& value) const | 1178 | std::string& value) const |
914 | { | 1179 | { |
915 | // *FIX: This is memory inefficient. | 1180 | // *FIX: This is memory inefficient. |
916 | U32 value_nbo = 0; | 1181 | U32 value_nbo = 0; |
917 | istr.read((char*)&value_nbo, sizeof(U32)); /*Flawfinder: ignore*/ | 1182 | read(istr, (char*)&value_nbo, sizeof(U32)); /*Flawfinder: ignore*/ |
918 | S32 size = (S32)ntohl(value_nbo); | 1183 | S32 size = (S32)ntohl(value_nbo); |
1184 | if(mCheckLimits && (size > mMaxBytesLeft)) return false; | ||
919 | std::vector<char> buf; | 1185 | std::vector<char> buf; |
920 | buf.resize(size); | 1186 | if(size) |
921 | istr.read(&buf[0], size); /*Flawfinder: ignore*/ | 1187 | { |
922 | value.assign(buf.begin(), buf.end()); | 1188 | buf.resize(size); |
1189 | account(fullread(istr, &buf[0], size)); | ||
1190 | value.assign(buf.begin(), buf.end()); | ||
1191 | } | ||
1192 | return true; | ||
923 | } | 1193 | } |
924 | 1194 | ||
925 | 1195 | ||
@@ -1217,33 +1487,38 @@ void LLSDBinaryFormatter::formatString( | |||
1217 | /** | 1487 | /** |
1218 | * local functions | 1488 | * local functions |
1219 | */ | 1489 | */ |
1220 | bool deserialize_string(std::istream& str, std::string& value) | 1490 | int deserialize_string(std::istream& istr, std::string& value, S32 max_bytes) |
1221 | { | 1491 | { |
1222 | char c = str.get(); | 1492 | char c = istr.get(); |
1223 | if (str.fail()) | 1493 | if(istr.fail()) |
1224 | { | 1494 | { |
1225 | // No data in stream, bail out | 1495 | // No data in stream, bail out but mention the character we |
1226 | return false; | 1496 | // grabbed. |
1497 | return LLSDParser::PARSE_FAILURE; | ||
1227 | } | 1498 | } |
1228 | 1499 | ||
1229 | bool rv = false; | 1500 | int rv = LLSDParser::PARSE_FAILURE; |
1230 | switch(c) | 1501 | switch(c) |
1231 | { | 1502 | { |
1232 | case '\'': | 1503 | case '\'': |
1233 | case '"': | 1504 | case '"': |
1234 | rv = deserialize_string_delim(str, value, c); | 1505 | rv = deserialize_string_delim(istr, value, c); |
1235 | break; | 1506 | break; |
1236 | case 's': | 1507 | case 's': |
1237 | rv = deserialize_string_raw(str, value); | 1508 | // technically, less than max_bytes, but this is just meant to |
1509 | // catch egregious protocol errors. parse errors will be | ||
1510 | // caught in the case of incorrect counts. | ||
1511 | rv = deserialize_string_raw(istr, value, max_bytes); | ||
1238 | break; | 1512 | break; |
1239 | default: | 1513 | default: |
1240 | break; | 1514 | break; |
1241 | } | 1515 | } |
1242 | return rv; | 1516 | if(LLSDParser::PARSE_FAILURE == rv) return rv; |
1517 | return rv + 1; // account for the character grabbed at the top. | ||
1243 | } | 1518 | } |
1244 | 1519 | ||
1245 | bool deserialize_string_delim( | 1520 | int deserialize_string_delim( |
1246 | std::istream& str, | 1521 | std::istream& istr, |
1247 | std::string& value, | 1522 | std::string& value, |
1248 | char delim) | 1523 | char delim) |
1249 | { | 1524 | { |
@@ -1252,16 +1527,18 @@ bool deserialize_string_delim( | |||
1252 | bool found_hex = false; | 1527 | bool found_hex = false; |
1253 | bool found_digit = false; | 1528 | bool found_digit = false; |
1254 | U8 byte = 0; | 1529 | U8 byte = 0; |
1255 | 1530 | int count = 0; | |
1531 | |||
1256 | while (true) | 1532 | while (true) |
1257 | { | 1533 | { |
1258 | char next_char = str.get(); | 1534 | char next_char = istr.get(); |
1259 | 1535 | ++count; | |
1260 | if(str.fail()) | 1536 | |
1537 | if(istr.fail()) | ||
1261 | { | 1538 | { |
1262 | // If our stream is empty, break out | 1539 | // If our stream is empty, break out |
1263 | value = write_buffer.str(); | 1540 | value = write_buffer.str(); |
1264 | return false; | 1541 | return LLSDParser::PARSE_FAILURE; |
1265 | } | 1542 | } |
1266 | 1543 | ||
1267 | if(found_escape) | 1544 | if(found_escape) |
@@ -1338,35 +1615,48 @@ bool deserialize_string_delim( | |||
1338 | } | 1615 | } |
1339 | 1616 | ||
1340 | value = write_buffer.str(); | 1617 | value = write_buffer.str(); |
1341 | return true; | 1618 | return count; |
1342 | } | 1619 | } |
1343 | 1620 | ||
1344 | bool deserialize_string_raw(std::istream& str, std::string& value) | 1621 | int deserialize_string_raw( |
1622 | std::istream& istr, | ||
1623 | std::string& value, | ||
1624 | S32 max_bytes) | ||
1345 | { | 1625 | { |
1346 | bool ok = false; | 1626 | int count = 0; |
1347 | const S32 BUF_LEN = 20; | 1627 | const S32 BUF_LEN = 20; |
1348 | char buf[BUF_LEN]; /* Flawfinder: ignore */ | 1628 | char buf[BUF_LEN]; /* Flawfinder: ignore */ |
1349 | str.get(buf, BUF_LEN - 1, ')'); | 1629 | istr.get(buf, BUF_LEN - 1, ')'); |
1350 | char c = str.get(); | 1630 | count += istr.gcount(); |
1351 | c = str.get(); | 1631 | char c = istr.get(); |
1632 | c = istr.get(); | ||
1633 | count += 2; | ||
1352 | if(((c == '"') || (c == '\'')) && (buf[0] == '(')) | 1634 | if(((c == '"') || (c == '\'')) && (buf[0] == '(')) |
1353 | { | 1635 | { |
1354 | // We probably have a valid raw string. determine | 1636 | // We probably have a valid raw string. determine |
1355 | // the size, and read it. | 1637 | // the size, and read it. |
1356 | // *FIX: Should we set a maximum size? | ||
1357 | // *FIX: This is memory inefficient. | 1638 | // *FIX: This is memory inefficient. |
1358 | S32 len = strtol(buf + 1, NULL, 0); | 1639 | S32 len = strtol(buf + 1, NULL, 0); |
1640 | if((max_bytes>0)&&(len>max_bytes)) return LLSDParser::PARSE_FAILURE; | ||
1359 | std::vector<char> buf; | 1641 | std::vector<char> buf; |
1360 | buf.resize(len); | 1642 | if(len) |
1361 | str.read(&buf[0], len); /*Flawfinder: ignore*/ | 1643 | { |
1362 | value.assign(buf.begin(), buf.end()); | 1644 | buf.resize(len); |
1363 | c = str.get(); | 1645 | count += fullread(istr, (char *)&buf[0], len); |
1364 | if((c == '"') || (c == '\'')) | 1646 | value.assign(buf.begin(), buf.end()); |
1647 | } | ||
1648 | c = istr.get(); | ||
1649 | ++count; | ||
1650 | if(!((c == '"') || (c == '\''))) | ||
1365 | { | 1651 | { |
1366 | ok = true; | 1652 | return LLSDParser::PARSE_FAILURE; |
1367 | } | 1653 | } |
1368 | } | 1654 | } |
1369 | return ok; | 1655 | else |
1656 | { | ||
1657 | return LLSDParser::PARSE_FAILURE; | ||
1658 | } | ||
1659 | return count; | ||
1370 | } | 1660 | } |
1371 | 1661 | ||
1372 | static const char* NOTATION_STRING_CHARACTERS[256] = | 1662 | static const char* NOTATION_STRING_CHARACTERS[256] = |
@@ -1641,6 +1931,43 @@ void serialize_string(const std::string& value, std::ostream& str) | |||
1641 | } | 1931 | } |
1642 | } | 1932 | } |
1643 | 1933 | ||
1934 | int deserialize_boolean( | ||
1935 | std::istream& istr, | ||
1936 | LLSD& data, | ||
1937 | const std::string& compare, | ||
1938 | bool value) | ||
1939 | { | ||
1940 | // | ||
1941 | // this method is a little goofy, because it gets the stream at | ||
1942 | // the point where the t or f has already been | ||
1943 | // consumed. Basically, parse for a patch to the string passed in | ||
1944 | // starting at index 1. If it's a match: | ||
1945 | // * assign data to value | ||
1946 | // * return the number of bytes read | ||
1947 | // otherwise: | ||
1948 | // * set data to LLSD::null | ||
1949 | // * return LLSDParser::PARSE_FAILURE (-1) | ||
1950 | // | ||
1951 | int bytes_read = 0; | ||
1952 | std::string::size_type ii = 0; | ||
1953 | char c = istr.peek(); | ||
1954 | while((++ii < compare.size()) | ||
1955 | && (tolower(c) == (int)compare[ii]) | ||
1956 | && istr.good()) | ||
1957 | { | ||
1958 | istr.ignore(); | ||
1959 | ++bytes_read; | ||
1960 | c = istr.peek(); | ||
1961 | } | ||
1962 | if(compare.size() != ii) | ||
1963 | { | ||
1964 | data.clear(); | ||
1965 | return LLSDParser::PARSE_FAILURE; | ||
1966 | } | ||
1967 | data = value; | ||
1968 | return bytes_read; | ||
1969 | } | ||
1970 | |||
1644 | std::ostream& operator<<(std::ostream& s, const LLSD& llsd) | 1971 | std::ostream& operator<<(std::ostream& s, const LLSD& llsd) |
1645 | { | 1972 | { |
1646 | s << LLSDNotationStreamer(llsd); | 1973 | s << LLSDNotationStreamer(llsd); |