PageRenderTime 87ms CodeModel.GetById 37ms app.highlight 45ms RepoModel.GetById 1ms app.codeStats 1ms

/indra/llxml/llxmltree.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 692 lines | 529 code | 100 blank | 63 comment | 60 complexity | d4ef1470132690ba358672fdbd3e7179 MD5 | raw file
  1/** 
  2 * @file llxmltree.cpp
  3 * @brief LLXmlTree implementation
  4 *
  5 * $LicenseInfo:firstyear=2002&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
 29#include "llxmltree.h"
 30#include "v3color.h"
 31#include "v4color.h"
 32#include "v4coloru.h"
 33#include "v3math.h"
 34#include "v3dmath.h"
 35#include "v4math.h"
 36#include "llquaternion.h"
 37#include "lluuid.h"
 38
 39//////////////////////////////////////////////////////////////
 40// LLXmlTree
 41
 42// static
 43LLStdStringTable LLXmlTree::sAttributeKeys(1024);
 44
 45LLXmlTree::LLXmlTree()
 46	: mRoot( NULL ),
 47	  mNodeNames(512)
 48{
 49}
 50
 51LLXmlTree::~LLXmlTree()
 52{
 53	cleanup();
 54}
 55
 56void LLXmlTree::cleanup()
 57{
 58	delete mRoot;
 59	mRoot = NULL;
 60	mNodeNames.cleanup();
 61}
 62
 63
 64BOOL LLXmlTree::parseFile(const std::string &path, BOOL keep_contents)
 65{
 66	delete mRoot;
 67	mRoot = NULL;
 68
 69	LLXmlTreeParser parser(this);
 70	BOOL success = parser.parseFile( path, &mRoot, keep_contents );
 71	if( !success )
 72	{
 73		S32 line_number = parser.getCurrentLineNumber();
 74		const char* error =  parser.getErrorString();
 75		llwarns << "LLXmlTree parse failed.  Line " << line_number << ": " << error << llendl;
 76	}
 77	return success;
 78}
 79
 80void LLXmlTree::dump()
 81{
 82	if( mRoot )
 83	{
 84		dumpNode( mRoot, "    " );
 85	}
 86}
 87
 88void LLXmlTree::dumpNode( LLXmlTreeNode* node, const std::string& prefix )
 89{
 90	node->dump( prefix );
 91
 92	std::string new_prefix = prefix + "    ";
 93	for( LLXmlTreeNode* child = node->getFirstChild(); child; child = node->getNextChild() )
 94	{
 95		dumpNode( child, new_prefix );
 96	}
 97}
 98
 99//////////////////////////////////////////////////////////////
100// LLXmlTreeNode
101
102LLXmlTreeNode::LLXmlTreeNode( const std::string& name, LLXmlTreeNode* parent, LLXmlTree* tree )
103	: mName(name),
104	  mParent(parent),
105	  mTree(tree)
106{
107}
108
109LLXmlTreeNode::~LLXmlTreeNode()
110{
111	attribute_map_t::iterator iter;
112	for (iter=mAttributes.begin(); iter != mAttributes.end(); iter++)
113		delete iter->second;
114	child_list_t::iterator child_iter;
115	for (child_iter=mChildList.begin(); child_iter != mChildList.end(); child_iter++)
116		delete *child_iter;
117}
118 
119void LLXmlTreeNode::dump( const std::string& prefix )
120{
121	llinfos << prefix << mName ;
122	if( !mContents.empty() )
123	{
124		llcont << " contents = \"" << mContents << "\"";
125	}
126	attribute_map_t::iterator iter;
127	for (iter=mAttributes.begin(); iter != mAttributes.end(); iter++)
128	{
129		LLStdStringHandle key = iter->first;
130		const std::string* value = iter->second;
131		llcont << prefix << " " << key << "=" << (value->empty() ? "NULL" : *value);
132	}
133	llcont << llendl;
134} 
135
136BOOL LLXmlTreeNode::hasAttribute(const std::string& name)
137{
138	LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
139	attribute_map_t::iterator iter = mAttributes.find(canonical_name);
140	return (iter == mAttributes.end()) ? false : true;
141}
142
143void LLXmlTreeNode::addAttribute(const std::string& name, const std::string& value)
144{
145	LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
146	const std::string *newstr = new std::string(value);
147	mAttributes[canonical_name] = newstr; // insert + copy
148}
149
150LLXmlTreeNode*	LLXmlTreeNode::getFirstChild()
151{
152	mChildListIter = mChildList.begin();
153	return getNextChild();
154}
155LLXmlTreeNode*	LLXmlTreeNode::getNextChild()
156{
157	if (mChildListIter == mChildList.end())
158		return 0;
159	else
160		return *mChildListIter++;
161}
162
163LLXmlTreeNode* LLXmlTreeNode::getChildByName(const std::string& name)
164{
165	LLStdStringHandle tableptr = mTree->mNodeNames.checkString(name);
166	mChildMapIter = mChildMap.lower_bound(tableptr);
167	mChildMapEndIter = mChildMap.upper_bound(tableptr);
168	return getNextNamedChild();
169}
170
171LLXmlTreeNode* LLXmlTreeNode::getNextNamedChild()
172{
173	if (mChildMapIter == mChildMapEndIter)
174		return NULL;
175	else
176		return (mChildMapIter++)->second;
177}
178
179void LLXmlTreeNode::appendContents(const std::string& str)
180{
181	mContents.append( str );
182}
183
184void LLXmlTreeNode::addChild(LLXmlTreeNode* child)
185{
186	llassert( child );
187	mChildList.push_back( child );
188
189	// Add a name mapping to this node
190	LLStdStringHandle tableptr = mTree->mNodeNames.insert(child->mName);
191	mChildMap.insert( child_map_t::value_type(tableptr, child));
192	
193	child->mParent = this;
194}
195
196//////////////////////////////////////////////////////////////
197
198// These functions assume that name is already in mAttritrubteKeys
199
200BOOL LLXmlTreeNode::getFastAttributeBOOL(LLStdStringHandle canonical_name, BOOL& value)
201{
202	const std::string *s = getAttribute( canonical_name );
203	return s && LLStringUtil::convertToBOOL( *s, value );
204}
205
206BOOL LLXmlTreeNode::getFastAttributeU8(LLStdStringHandle canonical_name, U8& value)
207{
208	const std::string *s = getAttribute( canonical_name );
209	return s && LLStringUtil::convertToU8( *s, value );
210}
211
212BOOL LLXmlTreeNode::getFastAttributeS8(LLStdStringHandle canonical_name, S8& value)
213{
214	const std::string *s = getAttribute( canonical_name );
215	return s && LLStringUtil::convertToS8( *s, value );
216}
217
218BOOL LLXmlTreeNode::getFastAttributeS16(LLStdStringHandle canonical_name, S16& value)
219{
220	const std::string *s = getAttribute( canonical_name );
221	return s && LLStringUtil::convertToS16( *s, value );
222}
223
224BOOL LLXmlTreeNode::getFastAttributeU16(LLStdStringHandle canonical_name, U16& value)
225{
226	const std::string *s = getAttribute( canonical_name );
227	return s && LLStringUtil::convertToU16( *s, value );
228}
229
230BOOL LLXmlTreeNode::getFastAttributeU32(LLStdStringHandle canonical_name, U32& value)
231{
232	const std::string *s = getAttribute( canonical_name );
233	return s && LLStringUtil::convertToU32( *s, value );
234}
235
236BOOL LLXmlTreeNode::getFastAttributeS32(LLStdStringHandle canonical_name, S32& value)
237{
238	const std::string *s = getAttribute( canonical_name );
239	return s && LLStringUtil::convertToS32( *s, value );
240}
241
242BOOL LLXmlTreeNode::getFastAttributeF32(LLStdStringHandle canonical_name, F32& value)
243{
244	const std::string *s = getAttribute( canonical_name );
245	return s && LLStringUtil::convertToF32( *s, value );
246}
247
248BOOL LLXmlTreeNode::getFastAttributeF64(LLStdStringHandle canonical_name, F64& value)
249{
250	const std::string *s = getAttribute( canonical_name );
251	return s && LLStringUtil::convertToF64( *s, value );
252}
253
254BOOL LLXmlTreeNode::getFastAttributeColor(LLStdStringHandle canonical_name, LLColor4& value)
255{
256	const std::string *s = getAttribute( canonical_name );
257	return s ? LLColor4::parseColor(*s, &value) : FALSE;
258}
259
260BOOL LLXmlTreeNode::getFastAttributeColor4(LLStdStringHandle canonical_name, LLColor4& value)
261{
262	const std::string *s = getAttribute( canonical_name );
263	return s ? LLColor4::parseColor4(*s, &value) : FALSE;
264}
265
266BOOL LLXmlTreeNode::getFastAttributeColor4U(LLStdStringHandle canonical_name, LLColor4U& value)
267{
268	const std::string *s = getAttribute( canonical_name );
269	return s ? LLColor4U::parseColor4U(*s, &value ) : FALSE;
270}
271
272BOOL LLXmlTreeNode::getFastAttributeVector3(LLStdStringHandle canonical_name, LLVector3& value)
273{
274	const std::string *s = getAttribute( canonical_name );
275	return s ? LLVector3::parseVector3(*s, &value ) : FALSE;
276}
277
278BOOL LLXmlTreeNode::getFastAttributeVector3d(LLStdStringHandle canonical_name, LLVector3d& value)
279{
280	const std::string *s = getAttribute( canonical_name );
281	return s ? LLVector3d::parseVector3d(*s,  &value ) : FALSE;
282}
283
284BOOL LLXmlTreeNode::getFastAttributeQuat(LLStdStringHandle canonical_name, LLQuaternion& value)
285{
286	const std::string *s = getAttribute( canonical_name );
287	return s ? LLQuaternion::parseQuat(*s, &value ) : FALSE;
288}
289
290BOOL LLXmlTreeNode::getFastAttributeUUID(LLStdStringHandle canonical_name, LLUUID& value)
291{
292	const std::string *s = getAttribute( canonical_name );
293	return s ? LLUUID::parseUUID(*s, &value ) : FALSE;
294}
295
296BOOL LLXmlTreeNode::getFastAttributeString(LLStdStringHandle canonical_name, std::string& value)
297{
298	const std::string *s = getAttribute( canonical_name );
299	if( !s )
300	{
301		return FALSE;
302	}
303
304	value = *s;
305	return TRUE;
306}
307
308
309//////////////////////////////////////////////////////////////
310
311BOOL LLXmlTreeNode::getAttributeBOOL(const std::string& name, BOOL& value)
312{
313	LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
314	return getFastAttributeBOOL(canonical_name, value);
315}
316
317BOOL LLXmlTreeNode::getAttributeU8(const std::string& name, U8& value)
318{
319	LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
320	return getFastAttributeU8(canonical_name, value);
321}
322
323BOOL LLXmlTreeNode::getAttributeS8(const std::string& name, S8& value)
324{
325	LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
326	return getFastAttributeS8(canonical_name, value);
327}
328
329BOOL LLXmlTreeNode::getAttributeS16(const std::string& name, S16& value)
330{
331	LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
332	return getFastAttributeS16(canonical_name, value);
333}
334
335BOOL LLXmlTreeNode::getAttributeU16(const std::string& name, U16& value)
336{
337	LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
338	return getFastAttributeU16(canonical_name, value);
339}
340
341BOOL LLXmlTreeNode::getAttributeU32(const std::string& name, U32& value)
342{
343	LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
344	return getFastAttributeU32(canonical_name, value);
345}
346
347BOOL LLXmlTreeNode::getAttributeS32(const std::string& name, S32& value)
348{
349	LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
350	return getFastAttributeS32(canonical_name, value);
351}
352
353BOOL LLXmlTreeNode::getAttributeF32(const std::string& name, F32& value)
354{
355	LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
356	return getFastAttributeF32(canonical_name, value);
357}
358
359BOOL LLXmlTreeNode::getAttributeF64(const std::string& name, F64& value)
360{
361	LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
362	return getFastAttributeF64(canonical_name, value);
363}
364
365BOOL LLXmlTreeNode::getAttributeColor(const std::string& name, LLColor4& value)
366{
367	LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
368	return getFastAttributeColor(canonical_name, value);
369}
370
371BOOL LLXmlTreeNode::getAttributeColor4(const std::string& name, LLColor4& value)
372{
373	LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
374	return getFastAttributeColor4(canonical_name, value);
375}
376
377BOOL LLXmlTreeNode::getAttributeColor4U(const std::string& name, LLColor4U& value)
378{
379	LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
380	return getFastAttributeColor4U(canonical_name, value);
381}
382
383BOOL LLXmlTreeNode::getAttributeVector3(const std::string& name, LLVector3& value)
384{
385	LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
386	return getFastAttributeVector3(canonical_name, value);
387}
388
389BOOL LLXmlTreeNode::getAttributeVector3d(const std::string& name, LLVector3d& value)
390{
391	LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
392	return getFastAttributeVector3d(canonical_name, value);
393}
394
395BOOL LLXmlTreeNode::getAttributeQuat(const std::string& name, LLQuaternion& value)
396{
397	LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
398	return getFastAttributeQuat(canonical_name, value);
399}
400
401BOOL LLXmlTreeNode::getAttributeUUID(const std::string& name, LLUUID& value)
402{
403	LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
404	return getFastAttributeUUID(canonical_name, value);
405}
406
407BOOL LLXmlTreeNode::getAttributeString(const std::string& name, std::string& value)
408{
409	LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
410	return getFastAttributeString(canonical_name, value);
411}
412
413/*
414  The following xml <message> nodes will all return the string from getTextContents():
415  "The quick brown fox\n  Jumps over the lazy dog"
416
417  1. HTML paragraph format:
418		<message>
419		<p>The quick brown fox</p>
420		<p>  Jumps over the lazy dog</p>
421		</message>
422  2. Each quoted section -> paragraph:
423		<message>
424		"The quick brown fox"
425		"  Jumps over the lazy dog"
426		</message>
427  3. Literal text with beginning and trailing whitespace removed:
428		<message>
429The quick brown fox
430  Jumps over the lazy dog
431		</message>
432  
433*/
434
435std::string LLXmlTreeNode::getTextContents()
436{
437	std::string msg;
438	LLXmlTreeNode* p = getChildByName("p");
439	if (p)
440	{
441		// Case 1: node has <p>text</p> tags
442		while (p)
443		{
444			msg += p->getContents() + "\n";
445			p = getNextNamedChild();
446		}
447	}
448	else
449	{
450		std::string::size_type n = mContents.find_first_not_of(" \t\n");
451		if (n != std::string::npos && mContents[n] == '\"')
452		{
453			// Case 2: node has quoted text
454			S32 num_lines = 0;
455			while(1)
456			{
457				// mContents[n] == '"'
458				++n;
459				std::string::size_type t = n;
460				std::string::size_type m = 0;
461				// fix-up escaped characters
462				while(1)
463				{
464					m = mContents.find_first_of("\\\"", t); // find first \ or "
465					if ((m == std::string::npos) || (mContents[m] == '\"'))
466					{
467						break;
468					}
469					mContents.erase(m,1);
470					t = m+1;
471				}
472				if (m == std::string::npos)
473				{
474					break;
475				}
476				// mContents[m] == '"'
477				num_lines++;
478				msg += mContents.substr(n,m-n) + "\n";
479				n = mContents.find_first_of("\"", m+1);
480				if (n == std::string::npos)
481				{
482					if (num_lines == 1)
483					{
484						msg.erase(msg.size()-1); // remove "\n" if only one line
485					}
486					break;
487				}
488			}
489		}
490		else
491		{
492			// Case 3: node has embedded text (beginning and trailing whitespace trimmed)
493			msg = mContents;
494		}
495	}
496	return msg;
497}
498	
499
500//////////////////////////////////////////////////////////////
501// LLXmlTreeParser
502
503LLXmlTreeParser::LLXmlTreeParser(LLXmlTree* tree) 
504	: mTree(tree),
505	  mRoot( NULL ),
506	  mCurrent( NULL ),
507	  mDump( FALSE ),
508	  mKeepContents(FALSE)
509{
510}
511
512LLXmlTreeParser::~LLXmlTreeParser() 
513{
514}
515
516BOOL LLXmlTreeParser::parseFile(const std::string &path, LLXmlTreeNode** root, BOOL keep_contents)
517{
518	llassert( !mRoot );
519	llassert( !mCurrent );
520
521	mKeepContents = keep_contents;
522
523	BOOL success = LLXmlParser::parseFile(path);
524
525	*root = mRoot;
526	mRoot = NULL;
527
528	if( success )
529	{
530		llassert( !mCurrent );
531	}
532	mCurrent = NULL;
533	
534	return success;
535}
536
537
538const std::string& LLXmlTreeParser::tabs()
539{
540	static std::string s;
541	s = "";
542	S32 num_tabs = getDepth() - 1;
543	for( S32 i = 0; i < num_tabs; i++)
544	{
545		s += "    ";
546	}
547	return s;
548}
549
550void LLXmlTreeParser::startElement(const char* name, const char **atts) 
551{
552	if( mDump )
553	{
554		llinfos << tabs() << "startElement " << name << llendl;
555		
556		S32 i = 0;
557		while( atts[i] && atts[i+1] )
558		{
559			llinfos << tabs() << "attribute: " << atts[i] << "=" << atts[i+1] << llendl;
560			i += 2;
561		}
562	}
563
564	LLXmlTreeNode* child = CreateXmlTreeNode( std::string(name), mCurrent );
565
566	S32 i = 0;
567	while( atts[i] && atts[i+1] )
568	{
569		child->addAttribute( atts[i], atts[i+1] );
570		i += 2;
571	}
572
573	if( mCurrent )
574	{
575		mCurrent->addChild( child );
576
577	}
578	else
579	{
580		llassert( !mRoot );
581		mRoot = child;
582	}
583	mCurrent = child;
584}
585
586LLXmlTreeNode* LLXmlTreeParser::CreateXmlTreeNode(const std::string& name, LLXmlTreeNode* parent)
587{
588	return new LLXmlTreeNode(name, parent, mTree);
589}
590
591
592void LLXmlTreeParser::endElement(const char* name) 
593{
594	if( mDump )
595	{
596		llinfos << tabs() << "endElement " << name << llendl;
597	}
598
599	if( !mCurrent->mContents.empty() )
600	{
601		LLStringUtil::trim(mCurrent->mContents);
602		LLStringUtil::removeCRLF(mCurrent->mContents);
603	}
604
605	mCurrent = mCurrent->getParent();
606}
607
608void LLXmlTreeParser::characterData(const char *s, int len) 
609{
610	std::string str;
611	if (s) str = std::string(s, len);
612	if( mDump )
613	{
614		llinfos << tabs() << "CharacterData " << str << llendl;
615	}
616
617	if (mKeepContents)
618	{
619		mCurrent->appendContents( str );
620	}
621}
622
623void LLXmlTreeParser::processingInstruction(const char *target, const char *data)
624{
625	if( mDump )
626	{
627		llinfos << tabs() << "processingInstruction " << data << llendl;
628	}
629}
630
631void LLXmlTreeParser::comment(const char *data)
632{
633	if( mDump )
634	{
635		llinfos << tabs() << "comment " << data << llendl;
636	}
637}
638
639void LLXmlTreeParser::startCdataSection()
640{
641	if( mDump )
642	{
643		llinfos << tabs() << "startCdataSection" << llendl;
644	}
645}
646
647void LLXmlTreeParser::endCdataSection()
648{
649	if( mDump )
650	{
651		llinfos << tabs() << "endCdataSection" << llendl;
652	}
653}
654
655void LLXmlTreeParser::defaultData(const char *s, int len)
656{
657	if( mDump )
658	{
659		std::string str;
660		if (s) str = std::string(s, len);
661		llinfos << tabs() << "defaultData " << str << llendl;
662	}
663}
664
665void LLXmlTreeParser::unparsedEntityDecl(
666	const char* entity_name,
667	const char* base,
668	const char* system_id,
669	const char* public_id,
670	const char* notation_name)
671{
672	if( mDump )
673	{
674		llinfos << tabs() << "unparsed entity:"			<< llendl;
675		llinfos << tabs() << "    entityName "			<< entity_name	<< llendl;
676		llinfos << tabs() << "    base "				<< base			<< llendl;
677		llinfos << tabs() << "    systemId "			<< system_id	<< llendl;
678		llinfos << tabs() << "    publicId "			<< public_id	<< llendl;
679		llinfos << tabs() << "    notationName "		<< notation_name<< llendl;
680	}
681}
682
683void test_llxmltree()
684{
685	LLXmlTree tree;
686	BOOL success = tree.parseFile( "test.xml" );
687	if( success )
688	{
689		tree.dump();
690	}
691}
692