diff options
Diffstat (limited to 'linden/indra/llcommon/llsdserialize_xml.cpp')
-rw-r--r-- | linden/indra/llcommon/llsdserialize_xml.cpp | 726 |
1 files changed, 726 insertions, 0 deletions
diff --git a/linden/indra/llcommon/llsdserialize_xml.cpp b/linden/indra/llcommon/llsdserialize_xml.cpp new file mode 100644 index 0000000..892f454 --- /dev/null +++ b/linden/indra/llcommon/llsdserialize_xml.cpp | |||
@@ -0,0 +1,726 @@ | |||
1 | /** | ||
2 | * @file llsdserialize_xml.cpp | ||
3 | * @brief XML parsers and formatters for LLSD | ||
4 | * | ||
5 | * Copyright (c) 2006-2007, Linden Research, Inc. | ||
6 | * | ||
7 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
8 | * to you under the terms of the GNU General Public License, version 2.0 | ||
9 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
10 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
11 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
12 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
13 | * | ||
14 | * There are special exceptions to the terms and conditions of the GPL as | ||
15 | * it is applied to this Source Code. View the full text of the exception | ||
16 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
17 | * online at http://secondlife.com/developers/opensource/flossexception | ||
18 | * | ||
19 | * By copying, modifying or distributing this software, you acknowledge | ||
20 | * that you have read and understood your obligations described above, | ||
21 | * and agree to abide by those obligations. | ||
22 | * | ||
23 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
24 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
25 | * COMPLETENESS OR PERFORMANCE. | ||
26 | */ | ||
27 | |||
28 | #include "linden_common.h" | ||
29 | #include "llsdserialize_xml.h" | ||
30 | |||
31 | #include <iostream> | ||
32 | #include <deque> | ||
33 | |||
34 | #include "apr-1/apr_base64.h" | ||
35 | |||
36 | extern "C" | ||
37 | { | ||
38 | #include "expat/expat.h" | ||
39 | } | ||
40 | |||
41 | /** | ||
42 | * LLSDXMLFormatter | ||
43 | */ | ||
44 | LLSDXMLFormatter::LLSDXMLFormatter() | ||
45 | { | ||
46 | } | ||
47 | |||
48 | // virtual | ||
49 | LLSDXMLFormatter::~LLSDXMLFormatter() | ||
50 | { | ||
51 | } | ||
52 | |||
53 | // virtual | ||
54 | S32 LLSDXMLFormatter::format(const LLSD& data, std::ostream& ostr, U32 options) const | ||
55 | { | ||
56 | std::streamsize old_precision = ostr.precision(25); | ||
57 | |||
58 | LLString post = ""; | ||
59 | if (options & LLSDFormatter::OPTIONS_PRETTY) | ||
60 | { | ||
61 | post = "\n"; | ||
62 | } | ||
63 | ostr << "<llsd>" << post; | ||
64 | S32 rv = format_impl(data, ostr, options, 1); | ||
65 | ostr << "</llsd>\n"; | ||
66 | |||
67 | ostr.precision(old_precision); | ||
68 | return rv; | ||
69 | } | ||
70 | |||
71 | S32 LLSDXMLFormatter::format_impl(const LLSD& data, std::ostream& ostr, U32 options, U32 level) const | ||
72 | { | ||
73 | S32 format_count = 1; | ||
74 | LLString pre = ""; | ||
75 | LLString post = ""; | ||
76 | |||
77 | if (options & LLSDFormatter::OPTIONS_PRETTY) | ||
78 | { | ||
79 | for (U32 i = 0; i < level; i++) | ||
80 | { | ||
81 | pre += " "; | ||
82 | } | ||
83 | post = "\n"; | ||
84 | } | ||
85 | |||
86 | switch(data.type()) | ||
87 | { | ||
88 | case LLSD::TypeMap: | ||
89 | if(0 == data.size()) | ||
90 | { | ||
91 | ostr << pre << "<map />" << post; | ||
92 | } | ||
93 | else | ||
94 | { | ||
95 | ostr << pre << "<map>" << post; | ||
96 | LLSD::map_const_iterator iter = data.beginMap(); | ||
97 | LLSD::map_const_iterator end = data.endMap(); | ||
98 | for(; iter != end; ++iter) | ||
99 | { | ||
100 | ostr << pre << "<key>" << escapeString((*iter).first) << "</key>" << post; | ||
101 | format_count += format_impl((*iter).second, ostr, options, level + 1); | ||
102 | } | ||
103 | ostr << pre << "</map>" << post; | ||
104 | } | ||
105 | break; | ||
106 | |||
107 | case LLSD::TypeArray: | ||
108 | if(0 == data.size()) | ||
109 | { | ||
110 | ostr << pre << "<array />" << post; | ||
111 | } | ||
112 | else | ||
113 | { | ||
114 | ostr << pre << "<array>" << post; | ||
115 | LLSD::array_const_iterator iter = data.beginArray(); | ||
116 | LLSD::array_const_iterator end = data.endArray(); | ||
117 | for(; iter != end; ++iter) | ||
118 | { | ||
119 | format_count += format_impl(*iter, ostr, options, level + 1); | ||
120 | } | ||
121 | ostr << pre << "</array>" << post; | ||
122 | } | ||
123 | break; | ||
124 | |||
125 | case LLSD::TypeUndefined: | ||
126 | ostr << pre << "<undef />" << post; | ||
127 | break; | ||
128 | |||
129 | case LLSD::TypeBoolean: | ||
130 | ostr << pre << "<boolean>"; | ||
131 | if(mBoolAlpha || | ||
132 | #if( LL_WINDOWS || __GNUC__ > 2) | ||
133 | (ostr.flags() & std::ios::boolalpha) | ||
134 | #else | ||
135 | (ostr.flags() & 0x0100) | ||
136 | #endif | ||
137 | ) | ||
138 | { | ||
139 | ostr << (data.asBoolean() ? "true" : "false"); | ||
140 | } | ||
141 | else | ||
142 | { | ||
143 | ostr << (data.asBoolean() ? 1 : 0); | ||
144 | } | ||
145 | ostr << "</boolean>" << post; | ||
146 | break; | ||
147 | |||
148 | case LLSD::TypeInteger: | ||
149 | ostr << pre << "<integer>" << data.asInteger() << "</integer>" << post; | ||
150 | break; | ||
151 | |||
152 | case LLSD::TypeReal: | ||
153 | ostr << pre << "<real>"; | ||
154 | if(mRealFormat.empty()) | ||
155 | { | ||
156 | ostr << data.asReal(); | ||
157 | } | ||
158 | else | ||
159 | { | ||
160 | formatReal(data.asReal(), ostr); | ||
161 | } | ||
162 | ostr << "</real>" << post; | ||
163 | break; | ||
164 | |||
165 | case LLSD::TypeUUID: | ||
166 | if(data.asUUID().isNull()) ostr << pre << "<uuid />" << post; | ||
167 | else ostr << pre << "<uuid>" << data.asUUID() << "</uuid>" << post; | ||
168 | break; | ||
169 | |||
170 | case LLSD::TypeString: | ||
171 | if(data.asString().empty()) ostr << pre << "<string />" << post; | ||
172 | else ostr << pre << "<string>" << escapeString(data.asString()) <<"</string>" << post; | ||
173 | break; | ||
174 | |||
175 | case LLSD::TypeDate: | ||
176 | ostr << pre << "<date>" << data.asDate() << "</date>" << post; | ||
177 | break; | ||
178 | |||
179 | case LLSD::TypeURI: | ||
180 | ostr << pre << "<uri>" << escapeString(data.asString()) << "</uri>" << post; | ||
181 | break; | ||
182 | |||
183 | case LLSD::TypeBinary: | ||
184 | { | ||
185 | LLSD::Binary buffer = data.asBinary(); | ||
186 | if(buffer.empty()) | ||
187 | { | ||
188 | ostr << pre << "<binary />" << post; | ||
189 | } | ||
190 | else | ||
191 | { | ||
192 | // *FIX: memory inefficient. | ||
193 | ostr << pre << "<binary encoding=\"base64\">"; | ||
194 | int b64_buffer_length = apr_base64_encode_len(buffer.size()); | ||
195 | char* b64_buffer = new char[b64_buffer_length]; | ||
196 | b64_buffer_length = apr_base64_encode_binary( | ||
197 | b64_buffer, | ||
198 | &buffer[0], | ||
199 | buffer.size()); | ||
200 | ostr.write(b64_buffer, b64_buffer_length - 1); | ||
201 | delete[] b64_buffer; | ||
202 | ostr << "</binary>" << post; | ||
203 | } | ||
204 | break; | ||
205 | } | ||
206 | default: | ||
207 | // *NOTE: This should never happen. | ||
208 | ostr << pre << "<undef />" << post; | ||
209 | break; | ||
210 | } | ||
211 | return format_count; | ||
212 | } | ||
213 | |||
214 | // static | ||
215 | std::string LLSDXMLFormatter::escapeString(const std::string& in) | ||
216 | { | ||
217 | std::ostringstream out; | ||
218 | std::string::const_iterator it = in.begin(); | ||
219 | std::string::const_iterator end = in.end(); | ||
220 | for(; it != end; ++it) | ||
221 | { | ||
222 | switch((*it)) | ||
223 | { | ||
224 | case '<': | ||
225 | out << "<"; | ||
226 | break; | ||
227 | case '>': | ||
228 | out << ">"; | ||
229 | break; | ||
230 | case '&': | ||
231 | out << "&"; | ||
232 | break; | ||
233 | case '\'': | ||
234 | out << "'"; | ||
235 | break; | ||
236 | case '"': | ||
237 | out << """; | ||
238 | break; | ||
239 | default: | ||
240 | out << (*it); | ||
241 | break; | ||
242 | } | ||
243 | } | ||
244 | return out.str(); | ||
245 | } | ||
246 | |||
247 | |||
248 | |||
249 | class LLSDXMLParser::Impl | ||
250 | { | ||
251 | public: | ||
252 | Impl(); | ||
253 | ~Impl(); | ||
254 | |||
255 | LLSD parse(std::istream& input); | ||
256 | |||
257 | void parsePart(const char *buf, int len); | ||
258 | |||
259 | private: | ||
260 | void reset(); | ||
261 | |||
262 | void startElementHandler(const XML_Char* name, const XML_Char** attributes); | ||
263 | void endElementHandler(const XML_Char* name); | ||
264 | void characterDataHandler(const XML_Char* data, int length); | ||
265 | |||
266 | static void sStartElementHandler( | ||
267 | void* userData, const XML_Char* name, const XML_Char** attributes); | ||
268 | static void sEndElementHandler( | ||
269 | void* userData, const XML_Char* name); | ||
270 | static void sCharacterDataHandler( | ||
271 | void* userData, const XML_Char* data, int length); | ||
272 | |||
273 | void startSkipping(); | ||
274 | |||
275 | enum Element { | ||
276 | ELEMENT_LLSD, | ||
277 | ELEMENT_UNDEF, | ||
278 | ELEMENT_BOOL, | ||
279 | ELEMENT_INTEGER, | ||
280 | ELEMENT_REAL, | ||
281 | ELEMENT_STRING, | ||
282 | ELEMENT_UUID, | ||
283 | ELEMENT_DATE, | ||
284 | ELEMENT_URI, | ||
285 | ELEMENT_BINARY, | ||
286 | ELEMENT_MAP, | ||
287 | ELEMENT_ARRAY, | ||
288 | ELEMENT_KEY, | ||
289 | ELEMENT_UNKNOWN | ||
290 | }; | ||
291 | static Element readElement(const XML_Char* name); | ||
292 | |||
293 | static const XML_Char* findAttribute(const XML_Char* name, const XML_Char** pairs); | ||
294 | |||
295 | |||
296 | XML_Parser mParser; | ||
297 | |||
298 | LLSD mResult; | ||
299 | |||
300 | bool mInLLSDElement; | ||
301 | bool mGracefullStop; | ||
302 | |||
303 | typedef std::deque<LLSD*> LLSDRefStack; | ||
304 | LLSDRefStack mStack; | ||
305 | |||
306 | int mDepth; | ||
307 | bool mSkipping; | ||
308 | int mSkipThrough; | ||
309 | |||
310 | std::string mCurrentKey; | ||
311 | std::ostringstream mCurrentContent; | ||
312 | |||
313 | bool mPreStaged; | ||
314 | }; | ||
315 | |||
316 | |||
317 | LLSDXMLParser::Impl::Impl() | ||
318 | { | ||
319 | mParser = XML_ParserCreate(NULL); | ||
320 | mPreStaged = false; | ||
321 | reset(); | ||
322 | } | ||
323 | |||
324 | LLSDXMLParser::Impl::~Impl() | ||
325 | { | ||
326 | XML_ParserFree(mParser); | ||
327 | } | ||
328 | |||
329 | bool is_eol(char c) | ||
330 | { | ||
331 | return (c == '\n' || c == '\r'); | ||
332 | } | ||
333 | |||
334 | void clear_eol(std::istream& input) | ||
335 | { | ||
336 | char c = input.peek(); | ||
337 | while (input.good() && is_eol(c)) | ||
338 | { | ||
339 | input.get(c); | ||
340 | c = input.peek(); | ||
341 | } | ||
342 | } | ||
343 | |||
344 | static unsigned get_till_eol(std::istream& input, char *buf, unsigned bufsize) | ||
345 | { | ||
346 | unsigned count = 0; | ||
347 | while (count < bufsize && input.good()) | ||
348 | { | ||
349 | input.get(buf[count]); | ||
350 | count++; | ||
351 | if (is_eol(buf[count - 1])) | ||
352 | break; | ||
353 | } | ||
354 | return count; | ||
355 | } | ||
356 | |||
357 | LLSD LLSDXMLParser::Impl::parse(std::istream& input) | ||
358 | { | ||
359 | reset(); | ||
360 | XML_Status status; | ||
361 | |||
362 | static const int BUFFER_SIZE = 1024; | ||
363 | void* buffer = NULL; | ||
364 | int count = 0; | ||
365 | while (input.good() && !input.eof()) | ||
366 | { | ||
367 | buffer = XML_GetBuffer(mParser, BUFFER_SIZE); | ||
368 | |||
369 | /* | ||
370 | * If we happened to end our last buffer right at the end of the llsd, but the | ||
371 | * stream is still going we will get a null buffer here. Check for mGracefullStop. | ||
372 | */ | ||
373 | if (!buffer) | ||
374 | { | ||
375 | break; | ||
376 | } | ||
377 | count = get_till_eol(input, (char *)buffer, BUFFER_SIZE); | ||
378 | if (!count) | ||
379 | { | ||
380 | break; | ||
381 | } | ||
382 | status = XML_ParseBuffer(mParser, count, false); | ||
383 | |||
384 | if (status == XML_STATUS_ERROR) | ||
385 | { | ||
386 | break; | ||
387 | } | ||
388 | } | ||
389 | |||
390 | // *FIX.: This code is buggy - if the stream was empty or not | ||
391 | // good, there is not buffer to parse, both the call to | ||
392 | // XML_ParseBuffer and the buffer manipulations are illegal | ||
393 | // futhermore, it isn't clear that the expat buffer semantics are | ||
394 | // preserved | ||
395 | |||
396 | status = XML_ParseBuffer(mParser, 0, true); | ||
397 | if (status == XML_STATUS_ERROR && !mGracefullStop) | ||
398 | { | ||
399 | ((char*) buffer)[count? count - 1 : 0] = '\0'; | ||
400 | llinfos << "LLSDXMLParser::Impl::parse: XML_STATUS_ERROR parsing:" << (char*) buffer << llendl; | ||
401 | return LLSD(); | ||
402 | } | ||
403 | |||
404 | clear_eol(input); | ||
405 | return mResult; | ||
406 | } | ||
407 | |||
408 | void LLSDXMLParser::Impl::reset() | ||
409 | { | ||
410 | if (mPreStaged) | ||
411 | { | ||
412 | mPreStaged = false; | ||
413 | return; | ||
414 | } | ||
415 | |||
416 | mResult.clear(); | ||
417 | |||
418 | mInLLSDElement = false; | ||
419 | mDepth = 0; | ||
420 | |||
421 | mGracefullStop = false; | ||
422 | |||
423 | mStack.clear(); | ||
424 | |||
425 | mSkipping = false; | ||
426 | |||
427 | #if( LL_WINDOWS || __GNUC__ > 2) | ||
428 | mCurrentKey.clear(); | ||
429 | #else | ||
430 | mCurrentKey = std::string(); | ||
431 | #endif | ||
432 | |||
433 | |||
434 | XML_ParserReset(mParser, "utf-8"); | ||
435 | XML_SetUserData(mParser, this); | ||
436 | XML_SetElementHandler(mParser, sStartElementHandler, sEndElementHandler); | ||
437 | XML_SetCharacterDataHandler(mParser, sCharacterDataHandler); | ||
438 | } | ||
439 | |||
440 | |||
441 | void LLSDXMLParser::Impl::startSkipping() | ||
442 | { | ||
443 | mSkipping = true; | ||
444 | mSkipThrough = mDepth; | ||
445 | } | ||
446 | |||
447 | const XML_Char* | ||
448 | LLSDXMLParser::Impl::findAttribute(const XML_Char* name, const XML_Char** pairs) | ||
449 | { | ||
450 | while (NULL != pairs && NULL != *pairs) | ||
451 | { | ||
452 | if(0 == strcmp(name, *pairs)) | ||
453 | { | ||
454 | return *(pairs + 1); | ||
455 | } | ||
456 | pairs += 2; | ||
457 | } | ||
458 | return NULL; | ||
459 | } | ||
460 | |||
461 | void LLSDXMLParser::Impl::parsePart(const char *buf, int len) | ||
462 | { | ||
463 | void * buffer = XML_GetBuffer(mParser, len); | ||
464 | if (buffer != NULL && buf != NULL) | ||
465 | { | ||
466 | memcpy(buffer, buf, len); | ||
467 | } | ||
468 | XML_ParseBuffer(mParser, len, false); | ||
469 | |||
470 | mPreStaged = true; | ||
471 | } | ||
472 | |||
473 | void LLSDXMLParser::Impl::startElementHandler(const XML_Char* name, const XML_Char** attributes) | ||
474 | { | ||
475 | mDepth += 1; | ||
476 | if (mSkipping) | ||
477 | { | ||
478 | return; | ||
479 | } | ||
480 | |||
481 | Element element = readElement(name); | ||
482 | mCurrentContent.str(""); | ||
483 | |||
484 | switch (element) | ||
485 | { | ||
486 | case ELEMENT_LLSD: | ||
487 | if (mInLLSDElement) { return startSkipping(); } | ||
488 | mInLLSDElement = true; | ||
489 | return; | ||
490 | |||
491 | case ELEMENT_KEY: | ||
492 | if (mStack.empty() || !(mStack.back()->isMap())) | ||
493 | { | ||
494 | return startSkipping(); | ||
495 | } | ||
496 | return; | ||
497 | |||
498 | case ELEMENT_BINARY: | ||
499 | { | ||
500 | const XML_Char* encoding = findAttribute("encoding", attributes); | ||
501 | if(encoding && strcmp("base64", encoding) != 0) { return startSkipping(); } | ||
502 | break; | ||
503 | } | ||
504 | |||
505 | default: | ||
506 | // all rest are values, fall through | ||
507 | ; | ||
508 | } | ||
509 | |||
510 | |||
511 | if (!mInLLSDElement) { return startSkipping(); } | ||
512 | |||
513 | if (mStack.empty()) | ||
514 | { | ||
515 | mStack.push_back(&mResult); | ||
516 | } | ||
517 | else if (mStack.back()->isMap()) | ||
518 | { | ||
519 | if (mCurrentKey.empty()) { return startSkipping(); } | ||
520 | |||
521 | LLSD& map = *mStack.back(); | ||
522 | LLSD& newElement = map[mCurrentKey]; | ||
523 | mStack.push_back(&newElement); | ||
524 | |||
525 | #if( LL_WINDOWS || __GNUC__ > 2) | ||
526 | mCurrentKey.clear(); | ||
527 | #else | ||
528 | mCurrentKey = std::string(); | ||
529 | #endif | ||
530 | } | ||
531 | else if (mStack.back()->isArray()) | ||
532 | { | ||
533 | LLSD& array = *mStack.back(); | ||
534 | array.append(LLSD()); | ||
535 | LLSD& newElement = array[array.size()-1]; | ||
536 | mStack.push_back(&newElement); | ||
537 | } | ||
538 | else { | ||
539 | // improperly nested value in a non-structure | ||
540 | return startSkipping(); | ||
541 | } | ||
542 | |||
543 | switch (element) | ||
544 | { | ||
545 | case ELEMENT_MAP: | ||
546 | *mStack.back() = LLSD::emptyMap(); | ||
547 | break; | ||
548 | |||
549 | case ELEMENT_ARRAY: | ||
550 | *mStack.back() = LLSD::emptyArray(); | ||
551 | break; | ||
552 | |||
553 | default: | ||
554 | // all the other values will be set in the end element handler | ||
555 | ; | ||
556 | } | ||
557 | } | ||
558 | |||
559 | void LLSDXMLParser::Impl::endElementHandler(const XML_Char* name) | ||
560 | { | ||
561 | mDepth -= 1; | ||
562 | if (mSkipping) | ||
563 | { | ||
564 | if (mDepth < mSkipThrough) | ||
565 | { | ||
566 | mSkipping = false; | ||
567 | } | ||
568 | return; | ||
569 | } | ||
570 | |||
571 | Element element = readElement(name); | ||
572 | |||
573 | switch (element) | ||
574 | { | ||
575 | case ELEMENT_LLSD: | ||
576 | if (mInLLSDElement) | ||
577 | { | ||
578 | mInLLSDElement = false; | ||
579 | mGracefullStop = true; | ||
580 | XML_StopParser(mParser, false); | ||
581 | } | ||
582 | return; | ||
583 | |||
584 | case ELEMENT_KEY: | ||
585 | mCurrentKey = mCurrentContent.str(); | ||
586 | return; | ||
587 | |||
588 | default: | ||
589 | // all rest are values, fall through | ||
590 | ; | ||
591 | } | ||
592 | |||
593 | if (!mInLLSDElement) { return; } | ||
594 | |||
595 | LLSD& value = *mStack.back(); | ||
596 | mStack.pop_back(); | ||
597 | |||
598 | std::string content = mCurrentContent.str(); | ||
599 | mCurrentContent.str(""); | ||
600 | |||
601 | switch (element) | ||
602 | { | ||
603 | case ELEMENT_UNDEF: | ||
604 | value.clear(); | ||
605 | break; | ||
606 | |||
607 | case ELEMENT_BOOL: | ||
608 | value = content == "true" || content == "1"; | ||
609 | break; | ||
610 | |||
611 | case ELEMENT_INTEGER: | ||
612 | value = LLSD(content).asInteger(); | ||
613 | break; | ||
614 | |||
615 | case ELEMENT_REAL: | ||
616 | value = LLSD(content).asReal(); | ||
617 | break; | ||
618 | |||
619 | case ELEMENT_STRING: | ||
620 | value = content; | ||
621 | break; | ||
622 | |||
623 | case ELEMENT_UUID: | ||
624 | value = LLSD(content).asUUID(); | ||
625 | break; | ||
626 | |||
627 | case ELEMENT_DATE: | ||
628 | value = LLSD(content).asDate(); | ||
629 | break; | ||
630 | |||
631 | case ELEMENT_URI: | ||
632 | value = LLSD(content).asURI(); | ||
633 | break; | ||
634 | |||
635 | case ELEMENT_BINARY: | ||
636 | { | ||
637 | S32 len = apr_base64_decode_len(content.c_str()); | ||
638 | std::vector<U8> data; | ||
639 | data.resize(len); | ||
640 | len = apr_base64_decode_binary(&data[0], content.c_str()); | ||
641 | data.resize(len); | ||
642 | value = data; | ||
643 | break; | ||
644 | } | ||
645 | |||
646 | case ELEMENT_UNKNOWN: | ||
647 | value.clear(); | ||
648 | break; | ||
649 | |||
650 | default: | ||
651 | // other values, map and array, have already been set | ||
652 | break; | ||
653 | } | ||
654 | } | ||
655 | |||
656 | void LLSDXMLParser::Impl::characterDataHandler(const XML_Char* data, int length) | ||
657 | { | ||
658 | mCurrentContent.write(data, length); | ||
659 | } | ||
660 | |||
661 | |||
662 | void LLSDXMLParser::Impl::sStartElementHandler( | ||
663 | void* userData, const XML_Char* name, const XML_Char** attributes) | ||
664 | { | ||
665 | ((LLSDXMLParser::Impl*)userData)->startElementHandler(name, attributes); | ||
666 | } | ||
667 | |||
668 | void LLSDXMLParser::Impl::sEndElementHandler( | ||
669 | void* userData, const XML_Char* name) | ||
670 | { | ||
671 | ((LLSDXMLParser::Impl*)userData)->endElementHandler(name); | ||
672 | } | ||
673 | |||
674 | void LLSDXMLParser::Impl::sCharacterDataHandler( | ||
675 | void* userData, const XML_Char* data, int length) | ||
676 | { | ||
677 | ((LLSDXMLParser::Impl*)userData)->characterDataHandler(data, length); | ||
678 | } | ||
679 | |||
680 | |||
681 | LLSDXMLParser::Impl::Element LLSDXMLParser::Impl::readElement(const XML_Char* name) | ||
682 | { | ||
683 | if (strcmp(name, "llsd") == 0) { return ELEMENT_LLSD; } | ||
684 | if (strcmp(name, "undef") == 0) { return ELEMENT_UNDEF; } | ||
685 | if (strcmp(name, "boolean") == 0) { return ELEMENT_BOOL; } | ||
686 | if (strcmp(name, "integer") == 0) { return ELEMENT_INTEGER; } | ||
687 | if (strcmp(name, "real") == 0) { return ELEMENT_REAL; } | ||
688 | if (strcmp(name, "string") == 0) { return ELEMENT_STRING; } | ||
689 | if (strcmp(name, "uuid") == 0) { return ELEMENT_UUID; } | ||
690 | if (strcmp(name, "date") == 0) { return ELEMENT_DATE; } | ||
691 | if (strcmp(name, "uri") == 0) { return ELEMENT_URI; } | ||
692 | if (strcmp(name, "binary") == 0) { return ELEMENT_BINARY; } | ||
693 | if (strcmp(name, "map") == 0) { return ELEMENT_MAP; } | ||
694 | if (strcmp(name, "array") == 0) { return ELEMENT_ARRAY; } | ||
695 | if (strcmp(name, "key") == 0) { return ELEMENT_KEY; } | ||
696 | |||
697 | return ELEMENT_UNKNOWN; | ||
698 | } | ||
699 | |||
700 | |||
701 | |||
702 | |||
703 | |||
704 | |||
705 | |||
706 | LLSDXMLParser::LLSDXMLParser() | ||
707 | : impl(* new Impl) | ||
708 | { | ||
709 | } | ||
710 | |||
711 | LLSDXMLParser::~LLSDXMLParser() | ||
712 | { | ||
713 | delete &impl; | ||
714 | } | ||
715 | |||
716 | void LLSDXMLParser::parsePart(const char *buf, int len) | ||
717 | { | ||
718 | impl.parsePart(buf, len); | ||
719 | } | ||
720 | |||
721 | // virtual | ||
722 | S32 LLSDXMLParser::parse(std::istream& input, LLSD& data) const | ||
723 | { | ||
724 | data = impl.parse(input); | ||
725 | return 0; | ||
726 | } | ||