Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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/. */
6 /*
7 * XML utility classes
8 */
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"
19 nsresult
20 txExpandedName::init(const nsAString& aQName, txNamespaceMap* aResolver,
21 bool aUseDefault)
22 {
23 const nsAFlatString& qName = PromiseFlatString(aQName);
24 const char16_t* colon;
25 bool valid = XMLUtils::isValidQName(qName, &colon);
26 if (!valid) {
27 return NS_ERROR_FAILURE;
28 }
30 if (colon) {
31 nsCOMPtr<nsIAtom> prefix = do_GetAtom(Substring(qName.get(), colon));
32 int32_t namespaceID = aResolver->lookupNamespace(prefix);
33 if (namespaceID == kNameSpaceID_Unknown)
34 return NS_ERROR_FAILURE;
35 mNamespaceID = namespaceID;
37 const char16_t *end;
38 qName.EndReading(end);
39 mLocalName = do_GetAtom(Substring(colon + 1, end));
40 }
41 else {
42 mNamespaceID = aUseDefault ? aResolver->lookupNamespace(nullptr) :
43 kNameSpaceID_None;
44 mLocalName = do_GetAtom(aQName);
45 }
46 return NS_OK;
47 }
49 //------------------------------/
50 //- Implementation of XMLUtils -/
51 //------------------------------/
53 // static
54 nsresult
55 XMLUtils::splitExpatName(const char16_t *aExpatName, nsIAtom **aPrefix,
56 nsIAtom **aLocalName, int32_t* aNameSpaceID)
57 {
58 /**
59 * Expat can send the following:
60 * localName
61 * namespaceURI<separator>localName
62 * namespaceURI<separator>localName<separator>prefix
63 */
65 const char16_t *uriEnd = nullptr;
66 const char16_t *nameEnd = nullptr;
67 const char16_t *pos;
68 for (pos = aExpatName; *pos; ++pos) {
69 if (*pos == kExpatSeparatorChar) {
70 if (uriEnd) {
71 nameEnd = pos;
72 }
73 else {
74 uriEnd = pos;
75 }
76 }
77 }
79 const char16_t *nameStart;
80 if (uriEnd) {
81 *aNameSpaceID =
82 txNamespaceManager::getNamespaceID(nsDependentSubstring(aExpatName,
83 uriEnd));
84 if (*aNameSpaceID == kNameSpaceID_Unknown) {
85 return NS_ERROR_FAILURE;
86 }
88 nameStart = (uriEnd + 1);
89 if (nameEnd) {
90 const char16_t *prefixStart = nameEnd + 1;
91 *aPrefix = NS_NewAtom(Substring(prefixStart, pos)).take();
92 if (!*aPrefix) {
93 return NS_ERROR_OUT_OF_MEMORY;
94 }
95 }
96 else {
97 nameEnd = pos;
98 *aPrefix = nullptr;
99 }
100 }
101 else {
102 *aNameSpaceID = kNameSpaceID_None;
103 nameStart = aExpatName;
104 nameEnd = pos;
105 *aPrefix = nullptr;
106 }
108 *aLocalName = NS_NewAtom(Substring(nameStart, nameEnd)).take();
110 return *aLocalName ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
111 }
113 nsresult
114 XMLUtils::splitQName(const nsAString& aName, nsIAtom** aPrefix,
115 nsIAtom** aLocalName)
116 {
117 const nsAFlatString& qName = PromiseFlatString(aName);
118 const char16_t* colon;
119 bool valid = XMLUtils::isValidQName(qName, &colon);
120 if (!valid) {
121 return NS_ERROR_FAILURE;
122 }
124 if (colon) {
125 const char16_t *end;
126 qName.EndReading(end);
128 *aPrefix = NS_NewAtom(Substring(qName.get(), colon)).take();
129 *aLocalName = NS_NewAtom(Substring(colon + 1, end)).take();
130 }
131 else {
132 *aPrefix = nullptr;
133 *aLocalName = NS_NewAtom(aName).take();
134 }
136 return NS_OK;
137 }
139 /**
140 * Returns true if the given string has only whitespace characters
141 */
142 bool XMLUtils::isWhitespace(const nsAFlatString& aText)
143 {
144 nsAFlatString::const_char_iterator start, end;
145 aText.BeginReading(start);
146 aText.EndReading(end);
147 for ( ; start != end; ++start) {
148 if (!isWhitespace(*start)) {
149 return false;
150 }
151 }
152 return true;
153 }
155 /**
156 * Normalizes the value of a XML processing instruction
157 **/
158 void XMLUtils::normalizePIValue(nsAString& piValue)
159 {
160 nsAutoString origValue(piValue);
161 uint32_t origLength = origValue.Length();
162 uint32_t conversionLoop = 0;
163 char16_t prevCh = 0;
164 piValue.Truncate();
166 while (conversionLoop < origLength) {
167 char16_t ch = origValue.CharAt(conversionLoop);
168 switch (ch) {
169 case '>':
170 {
171 if (prevCh == '?') {
172 piValue.Append(char16_t(' '));
173 }
174 break;
175 }
176 default:
177 {
178 break;
179 }
180 }
181 piValue.Append(ch);
182 prevCh = ch;
183 ++conversionLoop;
184 }
185 }
187 //static
188 bool XMLUtils::isValidQName(const nsAFlatString& aQName,
189 const char16_t** aColon)
190 {
191 return NS_SUCCEEDED(nsContentUtils::CheckQName(aQName, true, aColon));
192 }
194 //static
195 bool XMLUtils::getXMLSpacePreserve(const txXPathNode& aNode)
196 {
197 nsAutoString value;
198 txXPathTreeWalker walker(aNode);
199 do {
200 if (walker.getAttr(nsGkAtoms::space, kNameSpaceID_XML, value)) {
201 if (TX_StringEqualsAtom(value, nsGkAtoms::preserve)) {
202 return true;
203 }
204 if (TX_StringEqualsAtom(value, nsGkAtoms::_default)) {
205 return false;
206 }
207 }
208 } while (walker.moveToParent());
210 return false;
211 }