/* -*- 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.org code. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 2001 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the 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 "nsInterfaceHashtable.h" #include "nsHashKeys.h" #include "nsISchemaLoader.h" #include "nsDefaultSOAPEncoder.h" #include "nsSOAPUtils.h" #include "nsSOAPParameter.h" #include "nsISOAPAttachments.h" #include "nsXPIDLString.h" #include "nsIDOMDocument.h" #include "nsIDOMText.h" #include "nsCOMPtr.h" #include "nsISchema.h" #include "nsIComponentManager.h" #include "nsIServiceManager.h" #include "nsXPCOM.h" #include "nsISupportsPrimitives.h" #include "nsIDOMParser.h" #include "nsSOAPUtils.h" #include "nsISOAPEncoding.h" #include "nsISOAPEncoder.h" #include "nsISOAPDecoder.h" #include "nsISOAPMessage.h" #include "nsSOAPException.h" #include "prprf.h" #include "prdtoa.h" #include "plbase64.h" #include "prmem.h" #include "nsReadableUtils.h" #include "nsIDOMNamedNodeMap.h" #include "nsIDOMAttr.h" #include "nsPrintfCString.h" #include "nsISOAPPropertyBagMutator.h" #include "nsIProperty.h" #include "nsIPropertyBag.h" #include "nsSupportsArray.h" #define MAX_ARRAY_DIMENSIONS 100 class nsSOAPEncoderStub : public nsISOAPEncoder, public nsISOAPDecoder { public: NS_DECL_ISUPPORTS protected: PRUint16 mSOAPVersion; }; NS_IMPL_ISUPPORTS2(nsSOAPEncoderStub, nsISOAPEncoder, nsISOAPDecoder) // // Macros to declare and implement the default encoder classes // #define DECLARE_ENCODER(name) \ class ns##name##Encoder : public nsSOAPEncoderStub \ { \ public: \ ns##name##Encoder(); \ ns##name##Encoder(PRUint16 aSOAPVersion); \ virtual ~ns##name##Encoder(); \ NS_DECL_NSISOAPENCODER \ NS_DECL_NSISOAPDECODER \ }; \ ns##name##Encoder::ns##name##Encoder(PRUint16 aSOAPVersion) {mSOAPVersion=aSOAPVersion;} \ ns##name##Encoder::~ns##name##Encoder() {} // All encoders must be first declared and then registered. DECLARE_ENCODER(Default) DECLARE_ENCODER(AnyType) DECLARE_ENCODER(AnySimpleType) DECLARE_ENCODER(Array) DECLARE_ENCODER(Struct) DECLARE_ENCODER(String) DECLARE_ENCODER(Boolean) DECLARE_ENCODER(Double) DECLARE_ENCODER(Float) DECLARE_ENCODER(Long) DECLARE_ENCODER(Int) DECLARE_ENCODER(Short) DECLARE_ENCODER(Byte) DECLARE_ENCODER(UnsignedLong) DECLARE_ENCODER(UnsignedInt) DECLARE_ENCODER(UnsignedShort) DECLARE_ENCODER(UnsignedByte) DECLARE_ENCODER(Base64Binary) /** * This now separates the version with respect to the SOAP specification from the version * with respect to the schema version (using the same constants for both). This permits * a user of a SOAP 1.1 or 1.2 encoding to choose which encoding to encode to. */ #define REGISTER_ENCODER(name,type,uri) \ { \ ns##name##Encoder *handler = new ns##name##Encoder(version); \ SOAPEncodingKey(uri, gSOAPStrings->k##name##type##Type, encodingKey); \ SetEncoder(encodingKey, handler); \ SetDecoder(encodingKey, handler); \ } #define REGISTER_SCHEMA_ENCODER(name) REGISTER_ENCODER(name,Schema,gSOAPStrings->kXSURI) #define REGISTER_SOAP_ENCODER(name) REGISTER_ENCODER(name,SOAP,gSOAPStrings->kSOAPEncURI) #define REGISTER_ENCODERS \ { \ nsDefaultEncoder *handler = new nsDefaultEncoder(version); \ SetDefaultEncoder(handler); \ SetDefaultDecoder(handler); \ } \ nsAutoString encodingKey; \ REGISTER_SCHEMA_ENCODER(AnyType) \ REGISTER_SCHEMA_ENCODER(AnySimpleType) \ REGISTER_SOAP_ENCODER(Array) \ REGISTER_SOAP_ENCODER(Struct) \ REGISTER_SCHEMA_ENCODER(String) \ REGISTER_SCHEMA_ENCODER(Boolean) \ REGISTER_SCHEMA_ENCODER(Double) \ REGISTER_SCHEMA_ENCODER(Float) \ REGISTER_SCHEMA_ENCODER(Long) \ REGISTER_SCHEMA_ENCODER(Int) \ REGISTER_SCHEMA_ENCODER(Short) \ REGISTER_SCHEMA_ENCODER(Byte) \ REGISTER_SCHEMA_ENCODER(UnsignedLong) \ REGISTER_SCHEMA_ENCODER(UnsignedInt) \ REGISTER_SCHEMA_ENCODER(UnsignedShort) \ REGISTER_SCHEMA_ENCODER(UnsignedByte) \ REGISTER_SCHEMA_ENCODER(Base64Binary) // // Default SOAP Encodings // NS_IMPL_ADDREF(nsDefaultSOAPEncoding_1_1) NS_IMPL_RELEASE(nsDefaultSOAPEncoding_1_1) nsDefaultSOAPEncoding_1_1::nsDefaultSOAPEncoding_1_1() : nsSOAPEncoding(gSOAPStrings->kSOAPEncURI11, nsnull, nsnull) { PRUint16 version = nsISOAPMessage::VERSION_1_1; PRBool result; MapSchemaURI(gSOAPStrings->kXSURI1999,gSOAPStrings->kXSURI,PR_TRUE,&result); MapSchemaURI(gSOAPStrings->kXSIURI1999,gSOAPStrings->kXSIURI,PR_TRUE,&result); MapSchemaURI(gSOAPStrings->kSOAPEncURI11,gSOAPStrings->kSOAPEncURI,PR_TRUE,&result); REGISTER_ENCODERS } NS_IMPL_ADDREF(nsDefaultSOAPEncoding_1_2) NS_IMPL_RELEASE(nsDefaultSOAPEncoding_1_2) nsDefaultSOAPEncoding_1_2::nsDefaultSOAPEncoding_1_2() : nsSOAPEncoding(gSOAPStrings->kSOAPEncURI, nsnull, nsnull) { PRUint16 version = nsISOAPMessage::VERSION_1_2; PRBool result; MapSchemaURI(gSOAPStrings->kXSURI1999,gSOAPStrings->kXSURI,PR_FALSE,&result); MapSchemaURI(gSOAPStrings->kXSIURI1999,gSOAPStrings->kXSIURI,PR_FALSE,&result); MapSchemaURI(gSOAPStrings->kSOAPEncURI11,gSOAPStrings->kSOAPEncURI,PR_FALSE,&result); REGISTER_ENCODERS } // // Default Encoders -- static helper functions intermixed // // Getting the immediate supertype of any type static nsresult GetSupertype(nsISOAPEncoding* aEncoding, nsISchemaType* aType, nsISchemaType** aResult) { PRUint16 typevalue; nsresult rc = aType->GetSchemaType(&typevalue); NS_ENSURE_SUCCESS(rc, rc); nsCOMPtr base; nsAutoString name; switch (typevalue) { case nsISchemaType::SCHEMA_TYPE_COMPLEX: { nsCOMPtr type = do_QueryInterface(aType); rc = type->GetBaseType(getter_AddRefs(base)); NS_ENSURE_SUCCESS(rc, rc); break; } case nsISchemaType::SCHEMA_TYPE_SIMPLE: { nsCOMPtr type = do_QueryInterface(aType); PRUint16 simpletypevalue; rc = type->GetSimpleType(&simpletypevalue); NS_ENSURE_SUCCESS(rc, rc); switch (simpletypevalue) { // Ultimately, this is wrong because in XML types are value spaces // We have not handled unions and lists. // A union might be considered a supertype of anything it joins // but it is the supertype of all types with value spaces it includes. // SOAP is an attempt to treat XML types as though they were // data types, which are governed by labels instead of value spaces. // So two unrelated values may coexist, but we will disallow it // because the caller probably wants type guarantees, not value // guarantees. case nsISchemaSimpleType::SIMPLE_TYPE_RESTRICTION: { nsCOMPtr simpletype = do_QueryInterface(type); nsCOMPtr simplebasetype; rc = simpletype->GetBaseType(getter_AddRefs(simplebasetype)); NS_ENSURE_SUCCESS(rc, rc); base = simplebasetype; break; } case nsISchemaSimpleType::SIMPLE_TYPE_BUILTIN: { nsCOMPtr builtintype = do_QueryInterface(type); PRUint16 builtintypevalue; rc = builtintype->GetBuiltinType(&builtintypevalue); NS_ENSURE_SUCCESS(rc, rc); switch(builtintypevalue) { case nsISchemaBuiltinType::BUILTIN_TYPE_ANYTYPE: // Root of all types *aResult = nsnull; return NS_OK; case nsISchemaBuiltinType::BUILTIN_TYPE_STRING: // name = kAnySimpleTypeSchemaType; name = gSOAPStrings->kAnyTypeSchemaType; break; case nsISchemaBuiltinType::BUILTIN_TYPE_NORMALIZED_STRING: name = gSOAPStrings->kStringSchemaType; break; case nsISchemaBuiltinType::BUILTIN_TYPE_TOKEN: name = gSOAPStrings->kNormalizedStringSchemaType; break; case nsISchemaBuiltinType::BUILTIN_TYPE_BYTE: name = gSOAPStrings->kShortSchemaType; break; case nsISchemaBuiltinType::BUILTIN_TYPE_UNSIGNEDBYTE: name = gSOAPStrings->kUnsignedShortSchemaType; break; case nsISchemaBuiltinType::BUILTIN_TYPE_BASE64BINARY: // name = kAnySimpleTypeSchemaType; name = gSOAPStrings->kAnyTypeSchemaType; break; case nsISchemaBuiltinType::BUILTIN_TYPE_HEXBINARY: // name = kAnySimpleTypeSchemaType; name = gSOAPStrings->kAnyTypeSchemaType; break; case nsISchemaBuiltinType::BUILTIN_TYPE_INTEGER: name = gSOAPStrings->kDecimalSchemaType; break; case nsISchemaBuiltinType::BUILTIN_TYPE_POSITIVEINTEGER: name = gSOAPStrings->kNonNegativeIntegerSchemaType; break; case nsISchemaBuiltinType::BUILTIN_TYPE_NEGATIVEINTEGER: name = gSOAPStrings->kNonPositiveIntegerSchemaType; break; case nsISchemaBuiltinType::BUILTIN_TYPE_NONNEGATIVEINTEGER: name = gSOAPStrings->kIntegerSchemaType; break; case nsISchemaBuiltinType::BUILTIN_TYPE_NONPOSITIVEINTEGER: name = gSOAPStrings->kIntegerSchemaType; break; case nsISchemaBuiltinType::BUILTIN_TYPE_INT: name = gSOAPStrings->kLongSchemaType; break; case nsISchemaBuiltinType::BUILTIN_TYPE_UNSIGNEDINT: name = gSOAPStrings->kUnsignedLongSchemaType; break; case nsISchemaBuiltinType::BUILTIN_TYPE_LONG: name = gSOAPStrings->kIntegerSchemaType; break; case nsISchemaBuiltinType::BUILTIN_TYPE_UNSIGNEDLONG: name = gSOAPStrings->kNonNegativeIntegerSchemaType; break; case nsISchemaBuiltinType::BUILTIN_TYPE_SHORT: name = gSOAPStrings->kIntSchemaType; break; case nsISchemaBuiltinType::BUILTIN_TYPE_UNSIGNEDSHORT: name = gSOAPStrings->kUnsignedIntSchemaType; break; case nsISchemaBuiltinType::BUILTIN_TYPE_DECIMAL: // name = kAnySimpleTypeSchemaType; name = gSOAPStrings->kAnyTypeSchemaType; break; case nsISchemaBuiltinType::BUILTIN_TYPE_FLOAT: // name = kAnySimpleTypeSchemaType; name = gSOAPStrings->kAnyTypeSchemaType; break; case nsISchemaBuiltinType::BUILTIN_TYPE_DOUBLE: // name = kAnySimpleTypeSchemaType; name = gSOAPStrings->kAnyTypeSchemaType; break; case nsISchemaBuiltinType::BUILTIN_TYPE_BOOLEAN: // name = kAnySimpleTypeSchemaType; name = gSOAPStrings->kAnyTypeSchemaType; break; case nsISchemaBuiltinType::BUILTIN_TYPE_TIME: // name = kAnySimpleTypeSchemaType; name = gSOAPStrings->kAnyTypeSchemaType; break; case nsISchemaBuiltinType::BUILTIN_TYPE_DATETIME: // name = kAnySimpleTypeSchemaType; name = gSOAPStrings->kAnyTypeSchemaType; break; case nsISchemaBuiltinType::BUILTIN_TYPE_DURATION: // name = kAnySimpleTypeSchemaType; name = gSOAPStrings->kAnyTypeSchemaType; break; case nsISchemaBuiltinType::BUILTIN_TYPE_DATE: // name = kAnySimpleTypeSchemaType; name = gSOAPStrings->kAnyTypeSchemaType; break; case nsISchemaBuiltinType::BUILTIN_TYPE_GMONTH: // name = kAnySimpleTypeSchemaType; name = gSOAPStrings->kAnyTypeSchemaType; break; case nsISchemaBuiltinType::BUILTIN_TYPE_GYEAR: // name = kAnySimpleTypeSchemaType; name = gSOAPStrings->kAnyTypeSchemaType; break; case nsISchemaBuiltinType::BUILTIN_TYPE_GYEARMONTH: // name = kAnySimpleTypeSchemaType; name = gSOAPStrings->kAnyTypeSchemaType; break; case nsISchemaBuiltinType::BUILTIN_TYPE_GDAY: // name = kAnySimpleTypeSchemaType; name = gSOAPStrings->kAnyTypeSchemaType; break; case nsISchemaBuiltinType::BUILTIN_TYPE_GMONTHDAY: // name = kAnySimpleTypeSchemaType; name = gSOAPStrings->kAnyTypeSchemaType; break; case nsISchemaBuiltinType::BUILTIN_TYPE_NAME: // name = kAnySimpleTypeSchemaType; name = gSOAPStrings->kAnyTypeSchemaType; break; case nsISchemaBuiltinType::BUILTIN_TYPE_QNAME: // name = kAnySimpleTypeSchemaType; name = gSOAPStrings->kAnyTypeSchemaType; break; case nsISchemaBuiltinType::BUILTIN_TYPE_NCNAME: name = gSOAPStrings->kNameSchemaType; break; case nsISchemaBuiltinType::BUILTIN_TYPE_ANYURI: // name = kAnySimpleTypeSchemaType; name = gSOAPStrings->kAnyTypeSchemaType; break; case nsISchemaBuiltinType::BUILTIN_TYPE_LANGUAGE: name = gSOAPStrings->kTokenSchemaType; break; case nsISchemaBuiltinType::BUILTIN_TYPE_ID: name = gSOAPStrings->kNCNameSchemaType; break; case nsISchemaBuiltinType::BUILTIN_TYPE_IDREF: name = gSOAPStrings->kNCNameSchemaType; break; case nsISchemaBuiltinType::BUILTIN_TYPE_IDREFS: name = gSOAPStrings->kNormalizedStringSchemaType; // Really a list... break; case nsISchemaBuiltinType::BUILTIN_TYPE_ENTITY: name = gSOAPStrings->kNCNameSchemaType; break; case nsISchemaBuiltinType::BUILTIN_TYPE_ENTITIES: name = gSOAPStrings->kNormalizedStringSchemaType; // Really a list... break; case nsISchemaBuiltinType::BUILTIN_TYPE_NOTATION: // name = kAnySimpleTypeSchemaType; name = gSOAPStrings->kAnyTypeSchemaType; break; case nsISchemaBuiltinType::BUILTIN_TYPE_NMTOKEN: name = gSOAPStrings->kTokenSchemaType; break; case nsISchemaBuiltinType::BUILTIN_TYPE_NMTOKENS: name = gSOAPStrings->kNormalizedStringSchemaType; // Really a list... break; } } } break; } } if (!base) { if (name.IsEmpty()) { switch (typevalue) { case nsISchemaType::SCHEMA_TYPE_COMPLEX: name = gSOAPStrings->kAnyTypeSchemaType; break; default: // name = kAnySimpleTypeSchemaType; name = gSOAPStrings->kAnyTypeSchemaType; } } nsCOMPtr collection; rc = aEncoding->GetSchemaCollection(getter_AddRefs(collection)); NS_ENSURE_SUCCESS(rc, rc); rc = collection->GetType(name, gSOAPStrings->kXSURI, getter_AddRefs(base)); // if (NS_FAILED(rc)) return rc; } NS_IF_ADDREF(*aResult = base); return NS_OK; } static nsresult EncodeSimpleValue(nsISOAPEncoding* aEncoding, const nsAString& aValue, const nsAString& aNamespaceURI, const nsAString& aName, nsISchemaType* aSchemaType, nsIDOMElement* aDestination, nsIDOMElement** aResult) { nsresult rc; PRBool needType = PR_TRUE; nsAutoString typeName; nsAutoString typeNS; if (aSchemaType) { rc = aSchemaType->GetName(typeName); NS_ENSURE_SUCCESS(rc, rc); rc = aSchemaType->GetTargetNamespace(typeNS); NS_ENSURE_SUCCESS(rc, rc); } nsAutoString name; // First choose the appropriate name and namespace for the element. nsAutoString ns; if (aName.IsEmpty()) { // We automatically choose appropriate element names where none exist. // The idea here seems to be to walk up the schema hierarchy to // find the base type and use the name of that as the element name. ns = gSOAPStrings->kSOAPEncURI; nsAutoString currentURI = ns; nsCOMPtr currentType = aSchemaType; while (currentType && !(currentURI.Equals(gSOAPStrings->kXSURI) || currentURI.Equals(gSOAPStrings->kSOAPEncURI))) { nsCOMPtr supertype; rc = GetSupertype(aEncoding, currentType, getter_AddRefs(supertype)); NS_ENSURE_SUCCESS(rc, rc); if (!currentType) { break; } currentType = supertype; rc = currentType->GetTargetNamespace(currentURI); NS_ENSURE_SUCCESS(rc, rc); } if (currentType) { rc = aSchemaType->GetName(name); NS_ENSURE_SUCCESS(rc, rc); } else { name = gSOAPStrings->kAnyTypeSchemaType; needType = PR_FALSE; } if (!typeNS.IsEmpty()) { ns.Truncate(); ns.SetIsVoid(true); rc = NS_OK; } else { rc = aEncoding->GetExternalSchemaURI(gSOAPStrings->kSOAPEncURI, ns); } } else { name = aName; rc = aEncoding->GetExternalSchemaURI(aNamespaceURI, ns); } NS_ENSURE_SUCCESS(rc, rc); nsCOMPtr document; rc = aDestination->GetOwnerDocument(getter_AddRefs(document)); NS_ENSURE_SUCCESS(rc, rc); nsCOMPtr element; rc = document->CreateElementNS(ns, name, getter_AddRefs(element)); NS_ENSURE_SUCCESS(rc, rc); nsCOMPtr ignore; rc = aDestination->AppendChild(element, getter_AddRefs(ignore)); NS_ENSURE_SUCCESS(rc, rc); if (needType) { if (typeNS.IsEmpty() && typeName.IsEmpty()) { typeName = gSOAPStrings->kAnyTypeSchemaType; rc = aEncoding->GetExternalSchemaURI(gSOAPStrings->kXSURI, typeNS); NS_ENSURE_SUCCESS(rc, rc); } nsAutoString type; rc = nsSOAPUtils::MakeNamespacePrefix(aEncoding, element, typeNS, type); NS_ENSURE_SUCCESS(rc, rc); type.Append(gSOAPStrings->kQualifiedSeparator); type.Append(typeName); rc = aEncoding->GetExternalSchemaURI(gSOAPStrings->kXSIURI, ns); NS_ENSURE_SUCCESS(rc, rc); rc = (element)-> SetAttributeNS(ns, gSOAPStrings->kXSITypeAttribute, type); NS_ENSURE_SUCCESS(rc, rc); } if (!aValue.IsEmpty()) { nsCOMPtr text; rc = document->CreateTextNode(aValue, getter_AddRefs(text)); NS_ENSURE_SUCCESS(rc, rc); rc = (element)->AppendChild(text, getter_AddRefs(ignore)); NS_ENSURE_SUCCESS(rc, rc); } NS_IF_ADDREF(*aResult = element); return rc; } // Testing for a simple value static nsresult HasSimpleValue(nsISchemaType * aSchemaType, PRBool * aResult) { PRUint16 typevalue; nsresult rc = aSchemaType->GetSchemaType(&typevalue); NS_ENSURE_SUCCESS(rc, rc); if (typevalue == nsISchemaComplexType::SCHEMA_TYPE_COMPLEX) { nsCOMPtr ct = do_QueryInterface(aSchemaType); rc = ct->GetContentModel(&typevalue); NS_ENSURE_SUCCESS(rc, rc); *aResult = typevalue == nsISchemaComplexType::CONTENT_MODEL_SIMPLE; } else { *aResult = PR_TRUE; } return NS_OK; } // Default NS_IMETHODIMP nsDefaultEncoder::Encode(nsISOAPEncoding* aEncoding, nsIVariant* aSource, const nsAString& aNamespaceURI, const nsAString& aName, nsISchemaType* aSchemaType, nsISOAPAttachments* aAttachments, nsIDOMElement* aDestination, nsIDOMElement** aReturnValue) { NS_ENSURE_ARG_POINTER(aEncoding); NS_ENSURE_ARG_POINTER(aDestination); NS_ENSURE_ARG_POINTER(aReturnValue); *aReturnValue = nsnull; if (aSource == nsnull) { nsAutoString ns; nsresult rc = aEncoding->GetExternalSchemaURI(gSOAPStrings->kXSIURI, ns); NS_ENSURE_SUCCESS(rc, rc); nsAutoString name; if (!aName.IsEmpty()) name.Assign(gSOAPStrings->kNull); rc = EncodeSimpleValue(aEncoding, gSOAPStrings->kEmpty, gSOAPStrings->kEmpty, name, nsnull, aDestination, aReturnValue); NS_ENSURE_SUCCESS(rc, rc); rc = (*aReturnValue)->SetAttributeNS(ns, gSOAPStrings->kNull, gSOAPStrings->kTrueA); NS_ENSURE_SUCCESS(rc, rc); } nsCOMPtr encoder; if (aSchemaType) { nsCOMPtr lookupType = aSchemaType; do { nsAutoString schemaType; nsAutoString schemaURI; nsAutoString encodingKey; nsresult rc = lookupType->GetName(schemaType); NS_ENSURE_SUCCESS(rc, rc); rc = lookupType->GetTargetNamespace(schemaURI); NS_ENSURE_SUCCESS(rc, rc); SOAPEncodingKey(schemaURI, schemaType, encodingKey); rc = aEncoding->GetEncoder(encodingKey, getter_AddRefs(encoder)); NS_ENSURE_SUCCESS(rc, rc); if (encoder) break; nsCOMPtr supertype; rc = GetSupertype(aEncoding, lookupType, getter_AddRefs(supertype)); NS_ENSURE_SUCCESS(rc, rc); lookupType = supertype; } while (lookupType); } if (!encoder) { nsAutoString encodingKey; SOAPEncodingKey(gSOAPStrings->kXSURI, gSOAPStrings->kAnyTypeSchemaType, encodingKey); nsresult rc = aEncoding->GetEncoder(encodingKey, getter_AddRefs(encoder)); NS_ENSURE_SUCCESS(rc, rc); } if (encoder) { return encoder->Encode(aEncoding, aSource, aNamespaceURI, aName, aSchemaType, aAttachments, aDestination, aReturnValue); } return SOAP_EXCEPTION(NS_ERROR_NOT_IMPLEMENTED, "SOAP_NO_ENCODER_FOR_TYPE", "The default encoder finds no encoder for specific type"); } static void GetNativeType(PRUint16 aType, nsAString & aSchemaNamespaceURI, nsAString & aSchemaType) { aSchemaNamespaceURI.Assign(gSOAPStrings->kXSURI); switch (aType) { case nsIDataType::VTYPE_CHAR_STR: case nsIDataType::VTYPE_WCHAR_STR: case nsIDataType::VTYPE_CHAR: case nsIDataType::VTYPE_WCHAR: case nsIDataType::VTYPE_STRING_SIZE_IS: case nsIDataType::VTYPE_WSTRING_SIZE_IS: case nsIDataType::VTYPE_ASTRING: case nsIDataType::VTYPE_DOMSTRING: case nsIDataType::VTYPE_CSTRING: case nsIDataType::VTYPE_UTF8STRING: aSchemaType.Assign(gSOAPStrings->kStringSchemaType); break; case nsIDataType::VTYPE_INT8: aSchemaType.Assign(gSOAPStrings->kByteSchemaType); break; case nsIDataType::VTYPE_INT16: aSchemaType.Assign(gSOAPStrings->kShortSchemaType); break; case nsIDataType::VTYPE_INT32: aSchemaType.Assign(gSOAPStrings->kIntSchemaType); break; case nsIDataType::VTYPE_INT64: aSchemaType.Assign(gSOAPStrings->kLongSchemaType); break; case nsIDataType::VTYPE_UINT8: aSchemaType.Assign(gSOAPStrings->kUnsignedByteSchemaType); break; case nsIDataType::VTYPE_UINT16: aSchemaType.Assign(gSOAPStrings->kUnsignedShortSchemaType); break; case nsIDataType::VTYPE_UINT32: aSchemaType.Assign(gSOAPStrings->kUnsignedIntSchemaType); break; case nsIDataType::VTYPE_UINT64: aSchemaType.Assign(gSOAPStrings->kUnsignedLongSchemaType); break; case nsIDataType::VTYPE_FLOAT: aSchemaType.Assign(gSOAPStrings->kFloatSchemaType); break; case nsIDataType::VTYPE_DOUBLE: aSchemaType.Assign(gSOAPStrings->kDoubleSchemaType); break; case nsIDataType::VTYPE_BOOL: aSchemaType.Assign(gSOAPStrings->kBooleanSchemaType); break; case nsIDataType::VTYPE_ARRAY: case nsIDataType::VTYPE_EMPTY_ARRAY: aSchemaType.Assign(gSOAPStrings->kArraySOAPType); aSchemaNamespaceURI.Assign(gSOAPStrings->kSOAPEncURI); break; // case nsIDataType::VTYPE_VOID: // case nsIDataType::VTYPE_EMPTY: // Empty may be either simple or complex. break; case nsIDataType::VTYPE_INTERFACE_IS: case nsIDataType::VTYPE_INTERFACE: aSchemaType.Assign(gSOAPStrings->kStructSOAPType); aSchemaNamespaceURI.Assign(gSOAPStrings->kSOAPEncURI); break; default: aSchemaType.Assign(gSOAPStrings->kAnySimpleTypeSchemaType); } } NS_IMETHODIMP nsAnyTypeEncoder::Encode(nsISOAPEncoding* aEncoding, nsIVariant* aSource, const nsAString& aNamespaceURI, const nsAString& aName, nsISchemaType* aSchemaType, nsISOAPAttachments* aAttachments, nsIDOMElement* aDestination, nsIDOMElement** aReturnValue) { NS_ENSURE_ARG_POINTER(aEncoding); NS_ENSURE_ARG_POINTER(aDestination); NS_ENSURE_ARG_POINTER(aReturnValue); *aReturnValue = nsnull; nsAutoString nativeSchemaType; nsAutoString nativeSchemaURI; PRUint16 typevalue; nsresult rc = aSource->GetDataType(&typevalue); NS_ENSURE_SUCCESS(rc, rc); // If there is a schema type then regular native types will not avail us anything. if (aSchemaType) { PRBool simple = PR_FALSE; rc = HasSimpleValue(aSchemaType, &simple); NS_ENSURE_SUCCESS(rc, rc); if (simple) { switch (typevalue) { case nsIDataType::VTYPE_ARRAY: case nsIDataType::VTYPE_EMPTY_ARRAY: case nsIDataType::VTYPE_INTERFACE_IS: case nsIDataType::VTYPE_INTERFACE: simple = PR_FALSE; break; } } if (simple) { nativeSchemaType.Assign(gSOAPStrings->kAnySimpleTypeSchemaType); nativeSchemaURI.Assign(gSOAPStrings->kXSURI); } else { nativeSchemaType.Assign(gSOAPStrings->kStructSOAPType); nativeSchemaURI.Assign(gSOAPStrings->kSOAPEncURI); } } else { GetNativeType(typevalue, nativeSchemaURI, nativeSchemaType); } nsCOMPtr encoder; nsAutoString encodingKey; SOAPEncodingKey(nativeSchemaURI, nativeSchemaType, encodingKey); rc = aEncoding->GetEncoder(encodingKey, getter_AddRefs(encoder)); NS_ENSURE_SUCCESS(rc, rc); if (encoder) { nsCOMPtr type; if (aSchemaType) { type = aSchemaType; } else { nsCOMPtr collection; nsresult rc = aEncoding->GetSchemaCollection(getter_AddRefs(collection)); NS_ENSURE_SUCCESS(rc, rc); rc = collection->GetType(nativeSchemaType, nativeSchemaURI, getter_AddRefs(type)); // if (NS_FAILED(rc)) return rc; } return encoder->Encode(aEncoding, aSource, aNamespaceURI, aName, type, aAttachments, aDestination, aReturnValue); } return SOAP_EXCEPTION(NS_ERROR_NOT_IMPLEMENTED, "SOAP_NO_ENCODER_FOR_TYPE", "The any type encoder finds no encoder for specific data"); } static nsresult EncodeStructParticle(nsISOAPEncoding* aEncoding, nsIPropertyBag* aPropertyBag, nsISchemaParticle* aParticle, nsISOAPAttachments * aAttachments, nsIDOMElement* aDestination) { nsresult rc; if (aParticle) { PRUint32 minOccurs; rc = aParticle->GetMinOccurs(&minOccurs); NS_ENSURE_SUCCESS(rc, rc); PRUint32 maxOccurs; rc = aParticle->GetMaxOccurs(&maxOccurs); NS_ENSURE_SUCCESS(rc, rc); PRUint16 particleType; rc = aParticle->GetParticleType(&particleType); NS_ENSURE_SUCCESS(rc, rc); switch(particleType) { case nsISchemaParticle::PARTICLE_TYPE_ELEMENT: { if (maxOccurs > 1) { // Todo: Try to make this thing work as an array? return NS_ERROR_NOT_AVAILABLE; // For now, we just try something else if we can (recoverable) } nsCOMPtr element = do_QueryInterface(aParticle); nsAutoString name; rc = element->GetTargetNamespace(name); NS_ENSURE_SUCCESS(rc, rc); if (!name.IsEmpty()) { rc = NS_ERROR_NOT_AVAILABLE; // No known way to use namespace qualification in struct } else { rc = element->GetName(name); NS_ENSURE_SUCCESS(rc, rc); rc = element->GetName(name); NS_ENSURE_SUCCESS(rc, rc); nsCOMPtr type; rc = element->GetType(getter_AddRefs(type)); NS_ENSURE_SUCCESS(rc, rc); nsCOMPtr value; rc = aPropertyBag->GetProperty(name, getter_AddRefs(value)); if (NS_SUCCEEDED(rc)) { nsCOMPtr dummy; rc = aEncoding->Encode(value, gSOAPStrings->kEmpty, name, type, aAttachments, aDestination, getter_AddRefs(dummy)); NS_ENSURE_SUCCESS(rc, rc); } } if (minOccurs == 0 && rc == NS_ERROR_NOT_AVAILABLE) { // If we succeeded or failed recoverably, but we were permitted to, // then return success rc = NS_OK; } return rc; } case nsISchemaParticle::PARTICLE_TYPE_MODEL_GROUP: { if (maxOccurs > 1) { // Todo: Try to make this thing work as an array? return NS_ERROR_NOT_AVAILABLE; // For now, we just try something else if we can (recoverable) } nsCOMPtr modelGroup = do_QueryInterface(aParticle); PRUint16 compositor; rc = modelGroup->GetCompositor(&compositor); NS_ENSURE_SUCCESS(rc, rc); PRUint32 particleCount; rc = modelGroup->GetParticleCount(&particleCount); NS_ENSURE_SUCCESS(rc, rc); PRUint32 i; for (i = 0; i < particleCount; i++) { nsCOMPtr child; rc = modelGroup->GetParticle(i, getter_AddRefs(child)); NS_ENSURE_SUCCESS(rc, rc); rc = EncodeStructParticle(aEncoding, aPropertyBag, child, aAttachments, aDestination); if (compositor == nsISchemaModelGroup::COMPOSITOR_CHOICE) { if (NS_SUCCEEDED(rc)) { return NS_OK; } if (rc == NS_ERROR_NOT_AVAILABLE) { // In a choice, recoverable model failures are OK. rc = NS_OK; } } else if (i > 0 && rc == NS_ERROR_NOT_AVAILABLE) { // This detects ambiguous model (non-deterministic choice which fails after succeeding on first) return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE, "SOAP_AMBIGUOUS_ENCODING", "Cannot proceed due to ambiguity or error in content model"); } if (NS_FAILED(rc)) break; } if (compositor == nsISchemaModelGroup::COMPOSITOR_CHOICE) // If choice selected nothing, this is recoverable failure rc = NS_ERROR_NOT_AVAILABLE; if (minOccurs == 0 && rc == NS_ERROR_NOT_AVAILABLE) // If we succeeded or failed recoverably, but we were permitted to, then return success rc = NS_OK; return rc; // Return status } case nsISchemaParticle::PARTICLE_TYPE_ANY: // No model available here (we may wish to handle strict versus lazy, but what does that mean with only local accessor names) default: break; } } nsCOMPtr e; rc = aPropertyBag->GetEnumerator(getter_AddRefs(e)); NS_ENSURE_SUCCESS(rc, rc); PRBool more; rc = e->HasMoreElements(&more); NS_ENSURE_SUCCESS(rc, rc); while (more) { nsCOMPtr p; rc = e->GetNext(getter_AddRefs(p)); NS_ENSURE_SUCCESS(rc, rc); nsAutoString name; rc = p->GetName(name); NS_ENSURE_SUCCESS(rc, rc); nsCOMPtrvalue; rc = p->GetValue(getter_AddRefs(value)); NS_ENSURE_SUCCESS(rc, rc); nsCOMPtrresult; rc = aEncoding->Encode(value,gSOAPStrings->kEmpty,name,nsnull,aAttachments,aDestination,getter_AddRefs(result)); NS_ENSURE_SUCCESS(rc, rc); rc = e->HasMoreElements(&more); NS_ENSURE_SUCCESS(rc, rc); } return NS_OK; } NS_IMETHODIMP nsStructEncoder::Encode(nsISOAPEncoding * aEncoding, nsIVariant * aSource, const nsAString & aNamespaceURI, const nsAString & aName, nsISchemaType * aSchemaType, nsISOAPAttachments * aAttachments, nsIDOMElement * aDestination, nsIDOMElement * *aReturnValue) { NS_ENSURE_ARG_POINTER(aEncoding); NS_ENSURE_ARG_POINTER(aDestination); NS_ENSURE_ARG_POINTER(aReturnValue); *aReturnValue = nsnull; nsIID* iid; nsCOMPtr ptr; nsresult rc = aSource->GetAsInterface(&iid, getter_AddRefs(ptr)); NS_ENSURE_SUCCESS(rc, rc); nsCOMPtrpbptr = do_QueryInterface(ptr); if (pbptr) { // Do any object that can QI to a property bag. nsCOMPtrmodelGroup; if (aSchemaType) { nsCOMPtrctype = do_QueryInterface(aSchemaType); if (ctype) { rc = ctype->GetModelGroup(getter_AddRefs(modelGroup)); NS_ENSURE_SUCCESS(rc, rc); } } // We still have to fake this one, because there is no struct type in schema. if (aName.IsEmpty() && !aSchemaType) { rc = EncodeSimpleValue(aEncoding, gSOAPStrings->kEmpty, gSOAPStrings->kSOAPEncURI, gSOAPStrings->kStructSOAPType, aSchemaType, aDestination, aReturnValue); } else { rc = EncodeSimpleValue(aEncoding, gSOAPStrings->kEmpty, aNamespaceURI, aName, aSchemaType, aDestination, aReturnValue); } NS_ENSURE_SUCCESS(rc, rc); return EncodeStructParticle(aEncoding, pbptr, modelGroup, aAttachments, *aReturnValue); } return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE, "SOAP_PROPERTYBAG_REQUIRED", "When encoding as a struct, an object with properties is required"); } // AnySimpleType NS_IMETHODIMP nsAnySimpleTypeEncoder::Encode(nsISOAPEncoding * aEncoding, nsIVariant * aSource, const nsAString & aNamespaceURI, const nsAString & aName, nsISchemaType * aSchemaType, nsISOAPAttachments * aAttachments, nsIDOMElement * aDestination, nsIDOMElement * *aReturnValue) { NS_ENSURE_ARG_POINTER(aEncoding); NS_ENSURE_ARG_POINTER(aDestination); NS_ENSURE_ARG_POINTER(aReturnValue); *aReturnValue = nsnull; nsresult rc; nsAutoString value; rc = aSource->GetAsAString(value); NS_ENSURE_SUCCESS(rc, rc); // We still have to fake this one, because there is no any simple type in schema. if (aName.IsEmpty() && !aSchemaType) { return EncodeSimpleValue(aEncoding, value, gSOAPStrings->kSOAPEncURI, gSOAPStrings->kAnySimpleTypeSchemaType, aSchemaType, aDestination, aReturnValue); } return EncodeSimpleValue(aEncoding, value, aNamespaceURI, aName, aSchemaType, aDestination, aReturnValue); } /** * Handle SOAP element mark as null with xsi:null or xsi:nil. * * @param aEncoding SOAP encoding (in). * @param aSource SOAP DOM element (in). * @param aSchemaType Type of the SOAP element (in). * @param aAttachments (in). * @param aNullAttr Value for a xsi:null of xsi:nil attribute, * could be either true or 1 (in). * @param aResult Value for this element (out). */ static nsresult HandleNull(nsISOAPEncoding* aEncoding, nsIDOMElement* aSource, nsISchemaType* aSchemaType, nsISOAPAttachments* aAttachments, nsAutoString aNullAttr, nsIVariant** aResult) { NS_ENSURE_ARG_POINTER(aEncoding); NS_ENSURE_ARG_POINTER(aSource); NS_ENSURE_ARG_POINTER(aResult); if (aNullAttr.Equals(gSOAPStrings->kTrue) || aNullAttr.Equals(gSOAPStrings->kTrueA)) { PRUint16 schemaType; nsAutoString typeName; if (aSchemaType) { aSchemaType->GetSchemaType(&schemaType); aSchemaType->GetName(typeName); } nsCOMPtr nullVariant(do_CreateInstance("@mozilla.org/variant;1")); if (!nullVariant) { return NS_ERROR_OUT_OF_MEMORY; } if (aSchemaType && (typeName.Equals(NS_LITERAL_STRING("string")) || typeName.Equals(NS_LITERAL_STRING("normalizedString")))) { nsAutoString strVal; strVal.SetIsVoid(true); nullVariant->SetAsAString(strVal); } else { nullVariant->SetAsISupports(nsnull); } NS_ADDREF(*aResult = nullVariant); return NS_OK; } else if (!(aNullAttr.Equals(gSOAPStrings->kFalse) || aNullAttr.Equals(gSOAPStrings->kFalseA))) { return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE, "SOAP_NILL_VALUE", "The value of the nill attribute must be true or false."); } #ifdef DEBUG NS_ERROR("How have you get here ?"); #endif return NS_ERROR_UNEXPECTED; } /** * SOAP code should be given the explit type not to have to look for it. * Get explicit schema type from SOAP DOM element. * * @param aEncoding SOAP encoding (in). * @param aElement DOM element from SOAP response (in). * @param aResult Explicit schema type [xsi:type] (out). */ static nsresult GetExplicitType(nsISOAPEncoding* aEncoding, nsIDOMElement* aElement, nsISchemaType** aResult) { NS_ENSURE_ARG_POINTER(aEncoding); NS_ENSURE_ARG_POINTER(aElement); nsresult rc = NS_OK; nsCOMPtr schemaLoader = do_GetService(NS_SCHEMALOADER_CONTRACTID, &rc); NS_ENSURE_SUCCESS(rc, rc); nsAutoString explicitType; if (nsSOAPUtils::GetAttribute(aEncoding, aElement, gSOAPStrings->kXSIURI, gSOAPStrings->kXSITypeAttribute, explicitType)) { nsAutoString ns; nsAutoString name; nsCOMPtr type; rc = nsSOAPUtils::GetNamespaceURI(aEncoding, aElement, explicitType, ns); NS_ENSURE_SUCCESS(rc, rc); rc = nsSOAPUtils::GetLocalName(explicitType, name); NS_ENSURE_SUCCESS(rc, rc); nsCOMPtr col = do_QueryInterface(schemaLoader); rc = col->GetType(name, ns, getter_AddRefs(type)); NS_IF_ADDREF(*aResult = type); return rc; } #ifdef DEBUG NS_ERROR("::GetExplicitType: Wow how do you get here"); #endif return NS_ERROR_UNEXPECTED; } /** * Recursive method used by array encoding which counts the sizes of * the specified dimensions and does a very primitive determination whether * all the members of the array are of a single homogenious type. * This intelligently skips nulls wherever they occur. */ static nsresult GetArrayType(nsIVariant* aSource, PRUint32 aDimensionCount, PRUint32* aDimensionSizes, PRUint16* aType) { if (!aSource) { *aType = nsIDataType::VTYPE_EMPTY; return NS_OK; } PRUint16 type; nsIID iid; PRUint32 count; void* array; nsresult rc; PRUint32 i; rc = aSource->GetDataType(&type); NS_ENSURE_SUCCESS(rc, rc); if (type == nsIDataType::VTYPE_EMPTY || type == nsIDataType::VTYPE_VOID || type == nsIDataType::VTYPE_EMPTY_ARRAY) { rc = NS_OK; count = 0; type = nsIDataType::VTYPE_EMPTY; array = nsnull; } else { rc = aSource->GetAsArray(&type, &iid, &count, &array); // First, get the array, if any. NS_ENSURE_SUCCESS(rc, rc); } if (count > aDimensionSizes[0]) { aDimensionSizes[0] = count; } if (aDimensionCount > 1) { if (type != nsIDataType::VTYPE_INTERFACE_IS || !iid.Equals(NS_GET_IID(nsIVariant))) { rc = SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,"SOAP_ARRAY_OBJECTS","When encoding as an array, an array of array objects is required"); // All nested arrays (which is what multi-dimensional arrays are) are variants. } else { nsIVariant** a = static_cast(array); PRUint16 rtype = nsIDataType::VTYPE_EMPTY; for (i = 0; i < count; i++) { PRUint16 nexttype; rc = GetArrayType(a[i], aDimensionCount - 1, aDimensionSizes + 1, &nexttype); if (NS_FAILED(rc)) break; if (rtype == nsIDataType::VTYPE_EMPTY) rtype = nexttype; else if (nexttype != nsIDataType::VTYPE_EMPTY && nexttype != rtype) rtype = nsIDataType::VTYPE_INTERFACE_IS; } *aType = rtype; } } else { *aType = type; } // The memory model for variant arrays' GetAsArray is difficult to manage switch (type) { case nsIDataType::VTYPE_INTERFACE_IS: { nsISupports** values = static_cast(array); for (i = 0; i < count; i++) NS_RELEASE(values[i]); } break; case nsIDataType::VTYPE_WCHAR_STR: case nsIDataType::VTYPE_CHAR_STR: { void** ptrs = static_cast(array); for (i = 0; i < count; i++) { nsMemory::Free(ptrs[i]); } } break; } nsMemory::Free(array); { // Individual lengths guaranteed to fit because variant array length is 32-bit. PRUint64 tot = 1; // Collect in 64 bits, just to make sure combo fits for (i = 0; i < aDimensionCount; i++) { tot = tot * aDimensionSizes[i]; if (tot > 0xffffffffU) { return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE, "SOAP_ARRAY_TOO_BIG", "When encoding an object as an array, the total count of items exceeded maximum."); } } } return rc; } /** * Recursive method used by array encoding to encode the next level of the array into the * established array element. If dimension count is > 1, then it recursively doles out * the work. This intelligently skips nulls wherever they occur. */ static nsresult EncodeArray(nsISOAPEncoding* aEncoding, nsIVariant* aSource, nsISchemaType* aSchemaType, nsISOAPAttachments* aAttachments, nsIDOMElement* aArray, PRUint32 aDimensionCount, PRUint32* aDimensionSizes) { nsresult rc; PRUint16 type; nsIID iid; PRUint32 count; void *array; if (aSource != nsnull) { rc = aSource->GetDataType(&type); NS_ENSURE_SUCCESS(rc, rc); if (type == nsIDataType::VTYPE_EMPTY || type == nsIDataType::VTYPE_VOID || type == nsIDataType::VTYPE_EMPTY_ARRAY) { rc = NS_OK; count = 0; type = nsIDataType::VTYPE_EMPTY; array = nsnull; } else { rc = aSource->GetAsArray(&type, &iid, &count, &array); // First, get the array, if any. NS_ENSURE_SUCCESS(rc, rc); } } else { // If the source is null, then just add a bunch of nulls to the array. count = (PRUint32)aDimensionSizes[--aDimensionCount]; while (aDimensionCount) count *= (PRUint32)aDimensionSizes[--aDimensionCount]; if (count) { nsAutoString ns; nsCOMPtr cloneable; rc = aEncoding->GetExternalSchemaURI(gSOAPStrings->kXSIURI, ns); NS_ENSURE_SUCCESS(rc, rc); rc = EncodeSimpleValue(aEncoding, gSOAPStrings->kEmpty, gSOAPStrings->kEmpty, gSOAPStrings->kNull, nsnull, aArray, getter_AddRefs(cloneable)); NS_ENSURE_SUCCESS(rc, rc); rc = cloneable->SetAttributeNS(ns, gSOAPStrings->kNull, gSOAPStrings->kTrueA); NS_ENSURE_SUCCESS(rc, rc); nsCOMPtr clone; nsCOMPtr dummy; for (;--count;) { rc = cloneable->CloneNode(PR_TRUE, getter_AddRefs(clone));// No children so deep == shallow NS_ENSURE_SUCCESS(rc, rc); rc = aArray->AppendChild(clone, getter_AddRefs(dummy)); NS_ENSURE_SUCCESS(rc, rc); } } } nsCOMPtr dummy; PRBool freeptrs = PR_FALSE; PRUint32 i; // The more-robust way of encoding is to construct variants and call the encoder directly, // but for now, we short-circuit it for simple types. #define ENCODE_SIMPLE_ARRAY(XPType, VType, Source) \ { \ XPType* values = static_cast(array); \ nsCOMPtr p = \ do_CreateInstance(NS_VARIANT_CONTRACTID, &rc); \ if (NS_FAILED(rc)) break; \ for (i = 0; i < count; i++) { \ if (NS_FAILED(rc)) \ break; \ rc = p->SetAs##VType(Source); \ if (NS_FAILED(rc)) \ break; \ rc = aEncoding->Encode(p, \ gSOAPStrings->kEmpty, \ gSOAPStrings->kEmpty, \ aSchemaType, \ aAttachments, \ aArray, \ getter_AddRefs(dummy)); \ if (NS_FAILED(rc)) break; \ } \ break; \ } if (aDimensionCount > 1) { switch (type) { case nsIDataType::VTYPE_INTERFACE_IS: { nsIVariant** values = static_cast(array);// If not truly a variant, we only release. if (iid.Equals(NS_GET_IID(nsIVariant))) { // Only do variants for now. for (i = 0; i < count; i++) { rc = EncodeArray(aEncoding, values[i], aSchemaType, aAttachments, aArray, aDimensionCount - 1, aDimensionSizes + 1); if (NS_FAILED(rc)) break; } } for (i = 0; i < count; i++) NS_RELEASE(values[i]); break; } case nsIDataType::VTYPE_WCHAR_STR: case nsIDataType::VTYPE_CHAR_STR: freeptrs = PR_TRUE; default: rc = SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,"SOAP_ARRAY_OBJECTS","When encoding as an array, an array of array objects is required"); } } else switch (type) { case nsIDataType::VTYPE_INT8: ENCODE_SIMPLE_ARRAY(PRUint8, Int8, (signed char) values[i]); case nsIDataType::VTYPE_INT16: ENCODE_SIMPLE_ARRAY(PRInt16, Int16, values[i]); case nsIDataType::VTYPE_INT32: ENCODE_SIMPLE_ARRAY(PRInt32, Int32, values[i]); case nsIDataType::VTYPE_INT64: ENCODE_SIMPLE_ARRAY(PRInt64, Int64, values[i]); case nsIDataType::VTYPE_UINT8: ENCODE_SIMPLE_ARRAY(PRUint8, Uint8, values[i]); case nsIDataType::VTYPE_UINT16: ENCODE_SIMPLE_ARRAY(PRUint16, Uint16, values[i]); case nsIDataType::VTYPE_UINT32: ENCODE_SIMPLE_ARRAY(PRUint32, Uint32, values[i]); case nsIDataType::VTYPE_UINT64: ENCODE_SIMPLE_ARRAY(PRUint64, Uint64, values[i]); case nsIDataType::VTYPE_FLOAT: ENCODE_SIMPLE_ARRAY(float, Float, values[i]); case nsIDataType::VTYPE_DOUBLE: ENCODE_SIMPLE_ARRAY(double, Double, values[i]); case nsIDataType::VTYPE_BOOL: ENCODE_SIMPLE_ARRAY(PRBool, Bool, (PRUint16) values[i]); case nsIDataType::VTYPE_ID: case nsIDataType::VTYPE_CHAR_STR: freeptrs = PR_TRUE; ENCODE_SIMPLE_ARRAY(char *, String, values[i]); case nsIDataType::VTYPE_WCHAR_STR: freeptrs = PR_TRUE; ENCODE_SIMPLE_ARRAY(PRUnichar *, WString, values[i]); case nsIDataType::VTYPE_CHAR: ENCODE_SIMPLE_ARRAY(char, Char, values[i]); case nsIDataType::VTYPE_WCHAR: ENCODE_SIMPLE_ARRAY(PRUnichar, WChar, values[i]); case nsIDataType::VTYPE_INTERFACE_IS: { nsIVariant** values = static_cast(array);// If not truly a variant, we only use as nsISupports if (iid.Equals(NS_GET_IID(nsIVariant))) { // Only do variants for now. for (i = 0; i < count; i++) { rc = aEncoding->Encode(values[i], gSOAPStrings->kEmpty, gSOAPStrings->kEmpty, aSchemaType, aAttachments, aArray, getter_AddRefs(dummy)); if (NS_FAILED(rc)) break; } } else { nsCOMPtr p = do_CreateInstance(NS_VARIANT_CONTRACTID, &rc); if (NS_FAILED(rc)) break; for (i = 0; i < count; i++) { if (NS_FAILED(rc)) break; rc = p->SetAsInterface(iid, values[i]); if (NS_FAILED(rc)) break; rc = aEncoding->Encode(p, gSOAPStrings->kEmpty, gSOAPStrings->kEmpty, aSchemaType, aAttachments, aArray, getter_AddRefs(dummy)); if (NS_FAILED(rc)) break; } } for (i = 0; i < count; i++) NS_RELEASE(values[i]); break; } case nsIDataType::VTYPE_EMPTY_ARRAY: case nsIDataType::VTYPE_EMPTY: break; // I think an empty array needs no elements? // Don't support these array types, as they seem meaningless. case nsIDataType::VTYPE_ASTRING: case nsIDataType::VTYPE_VOID: case nsIDataType::VTYPE_INTERFACE: case nsIDataType::VTYPE_ARRAY: rc = SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,"SOAP_ARRAY_TYPES","When encoding an array, unable to handle array elements"); } if (freeptrs) { void** ptrs = static_cast(array); for (i = 0; i < count; i++) { nsMemory::Free(ptrs[i]); } nsMemory::Free(array); } // We know that count does not exceed size of dimension, but it may be less return rc; } NS_IMETHODIMP nsArrayEncoder::Encode(nsISOAPEncoding * aEncoding, nsIVariant * aSource, const nsAString & aNamespaceURI, const nsAString & aName, nsISchemaType * aSchemaType, nsISOAPAttachments * aAttachments, nsIDOMElement * aDestination, nsIDOMElement * *aReturnValue) { NS_ENSURE_ARG_POINTER(aEncoding); NS_ENSURE_ARG_POINTER(aDestination); NS_ENSURE_ARG_POINTER(aReturnValue); *aReturnValue = nsnull; PRUint16 arrayNativeType; PRUint32 dimensionSizes[MAX_ARRAY_DIMENSIONS]; PRUint32 i; PRUint32 dimensionCount = 1; nsCOMPtr schemaArrayType; if (aSchemaType) { PRUint16 type; nsresult rc = aSchemaType->GetSchemaType(&type); NS_ENSURE_SUCCESS(rc, rc); if (type == nsISchemaType::SCHEMA_TYPE_COMPLEX) { nsCOMPtr ct = do_QueryInterface(aSchemaType); nsresult rc = ct->GetArrayDimension(&dimensionCount); NS_ENSURE_SUCCESS(rc, rc); if (dimensionCount == 0) { dimensionCount = 1; } else { // Arrays with no defaults are supposed to return 0, but apparently do not rc = ct->GetArrayType(getter_AddRefs(schemaArrayType)); NS_ENSURE_SUCCESS(rc, rc); } } } for (i = 0; i < dimensionCount; i++) dimensionSizes[i] = 0; // Look over the array and find its dimensions and common type. nsresult rc = GetArrayType(aSource, dimensionCount, dimensionSizes, &arrayNativeType); NS_ENSURE_SUCCESS(rc, rc); nsAutoString arrayTypeSchemaURI; nsAutoString arrayTypeSchemaName; if (!schemaArrayType) { switch (arrayNativeType) { case nsIDataType::VTYPE_INTERFACE: // In a variant, an interface is a struct, but here it is any case nsIDataType::VTYPE_INTERFACE_IS: arrayTypeSchemaName = gSOAPStrings->kAnyTypeSchemaType; arrayTypeSchemaURI = gSOAPStrings->kXSURI; break; default: // Everything else can be interpreted correctly GetNativeType(arrayNativeType, arrayTypeSchemaURI, arrayTypeSchemaName); } nsCOMPtr collection; nsresult rc = aEncoding->GetSchemaCollection(getter_AddRefs(collection)); NS_ENSURE_SUCCESS(rc, rc); rc = collection->GetType(arrayTypeSchemaName, arrayTypeSchemaName, getter_AddRefs(schemaArrayType)); // if (NS_FAILED(rc)) return rc; } else { rc = schemaArrayType->GetTargetNamespace(arrayTypeSchemaURI); NS_ENSURE_SUCCESS(rc, rc); rc = schemaArrayType->GetName(arrayTypeSchemaName); NS_ENSURE_SUCCESS(rc, rc); } rc = EncodeSimpleValue(aEncoding, gSOAPStrings->kEmpty, aNamespaceURI, aName, aSchemaType, aDestination, aReturnValue); NS_ENSURE_SUCCESS(rc, rc); // This needs a real live interpretation of the type. { nsAutoString value; nsSOAPUtils::MakeNamespacePrefix(aEncoding,*aReturnValue,arrayTypeSchemaURI,value); value.Append(gSOAPStrings->kQualifiedSeparator); value.Append(arrayTypeSchemaName); value.Append(PRUnichar('[')); for (i = 0; i < dimensionCount; i++) { if (i > 0) value.Append(PRUnichar(',')); char* ptr = PR_smprintf("%d", dimensionSizes[i]); AppendUTF8toUTF16(ptr, value); PR_smprintf_free(ptr); } value.Append(PRUnichar(']')); nsAutoString encURI; rc = aEncoding->GetExternalSchemaURI(gSOAPStrings->kSOAPEncURI,encURI); NS_ENSURE_SUCCESS(rc, rc); rc = (*aReturnValue)->SetAttributeNS(encURI, gSOAPStrings->kSOAPArrayTypeAttribute, value); NS_ENSURE_SUCCESS(rc, rc); } // For efficiency, we should perform encoder lookup once here. return EncodeArray(aEncoding, aSource, schemaArrayType, aAttachments, *aReturnValue, dimensionCount, dimensionSizes); } // String NS_IMETHODIMP nsStringEncoder::Encode(nsISOAPEncoding * aEncoding, nsIVariant * aSource, const nsAString & aNamespaceURI, const nsAString & aName, nsISchemaType * aSchemaType, nsISOAPAttachments * aAttachments, nsIDOMElement * aDestination, nsIDOMElement * *aReturnValue) { NS_ENSURE_ARG_POINTER(aEncoding); NS_ENSURE_ARG_POINTER(aDestination); NS_ENSURE_ARG_POINTER(aReturnValue); *aReturnValue = nsnull; nsresult rc; nsAutoString value; rc = aSource->GetAsAString(value); NS_ENSURE_SUCCESS(rc, rc); return EncodeSimpleValue(aEncoding, value, aNamespaceURI, aName, aSchemaType, aDestination, aReturnValue); } // PRBool NS_IMETHODIMP nsBooleanEncoder::Encode(nsISOAPEncoding * aEncoding, nsIVariant * aSource, const nsAString & aNamespaceURI, const nsAString & aName, nsISchemaType * aSchemaType, nsISOAPAttachments * aAttachments, nsIDOMElement * aDestination, nsIDOMElement * *aReturnValue) { NS_ENSURE_ARG_POINTER(aEncoding); NS_ENSURE_ARG_POINTER(aDestination); NS_ENSURE_ARG_POINTER(aReturnValue); *aReturnValue = nsnull; nsresult rc; PRBool b; rc = aSource->GetAsBool(&b); NS_ENSURE_SUCCESS(rc, rc); return EncodeSimpleValue(aEncoding, b ? gSOAPStrings->kTrueA : gSOAPStrings->kFalseA, aNamespaceURI, aName, aSchemaType, aDestination, aReturnValue); } // Double NS_IMETHODIMP nsDoubleEncoder::Encode(nsISOAPEncoding * aEncoding, nsIVariant * aSource, const nsAString & aNamespaceURI, const nsAString & aName, nsISchemaType * aSchemaType, nsISOAPAttachments * aAttachments, nsIDOMElement * aDestination, nsIDOMElement * *aReturnValue) { NS_ENSURE_ARG_POINTER(aEncoding); NS_ENSURE_ARG_POINTER(aDestination); NS_ENSURE_ARG_POINTER(aReturnValue); *aReturnValue = nsnull; nsresult rc; double f; rc = aSource->GetAsDouble(&f); // Check that double works. NS_ENSURE_SUCCESS(rc, rc); nsAutoString value; // Note that AppendFloat actually takes a double, so this is ok. value.AppendFloat(f); return EncodeSimpleValue(aEncoding, value, aNamespaceURI, aName, aSchemaType, aDestination, aReturnValue); } // Float NS_IMETHODIMP nsFloatEncoder::Encode(nsISOAPEncoding * aEncoding, nsIVariant * aSource, const nsAString & aNamespaceURI, const nsAString & aName, nsISchemaType * aSchemaType, nsISOAPAttachments * aAttachments, nsIDOMElement * aDestination, nsIDOMElement * *aReturnValue) { NS_ENSURE_ARG_POINTER(aEncoding); NS_ENSURE_ARG_POINTER(aDestination); NS_ENSURE_ARG_POINTER(aReturnValue); *aReturnValue = nsnull; nsresult rc; float f; rc = aSource->GetAsFloat(&f); // Check that float works. NS_ENSURE_SUCCESS(rc, rc); nsAutoString value; value.AppendFloat(f); return EncodeSimpleValue(aEncoding, value, aNamespaceURI, aName, aSchemaType, aDestination, aReturnValue); } // PRInt64 NS_IMETHODIMP nsLongEncoder::Encode(nsISOAPEncoding * aEncoding, nsIVariant * aSource, const nsAString & aNamespaceURI, const nsAString & aName, nsISchemaType * aSchemaType, nsISOAPAttachments * aAttachments, nsIDOMElement * aDestination, nsIDOMElement * *aReturnValue) { NS_ENSURE_ARG_POINTER(aEncoding); NS_ENSURE_ARG_POINTER(aDestination); NS_ENSURE_ARG_POINTER(aReturnValue); *aReturnValue = nsnull; nsresult rc; PRInt64 f; rc = aSource->GetAsInt64(&f); // Get as a long number. NS_ENSURE_SUCCESS(rc, rc); char *ptr = PR_smprintf("%lld", f); if (!ptr) return NS_ERROR_OUT_OF_MEMORY; nsAutoString value; CopyASCIItoUTF16(nsDependentCString(ptr), value); PR_smprintf_free(ptr); return EncodeSimpleValue(aEncoding, value, aNamespaceURI, aName, aSchemaType, aDestination, aReturnValue); } // PRInt32 NS_IMETHODIMP nsIntEncoder::Encode(nsISOAPEncoding * aEncoding, nsIVariant * aSource, const nsAString & aNamespaceURI, const nsAString & aName, nsISchemaType * aSchemaType, nsISOAPAttachments * aAttachments, nsIDOMElement * aDestination, nsIDOMElement * *aReturnValue) { NS_ENSURE_ARG_POINTER(aEncoding); NS_ENSURE_ARG_POINTER(aDestination); NS_ENSURE_ARG_POINTER(aReturnValue); *aReturnValue = nsnull; nsresult rc; PRInt32 f; rc = aSource->GetAsInt32(&f); // Get as a long number. NS_ENSURE_SUCCESS(rc, rc); char *ptr = PR_smprintf("%d", f); if (!ptr) return NS_ERROR_OUT_OF_MEMORY; nsAutoString value; CopyASCIItoUTF16(nsDependentCString(ptr), value); PR_smprintf_free(ptr); return EncodeSimpleValue(aEncoding, value, aNamespaceURI, aName, aSchemaType, aDestination, aReturnValue); } // PRInt16 NS_IMETHODIMP nsShortEncoder::Encode(nsISOAPEncoding * aEncoding, nsIVariant * aSource, const nsAString & aNamespaceURI, const nsAString & aName, nsISchemaType * aSchemaType, nsISOAPAttachments * aAttachments, nsIDOMElement * aDestination, nsIDOMElement * *aReturnValue) { NS_ENSURE_ARG_POINTER(aEncoding); NS_ENSURE_ARG_POINTER(aDestination); NS_ENSURE_ARG_POINTER(aReturnValue); *aReturnValue = nsnull; nsresult rc; PRInt16 f; rc = aSource->GetAsInt16(&f); // Get as a long number. NS_ENSURE_SUCCESS(rc, rc); char *ptr = PR_smprintf("%d", (PRInt32) f); if (!ptr) return NS_ERROR_OUT_OF_MEMORY; nsAutoString value; CopyASCIItoUTF16(nsDependentCString(ptr), value); PR_smprintf_free(ptr); return EncodeSimpleValue(aEncoding, value, aNamespaceURI, aName, aSchemaType, aDestination, aReturnValue); } // Byte NS_IMETHODIMP nsByteEncoder::Encode(nsISOAPEncoding * aEncoding, nsIVariant * aSource, const nsAString & aNamespaceURI, const nsAString & aName, nsISchemaType * aSchemaType, nsISOAPAttachments * aAttachments, nsIDOMElement * aDestination, nsIDOMElement * *aReturnValue) { NS_ENSURE_ARG_POINTER(aEncoding); NS_ENSURE_ARG_POINTER(aDestination); NS_ENSURE_ARG_POINTER(aReturnValue); *aReturnValue = nsnull; nsresult rc; PRUint8 f; rc = aSource->GetAsInt8(&f); // Get as a long number. NS_ENSURE_SUCCESS(rc, rc); char *ptr = PR_smprintf("%d", (PRInt32) (signed char) f); if (!ptr) return NS_ERROR_OUT_OF_MEMORY; nsAutoString value; CopyASCIItoUTF16(nsDependentCString(ptr), value); PR_smprintf_free(ptr); return EncodeSimpleValue(aEncoding, value, aNamespaceURI, aName, aSchemaType, aDestination, aReturnValue); } // PRUint64 NS_IMETHODIMP nsUnsignedLongEncoder::Encode(nsISOAPEncoding * aEncoding, nsIVariant * aSource, const nsAString & aNamespaceURI, const nsAString & aName, nsISchemaType * aSchemaType, nsISOAPAttachments * aAttachments, nsIDOMElement * aDestination, nsIDOMElement * *aReturnValue) { NS_ENSURE_ARG_POINTER(aEncoding); NS_ENSURE_ARG_POINTER(aDestination); NS_ENSURE_ARG_POINTER(aReturnValue); *aReturnValue = nsnull; nsresult rc; PRUint64 f; rc = aSource->GetAsUint64(&f); // Get as a long number. NS_ENSURE_SUCCESS(rc, rc); char *ptr = PR_smprintf("%llu", f); if (!ptr) return NS_ERROR_OUT_OF_MEMORY; nsAutoString value; CopyASCIItoUTF16(nsDependentCString(ptr), value); PR_smprintf_free(ptr); return EncodeSimpleValue(aEncoding, value, aNamespaceURI, aName, aSchemaType, aDestination, aReturnValue); } // PRUint32 NS_IMETHODIMP nsUnsignedIntEncoder::Encode(nsISOAPEncoding * aEncoding, nsIVariant * aSource, const nsAString & aNamespaceURI, const nsAString & aName, nsISchemaType * aSchemaType, nsISOAPAttachments * aAttachments, nsIDOMElement * aDestination, nsIDOMElement * *aReturnValue) { NS_ENSURE_ARG_POINTER(aEncoding); NS_ENSURE_ARG_POINTER(aDestination); NS_ENSURE_ARG_POINTER(aReturnValue); *aReturnValue = nsnull; nsresult rc; PRUint32 f; rc = aSource->GetAsUint32(&f); // Get as a long number. NS_ENSURE_SUCCESS(rc, rc); char *ptr = PR_smprintf("%u", f); if (!ptr) return NS_ERROR_OUT_OF_MEMORY; nsAutoString value; CopyASCIItoUTF16(nsDependentCString(ptr), value); PR_smprintf_free(ptr); return EncodeSimpleValue(aEncoding, value, aNamespaceURI, aName, aSchemaType, aDestination, aReturnValue); } NS_IMETHODIMP nsBase64BinaryEncoder::Encode(nsISOAPEncoding * aEncoding, nsIVariant * aSource, const nsAString & aNamespaceURI, const nsAString & aName, nsISchemaType * aSchemaType, nsISOAPAttachments * aAttachments, nsIDOMElement * aDestination, nsIDOMElement * *aReturnValue) { NS_ENSURE_ARG_POINTER(aSource); NS_ENSURE_ARG_POINTER(aEncoding); NS_ENSURE_ARG_POINTER(aDestination); NS_ENSURE_ARG_POINTER(aReturnValue); *aReturnValue = nsnull; PRUint16 typeValue; nsresult rv = aSource->GetDataType(&typeValue); NS_ENSURE_SUCCESS(rv, rv); if (typeValue != nsIDataType::VTYPE_ARRAY) { return NS_ERROR_FAILURE; } nsIID iid; PRUint32 count; void* array; rv = aSource->GetAsArray(&typeValue, &iid, &count, &array); NS_ENSURE_SUCCESS(rv, rv); if (typeValue != nsIDataType::VTYPE_UINT8) { return NS_ERROR_FAILURE; } char* encodedVal = PL_Base64Encode(static_cast(array), count, nsnull); if (!encodedVal) { return NS_ERROR_FAILURE; } nsAdoptingCString encodedString(encodedVal); nsAutoString name, ns; if (aName.IsEmpty()) { // If we don't have a name, we pick soapenc:base64Binary. rv = aEncoding->GetStyleURI(ns); NS_ENSURE_SUCCESS(rv, rv); name.Append(gSOAPStrings->kBase64BinarySchemaType); } else { name = aName; // ns remains empty. This is ok. } nsCOMPtr document; rv = aDestination->GetOwnerDocument(getter_AddRefs(document)); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr element; rv = document->CreateElementNS(ns, name, getter_AddRefs(element)); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr ignore; rv = aDestination->AppendChild(element, getter_AddRefs(ignore)); NS_ENSURE_SUCCESS(rv, rv); if (aSchemaType) { nsAutoString typeName, typeNS; rv = aSchemaType->GetName(typeName); NS_ENSURE_SUCCESS(rv, rv); rv = aSchemaType->GetTargetNamespace(typeNS); NS_ENSURE_SUCCESS(rv, rv); nsAutoString qname; rv = nsSOAPUtils::MakeNamespacePrefix(nsnull, element, typeNS, qname); NS_ENSURE_SUCCESS(rv, rv); qname.Append(gSOAPStrings->kQualifiedSeparator + typeName); nsAutoString ns; rv = aEncoding->GetExternalSchemaURI(gSOAPStrings->kXSIURI, ns); NS_ENSURE_SUCCESS(rv, rv); rv = element->SetAttributeNS(ns, gSOAPStrings->kXSITypeAttribute, qname); NS_ENSURE_SUCCESS(rv, rv); } nsCOMPtr text; rv = document->CreateTextNode(NS_ConvertASCIItoUTF16(encodedString), getter_AddRefs(text)); NS_ENSURE_SUCCESS(rv, rv); rv = element->AppendChild(text, getter_AddRefs(ignore)); NS_ENSURE_SUCCESS(rv, rv); NS_ADDREF(*aReturnValue = element); return rv; } // PRUint16 NS_IMETHODIMP nsUnsignedShortEncoder::Encode(nsISOAPEncoding * aEncoding, nsIVariant * aSource, const nsAString & aNamespaceURI, const nsAString & aName, nsISchemaType * aSchemaType, nsISOAPAttachments * aAttachments, nsIDOMElement * aDestination, nsIDOMElement * *aReturnValue) { NS_ENSURE_ARG_POINTER(aEncoding); NS_ENSURE_ARG_POINTER(aDestination); NS_ENSURE_ARG_POINTER(aReturnValue); *aReturnValue = nsnull; nsresult rc; PRUint16 f; rc = aSource->GetAsUint16(&f); // Get as a long number. NS_ENSURE_SUCCESS(rc, rc); char *ptr = PR_smprintf("%u", (PRUint32) f); if (!ptr) return NS_ERROR_OUT_OF_MEMORY; nsAutoString value; CopyASCIItoUTF16(nsDependentCString(ptr), value); PR_smprintf_free(ptr); return EncodeSimpleValue(aEncoding, value, aNamespaceURI, aName, aSchemaType, aDestination, aReturnValue); } // Unsigned Byte NS_IMETHODIMP nsUnsignedByteEncoder::Encode(nsISOAPEncoding * aEncoding, nsIVariant * aSource, const nsAString & aNamespaceURI, const nsAString & aName, nsISchemaType * aSchemaType, nsISOAPAttachments * aAttachments, nsIDOMElement * aDestination, nsIDOMElement * *aReturnValue) { NS_ENSURE_ARG_POINTER(aEncoding); NS_ENSURE_ARG_POINTER(aDestination); NS_ENSURE_ARG_POINTER(aReturnValue); *aReturnValue = nsnull; nsresult rc; PRUint8 f; rc = aSource->GetAsUint8(&f); // Get as a long number. NS_ENSURE_SUCCESS(rc, rc); char *ptr = PR_smprintf("%u", (PRUint32) f); if (!ptr) return NS_ERROR_OUT_OF_MEMORY; nsAutoString value; CopyASCIItoUTF16(nsDependentCString(ptr), value); PR_smprintf_free(ptr); return EncodeSimpleValue(aEncoding, value, aNamespaceURI, aName, aSchemaType, aDestination, aReturnValue); } NS_IMETHODIMP nsDefaultEncoder::Decode(nsISOAPEncoding* aEncoding, nsIDOMElement* aSource, nsISchemaType* aSchemaType, nsISOAPAttachments* aAttachments, nsIVariant** aResult) { NS_ENSURE_ARG_POINTER(aEncoding); NS_ENSURE_ARG_POINTER(aSource); NS_ENSURE_ARG_POINTER(aResult); *aResult = nsnull; nsCOMPtr encoding = aEncoding; // First, handle encoding redesignation, if any nsCOMPtr schemaType; nsresult rv = GetExplicitType(aEncoding, aSource, getter_AddRefs(schemaType)); if (NS_FAILED(rv) || !schemaType) { schemaType = aSchemaType; } { nsCOMPtr enc; nsresult rv = aSource-> GetAttributeNodeNS(*gSOAPStrings->kSOAPEnvURI[mSOAPVersion], gSOAPStrings->kEncodingStyleAttribute, getter_AddRefs(enc)); NS_ENSURE_SUCCESS(rv, rv); if (enc) { nsAutoString oldstyle; rv = encoding->GetStyleURI(oldstyle); NS_ENSURE_SUCCESS(rv, rv); nsAutoString style; rv = enc->GetNodeValue(style); NS_ENSURE_SUCCESS(rv, rv); if (!style.Equals(oldstyle)) { nsCOMPtr newencoding; rv = encoding->GetAssociatedEncoding(style, PR_FALSE, getter_AddRefs(newencoding)); NS_ENSURE_SUCCESS(rv, rv); if (newencoding) { return newencoding->Decode(aSource, aSchemaType, aAttachments, aResult); } } } } // Handle xsi:null="true|1" and xsi:nil="true|1" nsAutoString nullstr; if (nsSOAPUtils::GetAttribute(aEncoding, aSource, gSOAPStrings->kXSIURI, gSOAPStrings->kNull, nullstr) || nsSOAPUtils::GetAttribute(aEncoding, aSource, gSOAPStrings->kXSIURI, gSOAPStrings->kNil, nullstr)) { return HandleNull(aEncoding, aSource, schemaType, aAttachments, nullstr, aResult); } nsCOMPtr type = schemaType; nsCOMPtr decoder; // All that comes out of this block is decoder, type, and some checks. { // Look up type element and schema attribute, if possible nsCOMPtr subType; nsCOMPtr collection; nsresult rc = aEncoding->GetSchemaCollection(getter_AddRefs(collection)); NS_ENSURE_SUCCESS(rc, rc); nsAutoString ns; nsAutoString name; rc = aSource->GetNamespaceURI(name); NS_ENSURE_SUCCESS(rc, rc); rc = aEncoding->GetInternalSchemaURI(name, ns); NS_ENSURE_SUCCESS(rc, rc); rc = aSource->GetLocalName(name); NS_ENSURE_SUCCESS(rc, rc); nsCOMPtr element; rc = collection->GetElement(name, ns, getter_AddRefs(element)); // if (NS_FAILED(rc)) return rc; if (element) { rc = element->GetType(getter_AddRefs(subType)); NS_ENSURE_SUCCESS(rc, rc); } else { nsAutoString internal; rc = aEncoding->GetInternalSchemaURI(ns, internal); NS_ENSURE_SUCCESS(rc, rc); if (internal.Equals(gSOAPStrings->kSOAPEncURI)) { // Last-ditch hack to get undeclared types from SOAP namespace if (name.Equals(gSOAPStrings->kArraySOAPType) || name.Equals(gSOAPStrings->kStructSOAPType)) { // This should not be needed if schema has these declarations rc = collection->GetType(name, internal, getter_AddRefs(subType)); } else { rc = collection->GetType(name, gSOAPStrings->kXSURI, getter_AddRefs(subType)); } } // if (NS_FAILED(rc)) return rc; } if (!subType) subType = type; nsCOMPtr subsubType; nsAutoString explicitType; if (nsSOAPUtils::GetAttribute(aEncoding, aSource, gSOAPStrings->kXSIURI, gSOAPStrings->kXSITypeAttribute, explicitType)) { rc = nsSOAPUtils::GetNamespaceURI(aEncoding, aSource, explicitType, ns); NS_ENSURE_SUCCESS(rc, rc); rc = nsSOAPUtils::GetLocalName(explicitType, name); NS_ENSURE_SUCCESS(rc, rc); rc = collection->GetType(name, ns, getter_AddRefs(subsubType)); // if (NS_FAILED(rc)) return rc; } if (!subsubType) subsubType = subType; if (subsubType) { // Loop up the hierarchy, to check and look for decoders for(;;) { nsCOMPtr lookupType = subsubType; do { if (lookupType == subType) { // Tick off the located super classes subType = nsnull; } if (lookupType == type) { // Tick off the located super classes type = nsnull; } if (!decoder) { nsAutoString schemaType; nsAutoString schemaURI; nsresult rc = lookupType->GetName(schemaType); NS_ENSURE_SUCCESS(rc, rc); rc = lookupType->GetTargetNamespace(schemaURI); NS_ENSURE_SUCCESS(rc, rc); nsAutoString encodingKey; SOAPEncodingKey(schemaURI, schemaType, encodingKey); rc = aEncoding->GetDecoder(encodingKey, getter_AddRefs(decoder)); NS_ENSURE_SUCCESS(rc, rc); } nsCOMPtr supertype; rc = GetSupertype(aEncoding, lookupType, getter_AddRefs(supertype)); NS_ENSURE_SUCCESS(rc, rc); lookupType = supertype; } while (lookupType); if (!type) { type = subsubType; break; } decoder = nsnull; if (!subType) { subType = type; } subsubType = subType; } } } if (!decoder) { PRBool simple = PR_TRUE; if (type) { nsresult rc = HasSimpleValue(type, &simple); NS_ENSURE_SUCCESS(rc, rc); } if (simple) { nsCOMPtr child; nsSOAPUtils::GetFirstChildElement(aSource, getter_AddRefs(child)); simple = !child; } nsAutoString decodingKey; if (!simple) { SOAPEncodingKey(gSOAPStrings->kSOAPEncURI, gSOAPStrings->kStructSOAPType, decodingKey); } else { SOAPEncodingKey(gSOAPStrings->kXSURI, gSOAPStrings->kAnySimpleTypeSchemaType, decodingKey); } nsresult rc = aEncoding->GetDecoder(decodingKey, getter_AddRefs(decoder)); NS_ENSURE_SUCCESS(rc, rc); } if (decoder) { return decoder->Decode(aEncoding, aSource, type, aAttachments, aResult); } return SOAP_EXCEPTION(NS_ERROR_NOT_IMPLEMENTED, "SOAP_NO_DECODER_FOR_TYPE", "The default decoder finds no decoder for specific type"); } NS_IMETHODIMP nsAnyTypeEncoder::Decode(nsISOAPEncoding * aEncoding, nsIDOMElement * aSource, nsISchemaType * aSchemaType, nsISOAPAttachments * aAttachments, nsIVariant ** _retval) { NS_ENSURE_ARG_POINTER(aEncoding); NS_ENSURE_ARG_POINTER(aSource); NS_ENSURE_ARG_POINTER(_retval); *_retval = nsnull; PRBool simple = PR_TRUE; if (aSchemaType) { nsresult rc = HasSimpleValue(aSchemaType, &simple); NS_ENSURE_SUCCESS(rc, rc); } if (simple) { nsCOMPtr child; nsSOAPUtils::GetFirstChildElement(aSource, getter_AddRefs(child)); simple = !child; } nsAutoString decodingKey; if (!simple) { SOAPEncodingKey(gSOAPStrings->kSOAPEncURI, gSOAPStrings->kStructSOAPType, decodingKey); } else { SOAPEncodingKey(gSOAPStrings->kXSURI, gSOAPStrings->kAnySimpleTypeSchemaType, decodingKey); } nsCOMPtr decoder; nsresult rc = aEncoding->GetDecoder(decodingKey, getter_AddRefs(decoder)); NS_ENSURE_SUCCESS(rc, rc); if (decoder) { return decoder->Decode(aEncoding, aSource, aSchemaType, aAttachments, _retval); return rc; } return SOAP_EXCEPTION(NS_ERROR_NOT_IMPLEMENTED,"SOAP_NO_DECODER_FOR_TYPE","The any type decoder finds no decoder for specific element"); } /** * Decode struct particle. If particle is model group this method * call itself recursively for each particle contained in the model group. * * @param aEncoding SOAP encoding to be used (in). * @param aElement DOM element representing particle to be decoded (in). * @param aParticle Schema particle that should declare struct particle (in). * @param aAttachments SOAP attachments (in). * @param aDestination Property bag where to stored decoded particle (in). * @param aResult Remaining DOM element to be decoded, left over one (out). */ static nsresult DecodeStructParticle(nsISOAPEncoding* aEncoding, nsIDOMElement* aElement, nsISchemaParticle* aParticle, nsISOAPAttachments * aAttachments, nsISOAPPropertyBagMutator* aDestination, nsIDOMElement** aResult) { nsresult rc; *aResult = nsnull; if (aParticle) { PRUint32 minOccurs; rc = aParticle->GetMinOccurs(&minOccurs); NS_ENSURE_SUCCESS(rc, rc); PRUint32 maxOccurs; rc = aParticle->GetMaxOccurs(&maxOccurs); NS_ENSURE_SUCCESS(rc, rc); PRUint16 particleType; rc = aParticle->GetParticleType(&particleType); NS_ENSURE_SUCCESS(rc, rc); switch(particleType) { case nsISchemaParticle::PARTICLE_TYPE_ELEMENT: { if (maxOccurs > 1) { // Todo: Try to make this thing work as an array? return NS_ERROR_NOT_AVAILABLE; // For now, we just try something else if we can (recoverable) } nsCOMPtr element = do_QueryInterface(aParticle); nsAutoString name; rc = element->GetTargetNamespace(name); NS_ENSURE_SUCCESS(rc, rc); if (!name.IsEmpty()) { rc = NS_ERROR_NOT_AVAILABLE; // No known way to use namespace qualification in struct } else { rc = element->GetName(name); NS_ENSURE_SUCCESS(rc, rc); nsAutoString ename; if (aElement) { // Permits aElement to be null and fail recoverably nsAutoString temp; rc = aElement->GetNamespaceURI(ename); NS_ENSURE_SUCCESS(rc, rc); if (ename.IsEmpty()) { // Only get an ename if there is an empty namespaceURI rc = aElement->GetLocalName(ename); NS_ENSURE_SUCCESS(rc, rc); } } if (!ename.Equals(name)) rc = NS_ERROR_NOT_AVAILABLE; // The element must be a declaration of the next element } if (NS_SUCCEEDED(rc)) { nsCOMPtr type; rc = element->GetType(getter_AddRefs(type)); NS_ENSURE_SUCCESS(rc, rc); nsCOMPtr value; rc = aEncoding->Decode(aElement, type, aAttachments, getter_AddRefs(value)); NS_ENSURE_SUCCESS(rc, rc); if (!value) { nsCOMPtr nullVariant(do_CreateInstance("@mozilla.org/variant;1")); if (nullVariant) { nullVariant->SetAsISupports(nsnull); value = do_QueryInterface(nullVariant); } } rc = aDestination->AddProperty(name, value); NS_ENSURE_SUCCESS(rc, rc); nsSOAPUtils::GetNextSiblingElement(aElement, aResult); } if (minOccurs == 0 && rc == NS_ERROR_NOT_AVAILABLE) { // If we failed recoverably, but we were permitted to, then return success NS_IF_ADDREF(*aResult = aElement); rc = NS_OK; } return rc; } case nsISchemaParticle::PARTICLE_TYPE_MODEL_GROUP: { if (maxOccurs > 1) { // Todo: Try to make this thing work as an array? return NS_ERROR_NOT_AVAILABLE; // For now, we just try something else if we can (recoverable) } nsCOMPtr modelGroup = do_QueryInterface(aParticle); PRUint16 compositor; rc = modelGroup->GetCompositor(&compositor); NS_ENSURE_SUCCESS(rc, rc); PRUint32 particleCount; rc = modelGroup->GetParticleCount(&particleCount); NS_ENSURE_SUCCESS(rc, rc); PRUint32 i; if (compositor == nsISchemaModelGroup::COMPOSITOR_ALL) { // This handles out-of-order appearances. // Use hashtable to be able to get corresponding particle // according SOAP element name not according schema order // as a model group is used nsInterfaceHashtable groupParticles; groupParticles.Init(particleCount); nsCOMPtr child; PRBool mangled = PR_FALSE; // Build schema particle mappings from model group for (i = 0; i < particleCount; i++) { rc = modelGroup->GetParticle(i, getter_AddRefs(child)); NS_ENSURE_SUCCESS(rc, rc); nsAutoString particleName; rc = child->GetName(particleName); NS_ENSURE_SUCCESS(rc, rc); rc = groupParticles.Put(particleName, child); NS_ENSURE_SUCCESS(rc, rc); } nsCOMPtr next = aElement; PRBool decoded; /* Since we are an xsd:all, the order of elements in the schema type does not matter. So we go element by element in the XML fragment we are decoding. We loop through all schema particles defined for this type until we find one that DecodeStructParticle succeeds on. DecodeStructParticle returns |after| with is what is left to decode, so we can figure if the decoding succeeded by checking if |after| is not equal to the element we are decoding (|next|). We track if we couldn't decode using the |decoded| boolean. If we exit the particle walking for loop and |decoded| is false, we bail. XXX: what if we get out of the while loop, and |all| still has particles? Should we walk them and see if any are minOccurs > 0 and return an error? */ // loop as long as we have something to decode. while (next) { decoded = PR_FALSE; // we cycle through the schema particles for (i = 0; i < particleCount; i++) { nsAutoString name; rc = next->GetTagName(name); NS_ENSURE_SUCCESS(rc, rc); // Get schema particle according SOAP element groupParticles.Get(name, getter_AddRefs(child)); if (NS_FAILED(rc) || !child) { #ifdef DEBUG nsAutoString msg(NS_LITERAL_STRING("::DecodeStructParticle: ")); msg.AppendLiteral("Cannot find schema particle for \""); msg.Append(name); msg.AppendLiteral("\""); NS_ERROR(NS_ConvertUTF16toUTF8(msg).get()); #endif } nsCOMPtr after; rc = DecodeStructParticle(aEncoding, next, child, aAttachments, aDestination, getter_AddRefs(after)); // DecodeStructParticle returns success even if decoding didn't // work. So we check if after != next to see if it did succeed. if (NS_SUCCEEDED(rc) && after != next) { decoded = PR_TRUE; next = after; mangled = PR_TRUE; groupParticles.Remove(name); particleCount--; break; } } // This detects ambiguous model (non-deterministic choice which // fails after succeeding on first) if ((mangled && rc == NS_ERROR_NOT_AVAILABLE) || !decoded) { rc = SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,"SOAP_AMBIGUOUS_DECODING","Cannot proceed due to ambiguity or error in content model"); // Error is not considered recoverable due to partially-created output. } // if we failed to decode after the for loop, abort. if (NS_FAILED(rc) || !decoded) break; } // if *aResult is not null, then caller knows we couldn't decode // everything. if (NS_SUCCEEDED(rc)) { NS_IF_ADDREF(*aResult = next); } else if (minOccurs == 0 && rc == NS_ERROR_NOT_AVAILABLE) { // If we succeeded or failed recoverably, but we were permitted to, // then return success NS_IF_ADDREF(*aResult = aElement); rc = NS_OK; } } else { // This handles sequences and choices. nsCOMPtr next = aElement; for (i = 0; i < particleCount; i++) { nsCOMPtr child; rc = modelGroup->GetParticle(i, getter_AddRefs(child)); NS_ENSURE_SUCCESS(rc, rc); nsCOMPtr after; rc = DecodeStructParticle(aEncoding, next, child, aAttachments, aDestination, getter_AddRefs(after)); if (NS_SUCCEEDED(rc)) { next = after; } if (compositor == nsISchemaModelGroup::COMPOSITOR_CHOICE) { if (rc == NS_ERROR_NOT_AVAILABLE) { rc = NS_OK; } else { if (NS_SUCCEEDED(rc)) { NS_IF_ADDREF(*aResult = next); } return rc; } } else if (i > 0 && rc == NS_ERROR_NOT_AVAILABLE) { // This detects ambiguous model (non-deterministic choice which fails after succeeding on first) rc = SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,"SOAP_AMBIGUOUS_DECODING","Cannot proceed due to ambiguity or error in content model"); // Error is not considered recoverable due to partially-created output. } if (NS_FAILED(rc)) break; } if (compositor == nsISchemaModelGroup::COMPOSITOR_CHOICE) rc = NS_ERROR_NOT_AVAILABLE; if (NS_SUCCEEDED(rc)) { NS_IF_ADDREF(*aResult = next); } if (minOccurs == 0 && rc == NS_ERROR_NOT_AVAILABLE) { // If we succeeded or failed recoverably, but we were permitted to, then return success NS_IF_ADDREF(*aResult = aElement); rc = NS_OK; } } return rc; // Return status } case nsISchemaParticle::PARTICLE_TYPE_ANY: // No model available here (we may wish to handle strict versus lazy, but what does that mean with only local accessor names) default: break; } } nsCOMPtr child = aElement; while (child) { nsAutoString name; nsAutoString namespaceURI; nsCOMPtrvalue; rc = child->GetLocalName(name); NS_ENSURE_SUCCESS(rc, rc); rc = child->GetNamespaceURI(namespaceURI); NS_ENSURE_SUCCESS(rc, rc); if (!namespaceURI.IsEmpty()) { // If we ever figure out what to do with namespaces, get an internal one return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE, "SOAP_GLOBAL_ACCESSOR", "Decoded struct contained global accessor, which does not map well into a property name."); } rc = aEncoding->Decode(child, nsnull, aAttachments, getter_AddRefs(value)); NS_ENSURE_SUCCESS(rc, rc); if (!value) { nsCOMPtr nullVariant(do_CreateInstance("@mozilla.org/variant;1")); if (nullVariant) { nullVariant->SetAsISupports(nsnull); value = do_QueryInterface(nullVariant); } } rc = aDestination->AddProperty(name, value); NS_ENSURE_SUCCESS(rc, rc); nsCOMPtr nextchild; nsSOAPUtils::GetNextSiblingElement(child, getter_AddRefs(nextchild)); child = nextchild; } *aResult = nsnull; return NS_OK; } NS_IMETHODIMP nsStructEncoder::Decode(nsISOAPEncoding* aEncoding, nsIDOMElement* aSource, nsISchemaType* aSchemaType, nsISOAPAttachments* aAttachments, nsIVariant** aResult) { NS_ENSURE_ARG_POINTER(aEncoding); NS_ENSURE_ARG_POINTER(aSource); NS_ENSURE_ARG_POINTER(aResult); *aResult = nsnull; nsresult rc; nsCOMPtr mutator = do_CreateInstance(NS_SOAPPROPERTYBAGMUTATOR_CONTRACTID, &rc); NS_ENSURE_SUCCESS(rc, rc); nsCOMPtr modelGroup; if (aSchemaType) { nsCOMPtr ctype = do_QueryInterface(aSchemaType); if (ctype) { rc = ctype->GetModelGroup(getter_AddRefs(modelGroup)); NS_ENSURE_SUCCESS(rc, rc); } } nsCOMPtr child; nsSOAPUtils::GetFirstChildElement(aSource, getter_AddRefs(child)); nsCOMPtr result; rc = DecodeStructParticle(aEncoding, child, modelGroup, aAttachments, mutator, getter_AddRefs(result)); if (NS_SUCCEEDED(rc) // If there were elements left over, then we failed to decode everything. && result) rc = SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,"SOAP_LEFTOVERS","Decoded struct contained extra items not mentioned in the content model."); NS_ENSURE_SUCCESS(rc, rc); nsCOMPtr bag; rc = mutator->GetPropertyBag(getter_AddRefs(bag)); NS_ENSURE_SUCCESS(rc, rc); nsCOMPtr p = do_CreateInstance(NS_VARIANT_CONTRACTID, &rc); NS_ENSURE_SUCCESS(rc, rc); rc = p->SetAsInterface(NS_GET_IID(nsIPropertyBag), bag); NS_ENSURE_SUCCESS(rc, rc); NS_ADDREF(*aResult = p); return NS_OK; } NS_IMETHODIMP nsAnySimpleTypeEncoder::Decode(nsISOAPEncoding* aEncoding, nsIDOMElement* aSource, nsISchemaType* aSchemaType, nsISOAPAttachments* aAttachments, nsIVariant** aResult) { NS_ENSURE_ARG_POINTER(aEncoding); NS_ENSURE_ARG_POINTER(aSource); NS_ENSURE_ARG_POINTER(aResult); *aResult = nsnull; nsAutoString value; nsresult rc = nsSOAPUtils::GetElementTextContent(aSource, value); NS_ENSURE_SUCCESS(rc, rc); nsCOMPtr p = do_CreateInstance(NS_VARIANT_CONTRACTID, &rc); NS_ENSURE_SUCCESS(rc, rc); rc = p->SetAsAString(value); NS_ENSURE_SUCCESS(rc, rc); NS_ADDREF(*aResult = p); return NS_OK; } /** * Extract multiple bracketted numbers from the end of * the string and return the string with the number * removed or return the original string and -1. Either * the number of dimensions or the size of any particular * dimension can be returned as -1. An over-all 0 * means that either there were no dimensions or there * was a fundamental problem interpreting it. A * -1 on any particular size of a dimension means that * that particular size was not available or was not * interpretable. That may be a recoverable error * if the values represented a size, because we can * manually scan the array, but that shouldbe fatal * if specifying a position. In these cases, the * bracketted values are removed. */ static PRUint32 DecodeArrayDimensions(const nsAString& src, PRInt32* aDimensionSizes, nsAString & dst) { dst.Assign(src); nsReadingIterator < PRUnichar > i1; nsReadingIterator < PRUnichar > i2; src.BeginReading(i1); src.EndReading(i2); if (src.IsEmpty()) return 0; while (i1 != i2 // Loop past white space && *(--i2) <= ' ') // In XML, all valid characters <= space are the only whitespace ; if (*i2 != ']') { // In this case, not an array dimension PRInt32 len = Distance(i1, i2) - 1; // This is the size to truncate to at the end. dst = Substring(src, 0, len); // Truncate the string. return 0; // Eliminated white space. } PRInt32 dimensionCount = 1; // Counting the dimensions for (;;) { // First look for the matching bracket from reverse and commas. if (i1 == i2) { // No matching bracket. return 0; } PRUnichar c = *(--i2); if (c == '[') { // Matching bracket found! break; } if (c == ',') { dimensionCount++; } } PRInt32 len; { nsReadingIterator < PRUnichar > i3 = i2++; // Cover any extra white space while (i1 != i3) { // Loop past white space if (*(--i3) > ' ') { // In XML, all valid characters <= space are the only whitespace i3++; break; } } len = Distance(i1, i3); // Length remaining in string after operation } if (dimensionCount > MAX_ARRAY_DIMENSIONS) { // Completely ignore it if too many dimensions. return 0; } i1 = i2; src.EndReading(i2); while (*(--i2) != ']') // Find end bracket again ; dimensionCount = 0; // Start with first dimension. aDimensionSizes[dimensionCount] = -1; PRBool finished = PR_FALSE; // Disallow space within numbers while (i1 != i2) { PRUnichar c = *(i1++); if (c < '0' || c > '9') { // There may be slightly more to do here if alternative radixes are supported. if (c <= ' ') { // In XML, all valid characters <= space are the only whitespace if (aDimensionSizes[dimensionCount] >= 0) { finished = PR_TRUE; } } else if (c == ',') { // Introducing new dimension aDimensionSizes[++dimensionCount] = -1; // Restarting it at -1 finished = PR_FALSE; } else return 0; // Unrecognized character } else { if (finished) { return 0; // Numbers not allowed after white space } if (aDimensionSizes[dimensionCount] == -1) aDimensionSizes[dimensionCount] = 0; if (aDimensionSizes[dimensionCount] < 214748364) { aDimensionSizes[dimensionCount] = aDimensionSizes[dimensionCount] * 10 + c - '0'; } else { return 0; // Number got too big. } } } dst = Substring(src, 0, len); // Truncate the string. return dimensionCount + 1; // Return the number of dimensions } /** * Extract multiple bracketted numbers from the end of * the string and reconcile with a passed-in set of * dimensions, computing the offset in the array. * Presumes that the caller already knows the dimensions * fit into 32-bit signed integer, due to computing * total size of array. * * If there is extra garbage within the * Any blank or unreadable dimensions or extra garbage * within the string result in a return of -1, which is * bad wherever a position string was interpreted. */ static PRInt32 DecodeArrayPosition(const nsAString& src, PRUint32 aDimensionCount, PRInt32* aDimensionSizes) { PRInt32 pos[MAX_ARRAY_DIMENSIONS]; nsAutoString leftover; PRUint32 i = DecodeArrayDimensions(src, pos, leftover); if (i != aDimensionCount || !leftover.IsEmpty()) { // Easy cases where something went wrong return -1; } PRInt32 result = 0; for (i = 0;;) { PRInt32 next = pos[i]; if (next == -1 || next >= aDimensionSizes[i]) return -1; result = result + next; if (++i < aDimensionCount) // Multiply for next round. result = result * aDimensionSizes[i]; else break; } return result; } /** * Expand the resulting array out into a nice pseudo-multi-dimensional * array. We trust that the caller guaranteed aDimensionCount >= 1 and that * the other sizes are reasonable (or they couldn't pass us a resultant * array). * The result is produced recursively as: * an array [of arrays [...]] of the specified type. * Variants are used to embed arrays inside of * arrays. */ static nsresult CreateArray(nsIWritableVariant* aResult, PRUint16 aType, const nsIID* aIID, PRUint32 aDimensionCount, PRInt32* aDimensionSizes, PRUint32 aSizeof, PRUint8* aArray) { if (aSizeof == 0) { // Variants do not support construction of null-sized arrays return aResult->SetAsEmptyArray(); } if (aDimensionCount > 1) { // We cannot reuse variants because they are kept by resulting array PRInt32 count = aDimensionSizes[0]; PRUint32 size = aSizeof / count; PRInt32 i; nsIVariant** a = new nsIVariant*[count]; // Create variant array. if (!a) return NS_ERROR_OUT_OF_MEMORY; nsresult rc = NS_OK; for (i = 0; i < count; i++) { nsCOMPtr v = do_CreateInstance(NS_VARIANT_CONTRACTID, &rc); if (NS_FAILED(rc)) break; nsresult rc = CreateArray(v, aType, aIID, aDimensionCount - 1, aDimensionSizes + 1, size, aArray); if (NS_FAILED(rc)) break; NS_ADDREF(a[i] = v); // Addref for array reference aArray += size; } if (NS_SUCCEEDED(rc)) { rc = aResult->SetAsArray(nsIDataType::VTYPE_INTERFACE_IS,&NS_GET_IID(nsIVariant),count,a); } for (i = 0; i < count; i++) { // Release variants for array nsIVariant* v = a[i]; if (v) NS_RELEASE(v); } delete[] a; return rc; } else { return aResult->SetAsArray(aType,aIID,aDimensionSizes[0],aArray); } } // Incomplete -- becomes very complex due to variant arrays NS_IMETHODIMP nsArrayEncoder::Decode(nsISOAPEncoding* aEncoding, nsIDOMElement* aSource, nsISchemaType* aSchemaType, nsISOAPAttachments* aAttachments, nsIVariant** aResult) { NS_ENSURE_ARG_POINTER(aEncoding); NS_ENSURE_ARG_POINTER(aSource); NS_ENSURE_ARG_POINTER(aResult); *aResult = nsnull; nsAutoString ns; nsAutoString name; nsCOMPtr schemaArrayType; nsAutoString value; PRUint32 dimensionCount = 0; // Number of dimensions PRInt32 dimensionSizes[MAX_ARRAY_DIMENSIONS]; PRInt32 size = -1; nsresult rc; PRUint32 i; if (aSchemaType) { PRUint16 type; nsresult rc = aSchemaType->GetSchemaType(&type); NS_ENSURE_SUCCESS(rc, rc); if (type == nsISchemaType::SCHEMA_TYPE_COMPLEX) { nsCOMPtr ct = do_QueryInterface(aSchemaType); nsresult rc = ct->GetArrayDimension(&dimensionCount); NS_ENSURE_SUCCESS(rc, rc); rc = ct->GetArrayType(getter_AddRefs(schemaArrayType)); NS_ENSURE_SUCCESS(rc, rc); } } if (nsSOAPUtils::GetAttribute(aEncoding, aSource, gSOAPStrings->kSOAPEncURI, gSOAPStrings->kSOAPArrayTypeAttribute, value)) { nsAutoString dst; PRUint32 n = DecodeArrayDimensions(value, dimensionSizes, dst); if (n > 0) { if (dimensionCount == n || dimensionCount == 0) { dimensionCount = n; } else { return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE, "SOAP_WRONG_ARRAY_SIZE", "Array declares different number of dimensions from what schema declared."); // We cannot get conflicting information from schema and content. } } value.Assign(dst); if (dimensionCount > 0) { PRInt64 tot = 1; // Collect in 64 bits, just to make sure it fits for (i = 0; i < dimensionCount; i++) { PRInt32 next = dimensionSizes[i]; if (next == -1) { tot = -1; break; } tot = tot * next; if (tot > 0x7fffffff) { return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE, "SOAP_ARRAY_TOO_BIG", "When decoding an object as an array, the total count of items exceeded maximum."); } } size = (PRInt32)tot; } else { return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE, "SOAP_ARRAY_UNDECLARED", "Array type did not end with proper array dimensions."); // A dimension count must be part of the arrayType } // The array type is either array if ']' or other specific type. nsCOMPtr collection; rc = aEncoding->GetSchemaCollection(getter_AddRefs(collection)); NS_ENSURE_SUCCESS(rc, rc); if (value.Last() ==']') { ns.Assign(gSOAPStrings->kSOAPEncURI); name.Assign(gSOAPStrings->kArraySOAPType); } else { rc = nsSOAPUtils::GetNamespaceURI(aEncoding, aSource, value, ns); NS_ENSURE_SUCCESS(rc, rc); rc = nsSOAPUtils::GetLocalName(value, name); NS_ENSURE_SUCCESS(rc, rc); } nsCOMPtr subtype; rc = collection->GetType(name, ns, getter_AddRefs(subtype)); // if (NS_FAILED(rc)) return rc; if (!subtype) subtype = schemaArrayType; if (subtype) { // Loop up the hierarchy, to ensure suitability of subtype if (schemaArrayType) { nsCOMPtr lookupType = subtype; do { if (lookupType == schemaArrayType) { // Tick off the located super classes schemaArrayType = nsnull; break; } nsCOMPtr supertype; rc = GetSupertype(aEncoding, lookupType, getter_AddRefs(supertype)); NS_ENSURE_SUCCESS(rc, rc); lookupType = supertype; } while (lookupType); } if (schemaArrayType) // If the proper subclass relationship didn't exist, then error return. return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE, "SOAP_ARRAY_TYPE", "The type of the array must be a subclass of the declared type."); schemaArrayType = subtype; // If they did, then we now have a new, better type. } } PRUint32 offset; // Computing offset trickier, because size may be unspecified. if (nsSOAPUtils::GetAttribute(aEncoding, aSource, gSOAPStrings->kSOAPEncURI, gSOAPStrings->kSOAPArrayOffsetAttribute, value)) { PRInt32 pos[MAX_ARRAY_DIMENSIONS]; nsAutoString leftover; offset = DecodeArrayDimensions(value, pos, leftover); if (dimensionCount == 0) dimensionCount = offset; if (offset == 0 || offset != dimensionCount || !leftover.IsEmpty()) { // We have to understand this or report an error // But the offset does not need to be understood return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE, "SOAP_ARRAY_OFFSET", "Illegal value given for array offset"); } PRInt32 old0 = dimensionSizes[0]; if (dimensionSizes[0] == -1) { // It is OK to have a offset where dimension 0 is unspecified dimensionSizes[0] = 2147483647; } offset = 0; for (i = 0;;) { PRInt64 next = pos[i]; if (next == -1 || next >= dimensionSizes[i]) { rc = NS_ERROR_ILLEGAL_VALUE; break; } next = (offset + next); if (next > 2147483647) { rc = NS_ERROR_ILLEGAL_VALUE; break; } offset = (PRInt32)next; if (++i < dimensionCount) { next = offset * dimensionSizes[i]; if (next > 2147483647) { rc = NS_ERROR_ILLEGAL_VALUE; break; } offset = (PRInt32)next; } else { rc = NS_OK; break; } } if (NS_FAILED(rc)) return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE, "SOAP_ARRAY_OFFSET", "Illegal value given for array offset"); dimensionSizes[0] = old0; } else { offset = 0; } if (size == -1) { // If no known size, we have to go through and pre-count. nsCOMPtr child; nsSOAPUtils::GetFirstChildElement(aSource, getter_AddRefs(child)); PRInt32 pp[MAX_ARRAY_DIMENSIONS]; if (dimensionCount != 0) { for (i = dimensionCount; i-- != 0;) { pp[i] = 0; } } size = 0; PRInt32 next = offset; while (child) { nsAutoString pos; if (nsSOAPUtils::GetAttribute(aEncoding, aSource, gSOAPStrings->kSOAPEncURI, gSOAPStrings->kSOAPArrayPositionAttribute, pos)) { // if array item contains an explicit 'position' attribute use it nsAutoString leftover; PRInt32 inc[MAX_ARRAY_DIMENSIONS]; i = DecodeArrayDimensions(pos, inc, leftover); if (i == 0 || !leftover.IsEmpty() || (dimensionCount !=0 && dimensionCount != i)) { // We have to understand this or report an error return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE, "SOAP_ARRAY_POSITION", "Illegal value given for array element position"); } if (dimensionCount == 0) { dimensionCount = i; // If we never had dimension count before, we do now. for (i = dimensionCount; i-- != 0;) { pp[i] = 0; } } for (i = 0; i < dimensionCount; i++) { PRInt32 n = inc[i]; if (n == -1) { // Positions must be concrete return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE, "SOAP_ARRAY_POSITION", "Illegal value given for array element position"); } if (n >= pp[i]) pp[i] = n + 1; } } else { // No explicit 'position' attribute next++; // Keep tabs on how many unnumbered items there are } nsCOMPtr nextchild; nsSOAPUtils::GetNextSiblingElement(child, getter_AddRefs(nextchild)); child = nextchild; } if (dimensionCount == 0) { // If unknown or 1 dimension, unpositioned entries can help dimensionCount = 1; pp[0] = next; dimensionSizes[0] = next; } else if (dimensionCount == 1 && next > pp[0]) { pp[0] = next; dimensionSizes[0] = next; } PRInt64 tot = 1; // Collect in 64 bits, just to make sure it fits for (i = 0; i < dimensionCount; i++) { PRInt32 next = dimensionSizes[i]; if (next == -1) { // Only derive those with no other declaration dimensionSizes[i] = next = pp[i]; } tot = tot * next; if (tot > 0x7fffffff) { return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE, "SOAP_ARRAY_TOO_BIG", "When decoding an object as an array, the total count of items exceeded maximum."); } } size = (PRInt32)tot; // At last, we know the dimensions of the array. } // After considerable work, we may have a schema type and a size. nsCOMPtr result = do_CreateInstance(NS_VARIANT_CONTRACTID, &rc); PRInt32 si; #define DECODE_ARRAY(XPType, VTYPE, iid, Convert, Free) \ XPType* a = new XPType[size];\ if (!a)\ return NS_ERROR_OUT_OF_MEMORY;\ for (si = 0; si < size; si++) a[si] = 0;\ nsCOMPtr child;\ nsSOAPUtils::GetFirstChildElement(aSource, getter_AddRefs(child));\ PRUint32 next = offset;\ while (child) {\ nsAutoString pos;\ PRInt32 p;\ if (nsSOAPUtils::GetAttribute(aEncoding, aSource, gSOAPStrings->kSOAPEncURI,\ gSOAPStrings->kSOAPArrayPositionAttribute, pos)) {\ p = DecodeArrayPosition(pos, dimensionCount, dimensionSizes);\ if (p == -1) {\ rc = NS_ERROR_ILLEGAL_VALUE;\ break;\ }\ }\ else {\ p = next++;\ }\ if (p >= size || a[p]) {\ rc = NS_ERROR_ILLEGAL_VALUE;\ break;\ }\ nsCOMPtr v;\ \ rc = aEncoding->Decode(child, schemaArrayType, aAttachments, getter_AddRefs(v));\ if (NS_FAILED(rc))\ break;\ Convert \ \ nsCOMPtr next;\ nsSOAPUtils::GetNextSiblingElement(child, getter_AddRefs(next));\ child = next;\ }\ if (NS_SUCCEEDED(rc)) {\ rc = CreateArray(result, nsIDataType::VTYPE_##VTYPE,iid,dimensionCount,dimensionSizes,sizeof(a[0])*size,(PRUint8*)a);\ }\ Free\ delete[] a;\ #define DECODE_SIMPLE_ARRAY(XPType, VType, VTYPE) \ DECODE_ARRAY(XPType, VTYPE, nsnull, rc = v->GetAs##VType(a + p);if(NS_FAILED(rc))break;,do{}while(0);) if (rc == NS_ERROR_ILLEGAL_VALUE) return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE, "SOAP_ARRAY_POSITIONS", "Colliding array positions discovered."); NS_ENSURE_SUCCESS(rc, rc); PRBool unhandled = PR_FALSE; if (ns.Equals(gSOAPStrings->kXSURI)) { if (name.Equals(gSOAPStrings->kStringSchemaType)) { DECODE_ARRAY(PRUnichar*,WCHAR_STR,nsnull,rc = v->GetAsWString(a + p);if(NS_FAILED(rc))break;, for (si = 0; si < size; si++) nsMemory::Free(a[si]);); } else if (name.Equals(gSOAPStrings->kBooleanSchemaType)) { DECODE_SIMPLE_ARRAY(PRBool,Bool,BOOL); } else if (name.Equals(gSOAPStrings->kFloatSchemaType)) { DECODE_SIMPLE_ARRAY(float,Float,FLOAT); } else if (name.Equals(gSOAPStrings->kDoubleSchemaType)) { DECODE_SIMPLE_ARRAY(double,Double,DOUBLE); } else if (name.Equals(gSOAPStrings->kLongSchemaType)) { DECODE_SIMPLE_ARRAY(PRInt64,Int64,INT64); } else if (name.Equals(gSOAPStrings->kIntSchemaType)) { DECODE_SIMPLE_ARRAY(PRInt32,Int32,INT32); } else if (name.Equals(gSOAPStrings->kShortSchemaType)) { DECODE_SIMPLE_ARRAY(PRInt16,Int16,INT16); } else if (name.Equals(gSOAPStrings->kByteSchemaType)) { DECODE_SIMPLE_ARRAY(PRUint8,Int8,INT8); } else if (name.Equals(gSOAPStrings->kUnsignedLongSchemaType)) { DECODE_SIMPLE_ARRAY(PRUint64,Uint64,UINT64); } else if (name.Equals(gSOAPStrings->kUnsignedIntSchemaType)) { DECODE_SIMPLE_ARRAY(PRUint32,Uint32,UINT32); } else if (name.Equals(gSOAPStrings->kUnsignedShortSchemaType)) { DECODE_SIMPLE_ARRAY(PRUint16,Uint16,UINT16); } else if (name.Equals(gSOAPStrings->kUnsignedByteSchemaType)) { DECODE_SIMPLE_ARRAY(PRUint8,Uint8,UINT8); } else { unhandled = PR_TRUE; } } else { unhandled = PR_TRUE; } if (unhandled) { // Handle all the other cases DECODE_ARRAY(nsIVariant*,INTERFACE_IS,&NS_GET_IID(nsIVariant), NS_ADDREF(a[p] = v);, for (si = 0; si < size; si++) NS_IF_RELEASE(a[si]);); } NS_ENSURE_SUCCESS(rc, rc); NS_ADDREF(*aResult = result); return NS_OK; } NS_IMETHODIMP nsStringEncoder::Decode(nsISOAPEncoding* aEncoding, nsIDOMElement* aSource, nsISchemaType* aSchemaType, nsISOAPAttachments* aAttachments, nsIVariant** aResult) { NS_ENSURE_ARG_POINTER(aEncoding); NS_ENSURE_ARG_POINTER(aSource); NS_ENSURE_ARG_POINTER(aResult); *aResult = nsnull; nsAutoString value; nsresult rc = nsSOAPUtils::GetElementTextContent(aSource, value); NS_ENSURE_SUCCESS(rc, rc); nsCOMPtr p = do_CreateInstance(NS_VARIANT_CONTRACTID, &rc); NS_ENSURE_SUCCESS(rc, rc); rc = p->SetAsAString(value); NS_ENSURE_SUCCESS(rc, rc); NS_ADDREF(*aResult = p); return NS_OK; } NS_IMETHODIMP nsBooleanEncoder::Decode(nsISOAPEncoding* aEncoding, nsIDOMElement* aSource, nsISchemaType* aSchemaType, nsISOAPAttachments* aAttachments, nsIVariant** aResult) { NS_ENSURE_ARG_POINTER(aEncoding); NS_ENSURE_ARG_POINTER(aSource); NS_ENSURE_ARG_POINTER(aResult); *aResult = nsnull; nsAutoString value; nsresult rc = nsSOAPUtils::GetElementTextContent(aSource, value); NS_ENSURE_SUCCESS(rc, rc); PRBool b; if (value.Equals(gSOAPStrings->kTrue) || value.Equals(gSOAPStrings->kTrueA)) { b = PR_TRUE; } else if (value.Equals(gSOAPStrings->kFalse) || value.Equals(gSOAPStrings->kFalseA)) { b = PR_FALSE; } else { return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE, "SOAP_ILLEGAL_BOOLEAN", "Illegal value discovered for boolean"); } nsCOMPtr p = do_CreateInstance(NS_VARIANT_CONTRACTID,&rc); NS_ENSURE_SUCCESS(rc, rc); p->SetAsBool(b); NS_ADDREF(*aResult = p); return NS_OK; } NS_IMETHODIMP nsDoubleEncoder::Decode(nsISOAPEncoding* aEncoding, nsIDOMElement* aSource, nsISchemaType* aSchemaType, nsISOAPAttachments* aAttachments, nsIVariant** aResult) { NS_ENSURE_ARG_POINTER(aEncoding); NS_ENSURE_ARG_POINTER(aSource); NS_ENSURE_ARG_POINTER(aResult); *aResult = nsnull; nsAutoString value; nsresult rc = nsSOAPUtils::GetElementTextContent(aSource, value); NS_ENSURE_SUCCESS(rc, rc); double f; PRUint32 n; PRInt32 r = PR_sscanf(NS_ConvertUTF16toUTF8(value).get(), " %lf %n", &f, &n); if (r == 0 || n < value.Length()) { return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE, "SOAP_ILLEGAL_DOUBLE", "Illegal value discovered for double"); } nsCOMPtr p = do_CreateInstance(NS_VARIANT_CONTRACTID, &rc); NS_ENSURE_SUCCESS(rc, rc); p->SetAsDouble(f); NS_ADDREF(*aResult = p); return NS_OK; } NS_IMETHODIMP nsFloatEncoder::Decode(nsISOAPEncoding* aEncoding, nsIDOMElement* aSource, nsISchemaType* aSchemaType, nsISOAPAttachments* aAttachments, nsIVariant** aResult) { NS_ENSURE_ARG_POINTER(aEncoding); NS_ENSURE_ARG_POINTER(aSource); NS_ENSURE_ARG_POINTER(aResult); *aResult = nsnull; nsAutoString value; nsresult rc = nsSOAPUtils::GetElementTextContent(aSource, value); NS_ENSURE_SUCCESS(rc, rc); float f; PRUint32 n; PRInt32 r = PR_sscanf(NS_ConvertUTF16toUTF8(value).get(), " %f %n", &f, &n); if (r == 0 || n < value.Length()) { return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE, "SOAP_ILLEGAL_FLOAT", "Illegal value discovered for float"); } nsCOMPtr p = do_CreateInstance(NS_VARIANT_CONTRACTID,&rc); NS_ENSURE_SUCCESS(rc, rc); p->SetAsFloat(f); NS_ADDREF(*aResult = p); return NS_OK; } NS_IMETHODIMP nsLongEncoder::Decode(nsISOAPEncoding* aEncoding, nsIDOMElement* aSource, nsISchemaType* aSchemaType, nsISOAPAttachments* aAttachments, nsIVariant** aResult) { NS_ENSURE_ARG_POINTER(aEncoding); NS_ENSURE_ARG_POINTER(aSource); NS_ENSURE_ARG_POINTER(aResult); *aResult = nsnull; nsAutoString value; nsresult rc = nsSOAPUtils::GetElementTextContent(aSource, value); NS_ENSURE_SUCCESS(rc, rc); PRInt64 f; PRUint32 n; PRInt32 r = PR_sscanf(NS_ConvertUTF16toUTF8(value).get(), " %lld %n", &f, &n); if (r == 0 || n < value.Length()) { return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE, "SOAP_ILLEGAL_LONG", "Illegal value discovered for long"); } nsCOMPtr p = do_CreateInstance(NS_VARIANT_CONTRACTID,&rc); NS_ENSURE_SUCCESS(rc, rc); p->SetAsInt64(f); NS_ADDREF(*aResult = p); return NS_OK; } NS_IMETHODIMP nsIntEncoder::Decode(nsISOAPEncoding* aEncoding, nsIDOMElement* aSource, nsISchemaType* aSchemaType, nsISOAPAttachments* aAttachments, nsIVariant** aResult) { NS_ENSURE_ARG_POINTER(aEncoding); NS_ENSURE_ARG_POINTER(aSource); NS_ENSURE_ARG_POINTER(aResult); *aResult = nsnull; nsAutoString value; nsresult rc = nsSOAPUtils::GetElementTextContent(aSource, value); NS_ENSURE_SUCCESS(rc, rc); PRInt32 f; PRUint32 n; PRInt32 r = PR_sscanf(NS_ConvertUTF16toUTF8(value).get(), " %ld %n", &f, &n); if (r == 0 || n < value.Length()) { return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE, "SOAP_ILLEGAL_INT", "Illegal value discovered for int"); } nsCOMPtr p = do_CreateInstance(NS_VARIANT_CONTRACTID,&rc); NS_ENSURE_SUCCESS(rc, rc); p->SetAsInt32(f); NS_ADDREF(*aResult = p); return NS_OK; } NS_IMETHODIMP nsShortEncoder::Decode(nsISOAPEncoding* aEncoding, nsIDOMElement* aSource, nsISchemaType* aSchemaType, nsISOAPAttachments* aAttachments, nsIVariant** aResult) { NS_ENSURE_ARG_POINTER(aEncoding); NS_ENSURE_ARG_POINTER(aSource); NS_ENSURE_ARG_POINTER(aResult); *aResult = nsnull; nsAutoString value; nsresult rc = nsSOAPUtils::GetElementTextContent(aSource, value); NS_ENSURE_SUCCESS(rc, rc); PRInt16 f; PRUint32 n; PRInt32 r = PR_sscanf(NS_ConvertUTF16toUTF8(value).get(), " %hd %n", &f, &n); if (r == 0 || n < value.Length()) { return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE, "SOAP_ILLEGAL_SHORT", "Illegal value discovered for short"); } nsCOMPtr p = do_CreateInstance(NS_VARIANT_CONTRACTID,&rc); NS_ENSURE_SUCCESS(rc, rc); p->SetAsInt16(f); NS_ADDREF(*aResult = p); return NS_OK; } NS_IMETHODIMP nsByteEncoder::Decode(nsISOAPEncoding* aEncoding, nsIDOMElement* aSource, nsISchemaType* aSchemaType, nsISOAPAttachments* aAttachments, nsIVariant** aResult) { NS_ENSURE_ARG_POINTER(aEncoding); NS_ENSURE_ARG_POINTER(aSource); NS_ENSURE_ARG_POINTER(aResult); *aResult = nsnull; nsAutoString value; nsresult rc = nsSOAPUtils::GetElementTextContent(aSource, value); NS_ENSURE_SUCCESS(rc, rc); PRInt16 f; PRUint32 n; PRInt32 r = PR_sscanf(NS_ConvertUTF16toUTF8(value).get(), " %hd %n", &f, &n); if (r == 0 || n < value.Length() || f < -128 || f > 127) { return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE, "SOAP_ILLEGAL_BYTE", "Illegal value discovered for byte"); } nsCOMPtr p = do_CreateInstance(NS_VARIANT_CONTRACTID,&rc); NS_ENSURE_SUCCESS(rc, rc); p->SetAsInt8((PRUint8) f); NS_ADDREF(*aResult = p); return NS_OK; } NS_IMETHODIMP nsUnsignedLongEncoder::Decode(nsISOAPEncoding* aEncoding, nsIDOMElement* aSource, nsISchemaType* aSchemaType, nsISOAPAttachments* aAttachments, nsIVariant** aResult) { NS_ENSURE_ARG_POINTER(aEncoding); NS_ENSURE_ARG_POINTER(aSource); NS_ENSURE_ARG_POINTER(aResult); *aResult = nsnull; nsAutoString value; nsresult rc = nsSOAPUtils::GetElementTextContent(aSource, value); NS_ENSURE_SUCCESS(rc, rc); PRUint64 f; PRUint32 n; PRInt32 r = PR_sscanf(NS_ConvertUTF16toUTF8(value).get(), " %llu %n", &f, &n); if (r == 0 || n < value.Length()) { return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE, "SOAP_ILLEGAL_ULONG", "Illegal value discovered for unsigned long"); } nsCOMPtr p = do_CreateInstance(NS_VARIANT_CONTRACTID,&rc); NS_ENSURE_SUCCESS(rc, rc); p->SetAsUint64(f); NS_ADDREF(*aResult = p); return NS_OK; } NS_IMETHODIMP nsUnsignedIntEncoder::Decode(nsISOAPEncoding* aEncoding, nsIDOMElement* aSource, nsISchemaType* aSchemaType, nsISOAPAttachments* aAttachments, nsIVariant** aResult) { NS_ENSURE_ARG_POINTER(aEncoding); NS_ENSURE_ARG_POINTER(aSource); NS_ENSURE_ARG_POINTER(aResult); *aResult = nsnull; nsAutoString value; nsresult rc = nsSOAPUtils::GetElementTextContent(aSource, value); NS_ENSURE_SUCCESS(rc, rc); PRUint32 f; PRUint32 n; PRInt32 r = PR_sscanf(NS_ConvertUTF16toUTF8(value).get(), " %lu %n", &f, &n); if (r == 0 || n < value.Length()) { return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE, "SOAP_ILLEGAL_UINT", "Illegal value discovered for unsigned int"); } nsCOMPtr p = do_CreateInstance(NS_VARIANT_CONTRACTID,&rc); NS_ENSURE_SUCCESS(rc, rc); p->SetAsUint32(f); NS_ADDREF(*aResult = p); return NS_OK; } NS_IMETHODIMP nsBase64BinaryEncoder::Decode(nsISOAPEncoding* aEncoding, nsIDOMElement* aSource, nsISchemaType* aSchemaType, nsISOAPAttachments* aAttachments, nsIVariant** aResult) { NS_ENSURE_ARG_POINTER(aEncoding); NS_ENSURE_ARG_POINTER(aSource); NS_ENSURE_ARG_POINTER(aResult); *aResult = nsnull; nsString value; nsresult rv = nsSOAPUtils::GetElementTextContent(aSource, value); NS_ENSURE_SUCCESS(rv, rv); NS_LossyConvertUTF16toASCII valueStr(value); valueStr.StripChars(" \n\r\t"); char* decodedVal = PL_Base64Decode(valueStr.get(), valueStr.Length(), nsnull); if (!decodedVal) { return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE, "SOAP_ILLEGAL_BASE64", "Data cannot be decoded as Base64"); } nsCOMPtr p = do_CreateInstance(NS_VARIANT_CONTRACTID, &rv); if (NS_SUCCEEDED(rv)) { rv = p->SetAsArray(nsIDataType::VTYPE_UINT8, nsnull, strlen(decodedVal), decodedVal); } PR_Free(decodedVal); NS_ENSURE_SUCCESS(rv, rv); NS_ADDREF(*aResult = p); return NS_OK; } NS_IMETHODIMP nsUnsignedShortEncoder::Decode(nsISOAPEncoding* aEncoding, nsIDOMElement* aSource, nsISchemaType* aSchemaType, nsISOAPAttachments* aAttachments, nsIVariant** aResult) { NS_ENSURE_ARG_POINTER(aEncoding); NS_ENSURE_ARG_POINTER(aSource); NS_ENSURE_ARG_POINTER(aResult); *aResult = nsnull; nsAutoString value; nsresult rc = nsSOAPUtils::GetElementTextContent(aSource, value); NS_ENSURE_SUCCESS(rc, rc); PRUint16 f; PRUint32 n; PRInt32 r = PR_sscanf(NS_ConvertUTF16toUTF8(value).get(), " %hu %n", &f, &n); if (r == 0 || n < value.Length()) { return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE, "SOAP_ILLEGAL_USHORT", "Illegal value discovered for unsigned short"); } nsCOMPtr p = do_CreateInstance(NS_VARIANT_CONTRACTID,&rc); NS_ENSURE_SUCCESS(rc, rc); p->SetAsUint16(f); NS_ADDREF(*aResult = p); return NS_OK; } NS_IMETHODIMP nsUnsignedByteEncoder::Decode(nsISOAPEncoding* aEncoding, nsIDOMElement* aSource, nsISchemaType* aSchemaType, nsISOAPAttachments* aAttachments, nsIVariant** aResult) { NS_ENSURE_ARG_POINTER(aEncoding); NS_ENSURE_ARG_POINTER(aSource); NS_ENSURE_ARG_POINTER(aResult); *aResult = nsnull; nsAutoString value; nsresult rc = nsSOAPUtils::GetElementTextContent(aSource, value); NS_ENSURE_SUCCESS(rc, rc); PRUint16 f; PRUint32 n; PRInt32 r = PR_sscanf(NS_ConvertUTF16toUTF8(value).get(), " %hu %n", &f, &n); if (r == 0 || n < value.Length() || f > 255) { return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE, "SOAP_ILLEGAL_UBYTE", "Illegal value discovered for unsigned byte"); } nsCOMPtr p = do_CreateInstance(NS_VARIANT_CONTRACTID,&rc); NS_ENSURE_SUCCESS(rc, rc); p->SetAsUint8((PRUint8) f); NS_ADDREF(*aResult = p); return NS_OK; }