(file) Return to XmlParser.cpp CVS log (file) (dir) Up to [Pegasus] / pegasus / src / Pegasus / Common

  1 mike  1.3 //%/////////////////////////////////////////////////////////////////////////////
  2 mike  1.1 //
  3           // Copyright (c) 2000 The Open Group, BMC Software, Tivoli Systems, IBM
  4           //
  5           // Permission is hereby granted, free of charge, to any person obtaining a
  6           // copy of this software and associated documentation files (the "Software"),
  7           // to deal in the Software without restriction, including without limitation
  8           // the rights to use, copy, modify, merge, publish, distribute, sublicense,
  9           // and/or sell copies of the Software, and to permit persons to whom the
 10           // Software is furnished to do so, subject to the following conditions:
 11           //
 12           // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 13           // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 14           // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 15           // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 16           // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 17           // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 18           // DEALINGS IN THE SOFTWARE.
 19           //
 20 mike  1.3 //==============================================================================
 21 mike  1.1 //
 22 mike  1.3 // Author: Mike Brasher (mbrasher@bmc.com)
 23 mike  1.1 //
 24 mike  1.3 // Modified By:
 25 mike  1.2 //
 26 mike  1.3 //%/////////////////////////////////////////////////////////////////////////////
 27 mike  1.1 
 28           ////////////////////////////////////////////////////////////////////////////////
 29           //
 30           // XmlParser
 31           //
 32           //	This file contains a simple non-validating XML parser. Here are 
 33           //	serveral rules for well-formed XML:
 34           //
 35           //	    1.	Documents must begin with an XML declaration:
 36           //
 37           //		<?xml version="1.0" standalone="yes"?>
 38           //
 39           //	    2.	Comments have the form:
 40           //
 41           //		<!-- blah blah blah -->
 42           //
 43           //	    3. The following entity references are supported:
 44           //
 45           //		&amp - ampersand
 46           //	 	&lt - less-than
 47           //		&gt - greater-than
 48 mike  1.1 //		&quot - full quote
 49           //		&apos - apostrophe
 50           //
 51           //	    4. Element names and attribute names take the following form:
 52           //
 53           //		[A-Za-z_][A-Za-z_0-9-.:]
 54           //
 55           //	    5.	Arbitrary data (CDATA) can be enclosed like this:
 56           //
 57           //		    <![CDATA[
 58           //		    ...
 59           //		    ]]>
 60           //
 61           //	    6.	Element names and attributes names are case-sensitive.
 62           //
 63           //	    7.	XmlAttribute values must be delimited by full or half quotes.
 64           //		XmlAttribute values must be delimited.
 65           //
 66           //	    8.  <!DOCTYPE...>
 67           //
 68           // TODO:
 69 mike  1.1 //
 70           //	Handle <!DOCTYPE...> sections which are complicated (containing
 71           //        rules rather than references to files).
 72           //
 73           //	Handle reference of this form: "&#913;"
 74           //
 75           //	Remove newlines from string literals:
 76           //
 77           //          Example: <xyz x="hello
 78           //		world">
 79           //
 80           ////////////////////////////////////////////////////////////////////////////////
 81           
 82           #include <cctype>
 83           #include <cassert>
 84           #include <cstdio>
 85           #include <cstdlib>
 86           #include <cstring>
 87           #include "XmlParser.h"
 88           
 89           PEGASUS_NAMESPACE_BEGIN
 90 mike  1.1 
 91           ////////////////////////////////////////////////////////////////////////////////
 92           //
 93           // Static helper functions
 94           //
 95           ////////////////////////////////////////////////////////////////////////////////
 96           
 97           static void _printValue(const char* p)
 98           {
 99               for (; *p; p++)
100               {
101           	if (*p == '\n')
102 mike  1.7 	    PEGASUS_STD(cout) << "\\n";
103 mike  1.1 	else if (*p == '\r')
104 mike  1.7 	    PEGASUS_STD(cout) << "\\r";
105 mike  1.1 	else if (*p == '\t')
106 mike  1.7 	    PEGASUS_STD(cout) << "\\t";
107 mike  1.1 	else
108 mike  1.7 	    PEGASUS_STD(cout) << *p;
109 mike  1.1     }
110           }
111           
112           struct EntityReference
113           {
114               const char* match;
115               Uint32 length;
116               char replacement;
117           };
118           
119           static EntityReference _references[] =
120           {
121               { "&amp;", 5, '&' },
122               { "&lt;", 4, '<' },
123               { "&gt;", 4, '>' },
124               { "&quot;", 6, '"' },
125               { "&apos;", 6, '\'' }
126           };
127           
128           static Uint32 _REFERENCES_SIZE = (sizeof(_references) / sizeof(_references[0]));
129           
130 mike  1.1 // Remove all redundant spaces from the given string:
131           
132           static void _normalize(char* text)
133           {
134               Uint32 length = strlen(text);
135               char* p = text;
136               char* end = p + length;
137           
138               // Remove leading spaces:
139           
140               while (isspace(*p))
141           	p++;
142           
143               if (p != text)
144           	memmove(text, p, end - p + 1);
145           
146               p = text;
147           
148               // Look for sequences of more than one space and remove all but one.
149           
150               for (;;)
151 mike  1.1     {
152           	// Advance to the next space:
153           
154           	while (*p && !isspace(*p))
155           	    p++;
156           
157           	if (!*p)
158           	    break;
159           
160           	// Advance to the next non-space:
161           
162           	char* q = p++;
163           
164           	while (isspace(*p))
165           	    p++;
166           
167           	// Discard trailing spaces (if we are at the end):
168           
169           	if (!*p)
170           	{
171           	    *q = '\0';
172 mike  1.1 	    break;
173           	}
174           
175           	// Remove the redundant spaces:
176           
177           	Uint32 n = p - q;
178           
179           	if (n > 1)
180           	{
181           	    *q++ = ' ';
182           	    memmove(q, p, end - p + 1);
183           	    p = q;
184           	}
185               }
186           }
187           
188           ////////////////////////////////////////////////////////////////////////////////
189           //
190           // XmlException
191           //
192           ////////////////////////////////////////////////////////////////////////////////
193 mike  1.1 
194           static char* _xmlMessages[] =
195           {
196               "Bad opening element",
197               "Bad closing element",
198               "Bad attribute name",
199               "Exepected equal sign",
200               "Bad attribute value",
201               "A \"--\" sequence found within comment",
202               "Unterminated comment",
203               "Unterminated CDATA block",
204               "Unterminated DOCTYPE",
205               "Too many attributes: parser only handles 10",
206               "Malformed reference",
207               "Expected a comment or CDATA following \"<!\" sequence",
208               "Closing element does not match opening element",
209               "One or more tags are still open",
210               "More than one root element was encountered",
211               "Validation error",
212               "Semantic error"
213           };
214 mike  1.1 
215           static String _formMessage(Uint32 code, Uint32 line, const String& message)
216           {
217               String result = _xmlMessages[Uint32(code) - 1];
218           
219               char buffer[32];
220               sprintf(buffer, "%d", line);
221               result.append(": on line ");
222               result.append(buffer);
223           
224 mike  1.4     if (message.size())
225 mike  1.1     {
226           	result.append(": ");
227           	result.append(message);
228               }
229           
230               return result;
231           }
232           
233           XmlException::XmlException(
234               XmlException::Code code, 
235               Uint32 lineNumber,
236               const String& message) 
237               : Exception(_formMessage(code, lineNumber, message))
238           {
239           
240           }
241           
242           ////////////////////////////////////////////////////////////////////////////////
243           //
244           // XmlValidationError
245           //
246 mike  1.1 ////////////////////////////////////////////////////////////////////////////////
247           
248           XmlValidationError::XmlValidationError(
249               Uint32 lineNumber,
250               const String& message)
251               : XmlException(XmlException::VALIDATION_ERROR, lineNumber, message)
252           {
253           
254           }
255           
256           ////////////////////////////////////////////////////////////////////////////////
257           //
258           // XmlSemanticError
259           //
260           ////////////////////////////////////////////////////////////////////////////////
261           
262           XmlSemanticError::XmlSemanticError(
263               Uint32 lineNumber,
264               const String& message)
265 sage  1.5     : XmlException(XmlException::SEMANTIC_ERROR, lineNumber, message)
266 mike  1.1 {
267           
268           }
269           
270           ////////////////////////////////////////////////////////////////////////////////
271           //
272           // XmlParser
273           //
274           ////////////////////////////////////////////////////////////////////////////////
275           
276           XmlParser::XmlParser(char* text) : _line(1), _text(text), _current(text), 
277               _restoreChar('\0'), _foundRoot(false)
278           {
279           
280           }
281           
282           Boolean XmlParser::next(XmlEntry& entry)
283           {
284               if (!_putBackStack.isEmpty())
285               {
286           	entry = _putBackStack.top();
287 mike  1.1 	_putBackStack.pop();
288           	return true;
289               }
290           
291               // If a character was overwritten with a null-terminator the last
292               // time this routine was called, then put back that character. Before
293               // exiting of course, restore the null-terminator.
294           
295               char* nullTerminator = 0;
296           
297               if (_restoreChar && !*_current)
298               {
299           	nullTerminator = _current;
300           	*_current = _restoreChar;
301           	_restoreChar = '\0';
302               }
303           
304               // Skip over any whitespace:
305           
306               _skipWhitespace(_current);
307           
308 mike  1.1     if (!*_current)
309               {
310           	if (nullTerminator)
311           	    *nullTerminator = '\0';
312           
313           	if (!_stack.isEmpty())
314           	    throw XmlException(XmlException::UNCLOSED_TAGS, _line);
315           
316           	return false;
317               }
318           
319               // Either a "<...>" or content begins next:
320           
321               if (*_current == '<')
322               {
323           	_current++;
324           	_getElement(_current, entry);
325           
326           	if (nullTerminator)
327           	    *nullTerminator = '\0';
328           
329 mike  1.1 	if (entry.type == XmlEntry::START_TAG)
330           	{
331           	    if (_stack.isEmpty() && _foundRoot)
332           		throw XmlException(XmlException::MULTIPLE_ROOTS, _line);
333           
334           	    _foundRoot = true;
335           	    _stack.push((char*)entry.text);
336           	}
337           	else if (entry.type == XmlEntry::END_TAG)
338           	{
339           	    if (_stack.isEmpty())
340           		throw XmlException(XmlException::START_END_MISMATCH, _line);
341           
342           	    if (strcmp(_stack.top(), entry.text) != 0)
343           		throw XmlException(XmlException::START_END_MISMATCH, _line);
344           
345           	    _stack.pop();
346           	}
347           
348           	return true;
349               }
350 mike  1.1     else
351               {
352           	entry.type = XmlEntry::CONTENT;
353           	entry.text = _current;
354           	_getContent(_current);
355           	_restoreChar = *_current;
356           	*_current = '\0';
357           
358           	if (nullTerminator)
359           	    *nullTerminator = '\0';
360           
361           	_substituteReferences((char*)entry.text);
362           	_normalize((char*)entry.text);
363           
364           	return true;
365               }
366           }
367           
368           void XmlParser::putBack(XmlEntry& entry)
369           {
370               _putBackStack.push(entry);
371 mike  1.1 }
372           
373           XmlParser::~XmlParser()
374           {
375               // Nothing to do!
376           }
377           
378           void XmlParser::_skipWhitespace(char*& p)
379           {
380               while (*p && isspace(*p))
381               {
382           	if (*p == '\n')
383           	    _line++;
384           
385           	p++;
386               }
387           }
388           
389           Boolean XmlParser::_getElementName(char*& p)
390           {
391               if (!isalpha(*p) && *p != '_')
392 mike  1.1 	throw XmlException(XmlException::BAD_START_TAG, _line);
393           
394               while (*p && 
395           	(isalnum(*p) || *p == '_' || *p == '-' || *p == ':' || *p == '.'))
396           	p++;
397           
398               // The next character must be a space:
399           
400               if (isspace(*p))
401               {
402           	*p++ = '\0';
403           	_skipWhitespace(p);
404               }
405           
406               if (*p == '>')
407               {
408           	*p++ = '\0';
409           	return true;
410               }
411           
412               return false;
413 mike  1.1 }
414           
415           Boolean XmlParser::_getOpenElementName(char*& p, Boolean& openCloseElement)
416           {
417               openCloseElement = false;
418           
419               if (!isalpha(*p) && *p != '_')
420           	throw XmlException(XmlException::BAD_START_TAG, _line);
421           
422               while (*p && 
423           	(isalnum(*p) || *p == '_' || *p == '-' || *p == ':' || *p == '.'))
424           	p++;
425           
426               // The next character must be a space:
427           
428               if (isspace(*p))
429               {
430           	*p++ = '\0';
431           	_skipWhitespace(p);
432               }
433           
434 mike  1.1     if (*p == '>')
435               {
436           	*p++ = '\0';
437           	return true;
438               }
439           
440               if (p[0] == '/' && p[1] == '>')
441               {
442           	openCloseElement = true;
443           	*p = '\0';
444           	p += 2;
445           	return true;
446               }
447           
448               return false;
449           }
450           
451           void XmlParser::_getAttributeNameAndEqual(char*& p)
452           {
453               if (!isalpha(*p) && *p != '_')
454           	throw XmlException(XmlException::BAD_ATTRIBUTE_NAME, _line);
455 mike  1.1 
456               while (*p && 
457           	(isalnum(*p) || *p == '_' || *p == '-' || *p == ':' || *p == '.'))
458           	p++;
459           
460               char* term = p;
461           
462               _skipWhitespace(p);
463           
464               if (*p != '=')
465           	throw XmlException(XmlException::BAD_ATTRIBUTE_NAME, _line);
466           
467               p++;
468           
469               _skipWhitespace(p);
470           
471               *term = '\0';
472           }
473           
474           void XmlParser::_getAttributeValue(char*& p)
475           {
476 mike  1.1     // ATTN-B: handle values contained in semiquotes:
477           
478               if (*p != '"' && *p != '\'')
479           	throw XmlException(XmlException::BAD_ATTRIBUTE_VALUE, _line);
480           
481               char startChar = *p++;
482           
483               while (*p && *p != startChar)
484           	p++;
485           
486               if (*p != startChar)
487           	throw XmlException(XmlException::BAD_ATTRIBUTE_VALUE, _line);
488           
489               *p++ = '\0';
490           }
491           
492           void XmlParser::_getComment(char*& p)
493           {
494               // Now p points to first non-whitespace character beyond "<--" sequence:
495           
496               for (; *p; p++)
497 mike  1.1     {
498           	if (p[0] == '-' && p[1] == '-')
499           	{
500           	    if (p[2] != '>')
501           	    {
502           		throw XmlException(
503           		    XmlException::MINUS_MINUS_IN_COMMENT, _line);
504           	    }
505           
506           	    // Find end of comment (excluding whitespace):
507           
508           	    *p = '\0';
509           	    p += 3;
510           	    return;
511           	}
512               }
513           
514               // If it got this far, then the comment is unterminated:
515           
516               throw XmlException(XmlException::UNTERMINATED_COMMENT, _line);
517           }
518 mike  1.1 
519           void XmlParser::_getCData(char*& p)
520           {
521               // At this point p points one past "<![CDATA[" sequence:
522           
523               for (; *p; p++)
524               {
525           	if (p[0] == ']' && p[1] == ']' && p[2] == '>')
526           	{
527           	    *p = '\0';
528           	    p += 3;
529           	    return;
530           	}
531           	else if (*p == '\n')
532           	    _line++;
533               }
534           
535               // If it got this far, then the comment is unterminated:
536           
537               throw XmlException(XmlException::UNTERMINATED_CDATA, _line);
538           }
539 mike  1.1 
540           void XmlParser::_getDocType(char*& p)
541           {
542               // Just ignore the DOCTYPE command for now:
543           
544               for (; *p && *p != '>'; p++)
545               {
546           	if (*p == '\n')
547           	    _line++;
548               }
549           
550               if (*p != '>')
551           	throw XmlException(XmlException::UNTERMINATED_DOCTYPE, _line);
552           
553               p++;
554           }
555           
556           void XmlParser::_getContent(char*& p)
557           {
558               while (*p && *p != '<')
559               {
560 mike  1.1 	if (*p == '\n')
561           	    _line++;
562           
563           	p++;
564               }
565           }
566           
567           void XmlParser::_substituteReferences(char* text)
568           {
569               Uint32 rem = strlen(text);
570           
571               for (char* p = text; *p; p++, rem--)
572               {
573           	if (*p == '&')
574           	{
575           	    // Look for predefined entity reference:
576           
577           	    Boolean found = false;
578           
579           	    for (Uint32 i = 0; i < _REFERENCES_SIZE; i++)
580           	    {
581 mike  1.1 		Uint32 length = _references[i].length;
582           		const char* match = _references[i].match;
583           
584           		if (strncmp(p, _references[i].match, length) == 0)
585           		{
586           		    found = true;
587           		    *p = _references[i].replacement;
588           		    char* q = p + length;
589           		    rem = rem - length + 1;
590           		    memmove(p + 1, q, rem);
591           		}
592           	    }
593           
594           	    // If not found, then at least make sure it is well formed:
595           
596           	    if (!found)
597           	    {
598           		char* start = p;
599           		p++;
600           
601           		XmlException::Code code = XmlException::MALFORMED_REFERENCE;
602 mike  1.1 
603           		if (isalpha(*p) || *p == '_')
604           		{
605           		    for (p++; *p && *p != ';'; p++)
606           		    {
607           			if (!isalnum(*p) && *p != '_')
608           			    throw XmlException(code, _line);
609           		    }
610           		}
611           		else if (*p == '#')
612           		{
613           		    for (p++ ; *p && *p != ';'; p++)
614           		    {
615           			if (!isdigit(*p))
616           			    throw XmlException(code, _line);
617           		    } 
618           		}
619           
620           		if (*p != ';')
621           		    throw XmlException(code, _line);
622           
623 mike  1.1 		rem -= p - start;
624           	    }
625           	}
626               }
627           }
628           
629           static const char _EMPTY_STRING[] = "";
630           
631           void XmlParser::_getElement(char*& p, XmlEntry& entry)
632           {
633               entry.attributeCount = 0;
634           
635               //--------------------------------------------------------------------------
636               // Get the element name (expect one of these: '?', '!', [A-Za-z_])
637               //--------------------------------------------------------------------------
638           
639               if (*p == '?')
640               {
641           	entry.type = XmlEntry::XML_DECLARATION;
642           	entry.text = ++p;
643           
644 mike  1.1 	Boolean openCloseElement = false;
645           
646           	if (_getElementName(p))
647           	    return;
648               }
649               else if (*p == '!')
650               {
651           	p++;
652           
653           	// Expect a comment or CDATA:
654           
655           	if (p[0] == '-' && p[1] == '-')
656           	{
657           	    p += 2;
658           	    entry.type = XmlEntry::COMMENT;
659           	    entry.text = p;
660           	    _getComment(p);
661           	    return;
662           	}
663           	else if (memcmp(p, "[CDATA[", 7) == 0)
664           	{
665 mike  1.1 	    p += 7;
666           	    entry.type = XmlEntry::CDATA;
667           	    entry.text = p;
668           	    _getCData(p);
669           	    return;
670           	}
671           	else if (memcmp(p, "DOCTYPE", 7) == 0)
672           	{
673           	    entry.type = XmlEntry::DOCTYPE;
674           	    entry.text = _EMPTY_STRING;
675           	    _getDocType(p);
676           	    return;
677           	}
678           	throw(XmlException(XmlException::EXPECTED_COMMENT_OR_CDATA, _line));
679               }
680               else if (*p == '/')
681               {
682           	entry.type = XmlEntry::END_TAG;
683           	entry.text = ++p;
684           
685           	if (!_getElementName(p))
686 mike  1.1 	    throw(XmlException(XmlException::BAD_END_TAG, _line));
687           
688           	return;
689               }
690               else if (isalpha(*p) || *p == '_')
691               {
692           	entry.type = XmlEntry::START_TAG;
693           	entry.text = p;
694           
695           	Boolean openCloseElement = false;
696           
697           	if (_getOpenElementName(p, openCloseElement))
698           	{
699           	    if (openCloseElement)
700           		entry.type = XmlEntry::EMPTY_TAG;
701           	    return;
702           	}
703               }
704               else
705           	throw XmlException(XmlException::BAD_START_TAG, _line);
706           
707 mike  1.1     //--------------------------------------------------------------------------
708               // Grab all the attributes:
709               //--------------------------------------------------------------------------
710           
711               for (;;)
712               {
713           	if (entry.type == XmlEntry::XML_DECLARATION)
714           	{
715           	    if (p[0] == '?' && p[1] == '>')
716           	    {
717           		p += 2;
718           		return;
719           	    }
720           	}
721           	else if (entry.type == XmlEntry::START_TAG && p[0] == '/' && p[1] =='>')
722           	{
723           	    entry.type = XmlEntry::EMPTY_TAG;
724           	    p += 2;
725           	    return;
726           	}
727           	else if (*p == '>')
728 mike  1.1 	{
729           	    p++;
730           	    return;
731           	}
732           
733           	XmlAttribute attr;
734           	attr.name = p;
735           	_getAttributeNameAndEqual(p);
736           
737           	if (*p != '"' && *p != '\'')
738           	    throw XmlException(XmlException::BAD_ATTRIBUTE_VALUE, _line);
739           
740           	attr.value = p + 1;
741           	_getAttributeValue(p);
742           
743           	if (entry.type == XmlEntry::XML_DECLARATION)
744           	{
745           	    // The next thing must a space or a "?>":
746           
747           	    if (!(p[0] == '?' && p[1] == '>') && !isspace(*p))
748           	    {
749 mike  1.1 		throw XmlException(
750           		    XmlException::BAD_ATTRIBUTE_VALUE, _line);
751           	    }
752           	}
753           	else if (!(*p == '>' || (p[0] == '/' && p[1] == '>') || isspace(*p)))
754           	{
755           	    // The next thing must be a space or a '>':
756           
757           	    throw XmlException(XmlException::BAD_ATTRIBUTE_VALUE, _line);
758           	}
759           
760           	_skipWhitespace(p);
761           
762           	if (entry.attributeCount == XmlEntry::MAX_ATTRIBUTES)
763           	    throw XmlException(XmlException::TOO_MANY_ATTRIBUTES, _line);
764           
765           	_substituteReferences((char*)attr.value);
766           	entry.attributes[entry.attributeCount++] = attr;
767               }
768           }
769           
770 mike  1.1 static const char* _typeStrings[] =
771           {
772               "XML_DECLARATION", 
773               "START_TAG", 
774               "EMPTY_TAG", 
775               "END_TAG", 
776               "COMMENT",
777               "CDATA",
778               "DOCTYPE",
779               "CONTENT" 
780           };
781           
782           void XmlEntry::print() const
783           {
784 mike  1.7     PEGASUS_STD(cout) << "=== " << _typeStrings[type] << " ";
785 mike  1.1 
786               Boolean needQuotes = type == XmlEntry::CDATA || type == XmlEntry::CONTENT;
787           
788               if (needQuotes)
789 mike  1.7 	PEGASUS_STD(cout) << "\"";
790 mike  1.1 	
791               _printValue(text);
792           
793               if (needQuotes)
794 mike  1.7 	PEGASUS_STD(cout) << "\"";
795 mike  1.1 
796 mike  1.7     PEGASUS_STD(cout) << '\n';
797 mike  1.1 
798               for (Uint32 i = 0; i < attributeCount; i++)
799               {
800 mike  1.7 	PEGASUS_STD(cout) << "    " << attributes[i].name << "=\"";
801 mike  1.1 	_printValue(attributes[i].value);
802 mike  1.7 	PEGASUS_STD(cout) << "\"" << PEGASUS_STD(endl);
803 mike  1.1     }
804           }
805           
806           const XmlAttribute* XmlEntry::findAttribute(
807               const char* name) const
808           {
809               for (Uint32 i = 0; i < attributeCount; i++)
810               {
811           	if (strcmp(attributes[i].name, name) == 0)
812           	    return &attributes[i];
813               }
814           
815               return 0;
816           }
817           
818           // Find first non-whitespace character (set first) and last non-whitespace
819           // character (set last one past this). For example, consider this string:
820           //
821           //	"   87     "
822           //
823           // The first pointer would point to '8' and the last pointer woudl point one
824 mike  1.1 // beyond '7'.
825           
826           static void _findEnds(
827               const char* str, 
828               const char*& first, 
829               const char*& last)
830           {
831               first = str;
832           
833               while (isspace(*first))
834           	first++;
835           
836               if (!*first)
837               {
838           	last = first;
839           	return;
840               }
841           
842               last = first + strlen(first);
843           
844               while (last != first && isspace(last[-1]))
845 mike  1.1 	last--;
846           }
847           
848           Boolean XmlEntry::getAttributeValue(
849               const char* name, 
850               Uint32& value) const
851           {
852               const XmlAttribute* attr = findAttribute(name);
853           
854               if (!attr)
855           	return false;
856           
857               const char* first;
858               const char* last;
859               _findEnds(attr->value, first, last);
860           
861               char* end = 0;
862               long tmp = strtol(first, &end, 10);
863           
864               if (!end || end != last)
865           	return false;
866 mike  1.1 
867               value = Uint32(tmp);
868               return true;
869           }
870           
871           Boolean XmlEntry::getAttributeValue(
872               const char* name, 
873               Real32& value) const
874           {
875               const XmlAttribute* attr = findAttribute(name);
876           
877               if (!attr)
878           	return false;
879           
880               const char* first;
881               const char* last;
882               _findEnds(attr->value, first, last);
883           
884               char* end = 0;
885               double tmp = strtod(first, &end);
886           
887 mike  1.1     if (!end || end != last)
888           	return false;
889           
890               value = Uint32(tmp);
891               return true;
892           }
893           
894           Boolean XmlEntry::getAttributeValue(
895               const char* name, 
896               const char*& value) const
897           {
898               const XmlAttribute* attr = findAttribute(name);
899           
900               if (!attr)
901           	return false;
902           
903               value = attr->value;
904               return true;
905           }
906           
907           Boolean XmlEntry::getAttributeValue(const char* name, String& value) const
908 mike  1.1 {
909               const char* tmp;
910           
911               if (!getAttributeValue(name, tmp))
912           	return false;
913           
914               value = tmp;
915               return true;
916           }
917           
918 mike  1.6 void XmlAppendCString(Array<Sint8>& out, const char* str)
919           {
920               out.append(str, strlen(str));
921           }
922           
923 mike  1.1 PEGASUS_NAMESPACE_END

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2