PageRenderTime 239ms CodeModel.GetById 149ms app.highlight 83ms RepoModel.GetById 2ms app.codeStats 0ms

/indra/llcommon/llsdserialize_xml.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 934 lines | 877 code | 23 blank | 34 comment | 20 complexity | 898d42fa51f43d4fcb59530c7bf2d29e MD5 | raw file
  1/** 
  2 * @file llsdserialize_xml.cpp
  3 * @brief XML parsers and formatters for LLSD
  4 *
  5 * $LicenseInfo:firstyear=2006&license=viewerlgpl$
  6 * Second Life Viewer Source Code
  7 * Copyright (C) 2010, Linden Research, Inc.
  8 * 
  9 * This library is free software; you can redistribute it and/or
 10 * modify it under the terms of the GNU Lesser General Public
 11 * License as published by the Free Software Foundation;
 12 * version 2.1 of the License only.
 13 * 
 14 * This library is distributed in the hope that it will be useful,
 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 17 * Lesser General Public License for more details.
 18 * 
 19 * You should have received a copy of the GNU Lesser General Public
 20 * License along with this library; if not, write to the Free Software
 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 22 * 
 23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 24 * $/LicenseInfo$
 25 */
 26
 27#include "linden_common.h"
 28#include "llsdserialize_xml.h"
 29
 30#include <iostream>
 31#include <deque>
 32
 33#include "apr_base64.h"
 34#include <boost/regex.hpp>
 35
 36extern "C"
 37{
 38#ifdef LL_STANDALONE
 39# include <expat.h>
 40#else
 41# include "expat/expat.h"
 42#endif
 43}
 44
 45/**
 46 * LLSDXMLFormatter
 47 */
 48LLSDXMLFormatter::LLSDXMLFormatter()
 49{
 50}
 51
 52// virtual
 53LLSDXMLFormatter::~LLSDXMLFormatter()
 54{
 55}
 56
 57// virtual
 58S32 LLSDXMLFormatter::format(const LLSD& data, std::ostream& ostr, U32 options) const
 59{
 60	std::streamsize old_precision = ostr.precision(25);
 61
 62	std::string post;
 63	if (options & LLSDFormatter::OPTIONS_PRETTY)
 64	{
 65		post = "\n";
 66	}
 67	ostr << "<llsd>" << post;
 68	S32 rv = format_impl(data, ostr, options, 1);
 69	ostr << "</llsd>\n";
 70
 71	ostr.precision(old_precision);
 72	return rv;
 73}
 74
 75S32 LLSDXMLFormatter::format_impl(const LLSD& data, std::ostream& ostr, U32 options, U32 level) const
 76{
 77	S32 format_count = 1;
 78	std::string pre;
 79	std::string post;
 80
 81	if (options & LLSDFormatter::OPTIONS_PRETTY)
 82	{
 83		for (U32 i = 0; i < level; i++)
 84		{
 85			pre += "    ";
 86		}
 87		post = "\n";
 88	}
 89
 90	switch(data.type())
 91	{
 92	case LLSD::TypeMap:
 93		if(0 == data.size())
 94		{
 95			ostr << pre << "<map />" << post;
 96		}
 97		else
 98		{
 99			ostr << pre << "<map>" << post;
100			LLSD::map_const_iterator iter = data.beginMap();
101			LLSD::map_const_iterator end = data.endMap();
102			for(; iter != end; ++iter)
103			{
104				ostr << pre << "<key>" << escapeString((*iter).first) << "</key>" << post;
105				format_count += format_impl((*iter).second, ostr, options, level + 1);
106			}
107			ostr << pre <<  "</map>" << post;
108		}
109		break;
110
111	case LLSD::TypeArray:
112		if(0 == data.size())
113		{
114			ostr << pre << "<array />" << post;
115		}
116		else
117		{
118			ostr << pre << "<array>" << post;
119			LLSD::array_const_iterator iter = data.beginArray();
120			LLSD::array_const_iterator end = data.endArray();
121			for(; iter != end; ++iter)
122			{
123				format_count += format_impl(*iter, ostr, options, level + 1);
124			}
125			ostr << pre << "</array>" << post;
126		}
127		break;
128
129	case LLSD::TypeUndefined:
130		ostr << pre << "<undef />" << post;
131		break;
132
133	case LLSD::TypeBoolean:
134		ostr << pre << "<boolean>";
135		if(mBoolAlpha ||
136		   (ostr.flags() & std::ios::boolalpha)
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			// *TODO: convert to use LLBase64
194			ostr << pre << "<binary encoding=\"base64\">";
195			int b64_buffer_length = apr_base64_encode_len(buffer.size());
196			char* b64_buffer = new char[b64_buffer_length];
197			b64_buffer_length = apr_base64_encode_binary(
198				b64_buffer,
199				&buffer[0],
200				buffer.size());
201			ostr.write(b64_buffer, b64_buffer_length - 1);
202			delete[] b64_buffer;
203			ostr << "</binary>" << post;
204		}
205		break;
206	}
207	default:
208		// *NOTE: This should never happen.
209		ostr << pre << "<undef />" << post;
210		break;
211	}
212	return format_count;
213}
214
215// static
216std::string LLSDXMLFormatter::escapeString(const std::string& in)
217{
218	std::ostringstream out;
219	std::string::const_iterator it = in.begin();
220	std::string::const_iterator end = in.end();
221	for(; it != end; ++it)
222	{
223		switch((*it))
224		{
225		case '<':
226			out << "&lt;";
227			break;
228		case '>':
229			out << "&gt;";
230			break;
231		case '&':
232			out << "&amp;";
233			break;
234		case '\'':
235			out << "&apos;";
236			break;
237		case '"':
238			out << "&quot;";
239			break;
240		default:
241			out << (*it);
242			break;
243		}
244	}
245	return out.str();
246}
247
248
249
250class LLSDXMLParser::Impl
251{
252public:
253	Impl();
254	~Impl();
255	
256	S32 parse(std::istream& input, LLSD& data);
257	S32 parseLines(std::istream& input, LLSD& data);
258
259	void parsePart(const char *buf, int len);
260	
261	void reset();
262
263private:
264	void startElementHandler(const XML_Char* name, const XML_Char** attributes);
265	void endElementHandler(const XML_Char* name);
266	void characterDataHandler(const XML_Char* data, int length);
267	
268	static void sStartElementHandler(
269		void* userData, const XML_Char* name, const XML_Char** attributes);
270	static void sEndElementHandler(
271		void* userData, const XML_Char* name);
272	static void sCharacterDataHandler(
273		void* userData, const XML_Char* data, int length);
274
275	void startSkipping();
276	
277	enum Element {
278		ELEMENT_LLSD,
279		ELEMENT_UNDEF,
280		ELEMENT_BOOL,
281		ELEMENT_INTEGER,
282		ELEMENT_REAL,
283		ELEMENT_STRING,
284		ELEMENT_UUID,
285		ELEMENT_DATE,
286		ELEMENT_URI,
287		ELEMENT_BINARY,
288		ELEMENT_MAP,
289		ELEMENT_ARRAY,
290		ELEMENT_KEY,
291		ELEMENT_UNKNOWN
292	};
293	static Element readElement(const XML_Char* name);
294	
295	static const XML_Char* findAttribute(const XML_Char* name, const XML_Char** pairs);
296	
297
298	XML_Parser	mParser;
299
300	LLSD mResult;
301	S32 mParseCount;
302	
303	bool mInLLSDElement;			// true if we're on LLSD
304	bool mGracefullStop;			// true if we found the </llsd
305	
306	typedef std::deque<LLSD*> LLSDRefStack;
307	LLSDRefStack mStack;
308	
309	int mDepth;
310	bool mSkipping;
311	int mSkipThrough;
312	
313	std::string mCurrentKey;		// Current XML <tag>
314	std::string mCurrentContent;	// String data between <tag> and </tag>
315};
316
317
318LLSDXMLParser::Impl::Impl()
319{
320	mParser = XML_ParserCreate(NULL);
321	reset();
322}
323
324LLSDXMLParser::Impl::~Impl()
325{
326	XML_ParserFree(mParser);
327}
328
329inline bool 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		char c = input.get();
350		buf[count++] = c;
351		if (is_eol(c))
352			break;
353	}
354	return count;
355}
356
357S32 LLSDXMLParser::Impl::parse(std::istream& input, LLSD& data)
358{
359	XML_Status status;
360	
361	static const int BUFFER_SIZE = 1024;
362	void* buffer = NULL;	
363	int count = 0;
364	while (input.good() && !input.eof())
365	{
366		buffer = XML_GetBuffer(mParser, BUFFER_SIZE);
367
368		/*
369		 * If we happened to end our last buffer right at the end of the llsd, but the
370		 * stream is still going we will get a null buffer here.  Check for mGracefullStop.
371		 */
372		if (!buffer)
373		{
374			break;
375		}
376		{
377		
378			count = get_till_eol(input, (char *)buffer, BUFFER_SIZE);
379			if (!count)
380			{
381				break;
382			}
383		}
384		status = XML_ParseBuffer(mParser, count, false);
385
386		if (status == XML_STATUS_ERROR)
387		{
388			break;
389		}
390	}
391	
392	// *FIX.: This code is buggy - if the stream was empty or not
393	// good, there is not buffer to parse, both the call to
394	// XML_ParseBuffer and the buffer manipulations are illegal
395	// futhermore, it isn't clear that the expat buffer semantics are
396	// preserved
397
398	status = XML_ParseBuffer(mParser, 0, true);
399	if (status == XML_STATUS_ERROR && !mGracefullStop)
400	{
401		if (buffer)
402		{
403			((char*) buffer)[count ? count - 1 : 0] = '\0';
404		}
405		llinfos << "LLSDXMLParser::Impl::parse: XML_STATUS_ERROR parsing:" << (char*) buffer << llendl;
406		data = LLSD();
407		return LLSDParser::PARSE_FAILURE;
408	}
409
410	clear_eol(input);
411	data = mResult;
412	return mParseCount;
413}
414
415
416S32 LLSDXMLParser::Impl::parseLines(std::istream& input, LLSD& data)
417{
418	XML_Status status = XML_STATUS_OK;
419
420	data = LLSD();
421
422	static const int BUFFER_SIZE = 1024;
423
424	//static char last_buffer[ BUFFER_SIZE ];
425	//std::streamsize last_num_read;
426
427	// Must get rid of any leading \n, otherwise the stream gets into an error/eof state
428	clear_eol(input);
429
430	while( !mGracefullStop
431		&& input.good() 
432		&& !input.eof())
433	{
434		void* buffer = XML_GetBuffer(mParser, BUFFER_SIZE);
435		/*
436		 * If we happened to end our last buffer right at the end of the llsd, but the
437		 * stream is still going we will get a null buffer here.  Check for mGracefullStop.
438		 * -- I don't think this is actually true - zero 2008-05-09
439		 */
440		if (!buffer)
441		{
442			break;
443		}
444		
445		// Get one line
446		input.getline((char*)buffer, BUFFER_SIZE);
447		std::streamsize num_read = input.gcount();
448
449		//memcpy( last_buffer, buffer, num_read );
450		//last_num_read = num_read;
451
452		if ( num_read > 0 )
453		{
454			if (!input.good() )
455			{	// Clear state that's set when we run out of buffer
456				input.clear();
457			}
458		
459			// Re-insert with the \n that was absorbed by getline()
460			char * text = (char *) buffer;
461			if ( text[num_read - 1] == 0)
462			{
463				text[num_read - 1] = '\n';
464			}
465		}
466
467		status = XML_ParseBuffer(mParser, num_read, false);
468		if (status == XML_STATUS_ERROR)
469		{
470			break;
471		}
472	}
473
474	if (status != XML_STATUS_ERROR
475		&& !mGracefullStop)
476	{	// Parse last bit
477		status = XML_ParseBuffer(mParser, 0, true);
478	}
479	
480	if (status == XML_STATUS_ERROR  
481		&& !mGracefullStop)
482	{
483		llinfos << "LLSDXMLParser::Impl::parseLines: XML_STATUS_ERROR" << llendl;
484		return LLSDParser::PARSE_FAILURE;
485	}
486
487	clear_eol(input);
488	data = mResult;
489	return mParseCount;
490}
491
492
493void LLSDXMLParser::Impl::reset()
494{
495	mResult.clear();
496	mParseCount = 0;
497
498	mInLLSDElement = false;
499	mDepth = 0;
500
501	mGracefullStop = false;
502
503	mStack.clear();
504	
505	mSkipping = false;
506	
507	mCurrentKey.clear();
508	
509	XML_ParserReset(mParser, "utf-8");
510	XML_SetUserData(mParser, this);
511	XML_SetElementHandler(mParser, sStartElementHandler, sEndElementHandler);
512	XML_SetCharacterDataHandler(mParser, sCharacterDataHandler);
513}
514
515
516void LLSDXMLParser::Impl::startSkipping()
517{
518	mSkipping = true;
519	mSkipThrough = mDepth;
520}
521
522const XML_Char*
523LLSDXMLParser::Impl::findAttribute(const XML_Char* name, const XML_Char** pairs)
524{
525	while (NULL != pairs && NULL != *pairs)
526	{
527		if(0 == strcmp(name, *pairs))
528		{
529			return *(pairs + 1);
530		}
531		pairs += 2;
532	}
533	return NULL;
534}
535
536void LLSDXMLParser::Impl::parsePart(const char* buf, int len)
537{
538	if ( buf != NULL 
539		&& len > 0 )
540	{
541		XML_Status status = XML_Parse(mParser, buf, len, false);
542		if (status == XML_STATUS_ERROR)
543		{
544			llinfos << "Unexpected XML parsing error at start" << llendl;
545		}
546	}
547}
548
549// Performance testing code
550//#define	XML_PARSER_PERFORMANCE_TESTS
551
552#ifdef XML_PARSER_PERFORMANCE_TESTS
553
554extern U64 totalTime();
555U64	readElementTime = 0;
556U64 startElementTime = 0;
557U64 endElementTime = 0;
558U64 charDataTime = 0;
559U64 parseTime = 0;
560
561class XML_Timer
562{
563public:
564	XML_Timer( U64 * sum ) : mSum( sum )
565	{
566		mStart = totalTime();
567	}
568	~XML_Timer()
569	{
570		*mSum += (totalTime() - mStart);
571	}
572
573	U64 * mSum;
574	U64 mStart;
575};
576#endif // XML_PARSER_PERFORMANCE_TESTS
577
578void LLSDXMLParser::Impl::startElementHandler(const XML_Char* name, const XML_Char** attributes)
579{
580	#ifdef XML_PARSER_PERFORMANCE_TESTS
581	XML_Timer timer( &startElementTime );
582	#endif // XML_PARSER_PERFORMANCE_TESTS
583	
584	++mDepth;
585	if (mSkipping)
586	{
587		return;
588	}
589
590	Element element = readElement(name);
591	
592	mCurrentContent.clear();
593
594	switch (element)
595	{
596		case ELEMENT_LLSD:
597			if (mInLLSDElement) { return startSkipping(); }
598			mInLLSDElement = true;
599			return;
600	
601		case ELEMENT_KEY:
602			if (mStack.empty()  ||  !(mStack.back()->isMap()))
603			{
604				return startSkipping();
605			}
606			return;
607
608		case ELEMENT_BINARY:
609		{
610			const XML_Char* encoding = findAttribute("encoding", attributes);
611			if(encoding && strcmp("base64", encoding) != 0) { return startSkipping(); }
612			break;
613		}
614		
615		default:
616			// all rest are values, fall through
617			;
618	}
619	
620
621	if (!mInLLSDElement) { return startSkipping(); }
622	
623	if (mStack.empty())
624	{
625		mStack.push_back(&mResult);
626	}
627	else if (mStack.back()->isMap())
628	{
629		if (mCurrentKey.empty()) { return startSkipping(); }
630		
631		LLSD& map = *mStack.back();
632		LLSD& newElement = map[mCurrentKey];
633		mStack.push_back(&newElement);		
634
635		mCurrentKey.clear();
636	}
637	else if (mStack.back()->isArray())
638	{
639		LLSD& array = *mStack.back();
640		array.append(LLSD());
641		LLSD& newElement = array[array.size()-1];
642		mStack.push_back(&newElement);
643	}
644	else {
645		// improperly nested value in a non-structure
646		return startSkipping();
647	}
648
649	++mParseCount;
650	switch (element)
651	{
652		case ELEMENT_MAP:
653			*mStack.back() = LLSD::emptyMap();
654			break;
655		
656		case ELEMENT_ARRAY:
657			*mStack.back() = LLSD::emptyArray();
658			break;
659			
660		default:
661			// all the other values will be set in the end element handler
662			;
663	}
664}
665
666void LLSDXMLParser::Impl::endElementHandler(const XML_Char* name)
667{
668	#ifdef XML_PARSER_PERFORMANCE_TESTS
669	XML_Timer timer( &endElementTime );
670	#endif // XML_PARSER_PERFORMANCE_TESTS
671
672	--mDepth;
673	if (mSkipping)
674	{
675		if (mDepth < mSkipThrough)
676		{
677			mSkipping = false;
678		}
679		return;
680	}
681	
682	Element element = readElement(name);
683	
684	switch (element)
685	{
686		case ELEMENT_LLSD:
687			if (mInLLSDElement)
688			{
689				mInLLSDElement = false;
690				mGracefullStop = true;
691				XML_StopParser(mParser, false);
692			}
693			return;
694	
695		case ELEMENT_KEY:
696			mCurrentKey = mCurrentContent;
697			return;
698			
699		default:
700			// all rest are values, fall through
701			;
702	}
703	
704	if (!mInLLSDElement) { return; }
705
706	LLSD& value = *mStack.back();
707	mStack.pop_back();
708	
709	switch (element)
710	{
711		case ELEMENT_UNDEF:
712			value.clear();
713			break;
714		
715		case ELEMENT_BOOL:
716			value = (mCurrentContent == "true" || mCurrentContent == "1");
717			break;
718		
719		case ELEMENT_INTEGER:
720			{
721				S32 i;
722				// sscanf okay here with different locales - ints don't change for different locale settings like floats do.
723				if ( sscanf(mCurrentContent.c_str(), "%d", &i ) == 1 )
724				{	// See if sscanf works - it's faster
725					value = i;
726				}
727				else
728				{
729					value = LLSD(mCurrentContent).asInteger();
730				}
731			}
732			break;
733		
734		case ELEMENT_REAL:
735			{
736				value = LLSD(mCurrentContent).asReal();
737				// removed since this breaks when locale has decimal separator that isn't '.'
738				// investigated changing local to something compatible each time but deemed higher
739				// risk that just using LLSD.asReal() each time.
740				//F64 r;
741				//if ( sscanf(mCurrentContent.c_str(), "%lf", &r ) == 1 )
742				//{	// See if sscanf works - it's faster
743				//	value = r;
744				//}
745				//else
746				//{
747				//	value = LLSD(mCurrentContent).asReal();
748				//}
749			}
750			break;
751		
752		case ELEMENT_STRING:
753			value = mCurrentContent;
754			break;
755		
756		case ELEMENT_UUID:
757			value = LLSD(mCurrentContent).asUUID();
758			break;
759		
760		case ELEMENT_DATE:
761			value = LLSD(mCurrentContent).asDate();
762			break;
763		
764		case ELEMENT_URI:
765			value = LLSD(mCurrentContent).asURI();
766			break;
767		
768		case ELEMENT_BINARY:
769		{
770			// Regex is expensive, but only fix for whitespace in base64,
771			// created by python and other non-linden systems - DEV-39358
772			// Fortunately we have very little binary passing now,
773			// so performance impact shold be negligible. + poppy 2009-09-04
774			boost::regex r;
775			r.assign("\\s");
776			std::string stripped = boost::regex_replace(mCurrentContent, r, "");
777			S32 len = apr_base64_decode_len(stripped.c_str());
778			std::vector<U8> data;
779			data.resize(len);
780			len = apr_base64_decode_binary(&data[0], stripped.c_str());
781			data.resize(len);
782			value = data;
783			break;
784		}
785		
786		case ELEMENT_UNKNOWN:
787			value.clear();
788			break;
789			
790		default:
791			// other values, map and array, have already been set
792			break;
793	}
794
795	mCurrentContent.clear();
796}
797
798void LLSDXMLParser::Impl::characterDataHandler(const XML_Char* data, int length)
799{
800	#ifdef XML_PARSER_PERFORMANCE_TESTS
801	XML_Timer timer( &charDataTime );
802	#endif	// XML_PARSER_PERFORMANCE_TESTS
803
804	mCurrentContent.append(data, length);
805}
806
807
808void LLSDXMLParser::Impl::sStartElementHandler(
809	void* userData, const XML_Char* name, const XML_Char** attributes)
810{
811	((LLSDXMLParser::Impl*)userData)->startElementHandler(name, attributes);
812}
813
814void LLSDXMLParser::Impl::sEndElementHandler(
815	void* userData, const XML_Char* name)
816{
817	((LLSDXMLParser::Impl*)userData)->endElementHandler(name);
818}
819
820void LLSDXMLParser::Impl::sCharacterDataHandler(
821	void* userData, const XML_Char* data, int length)
822{
823	((LLSDXMLParser::Impl*)userData)->characterDataHandler(data, length);
824}
825
826
827/*
828	This code is time critical
829
830	This is a sample of tag occurances of text in simstate file with ~8000 objects.
831	A tag pair (<key>something</key>) counts is counted as two:
832
833		key     - 2680178
834		real    - 1818362
835		integer -  906078
836		array   -  295682
837		map     -  191818
838		uuid    -  177903
839		binary  -  175748
840		string  -   53482
841		undef   -   40353
842		boolean -   33874
843		llsd    -   16332
844		uri     -      38
845		date    -       1
846*/
847LLSDXMLParser::Impl::Element LLSDXMLParser::Impl::readElement(const XML_Char* name)
848{
849	#ifdef XML_PARSER_PERFORMANCE_TESTS
850	XML_Timer timer( &readElementTime );
851	#endif // XML_PARSER_PERFORMANCE_TESTS
852
853	XML_Char c = *name;
854	switch (c)
855	{
856		case 'k':
857			if (strcmp(name, "key") == 0) { return ELEMENT_KEY; }
858			break;
859		case 'r':
860			if (strcmp(name, "real") == 0) { return ELEMENT_REAL; }
861			break;
862		case 'i':
863			if (strcmp(name, "integer") == 0) { return ELEMENT_INTEGER; }
864			break;
865		case 'a':
866			if (strcmp(name, "array") == 0) { return ELEMENT_ARRAY; }
867			break;
868		case 'm':
869			if (strcmp(name, "map") == 0) { return ELEMENT_MAP; }
870			break;
871		case 'u':
872			if (strcmp(name, "uuid") == 0) { return ELEMENT_UUID; }
873			if (strcmp(name, "undef") == 0) { return ELEMENT_UNDEF; }
874			if (strcmp(name, "uri") == 0) { return ELEMENT_URI; }
875			break;
876		case 'b':
877			if (strcmp(name, "binary") == 0) { return ELEMENT_BINARY; }
878			if (strcmp(name, "boolean") == 0) { return ELEMENT_BOOL; }
879			break;
880		case 's':
881			if (strcmp(name, "string") == 0) { return ELEMENT_STRING; }
882			break;
883		case 'l':
884			if (strcmp(name, "llsd") == 0) { return ELEMENT_LLSD; }
885			break;
886		case 'd':
887			if (strcmp(name, "date") == 0) { return ELEMENT_DATE; }
888			break;
889	}
890	return ELEMENT_UNKNOWN;
891}
892
893
894
895
896
897/**
898 * LLSDXMLParser
899 */
900LLSDXMLParser::LLSDXMLParser() : impl(* new Impl)
901{
902}
903
904LLSDXMLParser::~LLSDXMLParser()
905{
906	delete &impl;
907}
908
909void LLSDXMLParser::parsePart(const char *buf, int len)
910{
911	impl.parsePart(buf, len);
912}
913
914// virtual
915S32 LLSDXMLParser::doParse(std::istream& input, LLSD& data) const
916{
917	#ifdef XML_PARSER_PERFORMANCE_TESTS
918	XML_Timer timer( &parseTime );
919	#endif	// XML_PARSER_PERFORMANCE_TESTS
920
921	if (mParseLines)
922	{
923		// Use line-based reading (faster code)
924		return impl.parseLines(input, data);
925	}
926
927	return impl.parse(input, data);
928}
929
930//	virtual 
931void LLSDXMLParser::doReset()
932{
933	impl.reset();
934}