Files
Mozilla/mozilla/content/base/src/nsNameSpaceManager.cpp

577 lines
17 KiB
C++

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Netscape Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the NPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the NPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nscore.h"
#include "nsINameSpaceManager.h"
#include "nsINameSpace.h"
#include "nsISupportsArray.h"
#include "nsIElementFactory.h"
#include "nsIServiceManager.h"
#include "nsHashtable.h"
#include "nsVoidArray.h"
#include "nsLayoutAtoms.h"
#include "nsString.h"
#include "nsCRT.h"
#include "nsContentCID.h"
extern nsresult NS_NewXMLElementFactory(nsIElementFactory** aResult);
static const char kXMLNSNameSpaceURI[] = "http://www.w3.org/2000/xmlns/";
static const char kXMLNameSpaceURI[] = "http://www.w3.org/XML/1998/namespace";
static const char kHTMLNameSpaceURI[] = "http://www.w3.org/TR/REC-html40"; // XXX?? "urn:w3-org-ns:HTML"??
// XXX To be removed: Bug 7834 ---
static const char kXHTMLNameSpaceURI[] = "http://www.w3.org/1999/xhtml";
static const char kXLinkNameSpaceURI[] = "http://www.w3.org/1999/xlink";
static const char kXSLTNameSpaceURI[] = "http://www.w3.org/1999/XSL/Transform";
static const char kXBLNameSpaceURI[] = "http://www.mozilla.org/xbl";
static const char kMathMLNameSpaceURI[] = "http://www.w3.org/1998/Math/MathML";
//-----------------------------------------------------------
// Name Space ID table support
static PRBool gNameSpaceManagerIsInitialized = PR_FALSE;
static nsHashtable* gURIToIDTable;
static nsVoidArray* gURIArray;
static nsISupportsArray* gElementFactoryArray;
#ifdef NS_DEBUG
static PRBool gNameSpaceManagerWasShutDown = PR_FALSE;
#endif
static void InitializeNameSpaceManager()
{
if (gNameSpaceManagerIsInitialized) {
return;
}
NS_ASSERTION(nsnull == gURIToIDTable, "already have URI table");
NS_ASSERTION(nsnull == gURIArray, "already have URI array");
gURIToIDTable = new nsHashtable();
gURIArray = new nsVoidArray();
nsString* xmlns = new nsString( NS_ConvertASCIItoUCS2(kXMLNSNameSpaceURI) );
nsString* xml = new nsString( NS_ConvertASCIItoUCS2(kXMLNameSpaceURI) );
nsString* xhtml = new nsString( NS_ConvertASCIItoUCS2(kXHTMLNameSpaceURI) );
nsString* xlink = new nsString( NS_ConvertASCIItoUCS2(kXLinkNameSpaceURI) );
nsString* html = new nsString( NS_ConvertASCIItoUCS2(kHTMLNameSpaceURI) );
nsString* xslt = new nsString( NS_ConvertASCIItoUCS2(kXSLTNameSpaceURI) );
nsString* xbl = new nsString(NS_ConvertASCIItoUCS2(kXBLNameSpaceURI));
nsString* mathml = new nsString(NS_ConvertASCIItoUCS2(kMathMLNameSpaceURI));
gURIArray->AppendElement(xmlns); // ordering here needs to match IDs
gURIArray->AppendElement(xml);
gURIArray->AppendElement(xhtml);
gURIArray->AppendElement(xlink);
gURIArray->AppendElement(html);
gURIArray->AppendElement(xslt);
gURIArray->AppendElement(xbl);
gURIArray->AppendElement(mathml);
nsStringKey xmlnsKey(*xmlns);
nsStringKey xmlKey(*xml);
nsStringKey xhtmlKey(*xhtml);
nsStringKey xlinkKey(*xlink);
nsStringKey htmlKey(*html);
nsStringKey xsltKey(*xslt);
nsStringKey xblKey(*xbl);
nsStringKey mathmlKey(*mathml);
gURIToIDTable->Put(&xmlnsKey, (void*)kNameSpaceID_XMLNS);
gURIToIDTable->Put(&xmlKey, (void*)kNameSpaceID_XML);
gURIToIDTable->Put(&xhtmlKey, (void*)kNameSpaceID_HTML);
gURIToIDTable->Put(&xlinkKey, (void*)kNameSpaceID_XLink);
gURIToIDTable->Put(&htmlKey, (void*)kNameSpaceID_HTML);
gURIToIDTable->Put(&xsltKey, (void*)kNameSpaceID_XSLT);
gURIToIDTable->Put(&xblKey, (void*)kNameSpaceID_XBL);
gURIToIDTable->Put(&mathmlKey, (void*)kNameSpaceID_MathML);
NS_NewISupportsArray(&gElementFactoryArray);
NS_ASSERTION(nsnull != gURIToIDTable, "no URI table");
NS_ASSERTION(nsnull != gURIArray, "no URI array");
NS_ASSERTION(nsnull != gElementFactoryArray, "no element factory array");
gNameSpaceManagerIsInitialized = PR_TRUE;
}
void NS_NameSpaceManagerShutdown()
{
delete gURIToIDTable;
PRInt32 index = gURIArray->Count();
while (0 < index--) {
nsString* str = (nsString*)gURIArray->ElementAt(index);
delete str;
}
delete gURIArray;
gURIToIDTable = nsnull;
gURIArray = nsnull;
NS_IF_RELEASE(gElementFactoryArray);
#ifdef NS_DEBUG
gNameSpaceManagerWasShutDown = PR_TRUE;
#endif
}
static PRInt32 FindNameSpaceID(const nsAString& aURI)
{
NS_ASSERTION(nsnull != gURIToIDTable, "no URI table");
nsStringKey key(aURI);
void* value = gURIToIDTable->Get(&key);
if (nsnull != value) {
return NS_PTR_TO_INT32(value);
}
return kNameSpaceID_Unknown;
}
static const nsString* FindNameSpaceURI(PRInt32 aID)
{
NS_ASSERTION(nsnull != gURIArray, "no URI array");
return (const nsString*)gURIArray->SafeElementAt(aID - 1);
}
//-----------------------------------------------------------
// Name Space
class NameSpaceImpl : public nsINameSpace {
public:
NameSpaceImpl(nsINameSpaceManager* aManager,
NameSpaceImpl* aParent,
nsIAtom* aPrefix,
const nsAString& aURI);
NameSpaceImpl(nsINameSpaceManager* aManager,
NameSpaceImpl* aParent,
nsIAtom* aPrefix,
PRInt32 aNameSpaceID);
virtual ~NameSpaceImpl();
NS_DECL_ISUPPORTS
NS_IMETHOD GetNameSpaceManager(nsINameSpaceManager*& aManager) const;
NS_IMETHOD GetNameSpaceID(PRInt32& aID) const;
NS_IMETHOD GetNameSpaceURI(nsAString& aURI) const;
NS_IMETHOD GetNameSpacePrefix(nsIAtom*& aPrefix) const;
NS_IMETHOD GetParentNameSpace(nsINameSpace*& aParent) const;
NS_IMETHOD FindNameSpace(nsIAtom* aPrefix, nsINameSpace*& aNameSpace) const;
NS_IMETHOD FindNameSpaceID(nsIAtom* aPrefix, PRInt32& aNameSpaceID) const;
NS_IMETHOD FindNameSpacePrefix(PRInt32 aNameSpaceID, nsIAtom*& aPrefix) const;
NS_IMETHOD CreateChildNameSpace(nsIAtom* aPrefix, const nsAString& aURI,
nsINameSpace*& aChildNameSpace);
NS_IMETHOD CreateChildNameSpace(nsIAtom* aPrefix, PRInt32 aNameSpaceID,
nsINameSpace*& aChildNameSpace);
private:
// These are not supported and are not implemented!
NameSpaceImpl(const NameSpaceImpl& aCopy);
NameSpaceImpl& operator=(const NameSpaceImpl& aCopy);
public:
nsINameSpaceManager* mManager;
NameSpaceImpl* mParent;
nsIAtom* mPrefix;
PRInt32 mID;
};
NameSpaceImpl::NameSpaceImpl(nsINameSpaceManager* aManager,
NameSpaceImpl* aParent,
nsIAtom* aPrefix,
const nsAString& aURI)
: mManager(aManager),
mParent(aParent),
mPrefix(aPrefix)
{
NS_ASSERTION(nsnull != aManager, "null namespace manager");
NS_INIT_REFCNT();
NS_ADDREF(mManager);
NS_IF_ADDREF(mParent);
NS_IF_ADDREF(mPrefix);
mManager->RegisterNameSpace(aURI, mID);
}
NameSpaceImpl::NameSpaceImpl(nsINameSpaceManager* aManager,
NameSpaceImpl* aParent,
nsIAtom* aPrefix,
PRInt32 aNameSpaceID)
: mManager(aManager),
mParent(aParent),
mPrefix(aPrefix),
mID(aNameSpaceID)
{
NS_ASSERTION(nsnull != aManager, "null namespace manager");
NS_INIT_REFCNT();
NS_ADDREF(mManager);
NS_IF_ADDREF(mParent);
NS_IF_ADDREF(mPrefix);
}
NameSpaceImpl::~NameSpaceImpl()
{
NS_RELEASE(mManager);
NS_IF_RELEASE(mParent);
NS_IF_RELEASE(mPrefix);
}
NS_IMPL_ISUPPORTS1(NameSpaceImpl, nsINameSpace)
NS_IMETHODIMP
NameSpaceImpl::GetNameSpaceManager(nsINameSpaceManager*& aManager) const
{
NS_ASSERTION(nsnull != aManager, "null namespace manager");
aManager = mManager;
NS_ADDREF(aManager);
return NS_OK;
}
NS_IMETHODIMP
NameSpaceImpl::GetNameSpaceID(PRInt32& aID) const
{
aID = mID;
return NS_OK;
}
NS_IMETHODIMP
NameSpaceImpl::GetNameSpaceURI(nsAString& aURI) const
{
NS_ASSERTION(nsnull != mManager, "null namespace manager");
return mManager->GetNameSpaceURI(mID, aURI);
}
NS_IMETHODIMP
NameSpaceImpl::GetNameSpacePrefix(nsIAtom*& aPrefix) const
{
aPrefix = mPrefix;
NS_IF_ADDREF(aPrefix);
return NS_OK;
}
NS_IMETHODIMP
NameSpaceImpl::GetParentNameSpace(nsINameSpace*& aParent) const
{
aParent = mParent;
NS_IF_ADDREF(aParent);
return NS_OK;
}
NS_IMETHODIMP
NameSpaceImpl::FindNameSpace(nsIAtom* aPrefix, nsINameSpace*& aNameSpace) const
{
const NameSpaceImpl* nameSpace = this;
do {
if (aPrefix == nameSpace->mPrefix) {
aNameSpace = (nsINameSpace*)nameSpace;
NS_ADDREF(aNameSpace);
return NS_OK;
}
nameSpace = nameSpace->mParent;
}
while (nsnull != nameSpace);
aNameSpace = nsnull;
return NS_ERROR_ILLEGAL_VALUE;
}
NS_IMETHODIMP
NameSpaceImpl::FindNameSpaceID(nsIAtom* aPrefix, PRInt32& aNameSpaceID) const
{
const NameSpaceImpl* nameSpace = this;
do {
if (aPrefix == nameSpace->mPrefix) {
aNameSpaceID = nameSpace->mID;
return NS_OK;
}
nameSpace = nameSpace->mParent;
} while (nsnull != nameSpace);
if (nsnull == aPrefix) {
aNameSpaceID = kNameSpaceID_None;
}
else {
aNameSpaceID = kNameSpaceID_Unknown;
}
return NS_ERROR_ILLEGAL_VALUE;
}
NS_IMETHODIMP
NameSpaceImpl::FindNameSpacePrefix(PRInt32 aNameSpaceID, nsIAtom*& aPrefix) const
{
const NameSpaceImpl* nameSpace = this;
do {
if (aNameSpaceID == nameSpace->mID) {
aPrefix = nameSpace->mPrefix;
NS_IF_ADDREF(aPrefix);
return NS_OK;
}
nameSpace = nameSpace->mParent;
}
while (nsnull != nameSpace);
aPrefix = nsnull;
return NS_ERROR_ILLEGAL_VALUE;
}
NS_IMETHODIMP
NameSpaceImpl::CreateChildNameSpace(nsIAtom* aPrefix, const nsAString& aURI,
nsINameSpace*& aChildNameSpace)
{
NameSpaceImpl* child = new NameSpaceImpl(mManager, this, aPrefix, aURI);
if (child) {
return child->QueryInterface(NS_GET_IID(nsINameSpace), (void**)&aChildNameSpace);
}
aChildNameSpace = nsnull;
return NS_ERROR_OUT_OF_MEMORY;
}
NS_IMETHODIMP
NameSpaceImpl::CreateChildNameSpace(nsIAtom* aPrefix, PRInt32 aNameSpaceID,
nsINameSpace*& aChildNameSpace)
{
if (FindNameSpaceURI(aNameSpaceID)) {
NameSpaceImpl* child = new NameSpaceImpl(mManager, this, aPrefix, aNameSpaceID);
if (child) {
return child->QueryInterface(NS_GET_IID(nsINameSpace), (void**)&aChildNameSpace);
}
aChildNameSpace = nsnull;
return NS_ERROR_OUT_OF_MEMORY;
}
aChildNameSpace = nsnull;
return NS_ERROR_ILLEGAL_VALUE;
}
//-----------------------------------------------------------
// Name Space Manager
class NameSpaceManagerImpl : public nsINameSpaceManager {
public:
NameSpaceManagerImpl();
NS_DECL_ISUPPORTS
NS_IMETHOD CreateRootNameSpace(nsINameSpace*& aRootNameSpace);
NS_IMETHOD RegisterNameSpace(const nsAString& aURI,
PRInt32& aNameSpaceID);
NS_IMETHOD GetNameSpaceURI(PRInt32 aNameSpaceID, nsAString& aURI);
NS_IMETHOD GetNameSpaceID(const nsAString& aURI,
PRInt32& aNameSpaceID);
NS_IMETHOD GetElementFactory(PRInt32 aNameSpaceID,
nsIElementFactory **aElementFactory);
private:
// These are not supported and are not implemented!
NameSpaceManagerImpl(const NameSpaceManagerImpl& aCopy);
NameSpaceManagerImpl& operator=(const NameSpaceManagerImpl& aCopy);
protected:
virtual ~NameSpaceManagerImpl();
};
NameSpaceManagerImpl::NameSpaceManagerImpl()
{
NS_ASSERTION(!gNameSpaceManagerWasShutDown,
"Namespace manager used past content module shutdown!!!");
NS_INIT_REFCNT();
InitializeNameSpaceManager();
}
NameSpaceManagerImpl::~NameSpaceManagerImpl()
{
}
NS_IMPL_ISUPPORTS1(NameSpaceManagerImpl, nsINameSpaceManager)
NS_IMETHODIMP
NameSpaceManagerImpl::CreateRootNameSpace(nsINameSpace*& aRootNameSpace)
{
NS_ASSERTION(!gNameSpaceManagerWasShutDown,
"Namespace manager used past content module shutdown!!!");
nsresult rv = NS_ERROR_OUT_OF_MEMORY;
aRootNameSpace = nsnull;
NameSpaceImpl* xmlns = new NameSpaceImpl(this, nsnull, nsLayoutAtoms::xmlnsNameSpace, kNameSpaceID_XMLNS);
if (nsnull != xmlns) {
NameSpaceImpl* xml = new NameSpaceImpl(this, xmlns, nsLayoutAtoms::xmlNameSpace, kNameSpaceID_XML);
if (nsnull != xml) {
rv = xml->QueryInterface(NS_GET_IID(nsINameSpace), (void**)&aRootNameSpace);
}
else {
delete xmlns;
}
}
return rv;
}
NS_IMETHODIMP
NameSpaceManagerImpl::RegisterNameSpace(const nsAString& aURI,
PRInt32& aNameSpaceID)
{
NS_ASSERTION(!gNameSpaceManagerWasShutDown,
"Namespace manager used past content module shutdown!!!");
PRInt32 id = FindNameSpaceID(aURI);
if (kNameSpaceID_Unknown == id) {
if (aURI.IsEmpty()) {
id = kNameSpaceID_None; // xmlns="", see bug 75700 for details
} else {
nsString* uri = new nsString(aURI);
if (!uri)
return NS_ERROR_OUT_OF_MEMORY;
gURIArray->AppendElement(uri);
id = gURIArray->Count(); // id is index + 1
nsStringKey key(*uri);
gURIToIDTable->Put(&key, (void*)id);
}
}
aNameSpaceID = id;
return NS_OK;
}
NS_IMETHODIMP
NameSpaceManagerImpl::GetNameSpaceURI(PRInt32 aNameSpaceID, nsAString& aURI)
{
NS_ASSERTION(!gNameSpaceManagerWasShutDown,
"Namespace manager used past content module shutdown!!!");
const nsString* result = FindNameSpaceURI(aNameSpaceID);
if (nsnull != result) {
aURI = *result;
return NS_OK;
}
aURI.Truncate();
return NS_ERROR_ILLEGAL_VALUE;
}
NS_IMETHODIMP
NameSpaceManagerImpl::GetNameSpaceID(const nsAString& aURI, PRInt32& aNameSpaceID)
{
NS_ASSERTION(!gNameSpaceManagerWasShutDown,
"Namespace manager used past content module shutdown!!!");
aNameSpaceID = FindNameSpaceID(aURI);
return NS_OK;
}
NS_IMETHODIMP
NameSpaceManagerImpl::GetElementFactory(PRInt32 aNameSpaceID,
nsIElementFactory **aElementFactory)
{
NS_ASSERTION(!gNameSpaceManagerWasShutDown,
"Namespace manager used past content module shutdown!!!");
*aElementFactory = nsnull;
NS_ENSURE_TRUE(gElementFactoryArray, NS_ERROR_NOT_INITIALIZED);
NS_ENSURE_TRUE(aNameSpaceID >= 0, NS_ERROR_ILLEGAL_VALUE);
gElementFactoryArray->QueryElementAt(aNameSpaceID,
NS_GET_IID(nsIElementFactory),
(void **)aElementFactory);
if (*aElementFactory) {
return NS_OK;
}
nsAutoString uri;
GetNameSpaceURI(aNameSpaceID, uri);
nsCOMPtr<nsIElementFactory> ef;
if (!uri.IsEmpty()) {
nsCAutoString contract_id(NS_ELEMENT_FACTORY_CONTRACTID_PREFIX);
contract_id.Append(NS_ConvertUCS2toUTF8(uri));
ef = do_GetService(contract_id.get());
}
if (!ef) {
nsresult rv = NS_NewXMLElementFactory(getter_AddRefs(ef));
if (NS_FAILED(rv)) {
return rv;
}
}
PRUint32 count = 0;
gElementFactoryArray->Count(&count);
if ((PRUint32)aNameSpaceID < count) {
gElementFactoryArray->ReplaceElementAt(ef, aNameSpaceID);
} else {
// This sucks, simply doing an InsertElementAt() should IMNSHO
// automatically grow the array and insert null's as needed to
// fill up the array!?!!
for (PRInt32 i = count; i < aNameSpaceID; i++) {
gElementFactoryArray->AppendElement(nsnull);
}
gElementFactoryArray->AppendElement(ef);
}
*aElementFactory = ef;
NS_ADDREF(*aElementFactory);
return NS_OK;
}
nsresult
NS_NewNameSpaceManager(nsINameSpaceManager** aInstancePtrResult)
{
NS_ENSURE_ARG_POINTER(aInstancePtrResult);
*aInstancePtrResult = new NameSpaceManagerImpl();
if (!*aInstancePtrResult) {
return NS_ERROR_OUT_OF_MEMORY;
}
NS_ADDREF(*aInstancePtrResult);
return NS_OK;
}