extra: import at 3.0.1 beta 1
[mozilla-extra.git] / extensions / webservices / soap / src / nsDefaultSOAPEncoder.cpp
blob05e60d846404947b1ab44474af7a9bfbf7b629e1
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 2001
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
24 * Alternatively, the contents of this file may be used under the terms of
25 * either the GNU General Public License Version 2 or later (the "GPL"), or
26 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
38 #include "nsInterfaceHashtable.h"
39 #include "nsHashKeys.h"
40 #include "nsISchemaLoader.h"
41 #include "nsDefaultSOAPEncoder.h"
42 #include "nsSOAPUtils.h"
43 #include "nsSOAPParameter.h"
44 #include "nsISOAPAttachments.h"
45 #include "nsXPIDLString.h"
46 #include "nsIDOMDocument.h"
47 #include "nsIDOMText.h"
48 #include "nsCOMPtr.h"
49 #include "nsISchema.h"
50 #include "nsIComponentManager.h"
51 #include "nsIServiceManager.h"
52 #include "nsXPCOM.h"
53 #include "nsISupportsPrimitives.h"
54 #include "nsIDOMParser.h"
55 #include "nsSOAPUtils.h"
56 #include "nsISOAPEncoding.h"
57 #include "nsISOAPEncoder.h"
58 #include "nsISOAPDecoder.h"
59 #include "nsISOAPMessage.h"
60 #include "nsSOAPException.h"
61 #include "prprf.h"
62 #include "prdtoa.h"
63 #include "plbase64.h"
64 #include "prmem.h"
65 #include "nsReadableUtils.h"
66 #include "nsIDOMNamedNodeMap.h"
67 #include "nsIDOMAttr.h"
68 #include "nsPrintfCString.h"
69 #include "nsISOAPPropertyBagMutator.h"
70 #include "nsIProperty.h"
71 #include "nsIPropertyBag.h"
72 #include "nsSupportsArray.h"
75 #define MAX_ARRAY_DIMENSIONS 100
77 class nsSOAPEncoderStub : public nsISOAPEncoder,
78 public nsISOAPDecoder
80 public:
81 NS_DECL_ISUPPORTS
82 protected:
83 PRUint16 mSOAPVersion;
86 NS_IMPL_ISUPPORTS2(nsSOAPEncoderStub, nsISOAPEncoder, nsISOAPDecoder)
89 // Macros to declare and implement the default encoder classes
92 #define DECLARE_ENCODER(name) \
93 class ns##name##Encoder : public nsSOAPEncoderStub \
94 { \
95 public: \
96 ns##name##Encoder(); \
97 ns##name##Encoder(PRUint16 aSOAPVersion); \
98 virtual ~ns##name##Encoder(); \
99 NS_DECL_NSISOAPENCODER \
100 NS_DECL_NSISOAPDECODER \
101 }; \
102 ns##name##Encoder::ns##name##Encoder(PRUint16 aSOAPVersion) {mSOAPVersion=aSOAPVersion;} \
103 ns##name##Encoder::~ns##name##Encoder() {}
105 // All encoders must be first declared and then registered.
106 DECLARE_ENCODER(Default)
107 DECLARE_ENCODER(AnyType)
108 DECLARE_ENCODER(AnySimpleType)
109 DECLARE_ENCODER(Array)
110 DECLARE_ENCODER(Struct)
111 DECLARE_ENCODER(String)
112 DECLARE_ENCODER(Boolean)
113 DECLARE_ENCODER(Double)
114 DECLARE_ENCODER(Float)
115 DECLARE_ENCODER(Long)
116 DECLARE_ENCODER(Int)
117 DECLARE_ENCODER(Short)
118 DECLARE_ENCODER(Byte)
119 DECLARE_ENCODER(UnsignedLong)
120 DECLARE_ENCODER(UnsignedInt)
121 DECLARE_ENCODER(UnsignedShort)
122 DECLARE_ENCODER(UnsignedByte)
123 DECLARE_ENCODER(Base64Binary)
126 * This now separates the version with respect to the SOAP specification from the version
127 * with respect to the schema version (using the same constants for both). This permits
128 * a user of a SOAP 1.1 or 1.2 encoding to choose which encoding to encode to.
130 #define REGISTER_ENCODER(name,type,uri) \
132 ns##name##Encoder *handler = new ns##name##Encoder(version); \
133 SOAPEncodingKey(uri, gSOAPStrings->k##name##type##Type, encodingKey); \
134 SetEncoder(encodingKey, handler); \
135 SetDecoder(encodingKey, handler); \
138 #define REGISTER_SCHEMA_ENCODER(name) REGISTER_ENCODER(name,Schema,gSOAPStrings->kXSURI)
139 #define REGISTER_SOAP_ENCODER(name) REGISTER_ENCODER(name,SOAP,gSOAPStrings->kSOAPEncURI)
141 #define REGISTER_ENCODERS \
143 nsDefaultEncoder *handler = new nsDefaultEncoder(version); \
144 SetDefaultEncoder(handler); \
145 SetDefaultDecoder(handler); \
147 nsAutoString encodingKey; \
148 REGISTER_SCHEMA_ENCODER(AnyType) \
149 REGISTER_SCHEMA_ENCODER(AnySimpleType) \
150 REGISTER_SOAP_ENCODER(Array) \
151 REGISTER_SOAP_ENCODER(Struct) \
152 REGISTER_SCHEMA_ENCODER(String) \
153 REGISTER_SCHEMA_ENCODER(Boolean) \
154 REGISTER_SCHEMA_ENCODER(Double) \
155 REGISTER_SCHEMA_ENCODER(Float) \
156 REGISTER_SCHEMA_ENCODER(Long) \
157 REGISTER_SCHEMA_ENCODER(Int) \
158 REGISTER_SCHEMA_ENCODER(Short) \
159 REGISTER_SCHEMA_ENCODER(Byte) \
160 REGISTER_SCHEMA_ENCODER(UnsignedLong) \
161 REGISTER_SCHEMA_ENCODER(UnsignedInt) \
162 REGISTER_SCHEMA_ENCODER(UnsignedShort) \
163 REGISTER_SCHEMA_ENCODER(UnsignedByte) \
164 REGISTER_SCHEMA_ENCODER(Base64Binary)
167 // Default SOAP Encodings
170 NS_IMPL_ADDREF(nsDefaultSOAPEncoding_1_1)
171 NS_IMPL_RELEASE(nsDefaultSOAPEncoding_1_1)
173 nsDefaultSOAPEncoding_1_1::nsDefaultSOAPEncoding_1_1()
174 : nsSOAPEncoding(gSOAPStrings->kSOAPEncURI11, nsnull, nsnull)
176 PRUint16 version = nsISOAPMessage::VERSION_1_1;
177 PRBool result;
178 MapSchemaURI(gSOAPStrings->kXSURI1999,gSOAPStrings->kXSURI,PR_TRUE,&result);
179 MapSchemaURI(gSOAPStrings->kXSIURI1999,gSOAPStrings->kXSIURI,PR_TRUE,&result);
180 MapSchemaURI(gSOAPStrings->kSOAPEncURI11,gSOAPStrings->kSOAPEncURI,PR_TRUE,&result);
181 REGISTER_ENCODERS
184 NS_IMPL_ADDREF(nsDefaultSOAPEncoding_1_2)
185 NS_IMPL_RELEASE(nsDefaultSOAPEncoding_1_2)
187 nsDefaultSOAPEncoding_1_2::nsDefaultSOAPEncoding_1_2()
188 : nsSOAPEncoding(gSOAPStrings->kSOAPEncURI, nsnull, nsnull)
190 PRUint16 version = nsISOAPMessage::VERSION_1_2;
191 PRBool result;
192 MapSchemaURI(gSOAPStrings->kXSURI1999,gSOAPStrings->kXSURI,PR_FALSE,&result);
193 MapSchemaURI(gSOAPStrings->kXSIURI1999,gSOAPStrings->kXSIURI,PR_FALSE,&result);
194 MapSchemaURI(gSOAPStrings->kSOAPEncURI11,gSOAPStrings->kSOAPEncURI,PR_FALSE,&result);
195 REGISTER_ENCODERS
199 // Default Encoders -- static helper functions intermixed
202 // Getting the immediate supertype of any type
203 static nsresult GetSupertype(nsISOAPEncoding* aEncoding,
204 nsISchemaType* aType,
205 nsISchemaType** aResult)
207 PRUint16 typevalue;
208 nsresult rc = aType->GetSchemaType(&typevalue);
209 NS_ENSURE_SUCCESS(rc, rc);
211 nsCOMPtr<nsISchemaType> base;
212 nsAutoString name;
213 switch (typevalue) {
214 case nsISchemaType::SCHEMA_TYPE_COMPLEX:
216 nsCOMPtr<nsISchemaComplexType> type =
217 do_QueryInterface(aType);
218 rc = type->GetBaseType(getter_AddRefs(base));
219 NS_ENSURE_SUCCESS(rc, rc);
221 break;
223 case nsISchemaType::SCHEMA_TYPE_SIMPLE:
225 nsCOMPtr<nsISchemaSimpleType> type =
226 do_QueryInterface(aType);
227 PRUint16 simpletypevalue;
228 rc = type->GetSimpleType(&simpletypevalue);
229 NS_ENSURE_SUCCESS(rc, rc);
231 switch (simpletypevalue) {
232 // Ultimately, this is wrong because in XML types are value spaces
233 // We have not handled unions and lists.
234 // A union might be considered a supertype of anything it joins
235 // but it is the supertype of all types with value spaces it includes.
236 // SOAP is an attempt to treat XML types as though they were
237 // data types, which are governed by labels instead of value spaces.
238 // So two unrelated values may coexist, but we will disallow it
239 // because the caller probably wants type guarantees, not value
240 // guarantees.
241 case nsISchemaSimpleType::SIMPLE_TYPE_RESTRICTION:
243 nsCOMPtr<nsISchemaRestrictionType> simpletype =
244 do_QueryInterface(type);
245 nsCOMPtr<nsISchemaSimpleType> simplebasetype;
246 rc = simpletype->GetBaseType(getter_AddRefs(simplebasetype));
247 NS_ENSURE_SUCCESS(rc, rc);
249 base = simplebasetype;
250 break;
252 case nsISchemaSimpleType::SIMPLE_TYPE_BUILTIN:
254 nsCOMPtr<nsISchemaBuiltinType> builtintype =
255 do_QueryInterface(type);
256 PRUint16 builtintypevalue;
257 rc = builtintype->GetBuiltinType(&builtintypevalue);
258 NS_ENSURE_SUCCESS(rc, rc);
260 switch(builtintypevalue) {
261 case nsISchemaBuiltinType::BUILTIN_TYPE_ANYTYPE: // Root of all types
262 *aResult = nsnull;
263 return NS_OK;
264 case nsISchemaBuiltinType::BUILTIN_TYPE_STRING:
265 // name = kAnySimpleTypeSchemaType;
266 name = gSOAPStrings->kAnyTypeSchemaType;
267 break;
268 case nsISchemaBuiltinType::BUILTIN_TYPE_NORMALIZED_STRING:
269 name = gSOAPStrings->kStringSchemaType;
270 break;
271 case nsISchemaBuiltinType::BUILTIN_TYPE_TOKEN:
272 name = gSOAPStrings->kNormalizedStringSchemaType;
273 break;
274 case nsISchemaBuiltinType::BUILTIN_TYPE_BYTE:
275 name = gSOAPStrings->kShortSchemaType;
276 break;
277 case nsISchemaBuiltinType::BUILTIN_TYPE_UNSIGNEDBYTE:
278 name = gSOAPStrings->kUnsignedShortSchemaType;
279 break;
280 case nsISchemaBuiltinType::BUILTIN_TYPE_BASE64BINARY:
281 // name = kAnySimpleTypeSchemaType;
282 name = gSOAPStrings->kAnyTypeSchemaType;
283 break;
284 case nsISchemaBuiltinType::BUILTIN_TYPE_HEXBINARY:
285 // name = kAnySimpleTypeSchemaType;
286 name = gSOAPStrings->kAnyTypeSchemaType;
287 break;
288 case nsISchemaBuiltinType::BUILTIN_TYPE_INTEGER:
289 name = gSOAPStrings->kDecimalSchemaType;
290 break;
291 case nsISchemaBuiltinType::BUILTIN_TYPE_POSITIVEINTEGER:
292 name = gSOAPStrings->kNonNegativeIntegerSchemaType;
293 break;
294 case nsISchemaBuiltinType::BUILTIN_TYPE_NEGATIVEINTEGER:
295 name = gSOAPStrings->kNonPositiveIntegerSchemaType;
296 break;
297 case nsISchemaBuiltinType::BUILTIN_TYPE_NONNEGATIVEINTEGER:
298 name = gSOAPStrings->kIntegerSchemaType;
299 break;
300 case nsISchemaBuiltinType::BUILTIN_TYPE_NONPOSITIVEINTEGER:
301 name = gSOAPStrings->kIntegerSchemaType;
302 break;
303 case nsISchemaBuiltinType::BUILTIN_TYPE_INT:
304 name = gSOAPStrings->kLongSchemaType;
305 break;
306 case nsISchemaBuiltinType::BUILTIN_TYPE_UNSIGNEDINT:
307 name = gSOAPStrings->kUnsignedLongSchemaType;
308 break;
309 case nsISchemaBuiltinType::BUILTIN_TYPE_LONG:
310 name = gSOAPStrings->kIntegerSchemaType;
311 break;
312 case nsISchemaBuiltinType::BUILTIN_TYPE_UNSIGNEDLONG:
313 name = gSOAPStrings->kNonNegativeIntegerSchemaType;
314 break;
315 case nsISchemaBuiltinType::BUILTIN_TYPE_SHORT:
316 name = gSOAPStrings->kIntSchemaType;
317 break;
318 case nsISchemaBuiltinType::BUILTIN_TYPE_UNSIGNEDSHORT:
319 name = gSOAPStrings->kUnsignedIntSchemaType;
320 break;
321 case nsISchemaBuiltinType::BUILTIN_TYPE_DECIMAL:
322 // name = kAnySimpleTypeSchemaType;
323 name = gSOAPStrings->kAnyTypeSchemaType;
324 break;
325 case nsISchemaBuiltinType::BUILTIN_TYPE_FLOAT:
326 // name = kAnySimpleTypeSchemaType;
327 name = gSOAPStrings->kAnyTypeSchemaType;
328 break;
329 case nsISchemaBuiltinType::BUILTIN_TYPE_DOUBLE:
330 // name = kAnySimpleTypeSchemaType;
331 name = gSOAPStrings->kAnyTypeSchemaType;
332 break;
333 case nsISchemaBuiltinType::BUILTIN_TYPE_BOOLEAN:
334 // name = kAnySimpleTypeSchemaType;
335 name = gSOAPStrings->kAnyTypeSchemaType;
336 break;
337 case nsISchemaBuiltinType::BUILTIN_TYPE_TIME:
338 // name = kAnySimpleTypeSchemaType;
339 name = gSOAPStrings->kAnyTypeSchemaType;
340 break;
341 case nsISchemaBuiltinType::BUILTIN_TYPE_DATETIME:
342 // name = kAnySimpleTypeSchemaType;
343 name = gSOAPStrings->kAnyTypeSchemaType;
344 break;
345 case nsISchemaBuiltinType::BUILTIN_TYPE_DURATION:
346 // name = kAnySimpleTypeSchemaType;
347 name = gSOAPStrings->kAnyTypeSchemaType;
348 break;
349 case nsISchemaBuiltinType::BUILTIN_TYPE_DATE:
350 // name = kAnySimpleTypeSchemaType;
351 name = gSOAPStrings->kAnyTypeSchemaType;
352 break;
353 case nsISchemaBuiltinType::BUILTIN_TYPE_GMONTH:
354 // name = kAnySimpleTypeSchemaType;
355 name = gSOAPStrings->kAnyTypeSchemaType;
356 break;
357 case nsISchemaBuiltinType::BUILTIN_TYPE_GYEAR:
358 // name = kAnySimpleTypeSchemaType;
359 name = gSOAPStrings->kAnyTypeSchemaType;
360 break;
361 case nsISchemaBuiltinType::BUILTIN_TYPE_GYEARMONTH:
362 // name = kAnySimpleTypeSchemaType;
363 name = gSOAPStrings->kAnyTypeSchemaType;
364 break;
365 case nsISchemaBuiltinType::BUILTIN_TYPE_GDAY:
366 // name = kAnySimpleTypeSchemaType;
367 name = gSOAPStrings->kAnyTypeSchemaType;
368 break;
369 case nsISchemaBuiltinType::BUILTIN_TYPE_GMONTHDAY:
370 // name = kAnySimpleTypeSchemaType;
371 name = gSOAPStrings->kAnyTypeSchemaType;
372 break;
373 case nsISchemaBuiltinType::BUILTIN_TYPE_NAME:
374 // name = kAnySimpleTypeSchemaType;
375 name = gSOAPStrings->kAnyTypeSchemaType;
376 break;
377 case nsISchemaBuiltinType::BUILTIN_TYPE_QNAME:
378 // name = kAnySimpleTypeSchemaType;
379 name = gSOAPStrings->kAnyTypeSchemaType;
380 break;
381 case nsISchemaBuiltinType::BUILTIN_TYPE_NCNAME:
382 name = gSOAPStrings->kNameSchemaType;
383 break;
384 case nsISchemaBuiltinType::BUILTIN_TYPE_ANYURI:
385 // name = kAnySimpleTypeSchemaType;
386 name = gSOAPStrings->kAnyTypeSchemaType;
387 break;
388 case nsISchemaBuiltinType::BUILTIN_TYPE_LANGUAGE:
389 name = gSOAPStrings->kTokenSchemaType;
390 break;
391 case nsISchemaBuiltinType::BUILTIN_TYPE_ID:
392 name = gSOAPStrings->kNCNameSchemaType;
393 break;
394 case nsISchemaBuiltinType::BUILTIN_TYPE_IDREF:
395 name = gSOAPStrings->kNCNameSchemaType;
396 break;
397 case nsISchemaBuiltinType::BUILTIN_TYPE_IDREFS:
398 name = gSOAPStrings->kNormalizedStringSchemaType; // Really a list...
399 break;
400 case nsISchemaBuiltinType::BUILTIN_TYPE_ENTITY:
401 name = gSOAPStrings->kNCNameSchemaType;
402 break;
403 case nsISchemaBuiltinType::BUILTIN_TYPE_ENTITIES:
404 name = gSOAPStrings->kNormalizedStringSchemaType; // Really a list...
405 break;
406 case nsISchemaBuiltinType::BUILTIN_TYPE_NOTATION:
407 // name = kAnySimpleTypeSchemaType;
408 name = gSOAPStrings->kAnyTypeSchemaType;
409 break;
410 case nsISchemaBuiltinType::BUILTIN_TYPE_NMTOKEN:
411 name = gSOAPStrings->kTokenSchemaType;
412 break;
413 case nsISchemaBuiltinType::BUILTIN_TYPE_NMTOKENS:
414 name = gSOAPStrings->kNormalizedStringSchemaType; // Really a list...
415 break;
419 break;
422 if (!base) {
423 if (name.IsEmpty()) {
424 switch (typevalue) {
425 case nsISchemaType::SCHEMA_TYPE_COMPLEX:
426 name = gSOAPStrings->kAnyTypeSchemaType;
427 break;
428 default:
429 // name = kAnySimpleTypeSchemaType;
430 name = gSOAPStrings->kAnyTypeSchemaType;
433 nsCOMPtr<nsISchemaCollection> collection;
434 rc = aEncoding->GetSchemaCollection(getter_AddRefs(collection));
435 NS_ENSURE_SUCCESS(rc, rc);
437 rc = collection->GetType(name,
438 gSOAPStrings->kXSURI,
439 getter_AddRefs(base));
440 // if (NS_FAILED(rc)) return rc;
443 NS_IF_ADDREF(*aResult = base);
444 return NS_OK;
447 static nsresult
448 EncodeSimpleValue(nsISOAPEncoding* aEncoding,
449 const nsAString& aValue,
450 const nsAString& aNamespaceURI,
451 const nsAString& aName,
452 nsISchemaType* aSchemaType,
453 nsIDOMElement* aDestination,
454 nsIDOMElement** aResult)
456 nsresult rc;
457 PRBool needType = PR_TRUE;
458 nsAutoString typeName;
459 nsAutoString typeNS;
460 if (aSchemaType) {
461 rc = aSchemaType->GetName(typeName);
462 NS_ENSURE_SUCCESS(rc, rc);
464 rc = aSchemaType->GetTargetNamespace(typeNS);
465 NS_ENSURE_SUCCESS(rc, rc);
467 nsAutoString name; // First choose the appropriate name and namespace for the element.
468 nsAutoString ns;
469 if (aName.IsEmpty()) { // We automatically choose appropriate element names where none exist.
470 // The idea here seems to be to walk up the schema hierarchy to
471 // find the base type and use the name of that as the element name.
472 ns = gSOAPStrings->kSOAPEncURI;
473 nsAutoString currentURI = ns;
474 nsCOMPtr<nsISchemaType> currentType = aSchemaType;
475 while (currentType
476 && !(currentURI.Equals(gSOAPStrings->kXSURI) ||
477 currentURI.Equals(gSOAPStrings->kSOAPEncURI))) {
478 nsCOMPtr<nsISchemaType> supertype;
479 rc = GetSupertype(aEncoding, currentType, getter_AddRefs(supertype));
480 NS_ENSURE_SUCCESS(rc, rc);
482 if (!currentType) {
483 break;
485 currentType = supertype;
486 rc = currentType->GetTargetNamespace(currentURI);
487 NS_ENSURE_SUCCESS(rc, rc);
489 if (currentType) {
490 rc = aSchemaType->GetName(name);
491 NS_ENSURE_SUCCESS(rc, rc);
493 else {
494 name = gSOAPStrings->kAnyTypeSchemaType;
495 needType = PR_FALSE;
498 if (!typeNS.IsEmpty()) {
499 ns.Truncate();
500 ns.SetIsVoid(true);
502 rc = NS_OK;
504 else {
505 rc = aEncoding->GetExternalSchemaURI(gSOAPStrings->kSOAPEncURI, ns);
508 else {
509 name = aName;
510 rc = aEncoding->GetExternalSchemaURI(aNamespaceURI, ns);
512 NS_ENSURE_SUCCESS(rc, rc);
514 nsCOMPtr<nsIDOMDocument> document;
515 rc = aDestination->GetOwnerDocument(getter_AddRefs(document));
516 NS_ENSURE_SUCCESS(rc, rc);
518 nsCOMPtr<nsIDOMElement> element;
519 rc = document->CreateElementNS(ns, name, getter_AddRefs(element));
520 NS_ENSURE_SUCCESS(rc, rc);
522 nsCOMPtr<nsIDOMNode> ignore;
523 rc = aDestination->AppendChild(element, getter_AddRefs(ignore));
524 NS_ENSURE_SUCCESS(rc, rc);
526 if (needType) {
527 if (typeNS.IsEmpty() && typeName.IsEmpty()) {
528 typeName = gSOAPStrings->kAnyTypeSchemaType;
529 rc = aEncoding->GetExternalSchemaURI(gSOAPStrings->kXSURI, typeNS);
530 NS_ENSURE_SUCCESS(rc, rc);
533 nsAutoString type;
534 rc = nsSOAPUtils::MakeNamespacePrefix(aEncoding, element,
535 typeNS, type);
536 NS_ENSURE_SUCCESS(rc, rc);
538 type.Append(gSOAPStrings->kQualifiedSeparator);
539 type.Append(typeName);
540 rc = aEncoding->GetExternalSchemaURI(gSOAPStrings->kXSIURI, ns);
541 NS_ENSURE_SUCCESS(rc, rc);
543 rc = (element)->
544 SetAttributeNS(ns, gSOAPStrings->kXSITypeAttribute, type);
545 NS_ENSURE_SUCCESS(rc, rc);
547 if (!aValue.IsEmpty()) {
548 nsCOMPtr<nsIDOMText> text;
549 rc = document->CreateTextNode(aValue, getter_AddRefs(text));
550 NS_ENSURE_SUCCESS(rc, rc);
552 rc = (element)->AppendChild(text, getter_AddRefs(ignore));
553 NS_ENSURE_SUCCESS(rc, rc);
556 NS_IF_ADDREF(*aResult = element);
557 return rc;
560 // Testing for a simple value
561 static nsresult HasSimpleValue(nsISchemaType * aSchemaType, PRBool * aResult) {
562 PRUint16 typevalue;
563 nsresult rc = aSchemaType->GetSchemaType(&typevalue);
564 NS_ENSURE_SUCCESS(rc, rc);
566 if (typevalue == nsISchemaComplexType::SCHEMA_TYPE_COMPLEX) {
567 nsCOMPtr<nsISchemaComplexType> ct = do_QueryInterface(aSchemaType);
568 rc = ct->GetContentModel(&typevalue);
569 NS_ENSURE_SUCCESS(rc, rc);
571 *aResult = typevalue == nsISchemaComplexType::CONTENT_MODEL_SIMPLE;
572 } else {
573 *aResult = PR_TRUE;
575 return NS_OK;
578 // Default
580 NS_IMETHODIMP
581 nsDefaultEncoder::Encode(nsISOAPEncoding* aEncoding,
582 nsIVariant* aSource,
583 const nsAString& aNamespaceURI,
584 const nsAString& aName,
585 nsISchemaType* aSchemaType,
586 nsISOAPAttachments* aAttachments,
587 nsIDOMElement* aDestination,
588 nsIDOMElement** aReturnValue)
590 NS_ENSURE_ARG_POINTER(aEncoding);
591 NS_ENSURE_ARG_POINTER(aDestination);
592 NS_ENSURE_ARG_POINTER(aReturnValue);
593 *aReturnValue = nsnull;
594 if (aSource == nsnull) {
595 nsAutoString ns;
596 nsresult rc = aEncoding->GetExternalSchemaURI(gSOAPStrings->kXSIURI, ns);
597 NS_ENSURE_SUCCESS(rc, rc);
599 nsAutoString name;
600 if (!aName.IsEmpty())
601 name.Assign(gSOAPStrings->kNull);
602 rc = EncodeSimpleValue(aEncoding, gSOAPStrings->kEmpty, gSOAPStrings->kEmpty,
603 name, nsnull, aDestination, aReturnValue);
604 NS_ENSURE_SUCCESS(rc, rc);
606 rc = (*aReturnValue)->SetAttributeNS(ns, gSOAPStrings->kNull, gSOAPStrings->kTrueA);
607 NS_ENSURE_SUCCESS(rc, rc);
609 nsCOMPtr<nsISOAPEncoder> encoder;
610 if (aSchemaType) {
611 nsCOMPtr<nsISchemaType> lookupType = aSchemaType;
612 do {
613 nsAutoString schemaType;
614 nsAutoString schemaURI;
615 nsAutoString encodingKey;
616 nsresult rc = lookupType->GetName(schemaType);
617 NS_ENSURE_SUCCESS(rc, rc);
619 rc = lookupType->GetTargetNamespace(schemaURI);
620 NS_ENSURE_SUCCESS(rc, rc);
622 SOAPEncodingKey(schemaURI, schemaType, encodingKey);
623 rc = aEncoding->GetEncoder(encodingKey, getter_AddRefs(encoder));
624 NS_ENSURE_SUCCESS(rc, rc);
626 if (encoder)
627 break;
628 nsCOMPtr<nsISchemaType> supertype;
629 rc = GetSupertype(aEncoding, lookupType, getter_AddRefs(supertype));
630 NS_ENSURE_SUCCESS(rc, rc);
632 lookupType = supertype;
634 while (lookupType);
636 if (!encoder) {
637 nsAutoString encodingKey;
638 SOAPEncodingKey(gSOAPStrings->kXSURI,
639 gSOAPStrings->kAnyTypeSchemaType, encodingKey);
640 nsresult rc =
641 aEncoding->GetEncoder(encodingKey, getter_AddRefs(encoder));
642 NS_ENSURE_SUCCESS(rc, rc);
644 if (encoder) {
645 return encoder->Encode(aEncoding, aSource, aNamespaceURI, aName,
646 aSchemaType, aAttachments, aDestination,
647 aReturnValue);
649 return SOAP_EXCEPTION(NS_ERROR_NOT_IMPLEMENTED,
650 "SOAP_NO_ENCODER_FOR_TYPE",
651 "The default encoder finds no encoder for specific type");
654 static void
655 GetNativeType(PRUint16 aType, nsAString & aSchemaNamespaceURI, nsAString & aSchemaType)
657 aSchemaNamespaceURI.Assign(gSOAPStrings->kXSURI);
658 switch (aType) {
659 case nsIDataType::VTYPE_CHAR_STR:
660 case nsIDataType::VTYPE_WCHAR_STR:
661 case nsIDataType::VTYPE_CHAR:
662 case nsIDataType::VTYPE_WCHAR:
663 case nsIDataType::VTYPE_STRING_SIZE_IS:
664 case nsIDataType::VTYPE_WSTRING_SIZE_IS:
665 case nsIDataType::VTYPE_ASTRING:
666 case nsIDataType::VTYPE_DOMSTRING:
667 case nsIDataType::VTYPE_CSTRING:
668 case nsIDataType::VTYPE_UTF8STRING:
669 aSchemaType.Assign(gSOAPStrings->kStringSchemaType);
670 break;
671 case nsIDataType::VTYPE_INT8:
672 aSchemaType.Assign(gSOAPStrings->kByteSchemaType);
673 break;
674 case nsIDataType::VTYPE_INT16:
675 aSchemaType.Assign(gSOAPStrings->kShortSchemaType);
676 break;
677 case nsIDataType::VTYPE_INT32:
678 aSchemaType.Assign(gSOAPStrings->kIntSchemaType);
679 break;
680 case nsIDataType::VTYPE_INT64:
681 aSchemaType.Assign(gSOAPStrings->kLongSchemaType);
682 break;
683 case nsIDataType::VTYPE_UINT8:
684 aSchemaType.Assign(gSOAPStrings->kUnsignedByteSchemaType);
685 break;
686 case nsIDataType::VTYPE_UINT16:
687 aSchemaType.Assign(gSOAPStrings->kUnsignedShortSchemaType);
688 break;
689 case nsIDataType::VTYPE_UINT32:
690 aSchemaType.Assign(gSOAPStrings->kUnsignedIntSchemaType);
691 break;
692 case nsIDataType::VTYPE_UINT64:
693 aSchemaType.Assign(gSOAPStrings->kUnsignedLongSchemaType);
694 break;
695 case nsIDataType::VTYPE_FLOAT:
696 aSchemaType.Assign(gSOAPStrings->kFloatSchemaType);
697 break;
698 case nsIDataType::VTYPE_DOUBLE:
699 aSchemaType.Assign(gSOAPStrings->kDoubleSchemaType);
700 break;
701 case nsIDataType::VTYPE_BOOL:
702 aSchemaType.Assign(gSOAPStrings->kBooleanSchemaType);
703 break;
704 case nsIDataType::VTYPE_ARRAY:
705 case nsIDataType::VTYPE_EMPTY_ARRAY:
706 aSchemaType.Assign(gSOAPStrings->kArraySOAPType);
707 aSchemaNamespaceURI.Assign(gSOAPStrings->kSOAPEncURI);
708 break;
709 // case nsIDataType::VTYPE_VOID:
710 // case nsIDataType::VTYPE_EMPTY:
711 // Empty may be either simple or complex.
712 break;
713 case nsIDataType::VTYPE_INTERFACE_IS:
714 case nsIDataType::VTYPE_INTERFACE:
715 aSchemaType.Assign(gSOAPStrings->kStructSOAPType);
716 aSchemaNamespaceURI.Assign(gSOAPStrings->kSOAPEncURI);
717 break;
718 default:
719 aSchemaType.Assign(gSOAPStrings->kAnySimpleTypeSchemaType);
723 NS_IMETHODIMP
724 nsAnyTypeEncoder::Encode(nsISOAPEncoding* aEncoding,
725 nsIVariant* aSource,
726 const nsAString& aNamespaceURI,
727 const nsAString& aName,
728 nsISchemaType* aSchemaType,
729 nsISOAPAttachments* aAttachments,
730 nsIDOMElement* aDestination,
731 nsIDOMElement** aReturnValue)
733 NS_ENSURE_ARG_POINTER(aEncoding);
734 NS_ENSURE_ARG_POINTER(aDestination);
735 NS_ENSURE_ARG_POINTER(aReturnValue);
736 *aReturnValue = nsnull;
737 nsAutoString nativeSchemaType;
738 nsAutoString nativeSchemaURI;
739 PRUint16 typevalue;
740 nsresult rc = aSource->GetDataType(&typevalue);
741 NS_ENSURE_SUCCESS(rc, rc);
743 // If there is a schema type then regular native types will not avail us anything.
744 if (aSchemaType) {
745 PRBool simple = PR_FALSE;
746 rc = HasSimpleValue(aSchemaType, &simple);
747 NS_ENSURE_SUCCESS(rc, rc);
749 if (simple) {
750 switch (typevalue) {
751 case nsIDataType::VTYPE_ARRAY:
752 case nsIDataType::VTYPE_EMPTY_ARRAY:
753 case nsIDataType::VTYPE_INTERFACE_IS:
754 case nsIDataType::VTYPE_INTERFACE:
755 simple = PR_FALSE;
756 break;
759 if (simple) {
760 nativeSchemaType.Assign(gSOAPStrings->kAnySimpleTypeSchemaType);
761 nativeSchemaURI.Assign(gSOAPStrings->kXSURI);
763 else {
764 nativeSchemaType.Assign(gSOAPStrings->kStructSOAPType);
765 nativeSchemaURI.Assign(gSOAPStrings->kSOAPEncURI);
768 else {
769 GetNativeType(typevalue, nativeSchemaURI, nativeSchemaType);
772 nsCOMPtr<nsISOAPEncoder> encoder;
773 nsAutoString encodingKey;
774 SOAPEncodingKey(nativeSchemaURI, nativeSchemaType, encodingKey);
775 rc = aEncoding->GetEncoder(encodingKey, getter_AddRefs(encoder));
776 NS_ENSURE_SUCCESS(rc, rc);
778 if (encoder) {
779 nsCOMPtr<nsISchemaType> type;
780 if (aSchemaType) {
781 type = aSchemaType;
783 else {
784 nsCOMPtr<nsISchemaCollection> collection;
785 nsresult rc =
786 aEncoding->GetSchemaCollection(getter_AddRefs(collection));
787 NS_ENSURE_SUCCESS(rc, rc);
789 rc = collection->GetType(nativeSchemaType,
790 nativeSchemaURI,
791 getter_AddRefs(type));
792 // if (NS_FAILED(rc)) return rc;
795 return encoder->Encode(aEncoding, aSource, aNamespaceURI, aName,
796 type, aAttachments, aDestination,
797 aReturnValue);
799 return SOAP_EXCEPTION(NS_ERROR_NOT_IMPLEMENTED,
800 "SOAP_NO_ENCODER_FOR_TYPE",
801 "The any type encoder finds no encoder for specific data");
804 static nsresult EncodeStructParticle(nsISOAPEncoding* aEncoding, nsIPropertyBag* aPropertyBag,
805 nsISchemaParticle* aParticle,
806 nsISOAPAttachments * aAttachments, nsIDOMElement* aDestination)
808 nsresult rc;
809 if (aParticle) {
810 PRUint32 minOccurs;
811 rc = aParticle->GetMinOccurs(&minOccurs);
812 NS_ENSURE_SUCCESS(rc, rc);
814 PRUint32 maxOccurs;
815 rc = aParticle->GetMaxOccurs(&maxOccurs);
816 NS_ENSURE_SUCCESS(rc, rc);
818 PRUint16 particleType;
819 rc = aParticle->GetParticleType(&particleType);
820 NS_ENSURE_SUCCESS(rc, rc);
822 switch(particleType) {
823 case nsISchemaParticle::PARTICLE_TYPE_ELEMENT: {
824 if (maxOccurs > 1) { // Todo: Try to make this thing work as an array?
825 return NS_ERROR_NOT_AVAILABLE; // For now, we just try something else if we can (recoverable)
827 nsCOMPtr<nsISchemaElement> element = do_QueryInterface(aParticle);
828 nsAutoString name;
829 rc = element->GetTargetNamespace(name);
830 NS_ENSURE_SUCCESS(rc, rc);
832 if (!name.IsEmpty()) {
833 rc = NS_ERROR_NOT_AVAILABLE; // No known way to use namespace qualification in struct
835 else {
836 rc = element->GetName(name);
837 NS_ENSURE_SUCCESS(rc, rc);
839 rc = element->GetName(name);
840 NS_ENSURE_SUCCESS(rc, rc);
842 nsCOMPtr<nsISchemaType> type;
843 rc = element->GetType(getter_AddRefs(type));
844 NS_ENSURE_SUCCESS(rc, rc);
846 nsCOMPtr<nsIVariant> value;
847 rc = aPropertyBag->GetProperty(name, getter_AddRefs(value));
848 if (NS_SUCCEEDED(rc)) {
849 nsCOMPtr<nsIDOMElement> dummy;
850 rc = aEncoding->Encode(value, gSOAPStrings->kEmpty, name, type, aAttachments, aDestination, getter_AddRefs(dummy));
851 NS_ENSURE_SUCCESS(rc, rc);
854 if (minOccurs == 0 && rc == NS_ERROR_NOT_AVAILABLE) {
855 // If we succeeded or failed recoverably, but we were permitted to,
856 // then return success
857 rc = NS_OK;
859 return rc;
861 case nsISchemaParticle::PARTICLE_TYPE_MODEL_GROUP:
863 if (maxOccurs > 1) { // Todo: Try to make this thing work as an array?
864 return NS_ERROR_NOT_AVAILABLE; // For now, we just try something else if we can (recoverable)
866 nsCOMPtr<nsISchemaModelGroup> modelGroup = do_QueryInterface(aParticle);
867 PRUint16 compositor;
868 rc = modelGroup->GetCompositor(&compositor);
869 NS_ENSURE_SUCCESS(rc, rc);
871 PRUint32 particleCount;
872 rc = modelGroup->GetParticleCount(&particleCount);
873 NS_ENSURE_SUCCESS(rc, rc);
875 PRUint32 i;
876 for (i = 0; i < particleCount; i++) {
877 nsCOMPtr<nsISchemaParticle> child;
878 rc = modelGroup->GetParticle(i, getter_AddRefs(child));
879 NS_ENSURE_SUCCESS(rc, rc);
881 rc = EncodeStructParticle(aEncoding, aPropertyBag, child, aAttachments, aDestination);
882 if (compositor == nsISchemaModelGroup::COMPOSITOR_CHOICE) {
883 if (NS_SUCCEEDED(rc)) {
884 return NS_OK;
886 if (rc == NS_ERROR_NOT_AVAILABLE) { // In a choice, recoverable model failures are OK.
887 rc = NS_OK;
890 else if (i > 0 && rc == NS_ERROR_NOT_AVAILABLE) { // This detects ambiguous model (non-deterministic choice which fails after succeeding on first)
891 return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,
892 "SOAP_AMBIGUOUS_ENCODING",
893 "Cannot proceed due to ambiguity or error in content model");
895 if (NS_FAILED(rc))
896 break;
898 if (compositor == nsISchemaModelGroup::COMPOSITOR_CHOICE) // If choice selected nothing, this is recoverable failure
899 rc = NS_ERROR_NOT_AVAILABLE;
900 if (minOccurs == 0 && rc == NS_ERROR_NOT_AVAILABLE) // If we succeeded or failed recoverably, but we were permitted to, then return success
901 rc = NS_OK;
902 return rc; // Return status
904 case nsISchemaParticle::PARTICLE_TYPE_ANY:
905 // No model available here (we may wish to handle strict versus lazy, but what does that mean with only local accessor names)
906 default:
907 break;
911 nsCOMPtr<nsISimpleEnumerator> e;
912 rc = aPropertyBag->GetEnumerator(getter_AddRefs(e));
913 NS_ENSURE_SUCCESS(rc, rc);
915 PRBool more;
916 rc = e->HasMoreElements(&more);
917 NS_ENSURE_SUCCESS(rc, rc);
919 while (more) {
920 nsCOMPtr<nsIProperty> p;
921 rc = e->GetNext(getter_AddRefs(p));
922 NS_ENSURE_SUCCESS(rc, rc);
924 nsAutoString name;
925 rc = p->GetName(name);
926 NS_ENSURE_SUCCESS(rc, rc);
928 nsCOMPtr<nsIVariant>value;
929 rc = p->GetValue(getter_AddRefs(value));
930 NS_ENSURE_SUCCESS(rc, rc);
932 nsCOMPtr<nsIDOMElement>result;
933 rc = aEncoding->Encode(value,gSOAPStrings->kEmpty,name,nsnull,aAttachments,aDestination,getter_AddRefs(result));
934 NS_ENSURE_SUCCESS(rc, rc);
936 rc = e->HasMoreElements(&more);
937 NS_ENSURE_SUCCESS(rc, rc);
939 return NS_OK;
942 NS_IMETHODIMP
943 nsStructEncoder::Encode(nsISOAPEncoding * aEncoding,
944 nsIVariant * aSource,
945 const nsAString & aNamespaceURI,
946 const nsAString & aName,
947 nsISchemaType * aSchemaType,
948 nsISOAPAttachments * aAttachments,
949 nsIDOMElement * aDestination,
950 nsIDOMElement * *aReturnValue)
952 NS_ENSURE_ARG_POINTER(aEncoding);
953 NS_ENSURE_ARG_POINTER(aDestination);
954 NS_ENSURE_ARG_POINTER(aReturnValue);
955 *aReturnValue = nsnull;
956 nsIID* iid;
957 nsCOMPtr<nsISupports> ptr;
958 nsresult rc = aSource->GetAsInterface(&iid, getter_AddRefs(ptr));
959 NS_ENSURE_SUCCESS(rc, rc);
961 nsCOMPtr<nsIPropertyBag>pbptr = do_QueryInterface(ptr);
962 if (pbptr) { // Do any object that can QI to a property bag.
963 nsCOMPtr<nsISchemaModelGroup>modelGroup;
964 if (aSchemaType) {
965 nsCOMPtr<nsISchemaComplexType>ctype = do_QueryInterface(aSchemaType);
966 if (ctype) {
967 rc = ctype->GetModelGroup(getter_AddRefs(modelGroup));
968 NS_ENSURE_SUCCESS(rc, rc);
971 // We still have to fake this one, because there is no struct type in schema.
972 if (aName.IsEmpty() && !aSchemaType) {
973 rc = EncodeSimpleValue(aEncoding, gSOAPStrings->kEmpty,
974 gSOAPStrings->kSOAPEncURI,
975 gSOAPStrings->kStructSOAPType,
976 aSchemaType, aDestination,
977 aReturnValue);
979 else {
980 rc = EncodeSimpleValue(aEncoding, gSOAPStrings->kEmpty,
981 aNamespaceURI, aName, aSchemaType, aDestination,
982 aReturnValue);
984 NS_ENSURE_SUCCESS(rc, rc);
986 return EncodeStructParticle(aEncoding, pbptr, modelGroup, aAttachments, *aReturnValue);
988 return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,
989 "SOAP_PROPERTYBAG_REQUIRED",
990 "When encoding as a struct, an object with properties is required");
993 // AnySimpleType
995 NS_IMETHODIMP
996 nsAnySimpleTypeEncoder::Encode(nsISOAPEncoding * aEncoding,
997 nsIVariant * aSource,
998 const nsAString & aNamespaceURI,
999 const nsAString & aName,
1000 nsISchemaType * aSchemaType,
1001 nsISOAPAttachments * aAttachments,
1002 nsIDOMElement * aDestination,
1003 nsIDOMElement * *aReturnValue)
1005 NS_ENSURE_ARG_POINTER(aEncoding);
1006 NS_ENSURE_ARG_POINTER(aDestination);
1007 NS_ENSURE_ARG_POINTER(aReturnValue);
1008 *aReturnValue = nsnull;
1009 nsresult rc;
1010 nsAutoString value;
1011 rc = aSource->GetAsAString(value);
1012 NS_ENSURE_SUCCESS(rc, rc);
1014 // We still have to fake this one, because there is no any simple type in schema.
1015 if (aName.IsEmpty() && !aSchemaType) {
1016 return EncodeSimpleValue(aEncoding,
1017 value,
1018 gSOAPStrings->kSOAPEncURI,
1019 gSOAPStrings->kAnySimpleTypeSchemaType,
1020 aSchemaType,
1021 aDestination,
1022 aReturnValue);
1024 return EncodeSimpleValue(aEncoding,
1025 value,
1026 aNamespaceURI,
1027 aName,
1028 aSchemaType,
1029 aDestination,
1030 aReturnValue);
1034 * Handle SOAP element mark as null with xsi:null or xsi:nil.
1036 * @param aEncoding SOAP encoding (in).
1037 * @param aSource SOAP DOM element (in).
1038 * @param aSchemaType Type of the SOAP element (in).
1039 * @param aAttachments (in).
1040 * @param aNullAttr Value for a xsi:null of xsi:nil attribute,
1041 * could be either true or 1 (in).
1042 * @param aResult Value for this element (out).
1044 static nsresult HandleNull(nsISOAPEncoding* aEncoding,
1045 nsIDOMElement* aSource,
1046 nsISchemaType* aSchemaType,
1047 nsISOAPAttachments* aAttachments,
1048 nsAutoString aNullAttr,
1049 nsIVariant** aResult)
1051 NS_ENSURE_ARG_POINTER(aEncoding);
1052 NS_ENSURE_ARG_POINTER(aSource);
1053 NS_ENSURE_ARG_POINTER(aResult);
1055 if (aNullAttr.Equals(gSOAPStrings->kTrue) ||
1056 aNullAttr.Equals(gSOAPStrings->kTrueA)) {
1058 PRUint16 schemaType;
1059 nsAutoString typeName;
1061 if (aSchemaType) {
1062 aSchemaType->GetSchemaType(&schemaType);
1063 aSchemaType->GetName(typeName);
1066 nsCOMPtr<nsIWritableVariant> nullVariant(do_CreateInstance("@mozilla.org/variant;1"));
1067 if (!nullVariant) {
1068 return NS_ERROR_OUT_OF_MEMORY;
1071 if (aSchemaType &&
1072 (typeName.Equals(NS_LITERAL_STRING("string")) ||
1073 typeName.Equals(NS_LITERAL_STRING("normalizedString")))) {
1075 nsAutoString strVal;
1076 strVal.SetIsVoid(true);
1078 nullVariant->SetAsAString(strVal);
1079 } else {
1080 nullVariant->SetAsISupports(nsnull);
1083 NS_ADDREF(*aResult = nullVariant);
1084 return NS_OK;
1085 } else if (!(aNullAttr.Equals(gSOAPStrings->kFalse) ||
1086 aNullAttr.Equals(gSOAPStrings->kFalseA))) {
1088 return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,
1089 "SOAP_NILL_VALUE",
1090 "The value of the nill attribute must be true or false.");
1092 #ifdef DEBUG
1093 NS_ERROR("How have you get here ?");
1094 #endif
1096 return NS_ERROR_UNEXPECTED;
1100 * SOAP code should be given the explit type not to have to look for it.
1101 * Get explicit schema type from SOAP DOM element.
1103 * @param aEncoding SOAP encoding (in).
1104 * @param aElement DOM element from SOAP response (in).
1105 * @param aResult Explicit schema type [xsi:type] (out).
1107 static nsresult GetExplicitType(nsISOAPEncoding* aEncoding,
1108 nsIDOMElement* aElement,
1109 nsISchemaType** aResult)
1111 NS_ENSURE_ARG_POINTER(aEncoding);
1112 NS_ENSURE_ARG_POINTER(aElement);
1114 nsresult rc = NS_OK;
1115 nsCOMPtr<nsISchemaLoader> schemaLoader =
1116 do_GetService(NS_SCHEMALOADER_CONTRACTID, &rc);
1117 NS_ENSURE_SUCCESS(rc, rc);
1118 nsAutoString explicitType;
1120 if (nsSOAPUtils::GetAttribute(aEncoding, aElement, gSOAPStrings->kXSIURI,
1121 gSOAPStrings->kXSITypeAttribute,
1122 explicitType)) {
1123 nsAutoString ns;
1124 nsAutoString name;
1125 nsCOMPtr<nsISchemaType> type;
1127 rc = nsSOAPUtils::GetNamespaceURI(aEncoding, aElement, explicitType, ns);
1128 NS_ENSURE_SUCCESS(rc, rc);
1129 rc = nsSOAPUtils::GetLocalName(explicitType, name);
1130 NS_ENSURE_SUCCESS(rc, rc);
1132 nsCOMPtr<nsISchemaCollection> col = do_QueryInterface(schemaLoader);
1133 rc = col->GetType(name, ns, getter_AddRefs(type));
1135 NS_IF_ADDREF(*aResult = type);
1136 return rc;
1138 #ifdef DEBUG
1139 NS_ERROR("::GetExplicitType: Wow how do you get here");
1140 #endif
1142 return NS_ERROR_UNEXPECTED;
1146 * Recursive method used by array encoding which counts the sizes of
1147 * the specified dimensions and does a very primitive determination whether
1148 * all the members of the array are of a single homogenious type.
1149 * This intelligently skips nulls wherever they occur.
1151 static nsresult GetArrayType(nsIVariant* aSource,
1152 PRUint32 aDimensionCount,
1153 PRUint32* aDimensionSizes,
1154 PRUint16* aType)
1156 if (!aSource) {
1157 *aType = nsIDataType::VTYPE_EMPTY;
1158 return NS_OK;
1160 PRUint16 type;
1161 nsIID iid;
1162 PRUint32 count;
1163 void* array;
1164 nsresult rc;
1165 PRUint32 i;
1166 rc = aSource->GetDataType(&type);
1167 NS_ENSURE_SUCCESS(rc, rc);
1169 if (type == nsIDataType::VTYPE_EMPTY ||
1170 type == nsIDataType::VTYPE_VOID ||
1171 type == nsIDataType::VTYPE_EMPTY_ARRAY) {
1172 rc = NS_OK;
1173 count = 0;
1174 type = nsIDataType::VTYPE_EMPTY;
1175 array = nsnull;
1177 else {
1178 rc = aSource->GetAsArray(&type, &iid, &count, &array); // First, get the array, if any.
1179 NS_ENSURE_SUCCESS(rc, rc);
1181 if (count > aDimensionSizes[0]) {
1182 aDimensionSizes[0] = count;
1184 if (aDimensionCount > 1) {
1185 if (type != nsIDataType::VTYPE_INTERFACE_IS ||
1186 !iid.Equals(NS_GET_IID(nsIVariant))) {
1187 rc = SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,"SOAP_ARRAY_OBJECTS","When encoding as an array, an array of array objects is required");
1188 // All nested arrays (which is what multi-dimensional arrays are) are variants.
1190 else {
1191 nsIVariant** a = static_cast<nsIVariant**>(array);
1192 PRUint16 rtype = nsIDataType::VTYPE_EMPTY;
1193 for (i = 0; i < count; i++) {
1194 PRUint16 nexttype;
1195 rc = GetArrayType(a[i], aDimensionCount - 1, aDimensionSizes + 1, &nexttype);
1196 if (NS_FAILED(rc))
1197 break;
1198 if (rtype == nsIDataType::VTYPE_EMPTY)
1199 rtype = nexttype;
1200 else if (nexttype != nsIDataType::VTYPE_EMPTY
1201 && nexttype != rtype)
1202 rtype = nsIDataType::VTYPE_INTERFACE_IS;
1204 *aType = rtype;
1207 else {
1208 *aType = type;
1210 // The memory model for variant arrays' GetAsArray is difficult to manage
1211 switch (type) {
1212 case nsIDataType::VTYPE_INTERFACE_IS:
1214 nsISupports** values = static_cast<nsISupports**>(array);
1215 for (i = 0; i < count; i++)
1216 NS_RELEASE(values[i]);
1218 break;
1219 case nsIDataType::VTYPE_WCHAR_STR:
1220 case nsIDataType::VTYPE_CHAR_STR:
1222 void** ptrs = static_cast<void**>(array);
1223 for (i = 0; i < count; i++) {
1224 nsMemory::Free(ptrs[i]);
1227 break;
1229 nsMemory::Free(array);
1230 { // Individual lengths guaranteed to fit because variant array length is 32-bit.
1231 PRUint64 tot = 1; // Collect in 64 bits, just to make sure combo fits
1232 for (i = 0; i < aDimensionCount; i++) {
1233 tot = tot * aDimensionSizes[i];
1234 if (tot > 0xffffffffU) {
1235 return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,
1236 "SOAP_ARRAY_TOO_BIG",
1237 "When encoding an object as an array, the total count of items exceeded maximum.");
1241 return rc;
1244 * Recursive method used by array encoding to encode the next level of the array into the
1245 * established array element. If dimension count is > 1, then it recursively doles out
1246 * the work. This intelligently skips nulls wherever they occur.
1248 static nsresult EncodeArray(nsISOAPEncoding* aEncoding, nsIVariant* aSource, nsISchemaType* aSchemaType,
1249 nsISOAPAttachments* aAttachments, nsIDOMElement* aArray, PRUint32 aDimensionCount, PRUint32* aDimensionSizes)
1251 nsresult rc;
1252 PRUint16 type;
1253 nsIID iid;
1254 PRUint32 count;
1255 void *array;
1256 if (aSource != nsnull) {
1257 rc = aSource->GetDataType(&type);
1258 NS_ENSURE_SUCCESS(rc, rc);
1260 if (type == nsIDataType::VTYPE_EMPTY ||
1261 type == nsIDataType::VTYPE_VOID ||
1262 type == nsIDataType::VTYPE_EMPTY_ARRAY) {
1263 rc = NS_OK;
1264 count = 0;
1265 type = nsIDataType::VTYPE_EMPTY;
1266 array = nsnull;
1268 else {
1269 rc = aSource->GetAsArray(&type, &iid, &count, &array); // First, get the array, if any.
1270 NS_ENSURE_SUCCESS(rc, rc);
1273 else { // If the source is null, then just add a bunch of nulls to the array.
1274 count = (PRUint32)aDimensionSizes[--aDimensionCount];
1275 while (aDimensionCount)
1276 count *= (PRUint32)aDimensionSizes[--aDimensionCount];
1277 if (count) {
1278 nsAutoString ns;
1279 nsCOMPtr<nsIDOMElement> cloneable;
1280 rc = aEncoding->GetExternalSchemaURI(gSOAPStrings->kXSIURI, ns);
1281 NS_ENSURE_SUCCESS(rc, rc);
1283 rc = EncodeSimpleValue(aEncoding, gSOAPStrings->kEmpty, gSOAPStrings->kEmpty,
1284 gSOAPStrings->kNull, nsnull, aArray, getter_AddRefs(cloneable));
1285 NS_ENSURE_SUCCESS(rc, rc);
1287 rc = cloneable->SetAttributeNS(ns, gSOAPStrings->kNull, gSOAPStrings->kTrueA);
1288 NS_ENSURE_SUCCESS(rc, rc);
1290 nsCOMPtr<nsIDOMNode> clone;
1291 nsCOMPtr<nsIDOMNode> dummy;
1292 for (;--count;) {
1293 rc = cloneable->CloneNode(PR_TRUE, getter_AddRefs(clone));// No children so deep == shallow
1294 NS_ENSURE_SUCCESS(rc, rc);
1296 rc = aArray->AppendChild(clone, getter_AddRefs(dummy));
1297 NS_ENSURE_SUCCESS(rc, rc);
1301 nsCOMPtr<nsIDOMElement> dummy;
1302 PRBool freeptrs = PR_FALSE;
1303 PRUint32 i;
1305 // The more-robust way of encoding is to construct variants and call the encoder directly,
1306 // but for now, we short-circuit it for simple types.
1308 #define ENCODE_SIMPLE_ARRAY(XPType, VType, Source) \
1310 XPType* values = static_cast<XPType*>(array); \
1311 nsCOMPtr<nsIWritableVariant> p = \
1312 do_CreateInstance(NS_VARIANT_CONTRACTID, &rc); \
1313 if (NS_FAILED(rc)) break; \
1314 for (i = 0; i < count; i++) { \
1315 if (NS_FAILED(rc)) \
1316 break; \
1317 rc = p->SetAs##VType(Source); \
1318 if (NS_FAILED(rc)) \
1319 break; \
1320 rc = aEncoding->Encode(p, \
1321 gSOAPStrings->kEmpty, \
1322 gSOAPStrings->kEmpty, \
1323 aSchemaType, \
1324 aAttachments, \
1325 aArray, \
1326 getter_AddRefs(dummy)); \
1327 if (NS_FAILED(rc)) break; \
1329 break; \
1332 if (aDimensionCount > 1) {
1333 switch (type) {
1334 case nsIDataType::VTYPE_INTERFACE_IS:
1336 nsIVariant** values = static_cast<nsIVariant**>(array);// If not truly a variant, we only release.
1337 if (iid.Equals(NS_GET_IID(nsIVariant))) { // Only do variants for now.
1338 for (i = 0; i < count; i++) {
1339 rc = EncodeArray(aEncoding, values[i],
1340 aSchemaType,
1341 aAttachments,
1342 aArray,
1343 aDimensionCount - 1,
1344 aDimensionSizes + 1);
1345 if (NS_FAILED(rc)) break;
1348 for (i = 0; i < count; i++)
1349 NS_RELEASE(values[i]);
1350 break;
1352 case nsIDataType::VTYPE_WCHAR_STR:
1353 case nsIDataType::VTYPE_CHAR_STR:
1354 freeptrs = PR_TRUE;
1355 default:
1356 rc = SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,"SOAP_ARRAY_OBJECTS","When encoding as an array, an array of array objects is required");
1358 } else switch (type) {
1359 case nsIDataType::VTYPE_INT8:
1360 ENCODE_SIMPLE_ARRAY(PRUint8, Int8,
1361 (signed char) values[i]);
1362 case nsIDataType::VTYPE_INT16:
1363 ENCODE_SIMPLE_ARRAY(PRInt16, Int16, values[i]);
1364 case nsIDataType::VTYPE_INT32:
1365 ENCODE_SIMPLE_ARRAY(PRInt32, Int32, values[i]);
1366 case nsIDataType::VTYPE_INT64:
1367 ENCODE_SIMPLE_ARRAY(PRInt64, Int64, values[i]);
1368 case nsIDataType::VTYPE_UINT8:
1369 ENCODE_SIMPLE_ARRAY(PRUint8, Uint8, values[i]);
1370 case nsIDataType::VTYPE_UINT16:
1371 ENCODE_SIMPLE_ARRAY(PRUint16, Uint16, values[i]);
1372 case nsIDataType::VTYPE_UINT32:
1373 ENCODE_SIMPLE_ARRAY(PRUint32, Uint32, values[i]);
1374 case nsIDataType::VTYPE_UINT64:
1375 ENCODE_SIMPLE_ARRAY(PRUint64, Uint64, values[i]);
1376 case nsIDataType::VTYPE_FLOAT:
1377 ENCODE_SIMPLE_ARRAY(float, Float, values[i]);
1378 case nsIDataType::VTYPE_DOUBLE:
1379 ENCODE_SIMPLE_ARRAY(double, Double, values[i]);
1380 case nsIDataType::VTYPE_BOOL:
1381 ENCODE_SIMPLE_ARRAY(PRBool, Bool, (PRUint16) values[i]);
1382 case nsIDataType::VTYPE_ID:
1383 case nsIDataType::VTYPE_CHAR_STR:
1384 freeptrs = PR_TRUE;
1385 ENCODE_SIMPLE_ARRAY(char *, String, values[i]);
1386 case nsIDataType::VTYPE_WCHAR_STR:
1387 freeptrs = PR_TRUE;
1388 ENCODE_SIMPLE_ARRAY(PRUnichar *, WString, values[i]);
1389 case nsIDataType::VTYPE_CHAR:
1390 ENCODE_SIMPLE_ARRAY(char, Char, values[i]);
1391 case nsIDataType::VTYPE_WCHAR:
1392 ENCODE_SIMPLE_ARRAY(PRUnichar, WChar, values[i]);
1393 case nsIDataType::VTYPE_INTERFACE_IS:
1395 nsIVariant** values = static_cast<nsIVariant**>(array);// If not truly a variant, we only use as nsISupports
1396 if (iid.Equals(NS_GET_IID(nsIVariant))) { // Only do variants for now.
1397 for (i = 0; i < count; i++) {
1398 rc = aEncoding->Encode(values[i],
1399 gSOAPStrings->kEmpty,
1400 gSOAPStrings->kEmpty,
1401 aSchemaType,
1402 aAttachments,
1403 aArray,
1404 getter_AddRefs(dummy));
1405 if (NS_FAILED(rc)) break;
1408 else {
1409 nsCOMPtr<nsIWritableVariant> p =
1410 do_CreateInstance(NS_VARIANT_CONTRACTID, &rc);
1411 if (NS_FAILED(rc)) break;
1412 for (i = 0; i < count; i++) {
1413 if (NS_FAILED(rc))
1414 break;
1415 rc = p->SetAsInterface(iid, values[i]);
1416 if (NS_FAILED(rc))
1417 break;
1418 rc = aEncoding->Encode(p,
1419 gSOAPStrings->kEmpty,
1420 gSOAPStrings->kEmpty,
1421 aSchemaType,
1422 aAttachments,
1423 aArray,
1424 getter_AddRefs(dummy));
1425 if (NS_FAILED(rc)) break;
1428 for (i = 0; i < count; i++)
1429 NS_RELEASE(values[i]);
1430 break;
1433 case nsIDataType::VTYPE_EMPTY_ARRAY:
1434 case nsIDataType::VTYPE_EMPTY:
1435 break; // I think an empty array needs no elements?
1436 // Don't support these array types, as they seem meaningless.
1437 case nsIDataType::VTYPE_ASTRING:
1438 case nsIDataType::VTYPE_VOID:
1439 case nsIDataType::VTYPE_INTERFACE:
1440 case nsIDataType::VTYPE_ARRAY:
1441 rc = SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,"SOAP_ARRAY_TYPES","When encoding an array, unable to handle array elements");
1443 if (freeptrs) {
1444 void** ptrs = static_cast<void**>(array);
1445 for (i = 0; i < count; i++) {
1446 nsMemory::Free(ptrs[i]);
1448 nsMemory::Free(array);
1450 // We know that count does not exceed size of dimension, but it may be less
1451 return rc;
1454 NS_IMETHODIMP
1455 nsArrayEncoder::Encode(nsISOAPEncoding * aEncoding,
1456 nsIVariant * aSource,
1457 const nsAString & aNamespaceURI,
1458 const nsAString & aName,
1459 nsISchemaType * aSchemaType,
1460 nsISOAPAttachments * aAttachments,
1461 nsIDOMElement * aDestination,
1462 nsIDOMElement * *aReturnValue)
1464 NS_ENSURE_ARG_POINTER(aEncoding);
1465 NS_ENSURE_ARG_POINTER(aDestination);
1466 NS_ENSURE_ARG_POINTER(aReturnValue);
1467 *aReturnValue = nsnull;
1468 PRUint16 arrayNativeType;
1469 PRUint32 dimensionSizes[MAX_ARRAY_DIMENSIONS];
1470 PRUint32 i;
1471 PRUint32 dimensionCount = 1;
1472 nsCOMPtr<nsISchemaType> schemaArrayType;
1473 if (aSchemaType) {
1474 PRUint16 type;
1475 nsresult rc = aSchemaType->GetSchemaType(&type);
1476 NS_ENSURE_SUCCESS(rc, rc);
1478 if (type == nsISchemaType::SCHEMA_TYPE_COMPLEX) {
1479 nsCOMPtr<nsISchemaComplexType> ct = do_QueryInterface(aSchemaType);
1480 nsresult rc = ct->GetArrayDimension(&dimensionCount);
1481 NS_ENSURE_SUCCESS(rc, rc);
1483 if (dimensionCount == 0) {
1484 dimensionCount = 1;
1486 else {
1487 // Arrays with no defaults are supposed to return 0, but apparently do not
1488 rc = ct->GetArrayType(getter_AddRefs(schemaArrayType));
1489 NS_ENSURE_SUCCESS(rc, rc);
1493 for (i = 0; i < dimensionCount; i++)
1494 dimensionSizes[i] = 0;
1495 // Look over the array and find its dimensions and common type.
1496 nsresult rc = GetArrayType(aSource, dimensionCount, dimensionSizes, &arrayNativeType);
1497 NS_ENSURE_SUCCESS(rc, rc);
1499 nsAutoString arrayTypeSchemaURI;
1500 nsAutoString arrayTypeSchemaName;
1501 if (!schemaArrayType) {
1502 switch (arrayNativeType) {
1503 case nsIDataType::VTYPE_INTERFACE: // In a variant, an interface is a struct, but here it is any
1504 case nsIDataType::VTYPE_INTERFACE_IS:
1505 arrayTypeSchemaName = gSOAPStrings->kAnyTypeSchemaType;
1506 arrayTypeSchemaURI = gSOAPStrings->kXSURI;
1507 break;
1508 default: // Everything else can be interpreted correctly
1509 GetNativeType(arrayNativeType, arrayTypeSchemaURI, arrayTypeSchemaName);
1511 nsCOMPtr<nsISchemaCollection> collection;
1512 nsresult rc =
1513 aEncoding->GetSchemaCollection(getter_AddRefs(collection));
1514 NS_ENSURE_SUCCESS(rc, rc);
1516 rc = collection->GetType(arrayTypeSchemaName,
1517 arrayTypeSchemaName,
1518 getter_AddRefs(schemaArrayType));
1519 // if (NS_FAILED(rc)) return rc;
1521 else {
1522 rc = schemaArrayType->GetTargetNamespace(arrayTypeSchemaURI);
1523 NS_ENSURE_SUCCESS(rc, rc);
1525 rc = schemaArrayType->GetName(arrayTypeSchemaName);
1526 NS_ENSURE_SUCCESS(rc, rc);
1528 rc = EncodeSimpleValue(aEncoding, gSOAPStrings->kEmpty,
1529 aNamespaceURI,
1530 aName, aSchemaType, aDestination, aReturnValue);
1531 NS_ENSURE_SUCCESS(rc, rc);
1533 // This needs a real live interpretation of the type.
1536 nsAutoString value;
1537 nsSOAPUtils::MakeNamespacePrefix(aEncoding,*aReturnValue,arrayTypeSchemaURI,value);
1538 value.Append(gSOAPStrings->kQualifiedSeparator);
1539 value.Append(arrayTypeSchemaName);
1540 value.Append(PRUnichar('['));
1541 for (i = 0; i < dimensionCount; i++) {
1542 if (i > 0)
1543 value.Append(PRUnichar(','));
1544 char* ptr = PR_smprintf("%d", dimensionSizes[i]);
1545 AppendUTF8toUTF16(ptr, value);
1546 PR_smprintf_free(ptr);
1548 value.Append(PRUnichar(']'));
1549 nsAutoString encURI;
1550 rc = aEncoding->GetExternalSchemaURI(gSOAPStrings->kSOAPEncURI,encURI);
1551 NS_ENSURE_SUCCESS(rc, rc);
1553 rc = (*aReturnValue)->SetAttributeNS(encURI, gSOAPStrings->kSOAPArrayTypeAttribute, value);
1554 NS_ENSURE_SUCCESS(rc, rc);
1557 // For efficiency, we should perform encoder lookup once here.
1559 return EncodeArray(aEncoding, aSource, schemaArrayType, aAttachments, *aReturnValue, dimensionCount, dimensionSizes);
1562 // String
1564 NS_IMETHODIMP
1565 nsStringEncoder::Encode(nsISOAPEncoding * aEncoding,
1566 nsIVariant * aSource,
1567 const nsAString & aNamespaceURI,
1568 const nsAString & aName,
1569 nsISchemaType * aSchemaType,
1570 nsISOAPAttachments * aAttachments,
1571 nsIDOMElement * aDestination,
1572 nsIDOMElement * *aReturnValue)
1574 NS_ENSURE_ARG_POINTER(aEncoding);
1575 NS_ENSURE_ARG_POINTER(aDestination);
1576 NS_ENSURE_ARG_POINTER(aReturnValue);
1577 *aReturnValue = nsnull;
1578 nsresult rc;
1579 nsAutoString value;
1580 rc = aSource->GetAsAString(value);
1581 NS_ENSURE_SUCCESS(rc, rc);
1583 return EncodeSimpleValue(aEncoding, value,
1584 aNamespaceURI, aName, aSchemaType, aDestination,
1585 aReturnValue);
1588 // PRBool
1590 NS_IMETHODIMP
1591 nsBooleanEncoder::Encode(nsISOAPEncoding * aEncoding,
1592 nsIVariant * aSource,
1593 const nsAString & aNamespaceURI,
1594 const nsAString & aName,
1595 nsISchemaType * aSchemaType,
1596 nsISOAPAttachments * aAttachments,
1597 nsIDOMElement * aDestination,
1598 nsIDOMElement * *aReturnValue)
1600 NS_ENSURE_ARG_POINTER(aEncoding);
1601 NS_ENSURE_ARG_POINTER(aDestination);
1602 NS_ENSURE_ARG_POINTER(aReturnValue);
1603 *aReturnValue = nsnull;
1604 nsresult rc;
1605 PRBool b;
1606 rc = aSource->GetAsBool(&b);
1607 NS_ENSURE_SUCCESS(rc, rc);
1609 return EncodeSimpleValue(aEncoding, b ? gSOAPStrings->kTrueA : gSOAPStrings->kFalseA,
1610 aNamespaceURI, aName, aSchemaType, aDestination,
1611 aReturnValue);
1614 // Double
1616 NS_IMETHODIMP
1617 nsDoubleEncoder::Encode(nsISOAPEncoding * aEncoding,
1618 nsIVariant * aSource,
1619 const nsAString & aNamespaceURI,
1620 const nsAString & aName,
1621 nsISchemaType * aSchemaType,
1622 nsISOAPAttachments * aAttachments,
1623 nsIDOMElement * aDestination,
1624 nsIDOMElement * *aReturnValue)
1626 NS_ENSURE_ARG_POINTER(aEncoding);
1627 NS_ENSURE_ARG_POINTER(aDestination);
1628 NS_ENSURE_ARG_POINTER(aReturnValue);
1629 *aReturnValue = nsnull;
1630 nsresult rc;
1631 double f;
1632 rc = aSource->GetAsDouble(&f); // Check that double works.
1633 NS_ENSURE_SUCCESS(rc, rc);
1635 nsAutoString value;
1636 // Note that AppendFloat actually takes a double, so this is ok.
1637 value.AppendFloat(f);
1638 return EncodeSimpleValue(aEncoding, value,
1639 aNamespaceURI, aName, aSchemaType, aDestination,
1640 aReturnValue);
1643 // Float
1645 NS_IMETHODIMP
1646 nsFloatEncoder::Encode(nsISOAPEncoding * aEncoding,
1647 nsIVariant * aSource,
1648 const nsAString & aNamespaceURI,
1649 const nsAString & aName,
1650 nsISchemaType * aSchemaType,
1651 nsISOAPAttachments * aAttachments,
1652 nsIDOMElement * aDestination,
1653 nsIDOMElement * *aReturnValue)
1655 NS_ENSURE_ARG_POINTER(aEncoding);
1656 NS_ENSURE_ARG_POINTER(aDestination);
1657 NS_ENSURE_ARG_POINTER(aReturnValue);
1658 *aReturnValue = nsnull;
1659 nsresult rc;
1660 float f;
1661 rc = aSource->GetAsFloat(&f); // Check that float works.
1662 NS_ENSURE_SUCCESS(rc, rc);
1664 nsAutoString value;
1665 value.AppendFloat(f);
1666 return EncodeSimpleValue(aEncoding, value,
1667 aNamespaceURI, aName, aSchemaType, aDestination,
1668 aReturnValue);
1671 // PRInt64
1673 NS_IMETHODIMP
1674 nsLongEncoder::Encode(nsISOAPEncoding * aEncoding,
1675 nsIVariant * aSource,
1676 const nsAString & aNamespaceURI,
1677 const nsAString & aName,
1678 nsISchemaType * aSchemaType,
1679 nsISOAPAttachments * aAttachments,
1680 nsIDOMElement * aDestination,
1681 nsIDOMElement * *aReturnValue)
1683 NS_ENSURE_ARG_POINTER(aEncoding);
1684 NS_ENSURE_ARG_POINTER(aDestination);
1685 NS_ENSURE_ARG_POINTER(aReturnValue);
1686 *aReturnValue = nsnull;
1687 nsresult rc;
1688 PRInt64 f;
1689 rc = aSource->GetAsInt64(&f); // Get as a long number.
1690 NS_ENSURE_SUCCESS(rc, rc);
1692 char *ptr = PR_smprintf("%lld", f);
1693 if (!ptr)
1694 return NS_ERROR_OUT_OF_MEMORY;
1695 nsAutoString value;
1696 CopyASCIItoUTF16(nsDependentCString(ptr), value);
1697 PR_smprintf_free(ptr);
1698 return EncodeSimpleValue(aEncoding, value,
1699 aNamespaceURI, aName, aSchemaType, aDestination,
1700 aReturnValue);
1703 // PRInt32
1705 NS_IMETHODIMP
1706 nsIntEncoder::Encode(nsISOAPEncoding * aEncoding,
1707 nsIVariant * aSource,
1708 const nsAString & aNamespaceURI,
1709 const nsAString & aName,
1710 nsISchemaType * aSchemaType,
1711 nsISOAPAttachments * aAttachments,
1712 nsIDOMElement * aDestination,
1713 nsIDOMElement * *aReturnValue)
1715 NS_ENSURE_ARG_POINTER(aEncoding);
1716 NS_ENSURE_ARG_POINTER(aDestination);
1717 NS_ENSURE_ARG_POINTER(aReturnValue);
1718 *aReturnValue = nsnull;
1719 nsresult rc;
1720 PRInt32 f;
1721 rc = aSource->GetAsInt32(&f); // Get as a long number.
1722 NS_ENSURE_SUCCESS(rc, rc);
1724 char *ptr = PR_smprintf("%d", f);
1725 if (!ptr)
1726 return NS_ERROR_OUT_OF_MEMORY;
1727 nsAutoString value;
1728 CopyASCIItoUTF16(nsDependentCString(ptr), value);
1729 PR_smprintf_free(ptr);
1730 return EncodeSimpleValue(aEncoding, value,
1731 aNamespaceURI, aName, aSchemaType, aDestination,
1732 aReturnValue);
1735 // PRInt16
1737 NS_IMETHODIMP
1738 nsShortEncoder::Encode(nsISOAPEncoding * aEncoding,
1739 nsIVariant * aSource,
1740 const nsAString & aNamespaceURI,
1741 const nsAString & aName,
1742 nsISchemaType * aSchemaType,
1743 nsISOAPAttachments * aAttachments,
1744 nsIDOMElement * aDestination,
1745 nsIDOMElement * *aReturnValue)
1747 NS_ENSURE_ARG_POINTER(aEncoding);
1748 NS_ENSURE_ARG_POINTER(aDestination);
1749 NS_ENSURE_ARG_POINTER(aReturnValue);
1750 *aReturnValue = nsnull;
1751 nsresult rc;
1752 PRInt16 f;
1753 rc = aSource->GetAsInt16(&f); // Get as a long number.
1754 NS_ENSURE_SUCCESS(rc, rc);
1756 char *ptr = PR_smprintf("%d", (PRInt32) f);
1757 if (!ptr)
1758 return NS_ERROR_OUT_OF_MEMORY;
1759 nsAutoString value;
1760 CopyASCIItoUTF16(nsDependentCString(ptr), value);
1761 PR_smprintf_free(ptr);
1762 return EncodeSimpleValue(aEncoding, value,
1763 aNamespaceURI, aName, aSchemaType, aDestination,
1764 aReturnValue);
1767 // Byte
1769 NS_IMETHODIMP
1770 nsByteEncoder::Encode(nsISOAPEncoding * aEncoding,
1771 nsIVariant * aSource,
1772 const nsAString & aNamespaceURI,
1773 const nsAString & aName,
1774 nsISchemaType * aSchemaType,
1775 nsISOAPAttachments * aAttachments,
1776 nsIDOMElement * aDestination,
1777 nsIDOMElement * *aReturnValue)
1779 NS_ENSURE_ARG_POINTER(aEncoding);
1780 NS_ENSURE_ARG_POINTER(aDestination);
1781 NS_ENSURE_ARG_POINTER(aReturnValue);
1782 *aReturnValue = nsnull;
1783 nsresult rc;
1784 PRUint8 f;
1785 rc = aSource->GetAsInt8(&f); // Get as a long number.
1786 NS_ENSURE_SUCCESS(rc, rc);
1788 char *ptr = PR_smprintf("%d", (PRInt32) (signed char) f);
1789 if (!ptr)
1790 return NS_ERROR_OUT_OF_MEMORY;
1791 nsAutoString value;
1792 CopyASCIItoUTF16(nsDependentCString(ptr), value);
1793 PR_smprintf_free(ptr);
1794 return EncodeSimpleValue(aEncoding, value,
1795 aNamespaceURI, aName, aSchemaType, aDestination,
1796 aReturnValue);
1799 // PRUint64
1801 NS_IMETHODIMP
1802 nsUnsignedLongEncoder::Encode(nsISOAPEncoding * aEncoding,
1803 nsIVariant * aSource,
1804 const nsAString & aNamespaceURI,
1805 const nsAString & aName,
1806 nsISchemaType * aSchemaType,
1807 nsISOAPAttachments * aAttachments,
1808 nsIDOMElement * aDestination,
1809 nsIDOMElement * *aReturnValue)
1811 NS_ENSURE_ARG_POINTER(aEncoding);
1812 NS_ENSURE_ARG_POINTER(aDestination);
1813 NS_ENSURE_ARG_POINTER(aReturnValue);
1814 *aReturnValue = nsnull;
1815 nsresult rc;
1816 PRUint64 f;
1817 rc = aSource->GetAsUint64(&f); // Get as a long number.
1818 NS_ENSURE_SUCCESS(rc, rc);
1820 char *ptr = PR_smprintf("%llu", f);
1821 if (!ptr)
1822 return NS_ERROR_OUT_OF_MEMORY;
1823 nsAutoString value;
1824 CopyASCIItoUTF16(nsDependentCString(ptr), value);
1825 PR_smprintf_free(ptr);
1826 return EncodeSimpleValue(aEncoding, value,
1827 aNamespaceURI, aName, aSchemaType, aDestination,
1828 aReturnValue);
1831 // PRUint32
1833 NS_IMETHODIMP
1834 nsUnsignedIntEncoder::Encode(nsISOAPEncoding * aEncoding,
1835 nsIVariant * aSource,
1836 const nsAString & aNamespaceURI,
1837 const nsAString & aName,
1838 nsISchemaType * aSchemaType,
1839 nsISOAPAttachments * aAttachments,
1840 nsIDOMElement * aDestination,
1841 nsIDOMElement * *aReturnValue)
1843 NS_ENSURE_ARG_POINTER(aEncoding);
1844 NS_ENSURE_ARG_POINTER(aDestination);
1845 NS_ENSURE_ARG_POINTER(aReturnValue);
1846 *aReturnValue = nsnull;
1847 nsresult rc;
1848 PRUint32 f;
1849 rc = aSource->GetAsUint32(&f); // Get as a long number.
1850 NS_ENSURE_SUCCESS(rc, rc);
1852 char *ptr = PR_smprintf("%u", f);
1853 if (!ptr)
1854 return NS_ERROR_OUT_OF_MEMORY;
1855 nsAutoString value;
1856 CopyASCIItoUTF16(nsDependentCString(ptr), value);
1857 PR_smprintf_free(ptr);
1858 return EncodeSimpleValue(aEncoding, value,
1859 aNamespaceURI, aName, aSchemaType, aDestination,
1860 aReturnValue);
1863 NS_IMETHODIMP
1864 nsBase64BinaryEncoder::Encode(nsISOAPEncoding * aEncoding,
1865 nsIVariant * aSource,
1866 const nsAString & aNamespaceURI,
1867 const nsAString & aName,
1868 nsISchemaType * aSchemaType,
1869 nsISOAPAttachments * aAttachments,
1870 nsIDOMElement * aDestination,
1871 nsIDOMElement * *aReturnValue)
1873 NS_ENSURE_ARG_POINTER(aSource);
1874 NS_ENSURE_ARG_POINTER(aEncoding);
1875 NS_ENSURE_ARG_POINTER(aDestination);
1876 NS_ENSURE_ARG_POINTER(aReturnValue);
1878 *aReturnValue = nsnull;
1880 PRUint16 typeValue;
1881 nsresult rv = aSource->GetDataType(&typeValue);
1882 NS_ENSURE_SUCCESS(rv, rv);
1884 if (typeValue != nsIDataType::VTYPE_ARRAY) {
1885 return NS_ERROR_FAILURE;
1888 nsIID iid;
1889 PRUint32 count;
1890 void* array;
1891 rv = aSource->GetAsArray(&typeValue, &iid, &count, &array);
1892 NS_ENSURE_SUCCESS(rv, rv);
1894 if (typeValue != nsIDataType::VTYPE_UINT8) {
1895 return NS_ERROR_FAILURE;
1898 char* encodedVal = PL_Base64Encode(static_cast<char*>(array), count, nsnull);
1899 if (!encodedVal) {
1900 return NS_ERROR_FAILURE;
1902 nsAdoptingCString encodedString(encodedVal);
1904 nsAutoString name, ns;
1905 if (aName.IsEmpty()) {
1906 // If we don't have a name, we pick soapenc:base64Binary.
1907 rv = aEncoding->GetStyleURI(ns);
1908 NS_ENSURE_SUCCESS(rv, rv);
1909 name.Append(gSOAPStrings->kBase64BinarySchemaType);
1911 else {
1912 name = aName;
1913 // ns remains empty. This is ok.
1916 nsCOMPtr<nsIDOMDocument> document;
1917 rv = aDestination->GetOwnerDocument(getter_AddRefs(document));
1918 NS_ENSURE_SUCCESS(rv, rv);
1920 nsCOMPtr<nsIDOMElement> element;
1921 rv = document->CreateElementNS(ns, name, getter_AddRefs(element));
1922 NS_ENSURE_SUCCESS(rv, rv);
1924 nsCOMPtr<nsIDOMNode> ignore;
1925 rv = aDestination->AppendChild(element, getter_AddRefs(ignore));
1926 NS_ENSURE_SUCCESS(rv, rv);
1928 if (aSchemaType) {
1929 nsAutoString typeName, typeNS;
1930 rv = aSchemaType->GetName(typeName);
1931 NS_ENSURE_SUCCESS(rv, rv);
1932 rv = aSchemaType->GetTargetNamespace(typeNS);
1933 NS_ENSURE_SUCCESS(rv, rv);
1935 nsAutoString qname;
1936 rv = nsSOAPUtils::MakeNamespacePrefix(nsnull, element, typeNS, qname);
1937 NS_ENSURE_SUCCESS(rv, rv);
1939 qname.Append(gSOAPStrings->kQualifiedSeparator + typeName);
1941 nsAutoString ns;
1942 rv = aEncoding->GetExternalSchemaURI(gSOAPStrings->kXSIURI, ns);
1943 NS_ENSURE_SUCCESS(rv, rv);
1945 rv = element->SetAttributeNS(ns, gSOAPStrings->kXSITypeAttribute, qname);
1946 NS_ENSURE_SUCCESS(rv, rv);
1949 nsCOMPtr<nsIDOMText> text;
1950 rv = document->CreateTextNode(NS_ConvertASCIItoUTF16(encodedString),
1951 getter_AddRefs(text));
1952 NS_ENSURE_SUCCESS(rv, rv);
1954 rv = element->AppendChild(text, getter_AddRefs(ignore));
1955 NS_ENSURE_SUCCESS(rv, rv);
1957 NS_ADDREF(*aReturnValue = element);
1958 return rv;
1962 // PRUint16
1964 NS_IMETHODIMP
1965 nsUnsignedShortEncoder::Encode(nsISOAPEncoding * aEncoding,
1966 nsIVariant * aSource,
1967 const nsAString & aNamespaceURI,
1968 const nsAString & aName,
1969 nsISchemaType * aSchemaType,
1970 nsISOAPAttachments * aAttachments,
1971 nsIDOMElement * aDestination,
1972 nsIDOMElement * *aReturnValue)
1974 NS_ENSURE_ARG_POINTER(aEncoding);
1975 NS_ENSURE_ARG_POINTER(aDestination);
1976 NS_ENSURE_ARG_POINTER(aReturnValue);
1977 *aReturnValue = nsnull;
1978 nsresult rc;
1979 PRUint16 f;
1980 rc = aSource->GetAsUint16(&f); // Get as a long number.
1981 NS_ENSURE_SUCCESS(rc, rc);
1983 char *ptr = PR_smprintf("%u", (PRUint32) f);
1984 if (!ptr)
1985 return NS_ERROR_OUT_OF_MEMORY;
1986 nsAutoString value;
1987 CopyASCIItoUTF16(nsDependentCString(ptr), value);
1988 PR_smprintf_free(ptr);
1989 return EncodeSimpleValue(aEncoding, value,
1990 aNamespaceURI, aName, aSchemaType, aDestination,
1991 aReturnValue);
1994 // Unsigned Byte
1996 NS_IMETHODIMP
1997 nsUnsignedByteEncoder::Encode(nsISOAPEncoding * aEncoding,
1998 nsIVariant * aSource,
1999 const nsAString & aNamespaceURI,
2000 const nsAString & aName,
2001 nsISchemaType * aSchemaType,
2002 nsISOAPAttachments * aAttachments,
2003 nsIDOMElement * aDestination,
2004 nsIDOMElement * *aReturnValue)
2006 NS_ENSURE_ARG_POINTER(aEncoding);
2007 NS_ENSURE_ARG_POINTER(aDestination);
2008 NS_ENSURE_ARG_POINTER(aReturnValue);
2009 *aReturnValue = nsnull;
2010 nsresult rc;
2011 PRUint8 f;
2012 rc = aSource->GetAsUint8(&f); // Get as a long number.
2013 NS_ENSURE_SUCCESS(rc, rc);
2015 char *ptr = PR_smprintf("%u", (PRUint32) f);
2016 if (!ptr)
2017 return NS_ERROR_OUT_OF_MEMORY;
2018 nsAutoString value;
2019 CopyASCIItoUTF16(nsDependentCString(ptr), value);
2020 PR_smprintf_free(ptr);
2021 return EncodeSimpleValue(aEncoding, value,
2022 aNamespaceURI, aName, aSchemaType, aDestination,
2023 aReturnValue);
2026 NS_IMETHODIMP
2027 nsDefaultEncoder::Decode(nsISOAPEncoding* aEncoding,
2028 nsIDOMElement* aSource,
2029 nsISchemaType* aSchemaType,
2030 nsISOAPAttachments* aAttachments,
2031 nsIVariant** aResult)
2033 NS_ENSURE_ARG_POINTER(aEncoding);
2034 NS_ENSURE_ARG_POINTER(aSource);
2035 NS_ENSURE_ARG_POINTER(aResult);
2036 *aResult = nsnull;
2037 nsCOMPtr<nsISOAPEncoding> encoding = aEncoding; // First, handle encoding redesignation, if any
2038 nsCOMPtr<nsISchemaType> schemaType;
2039 nsresult rv = GetExplicitType(aEncoding, aSource, getter_AddRefs(schemaType));
2041 if (NS_FAILED(rv) || !schemaType) {
2042 schemaType = aSchemaType;
2046 nsCOMPtr<nsIDOMAttr> enc;
2047 nsresult rv =
2048 aSource->
2049 GetAttributeNodeNS(*gSOAPStrings->kSOAPEnvURI[mSOAPVersion],
2050 gSOAPStrings->kEncodingStyleAttribute,
2051 getter_AddRefs(enc));
2052 NS_ENSURE_SUCCESS(rv, rv);
2054 if (enc) {
2055 nsAutoString oldstyle;
2056 rv = encoding->GetStyleURI(oldstyle);
2057 NS_ENSURE_SUCCESS(rv, rv);
2059 nsAutoString style;
2060 rv = enc->GetNodeValue(style);
2061 NS_ENSURE_SUCCESS(rv, rv);
2063 if (!style.Equals(oldstyle)) {
2064 nsCOMPtr<nsISOAPEncoding> newencoding;
2065 rv = encoding->GetAssociatedEncoding(style, PR_FALSE,
2066 getter_AddRefs(newencoding));
2067 NS_ENSURE_SUCCESS(rv, rv);
2069 if (newencoding) {
2070 return newencoding->Decode(aSource, aSchemaType, aAttachments, aResult);
2076 // Handle xsi:null="true|1" and xsi:nil="true|1"
2078 nsAutoString nullstr;
2079 if (nsSOAPUtils::GetAttribute(aEncoding,
2080 aSource,
2081 gSOAPStrings->kXSIURI,
2082 gSOAPStrings->kNull,
2083 nullstr) ||
2084 nsSOAPUtils::GetAttribute(aEncoding,
2085 aSource,
2086 gSOAPStrings->kXSIURI,
2087 gSOAPStrings->kNil,
2088 nullstr)) {
2090 return HandleNull(aEncoding,
2091 aSource,
2092 schemaType,
2093 aAttachments,
2094 nullstr,
2095 aResult);
2099 nsCOMPtr<nsISchemaType> type = schemaType;
2100 nsCOMPtr<nsISOAPDecoder> decoder; // All that comes out of this block is decoder, type, and some checks.
2101 { // Look up type element and schema attribute, if possible
2102 nsCOMPtr<nsISchemaType> subType;
2103 nsCOMPtr<nsISchemaCollection> collection;
2104 nsresult rc =
2105 aEncoding->GetSchemaCollection(getter_AddRefs(collection));
2106 NS_ENSURE_SUCCESS(rc, rc);
2108 nsAutoString ns;
2109 nsAutoString name;
2111 rc = aSource->GetNamespaceURI(name);
2112 NS_ENSURE_SUCCESS(rc, rc);
2114 rc = aEncoding->GetInternalSchemaURI(name, ns);
2115 NS_ENSURE_SUCCESS(rc, rc);
2117 rc = aSource->GetLocalName(name);
2118 NS_ENSURE_SUCCESS(rc, rc);
2120 nsCOMPtr<nsISchemaElement> element;
2121 rc = collection->GetElement(name, ns, getter_AddRefs(element));
2122 // if (NS_FAILED(rc)) return rc;
2123 if (element) {
2124 rc = element->GetType(getter_AddRefs(subType));
2125 NS_ENSURE_SUCCESS(rc, rc);
2126 } else {
2127 nsAutoString internal;
2128 rc = aEncoding->GetInternalSchemaURI(ns, internal);
2129 NS_ENSURE_SUCCESS(rc, rc);
2131 if (internal.Equals(gSOAPStrings->kSOAPEncURI)) { // Last-ditch hack to get undeclared types from SOAP namespace
2132 if (name.Equals(gSOAPStrings->kArraySOAPType) ||
2133 name.Equals(gSOAPStrings->kStructSOAPType)) { // This should not be needed if schema has these declarations
2134 rc = collection->GetType(name, internal, getter_AddRefs(subType));
2135 } else {
2136 rc = collection->GetType(name,
2137 gSOAPStrings->kXSURI,
2138 getter_AddRefs(subType));
2141 // if (NS_FAILED(rc)) return rc;
2143 if (!subType)
2144 subType = type;
2146 nsCOMPtr<nsISchemaType> subsubType;
2147 nsAutoString explicitType;
2148 if (nsSOAPUtils::GetAttribute(aEncoding, aSource, gSOAPStrings->kXSIURI,
2149 gSOAPStrings->kXSITypeAttribute,
2150 explicitType)) {
2151 rc = nsSOAPUtils::GetNamespaceURI(aEncoding, aSource, explicitType, ns);
2152 NS_ENSURE_SUCCESS(rc, rc);
2154 rc = nsSOAPUtils::GetLocalName(explicitType, name);
2155 NS_ENSURE_SUCCESS(rc, rc);
2157 rc = collection->GetType(name, ns, getter_AddRefs(subsubType));
2158 // if (NS_FAILED(rc)) return rc;
2160 if (!subsubType)
2161 subsubType = subType;
2163 if (subsubType) { // Loop up the hierarchy, to check and look for decoders
2164 for(;;) {
2165 nsCOMPtr<nsISchemaType> lookupType = subsubType;
2166 do {
2167 if (lookupType == subType) { // Tick off the located super classes
2168 subType = nsnull;
2170 if (lookupType == type) { // Tick off the located super classes
2171 type = nsnull;
2173 if (!decoder) {
2174 nsAutoString schemaType;
2175 nsAutoString schemaURI;
2176 nsresult rc = lookupType->GetName(schemaType);
2177 NS_ENSURE_SUCCESS(rc, rc);
2179 rc = lookupType->GetTargetNamespace(schemaURI);
2180 NS_ENSURE_SUCCESS(rc, rc);
2182 nsAutoString encodingKey;
2183 SOAPEncodingKey(schemaURI, schemaType, encodingKey);
2184 rc = aEncoding->GetDecoder(encodingKey, getter_AddRefs(decoder));
2185 NS_ENSURE_SUCCESS(rc, rc);
2187 nsCOMPtr<nsISchemaType> supertype;
2188 rc = GetSupertype(aEncoding, lookupType, getter_AddRefs(supertype));
2189 NS_ENSURE_SUCCESS(rc, rc);
2191 lookupType = supertype;
2192 } while (lookupType);
2193 if (!type) {
2194 type = subsubType;
2195 break;
2197 decoder = nsnull;
2198 if (!subType) {
2199 subType = type;
2201 subsubType = subType;
2205 if (!decoder) {
2206 PRBool simple = PR_TRUE;
2207 if (type) {
2208 nsresult rc = HasSimpleValue(type, &simple);
2209 NS_ENSURE_SUCCESS(rc, rc);
2211 if (simple) {
2212 nsCOMPtr<nsIDOMElement> child;
2213 nsSOAPUtils::GetFirstChildElement(aSource, getter_AddRefs(child));
2214 simple = !child;
2216 nsAutoString decodingKey;
2217 if (!simple) {
2218 SOAPEncodingKey(gSOAPStrings->kSOAPEncURI,
2219 gSOAPStrings->kStructSOAPType, decodingKey);
2220 } else {
2221 SOAPEncodingKey(gSOAPStrings->kXSURI,
2222 gSOAPStrings->kAnySimpleTypeSchemaType, decodingKey);
2224 nsresult rc =
2225 aEncoding->GetDecoder(decodingKey, getter_AddRefs(decoder));
2226 NS_ENSURE_SUCCESS(rc, rc);
2228 if (decoder) {
2229 return decoder->Decode(aEncoding, aSource, type, aAttachments,
2230 aResult);
2233 return SOAP_EXCEPTION(NS_ERROR_NOT_IMPLEMENTED,
2234 "SOAP_NO_DECODER_FOR_TYPE",
2235 "The default decoder finds no decoder for specific type");
2238 NS_IMETHODIMP
2239 nsAnyTypeEncoder::Decode(nsISOAPEncoding * aEncoding,
2240 nsIDOMElement * aSource,
2241 nsISchemaType * aSchemaType,
2242 nsISOAPAttachments * aAttachments,
2243 nsIVariant ** _retval)
2245 NS_ENSURE_ARG_POINTER(aEncoding);
2246 NS_ENSURE_ARG_POINTER(aSource);
2247 NS_ENSURE_ARG_POINTER(_retval);
2248 *_retval = nsnull;
2249 PRBool simple = PR_TRUE;
2250 if (aSchemaType) {
2251 nsresult rc = HasSimpleValue(aSchemaType, &simple);
2252 NS_ENSURE_SUCCESS(rc, rc);
2254 if (simple) {
2255 nsCOMPtr<nsIDOMElement> child;
2256 nsSOAPUtils::GetFirstChildElement(aSource, getter_AddRefs(child));
2257 simple = !child;
2259 nsAutoString decodingKey;
2260 if (!simple) {
2261 SOAPEncodingKey(gSOAPStrings->kSOAPEncURI,
2262 gSOAPStrings->kStructSOAPType, decodingKey);
2263 } else {
2264 SOAPEncodingKey(gSOAPStrings->kXSURI,
2265 gSOAPStrings->kAnySimpleTypeSchemaType, decodingKey);
2267 nsCOMPtr<nsISOAPDecoder> decoder;
2268 nsresult rc =
2269 aEncoding->GetDecoder(decodingKey, getter_AddRefs(decoder));
2270 NS_ENSURE_SUCCESS(rc, rc);
2272 if (decoder) {
2273 return decoder->Decode(aEncoding, aSource,
2274 aSchemaType, aAttachments, _retval);
2275 return rc;
2277 return SOAP_EXCEPTION(NS_ERROR_NOT_IMPLEMENTED,"SOAP_NO_DECODER_FOR_TYPE","The any type decoder finds no decoder for specific element");
2281 * Decode struct particle. If particle is model group this method
2282 * call itself recursively for each particle contained in the model group.
2284 * @param aEncoding SOAP encoding to be used (in).
2285 * @param aElement DOM element representing particle to be decoded (in).
2286 * @param aParticle Schema particle that should declare struct particle (in).
2287 * @param aAttachments SOAP attachments (in).
2288 * @param aDestination Property bag where to stored decoded particle (in).
2289 * @param aResult Remaining DOM element to be decoded, left over one (out).
2291 static nsresult DecodeStructParticle(nsISOAPEncoding* aEncoding,
2292 nsIDOMElement* aElement,
2293 nsISchemaParticle* aParticle,
2294 nsISOAPAttachments * aAttachments,
2295 nsISOAPPropertyBagMutator* aDestination,
2296 nsIDOMElement** aResult)
2298 nsresult rc;
2299 *aResult = nsnull;
2300 if (aParticle) {
2301 PRUint32 minOccurs;
2302 rc = aParticle->GetMinOccurs(&minOccurs);
2303 NS_ENSURE_SUCCESS(rc, rc);
2305 PRUint32 maxOccurs;
2306 rc = aParticle->GetMaxOccurs(&maxOccurs);
2307 NS_ENSURE_SUCCESS(rc, rc);
2309 PRUint16 particleType;
2310 rc = aParticle->GetParticleType(&particleType);
2311 NS_ENSURE_SUCCESS(rc, rc);
2313 switch(particleType) {
2314 case nsISchemaParticle::PARTICLE_TYPE_ELEMENT: {
2315 if (maxOccurs > 1) { // Todo: Try to make this thing work as an array?
2316 return NS_ERROR_NOT_AVAILABLE; // For now, we just try something else if we can (recoverable)
2318 nsCOMPtr<nsISchemaElement> element = do_QueryInterface(aParticle);
2319 nsAutoString name;
2320 rc = element->GetTargetNamespace(name);
2321 NS_ENSURE_SUCCESS(rc, rc);
2323 if (!name.IsEmpty()) {
2324 rc = NS_ERROR_NOT_AVAILABLE; // No known way to use namespace qualification in struct
2326 else {
2327 rc = element->GetName(name);
2328 NS_ENSURE_SUCCESS(rc, rc);
2330 nsAutoString ename;
2331 if (aElement) { // Permits aElement to be null and fail recoverably
2332 nsAutoString temp;
2333 rc = aElement->GetNamespaceURI(ename);
2334 NS_ENSURE_SUCCESS(rc, rc);
2336 if (ename.IsEmpty()) { // Only get an ename if there is an empty namespaceURI
2337 rc = aElement->GetLocalName(ename);
2338 NS_ENSURE_SUCCESS(rc, rc);
2341 if (!ename.Equals(name))
2342 rc = NS_ERROR_NOT_AVAILABLE; // The element must be a declaration of the next element
2344 if (NS_SUCCEEDED(rc)) {
2345 nsCOMPtr<nsISchemaType> type;
2346 rc = element->GetType(getter_AddRefs(type));
2347 NS_ENSURE_SUCCESS(rc, rc);
2349 nsCOMPtr<nsIVariant> value;
2350 rc = aEncoding->Decode(aElement, type, aAttachments, getter_AddRefs(value));
2351 NS_ENSURE_SUCCESS(rc, rc);
2353 if (!value) {
2354 nsCOMPtr<nsIWritableVariant> nullVariant(do_CreateInstance("@mozilla.org/variant;1"));
2355 if (nullVariant) {
2356 nullVariant->SetAsISupports(nsnull);
2357 value = do_QueryInterface(nullVariant);
2360 rc = aDestination->AddProperty(name, value);
2361 NS_ENSURE_SUCCESS(rc, rc);
2363 nsSOAPUtils::GetNextSiblingElement(aElement, aResult);
2365 if (minOccurs == 0 && rc == NS_ERROR_NOT_AVAILABLE) { // If we failed recoverably, but we were permitted to, then return success
2366 NS_IF_ADDREF(*aResult = aElement);
2367 rc = NS_OK;
2369 return rc;
2371 case nsISchemaParticle::PARTICLE_TYPE_MODEL_GROUP:
2373 if (maxOccurs > 1) { // Todo: Try to make this thing work as an array?
2374 return NS_ERROR_NOT_AVAILABLE; // For now, we just try something else if we can (recoverable)
2376 nsCOMPtr<nsISchemaModelGroup> modelGroup = do_QueryInterface(aParticle);
2377 PRUint16 compositor;
2378 rc = modelGroup->GetCompositor(&compositor);
2379 NS_ENSURE_SUCCESS(rc, rc);
2381 PRUint32 particleCount;
2382 rc = modelGroup->GetParticleCount(&particleCount);
2383 NS_ENSURE_SUCCESS(rc, rc);
2385 PRUint32 i;
2386 if (compositor == nsISchemaModelGroup::COMPOSITOR_ALL) { // This handles out-of-order appearances.
2387 // Use hashtable to be able to get corresponding particle
2388 // according SOAP element name not according schema order
2389 // as a <all> model group is used
2390 nsInterfaceHashtable<nsStringHashKey,nsISchemaParticle> groupParticles;
2391 groupParticles.Init(particleCount);
2392 nsCOMPtr<nsISchemaParticle> child;
2393 PRBool mangled = PR_FALSE;
2395 // Build schema particle mappings from model group
2396 for (i = 0; i < particleCount; i++) {
2397 rc = modelGroup->GetParticle(i, getter_AddRefs(child));
2398 NS_ENSURE_SUCCESS(rc, rc);
2400 nsAutoString particleName;
2401 rc = child->GetName(particleName);
2402 NS_ENSURE_SUCCESS(rc, rc);
2404 rc = groupParticles.Put(particleName, child);
2405 NS_ENSURE_SUCCESS(rc, rc);
2408 nsCOMPtr<nsIDOMElement> next = aElement;
2409 PRBool decoded;
2412 Since we are an xsd:all, the order of elements in the schema type
2413 does not matter. So we go element by element in the XML fragment
2414 we are decoding. We loop through all schema particles defined for
2415 this type until we find one that DecodeStructParticle succeeds on.
2416 DecodeStructParticle returns |after| with is what is left to decode,
2417 so we can figure if the decoding succeeded by checking if |after|
2418 is not equal to the element we are decoding (|next|).
2420 We track if we couldn't decode using the |decoded| boolean. If we
2421 exit the particle walking for loop and |decoded| is false, we bail.
2423 XXX: what if we get out of the while loop, and |all| still has
2424 particles? Should we walk them and see if any are minOccurs > 0
2425 and return an error?
2428 // loop as long as we have something to decode.
2429 while (next) {
2430 decoded = PR_FALSE;
2432 // we cycle through the schema particles
2433 for (i = 0; i < particleCount; i++) {
2434 nsAutoString name;
2435 rc = next->GetTagName(name);
2436 NS_ENSURE_SUCCESS(rc, rc);
2438 // Get schema particle according SOAP element
2439 groupParticles.Get(name, getter_AddRefs(child));
2441 if (NS_FAILED(rc) || !child) {
2442 #ifdef DEBUG
2443 nsAutoString msg(NS_LITERAL_STRING("::DecodeStructParticle: "));
2444 msg.AppendLiteral("Cannot find schema particle for \"");
2445 msg.Append(name);
2446 msg.AppendLiteral("\"");
2447 NS_ERROR(NS_ConvertUTF16toUTF8(msg).get());
2448 #endif
2451 nsCOMPtr<nsIDOMElement> after;
2452 rc = DecodeStructParticle(aEncoding, next, child, aAttachments, aDestination, getter_AddRefs(after));
2454 // DecodeStructParticle returns success even if decoding didn't
2455 // work. So we check if after != next to see if it did succeed.
2456 if (NS_SUCCEEDED(rc) && after != next) {
2457 decoded = PR_TRUE;
2458 next = after;
2459 mangled = PR_TRUE;
2460 groupParticles.Remove(name);
2461 particleCount--;
2462 break;
2466 // This detects ambiguous model (non-deterministic choice which
2467 // fails after succeeding on first)
2468 if ((mangled && rc == NS_ERROR_NOT_AVAILABLE) || !decoded) {
2469 rc = SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,"SOAP_AMBIGUOUS_DECODING","Cannot proceed due to ambiguity or error in content model");
2470 // Error is not considered recoverable due to partially-created output.
2473 // if we failed to decode after the for loop, abort.
2474 if (NS_FAILED(rc) || !decoded)
2475 break;
2478 // if *aResult is not null, then caller knows we couldn't decode
2479 // everything.
2480 if (NS_SUCCEEDED(rc)) {
2481 NS_IF_ADDREF(*aResult = next);
2482 } else if (minOccurs == 0 && rc == NS_ERROR_NOT_AVAILABLE) {
2483 // If we succeeded or failed recoverably, but we were permitted to,
2484 // then return success
2485 NS_IF_ADDREF(*aResult = aElement);
2486 rc = NS_OK;
2489 else { // This handles sequences and choices.
2490 nsCOMPtr<nsIDOMElement> next = aElement;
2491 for (i = 0; i < particleCount; i++) {
2492 nsCOMPtr<nsISchemaParticle> child;
2493 rc = modelGroup->GetParticle(i, getter_AddRefs(child));
2494 NS_ENSURE_SUCCESS(rc, rc);
2496 nsCOMPtr<nsIDOMElement> after;
2497 rc = DecodeStructParticle(aEncoding, next, child, aAttachments, aDestination, getter_AddRefs(after));
2498 if (NS_SUCCEEDED(rc)) {
2499 next = after;
2501 if (compositor == nsISchemaModelGroup::COMPOSITOR_CHOICE) {
2502 if (rc == NS_ERROR_NOT_AVAILABLE) {
2503 rc = NS_OK;
2505 else {
2506 if (NS_SUCCEEDED(rc)) {
2507 NS_IF_ADDREF(*aResult = next);
2509 return rc;
2512 else if (i > 0 && rc == NS_ERROR_NOT_AVAILABLE) { // This detects ambiguous model (non-deterministic choice which fails after succeeding on first)
2513 rc = SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,"SOAP_AMBIGUOUS_DECODING","Cannot proceed due to ambiguity or error in content model");
2514 // Error is not considered recoverable due to partially-created output.
2516 if (NS_FAILED(rc))
2517 break;
2519 if (compositor == nsISchemaModelGroup::COMPOSITOR_CHOICE)
2520 rc = NS_ERROR_NOT_AVAILABLE;
2521 if (NS_SUCCEEDED(rc)) {
2522 NS_IF_ADDREF(*aResult = next);
2524 if (minOccurs == 0 && rc == NS_ERROR_NOT_AVAILABLE) { // If we succeeded or failed recoverably, but we were permitted to, then return success
2525 NS_IF_ADDREF(*aResult = aElement);
2526 rc = NS_OK;
2529 return rc; // Return status
2531 case nsISchemaParticle::PARTICLE_TYPE_ANY:
2532 // No model available here (we may wish to handle strict versus lazy, but what does that mean with only local accessor names)
2533 default:
2534 break;
2538 nsCOMPtr<nsIDOMElement> child = aElement;
2539 while (child) {
2540 nsAutoString name;
2541 nsAutoString namespaceURI;
2542 nsCOMPtr<nsIVariant>value;
2543 rc = child->GetLocalName(name);
2544 NS_ENSURE_SUCCESS(rc, rc);
2546 rc = child->GetNamespaceURI(namespaceURI);
2547 NS_ENSURE_SUCCESS(rc, rc);
2549 if (!namespaceURI.IsEmpty()) { // If we ever figure out what to do with namespaces, get an internal one
2550 return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,
2551 "SOAP_GLOBAL_ACCESSOR",
2552 "Decoded struct contained global accessor, which does not map well into a property name.");
2554 rc = aEncoding->Decode(child, nsnull, aAttachments, getter_AddRefs(value));
2555 NS_ENSURE_SUCCESS(rc, rc);
2557 if (!value) {
2558 nsCOMPtr<nsIWritableVariant> nullVariant(do_CreateInstance("@mozilla.org/variant;1"));
2559 if (nullVariant) {
2560 nullVariant->SetAsISupports(nsnull);
2561 value = do_QueryInterface(nullVariant);
2564 rc = aDestination->AddProperty(name, value);
2565 NS_ENSURE_SUCCESS(rc, rc);
2567 nsCOMPtr<nsIDOMElement> nextchild;
2568 nsSOAPUtils::GetNextSiblingElement(child, getter_AddRefs(nextchild));
2569 child = nextchild;
2571 *aResult = nsnull;
2572 return NS_OK;
2575 NS_IMETHODIMP
2576 nsStructEncoder::Decode(nsISOAPEncoding* aEncoding,
2577 nsIDOMElement* aSource,
2578 nsISchemaType* aSchemaType,
2579 nsISOAPAttachments* aAttachments,
2580 nsIVariant** aResult)
2582 NS_ENSURE_ARG_POINTER(aEncoding);
2583 NS_ENSURE_ARG_POINTER(aSource);
2584 NS_ENSURE_ARG_POINTER(aResult);
2585 *aResult = nsnull;
2586 nsresult rc;
2587 nsCOMPtr<nsISOAPPropertyBagMutator> mutator = do_CreateInstance(NS_SOAPPROPERTYBAGMUTATOR_CONTRACTID, &rc);
2588 NS_ENSURE_SUCCESS(rc, rc);
2590 nsCOMPtr<nsISchemaModelGroup> modelGroup;
2591 if (aSchemaType) {
2592 nsCOMPtr<nsISchemaComplexType> ctype = do_QueryInterface(aSchemaType);
2593 if (ctype) {
2594 rc = ctype->GetModelGroup(getter_AddRefs(modelGroup));
2595 NS_ENSURE_SUCCESS(rc, rc);
2598 nsCOMPtr<nsIDOMElement> child;
2599 nsSOAPUtils::GetFirstChildElement(aSource, getter_AddRefs(child));
2600 nsCOMPtr<nsIDOMElement> result;
2601 rc = DecodeStructParticle(aEncoding, child, modelGroup, aAttachments, mutator, getter_AddRefs(result));
2602 if (NS_SUCCEEDED(rc) // If there were elements left over, then we failed to decode everything.
2603 && result)
2604 rc = SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,"SOAP_LEFTOVERS","Decoded struct contained extra items not mentioned in the content model.");
2605 NS_ENSURE_SUCCESS(rc, rc);
2607 nsCOMPtr<nsIPropertyBag> bag;
2608 rc = mutator->GetPropertyBag(getter_AddRefs(bag));
2609 NS_ENSURE_SUCCESS(rc, rc);
2611 nsCOMPtr<nsIWritableVariant> p =
2612 do_CreateInstance(NS_VARIANT_CONTRACTID, &rc);
2613 NS_ENSURE_SUCCESS(rc, rc);
2615 rc = p->SetAsInterface(NS_GET_IID(nsIPropertyBag), bag);
2616 NS_ENSURE_SUCCESS(rc, rc);
2618 NS_ADDREF(*aResult = p);
2619 return NS_OK;
2622 NS_IMETHODIMP
2623 nsAnySimpleTypeEncoder::Decode(nsISOAPEncoding* aEncoding,
2624 nsIDOMElement* aSource,
2625 nsISchemaType* aSchemaType,
2626 nsISOAPAttachments* aAttachments,
2627 nsIVariant** aResult)
2629 NS_ENSURE_ARG_POINTER(aEncoding);
2630 NS_ENSURE_ARG_POINTER(aSource);
2631 NS_ENSURE_ARG_POINTER(aResult);
2632 *aResult = nsnull;
2633 nsAutoString value;
2634 nsresult rc = nsSOAPUtils::GetElementTextContent(aSource, value);
2635 NS_ENSURE_SUCCESS(rc, rc);
2637 nsCOMPtr<nsIWritableVariant> p =
2638 do_CreateInstance(NS_VARIANT_CONTRACTID, &rc);
2639 NS_ENSURE_SUCCESS(rc, rc);
2641 rc = p->SetAsAString(value);
2642 NS_ENSURE_SUCCESS(rc, rc);
2644 NS_ADDREF(*aResult = p);
2645 return NS_OK;
2649 * Extract multiple bracketted numbers from the end of
2650 * the string and return the string with the number
2651 * removed or return the original string and -1. Either
2652 * the number of dimensions or the size of any particular
2653 * dimension can be returned as -1. An over-all 0
2654 * means that either there were no dimensions or there
2655 * was a fundamental problem interpreting it. A
2656 * -1 on any particular size of a dimension means that
2657 * that particular size was not available or was not
2658 * interpretable. That may be a recoverable error
2659 * if the values represented a size, because we can
2660 * manually scan the array, but that shouldbe fatal
2661 * if specifying a position. In these cases, the
2662 * bracketted values are removed.
2664 static PRUint32 DecodeArrayDimensions(const nsAString& src, PRInt32* aDimensionSizes, nsAString & dst)
2666 dst.Assign(src);
2667 nsReadingIterator < PRUnichar > i1;
2668 nsReadingIterator < PRUnichar > i2;
2669 src.BeginReading(i1);
2670 src.EndReading(i2);
2671 if (src.IsEmpty()) return 0;
2672 while (i1 != i2 // Loop past white space
2673 && *(--i2) <= ' ') // In XML, all valid characters <= space are the only whitespace
2675 if (*i2 != ']') { // In this case, not an array dimension
2676 PRInt32 len = Distance(i1, i2) - 1; // This is the size to truncate to at the end.
2677 dst = Substring(src, 0, len); // Truncate the string.
2678 return 0; // Eliminated white space.
2681 PRInt32 dimensionCount = 1; // Counting the dimensions
2682 for (;;) { // First look for the matching bracket from reverse and commas.
2683 if (i1 == i2) { // No matching bracket.
2684 return 0;
2686 PRUnichar c = *(--i2);
2687 if (c == '[') { // Matching bracket found!
2688 break;
2690 if (c == ',') {
2691 dimensionCount++;
2694 PRInt32 len;
2696 nsReadingIterator < PRUnichar > i3 = i2++; // Cover any extra white space
2697 while (i1 != i3) { // Loop past white space
2698 if (*(--i3) > ' ') { // In XML, all valid characters <= space are the only whitespace
2699 i3++;
2700 break;
2703 len = Distance(i1, i3); // Length remaining in string after operation
2706 if (dimensionCount > MAX_ARRAY_DIMENSIONS) { // Completely ignore it if too many dimensions.
2707 return 0;
2710 i1 = i2;
2711 src.EndReading(i2);
2712 while (*(--i2) != ']') // Find end bracket again
2715 dimensionCount = 0; // Start with first dimension.
2716 aDimensionSizes[dimensionCount] = -1;
2717 PRBool finished = PR_FALSE; // Disallow space within numbers
2719 while (i1 != i2) {
2720 PRUnichar c = *(i1++);
2721 if (c < '0' || c > '9') {
2722 // There may be slightly more to do here if alternative radixes are supported.
2723 if (c <= ' ') { // In XML, all valid characters <= space are the only whitespace
2724 if (aDimensionSizes[dimensionCount] >= 0) {
2725 finished = PR_TRUE;
2728 else if (c == ',') { // Introducing new dimension
2729 aDimensionSizes[++dimensionCount] = -1; // Restarting it at -1
2730 finished = PR_FALSE;
2732 else
2733 return 0; // Unrecognized character
2734 } else {
2735 if (finished) {
2736 return 0; // Numbers not allowed after white space
2738 if (aDimensionSizes[dimensionCount] == -1)
2739 aDimensionSizes[dimensionCount] = 0;
2740 if (aDimensionSizes[dimensionCount] < 214748364) {
2741 aDimensionSizes[dimensionCount] = aDimensionSizes[dimensionCount] * 10 + c - '0';
2743 else {
2744 return 0; // Number got too big.
2748 dst = Substring(src, 0, len); // Truncate the string.
2749 return dimensionCount + 1; // Return the number of dimensions
2753 * Extract multiple bracketted numbers from the end of
2754 * the string and reconcile with a passed-in set of
2755 * dimensions, computing the offset in the array.
2756 * Presumes that the caller already knows the dimensions
2757 * fit into 32-bit signed integer, due to computing
2758 * total size of array.
2760 * If there is extra garbage within the
2761 * Any blank or unreadable dimensions or extra garbage
2762 * within the string result in a return of -1, which is
2763 * bad wherever a position string was interpreted.
2765 static PRInt32 DecodeArrayPosition(const nsAString& src, PRUint32 aDimensionCount, PRInt32* aDimensionSizes)
2767 PRInt32 pos[MAX_ARRAY_DIMENSIONS];
2768 nsAutoString leftover;
2769 PRUint32 i = DecodeArrayDimensions(src, pos, leftover);
2770 if (i != aDimensionCount || !leftover.IsEmpty()) {
2771 // Easy cases where something went wrong
2772 return -1;
2774 PRInt32 result = 0;
2775 for (i = 0;;) {
2776 PRInt32 next = pos[i];
2777 if (next == -1 || next >= aDimensionSizes[i])
2778 return -1;
2779 result = result + next;
2780 if (++i < aDimensionCount) // Multiply for next round.
2781 result = result * aDimensionSizes[i];
2782 else
2783 break;
2785 return result;
2789 * Expand the resulting array out into a nice pseudo-multi-dimensional
2790 * array. We trust that the caller guaranteed aDimensionCount >= 1 and that
2791 * the other sizes are reasonable (or they couldn't pass us a resultant
2792 * array). * The result is produced recursively as:
2793 * an array [of arrays [...]] of the specified type.
2794 * Variants are used to embed arrays inside of * arrays.
2796 static nsresult CreateArray(nsIWritableVariant* aResult, PRUint16 aType, const nsIID* aIID,
2797 PRUint32 aDimensionCount, PRInt32* aDimensionSizes, PRUint32 aSizeof, PRUint8* aArray)
2799 if (aSizeof == 0) { // Variants do not support construction of null-sized arrays
2800 return aResult->SetAsEmptyArray();
2802 if (aDimensionCount > 1) { // We cannot reuse variants because they are kept by resulting array
2803 PRInt32 count = aDimensionSizes[0];
2804 PRUint32 size = aSizeof / count;
2805 PRInt32 i;
2806 nsIVariant** a = new nsIVariant*[count]; // Create variant array.
2807 if (!a)
2808 return NS_ERROR_OUT_OF_MEMORY;
2810 nsresult rc = NS_OK;
2812 for (i = 0; i < count; i++) {
2813 nsCOMPtr<nsIWritableVariant> v = do_CreateInstance(NS_VARIANT_CONTRACTID, &rc);
2814 if (NS_FAILED(rc))
2815 break;
2816 nsresult rc = CreateArray(v, aType, aIID, aDimensionCount - 1, aDimensionSizes + 1,
2817 size, aArray);
2818 if (NS_FAILED(rc))
2819 break;
2820 NS_ADDREF(a[i] = v); // Addref for array reference
2821 aArray += size;
2823 if (NS_SUCCEEDED(rc)) {
2824 rc = aResult->SetAsArray(nsIDataType::VTYPE_INTERFACE_IS,&NS_GET_IID(nsIVariant),count,a);
2826 for (i = 0; i < count; i++) { // Release variants for array
2827 nsIVariant* v = a[i];
2828 if (v)
2829 NS_RELEASE(v);
2831 delete[] a;
2832 return rc;
2834 else {
2835 return aResult->SetAsArray(aType,aIID,aDimensionSizes[0],aArray);
2839 // Incomplete -- becomes very complex due to variant arrays
2840 NS_IMETHODIMP
2841 nsArrayEncoder::Decode(nsISOAPEncoding* aEncoding,
2842 nsIDOMElement* aSource,
2843 nsISchemaType* aSchemaType,
2844 nsISOAPAttachments* aAttachments,
2845 nsIVariant** aResult)
2847 NS_ENSURE_ARG_POINTER(aEncoding);
2848 NS_ENSURE_ARG_POINTER(aSource);
2849 NS_ENSURE_ARG_POINTER(aResult);
2850 *aResult = nsnull;
2851 nsAutoString ns;
2852 nsAutoString name;
2853 nsCOMPtr<nsISchemaType> schemaArrayType;
2854 nsAutoString value;
2855 PRUint32 dimensionCount = 0; // Number of dimensions
2856 PRInt32 dimensionSizes[MAX_ARRAY_DIMENSIONS];
2857 PRInt32 size = -1;
2858 nsresult rc;
2859 PRUint32 i;
2860 if (aSchemaType) {
2861 PRUint16 type;
2862 nsresult rc = aSchemaType->GetSchemaType(&type);
2863 NS_ENSURE_SUCCESS(rc, rc);
2865 if (type == nsISchemaType::SCHEMA_TYPE_COMPLEX) {
2866 nsCOMPtr<nsISchemaComplexType> ct = do_QueryInterface(aSchemaType);
2867 nsresult rc = ct->GetArrayDimension(&dimensionCount);
2868 NS_ENSURE_SUCCESS(rc, rc);
2870 rc = ct->GetArrayType(getter_AddRefs(schemaArrayType));
2871 NS_ENSURE_SUCCESS(rc, rc);
2874 if (nsSOAPUtils::GetAttribute(aEncoding, aSource, gSOAPStrings->kSOAPEncURI,
2875 gSOAPStrings->kSOAPArrayTypeAttribute, value)) {
2876 nsAutoString dst;
2877 PRUint32 n = DecodeArrayDimensions(value, dimensionSizes, dst);
2878 if (n > 0) {
2879 if (dimensionCount == n || dimensionCount == 0) {
2880 dimensionCount = n;
2882 else {
2883 return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,
2884 "SOAP_WRONG_ARRAY_SIZE",
2885 "Array declares different number of dimensions from what schema declared.");
2886 // We cannot get conflicting information from schema and content.
2889 value.Assign(dst);
2891 if (dimensionCount > 0) {
2892 PRInt64 tot = 1; // Collect in 64 bits, just to make sure it fits
2893 for (i = 0; i < dimensionCount; i++) {
2894 PRInt32 next = dimensionSizes[i];
2895 if (next == -1) {
2896 tot = -1;
2897 break;
2899 tot = tot * next;
2900 if (tot > 0x7fffffff) {
2901 return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,
2902 "SOAP_ARRAY_TOO_BIG",
2903 "When decoding an object as an array, the total count of items exceeded maximum.");
2906 size = (PRInt32)tot;
2908 else {
2909 return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,
2910 "SOAP_ARRAY_UNDECLARED",
2911 "Array type did not end with proper array dimensions.");
2912 // A dimension count must be part of the arrayType
2915 // The array type is either array if ']' or other specific type.
2916 nsCOMPtr<nsISchemaCollection> collection;
2917 rc = aEncoding->GetSchemaCollection(getter_AddRefs(collection));
2918 NS_ENSURE_SUCCESS(rc, rc);
2920 if (value.Last() ==']') {
2921 ns.Assign(gSOAPStrings->kSOAPEncURI);
2922 name.Assign(gSOAPStrings->kArraySOAPType);
2924 else {
2925 rc = nsSOAPUtils::GetNamespaceURI(aEncoding, aSource, value, ns);
2926 NS_ENSURE_SUCCESS(rc, rc);
2928 rc = nsSOAPUtils::GetLocalName(value, name);
2929 NS_ENSURE_SUCCESS(rc, rc);
2931 nsCOMPtr<nsISchemaType> subtype;
2932 rc = collection->GetType(name, ns, getter_AddRefs(subtype));
2933 // if (NS_FAILED(rc)) return rc;
2934 if (!subtype)
2935 subtype = schemaArrayType;
2937 if (subtype) { // Loop up the hierarchy, to ensure suitability of subtype
2938 if (schemaArrayType) {
2939 nsCOMPtr<nsISchemaType> lookupType = subtype;
2940 do {
2941 if (lookupType == schemaArrayType) { // Tick off the located super classes
2942 schemaArrayType = nsnull;
2943 break;
2945 nsCOMPtr<nsISchemaType> supertype;
2946 rc = GetSupertype(aEncoding, lookupType, getter_AddRefs(supertype));
2947 NS_ENSURE_SUCCESS(rc, rc);
2949 lookupType = supertype;
2950 } while (lookupType);
2952 if (schemaArrayType) // If the proper subclass relationship didn't exist, then error return.
2953 return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,
2954 "SOAP_ARRAY_TYPE",
2955 "The type of the array must be a subclass of the declared type.");
2956 schemaArrayType = subtype; // If they did, then we now have a new, better type.
2959 PRUint32 offset; // Computing offset trickier, because size may be unspecified.
2960 if (nsSOAPUtils::GetAttribute(aEncoding, aSource, gSOAPStrings->kSOAPEncURI,
2961 gSOAPStrings->kSOAPArrayOffsetAttribute, value)) {
2962 PRInt32 pos[MAX_ARRAY_DIMENSIONS];
2963 nsAutoString leftover;
2964 offset = DecodeArrayDimensions(value, pos, leftover);
2965 if (dimensionCount == 0)
2966 dimensionCount = offset;
2967 if (offset == 0 ||
2968 offset != dimensionCount ||
2969 !leftover.IsEmpty()) {
2970 // We have to understand this or report an error
2971 // But the offset does not need to be understood
2972 return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,
2973 "SOAP_ARRAY_OFFSET",
2974 "Illegal value given for array offset");
2976 PRInt32 old0 = dimensionSizes[0];
2977 if (dimensionSizes[0] == -1) {
2978 // It is OK to have a offset where dimension 0 is unspecified
2979 dimensionSizes[0] = 2147483647;
2981 offset = 0;
2982 for (i = 0;;) {
2983 PRInt64 next = pos[i];
2984 if (next == -1 || next >= dimensionSizes[i]) {
2985 rc = NS_ERROR_ILLEGAL_VALUE;
2986 break;
2988 next = (offset + next);
2989 if (next > 2147483647) {
2990 rc = NS_ERROR_ILLEGAL_VALUE;
2991 break;
2993 offset = (PRInt32)next;
2994 if (++i < dimensionCount) {
2995 next = offset * dimensionSizes[i];
2996 if (next > 2147483647) {
2997 rc = NS_ERROR_ILLEGAL_VALUE;
2998 break;
3000 offset = (PRInt32)next;
3002 else {
3003 rc = NS_OK;
3004 break;
3007 if (NS_FAILED(rc))
3008 return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,
3009 "SOAP_ARRAY_OFFSET",
3010 "Illegal value given for array offset");
3011 dimensionSizes[0] = old0;
3013 else {
3014 offset = 0;
3016 if (size == -1) { // If no known size, we have to go through and pre-count.
3017 nsCOMPtr<nsIDOMElement> child;
3018 nsSOAPUtils::GetFirstChildElement(aSource, getter_AddRefs(child));
3019 PRInt32 pp[MAX_ARRAY_DIMENSIONS];
3020 if (dimensionCount != 0) {
3021 for (i = dimensionCount; i-- != 0;) {
3022 pp[i] = 0;
3025 size = 0;
3026 PRInt32 next = offset;
3027 while (child) {
3028 nsAutoString pos;
3029 if (nsSOAPUtils::GetAttribute(aEncoding, aSource, gSOAPStrings->kSOAPEncURI,
3030 gSOAPStrings->kSOAPArrayPositionAttribute, pos)) {
3031 // if array item contains an explicit 'position' attribute use it
3032 nsAutoString leftover;
3033 PRInt32 inc[MAX_ARRAY_DIMENSIONS];
3034 i = DecodeArrayDimensions(pos, inc, leftover);
3035 if (i == 0 ||
3036 !leftover.IsEmpty() ||
3037 (dimensionCount !=0 && dimensionCount != i)) {
3038 // We have to understand this or report an error
3039 return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,
3040 "SOAP_ARRAY_POSITION",
3041 "Illegal value given for array element position");
3043 if (dimensionCount == 0) {
3044 dimensionCount = i; // If we never had dimension count before, we do now.
3045 for (i = dimensionCount; i-- != 0;) {
3046 pp[i] = 0;
3049 for (i = 0; i < dimensionCount; i++) {
3050 PRInt32 n = inc[i];
3051 if (n == -1) { // Positions must be concrete
3052 return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,
3053 "SOAP_ARRAY_POSITION",
3054 "Illegal value given for array element position");
3056 if (n >= pp[i])
3057 pp[i] = n + 1;
3060 else {
3061 // No explicit 'position' attribute
3062 next++; // Keep tabs on how many unnumbered items there are
3065 nsCOMPtr<nsIDOMElement> nextchild;
3066 nsSOAPUtils::GetNextSiblingElement(child, getter_AddRefs(nextchild));
3067 child = nextchild;
3069 if (dimensionCount == 0) { // If unknown or 1 dimension, unpositioned entries can help
3070 dimensionCount = 1;
3071 pp[0] = next;
3072 dimensionSizes[0] = next;
3074 else if (dimensionCount == 1
3075 && next > pp[0]) {
3076 pp[0] = next;
3077 dimensionSizes[0] = next;
3079 PRInt64 tot = 1; // Collect in 64 bits, just to make sure it fits
3080 for (i = 0; i < dimensionCount; i++) {
3081 PRInt32 next = dimensionSizes[i];
3082 if (next == -1) { // Only derive those with no other declaration
3083 dimensionSizes[i] = next = pp[i];
3085 tot = tot * next;
3086 if (tot > 0x7fffffff) {
3087 return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,
3088 "SOAP_ARRAY_TOO_BIG",
3089 "When decoding an object as an array, the total count of items exceeded maximum.");
3092 size = (PRInt32)tot; // At last, we know the dimensions of the array.
3095 // After considerable work, we may have a schema type and a size.
3097 nsCOMPtr<nsIWritableVariant> result = do_CreateInstance(NS_VARIANT_CONTRACTID, &rc);
3098 PRInt32 si;
3100 #define DECODE_ARRAY(XPType, VTYPE, iid, Convert, Free) \
3101 XPType* a = new XPType[size];\
3102 if (!a)\
3103 return NS_ERROR_OUT_OF_MEMORY;\
3104 for (si = 0; si < size; si++) a[si] = 0;\
3105 nsCOMPtr<nsIDOMElement> child;\
3106 nsSOAPUtils::GetFirstChildElement(aSource, getter_AddRefs(child));\
3107 PRUint32 next = offset;\
3108 while (child) {\
3109 nsAutoString pos;\
3110 PRInt32 p;\
3111 if (nsSOAPUtils::GetAttribute(aEncoding, aSource, gSOAPStrings->kSOAPEncURI,\
3112 gSOAPStrings->kSOAPArrayPositionAttribute, pos)) {\
3113 p = DecodeArrayPosition(pos, dimensionCount, dimensionSizes);\
3114 if (p == -1) {\
3115 rc = NS_ERROR_ILLEGAL_VALUE;\
3116 break;\
3119 else {\
3120 p = next++;\
3122 if (p >= size || a[p]) {\
3123 rc = NS_ERROR_ILLEGAL_VALUE;\
3124 break;\
3126 nsCOMPtr<nsIVariant> v;\
3128 rc = aEncoding->Decode(child, schemaArrayType, aAttachments, getter_AddRefs(v));\
3129 if (NS_FAILED(rc))\
3130 break;\
3131 Convert \
3133 nsCOMPtr<nsIDOMElement> next;\
3134 nsSOAPUtils::GetNextSiblingElement(child, getter_AddRefs(next));\
3135 child = next;\
3137 if (NS_SUCCEEDED(rc)) {\
3138 rc = CreateArray(result, nsIDataType::VTYPE_##VTYPE,iid,dimensionCount,dimensionSizes,sizeof(a[0])*size,(PRUint8*)a);\
3140 Free\
3141 delete[] a;\
3143 #define DECODE_SIMPLE_ARRAY(XPType, VType, VTYPE) \
3144 DECODE_ARRAY(XPType, VTYPE, nsnull, rc = v->GetAs##VType(a + p);if(NS_FAILED(rc))break;,do{}while(0);)
3146 if (rc == NS_ERROR_ILLEGAL_VALUE)
3147 return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,
3148 "SOAP_ARRAY_POSITIONS",
3149 "Colliding array positions discovered.");
3150 NS_ENSURE_SUCCESS(rc, rc);
3152 PRBool unhandled = PR_FALSE;
3153 if (ns.Equals(gSOAPStrings->kXSURI)) {
3154 if (name.Equals(gSOAPStrings->kStringSchemaType)) {
3155 DECODE_ARRAY(PRUnichar*,WCHAR_STR,nsnull,rc = v->GetAsWString(a + p);if(NS_FAILED(rc))break;,
3156 for (si = 0; si < size; si++) nsMemory::Free(a[si]););
3157 } else if (name.Equals(gSOAPStrings->kBooleanSchemaType)) {
3158 DECODE_SIMPLE_ARRAY(PRBool,Bool,BOOL);
3159 } else if (name.Equals(gSOAPStrings->kFloatSchemaType)) {
3160 DECODE_SIMPLE_ARRAY(float,Float,FLOAT);
3161 } else if (name.Equals(gSOAPStrings->kDoubleSchemaType)) {
3162 DECODE_SIMPLE_ARRAY(double,Double,DOUBLE);
3163 } else if (name.Equals(gSOAPStrings->kLongSchemaType)) {
3164 DECODE_SIMPLE_ARRAY(PRInt64,Int64,INT64);
3165 } else if (name.Equals(gSOAPStrings->kIntSchemaType)) {
3166 DECODE_SIMPLE_ARRAY(PRInt32,Int32,INT32);
3167 } else if (name.Equals(gSOAPStrings->kShortSchemaType)) {
3168 DECODE_SIMPLE_ARRAY(PRInt16,Int16,INT16);
3169 } else if (name.Equals(gSOAPStrings->kByteSchemaType)) {
3170 DECODE_SIMPLE_ARRAY(PRUint8,Int8,INT8);
3171 } else if (name.Equals(gSOAPStrings->kUnsignedLongSchemaType)) {
3172 DECODE_SIMPLE_ARRAY(PRUint64,Uint64,UINT64);
3173 } else if (name.Equals(gSOAPStrings->kUnsignedIntSchemaType)) {
3174 DECODE_SIMPLE_ARRAY(PRUint32,Uint32,UINT32);
3175 } else if (name.Equals(gSOAPStrings->kUnsignedShortSchemaType)) {
3176 DECODE_SIMPLE_ARRAY(PRUint16,Uint16,UINT16);
3177 } else if (name.Equals(gSOAPStrings->kUnsignedByteSchemaType)) {
3178 DECODE_SIMPLE_ARRAY(PRUint8,Uint8,UINT8);
3179 } else {
3180 unhandled = PR_TRUE;
3182 } else {
3183 unhandled = PR_TRUE;
3185 if (unhandled) { // Handle all the other cases
3186 DECODE_ARRAY(nsIVariant*,INTERFACE_IS,&NS_GET_IID(nsIVariant),
3187 NS_ADDREF(a[p] = v);,
3188 for (si = 0; si < size; si++) NS_IF_RELEASE(a[si]););
3190 NS_ENSURE_SUCCESS(rc, rc);
3192 NS_ADDREF(*aResult = result);
3193 return NS_OK;
3196 NS_IMETHODIMP
3197 nsStringEncoder::Decode(nsISOAPEncoding* aEncoding,
3198 nsIDOMElement* aSource,
3199 nsISchemaType* aSchemaType,
3200 nsISOAPAttachments* aAttachments,
3201 nsIVariant** aResult)
3203 NS_ENSURE_ARG_POINTER(aEncoding);
3204 NS_ENSURE_ARG_POINTER(aSource);
3205 NS_ENSURE_ARG_POINTER(aResult);
3206 *aResult = nsnull;
3207 nsAutoString value;
3208 nsresult rc = nsSOAPUtils::GetElementTextContent(aSource, value);
3209 NS_ENSURE_SUCCESS(rc, rc);
3211 nsCOMPtr<nsIWritableVariant> p =
3212 do_CreateInstance(NS_VARIANT_CONTRACTID, &rc);
3213 NS_ENSURE_SUCCESS(rc, rc);
3215 rc = p->SetAsAString(value);
3216 NS_ENSURE_SUCCESS(rc, rc);
3218 NS_ADDREF(*aResult = p);
3219 return NS_OK;
3222 NS_IMETHODIMP
3223 nsBooleanEncoder::Decode(nsISOAPEncoding* aEncoding,
3224 nsIDOMElement* aSource,
3225 nsISchemaType* aSchemaType,
3226 nsISOAPAttachments* aAttachments,
3227 nsIVariant** aResult)
3229 NS_ENSURE_ARG_POINTER(aEncoding);
3230 NS_ENSURE_ARG_POINTER(aSource);
3231 NS_ENSURE_ARG_POINTER(aResult);
3232 *aResult = nsnull;
3233 nsAutoString value;
3234 nsresult rc = nsSOAPUtils::GetElementTextContent(aSource, value);
3235 NS_ENSURE_SUCCESS(rc, rc);
3237 PRBool b;
3238 if (value.Equals(gSOAPStrings->kTrue) ||
3239 value.Equals(gSOAPStrings->kTrueA)) {
3240 b = PR_TRUE;
3241 } else if (value.Equals(gSOAPStrings->kFalse) ||
3242 value.Equals(gSOAPStrings->kFalseA)) {
3243 b = PR_FALSE;
3244 } else {
3245 return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,
3246 "SOAP_ILLEGAL_BOOLEAN",
3247 "Illegal value discovered for boolean");
3250 nsCOMPtr<nsIWritableVariant> p =
3251 do_CreateInstance(NS_VARIANT_CONTRACTID,&rc);
3252 NS_ENSURE_SUCCESS(rc, rc);
3254 p->SetAsBool(b);
3256 NS_ADDREF(*aResult = p);
3257 return NS_OK;
3260 NS_IMETHODIMP
3261 nsDoubleEncoder::Decode(nsISOAPEncoding* aEncoding,
3262 nsIDOMElement* aSource,
3263 nsISchemaType* aSchemaType,
3264 nsISOAPAttachments* aAttachments,
3265 nsIVariant** aResult)
3267 NS_ENSURE_ARG_POINTER(aEncoding);
3268 NS_ENSURE_ARG_POINTER(aSource);
3269 NS_ENSURE_ARG_POINTER(aResult);
3270 *aResult = nsnull;
3271 nsAutoString value;
3272 nsresult rc = nsSOAPUtils::GetElementTextContent(aSource, value);
3273 NS_ENSURE_SUCCESS(rc, rc);
3275 double f;
3276 PRUint32 n;
3277 PRInt32 r = PR_sscanf(NS_ConvertUTF16toUTF8(value).get(), " %lf %n", &f, &n);
3278 if (r == 0 || n < value.Length()) {
3279 return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,
3280 "SOAP_ILLEGAL_DOUBLE",
3281 "Illegal value discovered for double");
3284 nsCOMPtr<nsIWritableVariant> p =
3285 do_CreateInstance(NS_VARIANT_CONTRACTID, &rc);
3286 NS_ENSURE_SUCCESS(rc, rc);
3288 p->SetAsDouble(f);
3290 NS_ADDREF(*aResult = p);
3291 return NS_OK;
3294 NS_IMETHODIMP
3295 nsFloatEncoder::Decode(nsISOAPEncoding* aEncoding,
3296 nsIDOMElement* aSource,
3297 nsISchemaType* aSchemaType,
3298 nsISOAPAttachments* aAttachments,
3299 nsIVariant** aResult)
3301 NS_ENSURE_ARG_POINTER(aEncoding);
3302 NS_ENSURE_ARG_POINTER(aSource);
3303 NS_ENSURE_ARG_POINTER(aResult);
3304 *aResult = nsnull;
3305 nsAutoString value;
3306 nsresult rc = nsSOAPUtils::GetElementTextContent(aSource, value);
3307 NS_ENSURE_SUCCESS(rc, rc);
3309 float f;
3310 PRUint32 n;
3311 PRInt32 r = PR_sscanf(NS_ConvertUTF16toUTF8(value).get(), " %f %n", &f, &n);
3312 if (r == 0 || n < value.Length()) {
3313 return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,
3314 "SOAP_ILLEGAL_FLOAT",
3315 "Illegal value discovered for float");
3318 nsCOMPtr<nsIWritableVariant> p =
3319 do_CreateInstance(NS_VARIANT_CONTRACTID,&rc);
3320 NS_ENSURE_SUCCESS(rc, rc);
3322 p->SetAsFloat(f);
3324 NS_ADDREF(*aResult = p);
3325 return NS_OK;
3328 NS_IMETHODIMP
3329 nsLongEncoder::Decode(nsISOAPEncoding* aEncoding,
3330 nsIDOMElement* aSource,
3331 nsISchemaType* aSchemaType,
3332 nsISOAPAttachments* aAttachments,
3333 nsIVariant** aResult)
3335 NS_ENSURE_ARG_POINTER(aEncoding);
3336 NS_ENSURE_ARG_POINTER(aSource);
3337 NS_ENSURE_ARG_POINTER(aResult);
3338 *aResult = nsnull;
3339 nsAutoString value;
3340 nsresult rc = nsSOAPUtils::GetElementTextContent(aSource, value);
3341 NS_ENSURE_SUCCESS(rc, rc);
3343 PRInt64 f;
3344 PRUint32 n;
3345 PRInt32 r = PR_sscanf(NS_ConvertUTF16toUTF8(value).get(), " %lld %n", &f, &n);
3346 if (r == 0 || n < value.Length()) {
3347 return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,
3348 "SOAP_ILLEGAL_LONG",
3349 "Illegal value discovered for long");
3352 nsCOMPtr<nsIWritableVariant> p =
3353 do_CreateInstance(NS_VARIANT_CONTRACTID,&rc);
3354 NS_ENSURE_SUCCESS(rc, rc);
3356 p->SetAsInt64(f);
3358 NS_ADDREF(*aResult = p);
3359 return NS_OK;
3362 NS_IMETHODIMP
3363 nsIntEncoder::Decode(nsISOAPEncoding* aEncoding,
3364 nsIDOMElement* aSource,
3365 nsISchemaType* aSchemaType,
3366 nsISOAPAttachments* aAttachments,
3367 nsIVariant** aResult)
3369 NS_ENSURE_ARG_POINTER(aEncoding);
3370 NS_ENSURE_ARG_POINTER(aSource);
3371 NS_ENSURE_ARG_POINTER(aResult);
3372 *aResult = nsnull;
3373 nsAutoString value;
3374 nsresult rc = nsSOAPUtils::GetElementTextContent(aSource, value);
3375 NS_ENSURE_SUCCESS(rc, rc);
3377 PRInt32 f;
3378 PRUint32 n;
3379 PRInt32 r = PR_sscanf(NS_ConvertUTF16toUTF8(value).get(), " %ld %n", &f, &n);
3380 if (r == 0 || n < value.Length()) {
3381 return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,
3382 "SOAP_ILLEGAL_INT",
3383 "Illegal value discovered for int");
3386 nsCOMPtr<nsIWritableVariant> p =
3387 do_CreateInstance(NS_VARIANT_CONTRACTID,&rc);
3388 NS_ENSURE_SUCCESS(rc, rc);
3390 p->SetAsInt32(f);
3391 NS_ADDREF(*aResult = p);
3392 return NS_OK;
3395 NS_IMETHODIMP
3396 nsShortEncoder::Decode(nsISOAPEncoding* aEncoding,
3397 nsIDOMElement* aSource,
3398 nsISchemaType* aSchemaType,
3399 nsISOAPAttachments* aAttachments,
3400 nsIVariant** aResult)
3402 NS_ENSURE_ARG_POINTER(aEncoding);
3403 NS_ENSURE_ARG_POINTER(aSource);
3404 NS_ENSURE_ARG_POINTER(aResult);
3405 *aResult = nsnull;
3406 nsAutoString value;
3407 nsresult rc = nsSOAPUtils::GetElementTextContent(aSource, value);
3408 NS_ENSURE_SUCCESS(rc, rc);
3410 PRInt16 f;
3411 PRUint32 n;
3412 PRInt32 r = PR_sscanf(NS_ConvertUTF16toUTF8(value).get(), " %hd %n", &f, &n);
3413 if (r == 0 || n < value.Length()) {
3414 return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,
3415 "SOAP_ILLEGAL_SHORT",
3416 "Illegal value discovered for short");
3419 nsCOMPtr<nsIWritableVariant> p =
3420 do_CreateInstance(NS_VARIANT_CONTRACTID,&rc);
3421 NS_ENSURE_SUCCESS(rc, rc);
3423 p->SetAsInt16(f);
3424 NS_ADDREF(*aResult = p);
3425 return NS_OK;
3428 NS_IMETHODIMP
3429 nsByteEncoder::Decode(nsISOAPEncoding* aEncoding,
3430 nsIDOMElement* aSource,
3431 nsISchemaType* aSchemaType,
3432 nsISOAPAttachments* aAttachments,
3433 nsIVariant** aResult)
3435 NS_ENSURE_ARG_POINTER(aEncoding);
3436 NS_ENSURE_ARG_POINTER(aSource);
3437 NS_ENSURE_ARG_POINTER(aResult);
3438 *aResult = nsnull;
3439 nsAutoString value;
3440 nsresult rc = nsSOAPUtils::GetElementTextContent(aSource, value);
3441 NS_ENSURE_SUCCESS(rc, rc);
3443 PRInt16 f;
3444 PRUint32 n;
3445 PRInt32 r = PR_sscanf(NS_ConvertUTF16toUTF8(value).get(), " %hd %n", &f, &n);
3446 if (r == 0 || n < value.Length() || f < -128 || f > 127) {
3447 return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,
3448 "SOAP_ILLEGAL_BYTE",
3449 "Illegal value discovered for byte");
3452 nsCOMPtr<nsIWritableVariant> p =
3453 do_CreateInstance(NS_VARIANT_CONTRACTID,&rc);
3454 NS_ENSURE_SUCCESS(rc, rc);
3456 p->SetAsInt8((PRUint8) f);
3457 NS_ADDREF(*aResult = p);
3458 return NS_OK;
3461 NS_IMETHODIMP
3462 nsUnsignedLongEncoder::Decode(nsISOAPEncoding* aEncoding,
3463 nsIDOMElement* aSource,
3464 nsISchemaType* aSchemaType,
3465 nsISOAPAttachments* aAttachments,
3466 nsIVariant** aResult)
3468 NS_ENSURE_ARG_POINTER(aEncoding);
3469 NS_ENSURE_ARG_POINTER(aSource);
3470 NS_ENSURE_ARG_POINTER(aResult);
3471 *aResult = nsnull;
3472 nsAutoString value;
3473 nsresult rc = nsSOAPUtils::GetElementTextContent(aSource, value);
3474 NS_ENSURE_SUCCESS(rc, rc);
3476 PRUint64 f;
3477 PRUint32 n;
3478 PRInt32 r = PR_sscanf(NS_ConvertUTF16toUTF8(value).get(), " %llu %n", &f, &n);
3479 if (r == 0 || n < value.Length()) {
3480 return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,
3481 "SOAP_ILLEGAL_ULONG",
3482 "Illegal value discovered for unsigned long");
3485 nsCOMPtr<nsIWritableVariant> p =
3486 do_CreateInstance(NS_VARIANT_CONTRACTID,&rc);
3487 NS_ENSURE_SUCCESS(rc, rc);
3489 p->SetAsUint64(f);
3490 NS_ADDREF(*aResult = p);
3491 return NS_OK;
3494 NS_IMETHODIMP
3495 nsUnsignedIntEncoder::Decode(nsISOAPEncoding* aEncoding,
3496 nsIDOMElement* aSource,
3497 nsISchemaType* aSchemaType,
3498 nsISOAPAttachments* aAttachments,
3499 nsIVariant** aResult)
3501 NS_ENSURE_ARG_POINTER(aEncoding);
3502 NS_ENSURE_ARG_POINTER(aSource);
3503 NS_ENSURE_ARG_POINTER(aResult);
3504 *aResult = nsnull;
3505 nsAutoString value;
3506 nsresult rc = nsSOAPUtils::GetElementTextContent(aSource, value);
3507 NS_ENSURE_SUCCESS(rc, rc);
3509 PRUint32 f;
3510 PRUint32 n;
3511 PRInt32 r = PR_sscanf(NS_ConvertUTF16toUTF8(value).get(), " %lu %n", &f, &n);
3512 if (r == 0 || n < value.Length()) {
3513 return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,
3514 "SOAP_ILLEGAL_UINT",
3515 "Illegal value discovered for unsigned int");
3518 nsCOMPtr<nsIWritableVariant> p =
3519 do_CreateInstance(NS_VARIANT_CONTRACTID,&rc);
3520 NS_ENSURE_SUCCESS(rc, rc);
3522 p->SetAsUint32(f);
3523 NS_ADDREF(*aResult = p);
3524 return NS_OK;
3527 NS_IMETHODIMP
3528 nsBase64BinaryEncoder::Decode(nsISOAPEncoding* aEncoding,
3529 nsIDOMElement* aSource,
3530 nsISchemaType* aSchemaType,
3531 nsISOAPAttachments* aAttachments,
3532 nsIVariant** aResult)
3534 NS_ENSURE_ARG_POINTER(aEncoding);
3535 NS_ENSURE_ARG_POINTER(aSource);
3536 NS_ENSURE_ARG_POINTER(aResult);
3537 *aResult = nsnull;
3539 nsString value;
3540 nsresult rv = nsSOAPUtils::GetElementTextContent(aSource, value);
3541 NS_ENSURE_SUCCESS(rv, rv);
3543 NS_LossyConvertUTF16toASCII valueStr(value);
3544 valueStr.StripChars(" \n\r\t");
3546 char* decodedVal = PL_Base64Decode(valueStr.get(), valueStr.Length(), nsnull);
3547 if (!decodedVal) {
3548 return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,
3549 "SOAP_ILLEGAL_BASE64",
3550 "Data cannot be decoded as Base64");
3553 nsCOMPtr<nsIWritableVariant> p =
3554 do_CreateInstance(NS_VARIANT_CONTRACTID, &rv);
3556 if (NS_SUCCEEDED(rv)) {
3558 rv = p->SetAsArray(nsIDataType::VTYPE_UINT8, nsnull,
3559 strlen(decodedVal), decodedVal);
3562 PR_Free(decodedVal);
3563 NS_ENSURE_SUCCESS(rv, rv);
3565 NS_ADDREF(*aResult = p);
3566 return NS_OK;
3569 NS_IMETHODIMP
3570 nsUnsignedShortEncoder::Decode(nsISOAPEncoding* aEncoding,
3571 nsIDOMElement* aSource,
3572 nsISchemaType* aSchemaType,
3573 nsISOAPAttachments* aAttachments,
3574 nsIVariant** aResult)
3576 NS_ENSURE_ARG_POINTER(aEncoding);
3577 NS_ENSURE_ARG_POINTER(aSource);
3578 NS_ENSURE_ARG_POINTER(aResult);
3579 *aResult = nsnull;
3580 nsAutoString value;
3581 nsresult rc = nsSOAPUtils::GetElementTextContent(aSource, value);
3582 NS_ENSURE_SUCCESS(rc, rc);
3584 PRUint16 f;
3585 PRUint32 n;
3586 PRInt32 r = PR_sscanf(NS_ConvertUTF16toUTF8(value).get(), " %hu %n", &f, &n);
3587 if (r == 0 || n < value.Length()) {
3588 return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,
3589 "SOAP_ILLEGAL_USHORT",
3590 "Illegal value discovered for unsigned short");
3593 nsCOMPtr<nsIWritableVariant> p =
3594 do_CreateInstance(NS_VARIANT_CONTRACTID,&rc);
3595 NS_ENSURE_SUCCESS(rc, rc);
3597 p->SetAsUint16(f);
3598 NS_ADDREF(*aResult = p);
3599 return NS_OK;
3602 NS_IMETHODIMP
3603 nsUnsignedByteEncoder::Decode(nsISOAPEncoding* aEncoding,
3604 nsIDOMElement* aSource,
3605 nsISchemaType* aSchemaType,
3606 nsISOAPAttachments* aAttachments,
3607 nsIVariant** aResult)
3609 NS_ENSURE_ARG_POINTER(aEncoding);
3610 NS_ENSURE_ARG_POINTER(aSource);
3611 NS_ENSURE_ARG_POINTER(aResult);
3612 *aResult = nsnull;
3613 nsAutoString value;
3614 nsresult rc = nsSOAPUtils::GetElementTextContent(aSource, value);
3615 NS_ENSURE_SUCCESS(rc, rc);
3617 PRUint16 f;
3618 PRUint32 n;
3619 PRInt32 r = PR_sscanf(NS_ConvertUTF16toUTF8(value).get(), " %hu %n", &f, &n);
3620 if (r == 0 || n < value.Length() || f > 255) {
3621 return SOAP_EXCEPTION(NS_ERROR_ILLEGAL_VALUE,
3622 "SOAP_ILLEGAL_UBYTE",
3623 "Illegal value discovered for unsigned byte");
3626 nsCOMPtr<nsIWritableVariant> p =
3627 do_CreateInstance(NS_VARIANT_CONTRACTID,&rc);
3628 NS_ENSURE_SUCCESS(rc, rc);
3630 p->SetAsUint8((PRUint8) f);
3631 NS_ADDREF(*aResult = p);
3632 return NS_OK;