aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llcommon/llsdserialize_xml.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'linden/indra/llcommon/llsdserialize_xml.cpp')
-rw-r--r--linden/indra/llcommon/llsdserialize_xml.cpp726
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
36extern "C"
37{
38#include "expat/expat.h"
39}
40
41/**
42 * LLSDXMLFormatter
43 */
44LLSDXMLFormatter::LLSDXMLFormatter()
45{
46}
47
48// virtual
49LLSDXMLFormatter::~LLSDXMLFormatter()
50{
51}
52
53// virtual
54S32 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
71S32 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
215std::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 << "&lt;";
226 break;
227 case '>':
228 out << "&gt;";
229 break;
230 case '&':
231 out << "&amp;";
232 break;
233 case '\'':
234 out << "&apos;";
235 break;
236 case '"':
237 out << "&quot;";
238 break;
239 default:
240 out << (*it);
241 break;
242 }
243 }
244 return out.str();
245}
246
247
248
249class LLSDXMLParser::Impl
250{
251public:
252 Impl();
253 ~Impl();
254
255 LLSD parse(std::istream& input);
256
257 void parsePart(const char *buf, int len);
258
259private:
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
317LLSDXMLParser::Impl::Impl()
318{
319 mParser = XML_ParserCreate(NULL);
320 mPreStaged = false;
321 reset();
322}
323
324LLSDXMLParser::Impl::~Impl()
325{
326 XML_ParserFree(mParser);
327}
328
329bool is_eol(char c)
330{
331 return (c == '\n' || c == '\r');
332}
333
334void 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
344static 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
357LLSD 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
408void 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
441void LLSDXMLParser::Impl::startSkipping()
442{
443 mSkipping = true;
444 mSkipThrough = mDepth;
445}
446
447const XML_Char*
448LLSDXMLParser::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
461void 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
473void 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
559void 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
656void LLSDXMLParser::Impl::characterDataHandler(const XML_Char* data, int length)
657{
658 mCurrentContent.write(data, length);
659}
660
661
662void LLSDXMLParser::Impl::sStartElementHandler(
663 void* userData, const XML_Char* name, const XML_Char** attributes)
664{
665 ((LLSDXMLParser::Impl*)userData)->startElementHandler(name, attributes);
666}
667
668void LLSDXMLParser::Impl::sEndElementHandler(
669 void* userData, const XML_Char* name)
670{
671 ((LLSDXMLParser::Impl*)userData)->endElementHandler(name);
672}
673
674void LLSDXMLParser::Impl::sCharacterDataHandler(
675 void* userData, const XML_Char* data, int length)
676{
677 ((LLSDXMLParser::Impl*)userData)->characterDataHandler(data, length);
678}
679
680
681LLSDXMLParser::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
706LLSDXMLParser::LLSDXMLParser()
707 : impl(* new Impl)
708{
709}
710
711LLSDXMLParser::~LLSDXMLParser()
712{
713 delete &impl;
714}
715
716void LLSDXMLParser::parsePart(const char *buf, int len)
717{
718 impl.parsePart(buf, len);
719}
720
721// virtual
722S32 LLSDXMLParser::parse(std::istream& input, LLSD& data) const
723{
724 data = impl.parse(input);
725 return 0;
726}