1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 /*
7 * XML utility classes
8 */
9
10 #include "txXMLUtils.h"
11 #include "nsString.h"
12 #include "nsReadableUtils.h"
13 #include "nsGkAtoms.h"
14 #include "txStringUtils.h"
15 #include "txNamespaceMap.h"
16 #include "txXPathTreeWalker.h"
17 #include "nsContentUtils.h"
18
19 //------------------------------/
20 //- Implementation of XMLUtils -/
21 //------------------------------/
22
23 // static
splitExpatName(const char16_t * aExpatName,nsAtom ** aPrefix,nsAtom ** aLocalName,int32_t * aNameSpaceID)24 nsresult XMLUtils::splitExpatName(const char16_t* aExpatName, nsAtom** aPrefix,
25 nsAtom** aLocalName, int32_t* aNameSpaceID) {
26 /**
27 * Expat can send the following:
28 * localName
29 * namespaceURI<separator>localName
30 * namespaceURI<separator>localName<separator>prefix
31 */
32
33 const char16_t* uriEnd = nullptr;
34 const char16_t* nameEnd = nullptr;
35 const char16_t* pos;
36 for (pos = aExpatName; *pos; ++pos) {
37 if (*pos == kExpatSeparatorChar) {
38 if (uriEnd) {
39 nameEnd = pos;
40 } else {
41 uriEnd = pos;
42 }
43 }
44 }
45
46 const char16_t* nameStart;
47 if (uriEnd) {
48 *aNameSpaceID = txNamespaceManager::getNamespaceID(
49 nsDependentSubstring(aExpatName, uriEnd));
50 if (*aNameSpaceID == kNameSpaceID_Unknown) {
51 return NS_ERROR_FAILURE;
52 }
53
54 nameStart = (uriEnd + 1);
55 if (nameEnd) {
56 const char16_t* prefixStart = nameEnd + 1;
57 *aPrefix = NS_Atomize(Substring(prefixStart, pos)).take();
58 if (!*aPrefix) {
59 return NS_ERROR_OUT_OF_MEMORY;
60 }
61 } else {
62 nameEnd = pos;
63 *aPrefix = nullptr;
64 }
65 } else {
66 *aNameSpaceID = kNameSpaceID_None;
67 nameStart = aExpatName;
68 nameEnd = pos;
69 *aPrefix = nullptr;
70 }
71
72 *aLocalName = NS_Atomize(Substring(nameStart, nameEnd)).take();
73
74 return *aLocalName ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
75 }
76
splitQName(const nsAString & aName,nsAtom ** aPrefix,nsAtom ** aLocalName)77 nsresult XMLUtils::splitQName(const nsAString& aName, nsAtom** aPrefix,
78 nsAtom** aLocalName) {
79 const char16_t* colon;
80 bool valid = XMLUtils::isValidQName(aName, &colon);
81 if (!valid) {
82 return NS_ERROR_FAILURE;
83 }
84
85 if (colon) {
86 const char16_t* end;
87 aName.EndReading(end);
88
89 *aPrefix = NS_Atomize(Substring(aName.BeginReading(), colon)).take();
90 *aLocalName = NS_Atomize(Substring(colon + 1, end)).take();
91 } else {
92 *aPrefix = nullptr;
93 *aLocalName = NS_Atomize(aName).take();
94 }
95
96 return NS_OK;
97 }
98
99 /**
100 * Returns true if the given string has only whitespace characters
101 */
isWhitespace(const nsAString & aText)102 bool XMLUtils::isWhitespace(const nsAString& aText) {
103 nsString::const_char_iterator start, end;
104 aText.BeginReading(start);
105 aText.EndReading(end);
106 for (; start != end; ++start) {
107 if (!isWhitespace(*start)) {
108 return false;
109 }
110 }
111 return true;
112 }
113
114 /**
115 * Normalizes the value of a XML processing instruction
116 **/
normalizePIValue(nsAString & piValue)117 void XMLUtils::normalizePIValue(nsAString& piValue) {
118 nsAutoString origValue(piValue);
119 uint32_t origLength = origValue.Length();
120 uint32_t conversionLoop = 0;
121 char16_t prevCh = 0;
122 piValue.Truncate();
123
124 while (conversionLoop < origLength) {
125 char16_t ch = origValue.CharAt(conversionLoop);
126 switch (ch) {
127 case '>': {
128 if (prevCh == '?') {
129 piValue.Append(char16_t(' '));
130 }
131 break;
132 }
133 default: {
134 break;
135 }
136 }
137 piValue.Append(ch);
138 prevCh = ch;
139 ++conversionLoop;
140 }
141 }
142
143 // static
isValidQName(const nsAString & aQName,const char16_t ** aColon)144 bool XMLUtils::isValidQName(const nsAString& aQName, const char16_t** aColon) {
145 return NS_SUCCEEDED(nsContentUtils::CheckQName(aQName, true, aColon));
146 }
147
148 // static
getXMLSpacePreserve(const txXPathNode & aNode)149 bool XMLUtils::getXMLSpacePreserve(const txXPathNode& aNode) {
150 nsAutoString value;
151 txXPathTreeWalker walker(aNode);
152 do {
153 if (walker.getAttr(nsGkAtoms::space, kNameSpaceID_XML, value)) {
154 if (TX_StringEqualsAtom(value, nsGkAtoms::preserve)) {
155 return true;
156 }
157 if (TX_StringEqualsAtom(value, nsGkAtoms::_default)) {
158 return false;
159 }
160 }
161 } while (walker.moveToParent());
162
163 return false;
164 }
165