|
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/. */ |
|
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 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 } |
|
29 |
|
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; |
|
36 |
|
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 } |
|
48 |
|
49 //------------------------------/ |
|
50 //- Implementation of XMLUtils -/ |
|
51 //------------------------------/ |
|
52 |
|
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 */ |
|
64 |
|
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 } |
|
78 |
|
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 } |
|
87 |
|
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 } |
|
107 |
|
108 *aLocalName = NS_NewAtom(Substring(nameStart, nameEnd)).take(); |
|
109 |
|
110 return *aLocalName ? NS_OK : NS_ERROR_OUT_OF_MEMORY; |
|
111 } |
|
112 |
|
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 } |
|
123 |
|
124 if (colon) { |
|
125 const char16_t *end; |
|
126 qName.EndReading(end); |
|
127 |
|
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 } |
|
135 |
|
136 return NS_OK; |
|
137 } |
|
138 |
|
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 } |
|
154 |
|
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(); |
|
165 |
|
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 } |
|
186 |
|
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 } |
|
193 |
|
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()); |
|
209 |
|
210 return false; |
|
211 } |