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

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

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2