1 //%LICENSE////////////////////////////////////////////////////////////////
3 // Licensed to The Open Group (TOG) under one or more contributor license
4 // agreements. Refer to the OpenPegasusNOTICE.txt file distributed with
5 // this work for additional information regarding copyright ownership.
6 // Each contributor licenses this file to you under the OpenPegasus Open
7 // Source License; you may not use this file except in compliance with the
10 // Permission is hereby granted, free of charge, to any person obtaining a
11 // copy of this software and associated documentation files (the "Software"),
12 // to deal in the Software without restriction, including without limitation
13 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 // and/or sell copies of the Software, and to permit persons to whom the
15 // Software is furnished to do so, subject to the following conditions:
17 // The above copyright notice and this permission notice shall be included
18 // in all copies or substantial portions of the Software.
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
23 // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
24 // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
25 // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
26 // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 //////////////////////////////////////////////////////////////////////////
30 //%/////////////////////////////////////////////////////////////////////////////
32 ////////////////////////////////////////////////////////////////////////////////
36 // This file contains a simple non-validating XML parser. Here are
37 // serveral rules for well-formed XML:
39 // 1. Documents must begin with an XML declaration:
41 // <?xml version="1.0" standalone="yes"?>
43 // 2. Comments have the form:
45 // <!-- blah blah blah -->
47 // 3. The following entity references are supported:
55 // as well as character (numeric) references:
57 // 1 - decimal reference for character '1'
58 // 1 - hexadecimal reference for character '1'
60 // 4. Element names and attribute names take the following form:
62 // [A-Za-z_][A-Za-z_0-9-.:]
64 // 5. Arbitrary data (CDATA) can be enclosed like this:
70 // 6. Element names and attributes names are case-sensitive.
72 // 7. XmlAttribute values must be delimited by full or half quotes.
73 // XmlAttribute values must be delimited.
79 // ATTN: KS P1 4 Mar 2002. Review the following TODOs to see if there is
80 // work. Handle <!DOCTYPE...> sections which are complicated (containing
81 // rules rather than references to files).
83 // Remove newlines from string literals:
85 // Example: <xyz x="hello
88 ////////////////////////////////////////////////////////////////////////////////
90 #include <Pegasus/Common/Config.h>
95 #include "XmlParser.h"
97 #include "ExceptionRep.h"
100 PEGASUS_NAMESPACE_BEGIN
102 ////////////////////////////////////////////////////////////////////////////////
104 // Static helper functions
106 ////////////////////////////////////////////////////////////////////////////////
108 static void _printValue(const char* p)
113 PEGASUS_STD(cout) << "\\n";
115 PEGASUS_STD(cout) << "\\r";
117 PEGASUS_STD(cout) << "\\t";
119 PEGASUS_STD(cout) << *p;
123 struct EntityReference
130 // ATTN: Add support for more entity references
131 static EntityReference _references[] =
136 { """, 6, '"' },
137 { "'", 6, '\'' }
141 // Implements a check for a whitespace character, without calling
142 // isspace( ). The isspace( ) function is locale-sensitive,
143 // and incorrectly flags some chars above 0x7f as whitespace. This
144 // causes the XmlParser to incorrectly parse UTF-8 data.
146 // Section 2.3 of XML 1.0 Standard (http://www.w3.org/TR/REC-xml)
147 // defines white space as:
148 // S ::= (#x20 | #x9 | #xD | #xA)+
149 static inline int _isspace(char c)
151 return CharSet::isXmlWhiteSpace((Uint8)c);
154 static Uint32 _REFERENCES_SIZE = (sizeof(_references) / sizeof(_references[0]));
156 ////////////////////////////////////////////////////////////////////////////////
160 ////////////////////////////////////////////////////////////////////////////////
162 static const char* _xmlMessages[] =
164 "Bad opening element",
165 "Bad closing element",
166 "Bad attribute name",
167 "Exepected equal sign",
168 "Bad attribute value",
169 "A \"--\" sequence found within comment",
170 "Unterminated comment",
171 "Unterminated CDATA block",
172 "Unterminated DOCTYPE",
173 "Malformed reference",
174 "Expected a comment or CDATA following \"<!\" sequence",
175 "Closing element does not match opening element",
176 "One or more tags are still open",
177 "More than one root element was encountered",
180 "Namespace not declared"
183 static const char* _xmlKeys[] =
185 "Common.XmlParser.BAD_START_TAG",
186 "Common.XmlParser.BAD_END_TAG",
187 "Common.XmlParser.BAD_ATTRIBUTE_NAME",
188 "Common.XmlParser.EXPECTED_EQUAL_SIGN",
189 "Common.XmlParser.BAD_ATTRIBUTE_VALUE",
190 "Common.XmlParser.MINUS_MINUS_IN_COMMENT",
191 "Common.XmlParser.UNTERMINATED_COMMENT",
192 "Common.XmlParser.UNTERMINATED_CDATA",
193 "Common.XmlParser.UNTERMINATED_DOCTYPE",
194 "Common.XmlParser.MALFORMED_REFERENCE",
195 "Common.XmlParser.EXPECTED_COMMENT_OR_CDATA",
196 "Common.XmlParser.START_END_MISMATCH",
197 "Common.XmlParser.UNCLOSED_TAGS",
198 "Common.XmlParser.MULTIPLE_ROOTS",
199 "Common.XmlParser.VALIDATION_ERROR",
200 "Common.XmlParser.SEMANTIC_ERROR",
201 "Common.XmlParser.UNDECLARED_NAMESPACE"
205 static MessageLoaderParms _formMessage(
208 const String& message)
210 String dftMsg = _xmlMessages[Uint32(code) - 1];
211 const char* key = _xmlKeys[Uint32(code) - 1];
212 String msg = message;
214 dftMsg.append(": on line $0");
221 return MessageLoaderParms(key, dftMsg.getCString(), line ,msg);
224 static MessageLoaderParms _formPartialMessage(Uint32 code, Uint32 line)
226 String dftMsg = _xmlMessages[Uint32(code) - 1];
227 const char* key = _xmlKeys[Uint32(code) - 1];
229 dftMsg.append(": on line $0");
231 return MessageLoaderParms(key, dftMsg.getCString(), line);
235 XmlException::XmlException(
236 XmlException::Code code,
238 const String& message)
239 : Exception(_formMessage(code, lineNumber, message))
245 XmlException::XmlException(
246 XmlException::Code code,
248 MessageLoaderParms& msgParms)
249 : Exception(_formPartialMessage(code, lineNumber))
251 if (msgParms.default_msg.size())
253 msgParms.default_msg = ": " + msgParms.default_msg;
255 _rep->message.append(MessageLoader::getMessage(msgParms));
259 ////////////////////////////////////////////////////////////////////////////////
261 // XmlValidationError
263 ////////////////////////////////////////////////////////////////////////////////
265 XmlValidationError::XmlValidationError(
267 const String& message)
268 : XmlException(XmlException::VALIDATION_ERROR, lineNumber, message)
273 XmlValidationError::XmlValidationError(
275 MessageLoaderParms& msgParms)
276 : XmlException(XmlException::VALIDATION_ERROR, lineNumber, msgParms)
281 ////////////////////////////////////////////////////////////////////////////////
285 ////////////////////////////////////////////////////////////////////////////////
287 XmlSemanticError::XmlSemanticError(
289 const String& message)
290 : XmlException(XmlException::SEMANTIC_ERROR, lineNumber, message)
295 XmlSemanticError::XmlSemanticError(
297 MessageLoaderParms& msgParms)
298 : XmlException(XmlException::SEMANTIC_ERROR, lineNumber, msgParms)
303 ////////////////////////////////////////////////////////////////////////////////
307 ////////////////////////////////////////////////////////////////////////////////
309 XmlParser::XmlParser(char* text, XmlNamespace* ns)
314 _supportedNamespaces(ns),
315 // Start valid indexes with -2. -1 is reserved for not found.
316 _currentUnsupportedNSType(-2)
320 inline void _skipWhitespace(Uint32& line, char*& p)
322 while (*p && _isspace(*p))
331 #if defined(PEGASUS_PLATFORM_WIN64_IA64_MSVC) || \
332 defined(PEGASUS_PLATFORM_WIN64_X86_64_MSVC)
333 #pragma optimize( "", off )
335 static int _getEntityRef(char*& p)
337 if ((p[0] == 'g') && (p[1] == 't') && (p[2] == ';'))
343 if ((p[0] == 'l') && (p[1] == 't') && (p[2] == ';'))
349 if ((p[0] == 'a') && (p[1] == 'p') && (p[2] == 'o') && (p[3] == 's') &&
356 if ((p[0] == 'q') && (p[1] == 'u') && (p[2] == 'o') && (p[3] == 't') &&
363 if ((p[0] == 'a') && (p[1] == 'm') && (p[2] == 'p') && (p[3] == ';'))
371 #if defined(PEGASUS_PLATFORM_WIN64_IA64_MSVC) || \
372 defined(PEGASUS_PLATFORM_WIN64_X86_64_MSVC)
373 #pragma optimize( "", on )
376 static inline int _getCharRef(char*& p)
385 ch = strtoul(++p, &end, 16);
389 ch = strtoul(p, &end, 10);
392 if ((end == p) || (*end != ';') || (ch > 255))
397 if ((hex && (end - p > 4)) || (!hex && (end - p > 5)))
407 // Parse an entity reference or a character reference
408 static inline int _getRef(Uint32 line, char*& p)
414 ch = _getCharRef(++p);
418 ch = _getEntityRef(p);
423 throw XmlException(XmlException::MALFORMED_REFERENCE, line);
429 static inline void _normalizeElementValue(
434 // Process one character at a time:
439 while (*p && (*p != '<'))
443 // Trim whitespace from the end of the value, but do not compress
444 // whitespace within the value.
446 const char* start = p;
453 _skipWhitespace(line, p);
455 if (*p && (*p != '<'))
457 // Transfer internal whitespace to q without compressing it.
458 const char* i = start;
466 // Do not transfer trailing whitespace to q.
472 // Process an entity reference or a character reference.
474 *q++ = _getRef(line, ++p);
482 // If q got behind p, it is safe and necessary to null-terminate q
488 textLen = (Uint32)(q - start);
491 static inline void _normalizeAttributeValue(
497 // Skip over leading whitespace:
499 _skipWhitespace(line, p);
502 // Process one character at a time:
506 while (*p && (*p != end_char))
510 // Compress sequences of whitespace characters to a single space
511 // character. Update line number when newlines encountered.
520 _skipWhitespace(line, p);
524 // Process an entity reference or a character reference.
526 *q++ = _getRef(line, ++p);
534 // Remove single trailing whitespace (consecutive whitespaces already
535 // compressed above). Since p >= q, we can tell if we need to strip a
536 // trailing space from q by looking at the end of p. We must not look at
537 // the last character of p, though, if p is an empty string.
538 Boolean adjust_q = (p != start) && _isspace(p[-1]);
540 // We encountered a the end_char or a zero-terminator.
549 // If q got behind p, it is safe and necessary to null-terminate q
557 Boolean XmlParser::next(
559 Boolean includeComment)
561 if (!_putBackStack.isEmpty())
563 entry = _putBackStack.top();
568 // If a character was overwritten with a null-terminator the last
569 // time this routine was called, then put back that character. Before
570 // exiting of course, restore the null-terminator.
572 char* nullTerminator = 0;
574 if (_restoreChar && !*_current)
576 nullTerminator = _current;
577 *_current = _restoreChar;
581 entry.attributes.clear();
583 if (_supportedNamespaces)
585 // Remove namespaces of a deeper scope level from the stack.
586 while (!_nameSpaces.isEmpty() &&
587 _nameSpaces.top().scopeLevel > _stack.size())
593 // Loop until we are done with comments if includeComment is false.
596 // Skip over any whitespace:
597 _skipWhitespace(_line, _current);
602 *nullTerminator = '\0';
604 if (!_stack.isEmpty())
605 throw XmlException(XmlException::UNCLOSED_TAGS, _line);
610 // Either a "<...>" or content begins next:
612 if (*_current == '<')
615 _getElement(_current, entry);
618 *nullTerminator = '\0';
620 if (entry.type == XmlEntry::START_TAG)
622 if (_stack.isEmpty() && _foundRoot)
623 throw XmlException(XmlException::MULTIPLE_ROOTS, _line);
626 _stack.push((char*)entry.text);
628 else if (entry.type == XmlEntry::END_TAG)
630 if (_stack.isEmpty())
631 throw XmlException(XmlException::START_END_MISMATCH, _line);
633 if (strcmp(_stack.top(), entry.text) != 0)
634 throw XmlException(XmlException::START_END_MISMATCH, _line);
641 // Normalize the content:
643 char* start = _current;
645 _normalizeElementValue(_line, _current, textLen);
649 entry.type = XmlEntry::CONTENT;
651 entry.textLen = textLen;
653 // Overwrite '<' with a null character (temporarily).
655 _restoreChar = *_current;
659 *nullTerminator = '\0';
661 } while (!includeComment && entry.type == XmlEntry::COMMENT);
663 if (_supportedNamespaces &&
664 (entry.type == XmlEntry::START_TAG ||
665 entry.type == XmlEntry::EMPTY_TAG ||
666 entry.type == XmlEntry::END_TAG))
668 // Determine the namespace type for this entry
670 if (entry.type == XmlEntry::START_TAG ||
671 entry.type == XmlEntry::EMPTY_TAG)
673 // Process namespace declarations and determine the namespace type
674 // for the attributes.
676 Uint32 scopeLevel = _stack.size();
677 if (entry.type == XmlEntry::EMPTY_TAG)
679 // Empty tags are deeper scope, but not pushed onto the stack
683 for (Uint32 i = 0, n = entry.attributes.size(); i < n; i++)
685 XmlAttribute& attr = entry.attributes[i];
686 if ((strncmp(attr.name, "xmlns:", 6) == 0) ||
687 (strcmp(attr.name, "xmlns") == 0))
689 // Process a namespace declaration
691 if (attr.name[5] == ':')
693 ns.localName = attr.localName;
697 // Default name space has no local name
700 ns.extendedName = attr.value;
701 ns.scopeLevel = scopeLevel;
702 ns.type = _getSupportedNamespaceType(ns.extendedName);
704 // If the namespace is not supported, assign it a unique
705 // negative identifier.
708 ns.type = _currentUnsupportedNSType--;
711 _nameSpaces.push(ns);
715 // Get the namespace type for this attribute.
716 attr.nsType = _getNamespaceType(attr.name);
721 entry.nsType = _getNamespaceType(entry.text);
731 // Get the namespace type of the given tag
732 int XmlParser::_getNamespaceType(const char* tag)
734 const char* pos = strchr(tag, ':');
736 // If ':' is not found, the tag is not namespace qualified and we
737 // need to look for the default name space.
739 // Search the namespace stack from the top
740 for (Sint32 i = _nameSpaces.size() - 1; i >=0; i--)
742 // If ':' is found, look for the name space with the matching
744 if ((pos && _nameSpaces[i].localName &&
745 !strncmp(_nameSpaces[i].localName, tag, pos - tag)) ||
746 // ... otherwise look for the default name space. It's the
747 // one with localName set to NULL
748 (!pos && !_nameSpaces[i].localName))
750 return _nameSpaces[i].type;
754 // If the tag is namespace qualified, but the name space has not been
755 // declared, it's malformed XML and we must throw an exception.
756 // Note: The "xml" namespace is specifically defined by the W3C as a
757 // reserved prefix ("http://www.w3.org/XML/1998/namespace").
758 if (pos && (strncmp(tag, "xml:", 4) != 0))
760 throw XmlException(XmlException::UNDECLARED_NAMESPACE, _line);
763 // Otherwise it's OK not to have a name space.
767 // Given the extended namespace name, find it in the table of supported
768 // namespaces and return its type.
769 int XmlParser::_getSupportedNamespaceType(const char* extendedName)
772 _supportedNamespaces[i].localName != 0;
775 PEGASUS_ASSERT(_supportedNamespaces[i].type == i);
776 if (!strcmp(_supportedNamespaces[i].extendedName, extendedName))
778 return _supportedNamespaces[i].type;
784 XmlNamespace* XmlParser::getNamespace(int nsType)
786 for (Sint32 i = _nameSpaces.size() - 1; i >=0; i--)
788 if (_nameSpaces[i].type == nsType)
790 return &_nameSpaces[i];
796 void XmlParser::putBack(XmlEntry& entry)
798 _putBackStack.push(entry);
801 XmlParser::~XmlParser()
806 // A-Za-z0-9_-. (Note that ':' is not included and must be checked separately)
807 static unsigned char _isInnerElementChar[] =
809 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
810 0,0,0,0,0,0,0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,
811 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
812 1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
813 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
814 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
815 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
818 inline Boolean _getQName(char*& p, const char*& localName)
822 if (!CharSet::isAlNumUnder(Uint8(*p)))
827 // No explicit test for NULL termination is needed.
828 // On position 0 of the array false is returned.
829 while (_isInnerElementChar[Uint8(*p)])
832 // We've validated the prefix, now validate the local name
837 if (!CharSet::isAlNumUnder(Uint8(*p)))
841 // No explicit test for NULL termination is needed.
842 // On position 0 of the array false is returned.
843 while (_isInnerElementChar[Uint8(*p)])
850 Boolean XmlParser::_getElementName(char*& p, const char*& localName)
852 if (!_getQName(p, localName))
853 throw XmlException(XmlException::BAD_START_TAG, _line);
855 // The next character must be a space:
860 _skipWhitespace(_line, p);
872 Boolean XmlParser::_getOpenElementName(
874 const char*& localName,
875 Boolean& openCloseElement)
877 openCloseElement = false;
879 if (!_getQName(p, localName))
880 throw XmlException(XmlException::BAD_START_TAG, _line);
882 // The next character must be a space:
887 _skipWhitespace(_line, p);
896 if (p[0] == '/' && p[1] == '>')
898 openCloseElement = true;
907 void XmlParser::_getAttributeNameAndEqual(char*& p, const char*& localName)
909 if (!_getQName(p, localName))
910 throw XmlException(XmlException::BAD_ATTRIBUTE_NAME, _line);
914 _skipWhitespace(_line, p);
917 throw XmlException(XmlException::BAD_ATTRIBUTE_NAME, _line);
921 _skipWhitespace(_line, p);
926 void XmlParser::_getComment(char*& p)
928 // Now p points to first non-whitespace character beyond "<--" sequence:
932 if (p[0] == '-' && p[1] == '-')
937 XmlException::MINUS_MINUS_IN_COMMENT, _line);
940 // Find end of comment (excluding whitespace):
948 // If it got this far, then the comment is unterminated:
950 throw XmlException(XmlException::UNTERMINATED_COMMENT, _line);
953 void XmlParser::_getCData(char*& p)
955 // At this point p points one past "<![CDATA[" sequence:
959 if (p[0] == ']' && p[1] == ']' && p[2] == '>')
969 // If it got this far, then the comment is unterminated:
971 throw XmlException(XmlException::UNTERMINATED_CDATA, _line);
974 void XmlParser::_getDocType(char*& p)
976 // Just ignore the DOCTYPE command for now:
978 for (; *p && *p != '>'; p++)
985 throw XmlException(XmlException::UNTERMINATED_DOCTYPE, _line);
990 void XmlParser::_getElement(char*& p, XmlEntry& entry)
992 //--------------------------------------------------------------------------
993 // Get the element name (expect one of these: '?', '!', [A-Za-z_])
994 //--------------------------------------------------------------------------
998 entry.type = XmlEntry::XML_DECLARATION;
1001 if (_getElementName(p, entry.localName))
1008 // Expect a comment or CDATA:
1010 if (p[0] == '-' && p[1] == '-')
1013 entry.type = XmlEntry::COMMENT;
1018 else if (memcmp(p, "[CDATA[", 7) == 0)
1021 entry.type = XmlEntry::CDATA;
1024 entry.textLen = strlen(entry.text);
1027 else if (memcmp(p, "DOCTYPE", 7) == 0)
1029 entry.type = XmlEntry::DOCTYPE;
1034 throw(XmlException(XmlException::EXPECTED_COMMENT_OR_CDATA, _line));
1038 entry.type = XmlEntry::END_TAG;
1041 if (!_getElementName(p, entry.localName))
1042 throw(XmlException(XmlException::BAD_END_TAG, _line));
1046 else if (CharSet::isAlphaUnder(Uint8(*p)))
1048 entry.type = XmlEntry::START_TAG;
1051 Boolean openCloseElement = false;
1053 if (_getOpenElementName(p, entry.localName, openCloseElement))
1055 if (openCloseElement)
1056 entry.type = XmlEntry::EMPTY_TAG;
1061 throw XmlException(XmlException::BAD_START_TAG, _line);
1063 //--------------------------------------------------------------------------
1064 // Grab all the attributes:
1065 //--------------------------------------------------------------------------
1069 if (entry.type == XmlEntry::XML_DECLARATION)
1071 if (p[0] == '?' && p[1] == '>')
1077 else if (entry.type == XmlEntry::START_TAG && p[0] == '/' && p[1] =='>')
1079 entry.type = XmlEntry::EMPTY_TAG;
1092 _getAttributeNameAndEqual(p, attr.localName);
1094 // Get the attribute value (e.g., "some value")
1096 if ((*p != '"') && (*p != '\''))
1098 throw XmlException(XmlException::BAD_ATTRIBUTE_VALUE, _line);
1104 _normalizeAttributeValue(_line, p, quote, start);
1109 throw XmlException(XmlException::BAD_ATTRIBUTE_VALUE, _line);
1112 // Overwrite the closing quote with a null-terminator:
1117 if (entry.type == XmlEntry::XML_DECLARATION)
1119 // The next thing must a space or a "?>":
1121 if (!(p[0] == '?' && p[1] == '>') && !_isspace(*p))
1124 XmlException::BAD_ATTRIBUTE_VALUE, _line);
1127 else if (!(*p == '>' || (p[0] == '/' && p[1] == '>') || _isspace(*p)))
1129 // The next thing must be a space or a '>':
1131 throw XmlException(XmlException::BAD_ATTRIBUTE_VALUE, _line);
1134 _skipWhitespace(_line, p);
1136 entry.attributes.append(attr);
1140 static const char* _typeStrings[] =
1152 void XmlEntry::print() const
1154 PEGASUS_STD(cout) << "=== " << _typeStrings[type] << " ";
1156 Boolean needQuotes = type == XmlEntry::CDATA || type == XmlEntry::CONTENT;
1159 PEGASUS_STD(cout) << "\"";
1164 PEGASUS_STD(cout) << "\"";
1166 PEGASUS_STD(cout) << '\n';
1168 for (Uint32 i = 0, n = attributes.size(); i < n; i++)
1170 PEGASUS_STD(cout) << " " << attributes[i].name << "=\"";
1171 _printValue(attributes[i].value);
1172 PEGASUS_STD(cout) << "\"" << PEGASUS_STD(endl);
1176 const XmlAttribute* XmlEntry::findAttribute(
1177 const char* name) const
1179 for (Uint32 i = 0, n = attributes.size(); i < n; i++)
1181 if (strcmp(attributes[i].name, name) == 0)
1182 return &attributes[i];
1188 const XmlAttribute* XmlEntry::findAttribute(
1190 const char* name) const
1192 for (Uint32 i = 0, n = attributes.size(); i < n; i++)
1194 if ((attributes[i].nsType == attrNsType) &&
1195 (strcmp(attributes[i].localName, name) == 0))
1197 return &attributes[i];
1204 // Find first non-whitespace character (set first) and last non-whitespace
1205 // character (set last one past this). For example, consider this string:
1209 // The first pointer would point to '8' and the last pointer woudl point one
1212 static void _findEnds(
1219 while (_isspace(*first))
1228 last = first + strlen(first);
1230 while (last != first && _isspace(last[-1]))
1234 Boolean XmlEntry::getAttributeValue(
1236 Uint32& value) const
1238 const XmlAttribute* attr = findAttribute(name);
1245 _findEnds(attr->value, first, last);
1248 long tmp = strtol(first, &end, 10);
1250 if (!end || end != last)
1253 value = Uint32(tmp);
1257 Boolean XmlEntry::getAttributeValue(
1259 Real32& value) const
1261 const XmlAttribute* attr = findAttribute(name);
1268 _findEnds(attr->value, first, last);
1271 double tmp = strtod(first, &end);
1273 if (!end || end != last)
1276 value = static_cast<Real32>(tmp);
1280 Boolean XmlEntry::getAttributeValue(
1282 const char*& value) const
1284 const XmlAttribute* attr = findAttribute(name);
1289 value = attr->value;
1293 Boolean XmlEntry::getAttributeValue(const char* name, String& value) const
1297 if (!getAttributeValue(name, tmp))
1300 value = String(tmp);
1304 void XmlAppendCString(Buffer& out, const char* str)
1306 out.append(str, static_cast<Uint32>(strlen(str)));
1309 PEGASUS_NAMESPACE_END