Mozilla/mozilla/layout/base/src/nsDOMAttributeMap.cpp
vidur%netscape.com 8a6027fba4 new files
git-svn-id: svn://10.0.0.236/trunk@17573 18797224-902f-48f8-a5cc-f745e15eee43
1999-01-12 08:45:23 +00:00

445 lines
12 KiB
C++

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (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 Communicator client code.
*
* The Initial Developer of the Original Code is Netscape Communications
* Corporation. Portions created by Netscape are Copyright (C) 1998
* Netscape Communications Corporation. All Rights Reserved.
*/
#include "nsDOMAttributeMap.h"
#include "nsDOMAttribute.h"
#include "nsGenericElement.h"
#include "nsIContent.h"
#include "nsIDOMScriptObjectFactory.h"
#include "nsINameSpaceManager.h"
static NS_DEFINE_IID(kIDOMNamedNodeMapIID, NS_IDOMNAMEDNODEMAP_IID);
static NS_DEFINE_IID(kIDOMAttrIID, NS_IDOMATTR_IID);
static NS_DEFINE_IID(kIDOMAttributePrivateIID, NS_IDOMATTRIBUTEPRIVATE_IID);
//----------------------------------------------------------------------
nsDOMAttributeMap::nsDOMAttributeMap(nsIContent* aContent)
: mContent(aContent)
{
NS_INIT_REFCNT();
mScriptObject = nsnull;
mAttributes = nsnull;
// We don't add a reference to our content. If it goes away,
// we'll be told to drop our reference
}
PR_CALLBACK PRIntn
RemoveAttributes(PLHashEntry* he, PRIntn i, void* arg)
{
nsIDOMAttr* attr = (nsIDOMAttr*)he->value;
char* str = (char*)he->key;
if (nsnull != attr) {
nsIDOMAttributePrivate* attrPrivate;
attr->QueryInterface(kIDOMAttributePrivateIID, (void**)&attrPrivate);
attrPrivate->DropReference();
NS_RELEASE(attrPrivate);
NS_RELEASE(attr);
}
delete [] str;
return HT_ENUMERATE_REMOVE;
}
PR_CALLBACK PRIntn
DropReferencesInAttributes(PLHashEntry* he, PRIntn i, void* arg)
{
nsDOMAttribute* attr = (nsDOMAttribute*)he->value;
if (nsnull != attr) {
nsIDOMAttributePrivate* attrPrivate;
attr->QueryInterface(kIDOMAttributePrivateIID, (void**)&attrPrivate);
attrPrivate->DropReference();
NS_RELEASE(attrPrivate);
}
return HT_ENUMERATE_NEXT;
}
nsDOMAttributeMap::~nsDOMAttributeMap()
{
if (nsnull != mAttributes) {
PL_HashTableEnumerateEntries(mAttributes, RemoveAttributes, nsnull);
}
}
void
nsDOMAttributeMap::DropReference()
{
mContent = nsnull;
if (nsnull != mAttributes) {
PL_HashTableEnumerateEntries(mAttributes, DropReferencesInAttributes, nsnull);
}
}
nsresult
nsDOMAttributeMap::QueryInterface(REFNSIID aIID, void** aInstancePtr)
{
if (NULL == aInstancePtr) {
return NS_ERROR_NULL_POINTER;
}
if (aIID.Equals(kIDOMNamedNodeMapIID)) {
nsIDOMNamedNodeMap* tmp = this;
*aInstancePtr = (void*)tmp;
NS_ADDREF_THIS();
return NS_OK;
}
if (aIID.Equals(kIScriptObjectOwnerIID)) {
nsIScriptObjectOwner* tmp = this;
*aInstancePtr = (void*)tmp;
NS_ADDREF_THIS();
return NS_OK;
}
if (aIID.Equals(kISupportsIID)) {
nsIDOMNamedNodeMap* tmp1 = this;
nsISupports* tmp2 = tmp1;
*aInstancePtr = (void*)tmp2;
NS_ADDREF_THIS();
return NS_OK;
}
return NS_NOINTERFACE;
}
NS_IMPL_ADDREF(nsDOMAttributeMap)
NS_IMPL_RELEASE(nsDOMAttributeMap)
nsresult
nsDOMAttributeMap::GetScriptObject(nsIScriptContext *aContext,
void** aScriptObject)
{
nsresult res = NS_OK;
if (nsnull == mScriptObject) {
nsIDOMScriptObjectFactory *factory;
res = nsGenericElement::GetScriptObjectFactory(&factory);
if (NS_OK != res) {
return res;
}
res = factory->NewScriptNamedNodeMap(aContext,
(nsISupports *)(nsIDOMNamedNodeMap *)this,
(nsISupports *)mContent,
(void**)&mScriptObject);
NS_RELEASE(factory);
}
*aScriptObject = mScriptObject;
return res;
}
nsresult
nsDOMAttributeMap::SetScriptObject(void *aScriptObject)
{
mScriptObject = aScriptObject;
return NS_OK;
}
PLHashTable*
nsDOMAttributeMap::GetAttributeTable()
{
if ((nsnull == mAttributes) && (nsnull != mContent)) {
PRInt32 count;
mContent->GetAttributeCount(count);
mAttributes = PL_NewHashTable(count, PL_HashString, PL_CompareStrings,
PL_CompareValues, nsnull, nsnull);
}
return mAttributes;
}
nsresult
nsDOMAttributeMap::GetNamedItemCommon(const nsString& aAttrName,
PRInt32 aNameSpaceID,
nsIAtom* aNameAtom,
nsIDOMNode** aAttribute)
{
nsIDOMAttr* attribute;
char buf[128];
nsresult result = NS_OK;
PLHashTable* attrHash = GetAttributeTable();
aAttrName.ToCString(buf, sizeof(buf));
if (nsnull != attrHash) {
attribute = (nsIDOMAttr*)PL_HashTableLookup(attrHash, buf);
if (nsnull == attribute) {
nsresult attrResult;
nsAutoString value;
attrResult = mContent->GetAttribute(aNameSpaceID, aNameAtom, value);
if (NS_CONTENT_ATTR_NOT_THERE != attrResult) {
nsDOMAttribute* domAttribute;
domAttribute = new nsDOMAttribute(mContent, aAttrName, value);
if (nsnull == domAttribute) {
result = NS_ERROR_OUT_OF_MEMORY;
}
else {
result = domAttribute->QueryInterface(kIDOMAttrIID,
(void **)&attribute);
char* hashKey = aAttrName.ToNewCString();
PL_HashTableAdd(attrHash, hashKey, attribute);
}
}
}
}
if (nsnull != attribute) {
result = attribute->QueryInterface(kIDOMNodeIID, (void**)aAttribute);
}
else {
*aAttribute = nsnull;
}
return result;
}
void
nsDOMAttributeMap::GetNormalizedName(PRInt32 aNameSpaceID,
nsIAtom* aNameAtom,
nsString& aAttrName)
{
nsIAtom* prefix;
aAttrName.Truncate();
mContent->GetNameSpacePrefix(aNameSpaceID, prefix);
if (nsnull != prefix) {
prefix->ToString(aAttrName);
aAttrName.Append(":");
NS_RELEASE(prefix);
}
if (nsnull != aNameAtom) {
nsAutoString tmp;
aNameAtom->ToString(tmp);
aAttrName.Append(tmp);
}
}
nsresult
nsDOMAttributeMap::GetNamedItem(const nsString &aAttrName,
nsIDOMNode** aAttribute)
{
nsresult result = NS_OK;
if (nsnull != mContent) {
nsIAtom* nameAtom;
PRInt32 nameSpaceID;
nsAutoString normalizedName;
mContent->ParseAttributeString(aAttrName, nameAtom, nameSpaceID);
GetNormalizedName(nameSpaceID, nameAtom, normalizedName);
result = GetNamedItemCommon(normalizedName,
nameSpaceID,
nameAtom,
aAttribute);
NS_IF_RELEASE(nameAtom);
}
else {
*aAttribute = nsnull;
}
return result;
}
nsresult
nsDOMAttributeMap::SetNamedItem(nsIDOMNode *aNode, nsIDOMNode **aReturn)
{
nsresult result = NS_OK;
nsIDOMAttr* attribute;
if ((nsnull != mContent) && (nsnull != aNode)) {
result = aNode->QueryInterface(kIDOMAttrIID, (void**)&attribute);
if (NS_OK == result) {
PLHashTable* attrHash;
attrHash = GetAttributeTable();
if (nsnull != attrHash) {
nsIDOMNode* oldAttribute;
nsIDOMAttributePrivate* attrPrivate;
nsAutoString name, value;
char buf[128];
char* key;
nsIAtom* nameAtom;
PRInt32 nameSpaceID;
// Get normalized attribute name
attribute->GetName(name);
mContent->ParseAttributeString(name, nameAtom, nameSpaceID);
GetNormalizedName(nameSpaceID, nameAtom, name);
name.ToCString(buf, sizeof(buf));
result = GetNamedItemCommon(name, nameSpaceID, nameAtom, &oldAttribute);
if (nsnull != oldAttribute) {
nsIDOMAttributePrivate* oldAttributePrivate;
PLHashEntry** he;
// Remove the attribute from the hash table, cleaning
// the hash table entry as we go about it.
he = PL_HashTableRawLookup(attrHash, PL_HashString(buf), buf);
key = (char*)(*he)->key;
PL_HashTableRemove(attrHash, buf);
if (nsnull != key) {
delete [] key;
}
result = oldAttribute->QueryInterface(kIDOMAttributePrivateIID,
(void **)&oldAttributePrivate);
if (NS_OK == result) {
oldAttributePrivate->DropReference();
NS_RELEASE(oldAttributePrivate);
}
*aReturn = oldAttribute;
// Drop the reference held in the hash table
NS_RELEASE(oldAttribute);
}
else {
*aReturn = nsnull;
}
attribute->GetValue(value);
// Associate the new attribute with the content
// XXX Need to fail if it's already associated with other
// content
key = name.ToNewCString();
result = attribute->QueryInterface(kIDOMAttributePrivateIID,
(void **)&attrPrivate);
if (NS_OK == result) {
attrPrivate->SetContent(mContent);
attrPrivate->SetName(name);
NS_RELEASE(attrPrivate);
}
// Add the new attribute node to the hash table (maintaining
// a reference to it)
PL_HashTableAdd(attrHash, key, attribute);
// Set the attribute on the content
result = mContent->SetAttribute(nameSpaceID, nameAtom, value, PR_TRUE);
NS_IF_RELEASE(nameAtom);
}
}
}
else {
*aReturn = nsnull;
}
return result;
}
NS_IMETHODIMP
nsDOMAttributeMap::RemoveNamedItem(const nsString& aName, nsIDOMNode** aReturn)
{
nsresult result = NS_OK;
if (nsnull != mContent) {
PLHashTable* attrHash;
attrHash = GetAttributeTable();
if (nsnull != attrHash) {
nsIDOMNode* attribute;
nsIDOMAttributePrivate* attrPrivate;
char buf[128];
char* key;
nsIAtom* nameAtom;
PRInt32 nameSpaceID;
nsAutoString name;
mContent->ParseAttributeString(aName, nameAtom, nameSpaceID);
GetNormalizedName(nameSpaceID, nameAtom, name);
name.ToCString(buf, sizeof(buf));
result = GetNamedItemCommon(name, nameSpaceID, nameAtom, &attribute);
if (nsnull != attribute) {
PLHashEntry** he;
// Remove the attribute from the hash table, cleaning
// the hash table entry as we go about it.
he = PL_HashTableRawLookup(attrHash, PL_HashString(buf), buf);
key = (char*)(*he)->key;
PL_HashTableRemove(attrHash, buf);
if (nsnull != key) {
delete [] key;
}
result = attribute->QueryInterface(kIDOMAttributePrivateIID,
(void **)&attrPrivate);
if (NS_OK == result) {
attrPrivate->DropReference();
NS_RELEASE(attrPrivate);
}
*aReturn = attribute;
// Drop the reference held in the hash table
NS_RELEASE(attribute);
}
else {
*aReturn = nsnull;
}
// Unset the attribute in the content
result = mContent->UnsetAttribute(nameSpaceID, nameAtom, PR_TRUE);
NS_IF_RELEASE(nameAtom);
}
}
return result;
}
nsresult
nsDOMAttributeMap::Item(PRUint32 aIndex, nsIDOMNode** aReturn)
{
PRInt32 nameSpaceID;
nsIAtom* nameAtom = nsnull;
nsresult result = NS_OK;
if ((nsnull != mContent) &&
NS_SUCCEEDED(mContent->GetAttributeNameAt(aIndex,
nameSpaceID,
nameAtom))) {
nsAutoString attrName;
GetNormalizedName(nameSpaceID, nameAtom, attrName);
result = GetNamedItemCommon(attrName, nameSpaceID, nameAtom, aReturn);
NS_IF_RELEASE(nameAtom);
}
else {
*aReturn = nsnull;
}
return result;
}
nsresult
nsDOMAttributeMap::GetLength(PRUint32 *aLength)
{
PRInt32 n;
nsresult rv = NS_OK;
if (nsnull != mContent) {
rv = mContent->GetAttributeCount(n);
*aLength = PRUint32(n);
}
else {
*aLength = 0;
}
return rv;
}