Files
Mozilla/mozilla/extensions/schema-validation/src/nsSchemaLoader.cpp
jonas%sicking.cc 35f305467d Bug 416534: Clean up cross-site xmlhttprequest security checks. With fixes to tests this time. r/sr=peterv
git-svn-id: svn://10.0.0.236/trunk@246616 18797224-902f-48f8-a5cc-f745e15eee43
2008-02-27 03:45:32 +00:00

3446 lines
110 KiB
C++

/* -*- 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 <vidur@netscape.com> (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<nsIAtomService> 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<nsISVSchemaLoadListener> mListener;
nsCOMPtr<nsIXMLHttpRequest> 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<nsISVSchema> 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<nsIChannel> channel;
mRequest->GetChannel(getter_AddRefs(channel));
if (channel) {
nsCOMPtr<nsIHttpChannel> 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<nsIDOMDocument> document;
rv = mRequest->GetResponseXML(getter_AddRefs(document));
if (NS_SUCCEEDED(rv)) {
nsCOMPtr<nsIDOMElement> 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<nsIAtomService> atomServ =
do_GetService(NS_ATOMSERVICE_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIAtom> 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<nsISVSchemaType> 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<nsISVSchemaType> 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<nsISVSchema> 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<nsISVSchema> 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<nsISVSchema> 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<nsIXPConnect> 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<nsIScriptSecurityManager> secMan(do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv));
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIURI> baseURI;
nsCOMPtr<nsIPrincipal> 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<nsIDOMDocument> document;
nsresult rv = GetDocumentFromURI(schemaURI, getter_AddRefs(document));
NS_ENSURE_SUCCESS(rv, rv);
if (!document)
return NS_ERROR_SCHEMA_LOADING_ERROR;
nsCOMPtr<nsIDOMElement> 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<nsIURI> resolvedURI;
nsresult rv = GetResolvedURI(schemaURI, "loadAsync", getter_AddRefs(resolvedURI));
if (NS_FAILED(rv)) {
return rv;
}
nsCAutoString spec;
resolvedURI->GetSpec(spec);
nsCOMPtr<nsIXMLHttpRequest> 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<nsIDOMEventListener> listener;
LoadListener* listenerInst = new LoadListener(this, aListener, request);
if (!listenerInst) {
return NS_ERROR_OUT_OF_MEMORY;
}
listener = listenerInst;
nsCOMPtr<nsIDOMEventTarget> 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<nsIScriptSecurityManager> secMan =
do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
NS_ENSURE_STATE(secMan);
nsCOMPtr<nsIPrincipal> 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<nsSchema> 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<nsIDOMElement> childElement;
nsCOMPtr<nsIAtom> 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<nsISVSchemaElement> schemaElement;
rv = ProcessElement(aErrorHandler, schemaInst, childElement,
getter_AddRefs(schemaElement));
if (NS_SUCCEEDED(rv)) {
rv = schemaInst->AddElement(schemaElement);
}
}
else if (tagName == nsSchemaAtoms::sComplexType_atom) {
nsCOMPtr<nsISVSchemaComplexType> complexType;
rv = ProcessComplexType(aErrorHandler, schemaInst, childElement,
getter_AddRefs(complexType));
if (NS_SUCCEEDED(rv)) {
rv = schemaInst->AddType(complexType);
}
}
else if (tagName == nsSchemaAtoms::sSimpleType_atom) {
nsCOMPtr<nsISVSchemaSimpleType> simpleType;
rv = ProcessSimpleType(aErrorHandler, schemaInst, childElement,
getter_AddRefs(simpleType));
if (NS_SUCCEEDED(rv)) {
rv = schemaInst->AddType(simpleType);
}
}
else if (tagName == nsSchemaAtoms::sAttribute_atom) {
nsCOMPtr<nsISVSchemaAttribute> attribute;
rv = ProcessAttribute(aErrorHandler, schemaInst, childElement,
getter_AddRefs(attribute));
if (NS_SUCCEEDED(rv)) {
rv = schemaInst->AddAttribute(attribute);
}
}
else if (tagName == nsSchemaAtoms::sAttributeGroup_atom) {
nsCOMPtr<nsISVSchemaAttributeGroup> attributeGroup;
rv = ProcessAttributeGroup(aErrorHandler, schemaInst, childElement,
getter_AddRefs(attributeGroup));
if (NS_SUCCEEDED(rv)) {
rv = schemaInst->AddAttributeGroup(attributeGroup);
}
}
else if (tagName == nsSchemaAtoms::sModelGroup_atom) {
nsCOMPtr<nsISVSchemaModelGroup> 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 <include> and <import> 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<nsIIOService> ios = do_GetIOService();
NS_ENSURE_STATE(ios);
nsCOMPtr<nsIDOMDocument> document;
aElement->GetOwnerDocument(getter_AddRefs(document));
nsCOMPtr<nsIDocument> doc = do_QueryInterface(document);
NS_ENSURE_STATE(doc);
nsCOMPtr<nsIURI> 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<nsIDOMDocument> 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<nsIDOMElement> 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 <import>, 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<nsIDOMDocument> ownerDoc;
rv = childElement->GetOwnerDocument(getter_AddRefs(ownerDoc));
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_STATE(ownerDoc);
nsCOMPtr<nsIDOMNode> 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<nsIDOMNode> 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 <schema .../>");
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<nsIDOM3Node> 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 <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<nsISVSchemaElement> 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<nsIDOMNode> 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 <element>.
// Note: If the <element> element information item has <schema> as its
// parent,then the actual value of the targetNamespace is that of the
// parent <schema> element information item, or absent if there is
// none. Otherwise if the <element> element information item has
// <schema> 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 <schema> ancestor is qualified, then the
// actual value of the targetNamespace [attribute] is that of the ancestor
// <schema> 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<nsISVSchemaType> 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<nsIDOMElement> childElement;
nsCOMPtr<nsIAtom> tagName;
while (NS_SUCCEEDED(iterator.GetNextChild(getter_AddRefs(childElement),
getter_AddRefs(tagName))) &&
childElement) {
if (tagName == nsSchemaAtoms::sSimpleType_atom) {
nsCOMPtr<nsISVSchemaSimpleType> 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<nsISVSchemaComplexType> 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 <complexType ...>
*
* @param aErrorHandler Webservice error handler.
* @param aSchema Owning schema (in)
* @param aElement <complexType> 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<nsISVSchemaComplexType> 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<nsIDOMElement> childElement;
nsCOMPtr<nsIAtom> tagName;
PRUint16 contentModel = nsISVSchemaComplexType::CONTENT_MODEL_EMPTY;
PRUint16 derivation = nsISVSchemaComplexType::DERIVATION_SELF_CONTAINED;
nsCOMPtr<nsISVSchemaType> baseType;
nsCOMPtr<nsISVSchemaModelGroup> 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 <complexType />, should be <simpleContent .../>");
errorMsg.AppendLiteral(", <complexContent ../>, <annotation .../>");
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<nsISVSchemaType> 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<nsISVSchemaComplexType> complexType = typeInst;
rv = typeInst->Init();
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsISVSchemaType> 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<nsISVSchemaType> 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<nsIDOMElement> childElement;
nsCOMPtr<nsIAtom> tagName;
*aContentModel = nsISVSchemaComplexType::CONTENT_MODEL_EMPTY;
nsCOMPtr<nsISVSchemaModelGroup> 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 <complexType .../>, ");
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<nsISVSchemaModelGroup *>(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<nsISVSchemaAttributeComponent> 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<nsISVSchemaType> 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<nsISVSchemaType> baseType;
nsChildElementIterator iterator(aElement,
kSchemaNamespaces,
kSchemaNamespacesLength);
nsCOMPtr<nsIDOMElement> childElement;
nsCOMPtr<nsIAtom> tagName;
// A simpleContent element must have children
if (!iterator.HasChildNodes()) {
nsAutoString errorMsg(NS_LITERAL_STRING("Failure processing schema, "));
errorMsg.AppendLiteral("<simpleContent .../> invalid structure, should contains ");
errorMsg.AppendLiteral("<restriction .../> or <extension .../>");
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<nsISVSchemaSimpleType> 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<nsISVSchemaComplexType> 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<nsISVSchemaAttributeComponent> 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<nsIDOMElement> childElement;
nsCOMPtr<nsIAtom> tagName;
nsSchemaRestrictionType* restrictionInst;
nsCOMPtr<nsISVSchemaSimpleType> 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<nsISVSchemaComplexType> 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<nsISVSchemaSimpleType> 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<nsISVSchemaSimpleType> 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<nsISVSchemaFacet> 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<nsISVSchemaAttributeComponent> 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<nsIDOMElement> childElement;
nsCOMPtr<nsIAtom> tagName;
// If the base type is a complex type, it must itself have a simple
// base type
nsCOMPtr<nsISVSchemaComplexType> 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<nsISVSchemaAttributeComponent> 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<nsISVSchemaType> baseType;
nsChildElementIterator iterator(aElement,
kSchemaNamespaces,
kSchemaNamespacesLength);
nsCOMPtr<nsIDOMElement> childElement;
nsCOMPtr<nsIAtom> tagName;
// A complexContent element must have children
if (!iterator.HasChildNodes()) {
nsAutoString errorMsg(NS_LITERAL_STRING("Failure processing schema, "));
errorMsg.AppendLiteral("<complexContent .../> must contains ");
errorMsg.AppendLiteral("<restriction .../> or <extension .../>");
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<nsISVSchemaComplexType> 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<nsISVSchemaModelGroup> sequence;
nsSchemaModelGroup* sequenceInst = nsnull;
if (complexBaseType) {
// XXX Should really be cloning
nsCOMPtr<nsISVSchemaModelGroup> 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 <all>, <choice>, <sequence>, or <group>");
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<nsISVSchemaParticle> 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<nsISVSchemaAttributeComponent> 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<nsIDOMElement> childElement;
nsCOMPtr<nsIAtom> 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<nsISVSchemaSimpleType> restriction;
restrictionInst = new nsSchemaRestrictionType(aSchema, aName);
if (!restrictionInst) {
return NS_ERROR_OUT_OF_MEMORY;
}
restriction = restrictionInst;
nsCOMPtr<nsISVSchemaType> 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<nsISVSchemaSimpleType> 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<nsIDOMElement> childElement;
nsCOMPtr<nsIAtom> tagName;
while (NS_SUCCEEDED(iterator.GetNextChild(getter_AddRefs(childElement),
getter_AddRefs(tagName))) &&
childElement) {
if ((tagName == nsSchemaAtoms::sSimpleType_atom) &&
!baseType) {
nsCOMPtr<nsISVSchemaSimpleType> 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<nsISVSchemaFacet> 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<nsISVSchemaSimpleType> 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<nsISVSchemaSimpleType> itemType;
if (!itemTypeStr.IsEmpty()) {
nsCOMPtr<nsISVSchemaType> 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<nsIDOMElement> childElement;
nsCOMPtr<nsIAtom> 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<nsISVSchemaSimpleType> unionType;
unionInst = new nsSchemaUnionType(aSchema, aName);
if (!unionInst) {
return NS_ERROR_OUT_OF_MEMORY;
}
unionType = unionInst;
nsCOMPtr<nsISVSchemaSimpleType> 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<nsISVSchemaType> 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<nsIDOMElement> childElement;
nsCOMPtr<nsIAtom> 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<nsISVSchemaModelGroup> 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<nsIDOMElement> childElement;
nsCOMPtr<nsIAtom> 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<nsISVSchemaParticle> 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<nsISVSchemaElement> 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<nsISVSchemaModelGroup> 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<nsISVSchemaParticle> 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<nsISVSchemaAttribute> 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<nsISVSchemaAttributeGroup> 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<nsISVSchemaAttributeComponent> 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<nsISVSchemaAttribute> 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<nsISVSchemaSimpleType> simpleType;
nsChildElementIterator iterator(aElement,
kSchemaNamespaces,
kSchemaNamespacesLength);
nsCOMPtr<nsIDOMElement> childElement;
nsCOMPtr<nsIAtom> 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<nsISVSchemaType> 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<nsISVSchemaAttributeGroup> 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<nsIDOMElement> childElement;
nsCOMPtr<nsIAtom> 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<nsISVSchemaAttributeComponent> 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<nsISVSchemaFacet> 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<nsIParserService> 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<nsIDOM3Node> 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<nsIURI> resolvedURI;
nsresult rv = GetResolvedURI(aUri, "load", getter_AddRefs(resolvedURI));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIXMLHttpRequest> 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<nsIDOMDocument> document;
rv = request->GetResponseXML(getter_AddRefs(document));
NS_ENSURE_SUCCESS(rv, rv);
if (document) {
document.swap(*aDocument);
}
return NS_OK;
}