1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either of the GNU General Public License Version 2 or later (the "GPL"),
26 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : /*
39 : * A class for managing namespace IDs and mapping back and forth
40 : * between namespace IDs and namespace URIs.
41 : */
42 :
43 : #include "nscore.h"
44 : #include "nsINameSpaceManager.h"
45 : #include "nsAutoPtr.h"
46 : #include "nsINodeInfo.h"
47 : #include "nsCOMArray.h"
48 : #include "nsTArray.h"
49 : #include "nsContentCreatorFunctions.h"
50 : #include "nsDataHashtable.h"
51 : #include "nsString.h"
52 :
53 : #ifdef MOZ_XTF
54 : #include "nsIServiceManager.h"
55 : #include "nsIXTFService.h"
56 : #include "nsContentUtils.h"
57 : static NS_DEFINE_CID(kXTFServiceCID, NS_XTFSERVICE_CID);
58 : #endif
59 :
60 : using namespace mozilla;
61 : using namespace mozilla::dom;
62 :
63 : #define kXMLNSNameSpaceURI "http://www.w3.org/2000/xmlns/"
64 : #define kXMLNameSpaceURI "http://www.w3.org/XML/1998/namespace"
65 : #define kXHTMLNameSpaceURI "http://www.w3.org/1999/xhtml"
66 : #define kXLinkNameSpaceURI "http://www.w3.org/1999/xlink"
67 : #define kXSLTNameSpaceURI "http://www.w3.org/1999/XSL/Transform"
68 : #define kXBLNameSpaceURI "http://www.mozilla.org/xbl"
69 : #define kMathMLNameSpaceURI "http://www.w3.org/1998/Math/MathML"
70 : #define kRDFNameSpaceURI "http://www.w3.org/1999/02/22-rdf-syntax-ns#"
71 : #define kXULNameSpaceURI "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
72 : #define kSVGNameSpaceURI "http://www.w3.org/2000/svg"
73 : #define kXMLEventsNameSpaceURI "http://www.w3.org/2001/xml-events"
74 :
75 : class nsNameSpaceKey : public PLDHashEntryHdr
76 : {
77 : public:
78 : typedef const nsAString* KeyType;
79 : typedef const nsAString* KeyTypePointer;
80 :
81 22767 : nsNameSpaceKey(KeyTypePointer aKey) : mKey(aKey)
82 : {
83 22767 : }
84 : nsNameSpaceKey(const nsNameSpaceKey& toCopy) : mKey(toCopy.mKey)
85 : {
86 : }
87 :
88 : KeyType GetKey() const
89 : {
90 : return mKey;
91 : }
92 74664 : bool KeyEquals(KeyType aKey) const
93 : {
94 74664 : return mKey->Equals(*aKey);
95 : }
96 :
97 104754 : static KeyTypePointer KeyToPointer(KeyType aKey)
98 : {
99 104754 : return aKey;
100 : }
101 104754 : static PLDHashNumber HashKey(KeyTypePointer aKey) {
102 104754 : return HashString(*aKey);
103 : }
104 :
105 : enum {
106 : ALLOW_MEMMOVE = true
107 : };
108 :
109 : private:
110 : const nsAString* mKey;
111 : };
112 :
113 1404 : class NameSpaceManagerImpl : public nsINameSpaceManager {
114 : public:
115 2806 : virtual ~NameSpaceManagerImpl()
116 1403 : {
117 5612 : }
118 :
119 : NS_DECL_ISUPPORTS
120 :
121 : nsresult Init();
122 :
123 : nsresult RegisterNameSpace(const nsAString& aURI, PRInt32& aNameSpaceID);
124 :
125 : nsresult GetNameSpaceURI(PRInt32 aNameSpaceID, nsAString& aURI);
126 : PRInt32 GetNameSpaceID(const nsAString& aURI);
127 :
128 : bool HasElementCreator(PRInt32 aNameSpaceID);
129 :
130 : private:
131 : nsresult AddNameSpace(const nsAString& aURI, const PRInt32 aNameSpaceID);
132 :
133 : nsDataHashtable<nsNameSpaceKey,PRInt32> mURIToIDTable;
134 : nsTArray< nsAutoPtr<nsString> > mURIArray;
135 : };
136 :
137 : static NameSpaceManagerImpl* sNameSpaceManager = nsnull;
138 :
139 9826 : NS_IMPL_ISUPPORTS1(NameSpaceManagerImpl, nsINameSpaceManager)
140 :
141 1404 : nsresult NameSpaceManagerImpl::Init()
142 : {
143 1404 : nsresult rv = mURIToIDTable.Init(32);
144 1404 : NS_ENSURE_SUCCESS(rv, rv);
145 :
146 : #define REGISTER_NAMESPACE(uri, id) \
147 : rv = AddNameSpace(NS_LITERAL_STRING(uri), id); \
148 : NS_ENSURE_SUCCESS(rv, rv)
149 :
150 : // Need to be ordered according to ID.
151 1404 : REGISTER_NAMESPACE(kXMLNSNameSpaceURI, kNameSpaceID_XMLNS);
152 1404 : REGISTER_NAMESPACE(kXMLNameSpaceURI, kNameSpaceID_XML);
153 1404 : REGISTER_NAMESPACE(kXHTMLNameSpaceURI, kNameSpaceID_XHTML);
154 1404 : REGISTER_NAMESPACE(kXLinkNameSpaceURI, kNameSpaceID_XLink);
155 1404 : REGISTER_NAMESPACE(kXSLTNameSpaceURI, kNameSpaceID_XSLT);
156 1404 : REGISTER_NAMESPACE(kXBLNameSpaceURI, kNameSpaceID_XBL);
157 1404 : REGISTER_NAMESPACE(kMathMLNameSpaceURI, kNameSpaceID_MathML);
158 1404 : REGISTER_NAMESPACE(kRDFNameSpaceURI, kNameSpaceID_RDF);
159 1404 : REGISTER_NAMESPACE(kXULNameSpaceURI, kNameSpaceID_XUL);
160 1404 : REGISTER_NAMESPACE(kSVGNameSpaceURI, kNameSpaceID_SVG);
161 1404 : REGISTER_NAMESPACE(kXMLEventsNameSpaceURI, kNameSpaceID_XMLEvents);
162 :
163 : #undef REGISTER_NAMESPACE
164 :
165 1404 : return NS_OK;
166 : }
167 :
168 : nsresult
169 81973 : NameSpaceManagerImpl::RegisterNameSpace(const nsAString& aURI,
170 : PRInt32& aNameSpaceID)
171 : {
172 81973 : if (aURI.IsEmpty()) {
173 18 : aNameSpaceID = kNameSpaceID_None; // xmlns="", see bug 75700 for details
174 :
175 18 : return NS_OK;
176 : }
177 :
178 81955 : nsresult rv = NS_OK;
179 81955 : if (!mURIToIDTable.Get(&aURI, &aNameSpaceID)) {
180 7323 : aNameSpaceID = mURIArray.Length() + 1; // id is index + 1
181 :
182 7323 : rv = AddNameSpace(aURI, aNameSpaceID);
183 7323 : if (NS_FAILED(rv)) {
184 0 : aNameSpaceID = kNameSpaceID_Unknown;
185 : }
186 : }
187 :
188 81955 : NS_POSTCONDITION(aNameSpaceID >= -1, "Bogus namespace ID");
189 :
190 81955 : return rv;
191 : }
192 :
193 : nsresult
194 23225 : NameSpaceManagerImpl::GetNameSpaceURI(PRInt32 aNameSpaceID, nsAString& aURI)
195 : {
196 23225 : NS_PRECONDITION(aNameSpaceID >= 0, "Bogus namespace ID");
197 :
198 23225 : PRInt32 index = aNameSpaceID - 1; // id is index + 1
199 23225 : if (index < 0 || index >= PRInt32(mURIArray.Length())) {
200 1850 : aURI.Truncate();
201 :
202 1850 : return NS_ERROR_ILLEGAL_VALUE;
203 : }
204 :
205 21375 : aURI = *mURIArray.ElementAt(index);
206 :
207 21375 : return NS_OK;
208 : }
209 :
210 : PRInt32
211 32 : NameSpaceManagerImpl::GetNameSpaceID(const nsAString& aURI)
212 : {
213 32 : if (aURI.IsEmpty()) {
214 0 : return kNameSpaceID_None; // xmlns="", see bug 75700 for details
215 : }
216 :
217 : PRInt32 nameSpaceID;
218 :
219 32 : if (mURIToIDTable.Get(&aURI, &nameSpaceID)) {
220 32 : NS_POSTCONDITION(nameSpaceID >= 0, "Bogus namespace ID");
221 32 : return nameSpaceID;
222 : }
223 :
224 0 : return kNameSpaceID_Unknown;
225 : }
226 :
227 : nsresult
228 37707 : NS_NewElement(nsIContent** aResult,
229 : already_AddRefed<nsINodeInfo> aNodeInfo, FromParser aFromParser)
230 : {
231 37707 : PRInt32 ns = aNodeInfo.get()->NamespaceID();
232 37707 : if (ns == kNameSpaceID_XHTML) {
233 791 : return NS_NewHTMLElement(aResult, aNodeInfo, aFromParser);
234 : }
235 : #ifdef MOZ_XUL
236 36916 : if (ns == kNameSpaceID_XUL) {
237 144 : return NS_NewXULElement(aResult, aNodeInfo);
238 : }
239 : #endif
240 36772 : if (ns == kNameSpaceID_MathML) {
241 0 : return NS_NewMathMLElement(aResult, aNodeInfo);
242 : }
243 36772 : if (ns == kNameSpaceID_SVG) {
244 0 : return NS_NewSVGElement(aResult, aNodeInfo, aFromParser);
245 : }
246 36772 : if (ns == kNameSpaceID_XMLEvents) {
247 0 : return NS_NewXMLEventsElement(aResult, aNodeInfo);
248 : }
249 : #ifdef MOZ_XTF
250 36772 : if (ns > kNameSpaceID_LastBuiltin) {
251 19537 : nsIXTFService* xtfService = nsContentUtils::GetXTFService();
252 19537 : NS_ASSERTION(xtfService, "could not get xtf service");
253 39074 : if (xtfService &&
254 19537 : NS_SUCCEEDED(xtfService->CreateElement(aResult, aNodeInfo)))
255 2 : return NS_OK;
256 : }
257 : #endif
258 36770 : return NS_NewXMLElement(aResult, aNodeInfo);
259 : }
260 :
261 : bool
262 0 : NameSpaceManagerImpl::HasElementCreator(PRInt32 aNameSpaceID)
263 : {
264 : return aNameSpaceID == kNameSpaceID_XHTML ||
265 : #ifdef MOZ_XUL
266 : aNameSpaceID == kNameSpaceID_XUL ||
267 : #endif
268 : aNameSpaceID == kNameSpaceID_MathML ||
269 : aNameSpaceID == kNameSpaceID_SVG ||
270 : aNameSpaceID == kNameSpaceID_XMLEvents ||
271 0 : false;
272 : }
273 :
274 22767 : nsresult NameSpaceManagerImpl::AddNameSpace(const nsAString& aURI,
275 : const PRInt32 aNameSpaceID)
276 : {
277 22767 : if (aNameSpaceID < 0) {
278 : // We've wrapped... Can't do anything else here; just bail.
279 0 : return NS_ERROR_OUT_OF_MEMORY;
280 : }
281 :
282 22767 : NS_ASSERTION(aNameSpaceID - 1 == (PRInt32) mURIArray.Length(),
283 : "BAD! AddNameSpace not called in right order!");
284 :
285 22767 : nsString* uri = new nsString(aURI);
286 22767 : if (!uri || !mURIArray.AppendElement(uri)) {
287 0 : delete uri;
288 0 : return NS_ERROR_OUT_OF_MEMORY;
289 : }
290 :
291 22767 : if (!mURIToIDTable.Put(uri, aNameSpaceID)) {
292 0 : mURIArray.RemoveElementAt(aNameSpaceID - 1);
293 :
294 0 : return NS_ERROR_OUT_OF_MEMORY;
295 : }
296 :
297 22767 : return NS_OK;
298 : }
299 :
300 : nsresult
301 1404 : NS_GetNameSpaceManager(nsINameSpaceManager** aInstancePtrResult)
302 : {
303 1404 : NS_ENSURE_ARG_POINTER(aInstancePtrResult);
304 :
305 1404 : if (!sNameSpaceManager) {
306 2808 : nsCOMPtr<NameSpaceManagerImpl> manager = new NameSpaceManagerImpl();
307 1404 : if (manager) {
308 1404 : nsresult rv = manager->Init();
309 1404 : if (NS_SUCCEEDED(rv)) {
310 1404 : manager.swap(sNameSpaceManager);
311 : }
312 : }
313 : }
314 :
315 1404 : *aInstancePtrResult = sNameSpaceManager;
316 1404 : NS_ENSURE_TRUE(sNameSpaceManager, NS_ERROR_OUT_OF_MEMORY);
317 :
318 1404 : NS_ADDREF(*aInstancePtrResult);
319 :
320 1404 : return NS_OK;
321 : }
322 :
323 : void
324 1403 : NS_NameSpaceManagerShutdown()
325 : {
326 1403 : NS_IF_RELEASE(sNameSpaceManager);
327 1403 : }
|