/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla 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/MPL/ * * 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. * * The Initial Developer of the Original Code is * Netscape Communications. * Portions created by the Initial Developer are Copyright (C) 2001 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Vidur Apparao (original author) * * 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 MPL, 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 MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include "nsSchemaPrivate.h" #include "nsSchemaLoader.h" #include "nsISVSchemaErrorHandler.h" // content includes #include "nsIContent.h" #include "nsIDocument.h" #include "nsIDOMDocument.h" #include "nsIDOM3Node.h" // loading includes #include "nsIXMLHttpRequest.h" #include "nsIDOMEvent.h" #include "nsIDOMEventListener.h" #include "nsIDOMEventTarget.h" #include "nsNetUtil.h" #include "nsIParserService.h" // XPConnect includes #include "nsIXPConnect.h" #include "nsIScriptSecurityManager.h" #include "nsIPrincipal.h" // XPCOM includes #include "nsIServiceManager.h" #include "nsIComponentManager.h" #include "nsStaticAtom.h" #include "nsIAtomService.h" //////////////////////////////////////////////////////////// // // nsSchemaAtoms implementation // //////////////////////////////////////////////////////////// // define storage for all atoms #define SCHEMA_ATOM(_name, _value) nsIAtom* nsSchemaAtoms::_name; #include "nsSchemaAtomList.h" #undef SCHEMA_ATOM static const nsStaticAtom atomInfo[] = { #define SCHEMA_ATOM(_name, _value) { _value, &nsSchemaAtoms::_name }, #include "nsSchemaAtomList.h" #undef SCHEMA_ATOM }; nsresult nsSchemaAtoms::AddRefAtoms() { nsresult rv; PRUint32 numAtoms = NS_ARRAY_LENGTH(atomInfo); nsCOMPtr atomServ = do_GetService(NS_ATOMSERVICE_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); for (PRUint32 i = 0; i < numAtoms; ++i) { atomServ->GetPermanentAtomUTF8(atomInfo[i].mString, atomInfo[i].mAtom); } return NS_OK; } //////////////////////////////////////////////////////////// // // LoadListener implementation // //////////////////////////////////////////////////////////// class LoadListener : public nsIDOMEventListener { public: LoadListener(nsSchemaLoader* aLoader, nsISVSchemaLoadListener* aListener, nsIXMLHttpRequest* aRequest); virtual ~LoadListener(); NS_DECL_ISUPPORTS NS_DECL_NSIDOMEVENTLISTENER private: nsSchemaLoader* mLoader; nsCOMPtr mListener; nsCOMPtr mRequest; nsString mURI; }; LoadListener::LoadListener(nsSchemaLoader* aLoader, nsISVSchemaLoadListener* aListener, nsIXMLHttpRequest* aRequest) { mLoader = aLoader; NS_ADDREF(mLoader); mListener = aListener; mRequest = aRequest; } LoadListener::~LoadListener() { NS_IF_RELEASE(mLoader); } NS_IMPL_ISUPPORTS1(LoadListener, nsIDOMEventListener) /* void handleEvent (in nsIDOMEvent event); */ NS_IMETHODIMP LoadListener::HandleEvent(nsIDOMEvent *event) { nsresult rv; PRUint32 httpStatus; mRequest->GetStatus(&httpStatus); nsCOMPtr schema; nsAutoString eventType; event->GetType(eventType); PRBool succeeded = (httpStatus / 100 == 2); // if we loaded fine, and not http/https, we assume success in loaded the file. if (!succeeded && eventType.EqualsLiteral("load")) { nsCOMPtr channel; mRequest->GetChannel(getter_AddRefs(channel)); if (channel) { nsCOMPtr httpChannel(do_QueryInterface(channel)); // if qi to httpChannel fails, it isn't a http:// or https:// request if (!httpChannel) { succeeded = PR_TRUE; } } } if (succeeded && eventType.EqualsLiteral("load")) { nsCOMPtr document; rv = mRequest->GetResponseXML(getter_AddRefs(document)); if (NS_SUCCEEDED(rv)) { nsCOMPtr element; if (document) document->GetDocumentElement(getter_AddRefs(element)); //XXXTelemac TODO Use an nsISVSchemaErrorHandler instead of nsnull if (element) rv = mLoader->ProcessSchemaElement(element, nsnull, getter_AddRefs(schema)); else rv = NS_ERROR_SCHEMA_NOT_SCHEMA_ELEMENT; } } else { rv = NS_ERROR_SCHEMA_LOADING_ERROR; } //XXXTelemac OnError call replace by use of nsISVSchemaErrorHandler //XXXTelemac in sub-processing methods. if (mListener) { if (NS_SUCCEEDED(rv)) mListener->OnLoad(schema); else mListener->OnError(rv, NS_LITERAL_STRING("Failure loading")); } NS_IF_RELEASE(mLoader); mListener = nsnull; mRequest = nsnull; return NS_OK; } //////////////////////////////////////////////////////////// // // nsBuiltinSchemaCollection implementation // //////////////////////////////////////////////////////////// nsBuiltinSchemaCollection::nsBuiltinSchemaCollection() { } nsresult nsBuiltinSchemaCollection::Init() { return (mBuiltinTypesHash.Init() && mSOAPTypeHash.Init()) ? NS_OK : NS_ERROR_FAILURE; } NS_IMPL_ISUPPORTS1(nsBuiltinSchemaCollection, nsISVSchemaCollection) /* nsISVSchema getSchema (in AString targetNamespace); */ NS_IMETHODIMP nsBuiltinSchemaCollection::GetSchema(const nsAString & targetNamespace, nsISVSchema **_retval) { NS_ENSURE_ARG_POINTER(_retval); *_retval = nsnull; return NS_ERROR_SCHEMA_UNKNOWN_TARGET_NAMESPACE; } /* nsISVSchemaElement getElement (in AString name, in AString namespace); */ NS_IMETHODIMP nsBuiltinSchemaCollection::GetElement(const nsAString & aName, const nsAString & aNamespace, nsISVSchemaElement **_retval) { if (aNamespace.IsEmpty()) { NS_WARNING("nsSchemaLoader::GetSchema(nsAString,nsISVSchema): " "Invalid |targetNamespace| is empty"); return NS_ERROR_INVALID_ARG; } NS_ENSURE_ARG_POINTER(_retval); *_retval = nsnull; return NS_ERROR_FAILURE; } /* nsISVSchemaAttribute getAttribute (in AString name, in AString namespace); */ NS_IMETHODIMP nsBuiltinSchemaCollection::GetAttribute(const nsAString & aName, const nsAString & aNamespace, nsISVSchemaAttribute **_retval) { NS_ENSURE_ARG_POINTER(_retval); *_retval = nsnull; return NS_ERROR_FAILURE; } static PRBool IsSchemaNamespace(const nsAString& aNamespace) { if (aNamespace.EqualsLiteral(NS_SCHEMA_2001_NAMESPACE) || aNamespace.EqualsLiteral(NS_SCHEMA_1999_NAMESPACE)) { return PR_TRUE; } else { return PR_FALSE; } } static PRBool IsSOAPNamespace(const nsAString& aNamespace) { if (aNamespace.EqualsLiteral(NS_SOAP_1_1_ENCODING_NAMESPACE) || aNamespace.EqualsLiteral(NS_SOAP_1_2_ENCODING_NAMESPACE)) { return PR_TRUE; } else { return PR_FALSE; } } /* nsISVSchemaType getType (in AString name, in AString namespace); */ NS_IMETHODIMP nsBuiltinSchemaCollection::GetType(const nsAString & aName, const nsAString & aNamespace, nsISVSchemaType **_retval) { if (IsSchemaNamespace(aNamespace)) { return GetBuiltinType(aName, aNamespace, _retval); } if (IsSOAPNamespace(aNamespace)) { return GetSOAPType(aName, aNamespace, _retval); } return NS_ERROR_SCHEMA_UNKNOWN_TYPE; } nsresult nsBuiltinSchemaCollection::GetBuiltinType(const nsAString& aName, const nsAString& aNamespace, nsISVSchemaType** aType) { if (!mBuiltinTypesHash.Get(aName, aType)) { nsresult rv; nsCOMPtr atomServ = do_GetService(NS_ATOMSERVICE_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr typeName; rv = atomServ->GetAtom(aName.BeginReading(), getter_AddRefs(typeName)); NS_ENSURE_SUCCESS(rv, rv); PRUint16 typeVal; if (typeName == nsSchemaAtoms::sAnyType_atom) { typeVal = nsISVSchemaBuiltinType::BUILTIN_TYPE_ANYTYPE; } else if (typeName == nsSchemaAtoms::sString_atom) { typeVal = nsISVSchemaBuiltinType::BUILTIN_TYPE_STRING; } else if (typeName == nsSchemaAtoms::sNormalizedString_atom) { typeVal = nsISVSchemaBuiltinType::BUILTIN_TYPE_NORMALIZED_STRING; } else if (typeName == nsSchemaAtoms::sToken_atom) { typeVal = nsISVSchemaBuiltinType::BUILTIN_TYPE_TOKEN; } else if (typeName == nsSchemaAtoms::sByte_atom) { typeVal = nsISVSchemaBuiltinType::BUILTIN_TYPE_BYTE; } else if (typeName == nsSchemaAtoms::sUnsignedByte_atom) { typeVal = nsISVSchemaBuiltinType::BUILTIN_TYPE_UNSIGNEDBYTE; } else if (typeName == nsSchemaAtoms::sBase64Binary_atom) { typeVal = nsISVSchemaBuiltinType::BUILTIN_TYPE_BASE64BINARY; } else if (typeName == nsSchemaAtoms::sHexBinary_atom) { typeVal = nsISVSchemaBuiltinType::BUILTIN_TYPE_HEXBINARY; } else if (typeName == nsSchemaAtoms::sInteger_atom) { typeVal = nsISVSchemaBuiltinType::BUILTIN_TYPE_INTEGER; } else if (typeName == nsSchemaAtoms::sPositiveInteger_atom) { typeVal = nsISVSchemaBuiltinType::BUILTIN_TYPE_POSITIVEINTEGER; } else if (typeName == nsSchemaAtoms::sNegativeInteger_atom) { typeVal = nsISVSchemaBuiltinType::BUILTIN_TYPE_NEGATIVEINTEGER; } else if (typeName == nsSchemaAtoms::sNonnegativeInteger_atom) { typeVal = nsISVSchemaBuiltinType::BUILTIN_TYPE_NONNEGATIVEINTEGER; } else if (typeName == nsSchemaAtoms::sNonpositiveInteger_atom) { typeVal = nsISVSchemaBuiltinType::BUILTIN_TYPE_NONPOSITIVEINTEGER; } else if (typeName == nsSchemaAtoms::sInt_atom) { typeVal = nsISVSchemaBuiltinType::BUILTIN_TYPE_INT; } else if (typeName == nsSchemaAtoms::sUnsignedInt_atom) { typeVal = nsISVSchemaBuiltinType::BUILTIN_TYPE_UNSIGNEDINT; } else if (typeName == nsSchemaAtoms::sLong_atom) { typeVal = nsISVSchemaBuiltinType::BUILTIN_TYPE_LONG; } else if (typeName == nsSchemaAtoms::sUnsignedLong_atom) { typeVal = nsISVSchemaBuiltinType::BUILTIN_TYPE_UNSIGNEDLONG; } else if (typeName == nsSchemaAtoms::sShort_atom) { typeVal = nsISVSchemaBuiltinType::BUILTIN_TYPE_SHORT; } else if (typeName == nsSchemaAtoms::sUnsignedShort_atom) { typeVal = nsISVSchemaBuiltinType::BUILTIN_TYPE_UNSIGNEDSHORT; } else if (typeName == nsSchemaAtoms::sDecimal_atom) { typeVal = nsISVSchemaBuiltinType::BUILTIN_TYPE_DECIMAL; } else if (typeName == nsSchemaAtoms::sFloat_atom) { typeVal = nsISVSchemaBuiltinType::BUILTIN_TYPE_FLOAT; } else if (typeName == nsSchemaAtoms::sDouble_atom) { typeVal = nsISVSchemaBuiltinType::BUILTIN_TYPE_DOUBLE; } else if (typeName == nsSchemaAtoms::sBoolean_atom) { typeVal = nsISVSchemaBuiltinType::BUILTIN_TYPE_BOOLEAN; } else if (typeName == nsSchemaAtoms::sTime_atom) { typeVal = nsISVSchemaBuiltinType::BUILTIN_TYPE_TIME; } else if (typeName == nsSchemaAtoms::sDateTime_atom) { typeVal = nsISVSchemaBuiltinType::BUILTIN_TYPE_DATETIME; } else if (typeName == nsSchemaAtoms::sDuration_atom) { typeVal = nsISVSchemaBuiltinType::BUILTIN_TYPE_DURATION; } else if (typeName == nsSchemaAtoms::sDate_atom) { typeVal = nsISVSchemaBuiltinType::BUILTIN_TYPE_DATE; } else if (typeName == nsSchemaAtoms::sGMonth_atom) { typeVal = nsISVSchemaBuiltinType::BUILTIN_TYPE_GMONTH; } else if (typeName == nsSchemaAtoms::sGYear_atom) { typeVal = nsISVSchemaBuiltinType::BUILTIN_TYPE_GYEAR; } else if (typeName == nsSchemaAtoms::sGYearMonth_atom) { typeVal = nsISVSchemaBuiltinType::BUILTIN_TYPE_GYEARMONTH; } else if (typeName == nsSchemaAtoms::sGDay_atom) { typeVal = nsISVSchemaBuiltinType::BUILTIN_TYPE_GDAY; } else if (typeName == nsSchemaAtoms::sGMonthDay_atom) { typeVal = nsISVSchemaBuiltinType::BUILTIN_TYPE_GMONTHDAY; } else if (typeName == nsSchemaAtoms::sName_atom) { typeVal = nsISVSchemaBuiltinType::BUILTIN_TYPE_NAME; } else if (typeName == nsSchemaAtoms::sQName_atom) { typeVal = nsISVSchemaBuiltinType::BUILTIN_TYPE_QNAME; } else if (typeName == nsSchemaAtoms::sNCName_atom) { typeVal = nsISVSchemaBuiltinType::BUILTIN_TYPE_NCNAME; } else if (typeName == nsSchemaAtoms::sAnyURI_atom) { typeVal = nsISVSchemaBuiltinType::BUILTIN_TYPE_ANYURI; } else if (typeName == nsSchemaAtoms::sLanguage_atom) { typeVal = nsISVSchemaBuiltinType::BUILTIN_TYPE_LANGUAGE; } else if (typeName == nsSchemaAtoms::sID_atom) { typeVal = nsISVSchemaBuiltinType::BUILTIN_TYPE_ID; } else if (typeName == nsSchemaAtoms::sIDREF_atom) { typeVal = nsISVSchemaBuiltinType::BUILTIN_TYPE_IDREF; } else if (typeName == nsSchemaAtoms::sIDREFS_atom) { typeVal = nsISVSchemaBuiltinType::BUILTIN_TYPE_IDREFS; } else if (typeName == nsSchemaAtoms::sENTITY_atom) { typeVal = nsISVSchemaBuiltinType::BUILTIN_TYPE_ENTITY; } else if (typeName == nsSchemaAtoms::sENTITIES_atom) { typeVal = nsISVSchemaBuiltinType::BUILTIN_TYPE_ENTITIES; } else if (typeName == nsSchemaAtoms::sNOTATION_atom) { typeVal = nsISVSchemaBuiltinType::BUILTIN_TYPE_NOTATION; } else if (typeName == nsSchemaAtoms::sNMTOKEN_atom) { typeVal = nsISVSchemaBuiltinType::BUILTIN_TYPE_NMTOKEN; } else if (typeName == nsSchemaAtoms::sNMTOKENS_atom) { typeVal = nsISVSchemaBuiltinType::BUILTIN_TYPE_NMTOKENS; } else { NS_ERROR("Unknown builtin type"); return NS_ERROR_SCHEMA_UNKNOWN_TYPE; } nsCOMPtr builtin = new nsSchemaBuiltinType(typeVal); if (!builtin) { return NS_ERROR_OUT_OF_MEMORY; } mBuiltinTypesHash.Put(aName, builtin); builtin.swap(*aType); } return NS_OK; } nsresult nsBuiltinSchemaCollection::GetSOAPType(const nsAString& aName, const nsAString& aNamespace, nsISVSchemaType** aType) { nsresult rv = NS_OK; if (!mSOAPTypeHash.Get(aName, aType)) { if (aName.EqualsLiteral("Array")) { nsCOMPtr anyType; rv = GetBuiltinType(NS_LITERAL_STRING("anyType"), NS_LITERAL_STRING(NS_SCHEMA_2001_NAMESPACE), getter_AddRefs(anyType)); if (NS_FAILED(rv)) { return rv; } nsSOAPArray* array = new nsSOAPArray(anyType); if (!array) { return NS_ERROR_OUT_OF_MEMORY; } mSOAPTypeHash.Put(aName, array); *aType = array; NS_ADDREF(*aType); } else if (aName.EqualsLiteral("arrayType")) { nsSOAPArrayType* arrayType = new nsSOAPArrayType(); if (!arrayType) { return NS_ERROR_OUT_OF_MEMORY; } mSOAPTypeHash.Put(aName, arrayType); *aType = arrayType; NS_ADDREF(*aType); } else { rv = NS_ERROR_SCHEMA_UNKNOWN_TYPE; } } return rv; } //////////////////////////////////////////////////////////// // // nsSchemaLoader implementation // //////////////////////////////////////////////////////////// nsSchemaLoader::nsSchemaLoader() { mBuiltinCollection = do_GetService(NS_SVBUILTINSCHEMACOLLECTION_CONTRACTID); } nsresult nsSchemaLoader::Init() { return mSchemas.Init() ? NS_OK : NS_ERROR_FAILURE; } NS_IMPL_ISUPPORTS2(nsSchemaLoader, nsISVSchemaLoader, nsISVSchemaCollection) /* nsISVSchema getSchema (in AString targetNamespace); */ NS_IMETHODIMP nsSchemaLoader::GetSchema(const nsAString & targetNamespace, nsISVSchema ** aResult) { NS_ENSURE_ARG_POINTER(aResult); return mSchemas.Get(targetNamespace, aResult) ? NS_OK : NS_ERROR_SCHEMA_UNKNOWN_TARGET_NAMESPACE; } /* nsISVSchemaElement getElement (in AString name, in AString namespace); */ NS_IMETHODIMP nsSchemaLoader::GetElement(const nsAString & aName, const nsAString & aNamespace, nsISVSchemaElement **_retval) { nsCOMPtr schema; nsresult rv = GetSchema(aNamespace, getter_AddRefs(schema)); if (NS_FAILED(rv)) { return rv; } return schema->GetElementByName(aName, _retval); } /* nsISVSchemaAttribute getAttribute (in AString name, in AString namespace); */ NS_IMETHODIMP nsSchemaLoader::GetAttribute(const nsAString & aName, const nsAString & aNamespace, nsISVSchemaAttribute **_retval) { nsCOMPtr schema; nsresult rv = GetSchema(aNamespace, getter_AddRefs(schema)); if (NS_FAILED(rv)) { return rv; } return schema->GetAttributeByName(aName, _retval); } /* nsISVSchemaType getType (in AString name, in AString namespace); */ NS_IMETHODIMP nsSchemaLoader::GetType(const nsAString & aName, const nsAString & aNamespace, nsISVSchemaType **_retval) { nsresult rv = NS_OK; if (IsSchemaNamespace(aNamespace) || IsSOAPNamespace(aNamespace)) { rv = mBuiltinCollection->GetType(aName, aNamespace, _retval); if (NS_FAILED(rv)) { nsAutoString errorMsg(NS_LITERAL_STRING("nsSchemaLoader::GetType: ")); errorMsg.AppendLiteral("Failure processing schema: cannot get schema type \""); errorMsg.Append(aName); errorMsg.AppendLiteral("\""); NS_ERROR(NS_ConvertUTF16toUTF8(errorMsg).get()); return rv; } return NS_OK; } nsCOMPtr schema; rv = GetSchema(aNamespace, getter_AddRefs(schema)); if (NS_FAILED(rv)) { return rv; } rv = schema->GetTypeByName(aName, _retval); if (NS_FAILED(rv)) { nsAutoString msg(NS_LITERAL_STRING("nsSchemaLoader::GetType: ")); msg.AppendLiteral("Failure processing schema: "); msg.AppendLiteral("cannot get schema type \""); msg.Append(aName); msg.AppendLiteral("\""); NS_ERROR(NS_ConvertUTF16toUTF8(msg).get()); return rv; } return NS_OK; } nsresult nsSchemaLoader::GetResolvedURI(const nsAString& aSchemaURI, const char* aMethod, nsIURI** aURI) { nsresult rv; nsAXPCNativeCallContext *cc = nsnull; nsCOMPtr xpc(do_GetService(nsIXPConnect::GetCID(), &rv)); if (NS_SUCCEEDED(rv)) { rv = xpc->GetCurrentNativeCallContext(&cc); } if (NS_SUCCEEDED(rv) && cc) { JSContext* cx; rv = cc->GetJSContext(&cx); if (NS_FAILED(rv)) return rv; nsCOMPtr secMan(do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv)); if (NS_FAILED(rv)) return rv; nsCOMPtr baseURI; nsCOMPtr principal; rv = secMan->GetSubjectPrincipal(getter_AddRefs(principal)); if (NS_SUCCEEDED(rv)) { principal->GetURI(getter_AddRefs(baseURI)); } rv = NS_NewURI(aURI, aSchemaURI, nsnull, baseURI); if (NS_FAILED(rv)) return rv; rv = secMan->CheckLoadURIFromScript(cx, *aURI); if (NS_FAILED(rv)) { // Security check failed. The above call set a JS exception. The // following lines ensure that the exception is propagated. cc->SetExceptionWasThrown(PR_TRUE); return rv; } } else { rv = NS_NewURI(aURI, aSchemaURI, nsnull); if (NS_FAILED(rv)) return rv; } return NS_OK; } /* nsISVSchema load (in AString schemaURI); */ NS_IMETHODIMP nsSchemaLoader::Load(const nsAString& schemaURI, nsISVSchema **_retval) { NS_ENSURE_ARG_POINTER(_retval); nsCOMPtr document; nsresult rv = GetDocumentFromURI(schemaURI, getter_AddRefs(document)); NS_ENSURE_SUCCESS(rv, rv); if (!document) return NS_ERROR_SCHEMA_LOADING_ERROR; nsCOMPtr element; document->GetDocumentElement(getter_AddRefs(element)); if (element) { //XXXTelemac TODO Have an error handler there instead or nsnull rv = ProcessSchemaElement(element, nsnull, _retval); } else { rv = NS_ERROR_SCHEMA_NOT_SCHEMA_ELEMENT; } return rv; } /* [noscript] void loadAsyncWithPrincipal (in AString schemaURI, * in nsISVSchemaLoadListener listener, * in nsIPrincipal principal); */ NS_IMETHODIMP nsSchemaLoader::LoadAsyncWithPrincipal(const nsAString& schemaURI, nsISVSchemaLoadListener *aListener, nsIPrincipal *aPrincipal) { NS_ENSURE_ARG(aListener); NS_ENSURE_ARG(aPrincipal); nsCOMPtr resolvedURI; nsresult rv = GetResolvedURI(schemaURI, "loadAsync", getter_AddRefs(resolvedURI)); if (NS_FAILED(rv)) { return rv; } nsCAutoString spec; resolvedURI->GetSpec(spec); nsCOMPtr request(do_CreateInstance(NS_XMLHTTPREQUEST_CONTRACTID, &rv)); if (!request) { return rv; } rv = request->Init(aPrincipal, nsnull, nsnull); NS_ENSURE_SUCCESS(rv, rv); const nsAString& empty = EmptyString(); rv = request->OpenRequest(NS_LITERAL_CSTRING("GET"), spec, PR_TRUE, empty, empty); if (NS_FAILED(rv)) { return rv; } // Force the mimetype of the returned stream to be xml. rv = request->OverrideMimeType(NS_LITERAL_CSTRING("application/xml")); if (NS_FAILED(rv)) { return rv; } nsCOMPtr listener; LoadListener* listenerInst = new LoadListener(this, aListener, request); if (!listenerInst) { return NS_ERROR_OUT_OF_MEMORY; } listener = listenerInst; nsCOMPtr target(do_QueryInterface(request)); if (!target) { return NS_ERROR_UNEXPECTED; } rv = target->AddEventListener(NS_LITERAL_STRING("load"), listener, PR_FALSE); if (NS_FAILED(rv)) { return rv; } rv = target->AddEventListener(NS_LITERAL_STRING("error"), listener, PR_FALSE); if (NS_FAILED(rv)) { return rv; } // The listener keeps the request alive until its complete rv = request->Send(nsnull); return rv; } /* void loadAsync(in AString schemaURI, in nsISVSchemaLoadListener listener); */ NS_IMETHODIMP nsSchemaLoader::LoadAsync(const nsAString& aSchemaURI, nsISVSchemaLoadListener *aListener) { // Get the subject principal from the security manager. We need it to // initialize the nsIXMLHttpRequest inside loadAsyncWithPrincipal. nsCOMPtr secMan = do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID); NS_ENSURE_STATE(secMan); nsCOMPtr principal; nsresult rv = secMan->GetSubjectPrincipal(getter_AddRefs(principal)); NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_TRUE(principal, NS_ERROR_FAILURE); return LoadAsyncWithPrincipal(aSchemaURI, aListener, principal); } static const char* kSchemaNamespaces[] = {NS_SCHEMA_1999_NAMESPACE, NS_SCHEMA_2001_NAMESPACE}; static PRUint32 kSchemaNamespacesLength = sizeof(kSchemaNamespaces) / sizeof(const char*); /* nsISVSchema processSchemaElement (in nsIDOMElement element, in nsISVSchemaErrorHandler aErrorHandler); */ NS_IMETHODIMP nsSchemaLoader::ProcessSchemaElement(nsIDOMElement* aElement, nsISVSchemaErrorHandler* aErrorHandler, nsISVSchema **aResult) { NS_ENSURE_ARG(aElement); NS_ENSURE_ARG_POINTER(aResult); nsRefPtr schemaInst = new nsSchema(this, aElement); if (!schemaInst) { return NS_ERROR_OUT_OF_MEMORY; } nsresult rv = schemaInst->Init(); NS_ENSURE_SUCCESS(rv, rv); nsAutoString targetNamespace; schemaInst->GetTargetNamespace(targetNamespace); nsISVSchema * os; if (mSchemas.Get(targetNamespace, &os)) { *aResult = os; return NS_OK; } nsChildElementIterator iterator(aElement, kSchemaNamespaces, kSchemaNamespacesLength); nsCOMPtr childElement; nsCOMPtr tagName; // For now, ignore the following // annotations // redefine // notation // identity-constraint elements while (NS_SUCCEEDED(iterator.GetNextChild(getter_AddRefs(childElement), getter_AddRefs(tagName))) && childElement) { if (tagName == nsSchemaAtoms::sElement_atom) { nsCOMPtr schemaElement; rv = ProcessElement(aErrorHandler, schemaInst, childElement, getter_AddRefs(schemaElement)); if (NS_SUCCEEDED(rv)) { rv = schemaInst->AddElement(schemaElement); } } else if (tagName == nsSchemaAtoms::sComplexType_atom) { nsCOMPtr complexType; rv = ProcessComplexType(aErrorHandler, schemaInst, childElement, getter_AddRefs(complexType)); if (NS_SUCCEEDED(rv)) { rv = schemaInst->AddType(complexType); } } else if (tagName == nsSchemaAtoms::sSimpleType_atom) { nsCOMPtr simpleType; rv = ProcessSimpleType(aErrorHandler, schemaInst, childElement, getter_AddRefs(simpleType)); if (NS_SUCCEEDED(rv)) { rv = schemaInst->AddType(simpleType); } } else if (tagName == nsSchemaAtoms::sAttribute_atom) { nsCOMPtr attribute; rv = ProcessAttribute(aErrorHandler, schemaInst, childElement, getter_AddRefs(attribute)); if (NS_SUCCEEDED(rv)) { rv = schemaInst->AddAttribute(attribute); } } else if (tagName == nsSchemaAtoms::sAttributeGroup_atom) { nsCOMPtr attributeGroup; rv = ProcessAttributeGroup(aErrorHandler, schemaInst, childElement, getter_AddRefs(attributeGroup)); if (NS_SUCCEEDED(rv)) { rv = schemaInst->AddAttributeGroup(attributeGroup); } } else if (tagName == nsSchemaAtoms::sModelGroup_atom) { nsCOMPtr modelGroup; rv = ProcessModelGroup(aErrorHandler, schemaInst, childElement, tagName, nsnull, getter_AddRefs(modelGroup)); if (NS_SUCCEEDED(rv)) { rv = schemaInst->AddModelGroup(modelGroup); } } else if (tagName == nsSchemaAtoms::sInclude_atom || tagName == nsSchemaAtoms::sImport_atom) { /* Mixing the handling of and as they are very similar, other than a few requirements regarding namespaces. http://www.w3.org/TR/2004/REC-xmlschema-1-20041028/structures.html#element-include If we include a schema, it must either (a) have the same targetNamespace as the including schema document or (b) no targetNamespace at all http://www.w3.org/TR/2004/REC-xmlschema-1-20041028/structures.html#element-import When importing a schema, it must either (a) if namespace is defined, then namespace == imported targetNamespace (b) if namespace is not defined, then imported schema must NOT have a targetNamespace If the uri to load doesn't resolve, it isn't a error. It is if its an invalid XML document or not a schema file */ NS_NAMED_LITERAL_STRING(schemaLocationStr, "schemaLocation"); nsAutoString schemalocation; childElement->GetAttribute(schemaLocationStr, schemalocation); // if empty, skip it if (schemalocation.IsEmpty()) continue; nsCOMPtr ios = do_GetIOService(); NS_ENSURE_STATE(ios); nsCOMPtr document; aElement->GetOwnerDocument(getter_AddRefs(document)); nsCOMPtr doc = do_QueryInterface(document); NS_ENSURE_STATE(doc); nsCOMPtr uri; rv = NS_NewURI(getter_AddRefs(uri), NS_ConvertUTF16toUTF8(schemalocation), doc->GetDocumentCharacterSet().get(), doc->GetDocumentURI()); NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_STATE(uri); // since we could be going cross-domain, make sure we can load it by doing // a principal same origin check. // get the base document's principal nsIPrincipal *basePrincipal = doc->NodePrincipal(); NS_ENSURE_STATE(basePrincipal); // Do a same origin check on the principal rv = basePrincipal->CheckMayLoad(uri, PR_TRUE); if (NS_FAILED(rv)) continue; // get the url nsCAutoString spec; uri->GetSpec(spec); nsCOMPtr includedDocument; rv = GetDocumentFromURI(NS_ConvertUTF8toUTF16(spec), getter_AddRefs(includedDocument)); NS_ENSURE_SUCCESS(rv, rv); // if no document, it is an error NS_ENSURE_STATE(includedDocument); // get the document element - it should be a xsd:schema nsCOMPtr element; includedDocument->GetDocumentElement(getter_AddRefs(element)); nsAutoString localName, nsUri; element->GetLocalName(localName); element->GetNamespaceURI(nsUri); PRBool correctNamespace = PR_FALSE; PRUint32 i; for (i = 0; i < kSchemaNamespacesLength; i++) { if (nsUri.Equals(NS_ConvertASCIItoUTF16(kSchemaNamespaces[i]))) { correctNamespace = PR_TRUE; break; } } if (!correctNamespace || !localName.EqualsLiteral("schema")) { // not a valid schema file return NS_ERROR_SCHEMA_NOT_SCHEMA_ELEMENT; } // XXX: check the target namespace requirements // If , simply call self to do all the heavy lifting if (tagName == nsSchemaAtoms::sImport_atom) { rv = ProcessSchemaElement(element, nsnull, aResult); NS_ENSURE_SUCCESS(rv, rv); continue; } // import/append all elements in the included file to our schema element nsCOMPtr ownerDoc; rv = childElement->GetOwnerDocument(getter_AddRefs(ownerDoc)); NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_STATE(ownerDoc); nsCOMPtr tmpNode, importedNode, dummy; element->GetFirstChild(getter_AddRefs(tmpNode)); // get the child element's next sibling so we have something to insert // before while we are appending to the current schema document unsigned short nodeType; nsCOMPtr nextSibling; childElement->GetNextSibling(getter_AddRefs(nextSibling)); while (tmpNode) { tmpNode->GetNodeType(&nodeType); if (nodeType == nsIDOMNode::ELEMENT_NODE) { rv = ownerDoc->ImportNode(tmpNode, PR_TRUE, getter_AddRefs(importedNode)); NS_ENSURE_SUCCESS(rv, rv); // InsertBefore can deal with a null nextSibling (will append) rv = aElement->InsertBefore(importedNode, nextSibling, getter_AddRefs(dummy)); NS_ENSURE_SUCCESS(rv, rv); } tmpNode->GetNextSibling(getter_AddRefs(dummy)); tmpNode = dummy; } // we twidle the iterator (reset), making sure to point it at the right // place. We do this because the iterator takes a snapshot the DOMList, // so we tell it to reinit itself and then reset it to the original index. PRUint32 index = iterator.GetCurrentIndex(); iterator.SetElement(aElement); iterator.Reset(index); } else if (tagName != nsSchemaAtoms::sAnnotation_atom && tagName != nsSchemaAtoms::sRedefine_atom && tagName != nsSchemaAtoms::sNotation_atom) { // if it is none of these, unexpected element. nsAutoString elementName; nsresult rc = aElement->GetTagName(elementName); NS_ENSURE_SUCCESS(rc, rc); nsAutoString errorMsg; errorMsg.AppendLiteral("Failure processing schema, unexpected element \""); errorMsg.Append(elementName); errorMsg.AppendLiteral("\" in "); NS_SCHEMALOADER_FIRE_ERROR(rv, errorMsg); return NS_ERROR_UNEXPECTED; } if (NS_FAILED(rv)) { nsAutoString errorMsg; errorMsg.AppendLiteral("Failure processing schema"); NS_SCHEMALOADER_FIRE_ERROR(rv, errorMsg); return rv; } } // We need to add this schema into the schema collection because resolving // forward references may require resolving types with namespace prefixes, // which could easily point back at this schema file. mSchemas.Put(targetNamespace, schemaInst); // Resolve all forward references rv = schemaInst->Resolve(aErrorHandler); if (NS_FAILED(rv)) { return rv; } NS_ADDREF(*aResult = schemaInst); return NS_OK; } PRBool ParseQualifiedName(nsIDOMElement* aContext, const nsAString& aQualifiedName, nsAString& aPrefix, nsAString& aLocalName, nsAString& aNamespaceURI) { const PRUnichar *pos, *begin, *end; aQualifiedName.BeginReading(&begin, &end); pos = begin; while (pos < end && *pos != ':') { ++pos; } if (pos < end) { aPrefix.Assign(Substring(begin, pos-begin)); aLocalName.Assign(Substring(++pos, end-pos)); } else { aLocalName.Assign(aQualifiedName); } nsCOMPtr node(do_QueryInterface(aContext)); return node->LookupNamespaceURI(aPrefix, aNamespaceURI); } nsresult nsSchemaLoader::GetNewOrUsedType(nsSchema* aSchema, nsIDOMElement* aContext, const nsAString& aTypeName, nsISVSchemaType** aType) { nsresult rv = NS_OK; nsAutoString prefix, localName, namespaceURI; // See if there's a prefix and get the // namespace associated with the prefix rv = ParseQualifiedName(aContext, aTypeName, prefix, localName, namespaceURI); if (!prefix.IsEmpty() && NS_FAILED(rv)) { // Unknown prefix return NS_ERROR_SCHEMA_UNKNOWN_PREFIX; } *aType = nsnull; nsAutoString targetNamespace; aSchema->GetTargetNamespace(targetNamespace); if (namespaceURI.IsEmpty() || namespaceURI.Equals(targetNamespace)) { // It's a local type rv = aSchema->GetTypeByName(localName, aType); } else { rv = GetType(localName, namespaceURI, aType); if (!*aType) { return NS_ERROR_SCHEMA_UNKNOWN_TARGET_NAMESPACE; } } // If we didn't get a type, we need to create a placeholder if (NS_SUCCEEDED(rv) && !*aType) { nsSchemaTypePlaceholder* placeholder = new nsSchemaTypePlaceholder(aSchema, localName); if (!placeholder) { return NS_ERROR_OUT_OF_MEMORY; } *aType = placeholder; NS_ADDREF(*aType); } return rv; } /** * @param aErrorHandler Error handler (in). * @param aSchema Schema in which is the element, not null (in). * @param aElement DOM element , not null (in). * @param aSchemaElement Schema element from processing DOM element (out). */ nsresult nsSchemaLoader::ProcessElement(nsISVSchemaErrorHandler* aErrorHandler, nsSchema* aSchema, nsIDOMElement* aElement, nsISVSchemaElement** aSchemaElement) { nsresult rv = NS_OK; nsCOMPtr schemaElement; PRUint32 minOccurs, maxOccurs; GetMinAndMax(aElement, &minOccurs, &maxOccurs); // See if it's a reference or an actual element declaration nsAutoString ref; aElement->GetAttribute(NS_LITERAL_STRING("ref"), ref); if (!ref.IsEmpty()) { nsSchemaElementRef* elementRef; nsAutoString refNS; // need to handle ns:type rv = ParseNameAndNS(ref, aElement, ref, refNS); NS_ENSURE_SUCCESS(rv, rv); elementRef = new nsSchemaElementRef(aSchema, ref, refNS); if (!elementRef) { return NS_ERROR_OUT_OF_MEMORY; } schemaElement = elementRef; elementRef->SetMinOccurs(minOccurs); elementRef->SetMaxOccurs(maxOccurs); } else { nsAutoString value; nsSchemaElement* elementInst; const nsAString& empty = EmptyString(); rv = aElement->GetAttributeNS(empty, NS_LITERAL_STRING("name"), value); if (NS_FAILED(rv)) { nsresult rc = aElement->GetTagName(value); NS_ENSURE_SUCCESS(rc, rc); nsAutoString errorMsg; errorMsg.AppendLiteral("Failure processing schema element, cannot get "); errorMsg.AppendLiteral("attribute \"name\" of element \""); errorMsg.Append(value); errorMsg.AppendLiteral("\""); NS_SCHEMALOADER_FIRE_ERROR(rv, errorMsg); return rv; } value.Trim(" \r\n\t"); elementInst = new nsSchemaElement(aSchema, value); if (!elementInst) { return NS_ERROR_OUT_OF_MEMORY; } schemaElement = elementInst; elementInst->SetMinOccurs(minOccurs); elementInst->SetMaxOccurs(maxOccurs); nsAutoString defaultValue, fixedValue; rv = aElement->GetAttributeNS(empty, NS_LITERAL_STRING("default"), defaultValue); if (NS_FAILED(rv)) { nsresult rc = aElement->GetTagName(value); NS_ENSURE_SUCCESS(rc, rc); nsAutoString errorMsg; errorMsg.AppendLiteral("Failure processing schema element, cannot get "); errorMsg.AppendLiteral("attribute \"default\" of element \""); errorMsg.Append(value); errorMsg.AppendLiteral("\""); NS_SCHEMALOADER_FIRE_ERROR(rv, errorMsg); return rv; } rv = aElement->GetAttributeNS(empty, NS_LITERAL_STRING("fixed"), fixedValue); if (NS_FAILED(rv)) { nsresult rc = aElement->GetTagName(value); NS_ENSURE_SUCCESS(rc, rc); nsAutoString errorMsg; errorMsg.AppendLiteral("Failure processing schema element, cannot get "); errorMsg.AppendLiteral("attribute \"fixed\" of element \""); errorMsg.Append(value); errorMsg.AppendLiteral("\""); NS_SCHEMALOADER_FIRE_ERROR(rv, errorMsg); return rv; } elementInst->SetConstraints(defaultValue, fixedValue); rv = aElement->GetAttributeNS(empty, NS_LITERAL_STRING("nillable"), value); if (NS_FAILED(rv)) { nsresult rc = aElement->GetTagName(value); NS_ENSURE_SUCCESS(rc, rc); nsAutoString errorMsg; errorMsg.AppendLiteral("Failure processing schema element, cannot get "); errorMsg.AppendLiteral("attribute \"nillable\" of element \""); errorMsg.Append(value); errorMsg.AppendLiteral("\""); NS_SCHEMALOADER_FIRE_ERROR(rv, errorMsg); return rv; } value.Trim(" \r\n\t"); PRInt32 flags = 0; if (value.EqualsLiteral("true")) flags |= nsSchemaElement::NILLABLE; rv = aElement->GetAttributeNS(empty, NS_LITERAL_STRING("abstract"), value); if (NS_FAILED(rv)) { nsresult rc = aElement->GetTagName(value); NS_ENSURE_SUCCESS(rc, rc); nsAutoString errorMsg; errorMsg.AppendLiteral("Failure processing schema element, cannot get "); errorMsg.AppendLiteral("attribute \"abstract\" of element \""); errorMsg.Append(value); errorMsg.AppendLiteral("\""); NS_SCHEMALOADER_FIRE_ERROR(rv, errorMsg); return rv; } value.Trim(" \r\n\t"); if (value.EqualsLiteral("true")) flags |= nsSchemaElement::ABSTRACT; nsCOMPtr parent; rv = aElement->GetParentNode(getter_AddRefs(parent)); if (NS_FAILED(rv)) return rv; parent->GetLocalName(value); // Check if the schema element's targetNamespace applies to . // Note: If the element information item has as its // parent,then the actual value of the targetNamespace is that of the // parent element information item, or absent if there is // none. Otherwise if the element information item has // element as an ancestor then if "form" is present and its actual // value is qualified, or if "form" is absent and the actual value of // elementFormDefault on the ancestor is qualified, then the // actual value of the targetNamespace [attribute] is that of the ancestor // element information item, or absent if there is none. if (value.EqualsLiteral("schema")) { flags |= nsSchemaElement::FORM_QUALIFIED; } else { rv = aElement->GetAttributeNS(empty, NS_LITERAL_STRING("form"), value); if (NS_FAILED(rv)) { nsAutoString errorMsg; errorMsg.AppendLiteral("Failure processing schema element, cannot get "); errorMsg.AppendLiteral("attribute \"form\" of element \""); errorMsg.Append(value); errorMsg.AppendLiteral("\""); NS_SCHEMALOADER_FIRE_ERROR(rv, errorMsg); return rv; } value.Trim(" \r\n\t"); if (value.IsEmpty()) { if (aSchema->IsElementFormQualified()) { flags |= nsSchemaElement::FORM_QUALIFIED; } else { flags &= ~nsSchemaElement::FORM_QUALIFIED; } } else if (value.EqualsLiteral("qualified")) { flags |= nsSchemaElement::FORM_QUALIFIED; } else { flags &= ~nsSchemaElement::FORM_QUALIFIED; } } elementInst->SetFlags(flags); nsCOMPtr schemaType; nsAutoString typeStr; aElement->GetAttribute(NS_LITERAL_STRING("type"), typeStr); if (!typeStr.IsEmpty()) { rv = GetNewOrUsedType(aSchema, aElement, typeStr, getter_AddRefs(schemaType)); if (NS_FAILED(rv)) { nsAutoString errorMsg; errorMsg.AppendLiteral("Failure processing schema, unknown type \""); errorMsg.Append(typeStr); errorMsg.AppendLiteral("\""); NS_SCHEMALOADER_FIRE_ERROR(rv, errorMsg); return rv; } } // Look for the type as a child of the element else { nsChildElementIterator iterator(aElement, kSchemaNamespaces, kSchemaNamespacesLength); nsCOMPtr childElement; nsCOMPtr tagName; while (NS_SUCCEEDED(iterator.GetNextChild(getter_AddRefs(childElement), getter_AddRefs(tagName))) && childElement) { if (tagName == nsSchemaAtoms::sSimpleType_atom) { nsCOMPtr simpleType; rv = ProcessSimpleType(aErrorHandler, aSchema, childElement, getter_AddRefs(simpleType)); if (NS_FAILED(rv)) { return rv; } schemaType = simpleType; break; } else if (tagName == nsSchemaAtoms::sComplexType_atom) { nsCOMPtr complexType; rv = ProcessComplexType(aErrorHandler, aSchema, childElement, getter_AddRefs(complexType)); if (NS_FAILED(rv)) { return rv; } schemaType = complexType; break; } } } if (!schemaType) { nsAutoString ns; aElement->GetNamespaceURI(ns); rv = GetType(NS_LITERAL_STRING("anyType"), ns, getter_AddRefs(schemaType)); if (NS_FAILED(rv)) { nsAutoString errorMsg; errorMsg.AppendLiteral("Failure processing schema, cannot find \'anyType\' "); errorMsg.AppendLiteral("placeholder type in namespace \""); errorMsg.Append(ns); errorMsg.AppendLiteral("\""); NS_SCHEMALOADER_FIRE_ERROR(rv, errorMsg); return rv; } } rv = elementInst->SetType(schemaType); if (NS_FAILED(rv)) { return rv; } } *aSchemaElement = schemaElement; NS_ADDREF(*aSchemaElement); return NS_OK; } /** * Handle * * @param aErrorHandler Webservice error handler. * @param aSchema Owning schema (in) * @param aElement element (in) * @param aComplexType Schema complex type built from |aElement| */ nsresult nsSchemaLoader::ProcessComplexType(nsISVSchemaErrorHandler* aErrorHandler, nsSchema* aSchema, nsIDOMElement* aElement, nsISVSchemaComplexType** aComplexType) { nsresult rv = NS_OK; nsCOMPtr complexType; nsAutoString abstract, name; aElement->GetAttribute(NS_LITERAL_STRING("abstract"), abstract); aElement->GetAttribute(NS_LITERAL_STRING("name"), name); nsSchemaComplexType* typeInst; typeInst = new nsSchemaComplexType(aSchema, name, abstract.EqualsLiteral("true")); if (!typeInst) { return NS_ERROR_OUT_OF_MEMORY; } complexType = typeInst; rv = typeInst->Init(); NS_ENSURE_SUCCESS(rv, rv); nsChildElementIterator iterator(aElement, kSchemaNamespaces, kSchemaNamespacesLength); nsCOMPtr childElement; nsCOMPtr tagName; PRUint16 contentModel = nsISVSchemaComplexType::CONTENT_MODEL_EMPTY; PRUint16 derivation = nsISVSchemaComplexType::DERIVATION_SELF_CONTAINED; nsCOMPtr baseType; nsCOMPtr modelGroup; while (NS_SUCCEEDED(iterator.GetNextChild(getter_AddRefs(childElement), getter_AddRefs(tagName))) && childElement) { if (tagName == nsSchemaAtoms::sSimpleContent_atom) { contentModel = nsISVSchemaComplexType::CONTENT_MODEL_SIMPLE; rv = ProcessSimpleContent(aErrorHandler, aSchema, childElement, typeInst, &derivation, getter_AddRefs(baseType)); break; } if (tagName == nsSchemaAtoms::sComplexContent_atom) { rv = ProcessComplexContent(aErrorHandler, aSchema, childElement, typeInst, &contentModel, &derivation, getter_AddRefs(baseType)); break; } if (tagName == nsSchemaAtoms::sModelGroup_atom || tagName == nsSchemaAtoms::sAll_atom || tagName == nsSchemaAtoms::sChoice_atom || tagName == nsSchemaAtoms::sSequence_atom || tagName == nsSchemaAtoms::sAttribute_atom || tagName == nsSchemaAtoms::sAttributeGroup_atom || tagName == nsSchemaAtoms::sAnyAttribute_atom) { rv = ProcessComplexTypeBody(aErrorHandler, aSchema, aElement, typeInst, nsnull, &contentModel); break; } if (tagName == nsSchemaAtoms::sAnnotation_atom) { // XXX: skipping for now } else { // Unexpected schema element nsAutoString elementName; rv = aElement->GetTagName(elementName); NS_ENSURE_SUCCESS(rv, rv); rv = NS_ERROR_UNEXPECTED; nsAutoString errorMsg; errorMsg.AppendLiteral("Failure processing schema, unexpected element \""); errorMsg.Append(elementName); errorMsg.AppendLiteral("\" in , should be "); errorMsg.AppendLiteral(", , "); NS_SCHEMALOADER_FIRE_ERROR(rv, errorMsg); break; } } if (NS_FAILED(rv)) { return rv; } nsAutoString mixed; aElement->GetAttribute(NS_LITERAL_STRING("mixed"), mixed); if (mixed.EqualsLiteral("true")) { contentModel = nsISVSchemaComplexType::CONTENT_MODEL_MIXED; } typeInst->SetContentModel(contentModel); typeInst->SetDerivation(derivation, baseType); *aComplexType = complexType; NS_ADDREF(*aComplexType); return NS_OK; } void nsSchemaLoader::ConstructArrayName(nsISVSchemaType* aType, nsAString& aName) { nsAutoString typeName; aType->GetName(typeName); aName.AssignLiteral("ArrayOf"); aName.Append(typeName); } nsresult nsSchemaLoader::ParseDimensions(nsSchema* aSchema, nsIDOMElement* aAttrElement, const nsAString& aStr, nsISVSchemaType* aBaseType, nsISVSchemaType** aArrayType, PRUint32* aDimension) { const PRUnichar *iter, *done_reading; aStr.BeginReading(&iter, &done_reading); PRUint32 dimension = 1; PRUnichar uc = *iter++; if (uc != PRUnichar('[')) { return NS_ERROR_UNEXPECTED; } while (iter != done_reading) { uc = *iter++; if (uc == PRUnichar(',')) { dimension++; } else if (uc == PRUnichar(']')) { break; } } *aDimension = dimension; while ((iter != done_reading) && (*iter == PRUnichar(' '))) { ++iter; } // If there's still more to go, then create an array type // based on the base and continue to parse if ((iter != done_reading) && (*iter == PRUnichar('['))) { nsAutoString name; nsCOMPtr myArrayType; PRUint32 myDimension; nsresult rv = ParseDimensions(aSchema, aAttrElement, nsDependentSubstring(iter, done_reading-iter), aBaseType, getter_AddRefs(myArrayType), &myDimension); if (NS_FAILED(rv)) { return rv; } ConstructArrayName(myArrayType, name); nsSchemaComplexType* typeInst = new nsSchemaComplexType(aSchema, name, PR_FALSE); if (!typeInst) { return NS_ERROR_OUT_OF_MEMORY; } nsCOMPtr complexType = typeInst; rv = typeInst->Init(); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr soapArray; rv = GetType(NS_LITERAL_STRING("Array"), NS_LITERAL_STRING(NS_SOAP_1_2_ENCODING_NAMESPACE), getter_AddRefs(soapArray)); if (NS_FAILED(rv)) { return rv; } typeInst->SetContentModel(nsISVSchemaComplexType::CONTENT_MODEL_ELEMENT_ONLY); typeInst->SetDerivation(nsISVSchemaComplexType::DERIVATION_RESTRICTION_COMPLEX, soapArray); typeInst->SetArrayInfo(myArrayType, myDimension); *aArrayType = typeInst; } else { *aArrayType = aBaseType; } NS_ADDREF(*aArrayType); return NS_OK; } nsresult nsSchemaLoader::ParseArrayType(nsSchema* aSchema, nsIDOMElement* aAttrElement, const nsAString& aStr, nsISVSchemaType** aType, PRUint32* aDimension) { PRInt32 offset; offset = aStr.FindChar(PRUnichar('[')); if (offset == -1) { return NS_ERROR_SCHEMA_UNKNOWN_TYPE; } nsDependentSubstring typeStr(aStr, 0, offset); nsCOMPtr type; nsresult rv = GetNewOrUsedType(aSchema, aAttrElement, typeStr, getter_AddRefs(type)); if (NS_FAILED(rv)) { return rv; } nsDependentSubstring dimensionStr(aStr, offset, aStr.Length() - offset); return ParseDimensions(aSchema, aAttrElement, dimensionStr, type, aType, aDimension); } nsresult nsSchemaLoader::ProcessComplexTypeBody(nsISVSchemaErrorHandler* aErrorHandler, nsSchema* aSchema, nsIDOMElement* aElement, nsSchemaComplexType* aComplexType, nsSchemaModelGroup* aSequence, PRUint16* aContentModel) { nsresult rv = NS_OK; nsChildElementIterator iterator(aElement, kSchemaNamespaces, kSchemaNamespacesLength); nsCOMPtr childElement; nsCOMPtr tagName; *aContentModel = nsISVSchemaComplexType::CONTENT_MODEL_EMPTY; nsCOMPtr modelGroup; while (NS_SUCCEEDED(iterator.GetNextChild(getter_AddRefs(childElement), getter_AddRefs(tagName))) && childElement) { if ((tagName == nsSchemaAtoms::sModelGroup_atom) || (tagName == nsSchemaAtoms::sAll_atom) || (tagName == nsSchemaAtoms::sChoice_atom) || (tagName == nsSchemaAtoms::sSequence_atom)) { if (modelGroup) { // We shouldn't already have a model group nsAutoString elementName; nsresult rv = childElement->GetTagName(elementName); NS_ENSURE_SUCCESS(rv, rv); nsAutoString errorMsg; errorMsg.AppendLiteral("Failure processing schema, must have "); errorMsg.AppendLiteral("model group in , "); errorMsg.AppendLiteral("unexpected element \""); errorMsg.Append(elementName); errorMsg.AppendLiteral("\""); NS_SCHEMALOADER_FIRE_ERROR(NS_ERROR_SCHEMA_INVALID_STRUCTURE, errorMsg); return NS_ERROR_SCHEMA_INVALID_STRUCTURE; } rv = ProcessModelGroup(aErrorHandler, aSchema, childElement, tagName, aSequence, getter_AddRefs(modelGroup)); if (NS_FAILED(rv)) { return rv; } PRUint32 particleCount; modelGroup->GetParticleCount(&particleCount); if (particleCount) { *aContentModel = nsISVSchemaComplexType::CONTENT_MODEL_ELEMENT_ONLY; } else { PRUint16 compositor; modelGroup->GetCompositor(&compositor); PRUint32 minOccurs; modelGroup->GetMinOccurs(&minOccurs); if ((compositor == nsISVSchemaModelGroup::COMPOSITOR_CHOICE) && (minOccurs > 0)) { *aContentModel = nsISVSchemaComplexType::CONTENT_MODEL_ELEMENT_ONLY; } } if (aSequence) { // Check if we were collapsed if (modelGroup.get() != static_cast(aSequence)) { rv = aSequence->AddParticle(modelGroup); } } else { rv = aComplexType->SetModelGroup(modelGroup); } if (NS_FAILED(rv)) { return rv; } } else if ((tagName == nsSchemaAtoms::sAttribute_atom) || (tagName == nsSchemaAtoms::sAttributeGroup_atom) || (tagName == nsSchemaAtoms::sAnyAttribute_atom)) { nsCOMPtr attribute; rv = ProcessAttributeComponent(aErrorHandler, aSchema, childElement, tagName, getter_AddRefs(attribute)); if (NS_FAILED(rv)) { return rv; } rv = aComplexType->AddAttribute(attribute); if (NS_FAILED(rv)) { nsAutoString elementName; nsAutoString attributeName; nsresult rc = childElement->GetTagName(elementName); NS_ENSURE_SUCCESS(rc, rc); rc = attribute->GetName(attributeName); NS_ENSURE_SUCCESS(rc, rc); nsAutoString errorMsg; errorMsg.AppendLiteral("Failure processing schema, cannot process attribute \""); errorMsg.Append(attributeName); errorMsg.AppendLiteral("\" of element \""); errorMsg.Append(elementName); errorMsg.AppendLiteral("\""); NS_SCHEMALOADER_FIRE_ERROR(rv, errorMsg); return rv; } // XXX WSDL ugliness making itself into schemas. Hopefully this // mechanism for specifying an array type in schemas will die // when the Schema WG address qualified names in attribute // default values. if (tagName == nsSchemaAtoms::sAttribute_atom) { #define NS_WSDL_NAMESPACE "http://schemas.xmlsoap.org/wsdl/" nsAutoString arrayType; childElement->GetAttributeNS(NS_LITERAL_STRING(NS_WSDL_NAMESPACE), NS_LITERAL_STRING("arrayType"), arrayType); if (!arrayType.IsEmpty()) { nsCOMPtr arraySchemaType; PRUint32 arrayDimension; rv = ParseArrayType(aSchema, childElement, arrayType, getter_AddRefs(arraySchemaType), &arrayDimension); if (NS_FAILED(rv)) { nsAutoString errorMsg; errorMsg.AppendLiteral("Failure processing schema, "); errorMsg.AppendLiteral("cannot process array type \""); errorMsg.Append(arrayType); errorMsg.AppendLiteral("\""); NS_SCHEMALOADER_FIRE_ERROR(rv, errorMsg); return rv; } rv = aComplexType->SetArrayInfo(arraySchemaType, arrayDimension); if (NS_FAILED(rv)) { nsAutoString errorMsg; errorMsg.AppendLiteral("Failure processing schema, cannot set "); errorMsg.AppendLiteral("array information for array type \""); errorMsg.Append(arrayType); errorMsg.AppendLiteral("\""); NS_SCHEMALOADER_FIRE_ERROR(rv, errorMsg); return rv; } } } } } return rv; } nsresult nsSchemaLoader::ProcessSimpleContent(nsISVSchemaErrorHandler* aErrorHandler, nsSchema* aSchema, nsIDOMElement* aElement, nsSchemaComplexType* aComplexType, PRUint16* aDerivation, nsISVSchemaType** aBaseType) { nsresult rv = NS_OK; nsCOMPtr baseType; nsChildElementIterator iterator(aElement, kSchemaNamespaces, kSchemaNamespacesLength); nsCOMPtr childElement; nsCOMPtr tagName; // A simpleContent element must have children if (!iterator.HasChildNodes()) { nsAutoString errorMsg(NS_LITERAL_STRING("Failure processing schema, ")); errorMsg.AppendLiteral(" invalid structure, should contains "); errorMsg.AppendLiteral(" or "); NS_SCHEMALOADER_FIRE_ERROR(NS_ERROR_SCHEMA_INVALID_STRUCTURE, errorMsg); return NS_ERROR_SCHEMA_INVALID_STRUCTURE; } while (NS_SUCCEEDED(iterator.GetNextChild(getter_AddRefs(childElement), getter_AddRefs(tagName))) && childElement) { nsAutoString baseStr; if ((tagName == nsSchemaAtoms::sRestriction_atom) || (tagName == nsSchemaAtoms::sExtension_atom)) { childElement->GetAttribute(NS_LITERAL_STRING("base"), baseStr); if (baseStr.IsEmpty()) { nsAutoString elementName; rv = childElement->GetTagName(elementName); NS_ENSURE_SUCCESS(rv, rv); nsAutoString errorMsg; errorMsg.AppendLiteral("Failure processing schema, \""); errorMsg.Append(elementName); errorMsg.AppendLiteral("\" must have a \"base\" attribute in order "); errorMsg.AppendLiteral("to specify base type"); NS_SCHEMALOADER_FIRE_ERROR(NS_ERROR_SCHEMA_MISSING_TYPE, errorMsg); return NS_ERROR_SCHEMA_MISSING_TYPE; } rv = GetNewOrUsedType(aSchema, childElement, baseStr, getter_AddRefs(baseType)); if (NS_FAILED(rv)) { nsAutoString errorMsg; errorMsg.AppendLiteral("Failure processing schema, unknown base type \""); errorMsg.Append(baseStr); errorMsg.AppendLiteral("\""); NS_SCHEMALOADER_FIRE_ERROR(rv, errorMsg); return rv; } nsCOMPtr simpleBaseType; if (tagName == nsSchemaAtoms::sRestriction_atom) { *aDerivation = nsISVSchemaComplexType::DERIVATION_RESTRICTION_SIMPLE; rv = ProcessSimpleContentRestriction(aErrorHandler, aSchema, childElement, aComplexType, baseType, getter_AddRefs(simpleBaseType)); if (NS_FAILED(rv)) { return rv; } } else { *aDerivation = nsISVSchemaComplexType::DERIVATION_EXTENSION_SIMPLE; nsCOMPtr complexBaseType(do_QueryInterface(baseType)); if (complexBaseType) { // Copy over the attributes from the base type // XXX Should really be cloning PRUint32 attrIndex, attrCount; complexBaseType->GetAttributeCount(&attrCount); for (attrIndex = 0; attrIndex < attrCount; attrIndex++) { nsCOMPtr attribute; rv = complexBaseType->GetAttributeByIndex(attrIndex, getter_AddRefs(attribute)); if (NS_FAILED(rv)) { nsAutoString errorMsg; errorMsg.AppendLiteral("Failure processing schema, cannot clone "); errorMsg.AppendLiteral("attributes from base type \""); errorMsg.Append(baseStr); errorMsg.AppendLiteral("\""); NS_SCHEMALOADER_FIRE_ERROR(rv, errorMsg); return rv; } rv = aComplexType->AddAttribute(attribute); if (NS_FAILED(rv)) { nsAutoString errorMsg; errorMsg.AppendLiteral("Failure processing schema, cannot clone "); errorMsg.AppendLiteral("attributes from base type \""); errorMsg.Append(baseStr); errorMsg.AppendLiteral("\""); NS_SCHEMALOADER_FIRE_ERROR(rv, errorMsg); return rv; } } } rv = ProcessSimpleContentExtension(aErrorHandler, aSchema, childElement, aComplexType, baseType, getter_AddRefs(simpleBaseType)); if (NS_FAILED(rv)) { return rv; } } if (simpleBaseType) { rv = aComplexType->SetSimpleBaseType(simpleBaseType); if (NS_FAILED(rv)) { return rv; } } break; } } *aBaseType = baseType; NS_IF_ADDREF(*aBaseType); return NS_OK; } nsresult nsSchemaLoader::ProcessSimpleContentRestriction(nsISVSchemaErrorHandler* aErrorHandler, nsSchema* aSchema, nsIDOMElement* aElement, nsSchemaComplexType* aComplexType, nsISVSchemaType* aBaseType, nsISVSchemaSimpleType** aSimpleBaseType) { nsresult rv = NS_OK; nsChildElementIterator iterator(aElement, kSchemaNamespaces, kSchemaNamespacesLength); nsCOMPtr childElement; nsCOMPtr tagName; nsSchemaRestrictionType* restrictionInst; nsCOMPtr simpleBase; restrictionInst = new nsSchemaRestrictionType(aSchema, EmptyString()); if (!restrictionInst) { return NS_ERROR_OUT_OF_MEMORY; } simpleBase = restrictionInst; // The base type must actually be a complex type (which itself must // have a simple base type. nsCOMPtr complexBase = do_QueryInterface(aBaseType); if (!complexBase) { // if base type is a place holder, this is ok PRUint16 schemaType; rv = aBaseType->GetSchemaType(&schemaType); if (NS_SUCCEEDED(rv) && schemaType == nsISVSchemaType::SCHEMA_TYPE_PLACEHOLDER) { simpleBase = do_QueryInterface(aBaseType); } else { nsAutoString baseStr; rv = aBaseType->GetName(baseStr); NS_ENSURE_SUCCESS(rv, rv); nsAutoString errorMsg; errorMsg.AppendLiteral("Failure processing schema, base type \""); errorMsg.Append(baseStr); errorMsg.AppendLiteral("\" of restriction must be a complex type "); errorMsg.AppendLiteral("which itself must be based on a simple type"); NS_SCHEMALOADER_FIRE_ERROR(NS_ERROR_SCHEMA_INVALID_TYPE_USAGE, errorMsg); return NS_ERROR_SCHEMA_INVALID_TYPE_USAGE; } } else { nsCOMPtr parentSimpleBase; complexBase->GetSimpleBaseType(getter_AddRefs(parentSimpleBase)); if (parentSimpleBase) { rv = restrictionInst->SetBaseType(parentSimpleBase); NS_ENSURE_SUCCESS(rv, rv); } } while (NS_SUCCEEDED(iterator.GetNextChild(getter_AddRefs(childElement), getter_AddRefs(tagName))) && childElement) { if (tagName == nsSchemaAtoms::sSimpleType_atom) { nsCOMPtr simpleType; rv = ProcessSimpleType(aErrorHandler, aSchema, childElement, getter_AddRefs(simpleType)); NS_ENSURE_SUCCESS(rv, rv); rv = restrictionInst->SetBaseType(simpleType); NS_ENSURE_SUCCESS(rv, rv); } else if ((tagName == nsSchemaAtoms::sMinExclusive_atom) || (tagName == nsSchemaAtoms::sMinInclusive_atom) || (tagName == nsSchemaAtoms::sMaxExclusive_atom) || (tagName == nsSchemaAtoms::sMaxInclusive_atom) || (tagName == nsSchemaAtoms::sTotalDigits_atom) || (tagName == nsSchemaAtoms::sFractionDigits_atom) || (tagName == nsSchemaAtoms::sLength_atom) || (tagName == nsSchemaAtoms::sMinLength_atom) || (tagName == nsSchemaAtoms::sMaxLength_atom) || (tagName == nsSchemaAtoms::sEnumeration_atom) || (tagName == nsSchemaAtoms::sWhiteSpace_atom) || (tagName == nsSchemaAtoms::sPattern_atom)) { nsCOMPtr facet; rv = ProcessFacet(aErrorHandler, aSchema, childElement, tagName, getter_AddRefs(facet)); NS_ENSURE_SUCCESS(rv, rv); rv = restrictionInst->AddFacet(facet); NS_ENSURE_SUCCESS(rv, rv); } else if ((tagName == nsSchemaAtoms::sAttribute_atom) || (tagName == nsSchemaAtoms::sAttributeGroup_atom) || (tagName == nsSchemaAtoms::sAnyAttribute_atom)) { nsCOMPtr attribute; rv = ProcessAttributeComponent(aErrorHandler, aSchema, childElement, tagName, getter_AddRefs(attribute)); NS_ENSURE_SUCCESS(rv, rv); rv = aComplexType->AddAttribute(attribute); NS_ENSURE_SUCCESS(rv, rv); } } *aSimpleBaseType = simpleBase; NS_IF_ADDREF(*aSimpleBaseType); return NS_OK; } nsresult nsSchemaLoader::ProcessSimpleContentExtension(nsISVSchemaErrorHandler* aErrorHandler, nsSchema* aSchema, nsIDOMElement* aElement, nsSchemaComplexType* aComplexType, nsISVSchemaType* aBaseType, nsISVSchemaSimpleType** aSimpleBaseType) { nsresult rv = NS_OK; nsChildElementIterator iterator(aElement, kSchemaNamespaces, kSchemaNamespacesLength); nsCOMPtr childElement; nsCOMPtr tagName; // If the base type is a complex type, it must itself have a simple // base type nsCOMPtr complexBase = do_QueryInterface(aBaseType); if (complexBase) { complexBase->GetSimpleBaseType(aSimpleBaseType); } else { aBaseType->QueryInterface(NS_GET_IID(nsISVSchemaSimpleType), (void**)aSimpleBaseType); } while (NS_SUCCEEDED(iterator.GetNextChild(getter_AddRefs(childElement), getter_AddRefs(tagName))) && childElement) { if ((tagName == nsSchemaAtoms::sAttribute_atom) || (tagName == nsSchemaAtoms::sAttributeGroup_atom) || (tagName == nsSchemaAtoms::sAnyAttribute_atom)) { nsCOMPtr attribute; rv = ProcessAttributeComponent(aErrorHandler, aSchema, childElement, tagName, getter_AddRefs(attribute)); if (NS_FAILED(rv)) { return rv; } rv = aComplexType->AddAttribute(attribute); if (NS_FAILED(rv)) { return rv; } } } return NS_OK; } nsresult nsSchemaLoader::ProcessComplexContent(nsISVSchemaErrorHandler* aErrorHandler, nsSchema* aSchema, nsIDOMElement* aElement, nsSchemaComplexType* aComplexType, PRUint16* aContentModel, PRUint16* aDerivation, nsISVSchemaType** aBaseType) { nsresult rv = NS_OK; nsCOMPtr baseType; nsChildElementIterator iterator(aElement, kSchemaNamespaces, kSchemaNamespacesLength); nsCOMPtr childElement; nsCOMPtr tagName; // A complexContent element must have children if (!iterator.HasChildNodes()) { nsAutoString errorMsg(NS_LITERAL_STRING("Failure processing schema, ")); errorMsg.AppendLiteral(" must contains "); errorMsg.AppendLiteral(" or "); NS_SCHEMALOADER_FIRE_ERROR(NS_ERROR_SCHEMA_INVALID_STRUCTURE, errorMsg); return NS_ERROR_SCHEMA_INVALID_STRUCTURE; } while (NS_SUCCEEDED(iterator.GetNextChild(getter_AddRefs(childElement), getter_AddRefs(tagName))) && childElement) { nsAutoString baseStr; if ((tagName == nsSchemaAtoms::sRestriction_atom) || (tagName == nsSchemaAtoms::sExtension_atom)) { childElement->GetAttribute(NS_LITERAL_STRING("base"), baseStr); if (baseStr.IsEmpty()) { nsAutoString errorMsg; errorMsg.AppendLiteral("Failure processing schema, "); if (tagName == nsSchemaAtoms::sRestriction_atom) { errorMsg.AppendLiteral("restriction"); } else { errorMsg.AppendLiteral("extension"); } errorMsg.AppendLiteral(" must have a \"base\" attribute in order to "); errorMsg.AppendLiteral("specify base type"); NS_SCHEMALOADER_FIRE_ERROR(NS_ERROR_SCHEMA_MISSING_TYPE, errorMsg); return NS_ERROR_SCHEMA_MISSING_TYPE; } rv = GetNewOrUsedType(aSchema, childElement, baseStr, getter_AddRefs(baseType)); if (NS_FAILED(rv)) { nsAutoString errorMsg; errorMsg.AppendLiteral("Failure processing schema, unknown base type \""); errorMsg.Append(baseStr); errorMsg.AppendLiteral("\""); NS_SCHEMALOADER_FIRE_ERROR(rv, errorMsg); return rv; } nsCOMPtr complexBaseType(do_QueryInterface(baseType)); if (tagName == nsSchemaAtoms::sRestriction_atom) { *aDerivation = nsISVSchemaComplexType::DERIVATION_RESTRICTION_COMPLEX; rv = ProcessComplexTypeBody(aErrorHandler, aSchema, childElement, aComplexType, nsnull, aContentModel); } else { *aDerivation = nsISVSchemaComplexType::DERIVATION_EXTENSION_COMPLEX; nsCOMPtr sequence; nsSchemaModelGroup* sequenceInst = nsnull; if (complexBaseType) { // XXX Should really be cloning nsCOMPtr baseGroup; rv = complexBaseType->GetModelGroup(getter_AddRefs(baseGroup)); if (NS_FAILED(rv)) { nsAutoString errorMsg; errorMsg.AppendLiteral("Failure processing schema, extension for type \""); errorMsg.Append(baseStr); errorMsg.AppendLiteral("\" does not contains any model group"); errorMsg.AppendLiteral("such as , , , or "); NS_SCHEMALOADER_FIRE_ERROR(rv, errorMsg); return rv; } if (baseGroup) { // Create a new model group that's going to be the a sequence // of the base model group and the content below sequenceInst = new nsSchemaModelGroup(aSchema, EmptyString()); if (!sequenceInst) { return NS_ERROR_OUT_OF_MEMORY; } sequence = sequenceInst; PRUint16 compositor; baseGroup->GetCompositor(&compositor); PRUint32 minOccurs, maxOccurs; baseGroup->GetMinOccurs(&minOccurs); baseGroup->GetMaxOccurs(&maxOccurs); // If the base group also a sequence, we can collapse the // two sequences. if ((compositor == nsISVSchemaModelGroup::COMPOSITOR_SEQUENCE) && (minOccurs == 1) && (maxOccurs == 1)) { PRUint32 pIndex, pCount; baseGroup->GetParticleCount(&pCount); for (pIndex = 0; pIndex < pCount; pIndex++) { nsCOMPtr particle; rv = baseGroup->GetParticle(pIndex, getter_AddRefs(particle)); if (NS_FAILED(rv)) { nsAutoString errorMsg; errorMsg.AppendLiteral("Failure processing schema, failure "); errorMsg.AppendLiteral("processing model group for extension "); errorMsg.AppendLiteral("of type \""); errorMsg.Append(baseStr); errorMsg.AppendLiteral("\""); NS_SCHEMALOADER_FIRE_ERROR(rv, errorMsg); return rv; } rv = sequenceInst->AddParticle(particle); if (NS_FAILED(rv)) { nsAutoString errorMsg; errorMsg.AppendLiteral("Failure processing schema, failure "); errorMsg.AppendLiteral("processing model group for extension "); errorMsg.AppendLiteral("of type \""); errorMsg.Append(baseStr); errorMsg.AppendLiteral("\""); NS_SCHEMALOADER_FIRE_ERROR(rv, errorMsg); return rv; } } } else { sequenceInst->AddParticle(baseGroup); } aComplexType->SetModelGroup(sequence); } } PRUint16 explicitContent; rv = ProcessComplexTypeBody(aErrorHandler, aSchema, childElement, aComplexType, sequenceInst, &explicitContent); if (NS_FAILED(rv)) { return rv; } // If the explicit content is empty, get the content type // from the base if ((explicitContent == nsISVSchemaComplexType::CONTENT_MODEL_EMPTY) && complexBaseType) { complexBaseType->GetContentModel(aContentModel); } else { *aContentModel = explicitContent; } } // Copy over the attributes from the base type // XXX Should really be cloning if (complexBaseType) { PRUint32 attrIndex, attrCount; complexBaseType->GetAttributeCount(&attrCount); for (attrIndex = 0; attrIndex < attrCount; attrIndex++) { nsCOMPtr attribute; rv = complexBaseType->GetAttributeByIndex(attrIndex, getter_AddRefs(attribute)); if (NS_FAILED(rv)) { nsAutoString errorMsg; errorMsg.AppendLiteral("Failure processing schema, cannot clone "); errorMsg.AppendLiteral("attributes from base type \""); errorMsg.Append(baseStr); errorMsg.AppendLiteral("\""); NS_SCHEMALOADER_FIRE_ERROR(rv, errorMsg); return rv; } rv = aComplexType->AddAttribute(attribute); if (NS_FAILED(rv)) { nsAutoString errorMsg; errorMsg.AppendLiteral("Failure processing schema, cannot clone "); errorMsg.AppendLiteral("attributes from base type \""); errorMsg.Append(baseStr); errorMsg.AppendLiteral("\""); NS_SCHEMALOADER_FIRE_ERROR(rv, errorMsg); return rv; } } } break; } } nsAutoString mixed; aElement->GetAttribute(NS_LITERAL_STRING("mixed"), mixed); if (mixed.EqualsLiteral("true")) { *aContentModel = nsISVSchemaComplexType::CONTENT_MODEL_MIXED; } *aBaseType = baseType; NS_IF_ADDREF(*aBaseType); return NS_OK; } nsresult nsSchemaLoader::ProcessSimpleType(nsISVSchemaErrorHandler* aErrorHandler, nsSchema* aSchema, nsIDOMElement* aElement, nsISVSchemaSimpleType** aSimpleType) { nsresult rv = NS_OK; nsAutoString name; aElement->GetAttribute(NS_LITERAL_STRING("name"), name); nsChildElementIterator iterator(aElement, kSchemaNamespaces, kSchemaNamespacesLength); nsCOMPtr childElement; nsCOMPtr tagName; while (NS_SUCCEEDED(iterator.GetNextChild(getter_AddRefs(childElement), getter_AddRefs(tagName))) && childElement) { if (tagName == nsSchemaAtoms::sRestriction_atom) { rv = ProcessSimpleTypeRestriction(aErrorHandler, aSchema, childElement, name, aSimpleType); break; } else if (tagName == nsSchemaAtoms::sList_atom) { rv = ProcessSimpleTypeList(aErrorHandler, aSchema, childElement, name, aSimpleType); break; } else if (tagName == nsSchemaAtoms::sUnion_atom) { rv = ProcessSimpleTypeUnion(aErrorHandler, aSchema, childElement, name, aSimpleType); break; } } return rv; } nsresult nsSchemaLoader::ProcessSimpleTypeRestriction(nsISVSchemaErrorHandler* aErrorHandler, nsSchema* aSchema, nsIDOMElement* aElement, const nsAString& aName, nsISVSchemaSimpleType** aSimpleType) { nsresult rv = NS_OK; nsSchemaRestrictionType* restrictionInst; nsCOMPtr restriction; restrictionInst = new nsSchemaRestrictionType(aSchema, aName); if (!restrictionInst) { return NS_ERROR_OUT_OF_MEMORY; } restriction = restrictionInst; nsCOMPtr baseType; nsAutoString baseStr; aElement->GetAttribute(NS_LITERAL_STRING("base"), baseStr); if (!baseStr.IsEmpty()) { rv = GetNewOrUsedType(aSchema, aElement, baseStr, getter_AddRefs(baseType)); if (NS_FAILED(rv)) { nsAutoString errorMsg; errorMsg.AppendLiteral("Failure processing schema, unknown base type \""); errorMsg.Append(baseStr); errorMsg.AppendLiteral("\""); NS_SCHEMALOADER_FIRE_ERROR(rv, errorMsg); return rv; } nsCOMPtr simpleBase(do_QueryInterface(baseType)); if (!simpleBase) { nsAutoString errorMsg; errorMsg.AppendLiteral("Failure processing schema, base type \""); errorMsg.Append(baseStr); errorMsg.AppendLiteral("\" should be a simple type"); NS_SCHEMALOADER_FIRE_ERROR(NS_ERROR_SCHEMA_INVALID_TYPE_USAGE, errorMsg); return NS_ERROR_SCHEMA_INVALID_TYPE_USAGE; } rv = restrictionInst->SetBaseType(simpleBase); } nsChildElementIterator iterator(aElement, kSchemaNamespaces, kSchemaNamespacesLength); nsCOMPtr childElement; nsCOMPtr tagName; while (NS_SUCCEEDED(iterator.GetNextChild(getter_AddRefs(childElement), getter_AddRefs(tagName))) && childElement) { if ((tagName == nsSchemaAtoms::sSimpleType_atom) && !baseType) { nsCOMPtr simpleType; rv = ProcessSimpleType(aErrorHandler, aSchema, childElement, getter_AddRefs(simpleType)); if (NS_FAILED(rv)) { return rv; } rv = restrictionInst->SetBaseType(simpleType); if (NS_FAILED(rv)) { return rv; } baseType = simpleType; } else if ((tagName == nsSchemaAtoms::sMinExclusive_atom) || (tagName == nsSchemaAtoms::sMinInclusive_atom) || (tagName == nsSchemaAtoms::sMaxExclusive_atom) || (tagName == nsSchemaAtoms::sMaxInclusive_atom) || (tagName == nsSchemaAtoms::sTotalDigits_atom) || (tagName == nsSchemaAtoms::sFractionDigits_atom) || (tagName == nsSchemaAtoms::sLength_atom) || (tagName == nsSchemaAtoms::sMinLength_atom) || (tagName == nsSchemaAtoms::sMaxLength_atom) || (tagName == nsSchemaAtoms::sEnumeration_atom) || (tagName == nsSchemaAtoms::sWhiteSpace_atom) || (tagName == nsSchemaAtoms::sPattern_atom)) { nsCOMPtr facet; rv = ProcessFacet(aErrorHandler, aSchema, childElement, tagName, getter_AddRefs(facet)); if (NS_FAILED(rv)) { return rv; } rv = restrictionInst->AddFacet(facet); if (NS_FAILED(rv)) { return rv; } } } *aSimpleType = restriction; NS_ADDREF(*aSimpleType); return NS_OK; } nsresult nsSchemaLoader::ProcessSimpleTypeList(nsISVSchemaErrorHandler* aErrorHandler, nsSchema* aSchema, nsIDOMElement* aElement, const nsAString& aName, nsISVSchemaSimpleType** aSimpleType) { nsresult rv = NS_OK; nsSchemaListType* listInst; nsCOMPtr list; listInst = new nsSchemaListType(aSchema, aName); if (!listInst) { return NS_ERROR_OUT_OF_MEMORY; } list = listInst; nsAutoString itemTypeStr; aElement->GetAttribute(NS_LITERAL_STRING("itemType"), itemTypeStr); nsCOMPtr itemType; if (!itemTypeStr.IsEmpty()) { nsCOMPtr type; rv = GetNewOrUsedType(aSchema, aElement, itemTypeStr, getter_AddRefs(type)); if (NS_FAILED(rv)) { nsAutoString errorMsg; errorMsg.AppendLiteral("Failure processing schema, unknown item type \""); errorMsg.Append(itemTypeStr); errorMsg.AppendLiteral("\""); NS_SCHEMALOADER_FIRE_ERROR(rv, errorMsg); return rv; } itemType = do_QueryInterface(type); } else { nsChildElementIterator iterator(aElement, kSchemaNamespaces, kSchemaNamespacesLength); nsCOMPtr childElement; nsCOMPtr tagName; while (NS_SUCCEEDED(iterator.GetNextChild(getter_AddRefs(childElement), getter_AddRefs(tagName))) && childElement) { if (tagName == nsSchemaAtoms::sSimpleType_atom) { rv = ProcessSimpleType(aErrorHandler, aSchema, childElement, getter_AddRefs(itemType)); if (NS_FAILED(rv)) { return rv; } break; } } } if (!itemType) { nsAutoString errorMsg; errorMsg.AppendLiteral("Failure processing schema, no item type "); errorMsg.AppendLiteral("for simple type \""); errorMsg.Append(aName); errorMsg.AppendLiteral("\""); NS_SCHEMALOADER_FIRE_ERROR(NS_ERROR_SCHEMA_MISSING_TYPE, errorMsg); return NS_ERROR_SCHEMA_MISSING_TYPE; } listInst->SetListType(itemType); *aSimpleType = list; NS_ADDREF(*aSimpleType); return NS_OK; } nsresult nsSchemaLoader::ProcessSimpleTypeUnion(nsISVSchemaErrorHandler* aErrorHandler, nsSchema* aSchema, nsIDOMElement* aElement, const nsAString& aName, nsISVSchemaSimpleType** aSimpleType) { nsresult rv = NS_OK; nsSchemaUnionType* unionInst; nsCOMPtr unionType; unionInst = new nsSchemaUnionType(aSchema, aName); if (!unionInst) { return NS_ERROR_OUT_OF_MEMORY; } unionType = unionInst; nsCOMPtr memberType; nsAutoString memberTypes; aElement->GetAttribute(NS_LITERAL_STRING("memberTypes"), memberTypes); if (!memberTypes.IsEmpty()) { const PRUnichar *begin = nsnull, *end, *tokenEnd; memberTypes.BeginReading(&tokenEnd, &end); while (tokenEnd != end) { nsAutoString typeStr; begin = tokenEnd; while (tokenEnd < end && *tokenEnd != PRUnichar(' ')) ++tokenEnd; if (tokenEnd < end) { typeStr.Assign(Substring(begin, tokenEnd-begin)); ++tokenEnd; } else { typeStr.Assign(Substring(begin, end-begin)); } nsCOMPtr type; rv = GetNewOrUsedType(aSchema, aElement, typeStr, getter_AddRefs(type)); if (NS_FAILED(rv)) { nsAutoString errorMsg; errorMsg.AppendLiteral("Failure processing schema, unknown type \""); errorMsg.Append(typeStr); errorMsg.AppendLiteral("\""); NS_SCHEMALOADER_FIRE_ERROR(rv, errorMsg); return rv; } memberType = do_QueryInterface(type); if (!memberType) { nsAutoString errorMsg; errorMsg.AppendLiteral("Failure processing schema, invalid member type \""); errorMsg.Append(typeStr); errorMsg.AppendLiteral("\" for union about simple type \""); errorMsg.Append(aName); errorMsg.AppendLiteral("\""); NS_SCHEMALOADER_FIRE_ERROR(NS_ERROR_SCHEMA_INVALID_TYPE_USAGE, errorMsg); return NS_ERROR_SCHEMA_INVALID_TYPE_USAGE; } rv = unionInst->AddUnionType(memberType); if (NS_FAILED(rv)) { return rv; } } } nsChildElementIterator iterator(aElement, kSchemaNamespaces, kSchemaNamespacesLength); nsCOMPtr childElement; nsCOMPtr tagName; while (NS_SUCCEEDED(iterator.GetNextChild(getter_AddRefs(childElement), getter_AddRefs(tagName))) && childElement) { if (tagName == nsSchemaAtoms::sSimpleType_atom) { rv = ProcessSimpleType(aErrorHandler, aSchema, childElement, getter_AddRefs(memberType)); if (NS_FAILED(rv)) { return rv; } rv = unionInst->AddUnionType(memberType); if (NS_FAILED(rv)) { return rv; } } } *aSimpleType = unionType; NS_ADDREF(*aSimpleType); return NS_OK; } nsresult nsSchemaLoader::ProcessModelGroup(nsISVSchemaErrorHandler* aErrorHandler, nsSchema* aSchema, nsIDOMElement* aElement, nsIAtom* aTagName, nsSchemaModelGroup* aParentSequence, nsISVSchemaModelGroup** aModelGroup) { nsresult rv = NS_OK; nsCOMPtr modelGroup; PRUint32 minOccurs, maxOccurs; GetMinAndMax(aElement, &minOccurs, &maxOccurs); // Check for a ref attribute nsAutoString ref, refNS; aElement->GetAttribute(NS_LITERAL_STRING("ref"), ref); if ((aTagName == nsSchemaAtoms::sModelGroup_atom) && !ref.IsEmpty()) { rv = ParseNameAndNS(ref, aElement, ref, refNS); NS_ENSURE_SUCCESS(rv, rv); nsSchemaModelGroupRef* modelGroupRef = new nsSchemaModelGroupRef(aSchema, ref, refNS); if (!modelGroupRef) { return NS_ERROR_OUT_OF_MEMORY; } modelGroup = modelGroupRef; modelGroupRef->SetMinOccurs(minOccurs); modelGroupRef->SetMaxOccurs(maxOccurs); } else { nsAutoString name; aElement->GetAttribute(NS_LITERAL_STRING("name"), name); nsChildElementIterator iterator(aElement, kSchemaNamespaces, kSchemaNamespacesLength); nsCOMPtr childElement; nsCOMPtr tagName = aTagName; // If this is a group element, find the first compositor // child and continue with that. if (aTagName == nsSchemaAtoms::sModelGroup_atom) { while (NS_SUCCEEDED(iterator.GetNextChild(getter_AddRefs(childElement), getter_AddRefs(tagName))) && childElement) { if ((tagName == nsSchemaAtoms::sAll_atom) || (tagName == nsSchemaAtoms::sChoice_atom) || (tagName == nsSchemaAtoms::sSequence_atom)) { iterator.SetElement(childElement); break; } } } nsSchemaModelGroup* modelGroupInst; // If we have a parent sequence and we're a sequence that // only appears once, then collapse us. if (aParentSequence && (tagName == nsSchemaAtoms::sSequence_atom) && (minOccurs == 1) && (maxOccurs == 1)) { modelGroupInst = aParentSequence; modelGroup = modelGroupInst; } else { modelGroupInst = new nsSchemaModelGroup(aSchema, name); if (!modelGroupInst) { return NS_ERROR_OUT_OF_MEMORY; } modelGroup = modelGroupInst; modelGroupInst->SetMinOccurs(minOccurs); modelGroupInst->SetMaxOccurs(maxOccurs); if (tagName == nsSchemaAtoms::sAll_atom) { modelGroupInst->SetCompositor(nsISVSchemaModelGroup::COMPOSITOR_ALL); } else if (tagName == nsSchemaAtoms::sChoice_atom) { modelGroupInst->SetCompositor(nsISVSchemaModelGroup::COMPOSITOR_CHOICE); } else if (tagName == nsSchemaAtoms::sSequence_atom) { modelGroupInst->SetCompositor(nsISVSchemaModelGroup::COMPOSITOR_SEQUENCE); } } while (NS_SUCCEEDED(iterator.GetNextChild(getter_AddRefs(childElement), getter_AddRefs(tagName))) && childElement) { if (tagName != nsSchemaAtoms::sAnnotation_atom) { nsCOMPtr particle; rv = ProcessParticle(aErrorHandler, aSchema, childElement, tagName, getter_AddRefs(particle)); if (NS_FAILED(rv)) { return rv; } rv = modelGroupInst->AddParticle(particle); if (NS_FAILED(rv)) { return rv; } } } } *aModelGroup = modelGroup; NS_ADDREF(*aModelGroup); return NS_OK; } nsresult nsSchemaLoader::ProcessParticle(nsISVSchemaErrorHandler* aErrorHandler, nsSchema* aSchema, nsIDOMElement* aElement, nsIAtom* aTagName, nsISVSchemaParticle** aParticle) { nsresult rv; if (aTagName == nsSchemaAtoms::sElement_atom) { nsCOMPtr element; rv = ProcessElement(aErrorHandler, aSchema, aElement, getter_AddRefs(element)); if (NS_FAILED(rv)) { return rv; } *aParticle = element; NS_IF_ADDREF(*aParticle); } else if ((aTagName == nsSchemaAtoms::sModelGroup_atom) || (aTagName == nsSchemaAtoms::sChoice_atom) || (aTagName == nsSchemaAtoms::sSequence_atom)) { nsCOMPtr modelGroup; rv = ProcessModelGroup(aErrorHandler, aSchema, aElement, aTagName, nsnull, getter_AddRefs(modelGroup)); if (NS_FAILED(rv)) { return rv; } *aParticle = modelGroup; NS_IF_ADDREF(*aParticle); } else if (aTagName == nsSchemaAtoms::sAny_atom) { nsCOMPtr anyParticle; nsSchemaAnyParticle* anyParticleInst = new nsSchemaAnyParticle(aSchema); if (!anyParticleInst) { return NS_ERROR_OUT_OF_MEMORY; } anyParticle = anyParticleInst; PRUint32 minOccurs, maxOccurs; GetMinAndMax(aElement, &minOccurs, &maxOccurs); anyParticleInst->SetMinOccurs(minOccurs); anyParticleInst->SetMaxOccurs(maxOccurs); PRUint16 process; GetProcess(aElement, &process); anyParticleInst->SetProcess(process); nsAutoString namespaceStr; aElement->GetAttribute(NS_LITERAL_STRING("namespace"), namespaceStr); anyParticleInst->SetNamespace(namespaceStr); *aParticle = anyParticle; NS_ADDREF(*aParticle); } return NS_OK; } nsresult nsSchemaLoader::ProcessAttributeComponent(nsISVSchemaErrorHandler* aErrorHandler, nsSchema* aSchema, nsIDOMElement* aElement, nsIAtom* aTagName, nsISVSchemaAttributeComponent** aAttribute) { nsresult rv; if (aTagName == nsSchemaAtoms::sAttribute_atom) { nsCOMPtr attribute; rv = ProcessAttribute(aErrorHandler, aSchema, aElement, getter_AddRefs(attribute)); if (NS_FAILED(rv)) { return rv; } *aAttribute = attribute; NS_IF_ADDREF(*aAttribute); } else if (aTagName == nsSchemaAtoms::sAttributeGroup_atom) { nsCOMPtr attributeGroup; rv = ProcessAttributeGroup(aErrorHandler, aSchema, aElement, getter_AddRefs(attributeGroup)); if (NS_FAILED(rv)) { return rv; } *aAttribute = attributeGroup; NS_IF_ADDREF(*aAttribute); } else if (aTagName == nsSchemaAtoms::sAnyAttribute_atom) { nsCOMPtr anyAttribute; nsSchemaAnyAttribute* anyAttributeInst = new nsSchemaAnyAttribute(aSchema); if (!anyAttributeInst) { return NS_ERROR_OUT_OF_MEMORY; } anyAttribute = anyAttributeInst; PRUint16 process; GetProcess(aElement, &process); anyAttributeInst->SetProcess(process); nsAutoString namespaceStr; aElement->GetAttribute(NS_LITERAL_STRING("namespace"), namespaceStr); anyAttributeInst->SetNamespace(namespaceStr); *aAttribute = anyAttribute; NS_ADDREF(*aAttribute); } return NS_OK; } nsresult nsSchemaLoader::ProcessAttribute(nsISVSchemaErrorHandler* aErrorHandler, nsSchema* aSchema, nsIDOMElement* aElement, nsISVSchemaAttribute** aAttribute) { nsresult rv; nsCOMPtr attribute; nsAutoString defaultValue, fixedValue, formValue; aElement->GetAttribute(NS_LITERAL_STRING("default"), defaultValue); aElement->GetAttribute(NS_LITERAL_STRING("fixed"), fixedValue); aElement->GetAttribute(NS_LITERAL_STRING("form"), formValue); PRUint16 use; GetUse(aElement, &use); nsAutoString ref, refNS; aElement->GetAttribute(NS_LITERAL_STRING("ref"), ref); if (!ref.IsEmpty()) { rv = ParseNameAndNS(ref, aElement, ref, refNS); NS_ENSURE_SUCCESS(rv, rv); nsSchemaAttributeRef* attributeRef = new nsSchemaAttributeRef(aSchema, ref, refNS); if (!attributeRef) { return NS_ERROR_OUT_OF_MEMORY; } attribute = attributeRef; attributeRef->SetConstraints(defaultValue, fixedValue); attributeRef->SetUse(use); // set the qualified form if (formValue.EqualsLiteral("qualified")) { attributeRef->SetAttributeFormQualified(PR_TRUE); } else if (formValue.EqualsLiteral("unqualified")) { attributeRef->SetAttributeFormQualified(PR_FALSE); } else { // get default PRBool defaultvalue = aSchema->IsAttributeFormDefaultQualified(); attributeRef->SetAttributeFormQualified(defaultvalue); } } else { nsAutoString name; aElement->GetAttribute(NS_LITERAL_STRING("name"), name); nsSchemaAttribute* attributeInst = new nsSchemaAttribute(aSchema, name); if (!attributeInst) { return NS_ERROR_OUT_OF_MEMORY; } attribute = attributeInst; attributeInst->SetConstraints(defaultValue, fixedValue); attributeInst->SetUse(use); // set the qualified form if (formValue.EqualsLiteral("qualified")) { attributeInst->SetAttributeFormQualified(PR_TRUE); } else if (formValue.EqualsLiteral("unqualified")) { attributeInst->SetAttributeFormQualified(PR_FALSE); } else { // get default PRBool defaultvalue = aSchema->IsAttributeFormDefaultQualified(); attributeInst->SetAttributeFormQualified(defaultvalue); } nsCOMPtr simpleType; nsChildElementIterator iterator(aElement, kSchemaNamespaces, kSchemaNamespacesLength); nsCOMPtr childElement; nsCOMPtr tagName; while (NS_SUCCEEDED(iterator.GetNextChild(getter_AddRefs(childElement), getter_AddRefs(tagName))) && childElement) { if (tagName == nsSchemaAtoms::sSimpleType_atom) { rv = ProcessSimpleType(aErrorHandler, aSchema, childElement, getter_AddRefs(simpleType)); if (NS_FAILED(rv)) { return rv; } break; } } if (!simpleType) { nsAutoString typeStr; aElement->GetAttribute(NS_LITERAL_STRING("type"), typeStr); if (!typeStr.IsEmpty()) { nsCOMPtr schemaType; rv = GetNewOrUsedType(aSchema, aElement, typeStr, getter_AddRefs(schemaType)); if (NS_FAILED(rv)) { nsAutoString errorMsg; errorMsg.AppendLiteral("Failure processing schema, unknown type \""); errorMsg.Append(typeStr); errorMsg.AppendLiteral("\""); NS_SCHEMALOADER_FIRE_ERROR(rv, errorMsg); return rv; } simpleType = do_QueryInterface(schemaType); if (!simpleType) { nsAutoString errorMsg; errorMsg.AppendLiteral("Failure processing schema, invalid type \""); errorMsg.Append(typeStr); errorMsg.AppendLiteral("\" for attribute \""); errorMsg.Append(name); errorMsg.AppendLiteral("\""); NS_SCHEMALOADER_FIRE_ERROR(NS_ERROR_SCHEMA_INVALID_TYPE_USAGE, errorMsg); return NS_ERROR_SCHEMA_INVALID_TYPE_USAGE; } } } attributeInst->SetType(simpleType); } *aAttribute = attribute; NS_ADDREF(*aAttribute); return NS_OK; } nsresult nsSchemaLoader::ProcessAttributeGroup(nsISVSchemaErrorHandler* aErrorHandler, nsSchema* aSchema, nsIDOMElement* aElement, nsISVSchemaAttributeGroup** aAttributeGroup) { nsresult rv; nsCOMPtr attributeGroup; nsAutoString ref, refNS; aElement->GetAttribute(NS_LITERAL_STRING("ref"), ref); if (!ref.IsEmpty()) { // need to handle ns:type rv = ParseNameAndNS(ref, aElement, ref, refNS); NS_ENSURE_SUCCESS(rv, rv); nsSchemaAttributeGroupRef* attrRef = new nsSchemaAttributeGroupRef(aSchema, ref, refNS); if (!attrRef) { return NS_ERROR_OUT_OF_MEMORY; } attributeGroup = attrRef; } else { nsAutoString name; aElement->GetAttribute(NS_LITERAL_STRING("name"), name); nsSchemaAttributeGroup* attrInst = new nsSchemaAttributeGroup(aSchema, name); if (!attrInst) { return NS_ERROR_OUT_OF_MEMORY; } attributeGroup = attrInst; rv = attrInst->Init(); NS_ENSURE_SUCCESS(rv, rv); nsChildElementIterator iterator(aElement, kSchemaNamespaces, kSchemaNamespacesLength); nsCOMPtr childElement; nsCOMPtr tagName; while (NS_SUCCEEDED(iterator.GetNextChild(getter_AddRefs(childElement), getter_AddRefs(tagName))) && childElement) { if ((tagName == nsSchemaAtoms::sAttribute_atom) || (tagName == nsSchemaAtoms::sAttributeGroup_atom) || (tagName == nsSchemaAtoms::sAnyAttribute_atom)) { nsCOMPtr attribute; rv = ProcessAttributeComponent(aErrorHandler, aSchema, childElement, tagName, getter_AddRefs(attribute)); if (NS_FAILED(rv)) { return rv; } rv = attrInst->AddAttribute(attribute); if (NS_FAILED(rv)) { return rv; } } } } *aAttributeGroup = attributeGroup; NS_ADDREF(*aAttributeGroup); return NS_OK; } nsresult nsSchemaLoader::ProcessFacet(nsISVSchemaErrorHandler* aErrorHandler, nsSchema* aSchema, nsIDOMElement* aElement, nsIAtom* aTagName, nsISVSchemaFacet** aFacet) { nsresult rv; nsCOMPtr facet; nsSchemaFacet* facetInst = new nsSchemaFacet(aSchema); if (!facetInst) { return NS_ERROR_OUT_OF_MEMORY; } facet = facetInst; PRUint16 facetType; if (aTagName == nsSchemaAtoms::sLength_atom) { facetType = nsISVSchemaFacet::FACET_TYPE_LENGTH; } else if (aTagName == nsSchemaAtoms::sMinLength_atom) { facetType = nsISVSchemaFacet::FACET_TYPE_MINLENGTH; } else if (aTagName == nsSchemaAtoms::sMaxLength_atom) { facetType = nsISVSchemaFacet::FACET_TYPE_MAXLENGTH; } else if (aTagName == nsSchemaAtoms::sPattern_atom) { facetType = nsISVSchemaFacet::FACET_TYPE_PATTERN; } else if (aTagName == nsSchemaAtoms::sEnumeration_atom) { facetType = nsISVSchemaFacet::FACET_TYPE_ENUMERATION; } else if (aTagName == nsSchemaAtoms::sWhiteSpace_atom) { facetType = nsISVSchemaFacet::FACET_TYPE_WHITESPACE; } else if (aTagName == nsSchemaAtoms::sMaxInclusive_atom) { facetType = nsISVSchemaFacet::FACET_TYPE_MAXINCLUSIVE; } else if (aTagName == nsSchemaAtoms::sMinInclusive_atom) { facetType = nsISVSchemaFacet::FACET_TYPE_MININCLUSIVE; } else if (aTagName == nsSchemaAtoms::sMaxExclusive_atom) { facetType = nsISVSchemaFacet::FACET_TYPE_MAXEXCLUSIVE; } else if (aTagName == nsSchemaAtoms::sMinExclusive_atom) { facetType = nsISVSchemaFacet::FACET_TYPE_MINEXCLUSIVE; } else if (aTagName == nsSchemaAtoms::sTotalDigits_atom) { facetType = nsISVSchemaFacet::FACET_TYPE_TOTALDIGITS; } else if (aTagName == nsSchemaAtoms::sFractionDigits_atom) { facetType = nsISVSchemaFacet::FACET_TYPE_FRACTIONDIGITS; } else { nsAutoString elementName; rv = aElement->GetTagName(elementName); NS_ENSURE_SUCCESS(rv, rv); nsAutoString errorMsg; errorMsg.AppendLiteral("Failure processing schema, unknown type of facet \""); errorMsg.Append(elementName); errorMsg.AppendLiteral("\""); NS_SCHEMALOADER_FIRE_ERROR(NS_ERROR_UNEXPECTED, errorMsg); return NS_ERROR_UNEXPECTED; } facetInst->SetFacetType(facetType); nsAutoString valueStr; aElement->GetAttribute(NS_LITERAL_STRING("value"), valueStr); if (valueStr.IsEmpty()) { nsAutoString elementName; rv = aElement->GetTagName(elementName); NS_ENSURE_SUCCESS(rv, rv); rv = NS_ERROR_SCHEMA_FACET_VALUE_ERROR; nsAutoString errorMsg; errorMsg.AppendLiteral("Failure processing schema, invalid empty value "); errorMsg.AppendLiteral("for facet \""); errorMsg.Append(elementName); errorMsg.AppendLiteral("\""); NS_SCHEMALOADER_FIRE_ERROR(rv, errorMsg); return rv; } if ((aTagName == nsSchemaAtoms::sLength_atom) || (aTagName == nsSchemaAtoms::sMinLength_atom) || (aTagName == nsSchemaAtoms::sMaxLength_atom) || (aTagName == nsSchemaAtoms::sTotalDigits_atom) || (aTagName == nsSchemaAtoms::sFractionDigits_atom)) { PRInt32 intVal = valueStr.ToInteger(&rv); if (NS_FAILED(rv) || (intVal < 0) || ((aTagName == nsSchemaAtoms::sTotalDigits_atom) && (intVal == 0))) { nsAutoString elementName; rv = aElement->GetTagName(elementName); NS_ENSURE_SUCCESS(rv, rv); nsAutoString errorMsg; errorMsg.AppendLiteral("Failure processing schema, invalid value for facet \""); errorMsg.Append(elementName); errorMsg.AppendLiteral("\", <=0"); NS_SCHEMALOADER_FIRE_ERROR(NS_ERROR_SCHEMA_FACET_VALUE_ERROR, errorMsg); return NS_ERROR_SCHEMA_FACET_VALUE_ERROR; } facetInst->SetUintValue((PRUint32)intVal); } else if (aTagName == nsSchemaAtoms::sWhiteSpace_atom) { PRUint16 whiteSpaceVal; if (valueStr.EqualsLiteral("collapse")) { whiteSpaceVal = nsSchemaFacet::WHITESPACE_COLLAPSE; } else if (valueStr.EqualsLiteral("preserve")) { whiteSpaceVal = nsSchemaFacet::WHITESPACE_PRESERVE; } else if (valueStr.EqualsLiteral("replace")) { whiteSpaceVal = nsSchemaFacet::WHITESPACE_REPLACE; } else { nsAutoString elementName; rv = aElement->GetTagName(elementName); NS_ENSURE_SUCCESS(rv, rv); nsAutoString errorMsg; errorMsg.AppendLiteral("Failure processing schema, invalid value for facet \""); errorMsg.Append(elementName); errorMsg.AppendLiteral("\", should be \"collapse\", \"preserve\" or \"replace\""); NS_SCHEMALOADER_FIRE_ERROR(NS_ERROR_SCHEMA_FACET_VALUE_ERROR, errorMsg); return NS_ERROR_SCHEMA_FACET_VALUE_ERROR; } facetInst->SetWhitespaceValue(whiteSpaceVal); } else { facetInst->SetValue(valueStr); } nsAutoString isFixed; aElement->GetAttribute(NS_LITERAL_STRING("fixed"), isFixed); facetInst->SetIsFixed(isFixed.EqualsLiteral("true")); *aFacet = facet; NS_ADDREF(*aFacet); return NS_OK; } void nsSchemaLoader::GetUse(nsIDOMElement* aElement, PRUint16* aUse) { *aUse = nsISVSchemaAttribute::USE_OPTIONAL; nsAutoString use; aElement->GetAttribute(NS_LITERAL_STRING("use"), use); if (use.EqualsLiteral("prohibited")) { *aUse = nsISVSchemaAttribute::USE_PROHIBITED; } else if (use.EqualsLiteral("required")) { *aUse = nsISVSchemaAttribute::USE_REQUIRED; } } void nsSchemaLoader::GetProcess(nsIDOMElement* aElement, PRUint16* aProcess) { *aProcess = nsISVSchemaAnyParticle::PROCESS_STRICT; nsAutoString process; aElement->GetAttribute(NS_LITERAL_STRING("process"), process); if (process.EqualsLiteral("lax")) { *aProcess = nsISVSchemaAnyParticle::PROCESS_LAX; } else if (process.EqualsLiteral("skip")) { *aProcess = nsISVSchemaAnyParticle::PROCESS_SKIP; } } void nsSchemaLoader::GetMinAndMax(nsIDOMElement* aElement, PRUint32* aMinOccurs, PRUint32* aMaxOccurs) { *aMinOccurs = 1; *aMaxOccurs = 1; nsAutoString minStr, maxStr; aElement->GetAttribute(NS_LITERAL_STRING("minOccurs"), minStr); aElement->GetAttribute(NS_LITERAL_STRING("maxOccurs"), maxStr); nsresult rv; if (!minStr.IsEmpty()) { PRInt32 minVal = minStr.ToInteger(&rv); if (NS_SUCCEEDED(rv) && (minVal >= 0)) { *aMinOccurs = (PRUint32)minVal; } } if (!maxStr.IsEmpty()) { if (maxStr.EqualsLiteral("unbounded")) { *aMaxOccurs = nsISVSchemaParticle::OCCURRENCE_UNBOUNDED; } else { PRInt32 maxVal = maxStr.ToInteger(&rv); if (NS_SUCCEEDED(rv) && (maxVal >= 0)) { *aMaxOccurs = (PRUint32)maxVal; } } } } nsresult nsSchemaLoader::ParseNameAndNS(const nsAString& aName, nsIDOMElement* aElement, nsAString& aTypeName, nsAString& aTypeNS) { nsresult rv; nsCOMPtr parserService = do_GetService("@mozilla.org/parser/parser-service;1", &rv); NS_ENSURE_SUCCESS(rv, rv); const nsString& qName = PromiseFlatString(aName); const PRUnichar *colon; rv = parserService->CheckQName(qName, PR_TRUE, &colon); NS_ENSURE_SUCCESS(rv, rv); if (colon) { const PRUnichar* end = qName.EndReading(); nsAutoString schemaTypePrefix; schemaTypePrefix.Assign(Substring(qName.get(), colon)); aTypeName.Assign(Substring(colon + 1, end)); nsCOMPtr domNode3 = do_QueryInterface(aElement); NS_ENSURE_STATE(domNode3); // get the namespace url from the prefix rv = domNode3->LookupNamespaceURI(schemaTypePrefix, aTypeNS); NS_ENSURE_SUCCESS(rv, rv); } return rv; } nsresult nsSchemaLoader::GetDocumentFromURI(const nsAString& aUri, nsIDOMDocument** aDocument) { *aDocument = nsnull; nsCOMPtr resolvedURI; nsresult rv = GetResolvedURI(aUri, "load", getter_AddRefs(resolvedURI)); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr request = do_CreateInstance(NS_XMLHTTPREQUEST_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); nsCAutoString spec; resolvedURI->GetSpec(spec); const nsAString& empty = EmptyString(); rv = request->OpenRequest(NS_LITERAL_CSTRING("GET"), spec, PR_FALSE, empty, empty); NS_ENSURE_SUCCESS(rv, rv); // Force the mimetype of the returned stream to be xml. rv = request->OverrideMimeType(NS_LITERAL_CSTRING("application/xml")); NS_ENSURE_SUCCESS(rv, rv); rv = request->Send(nsnull); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr document; rv = request->GetResponseXML(getter_AddRefs(document)); NS_ENSURE_SUCCESS(rv, rv); if (document) { document.swap(*aDocument); } return NS_OK; }