diff options
author | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
---|---|---|
committer | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
commit | 38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch) | |
tree | adca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/llcommon/llsdserialize.cpp | |
parent | README.txt (diff) | |
download | meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2 meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz |
Second Life viewer sources 1.13.2.12
Diffstat (limited to 'linden/indra/llcommon/llsdserialize.cpp')
-rw-r--r-- | linden/indra/llcommon/llsdserialize.cpp | 1640 |
1 files changed, 1640 insertions, 0 deletions
diff --git a/linden/indra/llcommon/llsdserialize.cpp b/linden/indra/llcommon/llsdserialize.cpp new file mode 100644 index 0000000..4c00c98 --- /dev/null +++ b/linden/indra/llcommon/llsdserialize.cpp | |||
@@ -0,0 +1,1640 @@ | |||
1 | /** | ||
2 | * @file llsdserialize.cpp | ||
3 | * @author Phoenix | ||
4 | * @date 2006-03-05 | ||
5 | * @brief Implementation of LLSD parsers and formatters | ||
6 | * | ||
7 | * Copyright (c) 2006-2007, Linden Research, Inc. | ||
8 | * | ||
9 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
10 | * to you under the terms of the GNU General Public License, version 2.0 | ||
11 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
12 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
13 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
14 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
15 | * | ||
16 | * There are special exceptions to the terms and conditions of the GPL as | ||
17 | * it is applied to this Source Code. View the full text of the exception | ||
18 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
19 | * online at http://secondlife.com/developers/opensource/flossexception | ||
20 | * | ||
21 | * By copying, modifying or distributing this software, you acknowledge | ||
22 | * that you have read and understood your obligations described above, | ||
23 | * and agree to abide by those obligations. | ||
24 | * | ||
25 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
26 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
27 | * COMPLETENESS OR PERFORMANCE. | ||
28 | */ | ||
29 | |||
30 | #include "linden_common.h" | ||
31 | #include "llsdserialize.h" | ||
32 | #include "llmemory.h" | ||
33 | #include "llstreamtools.h" // for fullread | ||
34 | |||
35 | #include <iostream> | ||
36 | #include "apr-1/apr_base64.h" | ||
37 | |||
38 | #if !LL_WINDOWS | ||
39 | #include <netinet/in.h> // htonl & ntohl | ||
40 | #endif | ||
41 | |||
42 | #include "lldate.h" | ||
43 | #include "llsd.h" | ||
44 | #include "lluri.h" | ||
45 | |||
46 | // File constants | ||
47 | static const int MAX_HDR_LEN = 20; | ||
48 | static const char LEGACY_NON_HEADER[] = "<llsd>"; | ||
49 | |||
50 | //static | ||
51 | const char* LLSDSerialize::LLSDBinaryHeader = "LLSD/Binary"; | ||
52 | |||
53 | //static | ||
54 | const char* LLSDSerialize::LLSDXMLHeader = "LLSD/XML"; | ||
55 | |||
56 | // virtual | ||
57 | LLSDParser::~LLSDParser() | ||
58 | { } | ||
59 | |||
60 | // virtual | ||
61 | LLSDNotationParser::~LLSDNotationParser() | ||
62 | { } | ||
63 | |||
64 | |||
65 | // static | ||
66 | void LLSDSerialize::serialize(const LLSD& sd, std::ostream& str, ELLSD_Serialize type, U32 options) | ||
67 | { | ||
68 | LLPointer<LLSDFormatter> f = NULL; | ||
69 | |||
70 | switch (type) | ||
71 | { | ||
72 | case LLSD_BINARY: | ||
73 | str << "<? " << LLSDBinaryHeader << " ?>\n"; | ||
74 | f = new LLSDBinaryFormatter; | ||
75 | break; | ||
76 | |||
77 | case LLSD_XML: | ||
78 | str << "<? " << LLSDXMLHeader << " ?>\n"; | ||
79 | f = new LLSDXMLFormatter; | ||
80 | break; | ||
81 | |||
82 | default: | ||
83 | llwarns << "serialize request for unkown ELLSD_Serialize" << llendl; | ||
84 | } | ||
85 | |||
86 | if (f.notNull()) | ||
87 | { | ||
88 | f->format(sd, str, options); | ||
89 | } | ||
90 | } | ||
91 | |||
92 | // static | ||
93 | bool LLSDSerialize::deserialize(LLSD& sd, std::istream& str) | ||
94 | { | ||
95 | LLPointer<LLSDParser> p = NULL; | ||
96 | char hdr_buf[MAX_HDR_LEN + 1] = ""; /* Flawfinder: ignore */ | ||
97 | int i; | ||
98 | int inbuf = 0; | ||
99 | bool legacy_no_header = false; | ||
100 | bool fail_if_not_legacy = false; | ||
101 | std::string header = ""; | ||
102 | |||
103 | /* | ||
104 | * Get the first line before anything. | ||
105 | */ | ||
106 | str.get(hdr_buf, MAX_HDR_LEN, '\n'); | ||
107 | if (str.fail()) | ||
108 | { | ||
109 | str.clear(); | ||
110 | fail_if_not_legacy = true; | ||
111 | } | ||
112 | |||
113 | if (!strncasecmp(LEGACY_NON_HEADER, hdr_buf, strlen(LEGACY_NON_HEADER))) /* Flawfinder: ignore */ | ||
114 | { | ||
115 | legacy_no_header = true; | ||
116 | inbuf = str.gcount(); | ||
117 | } | ||
118 | else | ||
119 | { | ||
120 | if (fail_if_not_legacy) | ||
121 | goto fail; | ||
122 | /* | ||
123 | * Remove the newline chars | ||
124 | */ | ||
125 | for (i = 0; i < MAX_HDR_LEN; i++) | ||
126 | { | ||
127 | if (hdr_buf[i] == 0 || hdr_buf[i] == '\r' || | ||
128 | hdr_buf[i] == '\n') | ||
129 | { | ||
130 | hdr_buf[i] = 0; | ||
131 | break; | ||
132 | } | ||
133 | } | ||
134 | header = hdr_buf; | ||
135 | |||
136 | std::string::size_type start = std::string::npos; | ||
137 | std::string::size_type end = std::string::npos; | ||
138 | start = header.find_first_not_of("<? "); | ||
139 | if (start != std::string::npos) | ||
140 | { | ||
141 | end = header.find_first_of(" ?", start); | ||
142 | } | ||
143 | if ((start == std::string::npos) || (end == std::string::npos)) | ||
144 | goto fail; | ||
145 | |||
146 | header = header.substr(start, end - start); | ||
147 | ws(str); | ||
148 | } | ||
149 | /* | ||
150 | * Create the parser as appropriate | ||
151 | */ | ||
152 | if (legacy_no_header) | ||
153 | { | ||
154 | LLSDXMLParser *x = new LLSDXMLParser; | ||
155 | x->parsePart(hdr_buf, inbuf); | ||
156 | p = x; | ||
157 | } | ||
158 | else if (header == LLSDBinaryHeader) | ||
159 | { | ||
160 | p = new LLSDBinaryParser; | ||
161 | } | ||
162 | else if (header == LLSDXMLHeader) | ||
163 | { | ||
164 | p = new LLSDXMLParser; | ||
165 | } | ||
166 | else | ||
167 | { | ||
168 | llwarns << "deserialize request for unknown ELLSD_Serialize" << llendl; | ||
169 | } | ||
170 | |||
171 | if (p.notNull()) | ||
172 | { | ||
173 | p->parse(str, sd); | ||
174 | return true; | ||
175 | } | ||
176 | |||
177 | fail: | ||
178 | llwarns << "deserialize LLSD parse failure" << llendl; | ||
179 | return false; | ||
180 | } | ||
181 | |||
182 | /** | ||
183 | * Endian handlers | ||
184 | */ | ||
185 | #if LL_BIG_ENDIAN | ||
186 | U64 ll_htonll(U64 hostlonglong) { return hostlonglong; } | ||
187 | U64 ll_ntohll(U64 netlonglong) { return netlonglong; } | ||
188 | F64 ll_htond(F64 hostlonglong) { return hostlonglong; } | ||
189 | F64 ll_ntohd(F64 netlonglong) { return netlonglong; } | ||
190 | #else | ||
191 | // I read some comments one a indicating that doing an integer add | ||
192 | // here would be faster than a bitwise or. For now, the or has | ||
193 | // programmer clarity, since the intended outcome matches the | ||
194 | // operation. | ||
195 | U64 ll_htonll(U64 hostlonglong) | ||
196 | { | ||
197 | return ((U64)(htonl((U32)((hostlonglong >> 32) & 0xFFFFFFFF))) | | ||
198 | ((U64)(htonl((U32)(hostlonglong & 0xFFFFFFFF))) << 32)); | ||
199 | } | ||
200 | U64 ll_ntohll(U64 netlonglong) | ||
201 | { | ||
202 | return ((U64)(ntohl((U32)((netlonglong >> 32) & 0xFFFFFFFF))) | | ||
203 | ((U64)(ntohl((U32)(netlonglong & 0xFFFFFFFF))) << 32)); | ||
204 | } | ||
205 | union LLEndianSwapper | ||
206 | { | ||
207 | F64 d; | ||
208 | U64 i; | ||
209 | }; | ||
210 | F64 ll_htond(F64 hostdouble) | ||
211 | { | ||
212 | LLEndianSwapper tmp; | ||
213 | tmp.d = hostdouble; | ||
214 | tmp.i = ll_htonll(tmp.i); | ||
215 | return tmp.d; | ||
216 | } | ||
217 | F64 ll_ntohd(F64 netdouble) | ||
218 | { | ||
219 | LLEndianSwapper tmp; | ||
220 | tmp.d = netdouble; | ||
221 | tmp.i = ll_ntohll(tmp.i); | ||
222 | return tmp.d; | ||
223 | } | ||
224 | #endif | ||
225 | |||
226 | /** | ||
227 | * Local functions. | ||
228 | */ | ||
229 | bool deserialize_string(std::istream& str, std::string& value); | ||
230 | bool deserialize_string_delim(std::istream& str, std::string& value, char d); | ||
231 | bool deserialize_string_raw(std::istream& str, std::string& value); | ||
232 | void serialize_string(const std::string& value, std::ostream& str); | ||
233 | |||
234 | /** | ||
235 | * Local constants. | ||
236 | */ | ||
237 | static const std::string NOTATION_TRUE_SERIAL("true"); | ||
238 | static const std::string NOTATION_FALSE_SERIAL("false"); | ||
239 | |||
240 | static const char BINARY_TRUE_SERIAL = '1'; | ||
241 | static const char BINARY_FALSE_SERIAL = '0'; | ||
242 | |||
243 | static const S32 NOTATION_PARSE_FAILURE = -1; | ||
244 | |||
245 | /** | ||
246 | * LLSDParser | ||
247 | */ | ||
248 | LLSDParser::LLSDParser() | ||
249 | { | ||
250 | } | ||
251 | |||
252 | /** | ||
253 | * LLSDNotationParser | ||
254 | */ | ||
255 | // virtual | ||
256 | S32 LLSDNotationParser::parse(std::istream& istr, LLSD& data) const | ||
257 | { | ||
258 | // map: { string:object, string:object } | ||
259 | // array: [ object, object, object ] | ||
260 | // undef: ! | ||
261 | // boolean: true | false | 1 | 0 | T | F | t | f | TRUE | FALSE | ||
262 | // integer: i#### | ||
263 | // real: r#### | ||
264 | // uuid: u#### | ||
265 | // string: "g'day" | 'have a "nice" day' | s(size)"raw data" | ||
266 | // uri: l"escaped" | ||
267 | // date: d"YYYY-MM-DDTHH:MM:SS.FFZ" | ||
268 | // binary: b##"ff3120ab1" | b(size)"raw data" | ||
269 | char c; | ||
270 | c = istr.peek(); | ||
271 | while(isspace(c)) | ||
272 | { | ||
273 | // pop the whitespace. | ||
274 | c = istr.get(); | ||
275 | c = istr.peek(); | ||
276 | continue; | ||
277 | } | ||
278 | if(!istr.good()) | ||
279 | { | ||
280 | return 0; | ||
281 | } | ||
282 | S32 parse_count = 1; | ||
283 | switch(c) | ||
284 | { | ||
285 | case '{': | ||
286 | parse_count += parseMap(istr, data); | ||
287 | if(istr.fail()) | ||
288 | { | ||
289 | llinfos << "STREAM FAILURE reading map." << llendl; | ||
290 | } | ||
291 | if(data.isUndefined()) | ||
292 | { | ||
293 | parse_count = NOTATION_PARSE_FAILURE; | ||
294 | } | ||
295 | break; | ||
296 | |||
297 | case '[': | ||
298 | parse_count += parseArray(istr, data); | ||
299 | if(istr.fail()) | ||
300 | { | ||
301 | llinfos << "STREAM FAILURE reading array." << llendl; | ||
302 | } | ||
303 | if(data.isUndefined()) | ||
304 | { | ||
305 | parse_count = NOTATION_PARSE_FAILURE; | ||
306 | } | ||
307 | break; | ||
308 | |||
309 | case '!': | ||
310 | c = istr.get(); | ||
311 | data.clear(); | ||
312 | break; | ||
313 | |||
314 | case '0': | ||
315 | c = istr.get(); | ||
316 | data = false; | ||
317 | break; | ||
318 | |||
319 | case 'F': | ||
320 | case 'f': | ||
321 | do | ||
322 | { | ||
323 | istr.ignore(); | ||
324 | c = istr.peek(); | ||
325 | } while (isalpha(c)); | ||
326 | data = false; | ||
327 | if(istr.fail()) | ||
328 | { | ||
329 | llinfos << "STREAM FAILURE reading boolean." << llendl; | ||
330 | } | ||
331 | break; | ||
332 | |||
333 | case '1': | ||
334 | c = istr.get(); | ||
335 | data = true; | ||
336 | break; | ||
337 | |||
338 | case 'T': | ||
339 | case 't': | ||
340 | do | ||
341 | { | ||
342 | istr.ignore(); | ||
343 | c = istr.peek(); | ||
344 | } while (isalpha(c)); | ||
345 | data = true; | ||
346 | if(istr.fail()) | ||
347 | { | ||
348 | llinfos << "STREAM FAILURE reading boolean." << llendl; | ||
349 | } | ||
350 | break; | ||
351 | |||
352 | case 'i': | ||
353 | { | ||
354 | c = istr.get(); | ||
355 | S32 integer = 0; | ||
356 | istr >> integer; | ||
357 | data = integer; | ||
358 | if(istr.fail()) | ||
359 | { | ||
360 | llinfos << "STREAM FAILURE reading integer." << llendl; | ||
361 | } | ||
362 | break; | ||
363 | } | ||
364 | |||
365 | case 'r': | ||
366 | { | ||
367 | c = istr.get(); | ||
368 | F64 real = 0.0; | ||
369 | istr >> real; | ||
370 | data = real; | ||
371 | if(istr.fail()) | ||
372 | { | ||
373 | llinfos << "STREAM FAILURE reading real." << llendl; | ||
374 | } | ||
375 | break; | ||
376 | } | ||
377 | |||
378 | case 'u': | ||
379 | { | ||
380 | c = istr.get(); | ||
381 | LLUUID id; | ||
382 | istr >> id; | ||
383 | data = id; | ||
384 | if(istr.fail()) | ||
385 | { | ||
386 | llinfos << "STREAM FAILURE reading uuid." << llendl; | ||
387 | } | ||
388 | break; | ||
389 | } | ||
390 | |||
391 | case '\"': | ||
392 | case '\'': | ||
393 | case 's': | ||
394 | parseString(istr, data); | ||
395 | if(istr.fail()) | ||
396 | { | ||
397 | llinfos << "STREAM FAILURE reading string." << llendl; | ||
398 | } | ||
399 | if(data.isUndefined()) | ||
400 | { | ||
401 | parse_count = NOTATION_PARSE_FAILURE; | ||
402 | } | ||
403 | break; | ||
404 | |||
405 | case 'l': | ||
406 | { | ||
407 | c = istr.get(); // pop the 'l' | ||
408 | c = istr.get(); // pop the delimiter | ||
409 | std::string str; | ||
410 | deserialize_string_delim(istr, str, c); | ||
411 | data = LLURI(str); | ||
412 | if(istr.fail()) | ||
413 | { | ||
414 | llinfos << "STREAM FAILURE reading link." << llendl; | ||
415 | } | ||
416 | break; | ||
417 | } | ||
418 | |||
419 | case 'd': | ||
420 | { | ||
421 | c = istr.get(); // pop the 'd' | ||
422 | c = istr.get(); // pop the delimiter | ||
423 | std::string str; | ||
424 | deserialize_string_delim(istr, str, c); | ||
425 | data = LLDate(str); | ||
426 | if(istr.fail()) | ||
427 | { | ||
428 | llinfos << "STREAM FAILURE reading date." << llendl; | ||
429 | } | ||
430 | break; | ||
431 | } | ||
432 | |||
433 | case 'b': | ||
434 | parseBinary(istr, data); | ||
435 | if(istr.fail()) | ||
436 | { | ||
437 | llinfos << "STREAM FAILURE reading data." << llendl; | ||
438 | } | ||
439 | if(data.isUndefined()) | ||
440 | { | ||
441 | parse_count = NOTATION_PARSE_FAILURE; | ||
442 | } | ||
443 | break; | ||
444 | |||
445 | default: | ||
446 | data.clear(); | ||
447 | parse_count = NOTATION_PARSE_FAILURE; | ||
448 | llinfos << "Unrecognized character while parsing: int(" << (int)c | ||
449 | << ")" << llendl; | ||
450 | break; | ||
451 | } | ||
452 | return parse_count; | ||
453 | } | ||
454 | |||
455 | // static | ||
456 | LLSD LLSDNotationParser::parse(std::istream& istr) | ||
457 | { | ||
458 | LLSDNotationParser parser; | ||
459 | LLSD rv; | ||
460 | S32 count = parser.parse(istr, rv); | ||
461 | lldebugs << "LLSDNotationParser::parse parsed " << count << " objects." | ||
462 | << llendl; | ||
463 | return rv; | ||
464 | } | ||
465 | |||
466 | S32 LLSDNotationParser::parseMap(std::istream& istr, LLSD& map) const | ||
467 | { | ||
468 | // map: { string:object, string:object } | ||
469 | map = LLSD::emptyMap(); | ||
470 | S32 parse_count = 0; | ||
471 | char c = istr.get(); | ||
472 | if(c == '{') | ||
473 | { | ||
474 | // eat commas, white | ||
475 | bool found_name = false; | ||
476 | std::string name; | ||
477 | c = istr.get(); | ||
478 | while(c != '}' && istr.good()) | ||
479 | { | ||
480 | if(!found_name) | ||
481 | { | ||
482 | if((c == '\"') || (c == '\'') || (c == 's')) | ||
483 | { | ||
484 | istr.putback(c); | ||
485 | found_name = true; | ||
486 | deserialize_string(istr, name); | ||
487 | } | ||
488 | c = istr.get(); | ||
489 | } | ||
490 | else | ||
491 | { | ||
492 | if(isspace(c) || (c == ':')) | ||
493 | { | ||
494 | c = istr.get(); | ||
495 | continue; | ||
496 | } | ||
497 | istr.putback(c); | ||
498 | LLSD child; | ||
499 | S32 count = parse(istr, child); | ||
500 | if(count > 0) | ||
501 | { | ||
502 | parse_count += count; | ||
503 | map.insert(name, child); | ||
504 | } | ||
505 | else | ||
506 | { | ||
507 | map.clear(); | ||
508 | return NOTATION_PARSE_FAILURE; | ||
509 | } | ||
510 | found_name = false; | ||
511 | c = istr.get(); | ||
512 | } | ||
513 | } | ||
514 | } | ||
515 | return parse_count; | ||
516 | } | ||
517 | |||
518 | S32 LLSDNotationParser::parseArray(std::istream& istr, LLSD& array) const | ||
519 | { | ||
520 | // array: [ object, object, object ] | ||
521 | array = LLSD::emptyArray(); | ||
522 | S32 parse_count = 0; | ||
523 | char c = istr.get(); | ||
524 | if(c == '[') | ||
525 | { | ||
526 | // eat commas, white | ||
527 | c = istr.get(); | ||
528 | while((c != ']') && istr.good()) | ||
529 | { | ||
530 | LLSD child; | ||
531 | if(isspace(c) || (c == ',')) | ||
532 | { | ||
533 | c = istr.get(); | ||
534 | continue; | ||
535 | } | ||
536 | istr.putback(c); | ||
537 | S32 count = parse(istr, child); | ||
538 | if(count > 0) | ||
539 | { | ||
540 | parse_count += count; | ||
541 | array.append(child); | ||
542 | } | ||
543 | else | ||
544 | { | ||
545 | array.clear(); | ||
546 | return NOTATION_PARSE_FAILURE; | ||
547 | } | ||
548 | c = istr.get(); | ||
549 | } | ||
550 | } | ||
551 | return parse_count; | ||
552 | } | ||
553 | |||
554 | void LLSDNotationParser::parseString(std::istream& istr, LLSD& data) const | ||
555 | { | ||
556 | std::string value; | ||
557 | if(deserialize_string(istr, value)) | ||
558 | { | ||
559 | data = value; | ||
560 | } | ||
561 | else | ||
562 | { | ||
563 | // failed to parse. | ||
564 | data.clear(); | ||
565 | } | ||
566 | } | ||
567 | |||
568 | void LLSDNotationParser::parseBinary(std::istream& istr, LLSD& data) const | ||
569 | { | ||
570 | // binary: b##"ff3120ab1" | ||
571 | // or: b(len)"..." | ||
572 | |||
573 | // I want to manually control those values here to make sure the | ||
574 | // parser doesn't break when someone changes a constant somewhere | ||
575 | // else. | ||
576 | const U32 BINARY_BUFFER_SIZE = 256; | ||
577 | const U32 STREAM_GET_COUNT = 255; | ||
578 | |||
579 | // need to read the base out. | ||
580 | char buf[BINARY_BUFFER_SIZE]; /* Flawfinder: ignore */ | ||
581 | istr.get(buf, STREAM_GET_COUNT, '"'); | ||
582 | char c = istr.get(); | ||
583 | if((c == '"') && (0 == strncmp("b(", buf, 2))) | ||
584 | { | ||
585 | // We probably have a valid raw binary stream. determine | ||
586 | // the size, and read it. | ||
587 | // *FIX: Should we set a maximum size? | ||
588 | S32 len = strtol(buf + 2, NULL, 0); | ||
589 | std::vector<U8> value; | ||
590 | if(len) | ||
591 | { | ||
592 | value.resize(len); | ||
593 | fullread(istr, (char *)&value[0], len); | ||
594 | } | ||
595 | c = istr.get(); // strip off the trailing double-quote | ||
596 | data = value; | ||
597 | } | ||
598 | else if((c == '"') && (0 == strncmp("b64", buf, 3))) | ||
599 | { | ||
600 | // *FIX: A bit inefficient, but works for now. To make the | ||
601 | // format better, I would need to add a hint into the | ||
602 | // serialization format that indicated how long it was. | ||
603 | std::stringstream coded_stream; | ||
604 | istr.get(*(coded_stream.rdbuf()), '\"'); | ||
605 | c = istr.get(); | ||
606 | std::string encoded(coded_stream.str()); | ||
607 | S32 len = apr_base64_decode_len(encoded.c_str()); | ||
608 | std::vector<U8> value; | ||
609 | value.resize(len); | ||
610 | len = apr_base64_decode_binary(&value[0], encoded.c_str()); | ||
611 | value.resize(len); | ||
612 | data = value; | ||
613 | } | ||
614 | else if((c == '"') && (0 == strncmp("b16", buf, 3))) | ||
615 | { | ||
616 | // yay, base 16. We pop the next character which is either a | ||
617 | // double quote or base 16 data. If it's a double quote, we're | ||
618 | // done parsing. If it's not, put the data back, and read the | ||
619 | // stream until the next double quote. | ||
620 | char* read; /*Flawfinder: ignore*/ | ||
621 | U8 byte; | ||
622 | U8 byte_buffer[BINARY_BUFFER_SIZE]; | ||
623 | U8* write; | ||
624 | std::vector<U8> value; | ||
625 | c = istr.get(); | ||
626 | while(c != '"') | ||
627 | { | ||
628 | istr.putback(c); | ||
629 | read = buf; | ||
630 | write = byte_buffer; | ||
631 | istr.get(buf, STREAM_GET_COUNT, '"'); | ||
632 | c = istr.get(); | ||
633 | while(*read != '\0') /*Flawfinder: ignore*/ | ||
634 | { | ||
635 | byte = hex_as_nybble(*read++); | ||
636 | byte = byte << 4; | ||
637 | byte |= hex_as_nybble(*read++); | ||
638 | *write++ = byte; | ||
639 | } | ||
640 | // copy the data out of the byte buffer | ||
641 | value.insert(value.end(), byte_buffer, write); | ||
642 | } | ||
643 | data = value; | ||
644 | } | ||
645 | else | ||
646 | { | ||
647 | data.clear(); | ||
648 | } | ||
649 | } | ||
650 | |||
651 | |||
652 | /** | ||
653 | * LLSDBinaryParser | ||
654 | */ | ||
655 | LLSDBinaryParser::LLSDBinaryParser() | ||
656 | { | ||
657 | } | ||
658 | |||
659 | // virtual | ||
660 | LLSDBinaryParser::~LLSDBinaryParser() | ||
661 | { | ||
662 | } | ||
663 | |||
664 | // virtual | ||
665 | S32 LLSDBinaryParser::parse(std::istream& istr, LLSD& data) const | ||
666 | { | ||
667 | /** | ||
668 | * Undefined: '!'<br> | ||
669 | * Boolean: 't' for true 'f' for false<br> | ||
670 | * Integer: 'i' + 4 bytes network byte order<br> | ||
671 | * Real: 'r' + 8 bytes IEEE double<br> | ||
672 | * UUID: 'u' + 16 byte unsigned integer<br> | ||
673 | * String: 's' + 4 byte integer size + string<br> | ||
674 | * strings also secretly support the notation format | ||
675 | * Date: 'd' + 8 byte IEEE double for seconds since epoch<br> | ||
676 | * URI: 'l' + 4 byte integer size + string uri<br> | ||
677 | * Binary: 'b' + 4 byte integer size + binary data<br> | ||
678 | * Array: '[' + 4 byte integer size + all values + ']'<br> | ||
679 | * Map: '{' + 4 byte integer size every(key + value) + '}'<br> | ||
680 | * map keys are serialized as s + 4 byte integer size + string or in the | ||
681 | * notation format. | ||
682 | */ | ||
683 | char c; | ||
684 | c = istr.get(); | ||
685 | if(!istr.good()) | ||
686 | { | ||
687 | return 0; | ||
688 | } | ||
689 | S32 parse_count = 1; | ||
690 | switch(c) | ||
691 | { | ||
692 | case '{': | ||
693 | parse_count += parseMap(istr, data); | ||
694 | if(istr.fail()) | ||
695 | { | ||
696 | llinfos << "STREAM FAILURE reading binary map." << llendl; | ||
697 | } | ||
698 | break; | ||
699 | |||
700 | case '[': | ||
701 | parse_count += parseArray(istr, data); | ||
702 | if(istr.fail()) | ||
703 | { | ||
704 | llinfos << "STREAM FAILURE reading binary array." << llendl; | ||
705 | } | ||
706 | break; | ||
707 | |||
708 | case '!': | ||
709 | data.clear(); | ||
710 | break; | ||
711 | |||
712 | case '0': | ||
713 | data = false; | ||
714 | break; | ||
715 | |||
716 | case '1': | ||
717 | data = true; | ||
718 | break; | ||
719 | |||
720 | case 'i': | ||
721 | { | ||
722 | U32 value_nbo = 0; | ||
723 | istr.read((char*)&value_nbo, sizeof(U32)); /*Flawfinder: ignore*/ | ||
724 | data = (S32)ntohl(value_nbo); | ||
725 | if(istr.fail()) | ||
726 | { | ||
727 | llinfos << "STREAM FAILURE reading binary integer." << llendl; | ||
728 | } | ||
729 | break; | ||
730 | } | ||
731 | |||
732 | case 'r': | ||
733 | { | ||
734 | F64 real_nbo = 0.0; | ||
735 | istr.read((char*)&real_nbo, sizeof(F64)); /*Flawfinder: ignore*/ | ||
736 | data = ll_ntohd(real_nbo); | ||
737 | if(istr.fail()) | ||
738 | { | ||
739 | llinfos << "STREAM FAILURE reading binary real." << llendl; | ||
740 | } | ||
741 | break; | ||
742 | } | ||
743 | |||
744 | case 'u': | ||
745 | { | ||
746 | LLUUID id; | ||
747 | istr.read((char*)(&id.mData), UUID_BYTES); /*Flawfinder: ignore*/ | ||
748 | data = id; | ||
749 | if(istr.fail()) | ||
750 | { | ||
751 | llinfos << "STREAM FAILURE reading binary uuid." << llendl; | ||
752 | } | ||
753 | break; | ||
754 | } | ||
755 | |||
756 | case '\'': | ||
757 | case '"': | ||
758 | { | ||
759 | std::string value; | ||
760 | deserialize_string_delim(istr, value, c); | ||
761 | data = value; | ||
762 | break; | ||
763 | } | ||
764 | |||
765 | case 's': | ||
766 | { | ||
767 | std::string value; | ||
768 | parseString(istr, value); | ||
769 | data = value; | ||
770 | if(istr.fail()) | ||
771 | { | ||
772 | llinfos << "STREAM FAILURE reading binary string." << llendl; | ||
773 | } | ||
774 | break; | ||
775 | } | ||
776 | |||
777 | case 'l': | ||
778 | { | ||
779 | std::string value; | ||
780 | parseString(istr, value); | ||
781 | data = LLURI(value); | ||
782 | if(istr.fail()) | ||
783 | { | ||
784 | llinfos << "STREAM FAILURE reading binary link." << llendl; | ||
785 | } | ||
786 | break; | ||
787 | } | ||
788 | |||
789 | case 'd': | ||
790 | { | ||
791 | F64 real = 0.0; | ||
792 | istr.read((char*)&real, sizeof(F64)); /*Flawfinder: ignore*/ | ||
793 | data = LLDate(real); | ||
794 | if(istr.fail()) | ||
795 | { | ||
796 | llinfos << "STREAM FAILURE reading binary date." << llendl; | ||
797 | } | ||
798 | break; | ||
799 | } | ||
800 | |||
801 | case 'b': | ||
802 | { | ||
803 | // We probably have a valid raw binary stream. determine | ||
804 | // the size, and read it. | ||
805 | // *FIX: Should we set a maximum size? | ||
806 | U32 size_nbo = 0; | ||
807 | istr.read((char*)&size_nbo, sizeof(U32)); | ||
808 | S32 size = (S32)ntohl(size_nbo); | ||
809 | std::vector<U8> value; | ||
810 | if(size) | ||
811 | { | ||
812 | value.resize(size); | ||
813 | istr.read((char*)&value[0], size); /*Flawfinder: ignore*/ | ||
814 | } | ||
815 | data = value; | ||
816 | if(istr.fail()) | ||
817 | { | ||
818 | llinfos << "STREAM FAILURE reading binary." << llendl; | ||
819 | } | ||
820 | break; | ||
821 | } | ||
822 | |||
823 | default: | ||
824 | --parse_count; | ||
825 | llinfos << "Unrecognized character while parsing: int(" << (int)c | ||
826 | << ")" << llendl; | ||
827 | break; | ||
828 | } | ||
829 | return parse_count; | ||
830 | } | ||
831 | |||
832 | // static | ||
833 | LLSD LLSDBinaryParser::parse(std::istream& istr) | ||
834 | { | ||
835 | LLSDBinaryParser parser; | ||
836 | LLSD rv; | ||
837 | S32 count = parser.parse(istr, rv); | ||
838 | lldebugs << "LLSDBinaryParser::parse parsed " << count << " objects." | ||
839 | << llendl; | ||
840 | return rv; | ||
841 | } | ||
842 | |||
843 | S32 LLSDBinaryParser::parseMap(std::istream& istr, LLSD& map) const | ||
844 | { | ||
845 | map = LLSD::emptyMap(); | ||
846 | U32 value_nbo = 0; | ||
847 | istr.read((char*)&value_nbo, sizeof(U32)); /*Flawfinder: ignore*/ | ||
848 | S32 size = (S32)ntohl(value_nbo); | ||
849 | S32 parse_count = 0; | ||
850 | S32 count = 0; | ||
851 | char c = istr.get(); | ||
852 | while(c != '}' && (count < size) && istr.good()) | ||
853 | { | ||
854 | std::string name; | ||
855 | switch(c) | ||
856 | { | ||
857 | case 'k': | ||
858 | parseString(istr, name); | ||
859 | break; | ||
860 | case '\'': | ||
861 | case '"': | ||
862 | deserialize_string_delim(istr, name, c); | ||
863 | break; | ||
864 | } | ||
865 | LLSD child; | ||
866 | S32 child_count = parse(istr, child); | ||
867 | if(child_count) | ||
868 | { | ||
869 | parse_count += child_count; | ||
870 | map.insert(name, child); | ||
871 | } | ||
872 | ++count; | ||
873 | c = istr.get(); | ||
874 | } | ||
875 | return parse_count; | ||
876 | } | ||
877 | |||
878 | S32 LLSDBinaryParser::parseArray(std::istream& istr, LLSD& array) const | ||
879 | { | ||
880 | array = LLSD::emptyArray(); | ||
881 | U32 value_nbo = 0; | ||
882 | istr.read((char*)&value_nbo, sizeof(U32)); /*Flawfinder: ignore*/ | ||
883 | S32 size = (S32)ntohl(value_nbo); | ||
884 | |||
885 | // *FIX: This would be a good place to reserve some space in the | ||
886 | // array... | ||
887 | |||
888 | S32 parse_count = 0; | ||
889 | S32 count = 0; | ||
890 | char c = istr.peek(); | ||
891 | while((c != ']') && (count < size) && istr.good()) | ||
892 | { | ||
893 | LLSD child; | ||
894 | S32 child_count = parse(istr, child); | ||
895 | if(child_count) | ||
896 | { | ||
897 | parse_count += child_count; | ||
898 | array.append(child); | ||
899 | } | ||
900 | ++count; | ||
901 | c = istr.peek(); | ||
902 | } | ||
903 | c = istr.get(); | ||
904 | return parse_count; | ||
905 | } | ||
906 | |||
907 | void LLSDBinaryParser::parseString( | ||
908 | std::istream& istr, | ||
909 | std::string& value) const | ||
910 | { | ||
911 | // *FIX: This is memory inefficient. | ||
912 | U32 value_nbo = 0; | ||
913 | istr.read((char*)&value_nbo, sizeof(U32)); /*Flawfinder: ignore*/ | ||
914 | S32 size = (S32)ntohl(value_nbo); | ||
915 | std::vector<char> buf; | ||
916 | buf.resize(size); | ||
917 | istr.read(&buf[0], size); /*Flawfinder: ignore*/ | ||
918 | value.assign(buf.begin(), buf.end()); | ||
919 | } | ||
920 | |||
921 | |||
922 | /** | ||
923 | * LLSDFormatter | ||
924 | */ | ||
925 | LLSDFormatter::LLSDFormatter() : | ||
926 | mBoolAlpha(false) | ||
927 | { | ||
928 | } | ||
929 | |||
930 | // virtual | ||
931 | LLSDFormatter::~LLSDFormatter() | ||
932 | { } | ||
933 | |||
934 | void LLSDFormatter::boolalpha(bool alpha) | ||
935 | { | ||
936 | mBoolAlpha = alpha; | ||
937 | } | ||
938 | |||
939 | void LLSDFormatter::realFormat(const std::string& format) | ||
940 | { | ||
941 | mRealFormat = format; | ||
942 | } | ||
943 | |||
944 | void LLSDFormatter::formatReal(LLSD::Real real, std::ostream& ostr) const | ||
945 | { | ||
946 | char buffer[MAX_STRING]; /* Flawfinder: ignore */ | ||
947 | snprintf(buffer, MAX_STRING, mRealFormat.c_str(), real); | ||
948 | ostr << buffer; | ||
949 | } | ||
950 | |||
951 | /** | ||
952 | * LLSDNotationFormatter | ||
953 | */ | ||
954 | LLSDNotationFormatter::LLSDNotationFormatter() | ||
955 | { | ||
956 | } | ||
957 | |||
958 | // virtual | ||
959 | LLSDNotationFormatter::~LLSDNotationFormatter() | ||
960 | { } | ||
961 | |||
962 | // static | ||
963 | std::string LLSDNotationFormatter::escapeString(const std::string& in) | ||
964 | { | ||
965 | std::ostringstream ostr; | ||
966 | serialize_string(in, ostr); | ||
967 | return ostr.str(); | ||
968 | } | ||
969 | |||
970 | // virtual | ||
971 | S32 LLSDNotationFormatter::format(const LLSD& data, std::ostream& ostr, U32 options) const | ||
972 | { | ||
973 | S32 format_count = 1; | ||
974 | switch(data.type()) | ||
975 | { | ||
976 | case LLSD::TypeMap: | ||
977 | { | ||
978 | ostr << "{"; | ||
979 | bool need_comma = false; | ||
980 | LLSD::map_const_iterator iter = data.beginMap(); | ||
981 | LLSD::map_const_iterator end = data.endMap(); | ||
982 | for(; iter != end; ++iter) | ||
983 | { | ||
984 | if(need_comma) ostr << ","; | ||
985 | need_comma = true; | ||
986 | ostr << '\''; | ||
987 | serialize_string((*iter).first, ostr); | ||
988 | ostr << "':"; | ||
989 | format_count += format((*iter).second, ostr); | ||
990 | } | ||
991 | ostr << "}"; | ||
992 | break; | ||
993 | } | ||
994 | |||
995 | case LLSD::TypeArray: | ||
996 | { | ||
997 | ostr << "["; | ||
998 | bool need_comma = false; | ||
999 | LLSD::array_const_iterator iter = data.beginArray(); | ||
1000 | LLSD::array_const_iterator end = data.endArray(); | ||
1001 | for(; iter != end; ++iter) | ||
1002 | { | ||
1003 | if(need_comma) ostr << ","; | ||
1004 | need_comma = true; | ||
1005 | format_count += format(*iter, ostr); | ||
1006 | } | ||
1007 | ostr << "]"; | ||
1008 | break; | ||
1009 | } | ||
1010 | |||
1011 | case LLSD::TypeUndefined: | ||
1012 | ostr << "!"; | ||
1013 | break; | ||
1014 | |||
1015 | case LLSD::TypeBoolean: | ||
1016 | if(mBoolAlpha || | ||
1017 | #if( LL_WINDOWS || __GNUC__ > 2) | ||
1018 | (ostr.flags() & std::ios::boolalpha) | ||
1019 | #else | ||
1020 | (ostr.flags() & 0x0100) | ||
1021 | #endif | ||
1022 | ) | ||
1023 | { | ||
1024 | ostr << (data.asBoolean() | ||
1025 | ? NOTATION_TRUE_SERIAL : NOTATION_FALSE_SERIAL); | ||
1026 | } | ||
1027 | else | ||
1028 | { | ||
1029 | ostr << (data.asBoolean() ? 1 : 0); | ||
1030 | } | ||
1031 | break; | ||
1032 | |||
1033 | case LLSD::TypeInteger: | ||
1034 | ostr << "i" << data.asInteger(); | ||
1035 | break; | ||
1036 | |||
1037 | case LLSD::TypeReal: | ||
1038 | ostr << "r"; | ||
1039 | if(mRealFormat.empty()) | ||
1040 | { | ||
1041 | ostr << data.asReal(); | ||
1042 | } | ||
1043 | else | ||
1044 | { | ||
1045 | formatReal(data.asReal(), ostr); | ||
1046 | } | ||
1047 | break; | ||
1048 | |||
1049 | case LLSD::TypeUUID: | ||
1050 | ostr << "u" << data.asUUID(); | ||
1051 | break; | ||
1052 | |||
1053 | case LLSD::TypeString: | ||
1054 | ostr << '\''; | ||
1055 | serialize_string(data.asString(), ostr); | ||
1056 | ostr << '\''; | ||
1057 | break; | ||
1058 | |||
1059 | case LLSD::TypeDate: | ||
1060 | ostr << "d\"" << data.asDate() << "\""; | ||
1061 | break; | ||
1062 | |||
1063 | case LLSD::TypeURI: | ||
1064 | ostr << "l\""; | ||
1065 | serialize_string(data.asString(), ostr); | ||
1066 | ostr << "\""; | ||
1067 | break; | ||
1068 | |||
1069 | case LLSD::TypeBinary: | ||
1070 | { | ||
1071 | // *FIX: memory inefficient. | ||
1072 | std::vector<U8> buffer = data.asBinary(); | ||
1073 | ostr << "b(" << buffer.size() << ")\""; | ||
1074 | if(buffer.size()) ostr.write((const char*)&buffer[0], buffer.size()); | ||
1075 | ostr << "\""; | ||
1076 | break; | ||
1077 | } | ||
1078 | |||
1079 | default: | ||
1080 | // *NOTE: This should never happen. | ||
1081 | ostr << "!"; | ||
1082 | break; | ||
1083 | } | ||
1084 | return format_count; | ||
1085 | } | ||
1086 | |||
1087 | |||
1088 | /** | ||
1089 | * LLSDBinaryFormatter | ||
1090 | */ | ||
1091 | LLSDBinaryFormatter::LLSDBinaryFormatter() | ||
1092 | { | ||
1093 | } | ||
1094 | |||
1095 | // virtual | ||
1096 | LLSDBinaryFormatter::~LLSDBinaryFormatter() | ||
1097 | { } | ||
1098 | |||
1099 | // virtual | ||
1100 | S32 LLSDBinaryFormatter::format(const LLSD& data, std::ostream& ostr, U32 options) const | ||
1101 | { | ||
1102 | S32 format_count = 1; | ||
1103 | switch(data.type()) | ||
1104 | { | ||
1105 | case LLSD::TypeMap: | ||
1106 | { | ||
1107 | ostr.put('{'); | ||
1108 | U32 size_nbo = htonl(data.size()); | ||
1109 | ostr.write((const char*)(&size_nbo), sizeof(U32)); | ||
1110 | LLSD::map_const_iterator iter = data.beginMap(); | ||
1111 | LLSD::map_const_iterator end = data.endMap(); | ||
1112 | for(; iter != end; ++iter) | ||
1113 | { | ||
1114 | ostr.put('k'); | ||
1115 | formatString((*iter).first, ostr); | ||
1116 | format_count += format((*iter).second, ostr); | ||
1117 | } | ||
1118 | ostr.put('}'); | ||
1119 | break; | ||
1120 | } | ||
1121 | |||
1122 | case LLSD::TypeArray: | ||
1123 | { | ||
1124 | ostr.put('['); | ||
1125 | U32 size_nbo = htonl(data.size()); | ||
1126 | ostr.write((const char*)(&size_nbo), sizeof(U32)); | ||
1127 | LLSD::array_const_iterator iter = data.beginArray(); | ||
1128 | LLSD::array_const_iterator end = data.endArray(); | ||
1129 | for(; iter != end; ++iter) | ||
1130 | { | ||
1131 | format_count += format(*iter, ostr); | ||
1132 | } | ||
1133 | ostr.put(']'); | ||
1134 | break; | ||
1135 | } | ||
1136 | |||
1137 | case LLSD::TypeUndefined: | ||
1138 | ostr.put('!'); | ||
1139 | break; | ||
1140 | |||
1141 | case LLSD::TypeBoolean: | ||
1142 | if(data.asBoolean()) ostr.put(BINARY_TRUE_SERIAL); | ||
1143 | else ostr.put(BINARY_FALSE_SERIAL); | ||
1144 | break; | ||
1145 | |||
1146 | case LLSD::TypeInteger: | ||
1147 | { | ||
1148 | ostr.put('i'); | ||
1149 | U32 value_nbo = htonl(data.asInteger()); | ||
1150 | ostr.write((const char*)(&value_nbo), sizeof(U32)); | ||
1151 | break; | ||
1152 | } | ||
1153 | |||
1154 | case LLSD::TypeReal: | ||
1155 | { | ||
1156 | ostr.put('r'); | ||
1157 | F64 value_nbo = ll_htond(data.asReal()); | ||
1158 | ostr.write((const char*)(&value_nbo), sizeof(F64)); | ||
1159 | break; | ||
1160 | } | ||
1161 | |||
1162 | case LLSD::TypeUUID: | ||
1163 | ostr.put('u'); | ||
1164 | ostr.write((const char*)(&(data.asUUID().mData)), UUID_BYTES); | ||
1165 | break; | ||
1166 | |||
1167 | case LLSD::TypeString: | ||
1168 | ostr.put('s'); | ||
1169 | formatString(data.asString(), ostr); | ||
1170 | break; | ||
1171 | |||
1172 | case LLSD::TypeDate: | ||
1173 | { | ||
1174 | ostr.put('d'); | ||
1175 | F64 value = data.asReal(); | ||
1176 | ostr.write((const char*)(&value), sizeof(F64)); | ||
1177 | break; | ||
1178 | } | ||
1179 | |||
1180 | case LLSD::TypeURI: | ||
1181 | ostr.put('l'); | ||
1182 | formatString(data.asString(), ostr); | ||
1183 | break; | ||
1184 | |||
1185 | case LLSD::TypeBinary: | ||
1186 | { | ||
1187 | // *FIX: memory inefficient. | ||
1188 | ostr.put('b'); | ||
1189 | std::vector<U8> buffer = data.asBinary(); | ||
1190 | U32 size_nbo = htonl(buffer.size()); | ||
1191 | ostr.write((const char*)(&size_nbo), sizeof(U32)); | ||
1192 | if(buffer.size()) ostr.write((const char*)&buffer[0], buffer.size()); | ||
1193 | break; | ||
1194 | } | ||
1195 | |||
1196 | default: | ||
1197 | // *NOTE: This should never happen. | ||
1198 | ostr.put('!'); | ||
1199 | break; | ||
1200 | } | ||
1201 | return format_count; | ||
1202 | } | ||
1203 | |||
1204 | void LLSDBinaryFormatter::formatString( | ||
1205 | const std::string& string, | ||
1206 | std::ostream& ostr) const | ||
1207 | { | ||
1208 | U32 size_nbo = htonl(string.size()); | ||
1209 | ostr.write((const char*)(&size_nbo), sizeof(U32)); | ||
1210 | ostr.write(string.c_str(), string.size()); | ||
1211 | } | ||
1212 | |||
1213 | /** | ||
1214 | * local functions | ||
1215 | */ | ||
1216 | bool deserialize_string(std::istream& str, std::string& value) | ||
1217 | { | ||
1218 | char c = str.get(); | ||
1219 | if (str.fail()) | ||
1220 | { | ||
1221 | // No data in stream, bail out | ||
1222 | return false; | ||
1223 | } | ||
1224 | |||
1225 | bool rv = false; | ||
1226 | switch(c) | ||
1227 | { | ||
1228 | case '\'': | ||
1229 | case '"': | ||
1230 | rv = deserialize_string_delim(str, value, c); | ||
1231 | break; | ||
1232 | case 's': | ||
1233 | rv = deserialize_string_raw(str, value); | ||
1234 | break; | ||
1235 | default: | ||
1236 | break; | ||
1237 | } | ||
1238 | return rv; | ||
1239 | } | ||
1240 | |||
1241 | bool deserialize_string_delim( | ||
1242 | std::istream& str, | ||
1243 | std::string& value, | ||
1244 | char delim) | ||
1245 | { | ||
1246 | std::ostringstream write_buffer; | ||
1247 | bool found_escape = false; | ||
1248 | bool found_hex = false; | ||
1249 | bool found_digit = false; | ||
1250 | U8 byte = 0; | ||
1251 | |||
1252 | while (true) | ||
1253 | { | ||
1254 | char next_char = str.get(); | ||
1255 | |||
1256 | if(str.fail()) | ||
1257 | { | ||
1258 | // If our stream is empty, break out | ||
1259 | value = write_buffer.str(); | ||
1260 | return false; | ||
1261 | } | ||
1262 | |||
1263 | if(found_escape) | ||
1264 | { | ||
1265 | // next character(s) is a special sequence. | ||
1266 | if(found_hex) | ||
1267 | { | ||
1268 | if(found_digit) | ||
1269 | { | ||
1270 | found_digit = false; | ||
1271 | found_hex = false; | ||
1272 | found_escape = false; | ||
1273 | byte = byte << 4; | ||
1274 | byte |= hex_as_nybble(next_char); | ||
1275 | write_buffer << byte; | ||
1276 | byte = 0; | ||
1277 | } | ||
1278 | else | ||
1279 | { | ||
1280 | // next character is the first nybble of | ||
1281 | // | ||
1282 | found_digit = true; | ||
1283 | byte = hex_as_nybble(next_char); | ||
1284 | } | ||
1285 | } | ||
1286 | else if(next_char == 'x') | ||
1287 | { | ||
1288 | found_hex = true; | ||
1289 | } | ||
1290 | else | ||
1291 | { | ||
1292 | switch(next_char) | ||
1293 | { | ||
1294 | case 'a': | ||
1295 | write_buffer << '\a'; | ||
1296 | break; | ||
1297 | case 'b': | ||
1298 | write_buffer << '\b'; | ||
1299 | break; | ||
1300 | case 'f': | ||
1301 | write_buffer << '\f'; | ||
1302 | break; | ||
1303 | case 'n': | ||
1304 | write_buffer << '\n'; | ||
1305 | break; | ||
1306 | case 'r': | ||
1307 | write_buffer << '\r'; | ||
1308 | break; | ||
1309 | case 't': | ||
1310 | write_buffer << '\t'; | ||
1311 | break; | ||
1312 | case 'v': | ||
1313 | write_buffer << '\v'; | ||
1314 | break; | ||
1315 | default: | ||
1316 | write_buffer << next_char; | ||
1317 | break; | ||
1318 | } | ||
1319 | found_escape = false; | ||
1320 | } | ||
1321 | } | ||
1322 | else if(next_char == '\\') | ||
1323 | { | ||
1324 | found_escape = true; | ||
1325 | } | ||
1326 | else if(next_char == delim) | ||
1327 | { | ||
1328 | break; | ||
1329 | } | ||
1330 | else | ||
1331 | { | ||
1332 | write_buffer << next_char; | ||
1333 | } | ||
1334 | } | ||
1335 | |||
1336 | value = write_buffer.str(); | ||
1337 | return true; | ||
1338 | } | ||
1339 | |||
1340 | bool deserialize_string_raw(std::istream& str, std::string& value) | ||
1341 | { | ||
1342 | bool ok = false; | ||
1343 | const S32 BUF_LEN = 20; | ||
1344 | char buf[BUF_LEN]; /* Flawfinder: ignore */ | ||
1345 | str.get(buf, BUF_LEN - 1, ')'); | ||
1346 | char c = str.get(); | ||
1347 | c = str.get(); | ||
1348 | if(((c == '"') || (c == '\'')) && (buf[0] == '(')) | ||
1349 | { | ||
1350 | // We probably have a valid raw string. determine | ||
1351 | // the size, and read it. | ||
1352 | // *FIX: Should we set a maximum size? | ||
1353 | // *FIX: This is memory inefficient. | ||
1354 | S32 len = strtol(buf + 1, NULL, 0); | ||
1355 | std::vector<char> buf; | ||
1356 | buf.resize(len); | ||
1357 | str.read(&buf[0], len); /*Flawfinder: ignore*/ | ||
1358 | value.assign(buf.begin(), buf.end()); | ||
1359 | c = str.get(); | ||
1360 | if((c == '"') || (c == '\'')) | ||
1361 | { | ||
1362 | ok = true; | ||
1363 | } | ||
1364 | } | ||
1365 | return ok; | ||
1366 | } | ||
1367 | |||
1368 | static const char* NOTATION_STRING_CHARACTERS[256] = | ||
1369 | { | ||
1370 | "\\x00", // 0 | ||
1371 | "\\x01", // 1 | ||
1372 | "\\x02", // 2 | ||
1373 | "\\x03", // 3 | ||
1374 | "\\x04", // 4 | ||
1375 | "\\x05", // 5 | ||
1376 | "\\x06", // 6 | ||
1377 | "\\a", // 7 | ||
1378 | "\\b", // 8 | ||
1379 | "\\t", // 9 | ||
1380 | "\\n", // 10 | ||
1381 | "\\v", // 11 | ||
1382 | "\\f", // 12 | ||
1383 | "\\r", // 13 | ||
1384 | "\\x0e", // 14 | ||
1385 | "\\x0f", // 15 | ||
1386 | "\\x10", // 16 | ||
1387 | "\\x11", // 17 | ||
1388 | "\\x12", // 18 | ||
1389 | "\\x13", // 19 | ||
1390 | "\\x14", // 20 | ||
1391 | "\\x15", // 21 | ||
1392 | "\\x16", // 22 | ||
1393 | "\\x17", // 23 | ||
1394 | "\\x18", // 24 | ||
1395 | "\\x19", // 25 | ||
1396 | "\\x1a", // 26 | ||
1397 | "\\x1b", // 27 | ||
1398 | "\\x1c", // 28 | ||
1399 | "\\x1d", // 29 | ||
1400 | "\\x1e", // 30 | ||
1401 | "\\x1f", // 31 | ||
1402 | " ", // 32 | ||
1403 | "!", // 33 | ||
1404 | "\"", // 34 | ||
1405 | "#", // 35 | ||
1406 | "$", // 36 | ||
1407 | "%", // 37 | ||
1408 | "&", // 38 | ||
1409 | "\\'", // 39 | ||
1410 | "(", // 40 | ||
1411 | ")", // 41 | ||
1412 | "*", // 42 | ||
1413 | "+", // 43 | ||
1414 | ",", // 44 | ||
1415 | "-", // 45 | ||
1416 | ".", // 46 | ||
1417 | "/", // 47 | ||
1418 | "0", // 48 | ||
1419 | "1", // 49 | ||
1420 | "2", // 50 | ||
1421 | "3", // 51 | ||
1422 | "4", // 52 | ||
1423 | "5", // 53 | ||
1424 | "6", // 54 | ||
1425 | "7", // 55 | ||
1426 | "8", // 56 | ||
1427 | "9", // 57 | ||
1428 | ":", // 58 | ||
1429 | ";", // 59 | ||
1430 | "<", // 60 | ||
1431 | "=", // 61 | ||
1432 | ">", // 62 | ||
1433 | "?", // 63 | ||
1434 | "@", // 64 | ||
1435 | "A", // 65 | ||
1436 | "B", // 66 | ||
1437 | "C", // 67 | ||
1438 | "D", // 68 | ||
1439 | "E", // 69 | ||
1440 | "F", // 70 | ||
1441 | "G", // 71 | ||
1442 | "H", // 72 | ||
1443 | "I", // 73 | ||
1444 | "J", // 74 | ||
1445 | "K", // 75 | ||
1446 | "L", // 76 | ||
1447 | "M", // 77 | ||
1448 | "N", // 78 | ||
1449 | "O", // 79 | ||
1450 | "P", // 80 | ||
1451 | "Q", // 81 | ||
1452 | "R", // 82 | ||
1453 | "S", // 83 | ||
1454 | "T", // 84 | ||
1455 | "U", // 85 | ||
1456 | "V", // 86 | ||
1457 | "W", // 87 | ||
1458 | "X", // 88 | ||
1459 | "Y", // 89 | ||
1460 | "Z", // 90 | ||
1461 | "[", // 91 | ||
1462 | "\\\\", // 92 | ||
1463 | "]", // 93 | ||
1464 | "^", // 94 | ||
1465 | "_", // 95 | ||
1466 | "`", // 96 | ||
1467 | "a", // 97 | ||
1468 | "b", // 98 | ||
1469 | "c", // 99 | ||
1470 | "d", // 100 | ||
1471 | "e", // 101 | ||
1472 | "f", // 102 | ||
1473 | "g", // 103 | ||
1474 | "h", // 104 | ||
1475 | "i", // 105 | ||
1476 | "j", // 106 | ||
1477 | "k", // 107 | ||
1478 | "l", // 108 | ||
1479 | "m", // 109 | ||
1480 | "n", // 110 | ||
1481 | "o", // 111 | ||
1482 | "p", // 112 | ||
1483 | "q", // 113 | ||
1484 | "r", // 114 | ||
1485 | "s", // 115 | ||
1486 | "t", // 116 | ||
1487 | "u", // 117 | ||
1488 | "v", // 118 | ||
1489 | "w", // 119 | ||
1490 | "x", // 120 | ||
1491 | "y", // 121 | ||
1492 | "z", // 122 | ||
1493 | "{", // 123 | ||
1494 | "|", // 124 | ||
1495 | "}", // 125 | ||
1496 | "~", // 126 | ||
1497 | "\\x7f", // 127 | ||
1498 | "\\x80", // 128 | ||
1499 | "\\x81", // 129 | ||
1500 | "\\x82", // 130 | ||
1501 | "\\x83", // 131 | ||
1502 | "\\x84", // 132 | ||
1503 | "\\x85", // 133 | ||
1504 | "\\x86", // 134 | ||
1505 | "\\x87", // 135 | ||
1506 | "\\x88", // 136 | ||
1507 | "\\x89", // 137 | ||
1508 | "\\x8a", // 138 | ||
1509 | "\\x8b", // 139 | ||
1510 | "\\x8c", // 140 | ||
1511 | "\\x8d", // 141 | ||
1512 | "\\x8e", // 142 | ||
1513 | "\\x8f", // 143 | ||
1514 | "\\x90", // 144 | ||
1515 | "\\x91", // 145 | ||
1516 | "\\x92", // 146 | ||
1517 | "\\x93", // 147 | ||
1518 | "\\x94", // 148 | ||
1519 | "\\x95", // 149 | ||
1520 | "\\x96", // 150 | ||
1521 | "\\x97", // 151 | ||
1522 | "\\x98", // 152 | ||
1523 | "\\x99", // 153 | ||
1524 | "\\x9a", // 154 | ||
1525 | "\\x9b", // 155 | ||
1526 | "\\x9c", // 156 | ||
1527 | "\\x9d", // 157 | ||
1528 | "\\x9e", // 158 | ||
1529 | "\\x9f", // 159 | ||
1530 | "\\xa0", // 160 | ||
1531 | "\\xa1", // 161 | ||
1532 | "\\xa2", // 162 | ||
1533 | "\\xa3", // 163 | ||
1534 | "\\xa4", // 164 | ||
1535 | "\\xa5", // 165 | ||
1536 | "\\xa6", // 166 | ||
1537 | "\\xa7", // 167 | ||
1538 | "\\xa8", // 168 | ||
1539 | "\\xa9", // 169 | ||
1540 | "\\xaa", // 170 | ||
1541 | "\\xab", // 171 | ||
1542 | "\\xac", // 172 | ||
1543 | "\\xad", // 173 | ||
1544 | "\\xae", // 174 | ||
1545 | "\\xaf", // 175 | ||
1546 | "\\xb0", // 176 | ||
1547 | "\\xb1", // 177 | ||
1548 | "\\xb2", // 178 | ||
1549 | "\\xb3", // 179 | ||
1550 | "\\xb4", // 180 | ||
1551 | "\\xb5", // 181 | ||
1552 | "\\xb6", // 182 | ||
1553 | "\\xb7", // 183 | ||
1554 | "\\xb8", // 184 | ||
1555 | "\\xb9", // 185 | ||
1556 | "\\xba", // 186 | ||
1557 | "\\xbb", // 187 | ||
1558 | "\\xbc", // 188 | ||
1559 | "\\xbd", // 189 | ||
1560 | "\\xbe", // 190 | ||
1561 | "\\xbf", // 191 | ||
1562 | "\\xc0", // 192 | ||
1563 | "\\xc1", // 193 | ||
1564 | "\\xc2", // 194 | ||
1565 | "\\xc3", // 195 | ||
1566 | "\\xc4", // 196 | ||
1567 | "\\xc5", // 197 | ||
1568 | "\\xc6", // 198 | ||
1569 | "\\xc7", // 199 | ||
1570 | "\\xc8", // 200 | ||
1571 | "\\xc9", // 201 | ||
1572 | "\\xca", // 202 | ||
1573 | "\\xcb", // 203 | ||
1574 | "\\xcc", // 204 | ||
1575 | "\\xcd", // 205 | ||
1576 | "\\xce", // 206 | ||
1577 | "\\xcf", // 207 | ||
1578 | "\\xd0", // 208 | ||
1579 | "\\xd1", // 209 | ||
1580 | "\\xd2", // 210 | ||
1581 | "\\xd3", // 211 | ||
1582 | "\\xd4", // 212 | ||
1583 | "\\xd5", // 213 | ||
1584 | "\\xd6", // 214 | ||
1585 | "\\xd7", // 215 | ||
1586 | "\\xd8", // 216 | ||
1587 | "\\xd9", // 217 | ||
1588 | "\\xda", // 218 | ||
1589 | "\\xdb", // 219 | ||
1590 | "\\xdc", // 220 | ||
1591 | "\\xdd", // 221 | ||
1592 | "\\xde", // 222 | ||
1593 | "\\xdf", // 223 | ||
1594 | "\\xe0", // 224 | ||
1595 | "\\xe1", // 225 | ||
1596 | "\\xe2", // 226 | ||
1597 | "\\xe3", // 227 | ||
1598 | "\\xe4", // 228 | ||
1599 | "\\xe5", // 229 | ||
1600 | "\\xe6", // 230 | ||
1601 | "\\xe7", // 231 | ||
1602 | "\\xe8", // 232 | ||
1603 | "\\xe9", // 233 | ||
1604 | "\\xea", // 234 | ||
1605 | "\\xeb", // 235 | ||
1606 | "\\xec", // 236 | ||
1607 | "\\xed", // 237 | ||
1608 | "\\xee", // 238 | ||
1609 | "\\xef", // 239 | ||
1610 | "\\xf0", // 240 | ||
1611 | "\\xf1", // 241 | ||
1612 | "\\xf2", // 242 | ||
1613 | "\\xf3", // 243 | ||
1614 | "\\xf4", // 244 | ||
1615 | "\\xf5", // 245 | ||
1616 | "\\xf6", // 246 | ||
1617 | "\\xf7", // 247 | ||
1618 | "\\xf8", // 248 | ||
1619 | "\\xf9", // 249 | ||
1620 | "\\xfa", // 250 | ||
1621 | "\\xfb", // 251 | ||
1622 | "\\xfc", // 252 | ||
1623 | "\\xfd", // 253 | ||
1624 | "\\xfe", // 254 | ||
1625 | "\\xff" // 255 | ||
1626 | }; | ||
1627 | |||
1628 | void serialize_string(const std::string& value, std::ostream& str) | ||
1629 | { | ||
1630 | std::string::const_iterator it = value.begin(); | ||
1631 | std::string::const_iterator end = value.end(); | ||
1632 | U8 c; | ||
1633 | for(; it != end; ++it) | ||
1634 | { | ||
1635 | c = (U8)(*it); | ||
1636 | str << NOTATION_STRING_CHARACTERS[c]; | ||
1637 | } | ||
1638 | } | ||
1639 | |||
1640 | |||