Back to index

lightning-sunbird  0.9+nobinonly
nsDefaultSOAPEncoder.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 2001
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #include "nsInterfaceHashtable.h"
00039 #include "nsHashKeys.h"
00040 #include "nsISchemaLoader.h"
00041 #include "nsDefaultSOAPEncoder.h"
00042 #include "nsSOAPUtils.h"
00043 #include "nsSOAPParameter.h"
00044 #include "nsISOAPAttachments.h"
00045 #include "nsXPIDLString.h"
00046 #include "nsIDOMDocument.h"
00047 #include "nsIDOMText.h"
00048 #include "nsCOMPtr.h"
00049 #include "nsISchema.h"
00050 #include "nsIComponentManager.h"
00051 #include "nsIServiceManager.h"
00052 #include "nsXPCOM.h"
00053 #include "nsISupportsPrimitives.h"
00054 #include "nsIDOMParser.h"
00055 #include "nsSOAPUtils.h"
00056 #include "nsISOAPEncoding.h"
00057 #include "nsISOAPEncoder.h"
00058 #include "nsISOAPDecoder.h"
00059 #include "nsISOAPMessage.h"
00060 #include "nsSOAPException.h"
00061 #include "prprf.h"
00062 #include "prdtoa.h"
00063 #include "plbase64.h"
00064 #include "prmem.h"
00065 #include "nsReadableUtils.h"
00066 #include "nsIDOMNamedNodeMap.h"
00067 #include "nsIDOMAttr.h"
00068 #include "nsPrintfCString.h"
00069 #include "nsISOAPPropertyBagMutator.h"
00070 #include "nsIProperty.h"
00071 #include "nsIPropertyBag.h"
00072 #include "nsSupportsArray.h"
00073 
00074 
00075 #define MAX_ARRAY_DIMENSIONS 100
00076 
00077 class nsSOAPEncoderStub : public nsISOAPEncoder,
00078                           public nsISOAPDecoder
00079 {
00080  public:
00081   NS_DECL_ISUPPORTS
00082  protected:
00083   PRUint16 mSOAPVersion;
00084 };
00085 
00086 NS_IMPL_ISUPPORTS2(nsSOAPEncoderStub, nsISOAPEncoder, nsISOAPDecoder)
00087 
00088 //
00089 // Macros to declare and implement the default encoder classes
00090 //
00091 
00092 #define DECLARE_ENCODER(name)                                           \
00093   class ns##name##Encoder : public nsSOAPEncoderStub                    \
00094   {                                                                     \
00095   public:                                                               \
00096     ns##name##Encoder();                                                \
00097     ns##name##Encoder(PRUint16 aSOAPVersion);                           \
00098     virtual ~ns##name##Encoder();                                       \
00099     NS_DECL_NSISOAPENCODER                                              \
00100     NS_DECL_NSISOAPDECODER                                              \
00101   };                                                                    \
00102   ns##name##Encoder::ns##name##Encoder(PRUint16 aSOAPVersion) {mSOAPVersion=aSOAPVersion;} \
00103   ns##name##Encoder::~ns##name##Encoder() {}
00104 
00105 // All encoders must be first declared and then registered.
00106   DECLARE_ENCODER(Default)
00107     DECLARE_ENCODER(AnyType)
00108     DECLARE_ENCODER(AnySimpleType)
00109     DECLARE_ENCODER(Array)
00110     DECLARE_ENCODER(Struct)
00111     DECLARE_ENCODER(String)
00112     DECLARE_ENCODER(Boolean)
00113     DECLARE_ENCODER(Double)
00114     DECLARE_ENCODER(Float)
00115     DECLARE_ENCODER(Long)
00116     DECLARE_ENCODER(Int)
00117     DECLARE_ENCODER(Short)
00118     DECLARE_ENCODER(Byte)
00119     DECLARE_ENCODER(UnsignedLong)
00120     DECLARE_ENCODER(UnsignedInt)
00121     DECLARE_ENCODER(UnsignedShort) 
00122     DECLARE_ENCODER(UnsignedByte)
00123     DECLARE_ENCODER(Base64Binary)
00124 
00130 #define REGISTER_ENCODER(name,type,uri)                                 \
00131     {                                                                   \
00132       ns##name##Encoder *handler = new ns##name##Encoder(version);      \
00133       SOAPEncodingKey(uri, gSOAPStrings->k##name##type##Type, encodingKey); \
00134       SetEncoder(encodingKey, handler);                                 \
00135       SetDecoder(encodingKey, handler);                                 \
00136     }
00137 
00138 #define REGISTER_SCHEMA_ENCODER(name) REGISTER_ENCODER(name,Schema,gSOAPStrings->kXSURI)
00139 #define REGISTER_SOAP_ENCODER(name) REGISTER_ENCODER(name,SOAP,gSOAPStrings->kSOAPEncURI)
00140 
00141 #define REGISTER_ENCODERS                                         \
00142     {                                                             \
00143       nsDefaultEncoder *handler = new nsDefaultEncoder(version);  \
00144       SetDefaultEncoder(handler);                                 \
00145       SetDefaultDecoder(handler);                                 \
00146     }                                                             \
00147   nsAutoString encodingKey;                                       \
00148     REGISTER_SCHEMA_ENCODER(AnyType)                              \
00149       REGISTER_SCHEMA_ENCODER(AnySimpleType)                      \
00150       REGISTER_SOAP_ENCODER(Array)                                \
00151       REGISTER_SOAP_ENCODER(Struct)                               \
00152       REGISTER_SCHEMA_ENCODER(String)                             \
00153       REGISTER_SCHEMA_ENCODER(Boolean)                            \
00154       REGISTER_SCHEMA_ENCODER(Double)                             \
00155       REGISTER_SCHEMA_ENCODER(Float)                              \
00156       REGISTER_SCHEMA_ENCODER(Long)                               \
00157       REGISTER_SCHEMA_ENCODER(Int)                                \
00158       REGISTER_SCHEMA_ENCODER(Short)                              \
00159       REGISTER_SCHEMA_ENCODER(Byte)                               \
00160       REGISTER_SCHEMA_ENCODER(UnsignedLong)                       \
00161       REGISTER_SCHEMA_ENCODER(UnsignedInt)                        \
00162       REGISTER_SCHEMA_ENCODER(UnsignedShort)                      \
00163       REGISTER_SCHEMA_ENCODER(UnsignedByte)                       \
00164       REGISTER_SCHEMA_ENCODER(Base64Binary)
00165 
00166   //
00167   // Default SOAP Encodings
00168   //
00169 
00170     NS_IMPL_ADDREF(nsDefaultSOAPEncoding_1_1)
00171       NS_IMPL_RELEASE(nsDefaultSOAPEncoding_1_1)
00172 
00173       nsDefaultSOAPEncoding_1_1::nsDefaultSOAPEncoding_1_1() 
00174         : nsSOAPEncoding(gSOAPStrings->kSOAPEncURI11, nsnull, nsnull)
00175 {
00176   PRUint16 version = nsISOAPMessage::VERSION_1_1;
00177   PRBool result;
00178   MapSchemaURI(gSOAPStrings->kXSURI1999,gSOAPStrings->kXSURI,PR_TRUE,&result);
00179   MapSchemaURI(gSOAPStrings->kXSIURI1999,gSOAPStrings->kXSIURI,PR_TRUE,&result);
00180   MapSchemaURI(gSOAPStrings->kSOAPEncURI11,gSOAPStrings->kSOAPEncURI,PR_TRUE,&result);
00181   REGISTER_ENCODERS
00182     }
00183 
00184 NS_IMPL_ADDREF(nsDefaultSOAPEncoding_1_2)
00185   NS_IMPL_RELEASE(nsDefaultSOAPEncoding_1_2)
00186 
00187   nsDefaultSOAPEncoding_1_2::nsDefaultSOAPEncoding_1_2() 
00188     : nsSOAPEncoding(gSOAPStrings->kSOAPEncURI, nsnull, nsnull)
00189 {
00190   PRUint16 version = nsISOAPMessage::VERSION_1_2;
00191   PRBool result;
00192   MapSchemaURI(gSOAPStrings->kXSURI1999,gSOAPStrings->kXSURI,PR_FALSE,&result);
00193   MapSchemaURI(gSOAPStrings->kXSIURI1999,gSOAPStrings->kXSIURI,PR_FALSE,&result);
00194   MapSchemaURI(gSOAPStrings->kSOAPEncURI11,gSOAPStrings->kSOAPEncURI,PR_FALSE,&result);
00195   REGISTER_ENCODERS
00196     }
00197 
00198 //
00199 // Default Encoders -- static helper functions intermixed
00200 //
00201 
00202 //  Getting the immediate supertype of any type
00203 static nsresult GetSupertype(nsISOAPEncoding* aEncoding, 
00204                              nsISchemaType* aType, 
00205                              nsISchemaType** aResult)
00206 {
00207   PRUint16 typevalue;
00208   nsresult rc = aType->GetSchemaType(&typevalue);
00209   NS_ENSURE_SUCCESS(rc, rc);
00210 
00211   nsCOMPtr<nsISchemaType> base;
00212   nsAutoString name;
00213   switch (typevalue) {
00214   case nsISchemaType::SCHEMA_TYPE_COMPLEX:
00215     {
00216       nsCOMPtr<nsISchemaComplexType> type =
00217         do_QueryInterface(aType);
00218       rc = type->GetBaseType(getter_AddRefs(base));
00219       NS_ENSURE_SUCCESS(rc, rc);
00220 
00221       break;
00222     }
00223   case nsISchemaType::SCHEMA_TYPE_SIMPLE:
00224     {
00225       nsCOMPtr<nsISchemaSimpleType> type =
00226         do_QueryInterface(aType);
00227       PRUint16 simpletypevalue;
00228       rc = type->GetSimpleType(&simpletypevalue);
00229       NS_ENSURE_SUCCESS(rc, rc);
00230 
00231       switch (simpletypevalue) {
00232         //  Ultimately, this is wrong because in XML types are value spaces
00233         //  We have not handled unions and lists.
00234         //  A union might be considered a supertype of anything it joins
00235         //  but it is the supertype of all types with value spaces it includes.
00236         //  SOAP is an attempt to treat XML types as though they were
00237         //  data types, which are governed by labels instead of value spaces.
00238         //  So two unrelated values may coexist, but we will disallow it
00239         //  because the caller probably wants type guarantees, not value
00240         //  guarantees.
00241       case nsISchemaSimpleType::SIMPLE_TYPE_RESTRICTION:
00242         {
00243           nsCOMPtr<nsISchemaRestrictionType> simpletype =
00244             do_QueryInterface(type);
00245           nsCOMPtr<nsISchemaSimpleType> simplebasetype;
00246           rc = simpletype->GetBaseType(getter_AddRefs(simplebasetype));
00247           NS_ENSURE_SUCCESS(rc, rc);
00248 
00249           base = simplebasetype;
00250           break;
00251         }
00252       case nsISchemaSimpleType::SIMPLE_TYPE_BUILTIN:
00253         {
00254           nsCOMPtr<nsISchemaBuiltinType> builtintype = 
00255             do_QueryInterface(type);
00256           PRUint16 builtintypevalue;
00257           rc = builtintype->GetBuiltinType(&builtintypevalue);
00258           NS_ENSURE_SUCCESS(rc, rc);
00259 
00260           switch(builtintypevalue) {
00261           case nsISchemaBuiltinType::BUILTIN_TYPE_ANYTYPE:  //  Root of all types
00262             *aResult = nsnull;
00263             return NS_OK;
00264           case nsISchemaBuiltinType::BUILTIN_TYPE_STRING:
00265             //              name = kAnySimpleTypeSchemaType;
00266             name = gSOAPStrings->kAnyTypeSchemaType;
00267             break;
00268           case nsISchemaBuiltinType::BUILTIN_TYPE_NORMALIZED_STRING:
00269             name = gSOAPStrings->kStringSchemaType;
00270             break;
00271           case nsISchemaBuiltinType::BUILTIN_TYPE_TOKEN:
00272             name = gSOAPStrings->kNormalizedStringSchemaType;
00273             break;
00274           case nsISchemaBuiltinType::BUILTIN_TYPE_BYTE:
00275             name = gSOAPStrings->kShortSchemaType;
00276             break;
00277           case nsISchemaBuiltinType::BUILTIN_TYPE_UNSIGNEDBYTE:
00278             name = gSOAPStrings->kUnsignedShortSchemaType;
00279             break;
00280           case nsISchemaBuiltinType::BUILTIN_TYPE_BASE64BINARY:
00281             //              name = kAnySimpleTypeSchemaType;
00282             name = gSOAPStrings->kAnyTypeSchemaType;
00283             break;
00284           case nsISchemaBuiltinType::BUILTIN_TYPE_HEXBINARY:
00285             //              name = kAnySimpleTypeSchemaType;
00286             name = gSOAPStrings->kAnyTypeSchemaType;
00287             break;
00288           case nsISchemaBuiltinType::BUILTIN_TYPE_INTEGER:
00289             name = gSOAPStrings->kDecimalSchemaType;
00290             break;
00291           case nsISchemaBuiltinType::BUILTIN_TYPE_POSITIVEINTEGER:
00292             name = gSOAPStrings->kNonNegativeIntegerSchemaType;
00293             break;
00294           case nsISchemaBuiltinType::BUILTIN_TYPE_NEGATIVEINTEGER:
00295             name = gSOAPStrings->kNonPositiveIntegerSchemaType;
00296             break;
00297           case nsISchemaBuiltinType::BUILTIN_TYPE_NONNEGATIVEINTEGER:
00298             name = gSOAPStrings->kIntegerSchemaType;
00299             break;
00300           case nsISchemaBuiltinType::BUILTIN_TYPE_NONPOSITIVEINTEGER:
00301             name = gSOAPStrings->kIntegerSchemaType;
00302             break;
00303           case nsISchemaBuiltinType::BUILTIN_TYPE_INT:
00304             name = gSOAPStrings->kLongSchemaType;
00305             break;
00306           case nsISchemaBuiltinType::BUILTIN_TYPE_UNSIGNEDINT:
00307             name = gSOAPStrings->kUnsignedLongSchemaType;
00308             break;
00309           case nsISchemaBuiltinType::BUILTIN_TYPE_LONG:
00310             name = gSOAPStrings->kIntegerSchemaType;
00311             break;
00312           case nsISchemaBuiltinType::BUILTIN_TYPE_UNSIGNEDLONG:
00313             name = gSOAPStrings->kNonNegativeIntegerSchemaType;
00314             break;
00315           case nsISchemaBuiltinType::BUILTIN_TYPE_SHORT:
00316             name = gSOAPStrings->kIntSchemaType;
00317             break;
00318           case nsISchemaBuiltinType::BUILTIN_TYPE_UNSIGNEDSHORT:
00319             name = gSOAPStrings->kUnsignedIntSchemaType;
00320             break;
00321           case nsISchemaBuiltinType::BUILTIN_TYPE_DECIMAL:
00322             //              name = kAnySimpleTypeSchemaType;
00323             name = gSOAPStrings->kAnyTypeSchemaType;
00324             break;
00325           case nsISchemaBuiltinType::BUILTIN_TYPE_FLOAT:
00326             //              name = kAnySimpleTypeSchemaType;
00327             name = gSOAPStrings->kAnyTypeSchemaType;
00328             break;
00329           case nsISchemaBuiltinType::BUILTIN_TYPE_DOUBLE:
00330             //              name = kAnySimpleTypeSchemaType;
00331             name = gSOAPStrings->kAnyTypeSchemaType;
00332             break;
00333           case nsISchemaBuiltinType::BUILTIN_TYPE_BOOLEAN:
00334             //              name = kAnySimpleTypeSchemaType;
00335             name = gSOAPStrings->kAnyTypeSchemaType;
00336             break;
00337           case nsISchemaBuiltinType::BUILTIN_TYPE_TIME:
00338             //              name = kAnySimpleTypeSchemaType;
00339             name = gSOAPStrings->kAnyTypeSchemaType;
00340             break;
00341           case nsISchemaBuiltinType::BUILTIN_TYPE_DATETIME:
00342             //              name = kAnySimpleTypeSchemaType;
00343             name = gSOAPStrings->kAnyTypeSchemaType;
00344             break;
00345           case nsISchemaBuiltinType::BUILTIN_TYPE_DURATION:
00346             //              name = kAnySimpleTypeSchemaType;
00347             name = gSOAPStrings->kAnyTypeSchemaType;
00348             break;
00349           case nsISchemaBuiltinType::BUILTIN_TYPE_DATE:
00350             //              name = kAnySimpleTypeSchemaType;
00351             name = gSOAPStrings->kAnyTypeSchemaType;
00352             break;
00353           case nsISchemaBuiltinType::BUILTIN_TYPE_GMONTH:
00354             //              name = kAnySimpleTypeSchemaType;
00355             name = gSOAPStrings->kAnyTypeSchemaType;
00356             break;
00357           case nsISchemaBuiltinType::BUILTIN_TYPE_GYEAR:
00358             //              name = kAnySimpleTypeSchemaType;
00359             name = gSOAPStrings->kAnyTypeSchemaType;
00360             break;
00361           case nsISchemaBuiltinType::BUILTIN_TYPE_GYEARMONTH:
00362             //              name = kAnySimpleTypeSchemaType;
00363             name = gSOAPStrings->kAnyTypeSchemaType;
00364             break;
00365           case nsISchemaBuiltinType::BUILTIN_TYPE_GDAY:
00366             //              name = kAnySimpleTypeSchemaType;
00367             name = gSOAPStrings->kAnyTypeSchemaType;
00368             break;
00369           case nsISchemaBuiltinType::BUILTIN_TYPE_GMONTHDAY:
00370             //              name = kAnySimpleTypeSchemaType;
00371             name = gSOAPStrings->kAnyTypeSchemaType;
00372             break;
00373           case nsISchemaBuiltinType::BUILTIN_TYPE_NAME:
00374             //              name = kAnySimpleTypeSchemaType;
00375             name = gSOAPStrings->kAnyTypeSchemaType;
00376             break;
00377           case nsISchemaBuiltinType::BUILTIN_TYPE_QNAME:
00378             //              name = kAnySimpleTypeSchemaType;
00379             name = gSOAPStrings->kAnyTypeSchemaType;
00380             break;
00381           case nsISchemaBuiltinType::BUILTIN_TYPE_NCNAME:
00382             name = gSOAPStrings->kNameSchemaType;
00383             break;
00384           case nsISchemaBuiltinType::BUILTIN_TYPE_ANYURI:
00385             //              name = kAnySimpleTypeSchemaType;
00386             name = gSOAPStrings->kAnyTypeSchemaType;
00387             break;
00388           case nsISchemaBuiltinType::BUILTIN_TYPE_LANGUAGE:
00389             name = gSOAPStrings->kTokenSchemaType;
00390             break;
00391           case nsISchemaBuiltinType::BUILTIN_TYPE_ID:
00392             name = gSOAPStrings->kNCNameSchemaType;
00393             break;
00394           case nsISchemaBuiltinType::BUILTIN_TYPE_IDREF:
00395             name = gSOAPStrings->kNCNameSchemaType;
00396             break;
00397           case nsISchemaBuiltinType::BUILTIN_TYPE_IDREFS:
00398             name = gSOAPStrings->kNormalizedStringSchemaType;  //  Really a list...
00399             break;
00400           case nsISchemaBuiltinType::BUILTIN_TYPE_ENTITY:
00401             name = gSOAPStrings->kNCNameSchemaType;
00402             break;
00403           case nsISchemaBuiltinType::BUILTIN_TYPE_ENTITIES:
00404             name = gSOAPStrings->kNormalizedStringSchemaType;  //  Really a list...
00405             break;
00406           case nsISchemaBuiltinType::BUILTIN_TYPE_NOTATION:
00407             //              name = kAnySimpleTypeSchemaType;
00408             name = gSOAPStrings->kAnyTypeSchemaType;
00409             break;
00410           case nsISchemaBuiltinType::BUILTIN_TYPE_NMTOKEN:
00411             name = gSOAPStrings->kTokenSchemaType;
00412             break;
00413           case nsISchemaBuiltinType::BUILTIN_TYPE_NMTOKENS:
00414             name = gSOAPStrings->kNormalizedStringSchemaType;  //  Really a list...
00415             break;
00416           }
00417         }
00418       }
00419       break;
00420     }
00421   }
00422   if (!base) {
00423     if (name.IsEmpty()) {
00424       switch (typevalue) {
00425       case nsISchemaType::SCHEMA_TYPE_COMPLEX:
00426         name = gSOAPStrings->kAnyTypeSchemaType;
00427         break;
00428       default:
00429         //          name = kAnySimpleTypeSchemaType;
00430         name = gSOAPStrings->kAnyTypeSchemaType;
00431       }
00432     }
00433     nsCOMPtr<nsISchemaCollection> collection;
00434     rc = aEncoding->GetSchemaCollection(getter_AddRefs(collection));
00435     NS_ENSURE_SUCCESS(rc, rc);
00436 
00437     rc = collection->GetType(name,
00438                              gSOAPStrings->kXSURI,
00439                              getter_AddRefs(base));
00440     //    if (NS_FAILED(rc)) return rc;
00441   }
00442 
00443   NS_IF_ADDREF(*aResult = base);
00444   return NS_OK;
00445 }
00446 
00447 static nsresult
00448 EncodeSimpleValue(nsISOAPEncoding* aEncoding,
00449                   const nsAString& aValue,
00450                   const nsAString& aNamespaceURI,
00451                   const nsAString& aName,
00452                   nsISchemaType* aSchemaType,
00453                   nsIDOMElement* aDestination, 
00454                   nsIDOMElement** aResult)
00455 {
00456   nsresult rc;
00457   PRBool needType = PR_TRUE;
00458   nsAutoString typeName;
00459   nsAutoString typeNS;
00460   if (aSchemaType) {
00461     rc = aSchemaType->GetName(typeName);
00462     NS_ENSURE_SUCCESS(rc, rc);
00463 
00464     rc = aSchemaType->GetTargetNamespace(typeNS);
00465     NS_ENSURE_SUCCESS(rc, rc);
00466   }
00467   nsAutoString name;      //  First choose the appropriate name and namespace for the element.
00468   nsAutoString ns;
00469   if (aName.IsEmpty()) {  //  We automatically choose appropriate element names where none exist.
00470     // The idea here seems to be to walk up the schema hierarchy to
00471     // find the base type and use the name of that as the element name.
00472     ns = gSOAPStrings->kSOAPEncURI;
00473     nsAutoString currentURI = ns;
00474     nsCOMPtr<nsISchemaType> currentType = aSchemaType;
00475     while (currentType
00476            && !(currentURI.Equals(gSOAPStrings->kXSURI) ||
00477                 currentURI.Equals(gSOAPStrings->kSOAPEncURI))) {
00478       nsCOMPtr<nsISchemaType> supertype;
00479       rc = GetSupertype(aEncoding, currentType, getter_AddRefs(supertype));
00480       NS_ENSURE_SUCCESS(rc, rc);
00481 
00482       if (!currentType) {
00483         break;
00484       }
00485       currentType = supertype;
00486       rc = currentType->GetTargetNamespace(currentURI);
00487       NS_ENSURE_SUCCESS(rc, rc);
00488     }
00489     if (currentType) {
00490       rc = aSchemaType->GetName(name);
00491       NS_ENSURE_SUCCESS(rc, rc);
00492     }
00493     else {
00494       name = gSOAPStrings->kAnyTypeSchemaType;
00495       needType = PR_FALSE;
00496     }
00497 
00498     if (!typeNS.IsEmpty()) {
00499       ns.Truncate();
00500       ns.SetIsVoid(true);
00501       
00502       rc = NS_OK;
00503     }
00504     else {
00505       rc = aEncoding->GetExternalSchemaURI(gSOAPStrings->kSOAPEncURI, ns);
00506     }
00507   }
00508   else {
00509     name = aName;
00510     rc = aEncoding->GetExternalSchemaURI(aNamespaceURI, ns);
00511   }
00512   NS_ENSURE_SUCCESS(rc, rc);
00513 
00514   nsCOMPtr<nsIDOMDocument> document;
00515   rc = aDestination->GetOwnerDocument(getter_AddRefs(document));
00516   NS_ENSURE_SUCCESS(rc, rc);
00517 
00518   nsCOMPtr<nsIDOMElement> element;
00519   rc = document->CreateElementNS(ns, name, getter_AddRefs(element));
00520   NS_ENSURE_SUCCESS(rc, rc);
00521 
00522   nsCOMPtr<nsIDOMNode> ignore;
00523   rc = aDestination->AppendChild(element, getter_AddRefs(ignore));
00524   NS_ENSURE_SUCCESS(rc, rc);
00525 
00526   if (needType) {
00527     if (typeNS.IsEmpty() && typeName.IsEmpty()) {
00528       typeName = gSOAPStrings->kAnyTypeSchemaType;
00529       rc = aEncoding->GetExternalSchemaURI(gSOAPStrings->kXSURI, typeNS);
00530       NS_ENSURE_SUCCESS(rc, rc);
00531     }
00532 
00533     nsAutoString type;
00534     rc = nsSOAPUtils::MakeNamespacePrefix(aEncoding, element,
00535                                           typeNS, type);
00536     NS_ENSURE_SUCCESS(rc, rc);
00537 
00538     type.Append(gSOAPStrings->kQualifiedSeparator);
00539     type.Append(typeName);
00540     rc = aEncoding->GetExternalSchemaURI(gSOAPStrings->kXSIURI, ns);
00541     NS_ENSURE_SUCCESS(rc, rc);
00542 
00543     rc = (element)->
00544       SetAttributeNS(ns, gSOAPStrings->kXSITypeAttribute, type);
00545     NS_ENSURE_SUCCESS(rc, rc);
00546   }
00547   if (!aValue.IsEmpty()) {
00548     nsCOMPtr<nsIDOMText> text;
00549     rc = document->CreateTextNode(aValue, getter_AddRefs(text));
00550     NS_ENSURE_SUCCESS(rc, rc);
00551 
00552     rc = (element)->AppendChild(text, getter_AddRefs(ignore));
00553     NS_ENSURE_SUCCESS(rc, rc);
00554   }
00555 
00556   NS_IF_ADDREF(*aResult = element);
00557   return rc;
00558 }
00559 
00560 //  Testing for a simple value
00561 static nsresult HasSimpleValue(nsISchemaType * aSchemaType, PRBool * aResult) {
00562   PRUint16 typevalue;
00563   nsresult rc = aSchemaType->GetSchemaType(&typevalue);
00564   NS_ENSURE_SUCCESS(rc, rc);
00565 
00566   if (typevalue == nsISchemaComplexType::SCHEMA_TYPE_COMPLEX) {
00567     nsCOMPtr<nsISchemaComplexType> ct = do_QueryInterface(aSchemaType);
00568     rc = ct->GetContentModel(&typevalue);
00569     NS_ENSURE_SUCCESS(rc, rc);
00570 
00571     *aResult = typevalue == nsISchemaComplexType::CONTENT_MODEL_SIMPLE;
00572   } else {
00573     *aResult = PR_TRUE;
00574   }
00575   return NS_OK;
00576 }
00577 
00578 //  Default
00579 
00580 NS_IMETHODIMP
00581 nsDefaultEncoder::Encode(nsISOAPEncoding* aEncoding,
00582                          nsIVariant* aSource,
00583                          const nsAString& aNamespaceURI,
00584                          const nsAString& aName,
00585                          nsISchemaType* aSchemaType,
00586                          nsISOAPAttachments* aAttachments,
00587                          nsIDOMElement* aDestination,
00588                          nsIDOMElement** aReturnValue)
00589 {
00590   NS_ENSURE_ARG_POINTER(aEncoding);
00591   NS_ENSURE_ARG_POINTER(aDestination);
00592   NS_ENSURE_ARG_POINTER(aReturnValue);
00593   *aReturnValue = nsnull;
00594   if (aSource == nsnull) {
00595     nsAutoString ns;
00596     nsresult rc = aEncoding->GetExternalSchemaURI(gSOAPStrings->kXSIURI, ns);
00597     NS_ENSURE_SUCCESS(rc, rc);
00598 
00599     nsAutoString name;
00600     if (!aName.IsEmpty())
00601       name.Assign(gSOAPStrings->kNull);
00602     rc = EncodeSimpleValue(aEncoding, gSOAPStrings->kEmpty, gSOAPStrings->kEmpty, 
00603                            name, nsnull, aDestination, aReturnValue);
00604     NS_ENSURE_SUCCESS(rc, rc);
00605 
00606     rc = (*aReturnValue)->SetAttributeNS(ns, gSOAPStrings->kNull, gSOAPStrings->kTrueA);
00607     NS_ENSURE_SUCCESS(rc, rc);
00608   }
00609   nsCOMPtr<nsISOAPEncoder> encoder;
00610   if (aSchemaType) {
00611     nsCOMPtr<nsISchemaType> lookupType = aSchemaType;
00612     do {
00613       nsAutoString schemaType;
00614       nsAutoString schemaURI;
00615       nsAutoString encodingKey;
00616       nsresult rc = lookupType->GetName(schemaType);
00617       NS_ENSURE_SUCCESS(rc, rc);
00618 
00619       rc = lookupType->GetTargetNamespace(schemaURI);
00620       NS_ENSURE_SUCCESS(rc, rc);
00621 
00622       SOAPEncodingKey(schemaURI, schemaType, encodingKey);
00623       rc = aEncoding->GetEncoder(encodingKey, getter_AddRefs(encoder));
00624       NS_ENSURE_SUCCESS(rc, rc);
00625 
00626       if (encoder)
00627         break;
00628       nsCOMPtr<nsISchemaType> supertype;
00629       rc = GetSupertype(aEncoding, lookupType, getter_AddRefs(supertype));
00630       NS_ENSURE_SUCCESS(rc, rc);
00631 
00632       lookupType = supertype;
00633     }
00634     while (lookupType);
00635   }
00636   if (!encoder) {
00637     nsAutoString encodingKey;
00638     SOAPEncodingKey(gSOAPStrings->kXSURI,
00639                     gSOAPStrings->kAnyTypeSchemaType, encodingKey);
00640     nsresult rc =
00641       aEncoding->GetEncoder(encodingKey, getter_AddRefs(encoder));
00642     NS_ENSURE_SUCCESS(rc, rc);
00643   }
00644   if (encoder) {
00645     return encoder->Encode(aEncoding, aSource, aNamespaceURI, aName,
00646                            aSchemaType, aAttachments, aDestination,
00647                            aReturnValue);
00648   }
00649   return SOAP_EXCEPTION(NS_ERROR_NOT_IMPLEMENTED,
00650                         "SOAP_NO_ENCODER_FOR_TYPE",
00651                         "The default encoder finds no encoder for specific type");
00652 }
00653 
00654 static void
00655 GetNativeType(PRUint16 aType, nsAString & aSchemaNamespaceURI, nsAString & aSchemaType)
00656 {
00657   aSchemaNamespaceURI.Assign(gSOAPStrings->kXSURI);
00658   switch (aType) {
00659   case nsIDataType::VTYPE_CHAR_STR:
00660   case nsIDataType::VTYPE_WCHAR_STR:
00661   case nsIDataType::VTYPE_CHAR:
00662   case nsIDataType::VTYPE_WCHAR:
00663   case nsIDataType::VTYPE_STRING_SIZE_IS:
00664   case nsIDataType::VTYPE_WSTRING_SIZE_IS:
00665   case nsIDataType::VTYPE_ASTRING:
00666   case nsIDataType::VTYPE_DOMSTRING:
00667   case nsIDataType::VTYPE_CSTRING:
00668   case nsIDataType::VTYPE_UTF8STRING:
00669     aSchemaType.Assign(gSOAPStrings->kStringSchemaType);
00670     break;
00671   case nsIDataType::VTYPE_INT8:
00672     aSchemaType.Assign(gSOAPStrings->kByteSchemaType);
00673     break;
00674   case nsIDataType::VTYPE_INT16:
00675     aSchemaType.Assign(gSOAPStrings->kShortSchemaType);
00676     break;
00677   case nsIDataType::VTYPE_INT32:
00678     aSchemaType.Assign(gSOAPStrings->kIntSchemaType);
00679     break;
00680   case nsIDataType::VTYPE_INT64:
00681     aSchemaType.Assign(gSOAPStrings->kLongSchemaType);
00682     break;
00683   case nsIDataType::VTYPE_UINT8:
00684     aSchemaType.Assign(gSOAPStrings->kUnsignedByteSchemaType);
00685     break;
00686   case nsIDataType::VTYPE_UINT16:
00687     aSchemaType.Assign(gSOAPStrings->kUnsignedShortSchemaType);
00688     break;
00689   case nsIDataType::VTYPE_UINT32:
00690     aSchemaType.Assign(gSOAPStrings->kUnsignedIntSchemaType);
00691     break;
00692   case nsIDataType::VTYPE_UINT64:
00693     aSchemaType.Assign(gSOAPStrings->kUnsignedLongSchemaType);
00694     break;
00695   case nsIDataType::VTYPE_FLOAT:
00696     aSchemaType.Assign(gSOAPStrings->kFloatSchemaType);
00697     break;
00698   case nsIDataType::VTYPE_DOUBLE:
00699     aSchemaType.Assign(gSOAPStrings->kDoubleSchemaType);
00700     break;
00701   case nsIDataType::VTYPE_BOOL:
00702     aSchemaType.Assign(gSOAPStrings->kBooleanSchemaType);
00703     break;
00704   case nsIDataType::VTYPE_ARRAY:
00705   case nsIDataType::VTYPE_EMPTY_ARRAY:
00706     aSchemaType.Assign(gSOAPStrings->kArraySOAPType);
00707     aSchemaNamespaceURI.Assign(gSOAPStrings->kSOAPEncURI);
00708     break;
00709     //  case nsIDataType::VTYPE_VOID:
00710     //  case nsIDataType::VTYPE_EMPTY:
00711     //  Empty may be either simple or complex.
00712     break;
00713   case nsIDataType::VTYPE_INTERFACE_IS:
00714   case nsIDataType::VTYPE_INTERFACE:
00715     aSchemaType.Assign(gSOAPStrings->kStructSOAPType);
00716     aSchemaNamespaceURI.Assign(gSOAPStrings->kSOAPEncURI);
00717     break;
00718   default:
00719     aSchemaType.Assign(gSOAPStrings->kAnySimpleTypeSchemaType);
00720   }
00721 }
00722 
00723 NS_IMETHODIMP
00724 nsAnyTypeEncoder::Encode(nsISOAPEncoding* aEncoding,
00725                          nsIVariant* aSource,
00726                          const nsAString& aNamespaceURI,
00727                          const nsAString& aName,
00728                          nsISchemaType* aSchemaType,
00729                          nsISOAPAttachments* aAttachments,
00730                          nsIDOMElement* aDestination,
00731                          nsIDOMElement** aReturnValue)
00732 {
00733   NS_ENSURE_ARG_POINTER(aEncoding);
00734   NS_ENSURE_ARG_POINTER(aDestination);
00735   NS_ENSURE_ARG_POINTER(aReturnValue);
00736   *aReturnValue = nsnull;
00737   nsAutoString nativeSchemaType;
00738   nsAutoString nativeSchemaURI;
00739   PRUint16 typevalue;
00740   nsresult rc = aSource->GetDataType(&typevalue);
00741   NS_ENSURE_SUCCESS(rc, rc);
00742 
00743   //  If there is a schema type then regular native types will not avail us anything.
00744   if (aSchemaType) {
00745     PRBool simple = PR_FALSE;
00746     rc = HasSimpleValue(aSchemaType, &simple);
00747     NS_ENSURE_SUCCESS(rc, rc);
00748 
00749     if (simple) {
00750       switch (typevalue) {
00751       case nsIDataType::VTYPE_ARRAY:
00752       case nsIDataType::VTYPE_EMPTY_ARRAY:
00753       case nsIDataType::VTYPE_INTERFACE_IS:
00754       case nsIDataType::VTYPE_INTERFACE:
00755         simple = PR_FALSE;
00756         break;
00757       }
00758     }
00759     if (simple) {
00760       nativeSchemaType.Assign(gSOAPStrings->kAnySimpleTypeSchemaType);
00761       nativeSchemaURI.Assign(gSOAPStrings->kXSURI);
00762     }
00763     else {
00764       nativeSchemaType.Assign(gSOAPStrings->kStructSOAPType);
00765       nativeSchemaURI.Assign(gSOAPStrings->kSOAPEncURI);
00766     }
00767   }
00768   else {
00769     GetNativeType(typevalue, nativeSchemaURI, nativeSchemaType);
00770   }
00771 
00772   nsCOMPtr<nsISOAPEncoder> encoder;
00773   nsAutoString encodingKey;
00774   SOAPEncodingKey(nativeSchemaURI, nativeSchemaType, encodingKey);
00775   rc = aEncoding->GetEncoder(encodingKey, getter_AddRefs(encoder));
00776   NS_ENSURE_SUCCESS(rc, rc);
00777 
00778   if (encoder) {
00779     nsCOMPtr<nsISchemaType> type;
00780     if (aSchemaType) {
00781       type = aSchemaType;
00782     }
00783     else {
00784       nsCOMPtr<nsISchemaCollection> collection;
00785       nsresult rc =
00786         aEncoding->GetSchemaCollection(getter_AddRefs(collection));
00787       NS_ENSURE_SUCCESS(rc, rc);
00788 
00789       rc = collection->GetType(nativeSchemaType,
00790                                nativeSchemaURI,
00791                                getter_AddRefs(type));
00792       //    if (NS_FAILED(rc)) return rc;
00793     }
00794 
00795     return encoder->Encode(aEncoding, aSource, aNamespaceURI, aName,
00796                            type, aAttachments, aDestination,
00797                            aReturnValue);
00798   }
00799   return SOAP_EXCEPTION(NS_ERROR_NOT_IMPLEMENTED,
00800                         "SOAP_NO_ENCODER_FOR_TYPE",
00801                         "The any type encoder finds no encoder for specific data");
00802 }
00803 
00804 static nsresult EncodeStructParticle(nsISOAPEncoding* aEncoding, nsIPropertyBag* aPropertyBag, 
00805                                      nsISchemaParticle* aParticle, 
00806                                      nsISOAPAttachments * aAttachments, nsIDOMElement* aDestination)
00807 {
00808   nsresult rc;
00809   if (aParticle) {
00810     PRUint32 minOccurs;
00811     rc = aParticle->GetMinOccurs(&minOccurs);
00812     NS_ENSURE_SUCCESS(rc, rc);
00813 
00814     PRUint32 maxOccurs;
00815     rc = aParticle->GetMaxOccurs(&maxOccurs);
00816     NS_ENSURE_SUCCESS(rc, rc);
00817 
00818     PRUint16 particleType;
00819     rc = aParticle->GetParticleType(&particleType);
00820     NS_ENSURE_SUCCESS(rc, rc);
00821 
00822     switch(particleType) {
00823     case nsISchemaParticle::PARTICLE_TYPE_ELEMENT: {
00824       if (maxOccurs > 1) {  //  Todo: Try to make this thing work as an array?
00825         return NS_ERROR_NOT_AVAILABLE; //  For now, we just try something else if we can (recoverable)
00826       }
00827       nsCOMPtr<nsISchemaElement> element = do_QueryInterface(aParticle);
00828       nsAutoString name;
00829       rc = element->GetTargetNamespace(name);
00830       NS_ENSURE_SUCCESS(rc, rc);
00831 
00832       if (!name.IsEmpty()) {
00833         rc = NS_ERROR_NOT_AVAILABLE; //  No known way to use namespace qualification in struct
00834       }
00835       else {
00836         rc = element->GetName(name);
00837         NS_ENSURE_SUCCESS(rc, rc);
00838 
00839         rc = element->GetName(name);
00840         NS_ENSURE_SUCCESS(rc, rc);
00841 
00842         nsCOMPtr<nsISchemaType> type;
00843         rc = element->GetType(getter_AddRefs(type));
00844         NS_ENSURE_SUCCESS(rc, rc);
00845 
00846         nsCOMPtr<nsIVariant> value;
00847         rc = aPropertyBag->GetProperty(name, getter_AddRefs(value));
00848         if (NS_SUCCEEDED(rc)) {
00849           nsCOMPtr<nsIDOMElement> dummy;
00850           rc = aEncoding->Encode(value, gSOAPStrings->kEmpty, name, type, aAttachments, aDestination, getter_AddRefs(dummy));
00851           NS_ENSURE_SUCCESS(rc, rc);
00852         }
00853       }
00854       if (minOccurs == 0 && rc == NS_ERROR_NOT_AVAILABLE) {
00855         // If we succeeded or failed recoverably, but we were permitted to, 
00856         // then return success
00857         rc = NS_OK;
00858       }
00859       return rc;
00860     }
00861     case nsISchemaParticle::PARTICLE_TYPE_MODEL_GROUP: 
00862       {
00863         if (maxOccurs > 1) {  //  Todo: Try to make this thing work as an array?
00864           return NS_ERROR_NOT_AVAILABLE; //  For now, we just try something else if we can (recoverable)
00865         }
00866         nsCOMPtr<nsISchemaModelGroup> modelGroup = do_QueryInterface(aParticle);
00867         PRUint16 compositor;
00868         rc = modelGroup->GetCompositor(&compositor);
00869         NS_ENSURE_SUCCESS(rc, rc);
00870 
00871         PRUint32 particleCount;
00872         rc = modelGroup->GetParticleCount(&particleCount);
00873         NS_ENSURE_SUCCESS(rc, rc);
00874 
00875         PRUint32 i;
00876         for (i = 0; i < particleCount; i++) {
00877           nsCOMPtr<nsISchemaParticle> child;
00878           rc = modelGroup->GetParticle(i, getter_AddRefs(child));
00879           NS_ENSURE_SUCCESS(rc, rc);
00880 
00881           rc = EncodeStructParticle(aEncoding, aPropertyBag, child, aAttachments, aDestination);
00882           if (compositor == nsISchemaModelGroup::COMPOSITOR_CHOICE) {
00883             if (NS_SUCCEEDED(rc)) {
00884               return NS_OK;
00885             }
00886             if (rc == NS_ERROR_NOT_AVAILABLE) {  //  In a choice, recoverable model failures are OK.
00887               rc = NS_OK;
00888             }
00889           }
00890           else if (i > 0 && rc == NS_ERROR_NOT_AVAILABLE) {  //  This detects ambiguous model (non-deterministic choice which fails after succeeding on first)
00891             return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,
00892                                   "SOAP_AMBIGUOUS_ENCODING",
00893                                   "Cannot proceed due to ambiguity or error in content model");
00894           }
00895           if (NS_FAILED(rc))
00896             break;
00897         }
00898         if (compositor == nsISchemaModelGroup::COMPOSITOR_CHOICE)  //  If choice selected nothing, this is recoverable failure
00899           rc = NS_ERROR_NOT_AVAILABLE;
00900         if (minOccurs == 0 && rc == NS_ERROR_NOT_AVAILABLE)  //  If we succeeded or failed recoverably, but we were permitted to, then return success
00901           rc = NS_OK;
00902         return rc;                    //  Return status
00903       }
00904     case nsISchemaParticle::PARTICLE_TYPE_ANY:
00905       //  No model available here (we may wish to handle strict versus lazy, but what does that mean with only local accessor names)
00906     default:
00907       break;
00908     }
00909   }
00910 
00911   nsCOMPtr<nsISimpleEnumerator> e;
00912   rc = aPropertyBag->GetEnumerator(getter_AddRefs(e));
00913   NS_ENSURE_SUCCESS(rc, rc);
00914 
00915   PRBool more;
00916   rc = e->HasMoreElements(&more);
00917   NS_ENSURE_SUCCESS(rc, rc);
00918 
00919   while (more) {
00920     nsCOMPtr<nsIProperty> p;
00921     rc = e->GetNext(getter_AddRefs(p));
00922     NS_ENSURE_SUCCESS(rc, rc);
00923 
00924     nsAutoString name;
00925     rc = p->GetName(name);
00926     NS_ENSURE_SUCCESS(rc, rc);
00927 
00928     nsCOMPtr<nsIVariant>value;
00929     rc = p->GetValue(getter_AddRefs(value));
00930     NS_ENSURE_SUCCESS(rc, rc);
00931 
00932     nsCOMPtr<nsIDOMElement>result;
00933     rc = aEncoding->Encode(value,gSOAPStrings->kEmpty,name,nsnull,aAttachments,aDestination,getter_AddRefs(result));
00934     NS_ENSURE_SUCCESS(rc, rc);
00935 
00936     rc = e->HasMoreElements(&more);
00937     NS_ENSURE_SUCCESS(rc, rc);
00938   }
00939   return NS_OK;
00940 }
00941 
00942 NS_IMETHODIMP
00943 nsStructEncoder::Encode(nsISOAPEncoding * aEncoding,
00944                         nsIVariant * aSource,
00945                         const nsAString & aNamespaceURI,
00946                         const nsAString & aName,
00947                         nsISchemaType * aSchemaType,
00948                         nsISOAPAttachments * aAttachments,
00949                         nsIDOMElement * aDestination,
00950                         nsIDOMElement * *aReturnValue)
00951 {
00952   NS_ENSURE_ARG_POINTER(aEncoding);
00953   NS_ENSURE_ARG_POINTER(aDestination);
00954   NS_ENSURE_ARG_POINTER(aReturnValue);
00955   *aReturnValue = nsnull;
00956   nsIID* iid;
00957   nsCOMPtr<nsISupports> ptr;
00958   nsresult rc = aSource->GetAsInterface(&iid, getter_AddRefs(ptr));
00959   NS_ENSURE_SUCCESS(rc, rc);
00960 
00961   nsCOMPtr<nsIPropertyBag>pbptr = do_QueryInterface(ptr);
00962   if (pbptr) {  //  Do any object that can QI to a property bag.
00963     nsCOMPtr<nsISchemaModelGroup>modelGroup;
00964     if (aSchemaType) {
00965       nsCOMPtr<nsISchemaComplexType>ctype = do_QueryInterface(aSchemaType);
00966       if (ctype) {
00967         rc = ctype->GetModelGroup(getter_AddRefs(modelGroup));
00968         NS_ENSURE_SUCCESS(rc, rc);
00969       }
00970     }
00971     //  We still have to fake this one, because there is no struct type in schema.
00972     if (aName.IsEmpty() && !aSchemaType) {
00973       rc = EncodeSimpleValue(aEncoding, gSOAPStrings->kEmpty,
00974                              gSOAPStrings->kSOAPEncURI,
00975                              gSOAPStrings->kStructSOAPType,
00976                              aSchemaType, aDestination,
00977                              aReturnValue);
00978     }
00979     else {
00980       rc = EncodeSimpleValue(aEncoding, gSOAPStrings->kEmpty,
00981                              aNamespaceURI, aName, aSchemaType, aDestination,
00982                              aReturnValue);
00983     }
00984     NS_ENSURE_SUCCESS(rc, rc);
00985 
00986     return EncodeStructParticle(aEncoding, pbptr, modelGroup, aAttachments, *aReturnValue);
00987   }
00988   return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,
00989                         "SOAP_PROPERTYBAG_REQUIRED",
00990                         "When encoding as a struct, an object with properties is required");
00991 }
00992 
00993 //  AnySimpleType
00994 
00995 NS_IMETHODIMP
00996 nsAnySimpleTypeEncoder::Encode(nsISOAPEncoding * aEncoding,
00997                                nsIVariant * aSource,
00998                                const nsAString & aNamespaceURI,
00999                                const nsAString & aName,
01000                                nsISchemaType * aSchemaType,
01001                                nsISOAPAttachments * aAttachments,
01002                                nsIDOMElement * aDestination,
01003                                nsIDOMElement * *aReturnValue)
01004 {
01005   NS_ENSURE_ARG_POINTER(aEncoding);
01006   NS_ENSURE_ARG_POINTER(aDestination);
01007   NS_ENSURE_ARG_POINTER(aReturnValue);
01008   *aReturnValue = nsnull;
01009   nsresult rc;
01010   nsAutoString value;
01011   rc = aSource->GetAsAString(value);
01012   NS_ENSURE_SUCCESS(rc, rc);
01013 
01014   //  We still have to fake this one, because there is no any simple type in schema.
01015   if (aName.IsEmpty() && !aSchemaType) {
01016     return EncodeSimpleValue(aEncoding, 
01017                              value,
01018                              gSOAPStrings->kSOAPEncURI,
01019                              gSOAPStrings->kAnySimpleTypeSchemaType,
01020                              aSchemaType,
01021                              aDestination,
01022                              aReturnValue);
01023   }
01024   return EncodeSimpleValue(aEncoding,
01025                            value,
01026                            aNamespaceURI,
01027                            aName,
01028                            aSchemaType,
01029                            aDestination,
01030                            aReturnValue);
01031 }
01032 
01044 static nsresult HandleNull(nsISOAPEncoding* aEncoding,
01045                            nsIDOMElement* aSource,
01046                            nsISchemaType* aSchemaType,
01047                            nsISOAPAttachments* aAttachments,
01048                            nsAutoString aNullAttr,
01049                            nsIVariant** aResult)
01050 {
01051   NS_ENSURE_ARG_POINTER(aEncoding);
01052   NS_ENSURE_ARG_POINTER(aSource);
01053   NS_ENSURE_ARG_POINTER(aResult);
01054 
01055   if (aNullAttr.Equals(gSOAPStrings->kTrue) ||
01056       aNullAttr.Equals(gSOAPStrings->kTrueA)) {
01057     
01058     PRUint16 schemaType;
01059     nsAutoString typeName;
01060 
01061     if (aSchemaType) {
01062       aSchemaType->GetSchemaType(&schemaType);
01063       aSchemaType->GetName(typeName);
01064     }
01065    
01066     nsCOMPtr<nsIWritableVariant> nullVariant(do_CreateInstance("@mozilla.org/variant;1"));
01067     if (!nullVariant) {
01068       return NS_ERROR_OUT_OF_MEMORY;
01069     }
01070 
01071     if (aSchemaType &&
01072         (typeName.Equals(NS_LITERAL_STRING("string")) ||
01073          typeName.Equals(NS_LITERAL_STRING("normalizedString")))) {
01074      
01075       nsAutoString strVal;
01076       strVal.SetIsVoid(true);
01077      
01078       nullVariant->SetAsAString(strVal);
01079     } else {
01080       nullVariant->SetAsISupports(nsnull);
01081     }
01082 
01083     NS_ADDREF(*aResult = nullVariant);
01084     return NS_OK;
01085   } else if (!(aNullAttr.Equals(gSOAPStrings->kFalse) ||
01086                aNullAttr.Equals(gSOAPStrings->kFalseA))) {
01087    
01088     return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,
01089                           "SOAP_NILL_VALUE",
01090                           "The value of the nill attribute must be true or false.");
01091   }
01092 #ifdef DEBUG
01093   NS_ERROR("How have you get here ?");
01094 #endif
01095 
01096   return NS_ERROR_UNEXPECTED;
01097 } 
01098 
01107 static nsresult GetExplicitType(nsISOAPEncoding* aEncoding, 
01108                                 nsIDOMElement* aElement,
01109                                 nsISchemaType** aResult)
01110 {
01111   NS_ENSURE_ARG_POINTER(aEncoding);
01112   NS_ENSURE_ARG_POINTER(aElement);
01113 
01114   nsresult rc = NS_OK;
01115   nsCOMPtr<nsISchemaLoader> schemaLoader =
01116     do_GetService(NS_SCHEMALOADER_CONTRACTID, &rc);
01117   NS_ENSURE_SUCCESS(rc, rc);
01118   nsAutoString explicitType;
01119 
01120   if (nsSOAPUtils::GetAttribute(aEncoding, aElement, gSOAPStrings->kXSIURI,
01121                                 gSOAPStrings->kXSITypeAttribute,
01122                                 explicitType)) {
01123     nsAutoString ns;
01124     nsAutoString name;
01125     nsCOMPtr<nsISchemaType> type;
01126 
01127     rc = nsSOAPUtils::GetNamespaceURI(aEncoding, aElement, explicitType, ns);
01128     NS_ENSURE_SUCCESS(rc, rc);
01129     rc = nsSOAPUtils::GetLocalName(explicitType, name);
01130     NS_ENSURE_SUCCESS(rc, rc);
01131 
01132     nsCOMPtr<nsISchemaCollection> col = do_QueryInterface(schemaLoader);
01133     rc = col->GetType(name, ns, getter_AddRefs(type));
01134 
01135     NS_IF_ADDREF(*aResult = type);
01136     return rc;
01137   }
01138 #ifdef DEBUG
01139   NS_ERROR("::GetExplicitType: Wow how do you get here");
01140 #endif
01141 
01142   return NS_ERROR_UNEXPECTED;
01143 }
01144 
01151 static nsresult GetArrayType(nsIVariant* aSource, 
01152                              PRUint32 aDimensionCount, 
01153                              PRUint32* aDimensionSizes, 
01154                              PRUint16* aType)
01155 {
01156   if (!aSource) {
01157     *aType = nsIDataType::VTYPE_EMPTY;
01158     return NS_OK;
01159   }
01160   PRUint16 type;
01161   nsIID iid;
01162   PRUint32 count;
01163   void* array;
01164   nsresult rc;
01165   PRUint32 i;
01166   rc = aSource->GetDataType(&type);
01167   NS_ENSURE_SUCCESS(rc, rc);
01168 
01169   if (type == nsIDataType::VTYPE_EMPTY ||
01170       type == nsIDataType::VTYPE_VOID ||
01171       type == nsIDataType::VTYPE_EMPTY_ARRAY) {
01172     rc = NS_OK;
01173     count = 0;
01174     type = nsIDataType::VTYPE_EMPTY;
01175     array = nsnull;
01176   }
01177   else {
01178     rc = aSource->GetAsArray(&type, &iid, &count, &array);        // First, get the array, if any.
01179     NS_ENSURE_SUCCESS(rc, rc);
01180   }
01181   if (count > aDimensionSizes[0]) {
01182     aDimensionSizes[0] = count;
01183   }
01184   if (aDimensionCount > 1) {
01185     if (type != nsIDataType::VTYPE_INTERFACE_IS ||
01186         !iid.Equals(NS_GET_IID(nsIVariant))) {
01187       rc = SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,"SOAP_ARRAY_OBJECTS","When encoding as an array, an array of array objects is required");
01188       //  All nested arrays (which is what multi-dimensional arrays are) are variants.
01189     }
01190     else {
01191       nsIVariant** a = NS_STATIC_CAST(nsIVariant**,array);
01192       PRUint16 rtype = nsIDataType::VTYPE_EMPTY;
01193       for (i = 0; i < count; i++) {
01194         PRUint16 nexttype;
01195         rc = GetArrayType(a[i], aDimensionCount - 1, aDimensionSizes + 1, &nexttype);
01196         if (NS_FAILED(rc))
01197           break;
01198         if (rtype == nsIDataType::VTYPE_EMPTY)
01199           rtype = nexttype;
01200         else if (nexttype != nsIDataType::VTYPE_EMPTY
01201                  && nexttype != rtype)
01202           rtype = nsIDataType::VTYPE_INTERFACE_IS;
01203       }
01204       *aType = rtype;
01205     }
01206   }
01207   else {
01208     *aType = type;
01209   }
01210   //  The memory model for variant arrays' GetAsArray is difficult to manage
01211   switch (type) {
01212   case nsIDataType::VTYPE_INTERFACE_IS:
01213     {
01214       nsISupports** values = NS_STATIC_CAST(nsISupports**,array);
01215       for (i = 0; i < count; i++)
01216         NS_RELEASE(values[i]);
01217     }
01218     break;
01219   case nsIDataType::VTYPE_WCHAR_STR:
01220   case nsIDataType::VTYPE_CHAR_STR:
01221     {
01222       void** ptrs = NS_STATIC_CAST(void**,array);
01223       for (i = 0; i < count; i++) {
01224         nsMemory::Free(ptrs[i]);
01225       }
01226     }
01227     break;
01228   }
01229   nsMemory::Free(array);
01230   {  //  Individual lengths guaranteed to fit because variant array length is 32-bit.
01231     PRUint64 tot = 1;  //  Collect in 64 bits, just to make sure combo fits
01232     for (i = 0; i < aDimensionCount; i++) {
01233       tot = tot * aDimensionSizes[i];
01234       if (tot > 0xffffffffU) {
01235         return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,
01236                               "SOAP_ARRAY_TOO_BIG",
01237                               "When encoding an object as an array, the total count of items exceeded maximum.");
01238       }
01239     }
01240   }
01241   return rc;
01242 }
01248 static nsresult EncodeArray(nsISOAPEncoding* aEncoding, nsIVariant* aSource, nsISchemaType* aSchemaType,
01249                             nsISOAPAttachments* aAttachments, nsIDOMElement* aArray, PRUint32 aDimensionCount, PRUint32* aDimensionSizes)
01250 {
01251   nsresult rc;
01252   PRUint16 type;
01253   nsIID iid;
01254   PRUint32 count;
01255   void *array;
01256   if (aSource != nsnull) {
01257     nsresult rc = aSource->GetDataType(&type);
01258     NS_ENSURE_SUCCESS(rc, rc);
01259 
01260     if (type == nsIDataType::VTYPE_EMPTY ||
01261         type == nsIDataType::VTYPE_VOID ||
01262         type == nsIDataType::VTYPE_EMPTY_ARRAY) {
01263       rc = NS_OK;
01264       count = 0;
01265       type = nsIDataType::VTYPE_EMPTY;
01266       array = nsnull;
01267     }
01268     else {
01269       rc = aSource->GetAsArray(&type, &iid, &count, &array);        // First, get the array, if any.
01270       NS_ENSURE_SUCCESS(rc, rc);
01271     }
01272   }
01273   else {  //  If the source is null, then just add a bunch of nulls to the array.
01274     count = (PRUint32)aDimensionSizes[--aDimensionCount];
01275     while (aDimensionCount)
01276       count *= (PRUint32)aDimensionSizes[--aDimensionCount];
01277     if (count) {
01278       nsAutoString ns;
01279       nsCOMPtr<nsIDOMElement> cloneable;
01280       rc = aEncoding->GetExternalSchemaURI(gSOAPStrings->kXSIURI, ns);
01281       NS_ENSURE_SUCCESS(rc, rc);
01282 
01283       rc = EncodeSimpleValue(aEncoding, gSOAPStrings->kEmpty, gSOAPStrings->kEmpty, 
01284                              gSOAPStrings->kNull, nsnull, aArray, getter_AddRefs(cloneable));
01285       NS_ENSURE_SUCCESS(rc, rc);
01286 
01287       rc = cloneable->SetAttributeNS(ns, gSOAPStrings->kNull, gSOAPStrings->kTrueA);
01288       NS_ENSURE_SUCCESS(rc, rc);
01289 
01290       nsCOMPtr<nsIDOMNode> clone;
01291       nsCOMPtr<nsIDOMNode> dummy;
01292       for (;--count;) {
01293         rc = cloneable->CloneNode(PR_TRUE, getter_AddRefs(clone));// No children so deep == shallow
01294         NS_ENSURE_SUCCESS(rc, rc);
01295 
01296         rc = aArray->AppendChild(clone, getter_AddRefs(dummy));
01297         NS_ENSURE_SUCCESS(rc, rc);
01298       }
01299     }
01300   }
01301   nsCOMPtr<nsIDOMElement> dummy;
01302   PRBool freeptrs = PR_FALSE;
01303   PRUint32 i;
01304 
01305   //  The more-robust way of encoding is to construct variants and call the encoder directly,
01306   //  but for now, we short-circuit it for simple types.
01307 
01308 #define ENCODE_SIMPLE_ARRAY(XPType, VType, Source)    \
01309   {                                                   \
01310     XPType* values = NS_STATIC_CAST(XPType*, array);  \
01311     nsCOMPtr<nsIWritableVariant> p =                  \
01312       do_CreateInstance(NS_VARIANT_CONTRACTID, &rc);  \
01313     if (NS_FAILED(rc)) break;                         \
01314     for (i = 0; i < count; i++) {                     \
01315       if (NS_FAILED(rc))                              \
01316         break;                                        \
01317       rc = p->SetAs##VType(Source);                   \
01318       if (NS_FAILED(rc))                              \
01319         break;                                        \
01320       rc = aEncoding->Encode(p,                       \
01321                              gSOAPStrings->kEmpty,    \
01322                              gSOAPStrings->kEmpty,    \
01323                              aSchemaType,             \
01324                              aAttachments,            \
01325                              aArray,                  \
01326                              getter_AddRefs(dummy));  \
01327       if (NS_FAILED(rc)) break;                       \
01328     }                                                 \
01329     break;                                            \
01330   }
01331 
01332   if (aDimensionCount > 1) {
01333     switch (type) {
01334     case nsIDataType::VTYPE_INTERFACE_IS:
01335       {
01336         nsIVariant** values = NS_STATIC_CAST(nsIVariant**, array);//  If not truly a variant, we only release.
01337         if (iid.Equals(NS_GET_IID(nsIVariant))) {  //  Only do variants for now.
01338           for (i = 0; i < count; i++) {
01339             rc = EncodeArray(aEncoding, values[i],
01340                              aSchemaType,
01341                              aAttachments,
01342                              aArray,
01343                              aDimensionCount - 1,
01344                              aDimensionSizes + 1);
01345             if (NS_FAILED(rc)) break;
01346           }
01347         }
01348         for (i = 0; i < count; i++)
01349           NS_RELEASE(values[i]);
01350         break;
01351       }
01352     case nsIDataType::VTYPE_WCHAR_STR:
01353     case nsIDataType::VTYPE_CHAR_STR:
01354       freeptrs = PR_TRUE;
01355     default:
01356       rc = SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,"SOAP_ARRAY_OBJECTS","When encoding as an array, an array of array objects is required");
01357     }
01358   } else switch (type) {
01359   case nsIDataType::VTYPE_INT8:
01360     ENCODE_SIMPLE_ARRAY(PRUint8, Int8,
01361                         (signed char) values[i]);
01362   case nsIDataType::VTYPE_INT16:
01363     ENCODE_SIMPLE_ARRAY(PRInt16, Int16, values[i]);
01364   case nsIDataType::VTYPE_INT32:
01365     ENCODE_SIMPLE_ARRAY(PRInt32, Int32, values[i]);
01366   case nsIDataType::VTYPE_INT64:
01367     ENCODE_SIMPLE_ARRAY(PRInt64, Int64, values[i]);
01368   case nsIDataType::VTYPE_UINT8:
01369     ENCODE_SIMPLE_ARRAY(PRUint8, Uint8, values[i]);
01370   case nsIDataType::VTYPE_UINT16:
01371     ENCODE_SIMPLE_ARRAY(PRUint16, Uint16, values[i]);
01372   case nsIDataType::VTYPE_UINT32:
01373     ENCODE_SIMPLE_ARRAY(PRUint32, Uint32, values[i]);
01374   case nsIDataType::VTYPE_UINT64:
01375     ENCODE_SIMPLE_ARRAY(PRUint64, Uint64, values[i]);
01376   case nsIDataType::VTYPE_FLOAT:
01377     ENCODE_SIMPLE_ARRAY(float, Float, values[i]);
01378   case nsIDataType::VTYPE_DOUBLE:
01379     ENCODE_SIMPLE_ARRAY(double, Double, values[i]);
01380   case nsIDataType::VTYPE_BOOL:
01381     ENCODE_SIMPLE_ARRAY(PRBool, Bool, (PRUint16) values[i]);
01382   case nsIDataType::VTYPE_ID:
01383   case nsIDataType::VTYPE_CHAR_STR:
01384     freeptrs = PR_TRUE;
01385     ENCODE_SIMPLE_ARRAY(char *, String, values[i]);
01386   case nsIDataType::VTYPE_WCHAR_STR:
01387     freeptrs = PR_TRUE;
01388     ENCODE_SIMPLE_ARRAY(PRUnichar *, WString, values[i]);
01389   case nsIDataType::VTYPE_CHAR:
01390     ENCODE_SIMPLE_ARRAY(char, Char, values[i]);
01391   case nsIDataType::VTYPE_WCHAR:
01392     ENCODE_SIMPLE_ARRAY(PRUnichar, WChar, values[i]);
01393   case nsIDataType::VTYPE_INTERFACE_IS:
01394     {
01395       nsIVariant** values = NS_STATIC_CAST(nsIVariant**, array);//  If not truly a variant, we only use as nsISupports
01396       if (iid.Equals(NS_GET_IID(nsIVariant))) {  //  Only do variants for now.
01397         for (i = 0; i < count; i++) {
01398           rc = aEncoding->Encode(values[i],
01399                                  gSOAPStrings->kEmpty,
01400                                  gSOAPStrings->kEmpty,
01401                                  aSchemaType,
01402                                  aAttachments,
01403                                  aArray,
01404                                  getter_AddRefs(dummy));
01405           if (NS_FAILED(rc)) break;
01406         }
01407       }
01408       else {
01409         nsCOMPtr<nsIWritableVariant> p =
01410           do_CreateInstance(NS_VARIANT_CONTRACTID, &rc);
01411         if (NS_FAILED(rc)) break;
01412         for (i = 0; i < count; i++) {
01413           if (NS_FAILED(rc))
01414             break;
01415           rc = p->SetAsInterface(iid, values[i]);
01416           if (NS_FAILED(rc))
01417             break;
01418           rc = aEncoding->Encode(p,
01419                                  gSOAPStrings->kEmpty,
01420                                  gSOAPStrings->kEmpty,
01421                                  aSchemaType,
01422                                  aAttachments,
01423                                  aArray,
01424                                  getter_AddRefs(dummy));
01425           if (NS_FAILED(rc)) break;
01426         }
01427       }
01428       for (i = 0; i < count; i++)
01429         NS_RELEASE(values[i]);
01430       break;
01431     }
01432   
01433   case nsIDataType::VTYPE_EMPTY_ARRAY:
01434   case nsIDataType::VTYPE_EMPTY:
01435     break;  //  I think an empty array needs no elements?
01436     //  Don't support these array types, as they seem meaningless.
01437   case nsIDataType::VTYPE_ASTRING:
01438   case nsIDataType::VTYPE_VOID:
01439   case nsIDataType::VTYPE_INTERFACE:
01440   case nsIDataType::VTYPE_ARRAY:
01441     rc = SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,"SOAP_ARRAY_TYPES","When encoding an array, unable to handle array elements");
01442   }
01443   if (freeptrs) {
01444     void** ptrs = NS_STATIC_CAST(void**,array);
01445     for (i = 0; i < count; i++) {
01446       nsMemory::Free(ptrs[i]);
01447     }
01448     nsMemory::Free(array);
01449   }
01450   //  We know that count does not exceed size of dimension, but it may be less
01451   return rc;
01452 }
01453 
01454 NS_IMETHODIMP
01455 nsArrayEncoder::Encode(nsISOAPEncoding * aEncoding,
01456                        nsIVariant * aSource,
01457                        const nsAString & aNamespaceURI,
01458                        const nsAString & aName,
01459                        nsISchemaType * aSchemaType,
01460                        nsISOAPAttachments * aAttachments,
01461                        nsIDOMElement * aDestination,
01462                        nsIDOMElement * *aReturnValue)
01463 {
01464   NS_ENSURE_ARG_POINTER(aEncoding);
01465   NS_ENSURE_ARG_POINTER(aDestination);
01466   NS_ENSURE_ARG_POINTER(aReturnValue);
01467   *aReturnValue = nsnull;
01468   PRUint16 arrayNativeType;
01469   PRUint32 dimensionSizes[MAX_ARRAY_DIMENSIONS];
01470   PRUint32 i;
01471   PRUint32 dimensionCount = 1;
01472   nsCOMPtr<nsISchemaType> schemaArrayType;
01473   if (aSchemaType) {
01474     PRUint16 type;
01475     nsresult rc = aSchemaType->GetSchemaType(&type);
01476     NS_ENSURE_SUCCESS(rc, rc);
01477 
01478     if (type == nsISchemaType::SCHEMA_TYPE_COMPLEX) {
01479       nsCOMPtr<nsISchemaComplexType> ct = do_QueryInterface(aSchemaType);
01480       nsresult rc = ct->GetArrayDimension(&dimensionCount);
01481       NS_ENSURE_SUCCESS(rc, rc);
01482 
01483       if (dimensionCount == 0) {
01484         dimensionCount = 1;
01485       }
01486       else {
01487         //  Arrays with no defaults are supposed to return 0, but apparently do not
01488         rc = ct->GetArrayType(getter_AddRefs(schemaArrayType));
01489         NS_ENSURE_SUCCESS(rc, rc);
01490       }
01491     }
01492   }
01493   for (i = 0; i < dimensionCount; i++)
01494     dimensionSizes[i] = 0;
01495   //  Look over the array and find its dimensions and common type.
01496   nsresult rc = GetArrayType(aSource, dimensionCount, dimensionSizes, &arrayNativeType);
01497   NS_ENSURE_SUCCESS(rc, rc);
01498 
01499   nsAutoString arrayTypeSchemaURI;
01500   nsAutoString arrayTypeSchemaName;
01501   if (!schemaArrayType) {
01502     switch (arrayNativeType) {
01503     case nsIDataType::VTYPE_INTERFACE:  //  In a variant, an interface is a struct, but here it is any
01504     case nsIDataType::VTYPE_INTERFACE_IS:
01505       arrayTypeSchemaName = gSOAPStrings->kAnyTypeSchemaType;
01506       arrayTypeSchemaURI = gSOAPStrings->kXSURI;
01507       break;
01508     default:  //  Everything else can be interpreted correctly
01509       GetNativeType(arrayNativeType, arrayTypeSchemaURI, arrayTypeSchemaName);
01510     }
01511     nsCOMPtr<nsISchemaCollection> collection;
01512     nsresult rc =
01513       aEncoding->GetSchemaCollection(getter_AddRefs(collection));
01514     NS_ENSURE_SUCCESS(rc, rc);
01515 
01516     rc = collection->GetType(arrayTypeSchemaName,
01517                              arrayTypeSchemaName,
01518                              getter_AddRefs(schemaArrayType));
01519     //    if (NS_FAILED(rc)) return rc;
01520   }
01521   else {
01522     rc = schemaArrayType->GetTargetNamespace(arrayTypeSchemaURI);
01523     NS_ENSURE_SUCCESS(rc, rc);
01524 
01525     rc = schemaArrayType->GetName(arrayTypeSchemaName);
01526     NS_ENSURE_SUCCESS(rc, rc);
01527   }
01528   rc = EncodeSimpleValue(aEncoding, gSOAPStrings->kEmpty,
01529                          aNamespaceURI,
01530                          aName, aSchemaType, aDestination, aReturnValue);
01531   NS_ENSURE_SUCCESS(rc, rc);
01532 
01533   //  This needs a real live interpretation of the type.
01534 
01535   {
01536     nsAutoString value;
01537     nsSOAPUtils::MakeNamespacePrefix(aEncoding,*aReturnValue,arrayTypeSchemaURI,value);
01538     value.Append(gSOAPStrings->kQualifiedSeparator);
01539     value.Append(arrayTypeSchemaName);
01540     value.Append(PRUnichar('['));
01541     for (i = 0; i < dimensionCount; i++) {
01542       if (i > 0)
01543         value.Append(PRUnichar(','));
01544       char* ptr = PR_smprintf("%d", dimensionSizes[i]);
01545       AppendUTF8toUTF16(ptr, value);
01546       PR_smprintf_free(ptr);
01547     }
01548     value.Append(PRUnichar(']'));
01549     nsAutoString encURI;
01550     rc = aEncoding->GetExternalSchemaURI(gSOAPStrings->kSOAPEncURI,encURI);
01551     NS_ENSURE_SUCCESS(rc, rc);
01552 
01553     rc = (*aReturnValue)->SetAttributeNS(encURI, gSOAPStrings->kSOAPArrayTypeAttribute, value);
01554     NS_ENSURE_SUCCESS(rc, rc);
01555   }
01556 
01557   //  For efficiency, we should perform encoder lookup once here.
01558 
01559   return EncodeArray(aEncoding, aSource, schemaArrayType, aAttachments, *aReturnValue, dimensionCount, dimensionSizes);
01560 }
01561 
01562 //  String
01563 
01564 NS_IMETHODIMP
01565 nsStringEncoder::Encode(nsISOAPEncoding * aEncoding,
01566                         nsIVariant * aSource,
01567                         const nsAString & aNamespaceURI,
01568                         const nsAString & aName,
01569                         nsISchemaType * aSchemaType,
01570                         nsISOAPAttachments * aAttachments,
01571                         nsIDOMElement * aDestination,
01572                         nsIDOMElement * *aReturnValue)
01573 {
01574   NS_ENSURE_ARG_POINTER(aEncoding);
01575   NS_ENSURE_ARG_POINTER(aDestination);
01576   NS_ENSURE_ARG_POINTER(aReturnValue);
01577   *aReturnValue = nsnull;
01578   nsresult rc;
01579   nsAutoString value;
01580   rc = aSource->GetAsAString(value);
01581   NS_ENSURE_SUCCESS(rc, rc);
01582 
01583   return EncodeSimpleValue(aEncoding, value,
01584                            aNamespaceURI, aName, aSchemaType, aDestination,
01585                            aReturnValue);
01586 }
01587 
01588 //  PRBool
01589 
01590 NS_IMETHODIMP
01591 nsBooleanEncoder::Encode(nsISOAPEncoding * aEncoding,
01592                          nsIVariant * aSource,
01593                          const nsAString & aNamespaceURI,
01594                          const nsAString & aName,
01595                          nsISchemaType * aSchemaType,
01596                          nsISOAPAttachments * aAttachments,
01597                          nsIDOMElement * aDestination,
01598                          nsIDOMElement * *aReturnValue)
01599 {
01600   NS_ENSURE_ARG_POINTER(aEncoding);
01601   NS_ENSURE_ARG_POINTER(aDestination);
01602   NS_ENSURE_ARG_POINTER(aReturnValue);
01603   *aReturnValue = nsnull;
01604   nsresult rc;
01605   PRBool b;
01606   rc = aSource->GetAsBool(&b);
01607   NS_ENSURE_SUCCESS(rc, rc);
01608 
01609   return EncodeSimpleValue(aEncoding, b ? gSOAPStrings->kTrueA : gSOAPStrings->kFalseA,
01610                            aNamespaceURI, aName, aSchemaType, aDestination,
01611                            aReturnValue);
01612 }
01613 
01614 //  Double
01615 
01616 NS_IMETHODIMP
01617 nsDoubleEncoder::Encode(nsISOAPEncoding * aEncoding,
01618                         nsIVariant * aSource,
01619                         const nsAString & aNamespaceURI,
01620                         const nsAString & aName,
01621                         nsISchemaType * aSchemaType,
01622                         nsISOAPAttachments * aAttachments,
01623                         nsIDOMElement * aDestination,
01624                         nsIDOMElement * *aReturnValue)
01625 {
01626   NS_ENSURE_ARG_POINTER(aEncoding);
01627   NS_ENSURE_ARG_POINTER(aDestination);
01628   NS_ENSURE_ARG_POINTER(aReturnValue);
01629   *aReturnValue = nsnull;
01630   nsresult rc;
01631   double f;
01632   rc = aSource->GetAsDouble(&f);        //  Check that double works.
01633   NS_ENSURE_SUCCESS(rc, rc);
01634 
01635   nsAutoString value;
01636   // Note that AppendFloat actually takes a double, so this is ok.
01637   value.AppendFloat(f);
01638   return EncodeSimpleValue(aEncoding, value,
01639                            aNamespaceURI, aName, aSchemaType, aDestination,
01640                            aReturnValue);
01641 }
01642 
01643 //  Float
01644 
01645 NS_IMETHODIMP
01646 nsFloatEncoder::Encode(nsISOAPEncoding * aEncoding,
01647                        nsIVariant * aSource,
01648                        const nsAString & aNamespaceURI,
01649                        const nsAString & aName,
01650                        nsISchemaType * aSchemaType,
01651                        nsISOAPAttachments * aAttachments,
01652                        nsIDOMElement * aDestination,
01653                        nsIDOMElement * *aReturnValue)
01654 {
01655   NS_ENSURE_ARG_POINTER(aEncoding);
01656   NS_ENSURE_ARG_POINTER(aDestination);
01657   NS_ENSURE_ARG_POINTER(aReturnValue);
01658   *aReturnValue = nsnull;
01659   nsresult rc;
01660   float f;
01661   rc = aSource->GetAsFloat(&f);        //  Check that float works.
01662   NS_ENSURE_SUCCESS(rc, rc);
01663 
01664   nsAutoString value;
01665   value.AppendFloat(f);
01666   return EncodeSimpleValue(aEncoding, value,
01667                            aNamespaceURI, aName, aSchemaType, aDestination,
01668                            aReturnValue);
01669 }
01670 
01671 //  PRInt64
01672 
01673 NS_IMETHODIMP
01674 nsLongEncoder::Encode(nsISOAPEncoding * aEncoding,
01675                       nsIVariant * aSource,
01676                       const nsAString & aNamespaceURI,
01677                       const nsAString & aName,
01678                       nsISchemaType * aSchemaType,
01679                       nsISOAPAttachments * aAttachments,
01680                       nsIDOMElement * aDestination,
01681                       nsIDOMElement * *aReturnValue)
01682 {
01683   NS_ENSURE_ARG_POINTER(aEncoding);
01684   NS_ENSURE_ARG_POINTER(aDestination);
01685   NS_ENSURE_ARG_POINTER(aReturnValue);
01686   *aReturnValue = nsnull;
01687   nsresult rc;
01688   PRInt64 f;
01689   rc = aSource->GetAsInt64(&f);        //  Get as a long number.
01690   NS_ENSURE_SUCCESS(rc, rc);
01691 
01692   char *ptr = PR_smprintf("%lld", f);
01693   if (!ptr)
01694     return NS_ERROR_OUT_OF_MEMORY;
01695   nsAutoString value;
01696   CopyASCIItoUCS2(nsDependentCString(ptr), value);
01697   PR_smprintf_free(ptr);
01698   return EncodeSimpleValue(aEncoding, value,
01699                            aNamespaceURI, aName, aSchemaType, aDestination,
01700                            aReturnValue);
01701 }
01702 
01703 //  PRInt32
01704 
01705 NS_IMETHODIMP
01706 nsIntEncoder::Encode(nsISOAPEncoding * aEncoding,
01707                      nsIVariant * aSource,
01708                      const nsAString & aNamespaceURI,
01709                      const nsAString & aName,
01710                      nsISchemaType * aSchemaType,
01711                      nsISOAPAttachments * aAttachments,
01712                      nsIDOMElement * aDestination,
01713                      nsIDOMElement * *aReturnValue)
01714 {
01715   NS_ENSURE_ARG_POINTER(aEncoding);
01716   NS_ENSURE_ARG_POINTER(aDestination);
01717   NS_ENSURE_ARG_POINTER(aReturnValue);
01718   *aReturnValue = nsnull;
01719   nsresult rc;
01720   PRInt32 f;
01721   rc = aSource->GetAsInt32(&f);        //  Get as a long number.
01722   NS_ENSURE_SUCCESS(rc, rc);
01723 
01724   char *ptr = PR_smprintf("%d", f);
01725   if (!ptr)
01726     return NS_ERROR_OUT_OF_MEMORY;
01727   nsAutoString value;
01728   CopyASCIItoUCS2(nsDependentCString(ptr), value);
01729   PR_smprintf_free(ptr);
01730   return EncodeSimpleValue(aEncoding, value,
01731                            aNamespaceURI, aName, aSchemaType, aDestination,
01732                            aReturnValue);
01733 }
01734 
01735 //  PRInt16
01736 
01737 NS_IMETHODIMP
01738 nsShortEncoder::Encode(nsISOAPEncoding * aEncoding,
01739                        nsIVariant * aSource,
01740                        const nsAString & aNamespaceURI,
01741                        const nsAString & aName,
01742                        nsISchemaType * aSchemaType,
01743                        nsISOAPAttachments * aAttachments,
01744                        nsIDOMElement * aDestination,
01745                        nsIDOMElement * *aReturnValue)
01746 {
01747   NS_ENSURE_ARG_POINTER(aEncoding);
01748   NS_ENSURE_ARG_POINTER(aDestination);
01749   NS_ENSURE_ARG_POINTER(aReturnValue);
01750   *aReturnValue = nsnull;
01751   nsresult rc;
01752   PRInt16 f;
01753   rc = aSource->GetAsInt16(&f);        //  Get as a long number.
01754   NS_ENSURE_SUCCESS(rc, rc);
01755 
01756   char *ptr = PR_smprintf("%d", (PRInt32) f);
01757   if (!ptr)
01758     return NS_ERROR_OUT_OF_MEMORY;
01759   nsAutoString value;
01760   CopyASCIItoUCS2(nsDependentCString(ptr), value);
01761   PR_smprintf_free(ptr);
01762   return EncodeSimpleValue(aEncoding, value,
01763                            aNamespaceURI, aName, aSchemaType, aDestination,
01764                            aReturnValue);
01765 }
01766 
01767 //  Byte
01768 
01769 NS_IMETHODIMP
01770 nsByteEncoder::Encode(nsISOAPEncoding * aEncoding,
01771                       nsIVariant * aSource,
01772                       const nsAString & aNamespaceURI,
01773                       const nsAString & aName,
01774                       nsISchemaType * aSchemaType,
01775                       nsISOAPAttachments * aAttachments,
01776                       nsIDOMElement * aDestination,
01777                       nsIDOMElement * *aReturnValue)
01778 {
01779   NS_ENSURE_ARG_POINTER(aEncoding);
01780   NS_ENSURE_ARG_POINTER(aDestination);
01781   NS_ENSURE_ARG_POINTER(aReturnValue);
01782   *aReturnValue = nsnull;
01783   nsresult rc;
01784   PRUint8 f;
01785   rc = aSource->GetAsInt8(&f);        //  Get as a long number.
01786   NS_ENSURE_SUCCESS(rc, rc);
01787 
01788   char *ptr = PR_smprintf("%d", (PRInt32) (signed char) f);
01789   if (!ptr)
01790     return NS_ERROR_OUT_OF_MEMORY;
01791   nsAutoString value;
01792   CopyASCIItoUCS2(nsDependentCString(ptr), value);
01793   PR_smprintf_free(ptr);
01794   return EncodeSimpleValue(aEncoding, value,
01795                            aNamespaceURI, aName, aSchemaType, aDestination,
01796                            aReturnValue);
01797 }
01798 
01799 //  PRUint64
01800 
01801 NS_IMETHODIMP
01802 nsUnsignedLongEncoder::Encode(nsISOAPEncoding * aEncoding,
01803                               nsIVariant * aSource,
01804                               const nsAString & aNamespaceURI,
01805                               const nsAString & aName,
01806                               nsISchemaType * aSchemaType,
01807                               nsISOAPAttachments * aAttachments,
01808                               nsIDOMElement * aDestination,
01809                               nsIDOMElement * *aReturnValue)
01810 {
01811   NS_ENSURE_ARG_POINTER(aEncoding);
01812   NS_ENSURE_ARG_POINTER(aDestination);
01813   NS_ENSURE_ARG_POINTER(aReturnValue);
01814   *aReturnValue = nsnull;
01815   nsresult rc;
01816   PRUint64 f;
01817   rc = aSource->GetAsUint64(&f);        //  Get as a long number.
01818   NS_ENSURE_SUCCESS(rc, rc);
01819 
01820   char *ptr = PR_smprintf("%llu", f);
01821   if (!ptr)
01822     return NS_ERROR_OUT_OF_MEMORY;
01823   nsAutoString value;
01824   CopyASCIItoUCS2(nsDependentCString(ptr), value);
01825   PR_smprintf_free(ptr);
01826   return EncodeSimpleValue(aEncoding, value,
01827                            aNamespaceURI, aName, aSchemaType, aDestination,
01828                            aReturnValue);
01829 }
01830 
01831 //  PRUint32
01832 
01833 NS_IMETHODIMP
01834 nsUnsignedIntEncoder::Encode(nsISOAPEncoding * aEncoding,
01835                              nsIVariant * aSource,
01836                              const nsAString & aNamespaceURI,
01837                              const nsAString & aName,
01838                              nsISchemaType * aSchemaType,
01839                              nsISOAPAttachments * aAttachments,
01840                              nsIDOMElement * aDestination,
01841                              nsIDOMElement * *aReturnValue)
01842 {
01843   NS_ENSURE_ARG_POINTER(aEncoding);
01844   NS_ENSURE_ARG_POINTER(aDestination);
01845   NS_ENSURE_ARG_POINTER(aReturnValue);
01846   *aReturnValue = nsnull;
01847   nsresult rc;
01848   PRUint32 f;
01849   rc = aSource->GetAsUint32(&f);        //  Get as a long number.
01850   NS_ENSURE_SUCCESS(rc, rc);
01851 
01852   char *ptr = PR_smprintf("%u", f);
01853   if (!ptr)
01854     return NS_ERROR_OUT_OF_MEMORY;
01855   nsAutoString value;
01856   CopyASCIItoUCS2(nsDependentCString(ptr), value);
01857   PR_smprintf_free(ptr);
01858   return EncodeSimpleValue(aEncoding, value,
01859                            aNamespaceURI, aName, aSchemaType, aDestination,
01860                            aReturnValue);
01861 }
01862 
01863 NS_IMETHODIMP
01864 nsBase64BinaryEncoder::Encode(nsISOAPEncoding * aEncoding,
01865                               nsIVariant * aSource,
01866                               const nsAString & aNamespaceURI,
01867                               const nsAString & aName,
01868                               nsISchemaType * aSchemaType,
01869                               nsISOAPAttachments * aAttachments,
01870                               nsIDOMElement * aDestination,
01871                               nsIDOMElement * *aReturnValue)
01872 {
01873   NS_ENSURE_ARG_POINTER(aSource);
01874   NS_ENSURE_ARG_POINTER(aEncoding);
01875   NS_ENSURE_ARG_POINTER(aDestination);
01876   NS_ENSURE_ARG_POINTER(aReturnValue);
01877 
01878   *aReturnValue = nsnull;
01879 
01880   PRUint16 typeValue;
01881   nsresult rv = aSource->GetDataType(&typeValue);
01882   NS_ENSURE_SUCCESS(rv, rv);
01883 
01884   if (typeValue != nsIDataType::VTYPE_ARRAY) {
01885     return NS_ERROR_FAILURE;
01886   }
01887 
01888   nsIID iid;
01889   PRUint32 count;
01890   void* array;
01891   rv = aSource->GetAsArray(&typeValue, &iid, &count, &array);
01892   NS_ENSURE_SUCCESS(rv, rv);
01893     
01894   if (typeValue != nsIDataType::VTYPE_UINT8) {
01895     return NS_ERROR_FAILURE;
01896   }
01897 
01898   char* encodedVal = PL_Base64Encode(NS_STATIC_CAST(char*, array), count, nsnull);
01899   if (!encodedVal) {
01900     return NS_ERROR_FAILURE;
01901   }
01902   nsAdoptingCString encodedString(encodedVal);
01903 
01904   nsAutoString name, ns;
01905   if (aName.IsEmpty()) {
01906     // If we don't have a name, we pick soapenc:base64Binary.
01907     rv = aEncoding->GetStyleURI(ns);
01908     NS_ENSURE_SUCCESS(rv, rv);
01909     name.Append(gSOAPStrings->kBase64BinarySchemaType);
01910   }
01911   else {
01912     name = aName;
01913     // ns remains empty. This is ok.
01914   }
01915 
01916   nsCOMPtr<nsIDOMDocument> document;
01917   rv = aDestination->GetOwnerDocument(getter_AddRefs(document));
01918   NS_ENSURE_SUCCESS(rv, rv);
01919 
01920   nsCOMPtr<nsIDOMElement> element;
01921   rv = document->CreateElementNS(ns, name, getter_AddRefs(element));
01922   NS_ENSURE_SUCCESS(rv, rv);
01923 
01924   nsCOMPtr<nsIDOMNode> ignore;
01925   rv = aDestination->AppendChild(element, getter_AddRefs(ignore));
01926   NS_ENSURE_SUCCESS(rv, rv);
01927 
01928   if (aSchemaType) {
01929     nsAutoString typeName, typeNS;
01930     rv = aSchemaType->GetName(typeName);
01931     NS_ENSURE_SUCCESS(rv, rv);
01932     rv = aSchemaType->GetTargetNamespace(typeNS);
01933     NS_ENSURE_SUCCESS(rv, rv);
01934 
01935     nsAutoString qname;
01936     rv = nsSOAPUtils::MakeNamespacePrefix(nsnull, element, typeNS, qname);
01937     NS_ENSURE_SUCCESS(rv, rv);
01938     
01939     qname.Append(gSOAPStrings->kQualifiedSeparator + typeName);
01940     
01941     nsAutoString ns;
01942     rv = aEncoding->GetExternalSchemaURI(gSOAPStrings->kXSIURI, ns);
01943     NS_ENSURE_SUCCESS(rv, rv);
01944     
01945     rv = element->SetAttributeNS(ns, gSOAPStrings->kXSITypeAttribute, qname);
01946     NS_ENSURE_SUCCESS(rv, rv);
01947   }
01948 
01949   nsCOMPtr<nsIDOMText> text;
01950   rv = document->CreateTextNode(NS_ConvertASCIItoUTF16(encodedString),
01951                                 getter_AddRefs(text));
01952   NS_ENSURE_SUCCESS(rv, rv);
01953     
01954   rv = element->AppendChild(text, getter_AddRefs(ignore));
01955   NS_ENSURE_SUCCESS(rv, rv);
01956 
01957   NS_ADDREF(*aReturnValue = element);
01958   return rv;
01959 }
01960 
01961 
01962 //  PRUint16
01963 
01964 NS_IMETHODIMP
01965 nsUnsignedShortEncoder::Encode(nsISOAPEncoding * aEncoding,
01966                                nsIVariant * aSource,
01967                                const nsAString & aNamespaceURI,
01968                                const nsAString & aName,
01969                                nsISchemaType * aSchemaType,
01970                                nsISOAPAttachments * aAttachments,
01971                                nsIDOMElement * aDestination,
01972                                nsIDOMElement * *aReturnValue)
01973 {
01974   NS_ENSURE_ARG_POINTER(aEncoding);
01975   NS_ENSURE_ARG_POINTER(aDestination);
01976   NS_ENSURE_ARG_POINTER(aReturnValue);
01977   *aReturnValue = nsnull;
01978   nsresult rc;
01979   PRUint16 f;
01980   rc = aSource->GetAsUint16(&f);        //  Get as a long number.
01981   NS_ENSURE_SUCCESS(rc, rc);
01982 
01983   char *ptr = PR_smprintf("%u", (PRUint32) f);
01984   if (!ptr)
01985     return NS_ERROR_OUT_OF_MEMORY;
01986   nsAutoString value;
01987   CopyASCIItoUCS2(nsDependentCString(ptr), value);
01988   PR_smprintf_free(ptr);
01989   return EncodeSimpleValue(aEncoding, value,
01990                            aNamespaceURI, aName, aSchemaType, aDestination,
01991                            aReturnValue);
01992 }
01993 
01994 //  Unsigned Byte
01995 
01996 NS_IMETHODIMP
01997 nsUnsignedByteEncoder::Encode(nsISOAPEncoding * aEncoding,
01998                               nsIVariant * aSource,
01999                               const nsAString & aNamespaceURI,
02000                               const nsAString & aName,
02001                               nsISchemaType * aSchemaType,
02002                               nsISOAPAttachments * aAttachments,
02003                               nsIDOMElement * aDestination,
02004                               nsIDOMElement * *aReturnValue)
02005 {
02006   NS_ENSURE_ARG_POINTER(aEncoding);
02007   NS_ENSURE_ARG_POINTER(aDestination);
02008   NS_ENSURE_ARG_POINTER(aReturnValue);
02009   *aReturnValue = nsnull;
02010   nsresult rc;
02011   PRUint8 f;
02012   rc = aSource->GetAsUint8(&f);        //  Get as a long number.
02013   NS_ENSURE_SUCCESS(rc, rc);
02014 
02015   char *ptr = PR_smprintf("%u", (PRUint32) f);
02016   if (!ptr)
02017     return NS_ERROR_OUT_OF_MEMORY;
02018   nsAutoString value;
02019   CopyASCIItoUCS2(nsDependentCString(ptr), value);
02020   PR_smprintf_free(ptr);
02021   return EncodeSimpleValue(aEncoding, value,
02022                            aNamespaceURI, aName, aSchemaType, aDestination,
02023                            aReturnValue);
02024 }
02025 
02026 NS_IMETHODIMP
02027 nsDefaultEncoder::Decode(nsISOAPEncoding* aEncoding,
02028                          nsIDOMElement* aSource,
02029                          nsISchemaType* aSchemaType,
02030                          nsISOAPAttachments* aAttachments,
02031                          nsIVariant** aResult)
02032 {
02033   NS_ENSURE_ARG_POINTER(aEncoding);
02034   NS_ENSURE_ARG_POINTER(aSource);
02035   NS_ENSURE_ARG_POINTER(aResult);
02036   *aResult = nsnull;
02037   nsCOMPtr<nsISOAPEncoding> encoding = aEncoding;        //  First, handle encoding redesignation, if any
02038   nsCOMPtr<nsISchemaType> schemaType;
02039   nsresult rv = GetExplicitType(aEncoding, aSource, getter_AddRefs(schemaType));
02040   
02041   if (NS_FAILED(rv) || !schemaType) {
02042     schemaType = aSchemaType;
02043   }
02044 
02045   {
02046     nsCOMPtr<nsIDOMAttr> enc;
02047     nsresult rv =
02048       aSource->
02049       GetAttributeNodeNS(*gSOAPStrings->kSOAPEnvURI[mSOAPVersion],
02050                          gSOAPStrings->kEncodingStyleAttribute,
02051                          getter_AddRefs(enc));
02052     NS_ENSURE_SUCCESS(rv, rv);
02053 
02054     if (enc) {
02055       nsAutoString oldstyle;
02056       rv = encoding->GetStyleURI(oldstyle);
02057       NS_ENSURE_SUCCESS(rv, rv);
02058 
02059       nsAutoString style;
02060       rv = enc->GetNodeValue(style);
02061       NS_ENSURE_SUCCESS(rv, rv);
02062 
02063       if (!style.Equals(oldstyle)) {
02064         nsCOMPtr<nsISOAPEncoding> newencoding;
02065         rv = encoding->GetAssociatedEncoding(style, PR_FALSE,
02066                                              getter_AddRefs(newencoding));
02067         NS_ENSURE_SUCCESS(rv, rv);
02068 
02069         if (newencoding) {
02070           return newencoding->Decode(aSource, aSchemaType, aAttachments, aResult);
02071         }
02072       }
02073     }
02074   }
02075 
02076   // Handle xsi:null="true|1" and xsi:nil="true|1"
02077 
02078   nsAutoString nullstr;
02079   if (nsSOAPUtils::GetAttribute(aEncoding, 
02080                                 aSource, 
02081                                 gSOAPStrings->kXSIURI, 
02082                                 gSOAPStrings->kNull, 
02083                                 nullstr) ||
02084       nsSOAPUtils::GetAttribute(aEncoding, 
02085                                    aSource,
02086                                    gSOAPStrings->kXSIURI,
02087                                    gSOAPStrings->kNil,
02088                                    nullstr)) {
02089     
02090     return HandleNull(aEncoding,
02091                       aSource,
02092                       schemaType,
02093                       aAttachments,
02094                       nullstr,
02095                       aResult);
02096 
02097   }
02098 
02099   nsCOMPtr<nsISchemaType> type = schemaType;
02100   nsCOMPtr<nsISOAPDecoder> decoder;  //  All that comes out of this block is decoder, type, and some checks.
02101   {                        //  Look up type element and schema attribute, if possible
02102     nsCOMPtr<nsISchemaType> subType;
02103     nsCOMPtr<nsISchemaCollection> collection;
02104     nsresult rc =
02105       aEncoding->GetSchemaCollection(getter_AddRefs(collection));
02106     NS_ENSURE_SUCCESS(rc, rc);
02107 
02108     nsAutoString ns;
02109     nsAutoString name;
02110 
02111     rc = aSource->GetNamespaceURI(name);
02112     NS_ENSURE_SUCCESS(rc, rc);
02113 
02114     rc = aEncoding->GetInternalSchemaURI(name, ns);
02115     NS_ENSURE_SUCCESS(rc, rc);
02116 
02117     rc = aSource->GetLocalName(name);
02118     NS_ENSURE_SUCCESS(rc, rc);
02119 
02120     nsCOMPtr<nsISchemaElement> element;
02121     rc = collection->GetElement(name, ns, getter_AddRefs(element));
02122     //      if (NS_FAILED(rc)) return rc;
02123     if (element) {
02124       rc = element->GetType(getter_AddRefs(subType));
02125       NS_ENSURE_SUCCESS(rc, rc);
02126     } else {
02127       nsAutoString internal;
02128       rc = aEncoding->GetInternalSchemaURI(ns, internal);
02129       NS_ENSURE_SUCCESS(rc, rc);
02130 
02131       if (internal.Equals(gSOAPStrings->kSOAPEncURI)) {        //  Last-ditch hack to get undeclared types from SOAP namespace
02132         if (name.Equals(gSOAPStrings->kArraySOAPType) ||
02133             name.Equals(gSOAPStrings->kStructSOAPType)) {        //  This should not be needed if schema has these declarations
02134           rc = collection->GetType(name, internal, getter_AddRefs(subType));
02135         } else {
02136           rc = collection->GetType(name,
02137                                    gSOAPStrings->kXSURI,
02138                                    getter_AddRefs(subType));
02139         }
02140       }
02141       //        if (NS_FAILED(rc)) return rc;
02142     }
02143     if (!subType)
02144       subType = type;
02145 
02146     nsCOMPtr<nsISchemaType> subsubType;
02147     nsAutoString explicitType;
02148     if (nsSOAPUtils::GetAttribute(aEncoding, aSource, gSOAPStrings->kXSIURI,
02149                                   gSOAPStrings->kXSITypeAttribute,
02150                                   explicitType)) {
02151       rc = nsSOAPUtils::GetNamespaceURI(aEncoding, aSource, explicitType, ns);
02152       NS_ENSURE_SUCCESS(rc, rc);
02153 
02154       rc = nsSOAPUtils::GetLocalName(explicitType, name);
02155       NS_ENSURE_SUCCESS(rc, rc);
02156 
02157       rc = collection->GetType(name, ns, getter_AddRefs(subsubType));
02158       //      if (NS_FAILED(rc)) return rc;
02159     }
02160     if (!subsubType)
02161       subsubType = subType;
02162   
02163     if (subsubType) {  //  Loop up the hierarchy, to check and look for decoders
02164       for(;;) {
02165         nsCOMPtr<nsISchemaType> lookupType = subsubType;
02166         do {
02167           if (lookupType == subType) {  //  Tick off the located super classes
02168             subType = nsnull;
02169           }
02170           if (lookupType == type) {  //  Tick off the located super classes
02171             type = nsnull;
02172           }
02173           if (!decoder) {
02174             nsAutoString schemaType;
02175             nsAutoString schemaURI;
02176             nsresult rc = lookupType->GetName(schemaType);
02177             NS_ENSURE_SUCCESS(rc, rc);
02178 
02179             rc = lookupType->GetTargetNamespace(schemaURI);
02180             NS_ENSURE_SUCCESS(rc, rc);
02181 
02182             nsAutoString encodingKey;
02183             SOAPEncodingKey(schemaURI, schemaType, encodingKey);
02184             rc = aEncoding->GetDecoder(encodingKey, getter_AddRefs(decoder));
02185             NS_ENSURE_SUCCESS(rc, rc);
02186           }
02187           nsCOMPtr<nsISchemaType> supertype;
02188           rc = GetSupertype(aEncoding, lookupType, getter_AddRefs(supertype));
02189           NS_ENSURE_SUCCESS(rc, rc);
02190 
02191           lookupType = supertype;
02192         } while (lookupType);
02193         if (!type) {
02194           type = subsubType;
02195           break;
02196         }
02197         decoder = nsnull;
02198         if (!subType) {
02199           subType = type;
02200         }
02201         subsubType = subType;
02202       }
02203     }
02204   }
02205   if (!decoder) {
02206     PRBool simple = PR_TRUE;
02207     if (type) {
02208       nsresult rc = HasSimpleValue(type, &simple);
02209       NS_ENSURE_SUCCESS(rc, rc);
02210     }
02211     if (simple) {
02212       nsCOMPtr<nsIDOMElement> child;
02213       nsSOAPUtils::GetFirstChildElement(aSource, getter_AddRefs(child));
02214       simple = !child;
02215     }
02216     nsAutoString decodingKey;
02217     if (!simple) {
02218       SOAPEncodingKey(gSOAPStrings->kSOAPEncURI,
02219                       gSOAPStrings->kStructSOAPType, decodingKey);
02220     } else {
02221       SOAPEncodingKey(gSOAPStrings->kXSURI,
02222                       gSOAPStrings->kAnySimpleTypeSchemaType, decodingKey);
02223     }
02224     nsresult rc =
02225       aEncoding->GetDecoder(decodingKey, getter_AddRefs(decoder));
02226     NS_ENSURE_SUCCESS(rc, rc);
02227   }
02228   if (decoder) {
02229     return decoder->Decode(aEncoding, aSource, type, aAttachments,
02230                            aResult);
02231   }
02232 
02233   return SOAP_EXCEPTION(NS_ERROR_NOT_IMPLEMENTED,
02234                         "SOAP_NO_DECODER_FOR_TYPE",
02235                         "The default decoder finds no decoder for specific type");
02236 }
02237 
02238 NS_IMETHODIMP
02239 nsAnyTypeEncoder::Decode(nsISOAPEncoding * aEncoding,
02240                          nsIDOMElement * aSource,
02241                          nsISchemaType * aSchemaType,
02242                          nsISOAPAttachments * aAttachments,
02243                          nsIVariant ** _retval)
02244 {
02245   NS_ENSURE_ARG_POINTER(aEncoding);
02246   NS_ENSURE_ARG_POINTER(aSource);
02247   NS_ENSURE_ARG_POINTER(_retval);
02248   *_retval = nsnull;
02249   PRBool simple = PR_TRUE;
02250   if (aSchemaType) {
02251     nsresult rc = HasSimpleValue(aSchemaType, &simple);
02252     NS_ENSURE_SUCCESS(rc, rc);
02253   }
02254   if (simple) {
02255     nsCOMPtr<nsIDOMElement> child;
02256     nsSOAPUtils::GetFirstChildElement(aSource, getter_AddRefs(child));
02257     simple = !child;
02258   }
02259   nsAutoString decodingKey;
02260   if (!simple) {
02261     SOAPEncodingKey(gSOAPStrings->kSOAPEncURI,
02262                     gSOAPStrings->kStructSOAPType, decodingKey);
02263   } else {
02264     SOAPEncodingKey(gSOAPStrings->kXSURI,
02265                     gSOAPStrings->kAnySimpleTypeSchemaType, decodingKey);
02266   }
02267   nsCOMPtr<nsISOAPDecoder> decoder;
02268   nsresult rc =
02269     aEncoding->GetDecoder(decodingKey, getter_AddRefs(decoder));
02270   NS_ENSURE_SUCCESS(rc, rc);
02271 
02272   if (decoder) {
02273     return decoder->Decode(aEncoding, aSource,
02274                            aSchemaType, aAttachments, _retval);
02275     return rc;
02276   }
02277   return SOAP_EXCEPTION(NS_ERROR_NOT_IMPLEMENTED,"SOAP_NO_DECODER_FOR_TYPE","The any type decoder finds no decoder for specific element");
02278 }
02279 
02291 static nsresult DecodeStructParticle(nsISOAPEncoding* aEncoding, 
02292                                      nsIDOMElement* aElement, 
02293                                      nsISchemaParticle* aParticle, 
02294                                      nsISOAPAttachments * aAttachments, 
02295                                      nsISOAPPropertyBagMutator* aDestination,
02296                                      nsIDOMElement** aResult)
02297 {
02298   nsresult rc;
02299   *aResult = nsnull;
02300   if (aParticle) {
02301     PRUint32 minOccurs;
02302     rc = aParticle->GetMinOccurs(&minOccurs);
02303     NS_ENSURE_SUCCESS(rc, rc);
02304 
02305     PRUint32 maxOccurs;
02306     rc = aParticle->GetMaxOccurs(&maxOccurs);
02307     NS_ENSURE_SUCCESS(rc, rc);
02308 
02309     PRUint16 particleType;
02310     rc = aParticle->GetParticleType(&particleType);
02311     NS_ENSURE_SUCCESS(rc, rc);
02312 
02313     switch(particleType) {
02314     case nsISchemaParticle::PARTICLE_TYPE_ELEMENT: {
02315       if (maxOccurs > 1) {  //  Todo: Try to make this thing work as an array?
02316         return NS_ERROR_NOT_AVAILABLE; //  For now, we just try something else if we can (recoverable)
02317       }
02318       nsCOMPtr<nsISchemaElement> element = do_QueryInterface(aParticle);
02319       nsAutoString name;
02320       rc = element->GetTargetNamespace(name);
02321       NS_ENSURE_SUCCESS(rc, rc);
02322 
02323       if (!name.IsEmpty()) {
02324         rc = NS_ERROR_NOT_AVAILABLE; //  No known way to use namespace qualification in struct
02325       }
02326       else {
02327         rc = element->GetName(name);
02328         NS_ENSURE_SUCCESS(rc, rc);
02329 
02330         nsAutoString ename;
02331         if (aElement) {                //  Permits aElement to be null and fail recoverably
02332           nsAutoString temp;
02333           rc = aElement->GetNamespaceURI(ename);
02334           NS_ENSURE_SUCCESS(rc, rc);
02335 
02336           if (ename.IsEmpty()) {  //  Only get an ename if there is an empty namespaceURI
02337             rc = aElement->GetLocalName(ename);
02338             NS_ENSURE_SUCCESS(rc, rc);
02339           }
02340         }
02341         if (!ename.Equals(name))
02342           rc = NS_ERROR_NOT_AVAILABLE; //  The element must be a declaration of the next element
02343       }
02344       if (NS_SUCCEEDED(rc)) {
02345         nsCOMPtr<nsISchemaType> type;
02346         rc = element->GetType(getter_AddRefs(type));
02347         NS_ENSURE_SUCCESS(rc, rc);
02348 
02349         nsCOMPtr<nsIVariant> value;
02350         rc = aEncoding->Decode(aElement, type, aAttachments, getter_AddRefs(value));
02351         NS_ENSURE_SUCCESS(rc, rc);
02352 
02353         if (!value) {
02354           nsCOMPtr<nsIWritableVariant> nullVariant(do_CreateInstance("@mozilla.org/variant;1"));
02355           if (nullVariant) {
02356             nullVariant->SetAsISupports(nsnull);
02357             value = do_QueryInterface(nullVariant);
02358           }
02359         }
02360         rc = aDestination->AddProperty(name, value);
02361         NS_ENSURE_SUCCESS(rc, rc);
02362 
02363         nsSOAPUtils::GetNextSiblingElement(aElement, aResult);
02364       }
02365       if (minOccurs == 0 && rc == NS_ERROR_NOT_AVAILABLE) { //  If we failed recoverably, but we were permitted to, then return success
02366         NS_IF_ADDREF(*aResult = aElement);
02367         rc = NS_OK;
02368       }
02369       return rc;
02370     }
02371     case nsISchemaParticle::PARTICLE_TYPE_MODEL_GROUP: 
02372       {
02373         if (maxOccurs > 1) {  //  Todo: Try to make this thing work as an array?
02374           return NS_ERROR_NOT_AVAILABLE; //  For now, we just try something else if we can (recoverable)
02375         }
02376         nsCOMPtr<nsISchemaModelGroup> modelGroup = do_QueryInterface(aParticle);
02377         PRUint16 compositor;
02378         rc = modelGroup->GetCompositor(&compositor);
02379         NS_ENSURE_SUCCESS(rc, rc);
02380 
02381         PRUint32 particleCount;
02382         rc = modelGroup->GetParticleCount(&particleCount);
02383         NS_ENSURE_SUCCESS(rc, rc);
02384 
02385         PRUint32 i;
02386         if (compositor == nsISchemaModelGroup::COMPOSITOR_ALL) {  //  This handles out-of-order appearances.
02387           // Use hashtable to be able to get corresponding particle
02388           // according SOAP element name not according schema order 
02389           // as a <all> model group is used
02390           nsInterfaceHashtable<nsStringHashKey,nsISchemaParticle> groupParticles;
02391           groupParticles.Init(particleCount);
02392           nsCOMPtr<nsISchemaParticle> child;
02393           PRBool mangled = PR_FALSE;
02394 
02395           // Build schema particle mappings from model group
02396           for (i = 0; i < particleCount; i++) {
02397             rc = modelGroup->GetParticle(i, getter_AddRefs(child));
02398             NS_ENSURE_SUCCESS(rc, rc);
02399 
02400             nsAutoString particleName;
02401             rc = child->GetName(particleName);
02402             NS_ENSURE_SUCCESS(rc, rc);
02403 
02404             rc = groupParticles.Put(particleName, child);
02405             NS_ENSURE_SUCCESS(rc, rc);
02406           }
02407 
02408           nsCOMPtr<nsIDOMElement> next = aElement;
02409           PRBool decoded;
02410 
02411           /*
02412              Since we are an xsd:all, the order of elements in the schema type
02413              does not matter.  So we go element by element in the XML fragment
02414              we are decoding.  We loop through all schema particles defined for
02415              this type until we find one that DecodeStructParticle succeeds on.
02416              DecodeStructParticle returns |after| with is what is left to decode,
02417              so we can figure if the decoding succeeded by checking if |after|
02418              is not equal to the element we are decoding (|next|).
02419 
02420              We track if we couldn't decode using the |decoded| boolean.  If we
02421              exit the particle walking for loop and |decoded| is false, we bail.
02422 
02423              XXX: what if we get out of the while loop, and |all| still has
02424              particles?  Should we walk them and see if any are minOccurs > 0
02425              and return an error?
02426            */
02427 
02428           // loop as long as we have something to decode. 
02429           while (next) {
02430             decoded = PR_FALSE;
02431 
02432             // we cycle through the schema particles
02433             for (i = 0; i < particleCount; i++) {
02434               nsAutoString name;
02435               rc = next->GetTagName(name);
02436               NS_ENSURE_SUCCESS(rc, rc);
02437 
02438               // Get schema particle according SOAP element
02439               groupParticles.Get(name, getter_AddRefs(child));
02440 
02441               if (NS_FAILED(rc) || !child) {
02442 #ifdef DEBUG
02443                 nsAutoString msg(NS_LITERAL_STRING("::DecodeStructParticle: "));
02444                 msg.AppendLiteral("Cannot find schema particle for \"");
02445                 msg.Append(name);
02446                 msg.AppendLiteral("\"");
02447                 NS_ERROR(NS_ConvertUTF16toUTF8(msg).get());
02448 #endif
02449               }
02450 
02451               nsCOMPtr<nsIDOMElement> after;
02452               rc = DecodeStructParticle(aEncoding, next, child, aAttachments, aDestination, getter_AddRefs(after));
02453 
02454               // DecodeStructParticle returns success even if decoding didn't
02455               // work.  So we check if after != next to see if it did succeed.
02456               if (NS_SUCCEEDED(rc) && after != next) {
02457                 decoded = PR_TRUE;
02458                 next = after;
02459                 mangled = PR_TRUE;
02460                 groupParticles.Remove(name);
02461                 particleCount--;
02462                 break;
02463               }
02464             }
02465 
02466             // This detects ambiguous model (non-deterministic choice which 
02467             // fails after succeeding on first)
02468             if ((mangled && rc == NS_ERROR_NOT_AVAILABLE) || !decoded) {
02469               rc = SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,"SOAP_AMBIGUOUS_DECODING","Cannot proceed due to ambiguity or error in content model");
02470               //  Error is not considered recoverable due to partially-created output.
02471             }
02472 
02473             // if we failed to decode after the for loop, abort.
02474             if (NS_FAILED(rc) || !decoded)
02475               break;
02476           }
02477 
02478           // if *aResult is not null, then caller knows we couldn't decode
02479           // everything.
02480           if (NS_SUCCEEDED(rc)) {
02481             NS_IF_ADDREF(*aResult = next);
02482           } else if (minOccurs == 0 && rc == NS_ERROR_NOT_AVAILABLE) {
02483             // If we succeeded or failed recoverably, but we were permitted to,
02484             // then return success
02485             NS_IF_ADDREF(*aResult = aElement);
02486             rc = NS_OK;
02487           }
02488         }
02489         else {  //  This handles sequences and choices.
02490           nsCOMPtr<nsIDOMElement> next = aElement;
02491           for (i = 0; i < particleCount; i++) {
02492             nsCOMPtr<nsISchemaParticle> child;
02493             rc = modelGroup->GetParticle(i, getter_AddRefs(child));
02494             NS_ENSURE_SUCCESS(rc, rc);
02495 
02496             nsCOMPtr<nsIDOMElement> after;
02497             rc = DecodeStructParticle(aEncoding, next, child, aAttachments, aDestination, getter_AddRefs(after));
02498             if (NS_SUCCEEDED(rc)) {
02499               next = after;
02500             }
02501             if (compositor == nsISchemaModelGroup::COMPOSITOR_CHOICE) {
02502               if (rc == NS_ERROR_NOT_AVAILABLE) {
02503                 rc = NS_OK;
02504               }
02505               else {
02506                 if (NS_SUCCEEDED(rc)) {
02507                   NS_IF_ADDREF(*aResult = next);
02508                 }
02509                 return rc;
02510               }
02511             }
02512             else if (i > 0 && rc == NS_ERROR_NOT_AVAILABLE) {  //  This detects ambiguous model (non-deterministic choice which fails after succeeding on first)
02513               rc = SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,"SOAP_AMBIGUOUS_DECODING","Cannot proceed due to ambiguity or error in content model");
02514               //  Error is not considered recoverable due to partially-created output.
02515             }
02516             if (NS_FAILED(rc))
02517               break;
02518           }
02519           if (compositor == nsISchemaModelGroup::COMPOSITOR_CHOICE)
02520             rc = NS_ERROR_NOT_AVAILABLE;
02521           if (NS_SUCCEEDED(rc)) {
02522             NS_IF_ADDREF(*aResult = next);
02523           }
02524           if (minOccurs == 0 && rc == NS_ERROR_NOT_AVAILABLE) {  //  If we succeeded or failed recoverably, but we were permitted to, then return success
02525             NS_IF_ADDREF(*aResult = aElement);
02526             rc = NS_OK;
02527           }
02528         }
02529         return rc;                    //  Return status
02530       }
02531     case nsISchemaParticle::PARTICLE_TYPE_ANY:
02532       //  No model available here (we may wish to handle strict versus lazy, but what does that mean with only local accessor names)
02533     default:
02534       break;
02535     }
02536   }
02537 
02538   nsCOMPtr<nsIDOMElement> child = aElement;
02539   while (child) {
02540     nsAutoString name;
02541     nsAutoString namespaceURI;
02542     nsCOMPtr<nsIVariant>value;
02543     rc = child->GetLocalName(name);
02544     NS_ENSURE_SUCCESS(rc, rc);
02545 
02546     rc = child->GetNamespaceURI(namespaceURI);
02547     NS_ENSURE_SUCCESS(rc, rc);
02548 
02549     if (!namespaceURI.IsEmpty()) {    //  If we ever figure out what to do with namespaces, get an internal one
02550       return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,
02551                             "SOAP_GLOBAL_ACCESSOR",
02552                             "Decoded struct contained global accessor, which does not map well into a property name.");
02553     }
02554     rc = aEncoding->Decode(child, nsnull, aAttachments, getter_AddRefs(value));
02555     NS_ENSURE_SUCCESS(rc, rc);
02556 
02557     if (!value) {
02558       nsCOMPtr<nsIWritableVariant> nullVariant(do_CreateInstance("@mozilla.org/variant;1"));
02559       if (nullVariant) {
02560         nullVariant->SetAsISupports(nsnull);
02561         value = do_QueryInterface(nullVariant);
02562       }
02563     }
02564     rc = aDestination->AddProperty(name, value);
02565     NS_ENSURE_SUCCESS(rc, rc);
02566 
02567     nsCOMPtr<nsIDOMElement> nextchild;
02568     nsSOAPUtils::GetNextSiblingElement(child, getter_AddRefs(nextchild));
02569     child = nextchild;
02570   }
02571   *aResult = nsnull;
02572   return NS_OK;
02573 }
02574 
02575 NS_IMETHODIMP
02576 nsStructEncoder::Decode(nsISOAPEncoding* aEncoding,
02577                         nsIDOMElement* aSource,
02578                         nsISchemaType* aSchemaType,
02579                         nsISOAPAttachments* aAttachments,
02580                         nsIVariant** aResult)
02581 {
02582   NS_ENSURE_ARG_POINTER(aEncoding);
02583   NS_ENSURE_ARG_POINTER(aSource);
02584   NS_ENSURE_ARG_POINTER(aResult);
02585   *aResult = nsnull;
02586   nsresult rc;
02587   nsCOMPtr<nsISOAPPropertyBagMutator> mutator = do_CreateInstance(NS_SOAPPROPERTYBAGMUTATOR_CONTRACTID, &rc);
02588   NS_ENSURE_SUCCESS(rc, rc);
02589 
02590   nsCOMPtr<nsISchemaModelGroup> modelGroup;
02591   if (aSchemaType) {
02592     nsCOMPtr<nsISchemaComplexType> ctype = do_QueryInterface(aSchemaType);
02593     if (ctype) {
02594       rc = ctype->GetModelGroup(getter_AddRefs(modelGroup));
02595       NS_ENSURE_SUCCESS(rc, rc);
02596     }
02597   }
02598   nsCOMPtr<nsIDOMElement> child;
02599   nsSOAPUtils::GetFirstChildElement(aSource, getter_AddRefs(child));
02600   nsCOMPtr<nsIDOMElement> result;
02601   rc =  DecodeStructParticle(aEncoding, child, modelGroup, aAttachments, mutator, getter_AddRefs(result));
02602   if (NS_SUCCEEDED(rc)  //  If there were elements left over, then we failed to decode everything.
02603       && result)
02604     rc = SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,"SOAP_LEFTOVERS","Decoded struct contained extra items not mentioned in the content model.");
02605   NS_ENSURE_SUCCESS(rc, rc);
02606 
02607   nsCOMPtr<nsIPropertyBag> bag;
02608   rc = mutator->GetPropertyBag(getter_AddRefs(bag));
02609   NS_ENSURE_SUCCESS(rc, rc);
02610 
02611   nsCOMPtr<nsIWritableVariant> p =
02612     do_CreateInstance(NS_VARIANT_CONTRACTID, &rc);
02613   NS_ENSURE_SUCCESS(rc, rc);
02614 
02615   rc = p->SetAsInterface(NS_GET_IID(nsIPropertyBag), bag);
02616   NS_ENSURE_SUCCESS(rc, rc);
02617 
02618   NS_ADDREF(*aResult = p);
02619   return NS_OK;
02620 }
02621 
02622 NS_IMETHODIMP
02623 nsAnySimpleTypeEncoder::Decode(nsISOAPEncoding* aEncoding,
02624                                nsIDOMElement* aSource,
02625                                nsISchemaType* aSchemaType,
02626                                nsISOAPAttachments* aAttachments,
02627                                nsIVariant** aResult)
02628 {
02629   NS_ENSURE_ARG_POINTER(aEncoding);
02630   NS_ENSURE_ARG_POINTER(aSource);
02631   NS_ENSURE_ARG_POINTER(aResult);
02632   *aResult = nsnull;
02633   nsAutoString value;
02634   nsresult rc = nsSOAPUtils::GetElementTextContent(aSource, value);
02635   NS_ENSURE_SUCCESS(rc, rc);
02636 
02637   nsCOMPtr<nsIWritableVariant> p =
02638     do_CreateInstance(NS_VARIANT_CONTRACTID, &rc);
02639   NS_ENSURE_SUCCESS(rc, rc);
02640 
02641   rc = p->SetAsAString(value);
02642   NS_ENSURE_SUCCESS(rc, rc);
02643 
02644   NS_ADDREF(*aResult = p);
02645   return NS_OK;
02646 }
02647 
02664 static PRUint32 DecodeArrayDimensions(const nsAString& src, PRInt32* aDimensionSizes, nsAString & dst)
02665 {
02666   dst.Assign(src);
02667   nsReadingIterator < PRUnichar > i1;
02668   nsReadingIterator < PRUnichar > i2;
02669   src.BeginReading(i1);
02670   src.EndReading(i2);
02671   if (src.IsEmpty()) return 0;
02672   while (i1 != i2      //  Loop past white space
02673          && *(--i2) <= ' ') //  In XML, all valid characters <= space are the only whitespace
02674     ;
02675   if (*i2 != ']') {                  //  In this case, not an array dimension
02676     PRInt32 len = Distance(i1, i2) - 1;  //  This is the size to truncate to at the end.
02677     dst = Substring(src, 0, len);              //  Truncate the string.
02678     return 0;                       //  Eliminated white space.
02679   }
02680 
02681   PRInt32 dimensionCount = 1;    //  Counting the dimensions
02682   for (;;) {        //  First look for the matching bracket from reverse and commas.
02683     if (i1 == i2) {                  //  No matching bracket.
02684       return 0;
02685     }
02686     PRUnichar c = *(--i2);
02687     if (c == '[') {                  //  Matching bracket found!
02688       break;
02689     }
02690     if (c == ',') {
02691       dimensionCount++;
02692     }
02693   }
02694   PRInt32 len;
02695   {
02696     nsReadingIterator < PRUnichar > i3 = i2++;  //  Cover any extra white space
02697     while (i1 != i3) {      //  Loop past white space
02698       if (*(--i3) > ' ') { //  In XML, all valid characters <= space are the only whitespace
02699         i3++;
02700         break;
02701       }
02702     }
02703     len = Distance(i1, i3);        //  Length remaining in string after operation
02704   }
02705 
02706   if (dimensionCount > MAX_ARRAY_DIMENSIONS) {  //  Completely ignore it if too many dimensions.
02707     return 0;
02708   }
02709 
02710   i1 = i2;
02711   src.EndReading(i2);
02712   while (*(--i2) != ']')           //  Find end bracket again
02713     ;
02714 
02715   dimensionCount = 0;                           //  Start with first dimension.
02716   aDimensionSizes[dimensionCount] = -1;
02717   PRBool finished = PR_FALSE;      //  Disallow space within numbers
02718 
02719   while (i1 != i2) {
02720     PRUnichar c = *(i1++);
02721     if (c < '0' || c > '9') {
02722       //  There may be slightly more to do here if alternative radixes are supported.
02723       if (c <= ' ') {              //  In XML, all valid characters <= space are the only whitespace
02724         if (aDimensionSizes[dimensionCount] >= 0) {
02725           finished = PR_TRUE;
02726         }
02727       }
02728       else if (c == ',') {         //  Introducing new dimension
02729         aDimensionSizes[++dimensionCount] = -1;             //  Restarting it at -1
02730         finished = PR_FALSE;
02731       }
02732       else
02733         return 0;                 //  Unrecognized character
02734     } else {
02735       if (finished) {
02736         return 0;                 //  Numbers not allowed after white space
02737       }
02738       if (aDimensionSizes[dimensionCount] == -1)
02739         aDimensionSizes[dimensionCount] = 0;
02740       if (aDimensionSizes[dimensionCount] < 214748364) {
02741         aDimensionSizes[dimensionCount] = aDimensionSizes[dimensionCount] * 10 + c - '0';
02742       }
02743       else {
02744         return 0;                 //  Number got too big.
02745       }
02746     }
02747   }
02748   dst = Substring(src, 0, len);              //  Truncate the string.
02749   return dimensionCount + 1;                    //  Return the number of dimensions
02750 }
02751 
02765 static PRInt32 DecodeArrayPosition(const nsAString& src, PRUint32 aDimensionCount, PRInt32* aDimensionSizes)
02766 {
02767   PRInt32 pos[MAX_ARRAY_DIMENSIONS];
02768   nsAutoString leftover;
02769   PRUint32 i = DecodeArrayDimensions(src, pos, leftover);
02770   if (i != aDimensionCount || !leftover.IsEmpty()) {
02771     // Easy cases where something went wrong
02772     return -1;
02773   }
02774   PRInt32 result = 0;
02775   for (i = 0;;) {
02776     PRInt32 next = pos[i];
02777     if (next == -1 || next >= aDimensionSizes[i])
02778       return -1;
02779     result = result + next;
02780     if (++i < aDimensionCount)                 //  Multiply for next round.
02781       result = result * aDimensionSizes[i];
02782     else
02783       break;
02784   }
02785   return result;
02786 }
02787 
02796 static nsresult CreateArray(nsIWritableVariant* aResult, PRUint16 aType, const nsIID* aIID, 
02797                             PRUint32 aDimensionCount, PRInt32* aDimensionSizes, PRUint32 aSizeof, PRUint8* aArray)
02798 {
02799   if (aSizeof == 0) {  //  Variants do not support construction of null-sized arrays
02800     return aResult->SetAsEmptyArray();
02801   }
02802   if (aDimensionCount > 1) {                  //  We cannot reuse variants because they are kept by resulting array
02803     PRInt32 count = aDimensionSizes[0];
02804     PRUint32 size = aSizeof / count;
02805     PRInt32 i;
02806     nsIVariant** a = new nsIVariant*[count];  //  Create variant array.
02807     if (!a)
02808       return NS_ERROR_OUT_OF_MEMORY;
02809 
02810     nsresult rc = NS_OK;
02811 
02812     for (i = 0; i < count; i++) {
02813       nsCOMPtr<nsIWritableVariant> v = do_CreateInstance(NS_VARIANT_CONTRACTID, &rc);
02814       if (NS_FAILED(rc))
02815         break;
02816       nsresult rc = CreateArray(v, aType, aIID, aDimensionCount - 1, aDimensionSizes + 1,
02817                                 size, aArray);
02818       if (NS_FAILED(rc))
02819         break;
02820       NS_ADDREF(a[i] = v);                       //  Addref for array reference
02821       aArray += size;
02822     }
02823     if (NS_SUCCEEDED(rc)) {
02824       rc = aResult->SetAsArray(nsIDataType::VTYPE_INTERFACE_IS,&NS_GET_IID(nsIVariant),count,a);
02825     }
02826     for (i = 0; i < count; i++) {            //  Release variants for array
02827       nsIVariant* v = a[i];
02828       if (v)
02829         NS_RELEASE(v);
02830     }
02831     delete[] a;
02832     return rc;
02833   }
02834   else {
02835     return aResult->SetAsArray(aType,aIID,aDimensionSizes[0],aArray);
02836   }
02837 }
02838 
02839 //  Incomplete -- becomes very complex due to variant arrays
02840 NS_IMETHODIMP
02841 nsArrayEncoder::Decode(nsISOAPEncoding* aEncoding,
02842                        nsIDOMElement* aSource,
02843                        nsISchemaType* aSchemaType,
02844                        nsISOAPAttachments* aAttachments,
02845                        nsIVariant** aResult)
02846 {
02847   NS_ENSURE_ARG_POINTER(aEncoding);
02848   NS_ENSURE_ARG_POINTER(aSource);
02849   NS_ENSURE_ARG_POINTER(aResult);
02850   *aResult = nsnull;
02851   nsAutoString ns;
02852   nsAutoString name;
02853   nsCOMPtr<nsISchemaType> schemaArrayType;
02854   nsAutoString value;
02855   PRUint32 dimensionCount = 0;                  //  Number of dimensions
02856   PRInt32 dimensionSizes[MAX_ARRAY_DIMENSIONS];
02857   PRInt32 size = -1;
02858   nsresult rc;
02859   PRUint32 i;
02860   if (aSchemaType) {
02861     PRUint16 type;
02862     nsresult rc = aSchemaType->GetSchemaType(&type);
02863     NS_ENSURE_SUCCESS(rc, rc);
02864 
02865     if (type == nsISchemaType::SCHEMA_TYPE_COMPLEX) {
02866       nsCOMPtr<nsISchemaComplexType> ct = do_QueryInterface(aSchemaType);
02867       nsresult rc = ct->GetArrayDimension(&dimensionCount);
02868       NS_ENSURE_SUCCESS(rc, rc);
02869 
02870       rc = ct->GetArrayType(getter_AddRefs(schemaArrayType));
02871       NS_ENSURE_SUCCESS(rc, rc);
02872     }
02873   }
02874   if (nsSOAPUtils::GetAttribute(aEncoding, aSource, gSOAPStrings->kSOAPEncURI,
02875                                 gSOAPStrings->kSOAPArrayTypeAttribute, value)) {
02876     nsAutoString dst;
02877     PRUint32 n = DecodeArrayDimensions(value, dimensionSizes, dst);
02878     if (n > 0) {
02879       if (dimensionCount == n || dimensionCount == 0) {
02880         dimensionCount = n;
02881       }
02882       else {
02883         return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,
02884                               "SOAP_WRONG_ARRAY_SIZE",
02885                               "Array declares different number of dimensions from what schema declared.");
02886         //  We cannot get conflicting information from schema and content.
02887       }
02888     }
02889     value.Assign(dst);
02890 
02891     if (dimensionCount > 0) {
02892       PRInt64 tot = 1;  //  Collect in 64 bits, just to make sure it fits
02893       for (i = 0; i < dimensionCount; i++) {
02894         PRInt32 next = dimensionSizes[i];
02895         if (next == -1) {
02896           tot = -1;
02897           break;
02898         }
02899         tot = tot * next;
02900         if (tot > 0x7fffffff) {
02901           return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,
02902                                 "SOAP_ARRAY_TOO_BIG",
02903                                 "When decoding an object as an array, the total count of items exceeded maximum.");
02904         }
02905       }
02906       size = (PRInt32)tot;
02907     }
02908     else {
02909       return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,
02910                             "SOAP_ARRAY_UNDECLARED",
02911                             "Array type did not end with proper array dimensions.");
02912       //  A dimension count must be part of the arrayType
02913     }
02914 
02915     //  The array type is either array if ']' or other specific type.
02916     nsCOMPtr<nsISchemaCollection> collection;
02917     rc = aEncoding->GetSchemaCollection(getter_AddRefs(collection));
02918     NS_ENSURE_SUCCESS(rc, rc);
02919 
02920     if (value.Last() ==']') {
02921       ns.Assign(gSOAPStrings->kSOAPEncURI);
02922       name.Assign(gSOAPStrings->kArraySOAPType);
02923     }
02924     else {
02925       rc = nsSOAPUtils::GetNamespaceURI(aEncoding, aSource, value, ns);
02926       NS_ENSURE_SUCCESS(rc, rc);
02927 
02928       rc = nsSOAPUtils::GetLocalName(value, name);
02929       NS_ENSURE_SUCCESS(rc, rc);
02930     }
02931     nsCOMPtr<nsISchemaType> subtype;
02932     rc = collection->GetType(name, ns, getter_AddRefs(subtype));
02933     //      if (NS_FAILED(rc)) return rc;
02934     if (!subtype)
02935       subtype = schemaArrayType;
02936   
02937     if (subtype) {  //  Loop up the hierarchy, to ensure suitability of subtype
02938       if (schemaArrayType) {
02939         nsCOMPtr<nsISchemaType> lookupType = subtype;
02940         do {
02941           if (lookupType == schemaArrayType) {  //  Tick off the located super classes
02942             schemaArrayType = nsnull;
02943             break;
02944           }
02945           nsCOMPtr<nsISchemaType> supertype;
02946           rc = GetSupertype(aEncoding, lookupType, getter_AddRefs(supertype));
02947           NS_ENSURE_SUCCESS(rc, rc);
02948 
02949           lookupType = supertype;
02950         } while (lookupType);
02951       }
02952       if (schemaArrayType)  //  If the proper subclass relationship didn't exist, then error return.
02953         return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,
02954                               "SOAP_ARRAY_TYPE",
02955                               "The type of the array must be a subclass of the declared type.");
02956       schemaArrayType = subtype;    //  If they did, then we now have a new, better type.
02957     }
02958   }
02959   PRUint32 offset;           //  Computing offset trickier, because size may be unspecified.
02960   if (nsSOAPUtils::GetAttribute(aEncoding, aSource, gSOAPStrings->kSOAPEncURI,
02961                                 gSOAPStrings->kSOAPArrayOffsetAttribute, value)) {
02962     PRInt32 pos[MAX_ARRAY_DIMENSIONS];
02963     nsAutoString leftover;
02964     offset = DecodeArrayDimensions(value, pos, leftover);
02965     if (dimensionCount == 0)
02966       dimensionCount = offset;
02967     if (offset == 0 || 
02968         offset != dimensionCount || 
02969         !leftover.IsEmpty()) {
02970       // We have to understand this or report an error
02971       // But the offset does not need to be understood
02972       return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,
02973                             "SOAP_ARRAY_OFFSET",
02974                             "Illegal value given for array offset");
02975     }
02976     PRInt32 old0 = dimensionSizes[0];
02977     if (dimensionSizes[0] == -1) {
02978       // It is OK to have a offset where dimension 0 is unspecified
02979       dimensionSizes[0] = 2147483647;
02980     }
02981     offset  = 0;
02982     for (i = 0;;) {
02983       PRInt64 next = pos[i];
02984       if (next == -1 || next >= dimensionSizes[i]) {
02985         rc = NS_ERROR_ILLEGAL_VALUE;
02986         break;
02987       }
02988       next = (offset + next);
02989       if (next > 2147483647) {
02990         rc = NS_ERROR_ILLEGAL_VALUE;
02991         break;
02992       }
02993       offset = (PRInt32)next;
02994       if (++i < dimensionCount) {
02995         next = offset * dimensionSizes[i];
02996         if (next > 2147483647) {
02997           rc = NS_ERROR_ILLEGAL_VALUE;
02998           break;
02999         }
03000         offset = (PRInt32)next;
03001       }
03002       else {
03003         rc = NS_OK;
03004         break;
03005       }
03006     }
03007     if (NS_FAILED(rc))
03008       return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,
03009                             "SOAP_ARRAY_OFFSET",
03010                             "Illegal value given for array offset");
03011     dimensionSizes[0] = old0;
03012   }
03013   else {
03014     offset = 0;
03015   }
03016   if (size == -1) {  //  If no known size, we have to go through and pre-count.
03017     nsCOMPtr<nsIDOMElement> child;
03018     nsSOAPUtils::GetFirstChildElement(aSource, getter_AddRefs(child));
03019     PRInt32 pp[MAX_ARRAY_DIMENSIONS];
03020     if (dimensionCount != 0) {
03021       for (i = dimensionCount; i-- != 0;) {
03022         pp[i] = 0;
03023       }
03024     }
03025     size = 0;
03026     PRInt32 next = offset;
03027     while (child) {
03028       nsAutoString pos;
03029       if (nsSOAPUtils::GetAttribute(aEncoding, aSource, gSOAPStrings->kSOAPEncURI,
03030                                     gSOAPStrings->kSOAPArrayPositionAttribute, pos)) {
03031         // if array item contains an explicit 'position' attribute use it
03032         nsAutoString leftover;
03033         PRInt32 inc[MAX_ARRAY_DIMENSIONS];
03034         i = DecodeArrayDimensions(pos, inc, leftover);
03035         if (i == 0 || 
03036             !leftover.IsEmpty() || 
03037             (dimensionCount !=0 && dimensionCount != i)) {
03038           // We have to understand this or report an error
03039           return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,
03040                                 "SOAP_ARRAY_POSITION",
03041                                 "Illegal value given for array element position");
03042         }
03043         if (dimensionCount == 0) {
03044           dimensionCount = i;             //  If we never had dimension count before, we do now.
03045           for (i = dimensionCount; i-- != 0;) {
03046             pp[i] = 0;
03047           }
03048         }
03049         for (i = 0; i < dimensionCount; i++) {
03050           PRInt32 n = inc[i];
03051           if (n == -1) {  //  Positions must be concrete
03052             return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,
03053                                   "SOAP_ARRAY_POSITION",
03054                                   "Illegal value given for array element position");
03055           }
03056           if (n >= pp[i])
03057             pp[i] = n + 1;
03058         }
03059       }
03060       else {
03061         // No explicit 'position' attribute
03062         next++;            //  Keep tabs on how many unnumbered items there are
03063       }
03064 
03065       nsCOMPtr<nsIDOMElement> nextchild;
03066       nsSOAPUtils::GetNextSiblingElement(child, getter_AddRefs(nextchild));
03067       child = nextchild;
03068     }
03069     if (dimensionCount == 0) {         //  If unknown or 1 dimension, unpositioned entries can help
03070       dimensionCount = 1;
03071       pp[0] = next;
03072       dimensionSizes[0] = next;
03073     }
03074     else if (dimensionCount == 1
03075              && next > pp[0]) {
03076       pp[0] = next;
03077       dimensionSizes[0] = next;
03078     }
03079     PRInt64 tot = 1;  //  Collect in 64 bits, just to make sure it fits
03080     for (i = 0; i < dimensionCount; i++) {
03081       PRInt32 next = dimensionSizes[i];
03082       if (next == -1) {          //  Only derive those with no other declaration
03083         dimensionSizes[i] = next = pp[i];
03084       }
03085       tot = tot * next;
03086       if (tot > 0x7fffffff) {
03087         return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,
03088                               "SOAP_ARRAY_TOO_BIG",
03089                               "When decoding an object as an array, the total count of items exceeded maximum.");
03090       }
03091     }
03092     size = (PRInt32)tot;  //  At last, we know the dimensions of the array.
03093   }
03094 
03095   //  After considerable work, we may have a schema type and a size.
03096   
03097   nsCOMPtr<nsIWritableVariant> result = do_CreateInstance(NS_VARIANT_CONTRACTID, &rc);
03098   PRInt32 si;
03099 
03100 #define DECODE_ARRAY(XPType, VTYPE, iid, Convert, Free) \
03101   XPType* a = new XPType[size];\
03102   if (!a)\
03103     return NS_ERROR_OUT_OF_MEMORY;\
03104   for (si = 0; si < size; si++) a[si] = 0;\
03105   nsCOMPtr<nsIDOMElement> child;\
03106   nsSOAPUtils::GetFirstChildElement(aSource, getter_AddRefs(child));\
03107   PRUint32 next = offset;\
03108   while (child) {\
03109     nsAutoString pos;\
03110     PRInt32 p;\
03111     if (nsSOAPUtils::GetAttribute(aEncoding, aSource, gSOAPStrings->kSOAPEncURI,\
03112                                   gSOAPStrings->kSOAPArrayPositionAttribute, pos)) {\
03113       p = DecodeArrayPosition(pos, dimensionCount, dimensionSizes);\
03114       if (p == -1) {\
03115         rc = NS_ERROR_ILLEGAL_VALUE;\
03116         break;\
03117       }\
03118     }\
03119     else {\
03120       p = next++;\
03121     }\
03122     if (p >= size || a[p]) {\
03123       rc = NS_ERROR_ILLEGAL_VALUE;\
03124       break;\
03125     }\
03126     nsCOMPtr<nsIVariant> v;\
03127  \
03128     rc = aEncoding->Decode(child, schemaArrayType, aAttachments, getter_AddRefs(v));\
03129     if (NS_FAILED(rc))\
03130       break;\
03131     Convert \
03132 \
03133       nsCOMPtr<nsIDOMElement> next;\
03134     nsSOAPUtils::GetNextSiblingElement(child, getter_AddRefs(next));\
03135     child = next;\
03136   }\
03137   if (NS_SUCCEEDED(rc)) {\
03138     rc = CreateArray(result, nsIDataType::VTYPE_##VTYPE,iid,dimensionCount,dimensionSizes,sizeof(a[0])*size,(PRUint8*)a);\
03139   }\
03140   Free\
03141     delete[] a;\
03142 
03143 #define DECODE_SIMPLE_ARRAY(XPType, VType, VTYPE)                       \
03144   DECODE_ARRAY(XPType, VTYPE, nsnull, rc = v->GetAs##VType(a + p);if(NS_FAILED(rc))break;,do{}while(0);)
03145 
03146   if (rc == NS_ERROR_ILLEGAL_VALUE)
03147     return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,
03148                           "SOAP_ARRAY_POSITIONS",
03149                           "Colliding array positions discovered.");
03150   NS_ENSURE_SUCCESS(rc, rc);
03151 
03152   PRBool unhandled = PR_FALSE;
03153   if (ns.Equals(gSOAPStrings->kXSURI)) {
03154     if (name.Equals(gSOAPStrings->kStringSchemaType)) {
03155       DECODE_ARRAY(PRUnichar*,WCHAR_STR,nsnull,rc = v->GetAsWString(a + p);if(NS_FAILED(rc))break;,
03156                    for (si = 0; si < size; si++) nsMemory::Free(a[si]););
03157     } else if (name.Equals(gSOAPStrings->kBooleanSchemaType)) {
03158       DECODE_SIMPLE_ARRAY(PRBool,Bool,BOOL);
03159     } else if (name.Equals(gSOAPStrings->kFloatSchemaType)) {
03160       DECODE_SIMPLE_ARRAY(float,Float,FLOAT);
03161     } else if (name.Equals(gSOAPStrings->kDoubleSchemaType)) {
03162       DECODE_SIMPLE_ARRAY(double,Double,DOUBLE);
03163     } else if (name.Equals(gSOAPStrings->kLongSchemaType)) {
03164       DECODE_SIMPLE_ARRAY(PRInt64,Int64,INT64);
03165     } else if (name.Equals(gSOAPStrings->kIntSchemaType)) {
03166       DECODE_SIMPLE_ARRAY(PRInt32,Int32,INT32);
03167     } else if (name.Equals(gSOAPStrings->kShortSchemaType)) {
03168       DECODE_SIMPLE_ARRAY(PRInt16,Int16,INT16);
03169     } else if (name.Equals(gSOAPStrings->kByteSchemaType)) {
03170       DECODE_SIMPLE_ARRAY(PRUint8,Int8,INT8);
03171     } else if (name.Equals(gSOAPStrings->kUnsignedLongSchemaType)) {
03172       DECODE_SIMPLE_ARRAY(PRUint64,Uint64,UINT64);
03173     } else if (name.Equals(gSOAPStrings->kUnsignedIntSchemaType)) {
03174       DECODE_SIMPLE_ARRAY(PRUint32,Uint32,UINT32);
03175     } else if (name.Equals(gSOAPStrings->kUnsignedShortSchemaType)) {
03176       DECODE_SIMPLE_ARRAY(PRUint16,Uint16,UINT16);
03177     } else if (name.Equals(gSOAPStrings->kUnsignedByteSchemaType)) {
03178       DECODE_SIMPLE_ARRAY(PRUint8,Uint8,UINT8);
03179     } else {
03180       unhandled = PR_TRUE;
03181     }
03182   } else {
03183     unhandled = PR_TRUE;
03184   }
03185   if (unhandled) {  //  Handle all the other cases
03186     DECODE_ARRAY(nsIVariant*,INTERFACE_IS,&NS_GET_IID(nsIVariant),
03187                  NS_ADDREF(a[p] = v);,
03188                  for (si = 0; si < size; si++) NS_IF_RELEASE(a[si]););
03189   }
03190   NS_ENSURE_SUCCESS(rc, rc);
03191 
03192   NS_ADDREF(*aResult = result);
03193   return NS_OK;
03194 }
03195 
03196 NS_IMETHODIMP
03197 nsStringEncoder::Decode(nsISOAPEncoding* aEncoding,
03198                         nsIDOMElement* aSource,
03199                         nsISchemaType* aSchemaType,
03200                         nsISOAPAttachments* aAttachments,
03201                         nsIVariant** aResult)
03202 {
03203   NS_ENSURE_ARG_POINTER(aEncoding);
03204   NS_ENSURE_ARG_POINTER(aSource);
03205   NS_ENSURE_ARG_POINTER(aResult);
03206   *aResult = nsnull;
03207   nsAutoString value;
03208   nsresult rc = nsSOAPUtils::GetElementTextContent(aSource, value);
03209   NS_ENSURE_SUCCESS(rc, rc);
03210 
03211   nsCOMPtr<nsIWritableVariant> p =
03212     do_CreateInstance(NS_VARIANT_CONTRACTID, &rc);
03213   NS_ENSURE_SUCCESS(rc, rc);
03214 
03215   rc = p->SetAsAString(value);
03216   NS_ENSURE_SUCCESS(rc, rc);
03217 
03218   NS_ADDREF(*aResult = p);
03219   return NS_OK;
03220 }
03221 
03222 NS_IMETHODIMP
03223 nsBooleanEncoder::Decode(nsISOAPEncoding* aEncoding,
03224                          nsIDOMElement* aSource,
03225                          nsISchemaType* aSchemaType,
03226                          nsISOAPAttachments* aAttachments,
03227                          nsIVariant** aResult)
03228 {
03229   NS_ENSURE_ARG_POINTER(aEncoding);
03230   NS_ENSURE_ARG_POINTER(aSource);
03231   NS_ENSURE_ARG_POINTER(aResult);
03232   *aResult = nsnull;
03233   nsAutoString value;
03234   nsresult rc = nsSOAPUtils::GetElementTextContent(aSource, value);
03235   NS_ENSURE_SUCCESS(rc, rc);
03236 
03237   PRBool b;
03238   if (value.Equals(gSOAPStrings->kTrue) || 
03239       value.Equals(gSOAPStrings->kTrueA)) {
03240     b = PR_TRUE;
03241   } else if (value.Equals(gSOAPStrings->kFalse) || 
03242              value.Equals(gSOAPStrings->kFalseA)) {
03243     b = PR_FALSE;
03244   } else {
03245     return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,
03246                           "SOAP_ILLEGAL_BOOLEAN",
03247                           "Illegal value discovered for boolean");
03248   }
03249 
03250   nsCOMPtr<nsIWritableVariant> p =
03251     do_CreateInstance(NS_VARIANT_CONTRACTID,&rc);
03252   NS_ENSURE_SUCCESS(rc, rc);
03253 
03254   p->SetAsBool(b);
03255 
03256   NS_ADDREF(*aResult = p);
03257   return NS_OK;
03258 }
03259 
03260 NS_IMETHODIMP
03261 nsDoubleEncoder::Decode(nsISOAPEncoding* aEncoding,
03262                         nsIDOMElement* aSource,
03263                         nsISchemaType* aSchemaType,
03264                         nsISOAPAttachments* aAttachments,
03265                         nsIVariant** aResult)
03266 {
03267   NS_ENSURE_ARG_POINTER(aEncoding);
03268   NS_ENSURE_ARG_POINTER(aSource);
03269   NS_ENSURE_ARG_POINTER(aResult);
03270   *aResult = nsnull;
03271   nsAutoString value;
03272   nsresult rc = nsSOAPUtils::GetElementTextContent(aSource, value);
03273   NS_ENSURE_SUCCESS(rc, rc);
03274 
03275   double f;
03276   PRUint32 n;
03277   PRInt32 r = PR_sscanf(NS_ConvertUCS2toUTF8(value).get(), " %lf %n", &f, &n);
03278   if (r == 0 || n < value.Length()) {
03279     return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,
03280                           "SOAP_ILLEGAL_DOUBLE",
03281                           "Illegal value discovered for double");
03282   }
03283 
03284   nsCOMPtr<nsIWritableVariant> p =
03285     do_CreateInstance(NS_VARIANT_CONTRACTID, &rc);
03286   NS_ENSURE_SUCCESS(rc, rc);
03287 
03288   p->SetAsDouble(f);
03289 
03290   NS_ADDREF(*aResult = p);
03291   return NS_OK;
03292 }
03293 
03294 NS_IMETHODIMP
03295 nsFloatEncoder::Decode(nsISOAPEncoding* aEncoding,
03296                        nsIDOMElement* aSource,
03297                        nsISchemaType* aSchemaType,
03298                        nsISOAPAttachments* aAttachments,
03299                        nsIVariant** aResult)
03300 {
03301   NS_ENSURE_ARG_POINTER(aEncoding);
03302   NS_ENSURE_ARG_POINTER(aSource);
03303   NS_ENSURE_ARG_POINTER(aResult);
03304   *aResult = nsnull;
03305   nsAutoString value;
03306   nsresult rc = nsSOAPUtils::GetElementTextContent(aSource, value);
03307   NS_ENSURE_SUCCESS(rc, rc);
03308 
03309   float f;
03310   PRUint32 n;
03311   PRInt32 r = PR_sscanf(NS_ConvertUCS2toUTF8(value).get(), " %f %n", &f, &n);
03312   if (r == 0 || n < value.Length()) {
03313     return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,
03314                           "SOAP_ILLEGAL_FLOAT",
03315                           "Illegal value discovered for float");
03316   }
03317 
03318   nsCOMPtr<nsIWritableVariant> p =
03319     do_CreateInstance(NS_VARIANT_CONTRACTID,&rc);
03320   NS_ENSURE_SUCCESS(rc, rc);
03321 
03322   p->SetAsFloat(f);
03323 
03324   NS_ADDREF(*aResult = p);
03325   return NS_OK;
03326 }
03327 
03328 NS_IMETHODIMP
03329 nsLongEncoder::Decode(nsISOAPEncoding* aEncoding,
03330                       nsIDOMElement* aSource,
03331                       nsISchemaType* aSchemaType,
03332                       nsISOAPAttachments* aAttachments,
03333                       nsIVariant** aResult)
03334 {
03335   NS_ENSURE_ARG_POINTER(aEncoding);
03336   NS_ENSURE_ARG_POINTER(aSource);
03337   NS_ENSURE_ARG_POINTER(aResult);
03338   *aResult = nsnull;
03339   nsAutoString value;
03340   nsresult rc = nsSOAPUtils::GetElementTextContent(aSource, value);
03341   NS_ENSURE_SUCCESS(rc, rc);
03342 
03343   PRInt64 f;
03344   PRUint32 n;
03345   PRInt32 r = PR_sscanf(NS_ConvertUCS2toUTF8(value).get(), " %lld %n", &f, &n);
03346   if (r == 0 || n < value.Length()) {
03347     return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,
03348                           "SOAP_ILLEGAL_LONG",
03349                           "Illegal value discovered for long");
03350   }
03351 
03352   nsCOMPtr<nsIWritableVariant> p =
03353     do_CreateInstance(NS_VARIANT_CONTRACTID,&rc);
03354   NS_ENSURE_SUCCESS(rc, rc);
03355 
03356   p->SetAsInt64(f);
03357 
03358   NS_ADDREF(*aResult = p);
03359   return NS_OK;
03360 }
03361 
03362 NS_IMETHODIMP
03363 nsIntEncoder::Decode(nsISOAPEncoding* aEncoding,
03364                      nsIDOMElement* aSource,
03365                      nsISchemaType* aSchemaType,
03366                      nsISOAPAttachments* aAttachments,
03367                      nsIVariant** aResult)
03368 {
03369   NS_ENSURE_ARG_POINTER(aEncoding);
03370   NS_ENSURE_ARG_POINTER(aSource);
03371   NS_ENSURE_ARG_POINTER(aResult);
03372   *aResult = nsnull;
03373   nsAutoString value;
03374   nsresult rc = nsSOAPUtils::GetElementTextContent(aSource, value);
03375   NS_ENSURE_SUCCESS(rc, rc);
03376 
03377   PRInt32 f;
03378   PRUint32 n;
03379   PRInt32 r = PR_sscanf(NS_ConvertUCS2toUTF8(value).get(), " %ld %n", &f, &n);
03380   if (r == 0 || n < value.Length()) {
03381     return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,
03382                           "SOAP_ILLEGAL_INT",
03383                           "Illegal value discovered for int");
03384   }
03385 
03386   nsCOMPtr<nsIWritableVariant> p =
03387     do_CreateInstance(NS_VARIANT_CONTRACTID,&rc);
03388   NS_ENSURE_SUCCESS(rc, rc);
03389 
03390   p->SetAsInt32(f);
03391   NS_ADDREF(*aResult = p);
03392   return NS_OK;
03393 }
03394 
03395 NS_IMETHODIMP
03396 nsShortEncoder::Decode(nsISOAPEncoding* aEncoding,
03397                        nsIDOMElement* aSource,
03398                        nsISchemaType* aSchemaType,
03399                        nsISOAPAttachments* aAttachments,
03400                        nsIVariant** aResult)
03401 {
03402   NS_ENSURE_ARG_POINTER(aEncoding);
03403   NS_ENSURE_ARG_POINTER(aSource);
03404   NS_ENSURE_ARG_POINTER(aResult);
03405   *aResult = nsnull;
03406   nsAutoString value;
03407   nsresult rc = nsSOAPUtils::GetElementTextContent(aSource, value);
03408   NS_ENSURE_SUCCESS(rc, rc);
03409 
03410   PRInt16 f;
03411   PRUint32 n;
03412   PRInt32 r = PR_sscanf(NS_ConvertUCS2toUTF8(value).get(), " %hd %n", &f, &n);
03413   if (r == 0 || n < value.Length()) {
03414     return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,
03415                           "SOAP_ILLEGAL_SHORT",
03416                           "Illegal value discovered for short");
03417   }
03418 
03419   nsCOMPtr<nsIWritableVariant> p =
03420     do_CreateInstance(NS_VARIANT_CONTRACTID,&rc);
03421   NS_ENSURE_SUCCESS(rc, rc);
03422 
03423   p->SetAsInt16(f);
03424   NS_ADDREF(*aResult = p);
03425   return NS_OK;
03426 }
03427 
03428 NS_IMETHODIMP
03429 nsByteEncoder::Decode(nsISOAPEncoding* aEncoding,
03430                       nsIDOMElement* aSource,
03431                       nsISchemaType* aSchemaType,
03432                       nsISOAPAttachments* aAttachments,
03433                       nsIVariant** aResult)
03434 {
03435   NS_ENSURE_ARG_POINTER(aEncoding);
03436   NS_ENSURE_ARG_POINTER(aSource);
03437   NS_ENSURE_ARG_POINTER(aResult);
03438   *aResult = nsnull;
03439   nsAutoString value;
03440   nsresult rc = nsSOAPUtils::GetElementTextContent(aSource, value);
03441   NS_ENSURE_SUCCESS(rc, rc);
03442 
03443   PRInt16 f;
03444   PRUint32 n;
03445   PRInt32 r = PR_sscanf(NS_ConvertUCS2toUTF8(value).get(), " %hd %n", &f, &n);
03446   if (r == 0 || n < value.Length() || f < -128 || f > 127) {
03447     return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,
03448                           "SOAP_ILLEGAL_BYTE",
03449                           "Illegal value discovered for byte");
03450   }
03451 
03452   nsCOMPtr<nsIWritableVariant> p =
03453     do_CreateInstance(NS_VARIANT_CONTRACTID,&rc);
03454   NS_ENSURE_SUCCESS(rc, rc);
03455 
03456   p->SetAsInt8((PRUint8) f);
03457   NS_ADDREF(*aResult = p);
03458   return NS_OK;
03459 }
03460 
03461 NS_IMETHODIMP
03462 nsUnsignedLongEncoder::Decode(nsISOAPEncoding* aEncoding,
03463                               nsIDOMElement* aSource,
03464                               nsISchemaType* aSchemaType,
03465                               nsISOAPAttachments* aAttachments,
03466                               nsIVariant** aResult)
03467 {
03468   NS_ENSURE_ARG_POINTER(aEncoding);
03469   NS_ENSURE_ARG_POINTER(aSource);
03470   NS_ENSURE_ARG_POINTER(aResult);
03471   *aResult = nsnull;
03472   nsAutoString value;
03473   nsresult rc = nsSOAPUtils::GetElementTextContent(aSource, value);
03474   NS_ENSURE_SUCCESS(rc, rc);
03475 
03476   PRUint64 f;
03477   PRUint32 n;
03478   PRInt32 r = PR_sscanf(NS_ConvertUCS2toUTF8(value).get(), " %llu %n", &f, &n);
03479   if (r == 0 || n < value.Length()) {
03480     return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,
03481                           "SOAP_ILLEGAL_ULONG",
03482                           "Illegal value discovered for unsigned long");
03483   }
03484 
03485   nsCOMPtr<nsIWritableVariant> p =
03486     do_CreateInstance(NS_VARIANT_CONTRACTID,&rc);
03487   NS_ENSURE_SUCCESS(rc, rc);
03488 
03489   p->SetAsUint64(f);
03490   NS_ADDREF(*aResult = p);
03491   return NS_OK;
03492 }
03493 
03494 NS_IMETHODIMP
03495 nsUnsignedIntEncoder::Decode(nsISOAPEncoding* aEncoding,
03496                              nsIDOMElement* aSource,
03497                              nsISchemaType* aSchemaType,
03498                              nsISOAPAttachments* aAttachments,
03499                              nsIVariant** aResult)
03500 {
03501   NS_ENSURE_ARG_POINTER(aEncoding);
03502   NS_ENSURE_ARG_POINTER(aSource);
03503   NS_ENSURE_ARG_POINTER(aResult);
03504   *aResult = nsnull;
03505   nsAutoString value;
03506   nsresult rc = nsSOAPUtils::GetElementTextContent(aSource, value);
03507   NS_ENSURE_SUCCESS(rc, rc);
03508 
03509   PRUint32 f;
03510   PRUint32 n;
03511   PRInt32 r = PR_sscanf(NS_ConvertUCS2toUTF8(value).get(), " %lu %n", &f, &n);
03512   if (r == 0 || n < value.Length()) {
03513     return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,
03514                           "SOAP_ILLEGAL_UINT",
03515                           "Illegal value discovered for unsigned int");
03516   }
03517 
03518   nsCOMPtr<nsIWritableVariant> p =
03519     do_CreateInstance(NS_VARIANT_CONTRACTID,&rc);
03520   NS_ENSURE_SUCCESS(rc, rc);
03521 
03522   p->SetAsUint32(f);
03523   NS_ADDREF(*aResult = p);
03524   return NS_OK;
03525 }
03526 
03527 NS_IMETHODIMP
03528 nsBase64BinaryEncoder::Decode(nsISOAPEncoding* aEncoding,
03529                               nsIDOMElement* aSource,
03530                               nsISchemaType* aSchemaType,
03531                               nsISOAPAttachments* aAttachments,
03532                               nsIVariant** aResult)
03533 {
03534   NS_ENSURE_ARG_POINTER(aEncoding);
03535   NS_ENSURE_ARG_POINTER(aSource);
03536   NS_ENSURE_ARG_POINTER(aResult);
03537   *aResult = nsnull;
03538 
03539   nsString value;
03540   nsresult rv = nsSOAPUtils::GetElementTextContent(aSource, value);
03541   NS_ENSURE_SUCCESS(rv, rv);
03542 
03543   NS_LossyConvertUTF16toASCII valueStr(value);
03544   valueStr.StripChars(" \n\r\t");
03545 
03546   char* decodedVal = PL_Base64Decode(valueStr.get(), valueStr.Length(), nsnull);
03547   if (!decodedVal) {
03548     return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,
03549                           "SOAP_ILLEGAL_BASE64",
03550                           "Data cannot be decoded as Base64");
03551   }
03552 
03553   nsCOMPtr<nsIWritableVariant> p = 
03554     do_CreateInstance(NS_VARIANT_CONTRACTID, &rv);
03555 
03556   if (NS_SUCCEEDED(rv)) {
03557 
03558     rv = p->SetAsArray(nsIDataType::VTYPE_UINT8, nsnull,
03559                        strlen(decodedVal), decodedVal);
03560   }
03561 
03562   PR_Free(decodedVal);
03563   NS_ENSURE_SUCCESS(rv, rv);
03564 
03565   NS_ADDREF(*aResult = p);
03566   return NS_OK;
03567 }
03568 
03569 NS_IMETHODIMP
03570 nsUnsignedShortEncoder::Decode(nsISOAPEncoding* aEncoding,
03571                                nsIDOMElement* aSource,
03572                                nsISchemaType* aSchemaType,
03573                                nsISOAPAttachments* aAttachments,
03574                                nsIVariant** aResult)
03575 {
03576   NS_ENSURE_ARG_POINTER(aEncoding);
03577   NS_ENSURE_ARG_POINTER(aSource);
03578   NS_ENSURE_ARG_POINTER(aResult);
03579   *aResult = nsnull;
03580   nsAutoString value;
03581   nsresult rc = nsSOAPUtils::GetElementTextContent(aSource, value);
03582   NS_ENSURE_SUCCESS(rc, rc);
03583 
03584   PRUint16 f;
03585   PRUint32 n;
03586   PRInt32 r = PR_sscanf(NS_ConvertUCS2toUTF8(value).get(), " %hu %n", &f, &n);
03587   if (r == 0 || n < value.Length()) {
03588     return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,
03589                           "SOAP_ILLEGAL_USHORT",
03590                           "Illegal value discovered for unsigned short");
03591   }
03592 
03593   nsCOMPtr<nsIWritableVariant> p =
03594     do_CreateInstance(NS_VARIANT_CONTRACTID,&rc);
03595   NS_ENSURE_SUCCESS(rc, rc);
03596 
03597   p->SetAsUint16(f);
03598   NS_ADDREF(*aResult = p);
03599   return NS_OK;
03600 }
03601 
03602 NS_IMETHODIMP
03603 nsUnsignedByteEncoder::Decode(nsISOAPEncoding* aEncoding,
03604                               nsIDOMElement* aSource,
03605                               nsISchemaType* aSchemaType,
03606                               nsISOAPAttachments* aAttachments,
03607                               nsIVariant** aResult)
03608 {
03609   NS_ENSURE_ARG_POINTER(aEncoding);
03610   NS_ENSURE_ARG_POINTER(aSource);
03611   NS_ENSURE_ARG_POINTER(aResult);
03612   *aResult = nsnull;
03613   nsAutoString value;
03614   nsresult rc = nsSOAPUtils::GetElementTextContent(aSource, value);
03615   NS_ENSURE_SUCCESS(rc, rc);
03616 
03617   PRUint16 f;
03618   PRUint32 n;
03619   PRInt32 r = PR_sscanf(NS_ConvertUCS2toUTF8(value).get(), " %hu %n", &f, &n);
03620   if (r == 0 || n < value.Length() || f > 255) {
03621     return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,
03622                           "SOAP_ILLEGAL_UBYTE",
03623                           "Illegal value discovered for unsigned byte");
03624   }
03625 
03626   nsCOMPtr<nsIWritableVariant> p =
03627     do_CreateInstance(NS_VARIANT_CONTRACTID,&rc);
03628   NS_ENSURE_SUCCESS(rc, rc);
03629 
03630   p->SetAsUint8((PRUint8) f);
03631   NS_ADDREF(*aResult = p);
03632   return NS_OK;
03633 }