Back to index

lightning-sunbird  0.9+nobinonly
nsSchemaValidator.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is Mozilla Schema Validation.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * IBM Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 2004-2005
00020  * IBM Corporation. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Doron Rosenberg <doronr@us.ibm.com> (original author)
00024  *   Laurent Jouanneau <laurent@xulfr.org>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either the GNU General Public License Version 2 or later (the "GPL"), or
00028  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 #include "nsSchemaValidator.h"
00041 
00042 // content includes
00043 #include "nsIContent.h"
00044 #include "nsIDOMNode.h"
00045 #include "nsIDOM3Node.h"
00046 #include "nsIDOMElement.h"
00047 #include "nsIDOMAttr.h"
00048 #include "nsIDOMNodeList.h"
00049 #include "nsIParserService.h"
00050 #include "nsIDOMNamedNodeMap.h"
00051 #include "nsDataHashtable.h"
00052 #include "nsIVariant.h"
00053 #include "nsIAttribute.h"
00054 
00055 // string includes
00056 #include "nsReadableUtils.h"
00057 #include "nsString.h"
00058 #include "nsUnicharUtils.h"
00059 
00060 // XPCOM includes
00061 #include "nsMemory.h"
00062 #include "nsIServiceManager.h"
00063 #include "nsIComponentManager.h"
00064 
00065 #include "nsISchema.h"
00066 #include "nsISchemaLoader.h"
00067 #include "nsSchemaValidatorUtils.h"
00068 
00069 #include "nsNetUtil.h"
00070 #include "prlog.h"
00071 #include "nspr.h"
00072 
00073 #include <stdlib.h>
00074 #include <math.h>
00075 #include <float.h>
00076 #include "prprf.h"
00077 #include "prtime.h"
00078 #include "plbase64.h"
00079 #include <ctype.h>
00080 
00081 #define NS_SCHEMA_1999_NAMESPACE "http://www.w3.org/1999/XMLSchema"
00082 #define NS_SCHEMA_2001_NAMESPACE "http://www.w3.org/2001/XMLSchema"
00083 #define NS_SCHEMA_INSTANCE_NAMESPACE "http://www.w3.org/2001/XMLSchema-instance"
00084 
00085 #ifdef PR_LOGGING
00086 PRLogModuleInfo *gSchemaValidationLog = PR_NewLogModule("schemaValidation");
00087 
00088 #define LOG(x) PR_LOG(gSchemaValidationLog, PR_LOG_DEBUG, x)
00089 #define LOG_ENABLED() PR_LOG_TEST(gSchemaValidationLog, PR_LOG_DEBUG)
00090 #else
00091 #define LOG(x)
00092 #endif
00093 
00094 NS_IMPL_ISUPPORTS1_CI(nsSchemaValidator, nsISchemaValidator)
00095 
00096 nsSchemaValidator::nsSchemaValidator() : mForceInvalid(PR_FALSE)
00097 {
00098 }
00099 
00100 nsSchemaValidator::~nsSchemaValidator()
00101 {
00102 }
00103 
00105 //
00106 // nsSchemaValidator implementation
00107 //
00109 
00110 NS_IMETHODIMP
00111 nsSchemaValidator::LoadSchema(nsISchema* aSchema)
00112 {
00113   if (aSchema)
00114     aSchema->GetCollection(getter_AddRefs(mSchema));
00115   return NS_OK;
00116 }
00117 
00118 NS_IMETHODIMP
00119 nsSchemaValidator::ValidateString(const nsAString & aValue,
00120                                   const nsAString & aType,
00121                                   const nsAString & aNamespace,
00122                                   PRBool *aResult)
00123 {
00124   LOG(("--------- nsSchemaValidator::ValidateString called ---------"));
00125 
00126   // empty type is invalid
00127   if (aType.IsEmpty())
00128     return NS_ERROR_NOT_AVAILABLE;
00129 
00130   // no schemas loaded and type is not builtin, abort
00131   if (!mSchema && !aNamespace.EqualsLiteral(NS_SCHEMA_1999_NAMESPACE) &&
00132       !aNamespace.EqualsLiteral(NS_SCHEMA_2001_NAMESPACE))
00133     return NS_ERROR_SCHEMAVALIDATOR_NO_SCHEMA_LOADED;
00134 
00135   // figure out if it's a simple or complex type
00136   nsCOMPtr<nsISchemaType> type;
00137   nsresult rv = GetType(aType, aNamespace, getter_AddRefs(type));
00138   NS_ENSURE_SUCCESS(rv, rv);
00139 
00140   PRUint16 typevalue;
00141   rv = type->GetSchemaType(&typevalue);
00142   NS_ENSURE_SUCCESS(rv, rv);
00143 
00144   PRBool isValid = PR_FALSE;
00145   if (typevalue == nsISchemaType::SCHEMA_TYPE_SIMPLE) {
00146     nsCOMPtr<nsISchemaSimpleType> simpleType = do_QueryInterface(type);
00147     NS_ENSURE_TRUE(simpleType, NS_ERROR_FAILURE);
00148 
00149     LOG((" Type is a simple type! \n String to validate is: |%s|",
00150          NS_ConvertUTF16toUTF8(aValue).get()));
00151 
00152     rv = ValidateSimpletype(aValue, simpleType, &isValid);
00153   } else {
00154     // if its not a simpletype, validating a string makes no sense.
00155     rv = NS_ERROR_UNEXPECTED;
00156     LOG(("  -- unexpected type"));
00157   }
00158 
00159 #ifdef PR_LOGGING
00160   if (!isValid)
00161     LOG(("  *** INVALID ***"));
00162 #endif
00163 
00164   *aResult = isValid;
00165   return rv;
00166 }
00167 
00168 NS_IMETHODIMP
00169 nsSchemaValidator::Validate(nsIDOMNode* aElement, PRBool *aResult)
00170 {
00171   LOG(("--------- nsSchemaValidator::Validate called ---------"));
00172 
00173   if (!aElement)
00174     return NS_ERROR_SCHEMAVALIDATOR_NO_DOM_NODE_SPECIFIED;
00175 
00176   // init the override
00177   mForceInvalid = PR_FALSE;
00178 
00179   // will hold the type to validate against
00180   nsCOMPtr<nsISchemaType> type;
00181 
00182   nsresult rv = GetElementXsiType(aElement, getter_AddRefs(type));
00183   NS_ENSURE_SUCCESS(rv, rv);
00184 
00185   if (!type) {
00186     if (!mSchema) {
00187       // no type attribute and no loaded schemas, so abort
00188       // XXX: needed better error here
00189       return NS_ERROR_SCHEMAVALIDATOR_NO_SCHEMA_LOADED;
00190     }
00191 
00192     // no type attribute, look for an xsd:element in the schema that matches
00193     LOG(("   -- no type attribute found, so looking for matching xsd:element"));
00194 
00195     // get namespace from node
00196     nsAutoString schemaTypeNamespace;
00197     rv = aElement->GetNamespaceURI(schemaTypeNamespace);
00198     NS_ENSURE_SUCCESS(rv, rv);
00199 
00200     nsAutoString localName;
00201     rv = aElement->GetLocalName(localName);
00202     NS_ENSURE_SUCCESS(rv, rv);
00203 
00204     nsCOMPtr<nsISchemaElement> element;
00205     mSchema->GetElement(localName, schemaTypeNamespace, getter_AddRefs(element));
00206 
00207     if (!element) {
00208       // no type and no matching element, abort
00209       // XXX: needed better error here
00210       return NS_ERROR_SCHEMAVALIDATOR_NO_SCHEMA_LOADED;
00211     }
00212 
00213     rv = element->GetType(getter_AddRefs(type));
00214     NS_ENSURE_SUCCESS(rv, rv);
00215   }
00216 
00217   /*
00218    * We allow the schema validator to continue validating a structure
00219    * even if the nodevalue is invalid per its simpletype binding.  This is done
00220    * so that we continue to mark nodes with their types, even if we encounter
00221    * an invalid nodevalue.  We remember that we had an invalid nodevalue by
00222    * using mForceInvalid as an override for the final return.
00223    */
00224 
00225   PRBool isValid = PR_FALSE;
00226   rv = ValidateAgainstType(aElement, type, &isValid);
00227 
00228   *aResult = mForceInvalid ? PR_FALSE : isValid;
00229   return rv;
00230 }
00231 
00232 // This is passed into setProperty so that the variant passed as
00233 // an xsdtype is released when the property is destroyed
00234 static void VariantDTor(void           *aObject,
00235                         nsIAtom        *aPropertyName,
00236                         void           *aPropertyValue,
00237                         void           *aData)
00238 {
00239   nsIVariant *pVariant = static_cast<nsIVariant *>(aPropertyValue);
00240   NS_IF_RELEASE(pVariant);
00241 }
00242 
00243 
00244 
00245 NS_IMETHODIMP
00246 nsSchemaValidator::ValidateAgainstType(nsIDOMNode* aElement,
00247                                        nsISchemaType* aType,
00248                                        PRBool *aResult)
00249 {
00250   if (!aElement)
00251     return NS_ERROR_SCHEMAVALIDATOR_NO_DOM_NODE_SPECIFIED;
00252 
00253   NS_ENSURE_STATE(aType);
00254 
00255   PRUint16 typevalue;
00256   nsresult rv = aType->GetSchemaType(&typevalue);
00257   NS_ENSURE_SUCCESS(rv, rv);
00258 
00259   PRBool isValid = PR_FALSE;
00260 
00261   if (typevalue == nsISchemaType::SCHEMA_TYPE_SIMPLE) {
00262     nsCOMPtr<nsISchemaSimpleType> simpleType = do_QueryInterface(aType);
00263 
00264     if (simpleType) {
00265       // get the nodevalue using DOM 3's textContent
00266       nsAutoString nodeValue;
00267       nsCOMPtr<nsIDOM3Node> domNode3 = do_QueryInterface(aElement);
00268       domNode3->GetTextContent(nodeValue);
00269 
00270       LOG(("  Type is a simple type!"));
00271       LOG(("  String to validate is: |%s|",
00272         NS_ConvertUTF16toUTF8(nodeValue).get()));
00273 
00274       rv = ValidateSimpletype(nodeValue, simpleType, &isValid);
00275       NS_ENSURE_SUCCESS(rv, rv);
00276 
00277       nsAutoString typeName, nodeName;
00278       rv = aType->GetName(typeName);
00279       NS_ENSURE_SUCCESS(rv, rv);
00280 
00281       rv = aElement->GetLocalName(nodeName);
00282       NS_ENSURE_SUCCESS(rv, rv);
00283 
00284       // go on validating, but remember we failed
00285       if (!isValid) {
00286         mForceInvalid = PR_TRUE;
00287         isValid = PR_TRUE;
00288       }
00289 
00290       nsCOMPtr<nsIWritableVariant> holder =
00291         do_CreateInstance("@mozilla.org/variant;1");
00292       NS_ENSURE_STATE(holder);
00293 
00294       holder->SetAsInterface(nsISchemaType::GetIID(), aType);
00295 
00296       // and save on the node
00297       nsCOMPtr<nsIContent> content = do_QueryInterface(domNode3);
00298       NS_ENSURE_STATE(content);
00299 
00300       // we have to be really carefull to set the destructor function correctly.
00301       // this also has to be a pointer to a variant
00302       nsCOMPtr<nsIAtom> key = do_GetAtom("xsdtype");
00303       NS_ENSURE_TRUE(key, NS_ERROR_OUT_OF_MEMORY);
00304 
00305       nsIVariant *pVariant = holder;
00306       NS_IF_ADDREF(pVariant);
00307       rv = content->SetProperty(key, pVariant, &VariantDTor);
00308       NS_ENSURE_SUCCESS(rv, rv);
00309     }
00310   } else if (typevalue == nsISchemaType::SCHEMA_TYPE_COMPLEX) {
00311     nsCOMPtr<nsISchemaComplexType> complexType = do_QueryInterface(aType);
00312     if (complexType) {
00313       LOG(("  Type is a complex type!"));
00314       rv = ValidateComplextype(aElement, complexType, &isValid);
00315     }
00316   } else {
00317     rv = NS_ERROR_UNEXPECTED;
00318   }
00319 
00320   *aResult = isValid;
00321   return rv;
00322 }
00323 
00324 /*
00325   Returns the nsISchemaType for a given value/type/namespace pair.
00326 */
00327 NS_IMETHODIMP
00328 nsSchemaValidator::GetType(const nsAString & aType,
00329                            const nsAString & aNamespace,
00330                            nsISchemaType ** aSchemaType)
00331 {
00332   nsresult rv;
00333 
00334   if (!mSchema) {
00335     // if we are a built-in type, we can get a nsISchemaType for it from
00336     // nsISchemaCollection->GetType.
00337     nsCOMPtr<nsISchemaLoader> schemaLoader =
00338       do_CreateInstance("@mozilla.org/xmlextras/schemas/schemaloader;1", &rv);
00339     NS_ENSURE_SUCCESS(rv, rv);
00340     mSchema = do_QueryInterface(schemaLoader);
00341     NS_ENSURE_STATE(mSchema);
00342   }
00343 
00344   // First try looking for xsi:type
00345   rv = mSchema->GetType(aType, aNamespace, aSchemaType);
00346   NS_ENSURE_SUCCESS(rv, rv);
00347 
00348   // maybe its a xsd:element
00349   if (!*aSchemaType) {
00350     nsCOMPtr<nsISchemaElement> schemaElement;
00351     rv = mSchema->GetElement(aType, aNamespace, getter_AddRefs(schemaElement));
00352     NS_ENSURE_SUCCESS(rv, rv);
00353 
00354     if (schemaElement) {
00355       rv = schemaElement->GetType(aSchemaType);
00356       NS_ENSURE_SUCCESS(rv, rv);
00357     }
00358 
00359     if (!*aSchemaType) {
00360       // if its not a built-in type as well, its an unknown schema type.
00361       LOG(("    Error: The Schema type was not found.\n"));
00362       rv = NS_ERROR_SCHEMAVALIDATOR_TYPE_NOT_FOUND;
00363     }
00364   }
00365 
00366   return rv;
00367 }
00368 
00369 nsresult
00370 nsSchemaValidator::ValidateSimpletype(const nsAString & aNodeValue,
00371                                       nsISchemaSimpleType *aSchemaSimpleType,
00372                                       PRBool *aResult)
00373 {
00374   NS_ENSURE_ARG(aSchemaSimpleType);
00375 
00376   // get the simpletype type.
00377   PRUint16 simpleTypeValue;
00378   nsresult rv = aSchemaSimpleType->GetSimpleType(&simpleTypeValue);
00379   NS_ENSURE_SUCCESS(rv, rv);
00380 
00381   PRBool isValid = PR_FALSE;
00382   switch (simpleTypeValue) {
00383     case nsISchemaSimpleType::SIMPLE_TYPE_RESTRICTION: {
00384       // handle simpletypes with restrictions
00385       rv = ValidateRestrictionSimpletype(aNodeValue, aSchemaSimpleType, &isValid);
00386       break;
00387     }
00388 
00389     case nsISchemaSimpleType::SIMPLE_TYPE_BUILTIN: {
00390       // handle built-in types
00391       rv = ValidateBuiltinType(aNodeValue, aSchemaSimpleType, &isValid);
00392       break;
00393     }
00394 
00395     case nsISchemaSimpleType::SIMPLE_TYPE_LIST: {
00396       // handle lists
00397       rv = ValidateListSimpletype(aNodeValue, aSchemaSimpleType, nsnull,
00398                                   &isValid);
00399       break;
00400     }
00401 
00402     case nsISchemaSimpleType::SIMPLE_TYPE_UNION: {
00403       // handle unions
00404       rv = ValidateUnionSimpletype(aNodeValue, aSchemaSimpleType, &isValid);
00405       break;
00406     }
00407   }
00408 
00409   *aResult = isValid;
00410   return rv;
00411 }
00412 
00413 nsresult
00414 nsSchemaValidator::ValidateDerivedSimpletype(const nsAString & aNodeValue,
00415                                              nsSchemaDerivedSimpleType *aDerived,
00416                                              PRBool *aResult)
00417 {
00418   // This method is called when validating a simpletype that derives from another
00419   // simpletype.
00420 
00421   PRBool isValid = PR_FALSE;
00422 
00423   PRUint16 simpleTypeValue;
00424   nsresult rv = aDerived->mBaseType->GetSimpleType(&simpleTypeValue);
00425 
00426   switch (simpleTypeValue) {
00427     case nsISchemaSimpleType::SIMPLE_TYPE_BUILTIN: {
00428       rv = ValidateDerivedBuiltinType(aNodeValue, aDerived, &isValid);
00429       break;
00430     }
00431 
00432     case nsISchemaSimpleType::SIMPLE_TYPE_RESTRICTION: {
00433       // this happens when for example someone derives from a union which then
00434       // derives from another type.
00435       rv = nsSchemaValidatorUtils::GetDerivedSimpleType(aDerived->mBaseType,
00436                                                         aDerived);
00437       ValidateDerivedSimpletype(aNodeValue, aDerived, &isValid);
00438       break;
00439     }
00440 
00441     case nsISchemaSimpleType::SIMPLE_TYPE_LIST: {
00442       rv = ValidateListSimpletype(aNodeValue, aDerived->mBaseType, aDerived,
00443                                   &isValid);
00444       break;
00445     }
00446 
00447     case nsISchemaSimpleType::SIMPLE_TYPE_UNION: {
00448       rv = ValidateDerivedUnionSimpletype(aNodeValue, aDerived, &isValid);
00449       break;
00450     }
00451   }
00452 
00453   *aResult = isValid;
00454   return rv;
00455 }
00456 
00461 nsresult
00462 nsSchemaValidator::ValidateRestrictionSimpletype(const nsAString & aNodeValue,
00463                                                  nsISchemaSimpleType *aType,
00464                                                  PRBool *aResult)
00465 {
00466   PRBool isValid = PR_FALSE;
00467 
00468   nsCOMPtr<nsISchemaRestrictionType> restrictionType = do_QueryInterface(aType);
00469   NS_ENSURE_STATE(restrictionType);
00470 
00471   LOG(("  The simpletype definition contains restrictions."));
00472 
00473   nsCOMPtr<nsISchemaSimpleType> simpleBaseType;
00474   nsresult rv = restrictionType->GetBaseType(getter_AddRefs(simpleBaseType));
00475   NS_ENSURE_SUCCESS(rv, rv);
00476 
00477   nsSchemaDerivedSimpleType derivedType;
00478   rv = nsSchemaValidatorUtils::GetDerivedSimpleType(aType, &derivedType);
00479   rv = ValidateDerivedSimpletype(aNodeValue, &derivedType, &isValid);
00480   *aResult = isValid;
00481   return rv;
00482 }
00483 
00484 nsresult
00485 nsSchemaValidator::ValidateDerivedBuiltinType(const nsAString & aNodeValue,
00486                                               nsSchemaDerivedSimpleType *aDerived,
00487                                               PRBool *aResult)
00488 {
00489   PRBool isValid = PR_FALSE;
00490   // now that we have loaded all the restriction facets,
00491   // check the base type and validate
00492   nsCOMPtr<nsISchemaBuiltinType> schemaBuiltinType =
00493     do_QueryInterface(aDerived->mBaseType);
00494   NS_ENSURE_STATE(schemaBuiltinType);
00495 
00496   PRUint16 builtinTypeValue;
00497   nsresult rv = schemaBuiltinType->GetBuiltinType(&builtinTypeValue);
00498 
00499 #ifdef PR_LOGGING
00500   DumpBaseType(schemaBuiltinType);
00501 #endif
00502 
00503   switch (builtinTypeValue) {
00504     case nsISchemaBuiltinType::BUILTIN_TYPE_STRING: {
00505       rv = ValidateBuiltinTypeString(aNodeValue,
00506                                      aDerived->length.value,
00507                                      aDerived->length.isDefined,
00508                                      aDerived->minLength.value,
00509                                      aDerived->minLength.isDefined,
00510                                      aDerived->maxLength.value,
00511                                      aDerived->maxLength.isDefined,
00512                                      &aDerived->enumerationList,
00513                                      &isValid);
00514       break;
00515     }
00516 
00517     case nsISchemaBuiltinType::BUILTIN_TYPE_NORMALIZED_STRING: {
00518       if (nsSchemaValidatorUtils::IsValidSchemaNormalizedString(aNodeValue)) {
00519         rv = ValidateBuiltinTypeString(aNodeValue,
00520                                        aDerived->length.value,
00521                                        aDerived->length.isDefined,
00522                                        aDerived->minLength.value,
00523                                        aDerived->minLength.isDefined,
00524                                        aDerived->maxLength.value,
00525                                        aDerived->maxLength.isDefined,
00526                                        &aDerived->enumerationList,
00527                                        &isValid);
00528       }
00529       break;
00530     }
00531 
00532     case nsISchemaBuiltinType::BUILTIN_TYPE_TOKEN: {
00533       if (nsSchemaValidatorUtils::IsValidSchemaToken(aNodeValue)) {
00534         rv = ValidateBuiltinTypeString(aNodeValue,
00535                                        aDerived->length.value,
00536                                        aDerived->length.isDefined,
00537                                        aDerived->minLength.value,
00538                                        aDerived->minLength.isDefined,
00539                                        aDerived->maxLength.value,
00540                                        aDerived->maxLength.isDefined,
00541                                        &aDerived->enumerationList,
00542                                        &isValid);
00543       }
00544       break;
00545     }
00546 
00547     case nsISchemaBuiltinType::BUILTIN_TYPE_LANGUAGE: {
00548       if (nsSchemaValidatorUtils::IsValidSchemaLanguage(aNodeValue)) {
00549         rv = ValidateBuiltinTypeString(aNodeValue,
00550                                        aDerived->length.value,
00551                                        aDerived->length.isDefined,
00552                                        aDerived->minLength.value,
00553                                        aDerived->minLength.isDefined,
00554                                        aDerived->maxLength.value,
00555                                        aDerived->maxLength.isDefined,
00556                                        &aDerived->enumerationList,
00557                                        &isValid);
00558       }
00559       break;
00560     }
00561 
00562     case nsISchemaBuiltinType::BUILTIN_TYPE_BOOLEAN: {
00563       rv = ValidateBuiltinTypeBoolean(aNodeValue, &isValid);
00564       break;
00565     }
00566 
00567     case nsISchemaBuiltinType::BUILTIN_TYPE_GDAY: {
00568       rv = ValidateBuiltinTypeGDay(aNodeValue,
00569                                    aDerived->maxExclusive.value,
00570                                    aDerived->minExclusive.value,
00571                                    aDerived->maxInclusive.value,
00572                                    aDerived->minInclusive.value,
00573                                    &isValid);
00574       break;
00575     }
00576 
00577     case nsISchemaBuiltinType::BUILTIN_TYPE_GMONTH: {
00578       rv = ValidateBuiltinTypeGMonth(aNodeValue,
00579                                      aDerived->maxExclusive.value,
00580                                      aDerived->minExclusive.value,
00581                                      aDerived->maxInclusive.value,
00582                                      aDerived->minInclusive.value,
00583                                      &isValid);
00584       break;
00585     }
00586 
00587     case nsISchemaBuiltinType::BUILTIN_TYPE_GYEAR: {
00588       rv = ValidateBuiltinTypeGYear(aNodeValue,
00589                                     aDerived->maxExclusive.value,
00590                                     aDerived->minExclusive.value,
00591                                     aDerived->maxInclusive.value,
00592                                     aDerived->minInclusive.value,
00593                                     &isValid);
00594       break;
00595     }
00596 
00597     case nsISchemaBuiltinType::BUILTIN_TYPE_GYEARMONTH: {
00598       rv = ValidateBuiltinTypeGYearMonth(aNodeValue,
00599                                          aDerived->maxExclusive.value,
00600                                          aDerived->minExclusive.value,
00601                                          aDerived->maxInclusive.value,
00602                                          aDerived->minInclusive.value,
00603                                          &isValid);
00604       break;
00605     }
00606 
00607     case nsISchemaBuiltinType::BUILTIN_TYPE_GMONTHDAY: {
00608       rv = ValidateBuiltinTypeGMonthDay(aNodeValue,
00609                                         aDerived->maxExclusive.value,
00610                                         aDerived->minExclusive.value,
00611                                         aDerived->maxInclusive.value,
00612                                         aDerived->minInclusive.value,
00613                                         &isValid);
00614       break;
00615     }
00616 
00617     case nsISchemaBuiltinType::BUILTIN_TYPE_DATE: {
00618       rv = ValidateBuiltinTypeDate(aNodeValue,
00619                                    aDerived->maxExclusive.value,
00620                                    aDerived->minExclusive.value,
00621                                    aDerived->maxInclusive.value,
00622                                    aDerived->minInclusive.value,
00623                                    &isValid);
00624       break;
00625     }
00626 
00627     case nsISchemaBuiltinType::BUILTIN_TYPE_TIME: {
00628       rv = ValidateBuiltinTypeTime(aNodeValue,
00629                                    aDerived->maxExclusive.value,
00630                                    aDerived->minExclusive.value,
00631                                    aDerived->maxInclusive.value,
00632                                    aDerived->minInclusive.value,
00633                                    &isValid);
00634       break;
00635     }
00636 
00637     case nsISchemaBuiltinType::BUILTIN_TYPE_DATETIME: {
00638       rv = ValidateBuiltinTypeDateTime(aNodeValue,
00639                                        aDerived->maxExclusive.value,
00640                                        aDerived->minExclusive.value,
00641                                        aDerived->maxInclusive.value,
00642                                        aDerived->minInclusive.value,
00643                                        &isValid);
00644       break;
00645     }
00646 
00647     case nsISchemaBuiltinType::BUILTIN_TYPE_DURATION: {
00648       rv = ValidateBuiltinTypeDuration(aNodeValue,
00649                                        aDerived->maxExclusive.value,
00650                                        aDerived->minExclusive.value,
00651                                        aDerived->maxInclusive.value,
00652                                        aDerived->minInclusive.value,
00653                                        &isValid);
00654       break;
00655     }
00656 
00657     case nsISchemaBuiltinType::BUILTIN_TYPE_INTEGER: {
00658       rv = ValidateBuiltinTypeInteger(aNodeValue,
00659                                       aDerived->totalDigits.value,
00660                                       aDerived->maxExclusive.value,
00661                                       aDerived->minExclusive.value,
00662                                       aDerived->maxInclusive.value,
00663                                       aDerived->minInclusive.value,
00664                                       &aDerived->enumerationList,
00665                                       &isValid);
00666       break;
00667     }
00668 
00669     /* http://w3.org/TR/xmlschema-2/#nonPositiveInteger */
00670     case nsISchemaBuiltinType::BUILTIN_TYPE_NONPOSITIVEINTEGER: {
00671       if (aDerived->maxExclusive.value.IsEmpty()) {
00672         aDerived->maxExclusive.value.AssignLiteral("1");
00673       } else if (aDerived->maxInclusive.value.IsEmpty()) {
00674         aDerived->maxInclusive.value.AssignLiteral("0");
00675       }
00676 
00677       rv = ValidateBuiltinTypeInteger(aNodeValue,
00678                                       aDerived->totalDigits.value,
00679                                       aDerived->maxExclusive.value,
00680                                       aDerived->minExclusive.value,
00681                                       aDerived->maxInclusive.value,
00682                                       aDerived->minInclusive.value,
00683                                       &aDerived->enumerationList,
00684                                       &isValid);
00685       break;
00686     }
00687 
00688     /* http://w3.org/TR/xmlschema-2/#nonNegativeInteger */
00689     case nsISchemaBuiltinType::BUILTIN_TYPE_NONNEGATIVEINTEGER: {
00690       if (aDerived->minExclusive.value.IsEmpty()) {
00691         aDerived->minExclusive.value.AssignLiteral("-1");
00692       } else if (aDerived->minInclusive.value.IsEmpty()) {
00693         aDerived->minInclusive.value.AssignLiteral("0");
00694       }
00695 
00696       rv = ValidateBuiltinTypeInteger(aNodeValue,
00697                                       aDerived->totalDigits.value,
00698                                       aDerived->maxExclusive.value,
00699                                       aDerived->minExclusive.value,
00700                                       aDerived->maxInclusive.value,
00701                                       aDerived->minInclusive.value,
00702                                       &aDerived->enumerationList,
00703                                       &isValid);
00704       break;
00705     }
00706 
00707     /* http://www.w3.org/TR/xmlschema-2/#negativeInteger */
00708     case nsISchemaBuiltinType::BUILTIN_TYPE_NEGATIVEINTEGER: {
00709       if (aDerived->maxExclusive.value.IsEmpty()) {
00710         aDerived->maxExclusive.value.AssignLiteral("0");
00711       } else if (aDerived->maxInclusive.value.IsEmpty()) {
00712         aDerived->maxInclusive.value.AssignLiteral("-1");
00713       }
00714 
00715       rv = ValidateBuiltinTypeInteger(aNodeValue,
00716                                       aDerived->totalDigits.value,
00717                                       aDerived->maxExclusive.value,
00718                                       aDerived->minExclusive.value,
00719                                       aDerived->maxInclusive.value,
00720                                       aDerived->minInclusive.value,
00721                                       &aDerived->enumerationList,
00722                                       &isValid);
00723       break;
00724     }
00725 
00726     /* http://w3.org/TR/xmlschema-2/#positiveInteger */
00727     case nsISchemaBuiltinType::BUILTIN_TYPE_POSITIVEINTEGER: {
00728       if (aDerived->minInclusive.value.IsEmpty()) {
00729         aDerived->minInclusive.value.AssignLiteral("1");
00730       } else if (aDerived->minExclusive.value.IsEmpty()) {
00731         aDerived->minExclusive.value.AssignLiteral("0");
00732       }
00733 
00734       rv = ValidateBuiltinTypeInteger(aNodeValue,
00735                                       aDerived->totalDigits.value,
00736                                       aDerived->maxExclusive.value,
00737                                       aDerived->minExclusive.value,
00738                                       aDerived->maxInclusive.value,
00739                                       aDerived->minInclusive.value,
00740                                       &aDerived->enumerationList,
00741                                       &isValid);
00742       break;
00743     }
00744 
00745     /* http://www.w3.org/TR/xmlschema-2/#long */
00746     case nsISchemaBuiltinType::BUILTIN_TYPE_LONG: {
00747       if (aDerived->maxInclusive.value.IsEmpty()) {
00748         aDerived->maxInclusive.value.AssignLiteral("9223372036854775807");
00749       }
00750 
00751       if (aDerived->minInclusive.value.IsEmpty()) {
00752         aDerived->minInclusive.value.AssignLiteral("-9223372036854775808");
00753       }
00754 
00755       rv = ValidateBuiltinTypeInteger(aNodeValue,
00756                                       aDerived->totalDigits.value,
00757                                       aDerived->maxExclusive.value,
00758                                       aDerived->minExclusive.value,
00759                                       aDerived->maxInclusive.value,
00760                                       aDerived->minInclusive.value,
00761                                       &aDerived->enumerationList,
00762                                       &isValid);
00763       break;
00764     }
00765 
00766     /* http://www.w3.org/TR/xmlschema-2/#int */
00767     case nsISchemaBuiltinType::BUILTIN_TYPE_INT: {
00768       if (aDerived->maxInclusive.value.IsEmpty()) {
00769         aDerived->maxInclusive.value.AssignLiteral("2147483647");
00770       }
00771 
00772       if (aDerived->minInclusive.value.IsEmpty()) {
00773         aDerived->minInclusive.value.AssignLiteral("-2147483648");
00774       }
00775 
00776       rv = ValidateBuiltinTypeInteger(aNodeValue,
00777                                       aDerived->totalDigits.value,
00778                                       aDerived->maxExclusive.value,
00779                                       aDerived->minExclusive.value,
00780                                       aDerived->maxInclusive.value,
00781                                       aDerived->minInclusive.value,
00782                                       &aDerived->enumerationList,
00783                                       &isValid);
00784       break;
00785     }
00786 
00787     /* http://www.w3.org/TR/xmlschema-2/#short */
00788     case nsISchemaBuiltinType::BUILTIN_TYPE_SHORT: {
00789       if (aDerived->maxInclusive.value.IsEmpty()) {
00790         aDerived->maxInclusive.value.AssignLiteral("32767");
00791       }
00792 
00793       if (aDerived->minInclusive.value.IsEmpty()) {
00794         aDerived->minInclusive.value.AssignLiteral("-32768");
00795       }
00796 
00797       rv = ValidateBuiltinTypeInteger(aNodeValue,
00798                                       aDerived->totalDigits.value,
00799                                       aDerived->maxExclusive.value,
00800                                       aDerived->minExclusive.value,
00801                                       aDerived->maxInclusive.value,
00802                                       aDerived->minInclusive.value,
00803                                       &aDerived->enumerationList,
00804                                       &isValid);
00805       break;
00806     }
00807 
00808     /* http://www.w3.org/TR/xmlschema-2/#unsignedLong */
00809     case nsISchemaBuiltinType::BUILTIN_TYPE_UNSIGNEDLONG: {
00810       if (aDerived->maxInclusive.value.IsEmpty()) {
00811         aDerived->maxInclusive.value.AssignLiteral("18446744073709551615");
00812       }
00813 
00814       if (aDerived->minInclusive.value.IsEmpty()) {
00815         aDerived->minInclusive.value.AssignLiteral("0");
00816       }
00817 
00818       rv = ValidateBuiltinTypeInteger(aNodeValue,
00819                                       aDerived->totalDigits.value,
00820                                       aDerived->maxExclusive.value,
00821                                       aDerived->minExclusive.value,
00822                                       aDerived->maxInclusive.value,
00823                                       aDerived->minInclusive.value,
00824                                       &aDerived->enumerationList,
00825                                       &isValid);
00826       break;
00827     }
00828 
00829     /* http://www.w3.org/TR/xmlschema-2/#unsignedInt */
00830     case nsISchemaBuiltinType::BUILTIN_TYPE_UNSIGNEDINT: {
00831       if (aDerived->maxInclusive.value.IsEmpty()) {
00832         aDerived->maxInclusive.value.AssignLiteral("4294967295");
00833       }
00834 
00835       if (aDerived->minInclusive.value.IsEmpty()) {
00836         aDerived->minInclusive.value.AssignLiteral("0");
00837       }
00838 
00839       rv = ValidateBuiltinTypeInteger(aNodeValue,
00840                                       aDerived->totalDigits.value,
00841                                       aDerived->maxExclusive.value,
00842                                       aDerived->minExclusive.value,
00843                                       aDerived->maxInclusive.value,
00844                                       aDerived->minInclusive.value,
00845                                       &aDerived->enumerationList,
00846                                       &isValid);
00847       break;
00848     }
00849 
00850     /* http://www.w3.org/TR/xmlschema-2/#unsignedShort */
00851     case nsISchemaBuiltinType::BUILTIN_TYPE_UNSIGNEDSHORT: {
00852       if (aDerived->maxInclusive.value.IsEmpty()) {
00853         aDerived->maxInclusive.value.AssignLiteral("65535");
00854       }
00855 
00856       if (aDerived->minInclusive.value.IsEmpty()) {
00857         aDerived->minInclusive.value.AssignLiteral("0");
00858       }
00859 
00860       rv = ValidateBuiltinTypeInteger(aNodeValue,
00861                                       aDerived->totalDigits.value,
00862                                       aDerived->maxExclusive.value,
00863                                       aDerived->minExclusive.value,
00864                                       aDerived->maxInclusive.value,
00865                                       aDerived->minInclusive.value,
00866                                       &aDerived->enumerationList,
00867                                       &isValid);
00868       break;
00869     }
00870 
00871     /* http://www.w3.org/TR/xmlschema-2/#unsignedByte */
00872     case nsISchemaBuiltinType::BUILTIN_TYPE_UNSIGNEDBYTE: {
00873       if (aDerived->maxInclusive.value.IsEmpty()) {
00874         aDerived->maxInclusive.value.AssignLiteral("255");
00875       }
00876 
00877       if (aDerived->minInclusive.value.IsEmpty()) {
00878         aDerived->minInclusive.value.AssignLiteral("0");
00879       }
00880 
00881       rv = ValidateBuiltinTypeInteger(aNodeValue,
00882                                       aDerived->totalDigits.value,
00883                                       aDerived->maxExclusive.value,
00884                                       aDerived->minExclusive.value,
00885                                       aDerived->maxInclusive.value,
00886                                       aDerived->minInclusive.value,
00887                                       &aDerived->enumerationList,
00888                                       &isValid);
00889       break;
00890     }
00891 
00892     case nsISchemaBuiltinType::BUILTIN_TYPE_BYTE: {
00893       rv = ValidateBuiltinTypeByte(aNodeValue,
00894                                    aDerived->totalDigits.value,
00895                                    aDerived->maxExclusive.value,
00896                                    aDerived->minExclusive.value,
00897                                    aDerived->maxInclusive.value,
00898                                    aDerived->minInclusive.value,
00899                                    &aDerived->enumerationList,
00900                                    &isValid);
00901       break;
00902     }
00903 
00904     case nsISchemaBuiltinType::BUILTIN_TYPE_FLOAT: {
00905       rv = ValidateBuiltinTypeFloat(aNodeValue,
00906                                     aDerived->totalDigits.value,
00907                                     aDerived->maxExclusive.value,
00908                                     aDerived->minExclusive.value,
00909                                     aDerived->maxInclusive.value,
00910                                     aDerived->minInclusive.value,
00911                                     &aDerived->enumerationList,
00912                                     &isValid);
00913       break;
00914     }
00915 
00916     case nsISchemaBuiltinType::BUILTIN_TYPE_DOUBLE: {
00917       rv = ValidateBuiltinTypeDouble(aNodeValue,
00918                                     aDerived->totalDigits.value,
00919                                     aDerived->maxExclusive.value,
00920                                     aDerived->minExclusive.value,
00921                                     aDerived->maxInclusive.value,
00922                                     aDerived->minInclusive.value,
00923                                     &aDerived->enumerationList,
00924                                     &isValid);
00925       break;
00926     }
00927 
00928     case nsISchemaBuiltinType::BUILTIN_TYPE_DECIMAL: {
00929       rv = ValidateBuiltinTypeDecimal(aNodeValue,
00930                                       aDerived->totalDigits.value,
00931                                       aDerived->fractionDigits.value,
00932                                       aDerived->fractionDigits.isDefined,
00933                                       aDerived->maxExclusive.value,
00934                                       aDerived->minExclusive.value,
00935                                       aDerived->maxInclusive.value,
00936                                       aDerived->minInclusive.value,
00937                                       &aDerived->enumerationList,
00938                                       &isValid);
00939       break;
00940     }
00941 
00942     case nsISchemaBuiltinType::BUILTIN_TYPE_ANYURI: {
00943       rv = ValidateBuiltinTypeAnyURI(aNodeValue,
00944                                      aDerived->length.value,
00945                                      aDerived->minLength.value,
00946                                      aDerived->maxLength.value,
00947                                      &aDerived->enumerationList,
00948                                      &isValid);
00949       break;
00950     }
00951 
00952     case nsISchemaBuiltinType::BUILTIN_TYPE_BASE64BINARY: {
00953       rv = ValidateBuiltinTypeBase64Binary(aNodeValue,
00954                                            aDerived->length.value,
00955                                            aDerived->length.isDefined,
00956                                            aDerived->minLength.value,
00957                                            aDerived->minLength.isDefined,
00958                                            aDerived->maxLength.value,
00959                                            aDerived->maxLength.isDefined,
00960                                            &aDerived->enumerationList,
00961                                            &isValid);
00962       break;
00963     }
00964 
00965     case nsISchemaBuiltinType::BUILTIN_TYPE_HEXBINARY: {
00966       rv = ValidateBuiltinTypeHexBinary(aNodeValue,
00967                                         aDerived->length.value,
00968                                         aDerived->length.isDefined,
00969                                         aDerived->minLength.value,
00970                                         aDerived->minLength.isDefined,
00971                                         aDerived->maxLength.value,
00972                                         aDerived->maxLength.isDefined,
00973                                         &aDerived->enumerationList,
00974                                         &isValid);
00975       break;
00976     }
00977 
00978     case nsISchemaBuiltinType::BUILTIN_TYPE_QNAME: {
00979       rv = ValidateBuiltinTypeQName(aNodeValue,
00980                                     aDerived->length.value,
00981                                     aDerived->length.isDefined,
00982                                     aDerived->minLength.value,
00983                                     aDerived->minLength.isDefined,
00984                                     aDerived->maxLength.value,
00985                                     aDerived->maxLength.isDefined,
00986                                     &aDerived->enumerationList,
00987                                     &isValid);
00988       break;
00989     }
00990     /* http://www.w3.org/TR/xmlschema-2/#name */
00991     case nsISchemaBuiltinType::BUILTIN_TYPE_NAME: {
00992       if (nsSchemaValidatorUtils::IsValidSchemaName(aNodeValue)) {
00993         rv = ValidateBuiltinTypeString(aNodeValue,
00994                                        aDerived->length.value,
00995                                        aDerived->length.isDefined,
00996                                        aDerived->minLength.value,
00997                                        aDerived->minLength.isDefined,
00998                                        aDerived->maxLength.value,
00999                                        aDerived->maxLength.isDefined,
01000                                        &aDerived->enumerationList,
01001                                        &isValid);
01002       }
01003       break;
01004     }
01005     case nsISchemaBuiltinType::BUILTIN_TYPE_NCNAME: {
01006       if (nsSchemaValidatorUtils::IsValidSchemaNCName(aNodeValue)) {
01007         rv = ValidateBuiltinTypeString(aNodeValue,
01008                                        aDerived->length.value,
01009                                        aDerived->length.isDefined,
01010                                        aDerived->minLength.value,
01011                                        aDerived->minLength.isDefined,
01012                                        aDerived->maxLength.value,
01013                                        aDerived->maxLength.isDefined,
01014                                        &aDerived->enumerationList,
01015                                        &isValid);
01016       }
01017       break;
01018     }
01019     case nsISchemaBuiltinType::BUILTIN_TYPE_ID: {
01020       if (nsSchemaValidatorUtils::IsValidSchemaID(aNodeValue)) {
01021         rv = ValidateBuiltinTypeString(aNodeValue,
01022                                        aDerived->length.value,
01023                                        aDerived->length.isDefined,
01024                                        aDerived->minLength.value,
01025                                        aDerived->minLength.isDefined,
01026                                        aDerived->maxLength.value,
01027                                        aDerived->maxLength.isDefined,
01028                                        &aDerived->enumerationList,
01029                                        &isValid);
01030       }
01031       break;
01032     }
01033     case nsISchemaBuiltinType::BUILTIN_TYPE_IDREF: {
01034       if (nsSchemaValidatorUtils::IsValidSchemaIDRef(aNodeValue)) {
01035         rv = ValidateBuiltinTypeString(aNodeValue,
01036                                        aDerived->length.value,
01037                                        aDerived->length.isDefined,
01038                                        aDerived->minLength.value,
01039                                        aDerived->minLength.isDefined,
01040                                        aDerived->maxLength.value,
01041                                        aDerived->maxLength.isDefined,
01042                                        &aDerived->enumerationList,
01043                                        &isValid);
01044       }
01045       break;
01046     }
01047     case nsISchemaBuiltinType::BUILTIN_TYPE_IDREFS: {
01048       if (nsSchemaValidatorUtils::IsValidSchemaIDRefs(aNodeValue)) {
01049         rv = ValidateBuiltinTypeString(aNodeValue,
01050                                        aDerived->length.value,
01051                                        aDerived->length.isDefined,
01052                                        aDerived->minLength.value,
01053                                        aDerived->minLength.isDefined,
01054                                        aDerived->maxLength.value,
01055                                        aDerived->maxLength.isDefined,
01056                                        &aDerived->enumerationList,
01057                                        &isValid);
01058       }
01059       break;
01060     }
01061     case nsISchemaBuiltinType::BUILTIN_TYPE_NMTOKEN: {
01062       if (nsSchemaValidatorUtils::IsValidSchemaNMToken(aNodeValue)) {
01063         rv = ValidateBuiltinTypeString(aNodeValue,
01064                                        aDerived->length.value,
01065                                        aDerived->length.isDefined,
01066                                        aDerived->minLength.value,
01067                                        aDerived->minLength.isDefined,
01068                                        aDerived->maxLength.value,
01069                                        aDerived->maxLength.isDefined,
01070                                        &aDerived->enumerationList,
01071                                        &isValid);
01072       }
01073       break;
01074     }
01075     case nsISchemaBuiltinType::BUILTIN_TYPE_NMTOKENS: {
01076       if (nsSchemaValidatorUtils::IsValidSchemaNMTokens(aNodeValue)) {
01077         rv = ValidateBuiltinTypeString(aNodeValue,
01078                                        aDerived->length.value,
01079                                        aDerived->length.isDefined,
01080                                        aDerived->minLength.value,
01081                                        aDerived->minLength.isDefined,
01082                                        aDerived->maxLength.value,
01083                                        aDerived->maxLength.isDefined,
01084                                        &aDerived->enumerationList,
01085                                        &isValid);
01086       }
01087       break;
01088     }
01089 
01090     default:
01091       rv = NS_ERROR_SCHEMAVALIDATOR_TYPE_NOT_FOUND;
01092       break;
01093   }
01094 
01095   // finally check if a pattern is defined, as all types can be constrained by
01096   // regexp patterns.
01097   if (isValid && aDerived->pattern.isDefined) {
01098     // check if the pattern matches
01099     nsCOMPtr<nsISchemaValidatorRegexp> regexp = do_GetService(kREGEXP_CID);
01100     rv = regexp->RunRegexp(aNodeValue, aDerived->pattern.value, "g", &isValid);
01101     NS_ENSURE_SUCCESS(rv, rv);
01102 
01103 #ifdef PR_LOGGING
01104     LOG(("  Checking Regular Expression"));
01105     if (isValid) {
01106       LOG(("    -- pattern validates!"));
01107     } else {
01108       LOG(("    -- pattern does not validate!"));
01109     }
01110 #endif
01111   }
01112 
01113   *aResult = isValid;
01114   return rv;
01115 }
01116 
01117 /*
01118   Handles validation of built-in schema types.
01119 */
01120 nsresult
01121 nsSchemaValidator::ValidateBuiltinType(const nsAString & aNodeValue,
01122                                        nsISchemaSimpleType *aSchemaSimpleType,
01123                                        PRBool *aResult)
01124 {
01125   nsCOMPtr<nsISchemaBuiltinType> builtinType =
01126     do_QueryInterface(aSchemaSimpleType);
01127   NS_ENSURE_STATE(builtinType);
01128 
01129   PRUint16 builtinTypeValue;
01130   nsresult rv = builtinType->GetBuiltinType(&builtinTypeValue);
01131   NS_ENSURE_SUCCESS(rv, rv);
01132 
01133 #ifdef PR_LOGGING
01134   DumpBaseType(builtinType);
01135 #endif
01136 
01137   PRBool isValid = PR_FALSE;
01138 
01139   switch(builtinTypeValue) {
01140     case nsISchemaBuiltinType::BUILTIN_TYPE_STRING: {
01141       isValid = PR_TRUE;
01142       break;
01143     }
01144 
01145     case nsISchemaBuiltinType::BUILTIN_TYPE_NORMALIZED_STRING: {
01146       if (nsSchemaValidatorUtils::IsValidSchemaNormalizedString(aNodeValue)) {
01147         rv = ValidateBuiltinTypeString(aNodeValue, 0, PR_FALSE, 0, PR_FALSE, 0,
01148                                        PR_FALSE, nsnull, &isValid);
01149       }
01150       break;
01151     }
01152 
01153     case nsISchemaBuiltinType::BUILTIN_TYPE_TOKEN: {
01154       if (nsSchemaValidatorUtils::IsValidSchemaToken(aNodeValue)) {
01155         rv = ValidateBuiltinTypeString(aNodeValue, 0, PR_FALSE, 0, PR_FALSE, 0,
01156                                        PR_FALSE, nsnull, &isValid);
01157       }
01158       break;
01159     }
01160 
01161     case nsISchemaBuiltinType::BUILTIN_TYPE_LANGUAGE: {
01162       if (nsSchemaValidatorUtils::IsValidSchemaLanguage(aNodeValue)) {
01163         rv = ValidateBuiltinTypeString(aNodeValue, 0, PR_FALSE, 0, PR_FALSE, 0,
01164                                        PR_FALSE, nsnull, &isValid);
01165       }
01166       break;
01167     }
01168 
01169     case nsISchemaBuiltinType::BUILTIN_TYPE_BOOLEAN: {
01170       rv = ValidateBuiltinTypeBoolean(aNodeValue, &isValid);
01171       break;
01172     }
01173 
01174     case nsISchemaBuiltinType::BUILTIN_TYPE_GDAY: {
01175       isValid = IsValidSchemaGDay(aNodeValue, nsnull);
01176       break;
01177     }
01178 
01179     case nsISchemaBuiltinType::BUILTIN_TYPE_GMONTH: {
01180       isValid = IsValidSchemaGMonth(aNodeValue, nsnull);
01181       break;
01182     }
01183 
01184     case nsISchemaBuiltinType::BUILTIN_TYPE_GYEAR: {
01185       isValid = IsValidSchemaGYear(aNodeValue, nsnull);
01186       break;
01187     }
01188 
01189     case nsISchemaBuiltinType::BUILTIN_TYPE_GYEARMONTH: {
01190       isValid = IsValidSchemaGYearMonth(aNodeValue, nsnull);
01191       break;
01192     }
01193 
01194     case nsISchemaBuiltinType::BUILTIN_TYPE_GMONTHDAY: {
01195       isValid = IsValidSchemaGMonthDay(aNodeValue, nsnull);
01196       break;
01197     }
01198 
01199     case nsISchemaBuiltinType::BUILTIN_TYPE_DATE: {
01200       nsSchemaDate tmp;
01201       isValid = IsValidSchemaDate(aNodeValue, &tmp);
01202       break;
01203     }
01204 
01205     case nsISchemaBuiltinType::BUILTIN_TYPE_TIME: {
01206       nsSchemaTime tmp;
01207       isValid = IsValidSchemaTime(aNodeValue, &tmp);
01208       break;
01209     }
01210 
01211     case nsISchemaBuiltinType::BUILTIN_TYPE_DATETIME: {
01212       nsSchemaDateTime tmp;
01213       isValid = IsValidSchemaDateTime(aNodeValue, &tmp);
01214       break;
01215     }
01216 
01217     case nsISchemaBuiltinType::BUILTIN_TYPE_DURATION: {
01218       nsCOMPtr<nsISchemaDuration> temp;
01219       isValid = IsValidSchemaDuration(aNodeValue, getter_AddRefs(temp));
01220       break;
01221     }
01222 
01223     case nsISchemaBuiltinType::BUILTIN_TYPE_INTEGER: {
01224       isValid = nsSchemaValidatorUtils::IsValidSchemaInteger(aNodeValue, nsnull);
01225       break;
01226     }
01227 
01228     /* http://w3.org/TR/xmlschema-2/#nonPositiveInteger */
01229     case nsISchemaBuiltinType::BUILTIN_TYPE_NONPOSITIVEINTEGER: {
01230       // nonPositiveInteger inherits from integer, with maxInclusive
01231       // being 0
01232       ValidateBuiltinTypeInteger(aNodeValue, nsnull, EmptyString(),
01233                                  EmptyString(), NS_LITERAL_STRING("0"),
01234                                  EmptyString(), nsnull, &isValid);
01235       break;
01236     }
01237 
01238     /* http://w3.org/TR/xmlschema-2/#nonNegativeInteger */
01239     case nsISchemaBuiltinType::BUILTIN_TYPE_NONNEGATIVEINTEGER: {
01240       // nonNegativeInteger inherits from integer, with minInclusive
01241       // being 0 (only positive integers)
01242       ValidateBuiltinTypeInteger(aNodeValue, nsnull, EmptyString(),
01243                                  EmptyString(), EmptyString(),
01244                                  NS_LITERAL_STRING("0"), nsnull, &isValid);
01245       break;
01246     }
01247 
01248     /* http://www.w3.org/TR/xmlschema-2/#negativeInteger */
01249     case nsISchemaBuiltinType::BUILTIN_TYPE_NEGATIVEINTEGER: {
01250       // negativeInteger inherits from integer, with maxInclusive
01251       // being -1 (only negative integers)
01252       ValidateBuiltinTypeInteger(aNodeValue, nsnull, EmptyString(),
01253                                  EmptyString(), NS_LITERAL_STRING("-1"),
01254                                  EmptyString(), nsnull, &isValid);
01255       break;
01256     }
01257 
01258     /* http://w3.org/TR/xmlschema-2/#positiveInteger */
01259     case nsISchemaBuiltinType::BUILTIN_TYPE_POSITIVEINTEGER: {
01260       // positiveInteger inherits from integer, with minInclusive
01261       // being 1
01262       ValidateBuiltinTypeInteger(aNodeValue, nsnull, EmptyString(),
01263                                  EmptyString(), EmptyString(),
01264                                  NS_LITERAL_STRING("1"), nsnull, &isValid);
01265       break;
01266     }
01267 
01268     /* http://www.w3.org/TR/xmlschema-2/#long */
01269     case nsISchemaBuiltinType::BUILTIN_TYPE_LONG: {
01270       // maxInclusive is 9223372036854775807 and minInclusive is
01271       // -9223372036854775808
01272       ValidateBuiltinTypeInteger(aNodeValue, nsnull,
01273                                  EmptyString(), EmptyString(),
01274                                  NS_LITERAL_STRING("9223372036854775807"),
01275                                  NS_LITERAL_STRING("-9223372036854775808"),
01276                                  nsnull, &isValid);
01277       break;
01278     }
01279 
01280     /* http://www.w3.org/TR/xmlschema-2/#int */
01281     case nsISchemaBuiltinType::BUILTIN_TYPE_INT: {
01282       // maxInclusive is 2147483647 and minInclusive is -2147483648
01283       ValidateBuiltinTypeInteger(aNodeValue, nsnull,
01284                                  EmptyString(), EmptyString(),
01285                                  NS_LITERAL_STRING("2147483647"),
01286                                  NS_LITERAL_STRING("-2147483648"),
01287                                  nsnull, &isValid);
01288       break;
01289     }
01290 
01291     /* http://www.w3.org/TR/xmlschema-2/#short */
01292     case nsISchemaBuiltinType::BUILTIN_TYPE_SHORT: {
01293       // maxInclusive is 32767 and minInclusive is -32768
01294       ValidateBuiltinTypeInteger(aNodeValue, nsnull,
01295                                  EmptyString(), EmptyString(),
01296                                  NS_LITERAL_STRING("32767"),
01297                                  NS_LITERAL_STRING("-32768"),
01298                                  nsnull, &isValid);
01299       break;
01300     }
01301 
01302     /* http://www.w3.org/TR/xmlschema-2/#unsignedLong */
01303     case nsISchemaBuiltinType::BUILTIN_TYPE_UNSIGNEDLONG: {
01304       // maxInclusive is 18446744073709551615. and minInclusive is 0
01305       ValidateBuiltinTypeInteger(aNodeValue, nsnull,
01306                                  EmptyString(), EmptyString(),
01307                                  NS_LITERAL_STRING("18446744073709551615"),
01308                                  NS_LITERAL_STRING("0"),
01309                                  nsnull, &isValid);
01310       break;
01311     }
01312 
01313     /* http://www.w3.org/TR/xmlschema-2/#unsignedInt */
01314     case nsISchemaBuiltinType::BUILTIN_TYPE_UNSIGNEDINT: {
01315       // maxInclusive is 4294967295. and minInclusive is 0
01316       ValidateBuiltinTypeInteger(aNodeValue, nsnull,
01317                                  EmptyString(), EmptyString(),
01318                                  NS_LITERAL_STRING("4294967295"),
01319                                  NS_LITERAL_STRING("0"),
01320                                  nsnull, &isValid);
01321       break;
01322     }
01323 
01324     /* http://www.w3.org/TR/xmlschema-2/#unsignedShort */
01325     case nsISchemaBuiltinType::BUILTIN_TYPE_UNSIGNEDSHORT: {
01326       // maxInclusive is 65535. and minInclusive is 0
01327       ValidateBuiltinTypeInteger(aNodeValue, nsnull,
01328                                  EmptyString(), EmptyString(),
01329                                  NS_LITERAL_STRING("65535"),
01330                                  NS_LITERAL_STRING("0"),
01331                                  nsnull, &isValid);
01332       break;
01333     }
01334 
01335     /* http://www.w3.org/TR/xmlschema-2/#unsignedByte */
01336     case nsISchemaBuiltinType::BUILTIN_TYPE_UNSIGNEDBYTE: {
01337       // maxInclusive is 255. and minInclusive is 0
01338       ValidateBuiltinTypeInteger(aNodeValue, nsnull,
01339                                  EmptyString(), EmptyString(),
01340                                  NS_LITERAL_STRING("255"),
01341                                  NS_LITERAL_STRING("0"),
01342                                  nsnull, &isValid);
01343       break;
01344     }
01345 
01346     case nsISchemaBuiltinType::BUILTIN_TYPE_BYTE: {
01347       isValid = IsValidSchemaByte(aNodeValue, nsnull);
01348       break;
01349     }
01350 
01351     case nsISchemaBuiltinType::BUILTIN_TYPE_FLOAT: {
01352       isValid = IsValidSchemaFloat(aNodeValue, nsnull);
01353       break;
01354     }
01355 
01356     case nsISchemaBuiltinType::BUILTIN_TYPE_DOUBLE: {
01357       isValid = IsValidSchemaDouble(aNodeValue, nsnull);
01358       break;
01359     }
01360 
01361     case nsISchemaBuiltinType::BUILTIN_TYPE_DECIMAL: {
01362       nsAutoString wholePart, fractionPart;
01363       isValid = IsValidSchemaDecimal(aNodeValue, wholePart, fractionPart);
01364       break;
01365     }
01366 
01367     case nsISchemaBuiltinType::BUILTIN_TYPE_ANYURI: {
01368       isValid = IsValidSchemaAnyURI(aNodeValue);
01369       break;
01370     }
01371 
01372     case nsISchemaBuiltinType::BUILTIN_TYPE_BASE64BINARY: {
01373       char* decodedString;
01374       isValid = IsValidSchemaBase64Binary(aNodeValue, &decodedString);
01375       nsMemory::Free(decodedString);
01376       break;
01377     }
01378 
01379     case nsISchemaBuiltinType::BUILTIN_TYPE_HEXBINARY: {
01380       isValid = IsValidSchemaHexBinary(aNodeValue);
01381       break;
01382     }
01383 
01384     case nsISchemaBuiltinType::BUILTIN_TYPE_QNAME: {
01385       isValid = IsValidSchemaQName(aNodeValue);
01386       break;
01387     }
01388     /* http://www.w3.org/TR/xmlschema-2/#name */
01389     case nsISchemaBuiltinType::BUILTIN_TYPE_NAME: {
01390       isValid = nsSchemaValidatorUtils::IsValidSchemaName(aNodeValue);
01391       break;
01392     }
01393     case nsISchemaBuiltinType::BUILTIN_TYPE_NCNAME: {
01394       isValid = nsSchemaValidatorUtils::IsValidSchemaNCName(aNodeValue);
01395       break;
01396     }
01397     case nsISchemaBuiltinType::BUILTIN_TYPE_ID: {
01398       isValid = nsSchemaValidatorUtils::IsValidSchemaID(aNodeValue);
01399       break;
01400     }
01401     case nsISchemaBuiltinType::BUILTIN_TYPE_IDREF: {
01402       isValid = nsSchemaValidatorUtils::IsValidSchemaIDRef(aNodeValue);
01403       break;
01404     }
01405     case nsISchemaBuiltinType::BUILTIN_TYPE_IDREFS: {
01406       isValid = nsSchemaValidatorUtils::IsValidSchemaIDRefs(aNodeValue);
01407       break;
01408     }
01409     case nsISchemaBuiltinType::BUILTIN_TYPE_NMTOKEN: {
01410       isValid = nsSchemaValidatorUtils::IsValidSchemaNMToken(aNodeValue);
01411       break;
01412     }
01413     case nsISchemaBuiltinType::BUILTIN_TYPE_NMTOKENS: {
01414       isValid = nsSchemaValidatorUtils::IsValidSchemaNMTokens(aNodeValue);
01415       break;
01416     }
01417 
01418     default:
01419       rv = NS_ERROR_SCHEMAVALIDATOR_TYPE_NOT_FOUND;
01420       break;
01421   }
01422 
01423   *aResult = isValid;
01424   return rv;
01425 }
01426 
01427 /* http://www.w3.org/TR/xmlschema-2/#dt-list */
01428 nsresult
01429 nsSchemaValidator::ValidateListSimpletype(const nsAString & aNodeValue,
01430                                           nsISchemaSimpleType *aSchemaSimpleType,
01431                                           nsSchemaDerivedSimpleType *aFacets,
01432                                           PRBool *aResult)
01433 {
01434  /* When a datatype is derived from an list datatype, the following facets apply:
01435   * length, maxLength, minLength, enumeration, pattern, whitespace
01436   *
01437   * The length facets apply to the whole list, ie the number of items in the list.
01438   * Patterns are applied to the whole list as well.
01439   */
01440 
01441   PRBool isValid = PR_FALSE;
01442 
01443   nsresult rv;
01444   nsCOMPtr<nsISchemaListType> listType = do_QueryInterface(aSchemaSimpleType, &rv);
01445   NS_ENSURE_SUCCESS(rv, rv);
01446 
01447   nsCOMPtr<nsISchemaSimpleType> listSimpleType;
01448   rv = listType->GetListType(getter_AddRefs(listSimpleType));
01449   NS_ENSURE_SUCCESS(rv, rv);
01450 
01451   if (listSimpleType) {
01452     nsCStringArray stringArray;
01453     stringArray.ParseString(NS_ConvertUTF16toUTF8(aNodeValue).get(), " \t\r\n");
01454 
01455     PRUint32 count = stringArray.Count();
01456 
01457     // if facets have been provided, check them first
01458     PRBool facetsValid = PR_TRUE;
01459     if (aFacets) {
01460       if (aFacets->length.isDefined) {
01461         if (aFacets->length.value != count) {
01462           facetsValid = PR_FALSE;
01463           LOG(("  Not valid: List is not the right length (%d)",
01464                aFacets->length.value));
01465         }
01466       }
01467 
01468       if (facetsValid && aFacets->maxLength.isDefined) {
01469         if (aFacets->maxLength.value < count) {
01470           facetsValid = PR_FALSE;
01471           LOG(("  Not valid: Length (%d) of the list is too large",
01472                aFacets->maxLength.value));
01473         }
01474       }
01475 
01476       if (facetsValid && aFacets->minLength.isDefined) {
01477         if (aFacets->minLength.value > count) {
01478           facetsValid = PR_FALSE;
01479           LOG(("  Not valid: Length (%d) of the list is too small",
01480                aFacets->minLength.value));
01481         }
01482       }
01483 
01484       if (facetsValid && aFacets->pattern.isDefined) {
01485         // check if the pattern matches
01486         nsCOMPtr<nsISchemaValidatorRegexp> regexp = do_GetService(kREGEXP_CID);
01487         rv = regexp->RunRegexp(aNodeValue, aFacets->pattern.value, "g",
01488                                &facetsValid);
01489 #ifdef PR_LOGGING
01490         LOG(("  Checking Regular Expression"));
01491         if (facetsValid) {
01492           LOG(("    -- pattern validates!"));
01493         } else {
01494           LOG(("    -- pattern does not validate!"));
01495         }
01496 #endif
01497       }
01498 
01499       if (facetsValid && aFacets->enumerationList.Count() > 0) {
01500         facetsValid =
01501           nsSchemaValidatorUtils::HandleEnumeration(aNodeValue,
01502                                                     aFacets->enumerationList);
01503       }
01504     }
01505 
01506     // either no facets passed in or facets validated fine
01507     if (facetsValid) {
01508       nsAutoString tmp;
01509       for (PRUint32 i=0; i < count; ++i) {
01510         CopyUTF8toUTF16(stringArray[i]->get(), tmp);
01511         LOG(("  Validating List Item (%d): %s", i, NS_ConvertUTF16toUTF8(tmp).get()));
01512         rv = ValidateSimpletype(tmp, listSimpleType, &isValid);
01513 
01514         if (!isValid)
01515           break;
01516       }
01517     }
01518   }
01519 
01520   *aResult = isValid;
01521   return rv;
01522 }
01523 
01524 /* http://www.w3.org/TR/xmlschema-2/#dt-union */
01525 nsresult
01526 nsSchemaValidator::ValidateUnionSimpletype(const nsAString & aNodeValue,
01527                                            nsISchemaSimpleType *aSchemaSimpleType,
01528                                            PRBool *aResult)
01529 {
01530   PRBool isValid = PR_FALSE;
01531 
01532   nsresult rv;
01533   nsCOMPtr<nsISchemaUnionType> unionType = do_QueryInterface(aSchemaSimpleType,
01534                                                              &rv);
01535   NS_ENSURE_SUCCESS(rv, rv);
01536 
01537   nsCOMPtr<nsISchemaSimpleType> unionSimpleType;
01538   PRUint32 count;
01539   unionType->GetUnionTypeCount(&count);
01540 
01541   // compare against the union simpletypes in order until a match is found
01542   for (PRUint32 i=0; i < count; ++i) {
01543     rv = unionType->GetUnionType(i, getter_AddRefs(unionSimpleType));
01544     NS_ENSURE_SUCCESS(rv, rv);
01545 
01546     LOG(("  Validating Untion Type #%d", i));
01547     rv = ValidateSimpletype(aNodeValue, unionSimpleType, &isValid);
01548 
01549     if (isValid)
01550       break;
01551   }
01552 
01553   *aResult = isValid;
01554   return rv;
01555 }
01556 
01557 nsresult
01558 nsSchemaValidator::ValidateDerivedUnionSimpletype(const nsAString & aNodeValue,
01559                                                   nsSchemaDerivedSimpleType *aDerived,
01560                                                   PRBool *aResult)
01561 {
01562   // This method is called when a simple type is derived from a union type
01563   // via restrictions.  So we walk all the possible types, and pass in the
01564   // loaded restriction facets so that they will override the ones defined
01565   // my the union type.  We actually have to create a custom
01566   // nsSchemaDerivedSimpleType for each type, since we need to change the basetype
01567   // and to avoid any new restrictions being added to aDerived.
01568 
01569   PRBool isValid = PR_FALSE;
01570 
01571   nsresult rv;
01572   nsCOMPtr<nsISchemaUnionType> unionType = do_QueryInterface(aDerived->mBaseType,
01573                                                              &rv);
01574   NS_ENSURE_SUCCESS(rv, rv);
01575 
01576   nsCOMPtr<nsISchemaSimpleType> unionSimpleType;
01577   PRUint32 count;
01578   unionType->GetUnionTypeCount(&count);
01579 
01580   // compare against the union simpletypes in order until a match is found
01581   for (PRUint32 i=0; i < count; ++i) {
01582     rv = unionType->GetUnionType(i, getter_AddRefs(unionSimpleType));
01583     NS_ENSURE_SUCCESS(rv, rv);
01584 
01585     nsSchemaDerivedSimpleType derivedType;
01586     nsSchemaValidatorUtils::CopyDerivedSimpleType(&derivedType, aDerived);
01587 
01588     derivedType.mBaseType = unionSimpleType;
01589 
01590     LOG(("  Validating Union Type #%d", i));
01591     rv = ValidateDerivedSimpletype(aNodeValue, &derivedType, &isValid);
01592 
01593     if (isValid)
01594       break;
01595   }
01596 
01597   *aResult = isValid;
01598   return rv;
01599 }
01600 
01601 /* http://www.w3.org/TR/xmlschema-2/#string */
01602 nsresult
01603 nsSchemaValidator::ValidateBuiltinTypeString(const nsAString & aNodeValue,
01604                                              PRUint32 aLength,
01605                                              PRBool aLengthDefined,
01606                                              PRUint32 aMinLength,
01607                                              PRBool aMinLengthDefined,
01608                                              PRUint32 aMaxLength,
01609                                              PRBool aMaxLengthDefined,
01610                                              nsStringArray *aEnumerationList,
01611                                              PRBool *aResult)
01612 {
01613   // XXX needs to check if all chars are legal per spec
01614   // IsUTF8(NS_ConvertUTF16toUTF8(theString).get())
01615   PRBool isValid = PR_TRUE;
01616   PRUint32 length = aNodeValue.Length();
01617 
01618   if (aLengthDefined && (length != aLength)) {
01619     isValid = PR_FALSE;
01620     LOG(("  Not valid: Not the right length (%d)", length));
01621   }
01622 
01623   if (isValid && aMinLengthDefined && (length < aMinLength)) {
01624     isValid = PR_FALSE;
01625     LOG(("  Not valid: Length (%d) is too small", length));
01626   }
01627 
01628   if (isValid && aMaxLengthDefined && (length > aMaxLength)) {
01629     isValid = PR_FALSE;
01630     LOG(("  Not valid: Length (%d) is too large", length));
01631   }
01632 
01633   if (isValid && aEnumerationList && (aEnumerationList->Count() > 0)) {
01634     isValid = nsSchemaValidatorUtils::HandleEnumeration(aNodeValue,
01635                                                         *aEnumerationList);
01636   }
01637 
01638 #ifdef PR_LOGGING
01639   if (isValid)
01640     LOG(("  Value is valid!"));
01641 #endif
01642 
01643  *aResult = isValid;
01644   return NS_OK;
01645 }
01646 
01647 /* http://www.w3.org/TR/xmlschema-2/#boolean */
01648 nsresult
01649 nsSchemaValidator::ValidateBuiltinTypeBoolean(const nsAString & aNodeValue,
01650                                               PRBool *aResult)
01651 {
01652   // possible values are 0, 1, true, false.  Spec makes no mention if TRUE is
01653   // valid, so performing a case insensitive comparision to be safe
01654   *aResult = aNodeValue.EqualsLiteral("false") ||
01655              aNodeValue.EqualsLiteral("true") ||
01656              aNodeValue.EqualsLiteral("1") ||
01657              aNodeValue.EqualsLiteral("0");
01658 
01659 #ifdef PR_LOGGING
01660   if (*aResult) {
01661     LOG(("  Value is valid."));
01662   } else {
01663     LOG(("  Not valid: Value (%s) is not in {1,0,true,false}.",
01664       NS_ConvertUTF16toUTF8(aNodeValue).get()));
01665   }
01666 #endif
01667 
01668   return NS_OK;
01669 }
01670 
01671 /* http://www.w3.org/TR/xmlschema-2/#gDay */
01672 nsresult
01673 nsSchemaValidator::ValidateBuiltinTypeGDay(const nsAString & aNodeValue,
01674                                            const nsAString & aMaxExclusive,
01675                                            const nsAString & aMinExclusive,
01676                                            const nsAString & aMaxInclusive,
01677                                            const nsAString & aMinInclusive,
01678                                            PRBool *aResult)
01679 {
01680   PRBool isValidGDay;
01681   nsSchemaGDay gday;
01682   PRBool isValid = IsValidSchemaGDay(aNodeValue, &gday);
01683 
01684   if (isValid && !aMaxExclusive.IsEmpty()) {
01685     nsSchemaGDay maxExclusive;
01686     isValidGDay = IsValidSchemaGDay(aMaxExclusive, &maxExclusive);
01687 
01688     if (isValidGDay) {
01689       if (gday.day >= maxExclusive.day) {
01690         isValid = PR_FALSE;
01691         LOG(("  Not valid: Value (%d) is too large", gday.day));
01692       }
01693     }
01694   }
01695 
01696   if (isValid && !aMinExclusive.IsEmpty()) {
01697     nsSchemaGDay minExclusive;
01698     isValidGDay = IsValidSchemaGDay(aMinExclusive, &minExclusive);
01699 
01700     if (isValidGDay) {
01701       if (gday.day <= minExclusive.day) {
01702         isValid = PR_FALSE;
01703         LOG(("  Not valid: Value (%d) is too small", gday.day));
01704       }
01705     }
01706   }
01707 
01708   if (isValid && !aMaxInclusive.IsEmpty()) {
01709     nsSchemaGDay maxInclusive;
01710     isValidGDay = IsValidSchemaGDay(aMaxInclusive, &maxInclusive);
01711 
01712     if (isValidGDay) {
01713       if (gday.day > maxInclusive.day) {
01714         isValid = PR_FALSE;
01715         LOG(("  Not valid: Value (%d) is too large", gday.day));
01716       }
01717     }
01718   }
01719 
01720   if (isValid && !aMinInclusive.IsEmpty()) {
01721     nsSchemaGDay minInclusive;
01722     isValidGDay = IsValidSchemaGDay(aMinInclusive, &minInclusive);
01723 
01724     if (isValidGDay) {
01725       if (gday.day < minInclusive.day) {
01726         isValid = PR_FALSE;
01727         LOG(("  Not valid: Value (%d) is too small", gday.day));
01728       }
01729     }
01730   }
01731 
01732 #ifdef PR_LOGGING
01733     LOG((isValid ? ("  Value is valid!") : (" Value is not valid!")));
01734 #endif
01735 
01736  *aResult = isValid;
01737   return NS_OK;
01738 }
01739 
01740 PRBool
01741 nsSchemaValidator::IsValidSchemaGDay(const nsAString & aNodeValue,
01742                                      nsSchemaGDay *aResult)
01743 {
01744   // GDay looks like this: ---DD(Z|(+|-)hh:mm)
01745 
01746   PRUint32 strLength = aNodeValue.Length();
01747   //   ---DD            ---DDZ            ---DD(+|-)hh:mm
01748   if (strLength != 5 && strLength != 6 && strLength != 11)
01749     return PR_FALSE;
01750 
01751   char timezoneHour[3] = "";
01752   char timezoneMinute[3] = "";
01753   PRUnichar tzSign = PRUnichar(' ');
01754   int dayInt;
01755 
01756   // iterate over the string and parse/validate
01757   nsAString::const_iterator start, end;
01758   aNodeValue.BeginReading(start);
01759   aNodeValue.EndReading(end);
01760   nsAutoString nodeValue(aNodeValue);
01761 
01762   // validate the ---DD part
01763   PRBool isValid = Substring(start.get(), start.get()+3).EqualsLiteral("---") &&
01764                    IsValidSchemaGType(Substring(start.get()+3, start.get()+5),
01765                                       1, 31, &dayInt);
01766   if (isValid) {
01767     tzSign = nodeValue.CharAt(5);
01768     if (strLength == 6) {
01769       isValid &= (tzSign == 'Z');
01770     } else if (strLength == 11) {
01771       const nsAString &tz = Substring(start.get()+6, end.get());
01772 
01773       isValid &= ((tzSign == '+' || tzSign == '-') &&
01774                   nsSchemaValidatorUtils::ParseSchemaTimeZone(tz, timezoneHour,
01775                                                               timezoneMinute));
01776     }
01777   }
01778 
01779   if (isValid && aResult) {
01780     char * pEnd;
01781     aResult->day = dayInt;
01782     aResult->tz_negative = (tzSign == '-') ? PR_TRUE : PR_FALSE;
01783     aResult->tz_hour = (timezoneHour[0] == '\0') ? nsnull : strtol(timezoneHour, &pEnd, 10);
01784     aResult->tz_minute = (timezoneMinute[0] == '\0') ? nsnull : strtol(timezoneMinute, &pEnd, 10);
01785   }
01786 
01787   return isValid;
01788 }
01789 
01790 // Helper function used to validate gregorian date types
01791 PRBool
01792 nsSchemaValidator::IsValidSchemaGType(const nsAString & aNodeValue,
01793                                       long aMinValue, long aMaxValue,
01794                                       int *aResult)
01795 {
01796   long intValue;
01797   PRBool isValid =
01798     nsSchemaValidatorUtils::IsValidSchemaInteger(aNodeValue, &intValue, PR_TRUE);
01799 
01800   *aResult = intValue;
01801   return isValid && (intValue >= aMinValue) && (intValue <= aMaxValue);
01802 }
01803 
01804 /* http://www.w3.org/TR/xmlschema-2/#gMonth */
01805 nsresult
01806 nsSchemaValidator::ValidateBuiltinTypeGMonth(const nsAString & aNodeValue,
01807                                              const nsAString & aMaxExclusive,
01808                                              const nsAString & aMinExclusive,
01809                                              const nsAString & aMaxInclusive,
01810                                              const nsAString & aMinInclusive,
01811                                              PRBool *aResult)
01812 {
01813   nsSchemaGMonth gmonth;
01814   PRBool isValid = IsValidSchemaGMonth(aNodeValue, &gmonth);
01815 
01816   if (isValid && !aMaxExclusive.IsEmpty()) {
01817     nsSchemaGMonth maxExclusive;
01818 
01819     if (IsValidSchemaGMonth(aMaxExclusive, &maxExclusive) &&
01820        gmonth.month >= maxExclusive.month) {
01821       isValid = PR_FALSE;
01822       LOG(("  Not valid: Value (%d) is too large", gmonth.month));
01823     }
01824   }
01825 
01826   if (isValid && !aMinExclusive.IsEmpty()) {
01827     nsSchemaGMonth minExclusive;
01828 
01829     if (IsValidSchemaGMonth(aMinExclusive, &minExclusive) &&
01830         gmonth.month <= minExclusive.month) {
01831       isValid = PR_FALSE;
01832       LOG(("  Not valid: Value (%d) is too small", gmonth.month));
01833     }
01834   }
01835 
01836   if (isValid && !aMaxInclusive.IsEmpty()) {
01837     nsSchemaGMonth maxInclusive;
01838 
01839     if (IsValidSchemaGMonth(aMaxInclusive, &maxInclusive) &&
01840         gmonth.month > maxInclusive.month) {
01841       isValid = PR_FALSE;
01842       LOG(("  Not valid: Value (%d) is too large", gmonth.month));
01843     }
01844   }
01845 
01846   if (isValid && !aMinInclusive.IsEmpty()) {
01847     nsSchemaGMonth minInclusive;
01848 
01849     if (IsValidSchemaGMonth(aMinInclusive, &minInclusive) &&
01850         gmonth.month < minInclusive.month) {
01851       isValid = PR_FALSE;
01852       LOG(("  Not valid: Value (%d) is too small", gmonth.month));
01853     }
01854   }
01855 
01856 #ifdef PR_LOGGING
01857   LOG((isValid ? ("  Value is valid!") : ("  Value is not valid!")));
01858 #endif
01859 
01860  *aResult = isValid;
01861   return NS_OK;
01862 }
01863 
01864 PRBool
01865 nsSchemaValidator::IsValidSchemaGMonth(const nsAString & aNodeValue,
01866                                        nsSchemaGMonth *aResult)
01867 {
01868   // GMonth looks like this: --MM(Z|(+|-)hh:mm)
01869 
01870   PRUint32 strLength = aNodeValue.Length();
01871   //   --MM                --MMZ               --MM(+|-)hh:mm
01872   if ((strLength != 4) && (strLength != 5) && (strLength != 10))
01873     return PR_FALSE;
01874 
01875   char timezoneHour[3] = "";
01876   char timezoneMinute[3] = "";
01877   PRUnichar tzSign = 0;
01878   int monthInt;
01879 
01880   nsAString::const_iterator start, end;
01881   aNodeValue.BeginReading(start);
01882   aNodeValue.EndReading(end);
01883   nsAutoString nodeValue(aNodeValue);
01884 
01885   // validate the --MM part
01886   PRBool isValid = Substring(start.get(), start.get()+2).EqualsLiteral("--") &&
01887                    IsValidSchemaGType(Substring(start.get()+2, start.get()+4),
01888                                       1, 12, &monthInt);
01889   if (isValid) {
01890     tzSign = nodeValue.CharAt(4);
01891     if (strLength == 5) {
01892       isValid &= (tzSign == 'Z');
01893     } else if (strLength == 10) {
01894       const nsAString &tz = Substring(start.get()+5, end.get());
01895 
01896       isValid &= ((tzSign == '+' || tzSign == '-') &&
01897                   nsSchemaValidatorUtils::ParseSchemaTimeZone(tz, timezoneHour,
01898                                                               timezoneMinute));
01899     }
01900   }
01901 
01902   if (isValid && aResult) {
01903     char * pEnd;
01904     aResult->month = monthInt;
01905     aResult->tz_negative = (tzSign == '-') ? PR_TRUE : PR_FALSE;
01906     aResult->tz_hour = (timezoneHour[0] == '\0') ? nsnull : strtol(timezoneHour, &pEnd, 10);
01907     aResult->tz_minute = (timezoneMinute[0] == '\0') ? nsnull : strtol(timezoneMinute, &pEnd, 10);
01908   }
01909 
01910   return isValid;
01911 }
01912 
01913 /* http://www.w3.org/TR/xmlschema-2/#gYear */
01914 nsresult
01915 nsSchemaValidator::ValidateBuiltinTypeGYear(const nsAString & aNodeValue,
01916                                             const nsAString & aMaxExclusive,
01917                                             const nsAString & aMinExclusive,
01918                                             const nsAString & aMaxInclusive,
01919                                             const nsAString & aMinInclusive,
01920                                             PRBool *aResult)
01921 {
01922   nsSchemaGYear gyear;
01923   PRBool isValid = IsValidSchemaGYear(aNodeValue, &gyear);
01924 
01925   if (isValid && !aMaxExclusive.IsEmpty()) {
01926     nsSchemaGYear maxExclusive;
01927 
01928     if (IsValidSchemaGYear(aMaxExclusive, &maxExclusive) &&
01929         gyear.year >= maxExclusive.year) {
01930       isValid = PR_FALSE;
01931       LOG(("  Not valid: Value (%ld) is too large", gyear.year));
01932     }
01933   }
01934 
01935   if (isValid && !aMinExclusive.IsEmpty()) {
01936     nsSchemaGYear minExclusive;
01937 
01938     if (IsValidSchemaGYear(aMinExclusive, &minExclusive) &&
01939         gyear.year <= minExclusive.year) {
01940       isValid = PR_FALSE;
01941       LOG(("  Not valid: Value (%ld) is too small", gyear.year));
01942     }
01943   }
01944 
01945   if (isValid && !aMaxInclusive.IsEmpty()) {
01946     nsSchemaGYear maxInclusive;
01947 
01948     if (IsValidSchemaGYear(aMaxInclusive, &maxInclusive) &&
01949         gyear.year > maxInclusive.year) {
01950       isValid = PR_FALSE;
01951       LOG(("  Not valid: Value (%ld) is too large", gyear.year));
01952     }
01953   }
01954 
01955   if (isValid && !aMinInclusive.IsEmpty()) {
01956     nsSchemaGYear minInclusive;
01957 
01958     if (IsValidSchemaGYear(aMinInclusive, &minInclusive) &&
01959         gyear.year < minInclusive.year) {
01960       isValid = PR_FALSE;
01961       LOG(("  Not valid: Value (%ld) is too small", gyear.year));
01962     }
01963   }
01964 
01965 #ifdef PR_LOGGING
01966   LOG((isValid ? ("  Value is valid!") : ("  Value is not valid!")));
01967 #endif
01968 
01969  *aResult = isValid;
01970   return NS_OK;
01971 }
01972 
01973 PRBool
01974 nsSchemaValidator::IsValidSchemaGYear(const nsAString & aNodeValue,
01975                                       nsSchemaGYear *aResult)
01976 {
01977   // GYear looks like this: (-)CCYY(Z|(+|-)hh:mm)
01978   PRBool isValid = PR_FALSE;
01979   PRUint32 strLength = aNodeValue.Length();
01980 
01981   char timezoneHour[3] = "";
01982   char timezoneMinute[3] = "";
01983   PRUnichar tzSign = 0;
01984 
01985   nsAString::const_iterator start, end, buffStart;
01986   aNodeValue.BeginReading(start);
01987   aNodeValue.BeginReading(buffStart);
01988   aNodeValue.EndReading(end);
01989   PRUint32 state = 0;
01990   PRUint32 buffLength = 0, yearLength = 0;
01991   PRBool done = PR_FALSE;
01992 
01993   long yearNum;
01994 
01995   if (aNodeValue.First() == '-') {
01996     // jump the negative sign
01997     *start++;
01998     buffLength++;
01999   }
02000 
02001   while ((start != end) && !done) {
02002     // 0 - year
02003     // 1 - timezone
02004 
02005     if (state == 0) {
02006       // year
02007       PRUnichar temp = *start++;
02008       // walk till the first non-numerical char
02009       while (((temp >= '0') && (temp <= '9')) && (buffLength < strLength)) {
02010         buffLength++;
02011         temp = *start++;
02012         yearLength++;
02013       }
02014 
02015       // if we are not at the end of the string, back up one, as we hit the
02016       // timezone separator.
02017       if (buffLength < strLength)
02018         *start--;
02019 
02020       // need a minimum of 4 digits for year
02021       if (yearLength >= 4) {
02022         isValid = nsSchemaValidatorUtils::IsValidSchemaInteger(
02023                     Substring(buffStart, start), &yearNum, PR_TRUE);
02024       }
02025 
02026       // 0 is an invalid year per the spec
02027       if (isValid && (yearNum == 0))
02028         isValid = PR_FALSE;
02029 
02030       if (isValid && (strLength > buffLength)) {
02031         state = 1;
02032       } else {
02033         done = PR_TRUE;
02034       }
02035     } else if (state == 1) {
02036       // timezone
02037       int lengthDiff = (strLength - buffLength);
02038 
02039       if (lengthDiff == 0){
02040         // timezone is optional
02041         isValid = PR_TRUE;
02042       } else if (lengthDiff == 1) {
02043         // timezone is one character, so has to be 'Z'
02044         isValid = (*start == 'Z');
02045       } else if (lengthDiff == 6){
02046         // timezone is (+|-)hh:mm
02047         tzSign = *start++;
02048         if ((tzSign == '+') || (tzSign == '-')) {
02049           isValid = nsSchemaValidatorUtils::ParseSchemaTimeZone(
02050                       Substring(start, end), timezoneHour, timezoneMinute);
02051         }
02052       } else {
02053         // invalid length for timezone
02054         isValid = PR_FALSE;
02055       }
02056 
02057       done = PR_TRUE;
02058     }
02059   }
02060 
02061   if (isValid && aResult) {
02062     char * pEnd;
02063     aResult->year = yearNum;
02064     aResult->tz_negative = (tzSign == '-') ? PR_TRUE : PR_FALSE;
02065     aResult->tz_hour = (timezoneHour[0] == '\0') ? nsnull : strtol(timezoneHour, &pEnd, 10);
02066     aResult->tz_minute = (timezoneMinute[0] == '\0') ? nsnull : strtol(timezoneMinute, &pEnd, 10);
02067   }
02068 
02069   return isValid;
02070 }
02071 
02072 /* http://www.w3.org/TR/xmlschema-2/#gYearMonth */
02073 nsresult
02074 nsSchemaValidator::ValidateBuiltinTypeGYearMonth(const nsAString & aNodeValue,
02075                                                  const nsAString & aMaxExclusive,
02076                                                  const nsAString & aMinExclusive,
02077                                                  const nsAString & aMaxInclusive,
02078                                                  const nsAString & aMinInclusive,
02079                                                  PRBool *aResult)
02080 {
02081   nsSchemaGYearMonth gyearmonth;
02082 
02083   PRBool isValid = IsValidSchemaGYearMonth(aNodeValue, &gyearmonth);
02084 
02085   if (isValid && !aMaxExclusive.IsEmpty()) {
02086     nsSchemaGYearMonth maxExclusive;
02087 
02088     if (IsValidSchemaGYearMonth(aMaxExclusive, &maxExclusive) &&
02089         (nsSchemaValidatorUtils::CompareGYearMonth(gyearmonth, maxExclusive) > -1)) {
02090       isValid = PR_FALSE;
02091       LOG(("  Not valid: Value (%ld-%d) is too large", gyearmonth.gYear.year,
02092         gyearmonth.gMonth.month));
02093     }
02094   }
02095 
02096   if (isValid && !aMinExclusive.IsEmpty()) {
02097     nsSchemaGYearMonth minExclusive;
02098 
02099     if (IsValidSchemaGYearMonth(aMinExclusive, &minExclusive) &&
02100         (nsSchemaValidatorUtils::CompareGYearMonth(gyearmonth, minExclusive) < 1)) {
02101       isValid = PR_FALSE;
02102       LOG(("  Not valid: Value (%ld-%d) is too small", gyearmonth.gYear.year,
02103         gyearmonth.gMonth.month));
02104     }
02105   }
02106 
02107   if (isValid && !aMaxInclusive.IsEmpty()) {
02108     nsSchemaGYearMonth maxInclusive;
02109 
02110     if (IsValidSchemaGYearMonth(aMaxInclusive, &maxInclusive) &&
02111         (nsSchemaValidatorUtils::CompareGYearMonth(gyearmonth, maxInclusive) > 0)) {
02112       isValid = PR_FALSE;
02113       LOG(("  Not valid: Value (%ld-%d) is too large", gyearmonth.gYear.year,
02114         gyearmonth.gMonth.month));
02115     }
02116   }
02117 
02118   if (isValid && !aMinInclusive.IsEmpty()) {
02119     nsSchemaGYearMonth minInclusive;
02120 
02121     if (IsValidSchemaGYearMonth(aMinInclusive, &minInclusive) &&
02122         (nsSchemaValidatorUtils::CompareGYearMonth(gyearmonth, minInclusive) < 0)) {
02123       isValid = PR_FALSE;
02124       LOG(("  Not valid: Value (%ld-%d) is too small", gyearmonth.gYear.year,
02125         gyearmonth.gMonth.month));
02126     }
02127   }
02128 
02129 #ifdef PR_LOGGING
02130   LOG((isValid ? ("  Value is valid!") : ("  Value is not valid!")));
02131 #endif
02132 
02133  *aResult = isValid;
02134   return NS_OK;
02135 }
02136 
02137 PRBool
02138 nsSchemaValidator::IsValidSchemaGYearMonth(const nsAString & aNodeValue,
02139                                           nsSchemaGYearMonth *aYearMonth)
02140 {
02141   // GYearMonth looks like this: (-)CCYY-MM(Z|(+|-)hh:mm)
02142   PRBool isValid = PR_FALSE;
02143 
02144   nsAString::const_iterator start, end, buffStart;
02145   aNodeValue.BeginReading(start);
02146   aNodeValue.BeginReading(buffStart);
02147   aNodeValue.EndReading(end);
02148   PRUint32 buffLength = 0;
02149   PRBool done = PR_FALSE;
02150 
02151   PRUint32 strLength = aNodeValue.Length();
02152 
02153   if (aNodeValue.First() == '-') {
02154     // jump the negative sign
02155     *start++;
02156     *buffStart++;
02157     buffLength++;
02158   }
02159 
02160   while ((start != end) && !done) {
02161     if (*start++ == '-') {
02162       // separator found
02163 
02164       int monthLength = strLength - buffLength;
02165       //   -MMZ                  -MM(+|-)hh:mm         -MM
02166       if ((monthLength != 4) && (monthLength != 9) && (monthLength != 3))
02167         return PR_FALSE;
02168 
02169       // validate year
02170       nsAutoString year;
02171       // back one up since we have the separator included
02172       year = Substring(buffStart, --start);
02173 
02174       isValid = IsValidSchemaGYear(year,
02175                                    aYearMonth ? &aYearMonth->gYear : nsnull);
02176 
02177       if (isValid) {
02178         nsAutoString month;
02179         month.AppendLiteral("--");
02180         start++;
02181         month.Append(Substring(start, end));
02182 
02183         isValid = IsValidSchemaGMonth(month,
02184                                       aYearMonth ? &aYearMonth->gMonth : nsnull);
02185       }
02186       done = PR_TRUE;
02187     } else {
02188       buffLength++;
02189     }
02190   }
02191 
02192   return isValid;
02193 }
02194 
02195 /* http://www.w3.org/TR/xmlschema-2/#gMonthDay */
02196 nsresult
02197 nsSchemaValidator::ValidateBuiltinTypeGMonthDay(const nsAString & aNodeValue,
02198                                                 const nsAString & aMaxExclusive,
02199                                                 const nsAString & aMinExclusive,
02200                                                 const nsAString & aMaxInclusive,
02201                                                 const nsAString & aMinInclusive,
02202                                                 PRBool *aResult)
02203 {
02204   nsSchemaGMonthDay gmonthday;
02205 
02206   PRBool isValid = IsValidSchemaGMonthDay(aNodeValue, &gmonthday);
02207 
02208   if (isValid && !aMaxExclusive.IsEmpty()) {
02209     nsSchemaGMonthDay maxExclusive;
02210 
02211     if (IsValidSchemaGMonthDay(aMaxExclusive, &maxExclusive) &&
02212         (nsSchemaValidatorUtils::CompareGMonthDay(gmonthday, maxExclusive) > -1)) {
02213       isValid = PR_FALSE;
02214       LOG(("  Not valid: Value (%d-%d) is too large", gmonthday.gMonth.month,
02215         gmonthday.gDay.day));
02216     }
02217   }
02218 
02219   if (isValid && !aMinExclusive.IsEmpty()) {
02220     nsSchemaGMonthDay minExclusive;
02221 
02222     if (IsValidSchemaGMonthDay(aMinExclusive, &minExclusive) &&
02223         (nsSchemaValidatorUtils::CompareGMonthDay(gmonthday, minExclusive) < 1)) {
02224       isValid = PR_FALSE;
02225       LOG(("  Not valid: Value (%d-%d) is too small", gmonthday.gMonth.month,
02226         gmonthday.gDay.day));
02227     }
02228   }
02229 
02230   if (isValid && !aMaxInclusive.IsEmpty()) {
02231     nsSchemaGMonthDay maxInclusive;
02232 
02233     if (IsValidSchemaGMonthDay(aMaxInclusive, &maxInclusive) &&
02234         (nsSchemaValidatorUtils::CompareGMonthDay(gmonthday, maxInclusive) > 0)) {
02235       isValid = PR_FALSE;
02236       LOG(("  Not valid: Value (%d-%d) is too large", gmonthday.gMonth.month,
02237         gmonthday.gDay.day));
02238     }
02239   }
02240 
02241   if (isValid && !aMinInclusive.IsEmpty()) {
02242     nsSchemaGMonthDay minInclusive;
02243 
02244     if (IsValidSchemaGMonthDay(aMinInclusive, &minInclusive) &&
02245         (nsSchemaValidatorUtils::CompareGMonthDay(gmonthday, minInclusive) < 0)) {
02246       isValid = PR_FALSE;
02247       LOG(("  Not valid: Value (%d-%d) is too small", gmonthday.gMonth.month,
02248         gmonthday.gDay.day));
02249     }
02250   }
02251 
02252 #ifdef PR_LOGGING
02253   LOG((isValid ? ("  Value is valid!") : ("  Value is not valid!")));
02254 #endif
02255 
02256  *aResult = isValid;
02257   return NS_OK;
02258 }
02259 
02260 PRBool
02261 nsSchemaValidator::IsValidSchemaGMonthDay(const nsAString & aNodeValue,
02262                                           nsSchemaGMonthDay *aMonthDay)
02263 {
02264   // GMonthDay looks like this: --MM-DD(Z|(+|-)hh:mm)
02265   PRBool isValid = PR_FALSE;
02266 
02267   nsAString::const_iterator start, end, buffStart;
02268   aNodeValue.BeginReading(start);
02269   aNodeValue.BeginReading(buffStart);
02270   aNodeValue.EndReading(end);
02271   PRUint32 buffLength = 0;
02272   PRUint32 state = 0;
02273   PRBool done = PR_FALSE;
02274 
02275   PRUint32 strLength = aNodeValue.Length();
02276   //   --MM-DD             --MM-DDZ            --MM-DD(+|-)hh:mm
02277   if ((strLength != 7) && (strLength != 8) && (strLength != 13))
02278     return PR_FALSE;
02279 
02280   while ((start != end) && !done) {
02281     if (state == 0) {
02282       // separator
02283       if (*start++ == '-') {
02284         buffLength++;
02285 
02286         if (buffLength == 2) {
02287           state = 1;
02288           buffStart = start;
02289         }
02290       } else {
02291         done = PR_TRUE;
02292       }
02293     } else if (state == 1) {
02294       // month part -  construct an --MM--
02295 
02296       nsAutoString month;
02297       month.AppendLiteral("--");
02298       month.Append(Substring(buffStart, start.advance(2)));
02299       isValid = IsValidSchemaGMonth(month,
02300                                     aMonthDay ? &aMonthDay->gMonth : nsnull);
02301 
02302       if (isValid) {
02303         buffStart = start;
02304         state = 2;
02305       } else {
02306         done = PR_TRUE;
02307       }
02308     } else if (state == 2) {
02309       // day part - construct ---DD(timezone)
02310       nsAutoString day;
02311       day.AppendLiteral("---");
02312       day.Append(Substring(++buffStart, end));
02313       isValid = IsValidSchemaGDay(day,
02314                                   aMonthDay ? &aMonthDay->gDay : nsnull);
02315       done = PR_TRUE;
02316     }
02317   }
02318 
02319   return isValid;
02320 }
02321 
02322 /* http://www.w3.org/TR/xmlschema-2/#time */
02323 nsresult
02324 nsSchemaValidator::ValidateBuiltinTypeTime(const nsAString & aNodeValue,
02325                                            const nsAString & aMaxExclusive,
02326                                            const nsAString & aMinExclusive,
02327                                            const nsAString & aMaxInclusive,
02328                                            const nsAString & aMinInclusive,
02329                                            PRBool *aResult)
02330 {
02331   nsSchemaTime time;
02332   int timeCompare;
02333 
02334   PRBool isValid = IsValidSchemaTime(aNodeValue, &time);
02335 
02336   if (isValid && !aMinExclusive.IsEmpty()) {
02337     nsSchemaTime minExclusive;
02338 
02339     if (IsValidSchemaTime(aMinExclusive, &minExclusive)) {
02340       timeCompare =
02341         nsSchemaValidatorUtils::CompareTime(time, minExclusive);
02342 
02343       if (timeCompare < 1) {
02344         isValid = PR_FALSE;
02345         LOG(("  Not valid: Value is too small"));
02346       }
02347     }
02348   }
02349 
02350   if (isValid && !aMaxExclusive.IsEmpty()) {
02351     nsSchemaTime maxExclusive;
02352 
02353     if (IsValidSchemaTime(aMaxExclusive, &maxExclusive)) {
02354       timeCompare =
02355         nsSchemaValidatorUtils::CompareTime(time, maxExclusive);
02356 
02357       if (timeCompare > -1) {
02358         isValid = PR_FALSE;
02359         LOG(("  Not valid: Value is too large"));
02360       }
02361     }
02362   }
02363 
02364   if (isValid && !aMaxInclusive.IsEmpty()) {
02365     nsSchemaTime maxInclusive;
02366 
02367     if (IsValidSchemaTime(aMaxInclusive, &maxInclusive)) {
02368       timeCompare =
02369         nsSchemaValidatorUtils::CompareTime(time, maxInclusive);
02370 
02371       if (timeCompare > 0) {
02372         isValid = PR_FALSE;
02373         LOG(("  Not valid: Value is too large"));
02374       }
02375     }
02376   }
02377 
02378   if (isValid && !aMinInclusive.IsEmpty()) {
02379     nsSchemaTime minInclusive;
02380 
02381     if (IsValidSchemaTime(aMinInclusive, &minInclusive)) {
02382       timeCompare =
02383         nsSchemaValidatorUtils::CompareTime(time, minInclusive);
02384 
02385       if (timeCompare < 0) {
02386         isValid = PR_FALSE;
02387         LOG(("  Not valid: Value is too small"));
02388       }
02389     }
02390   }
02391 
02392  *aResult = isValid;
02393   return NS_OK;
02394 }
02395 
02396 NS_IMETHODIMP
02397 nsSchemaValidator::ValidateBuiltinTypeTime(const nsAString & aValue,
02398                                            PRTime *aResult)
02399 {
02400   nsresult rv = NS_OK;
02401   nsSchemaTime time;
02402   PRBool isValid = IsValidSchemaTime(aValue, &time);
02403 
02404   if (isValid) {
02405     char fulldate[100] = "";
02406 
02407     // 22-AUG-1993 10:59:12.82
02408     sprintf(fulldate, "22-AUG-1993 %d:%d:%d.%u", time.hour, time.minute,
02409             time.second, time.milisecond);
02410 
02411     PRBool isGMT = nsSchemaValidatorUtils::IsGMT(aValue);
02412     PR_ParseTimeString(fulldate, isGMT ? PR_TRUE : PR_FALSE, aResult);
02413   } else {
02414     *aResult = nsnull;
02415     rv = NS_ERROR_ILLEGAL_VALUE;
02416   }
02417 
02418   return rv;
02419 }
02420 
02421 PRBool
02422 nsSchemaValidator::IsValidSchemaTime(const nsAString & aNodeValue,
02423                                      nsSchemaTime *aResult)
02424 {
02425   PRBool isValid = PR_FALSE;
02426 
02427   nsAutoString timeString(aNodeValue);
02428 
02429   // if no timezone ([+/-]hh:ss) or no timezone Z, add a Z to the end so that
02430   // nsSchemaValidatorUtils::ParseSchemaTime can parse it
02431   if ((timeString.FindChar('-') == kNotFound) &&
02432       (timeString.FindChar('+') == kNotFound) &&
02433        timeString.Last() != 'Z'){
02434     timeString.Append('Z');
02435   }
02436 
02437   LOG(("  Validating Time: "));
02438 
02439   isValid = nsSchemaValidatorUtils::ParseSchemaTime(timeString, aResult);
02440 
02441   return isValid;
02442 }
02443 
02444 /* http://www.w3.org/TR/xmlschema-2/#date */
02445 nsresult
02446 nsSchemaValidator::ValidateBuiltinTypeDate(const nsAString & aNodeValue,
02447                                            const nsAString & aMaxExclusive,
02448                                            const nsAString & aMinExclusive,
02449                                            const nsAString & aMaxInclusive,
02450                                            const nsAString & aMinInclusive,
02451                                            PRBool *aResult)
02452 {
02453   PRBool isValid = PR_FALSE;
02454   nsSchemaDate date;
02455   int dateCompare;
02456 
02457   isValid = IsValidSchemaDate(aNodeValue, &date);
02458 
02459   if (isValid && !aMaxExclusive.IsEmpty()) {
02460     nsSchemaDate maxExclusive;
02461 
02462     if (IsValidSchemaDate(aMaxExclusive, &maxExclusive)) {
02463       dateCompare = nsSchemaValidatorUtils::CompareDate(date, maxExclusive);
02464 
02465       if (dateCompare > -1) {
02466         isValid = PR_FALSE;
02467         LOG(("  Not valid: Value is too large"));
02468       }
02469     }
02470   }
02471 
02472   if (isValid && !aMinExclusive.IsEmpty()) {
02473     nsSchemaDate minExclusive;
02474 
02475     if (IsValidSchemaDate(aMinExclusive, &minExclusive)) {
02476       dateCompare = nsSchemaValidatorUtils::CompareDate(date, minExclusive);
02477 
02478       if (dateCompare < 1) {
02479         isValid = PR_FALSE;
02480         LOG(("  Not valid: Value is too small"));
02481       }
02482     }
02483   }
02484 
02485   if (isValid && !aMaxInclusive.IsEmpty()) {
02486     nsSchemaDate maxInclusive;
02487 
02488     if (IsValidSchemaDate(aMaxInclusive, &maxInclusive)) {
02489       dateCompare = nsSchemaValidatorUtils::CompareDate(date, maxInclusive);
02490 
02491       if (dateCompare > 0) {
02492         isValid = PR_FALSE;
02493         LOG(("  Not valid: Value is too large"));
02494       }
02495     }
02496   }
02497 
02498   if (isValid && !aMinInclusive.IsEmpty()) {
02499     nsSchemaDate minInclusive;
02500 
02501     if (IsValidSchemaDate(aMinInclusive, &minInclusive)) {
02502       dateCompare = nsSchemaValidatorUtils::CompareDate(date, minInclusive);
02503 
02504       if (dateCompare < 0) {
02505         isValid = PR_FALSE;
02506         LOG(("  Not valid: Value is too small"));
02507       }
02508     }
02509   }
02510 
02511  *aResult = isValid;
02512   return NS_OK;
02513 }
02514 
02515 NS_IMETHODIMP
02516 nsSchemaValidator::ValidateBuiltinTypeDate(const nsAString & aValue,
02517                                            PRTime *aResult)
02518 {
02519   nsresult rv = NS_OK;
02520   nsSchemaDate date;
02521   PRBool isValid = IsValidSchemaDate(aValue, &date);
02522 
02523   if (isValid) {
02524     char fulldate[100] = "";
02525     nsCAutoString monthShorthand;
02526     nsSchemaValidatorUtils::GetMonthShorthand(date.month, monthShorthand);
02527 
02528     // 22-AUG-1993 10:59:12.82
02529     sprintf(fulldate, "%d-%s-%u 00:00:00", date.day,
02530             monthShorthand.get(), date.year);
02531 
02532     PRBool isGMT = nsSchemaValidatorUtils::IsGMT(aValue);
02533     PR_ParseTimeString(fulldate, isGMT ? PR_TRUE : PR_FALSE, aResult);
02534   } else {
02535     *aResult = nsnull;
02536     rv = NS_ERROR_ILLEGAL_VALUE;
02537   }
02538 
02539   return rv;
02540 }
02541 
02542 /* http://www.w3.org/TR/xmlschema-2/#dateTime */
02543 nsresult
02544 nsSchemaValidator::ValidateBuiltinTypeDateTime(const nsAString & aNodeValue,
02545                                            const nsAString & aMaxExclusive,
02546                                            const nsAString & aMinExclusive,
02547                                            const nsAString & aMaxInclusive,
02548                                            const nsAString & aMinInclusive,
02549                                            PRBool *aResult)
02550 {
02551   nsSchemaDateTime dateTime;
02552   PRBool isValid = IsValidSchemaDateTime(aNodeValue, &dateTime);
02553 
02554   if (isValid && !aMaxExclusive.IsEmpty()) {
02555     nsSchemaDateTime maxExclusive;
02556 
02557     if (IsValidSchemaDateTime(aMaxExclusive, &maxExclusive) &&
02558         CompareSchemaDateTime(dateTime, maxExclusive) > -1) {
02559       isValid = PR_FALSE;
02560       LOG(("  Not valid: Value is too large"));
02561     }
02562   }
02563 
02564   if (isValid && !aMinExclusive.IsEmpty()) {
02565     nsSchemaDateTime minExclusive;
02566 
02567     if (IsValidSchemaDateTime(aMinExclusive, &minExclusive) &&
02568         CompareSchemaDateTime(dateTime, minExclusive) < 1) {
02569       isValid = PR_FALSE;
02570       LOG(("  Not valid: Value is too small"));
02571     }
02572   }
02573 
02574   if (isValid && !aMaxInclusive.IsEmpty()) {
02575     nsSchemaDateTime maxInclusive;
02576 
02577     if (IsValidSchemaDateTime(aMaxInclusive, &maxInclusive) &&
02578         CompareSchemaDateTime(dateTime, maxInclusive) > 0) {
02579       isValid = PR_FALSE;
02580       LOG(("  Not valid: Value is too large"));
02581     }
02582   }
02583 
02584   if (isValid && !aMinInclusive.IsEmpty()) {
02585     nsSchemaDateTime minInclusive;
02586 
02587     if (IsValidSchemaDateTime(aMinInclusive, &minInclusive) &&
02588         CompareSchemaDateTime(dateTime, minInclusive) < 0) {
02589       isValid = PR_FALSE;
02590       LOG(("  Not valid: Value is too small"));
02591     }
02592   }
02593 
02594  *aResult = isValid;
02595   return NS_OK;
02596 }
02597 
02598 NS_IMETHODIMP
02599 nsSchemaValidator::ValidateBuiltinTypeDateTime(const nsAString & aValue,
02600                                                PRTime *aResult)
02601 {
02602   nsresult rv = NS_OK;
02603   nsSchemaDateTime dateTime;
02604   PRBool isValid = IsValidSchemaDateTime(aValue, &dateTime);
02605 
02606   if (isValid) {
02607     char fulldate[100] = "";
02608     nsCAutoString monthShorthand;
02609     nsSchemaValidatorUtils::GetMonthShorthand(dateTime.date.month, monthShorthand);
02610     // 22-AUG-1993 10:59:12.82
02611     sprintf(fulldate, "%d-%s-%u %d:%d:%d.%u",
02612       dateTime.date.day,
02613       monthShorthand.get(),
02614       dateTime.date.year,
02615       dateTime.time.hour,
02616       dateTime.time.minute,
02617       dateTime.time.second,
02618       dateTime.time.milisecond);
02619 
02620     PRBool isGMT = nsSchemaValidatorUtils::IsGMT(aValue);
02621     PR_ParseTimeString(fulldate, isGMT ? PR_TRUE : PR_FALSE, aResult);
02622   } else {
02623     *aResult = nsnull;
02624     rv = NS_ERROR_ILLEGAL_VALUE;
02625   }
02626 
02627   return rv;
02628 }
02629 
02630 int
02631 nsSchemaValidator::CompareSchemaDateTime(nsSchemaDateTime datetime1,
02632                                          nsSchemaDateTime datetime2)
02633 {
02634   return nsSchemaValidatorUtils::CompareDateTime(datetime1, datetime2);
02635 }
02636 
02637 PRBool
02638 nsSchemaValidator::IsValidSchemaDate(const nsAString & aNodeValue,
02639                                      nsSchemaDate *aResult)
02640 {
02641   PRBool isValid = PR_FALSE;
02642 
02643   LOG(("  Validating Date:"));
02644 
02645   if (aNodeValue.IsEmpty())
02646     return PR_FALSE;
02647 
02648   nsAutoString dateString(aNodeValue);
02649   if (dateString.First() == '-') {
02650     aResult->isNegative = PR_TRUE;
02651   }
02652 
02653  /*
02654     http://www.w3.org/TR/xmlschema-2/#date
02655     (-)CCYY-MM-DD
02656       then optionally either: 
02657         Z
02658         or [+/-]hh:mm
02659   */
02660 
02661   isValid = nsSchemaValidatorUtils::ParseSchemaDate(dateString, PR_TRUE, aResult);
02662 
02663   return isValid;
02664 }
02665 
02666 PRBool
02667 nsSchemaValidator::IsValidSchemaDateTime(const nsAString & aNodeValue,
02668                                          nsSchemaDateTime *aResult)
02669 {
02670   return nsSchemaValidatorUtils::ParseDateTime(aNodeValue, aResult);
02671 }
02672 
02673 /* http://w3.org/TR/xmlschema-2/#duration */
02674 nsresult
02675 nsSchemaValidator::ValidateBuiltinTypeDuration(const nsAString & aNodeValue,
02676                                            const nsAString & aMaxExclusive,
02677                                            const nsAString & aMinExclusive,
02678                                            const nsAString & aMaxInclusive,
02679                                            const nsAString & aMinInclusive,
02680                                            PRBool *aResult)
02681 {
02682   PRBool isValid = PR_FALSE;
02683 
02684   nsCOMPtr<nsISchemaDuration> duration;
02685   isValid = IsValidSchemaDuration(aNodeValue, getter_AddRefs(duration));
02686 
02687   if (isValid && !aMaxExclusive.IsEmpty()) {
02688     nsCOMPtr<nsISchemaDuration> maxExclusiveDuration;
02689 
02690     if (IsValidSchemaDuration(aMaxExclusive, getter_AddRefs(maxExclusiveDuration)) &&
02691         nsSchemaValidatorUtils::CompareDurations(duration, maxExclusiveDuration) == 1){
02692       isValid = PR_FALSE;
02693       LOG(("  Not valid: Value is too large or indeterminate"));
02694     }
02695   }
02696 
02697   if (isValid && !aMinExclusive.IsEmpty()) {
02698     nsCOMPtr<nsISchemaDuration> minExclusiveDuration;
02699 
02700     if (IsValidSchemaDuration(aMinExclusive, getter_AddRefs(minExclusiveDuration)) &&
02701         nsSchemaValidatorUtils::CompareDurations(minExclusiveDuration, duration) == 1){
02702       isValid = PR_FALSE;
02703       LOG(("  Not valid: Value is too small or indeterminate"));
02704     }
02705   }
02706 
02707   if (isValid && !aMaxInclusive.IsEmpty()) {
02708     nsCOMPtr<nsISchemaDuration> maxInclusiveDuration;
02709 
02710     if (IsValidSchemaDuration(aMaxInclusive, getter_AddRefs(maxInclusiveDuration)) &&
02711         nsSchemaValidatorUtils::CompareDurations(duration, maxInclusiveDuration) == 1){
02712       isValid = PR_FALSE;
02713       LOG(("  Not valid: Value is too large or indeterminate"));
02714     }
02715   }
02716 
02717   if (isValid && !aMinInclusive.IsEmpty()) {
02718     nsCOMPtr<nsISchemaDuration> minInclusiveDuration;
02719 
02720     if (IsValidSchemaDuration(aMinInclusive, getter_AddRefs(minInclusiveDuration)) &&
02721         nsSchemaValidatorUtils::CompareDurations(minInclusiveDuration, duration) == 1){
02722       isValid = PR_FALSE;
02723       LOG(("  Not valid: Value is too small or indeterminate"));
02724     }
02725   }
02726 
02727  *aResult = isValid;
02728   return NS_OK;
02729 }
02730 
02731 // scriptable method for validating and parsing durations
02732 NS_IMETHODIMP
02733 nsSchemaValidator::ValidateBuiltinTypeDuration(const nsAString & aValue,
02734                                                nsISchemaDuration **aDuration)
02735 {
02736   nsresult rv = NS_OK;
02737   *aDuration = nsnull;
02738   nsCOMPtr<nsISchemaDuration> duration;
02739 
02740   if (IsValidSchemaDuration(aValue, getter_AddRefs(duration))) {
02741     duration.swap(*aDuration);
02742   } else {
02743     rv = NS_ERROR_ILLEGAL_VALUE;
02744   }
02745 
02746   return rv;
02747 }
02748 
02749 PRBool
02750 nsSchemaValidator::IsValidSchemaDuration(const nsAString & aNodeValue,
02751                                          nsISchemaDuration **aResult)
02752 {
02753   PRBool isValid = PR_FALSE;
02754   nsCOMPtr<nsISchemaDuration> duration;
02755 
02756   isValid = nsSchemaValidatorUtils::ParseSchemaDuration(aNodeValue,
02757                                                         getter_AddRefs(duration));
02758 
02759   duration.swap(*aResult);
02760   return isValid;
02761 }
02762 
02763 /* http://w3.org/TR/xmlschema-2/#integer */
02764 nsresult
02765 nsSchemaValidator::ValidateBuiltinTypeInteger(const nsAString & aNodeValue,
02766                                               PRUint32 aTotalDigits,
02767                                               const nsAString & aMaxExclusive,
02768                                               const nsAString & aMinExclusive,
02769                                               const nsAString & aMaxInclusive,
02770                                               const nsAString & aMinInclusive,
02771                                               nsStringArray *aEnumerationList,
02772                                               PRBool *aResult)
02773 {
02774   PRBool isValid = PR_FALSE;
02775   long intValue;
02776   isValid = nsSchemaValidatorUtils::IsValidSchemaInteger(aNodeValue, &intValue);
02777 
02778   if (isValid && aTotalDigits) {
02779     PRUint32 length = aNodeValue.Length();
02780 
02781     if (aNodeValue.First() == PRUnichar('-'))
02782       length -= 1;
02783 
02784     if (length > aTotalDigits) {
02785       isValid = PR_FALSE;
02786       LOG(("  Not valid: Too many digits (%d)", length));
02787     }
02788   }
02789 
02790   if (isValid && !aMaxExclusive.IsEmpty()){
02791     long maxExclusive;
02792 
02793     if (nsSchemaValidatorUtils::IsValidSchemaInteger(aMaxExclusive, &maxExclusive)
02794         && (nsSchemaValidatorUtils::CompareStrings(aNodeValue, aMaxExclusive) >= 0)) {
02795       isValid = PR_FALSE;
02796       LOG(("  Not valid: Value is too large"));
02797     }
02798   }
02799 
02800   if (isValid && !aMinExclusive.IsEmpty()){
02801     long minExclusive;
02802 
02803     if (nsSchemaValidatorUtils::IsValidSchemaInteger(aMinExclusive, &minExclusive)
02804         && (nsSchemaValidatorUtils::CompareStrings(aNodeValue, aMinExclusive) <= 0)) {
02805       isValid = PR_FALSE;
02806       LOG(("  Not valid: Value is too small"));
02807     }
02808   }
02809 
02810   if (isValid && !aMaxInclusive.IsEmpty()){
02811     long maxInclusive;
02812 
02813     if (nsSchemaValidatorUtils::IsValidSchemaInteger(aMaxInclusive, &maxInclusive)
02814         && (nsSchemaValidatorUtils::CompareStrings(aNodeValue, aMaxInclusive) > 0)) {
02815       isValid = PR_FALSE;
02816       LOG(("  Not valid: Value is too large"));
02817     }
02818   }
02819 
02820   if (isValid && !aMinInclusive.IsEmpty()){
02821     long minInclusive;
02822 
02823     if (nsSchemaValidatorUtils::IsValidSchemaInteger(aMinInclusive, &minInclusive)
02824         && (nsSchemaValidatorUtils::CompareStrings(aNodeValue, aMinInclusive) < 0)) {
02825       isValid = PR_FALSE;
02826       LOG(("  Not valid: Value is too small"));
02827     }
02828   }
02829 
02830   if (isValid && aEnumerationList && (aEnumerationList->Count() > 0)) {
02831     isValid = nsSchemaValidatorUtils::HandleEnumeration(aNodeValue, *aEnumerationList);
02832   }
02833 
02834  *aResult = isValid;
02835   return NS_OK;
02836 }
02837 
02838 nsresult
02839 nsSchemaValidator::ValidateBuiltinTypeByte(const nsAString & aNodeValue,
02840                                            PRUint32 aTotalDigits,
02841                                            const nsAString & aMaxExclusive,
02842                                            const nsAString & aMinExclusive,
02843                                            const nsAString & aMaxInclusive,
02844                                            const nsAString & aMinInclusive,
02845                                            nsStringArray *aEnumerationList,
02846                                            PRBool *aResult)
02847 {
02848   PRBool isValid = PR_FALSE;
02849 
02850   long intValue;
02851   isValid = IsValidSchemaByte(aNodeValue, &intValue);
02852 
02853   if (aTotalDigits) {
02854     PRUint32 length = aNodeValue.Length();
02855 
02856     if (aNodeValue.First() == PRUnichar('-'))
02857       length -= 1;
02858 
02859     if (length > aTotalDigits) {
02860       isValid = PR_FALSE;
02861       LOG(("  Not valid: Too many digits (%d)", length));
02862     }
02863   }
02864 
02865   if (isValid && !aMaxExclusive.IsEmpty()){
02866     long maxExclusive;
02867 
02868     if (IsValidSchemaByte(aMaxExclusive, &maxExclusive) &&
02869         (intValue >= maxExclusive)) {
02870       isValid = PR_FALSE;
02871       LOG(("  Not valid: Value is too large"));
02872     }
02873   }
02874 
02875   if (isValid && !aMinExclusive.IsEmpty()){
02876     long minExclusive;
02877 
02878     if (IsValidSchemaByte(aMinExclusive, &minExclusive) &&
02879         (intValue <= minExclusive)) {
02880       isValid = PR_FALSE;
02881       LOG(("  Not valid: Value is too small"));
02882     }
02883   }
02884 
02885   if (isValid && !aMaxInclusive.IsEmpty()){
02886     long maxInclusive;
02887 
02888     if (IsValidSchemaByte(aMaxInclusive, &maxInclusive) &&
02889         (intValue > maxInclusive)) {
02890       isValid = PR_FALSE;
02891       LOG(("  Not valid: Value is too large"));
02892     }
02893   }
02894 
02895   if (isValid && !aMinInclusive.IsEmpty()){
02896     long minInclusive;
02897 
02898     if (IsValidSchemaByte(aMinInclusive, &minInclusive) &&
02899         (intValue < minInclusive)) {
02900       isValid = PR_FALSE;
02901       LOG(("  Not valid: Value is too small"));
02902     }
02903   }
02904 
02905   if (isValid && aEnumerationList && (aEnumerationList->Count() > 0)) {
02906     isValid = nsSchemaValidatorUtils::HandleEnumeration(aNodeValue,
02907                                                         *aEnumerationList);
02908   }
02909 
02910  *aResult = isValid;
02911   return NS_OK;
02912 }
02913 
02914 /* http://w3.org/TR/xmlschema-2/#byte */
02915 PRBool
02916 nsSchemaValidator::IsValidSchemaByte(const nsAString & aNodeValue, long *aResult)
02917 {
02918   PRBool isValid = PR_FALSE;
02919   long byteValue;
02920 
02921   isValid = nsSchemaValidatorUtils::IsValidSchemaInteger(aNodeValue, &byteValue,
02922                                                          PR_TRUE);
02923 
02924   if (isValid && ((byteValue > 127) || (byteValue < -128)))
02925     isValid = PR_FALSE;
02926 
02927   if (aResult)
02928     *aResult = byteValue;
02929   return isValid;
02930 }
02931 
02932 /* http://www.w3.org/TR/xmlschema-2/#float */
02933 nsresult
02934 nsSchemaValidator::ValidateBuiltinTypeFloat(const nsAString & aNodeValue,
02935                                             PRUint32 aTotalDigits,
02936                                             const nsAString & aMaxExclusive,
02937                                             const nsAString & aMinExclusive,
02938                                             const nsAString & aMaxInclusive,
02939                                             const nsAString & aMinInclusive,
02940                                             nsStringArray *aEnumerationList,
02941                                             PRBool *aResult)
02942 {
02943   PRBool isValid = PR_FALSE;
02944 
02945   float floatValue;
02946   isValid = IsValidSchemaFloat(aNodeValue, &floatValue);
02947 
02948   if (isValid && !aMaxExclusive.IsEmpty()){
02949     // If there is a facet and value is NaN,
02950     // then it is not valid.
02951     if (aNodeValue.EqualsLiteral("NaN")) {
02952       isValid = PR_FALSE;
02953       LOG(("  Not valid: Value NaN can't be constrained by facets"));
02954     } else {
02955       float maxExclusive;
02956 
02957       if (IsValidSchemaFloat(aMaxExclusive, &maxExclusive) &&
02958           (floatValue >= maxExclusive)) {
02959         isValid = PR_FALSE;
02960         LOG(("  Not valid: Value (%f) is too big", floatValue));
02961       }
02962     }
02963   }
02964 
02965   if (isValid && !aMinExclusive.IsEmpty()){
02966     // If there is a facet and value is NaN,
02967     // then it is not valid.
02968     if (aNodeValue.EqualsLiteral("NaN")) {
02969       isValid = PR_FALSE;
02970       LOG(("  Not valid: Value NaN can't be constrained by facets"));
02971     } else {
02972       float minExclusive;
02973 
02974       if (IsValidSchemaFloat(aMinExclusive, &minExclusive) &&
02975           (floatValue <= minExclusive)) {
02976         isValid = PR_FALSE;
02977         LOG(("  Not valid: Value (%f) is too small", floatValue));
02978       }
02979     }
02980   }
02981 
02982   if (isValid && !aMaxInclusive.IsEmpty()){
02983     // If there is a facet and value is NaN,
02984     // then it is not valid.
02985     if (aNodeValue.EqualsLiteral("NaN")) {
02986       isValid = PR_FALSE;
02987       LOG(("  Not valid: Value NaN can't be constrained by facets"));
02988     } else {
02989       float maxInclusive;
02990 
02991       if (IsValidSchemaFloat(aMaxInclusive, &maxInclusive) &&
02992           (floatValue > maxInclusive)) {
02993         isValid = PR_FALSE;
02994         LOG(("  Not valid: Value (%f) is too big", floatValue));
02995       }
02996     }
02997   }
02998 
02999   if (isValid && !aMinInclusive.IsEmpty()){
03000     // If there is a facet and value is NaN,
03001     // then it is not valid.
03002     if (aNodeValue.EqualsLiteral("NaN")) {
03003       isValid = PR_FALSE;
03004       LOG(("  Not valid: Value NaN can't be constrained by facets"));
03005     } else {
03006       float minInclusive;
03007 
03008       if (IsValidSchemaFloat(aMinInclusive, &minInclusive) &&
03009           (floatValue < minInclusive)) {
03010         isValid = PR_FALSE;
03011         LOG(("  Not valid: Value (%f) is too small", floatValue));
03012       }
03013     }
03014   }
03015 
03016   if (isValid && aEnumerationList && (aEnumerationList->Count() > 0)) {
03017     isValid = nsSchemaValidatorUtils::HandleEnumeration(aNodeValue,
03018                                                         *aEnumerationList);
03019   }
03020 
03021 #ifdef PR_LOGGING
03022   LOG((isValid ? ("  Value is valid!") : ("  Value is not valid!")));
03023 #endif
03024 
03025  *aResult = isValid;
03026   return NS_OK;
03027 }
03028 
03029 PRBool
03030 nsSchemaValidator::IsValidSchemaFloat(const nsAString & aNodeValue,
03031                                       float *aResult)
03032 {
03033   PRBool isValid = PR_TRUE;
03034   nsAutoString temp(aNodeValue);
03035 
03036   PRInt32 errorCode;
03037   float floatValue = temp.ToFloat(&errorCode);
03038   if (NS_FAILED(errorCode)) {
03039     // floats may be INF, -INF and NaN
03040     if (aNodeValue.EqualsLiteral("INF")) {
03041       floatValue = FLT_MAX;
03042     } else if (aNodeValue.EqualsLiteral("-INF")) {
03043       floatValue = - FLT_MAX;
03044     } else if (!aNodeValue.EqualsLiteral("NaN")) {
03045       isValid = PR_FALSE;
03046     }
03047   }
03048 
03049   if (aResult)
03050     *aResult = floatValue;
03051 
03052   return isValid;
03053 }
03054 
03055 /* http://www.w3.org/TR/xmlschema-2/#double */
03056 nsresult
03057 nsSchemaValidator::ValidateBuiltinTypeDouble(const nsAString & aNodeValue,
03058                                             PRUint32 aTotalDigits,
03059                                             const nsAString & aMaxExclusive,
03060                                             const nsAString & aMinExclusive,
03061                                             const nsAString & aMaxInclusive,
03062                                             const nsAString & aMinInclusive,
03063                                             nsStringArray *aEnumerationList,
03064                                             PRBool *aResult)
03065 {
03066   PRBool isValid = PR_FALSE;
03067 
03068   double doubleValue;
03069   isValid = IsValidSchemaDouble(aNodeValue, &doubleValue);
03070 
03071   if (isValid && !aMaxExclusive.IsEmpty()) {
03072     // If there is a facet and value is NaN,
03073     // then it is not valid.
03074     if (aNodeValue.EqualsLiteral("NaN")) {
03075       isValid = PR_FALSE;
03076       LOG(("  Not valid: Value NaN can't be constrained by facets"));
03077     } else {
03078       double maxExclusive;
03079 
03080       if (IsValidSchemaDouble(aMaxExclusive, &maxExclusive) &&
03081           (doubleValue >= maxExclusive)) {
03082         isValid = PR_FALSE;
03083         LOG(("  Not valid: Value (%f) is too big", doubleValue));
03084       }
03085     }
03086   }
03087 
03088   if (isValid && !aMinExclusive.IsEmpty()) {
03089     // If there is a facet and value is NaN,
03090     // then it is not valid.
03091     if (aNodeValue.EqualsLiteral("NaN")) {
03092       isValid = PR_FALSE;
03093       LOG(("  Not valid: Value NaN can't be constrained by facets"));
03094     } else {
03095       double minExclusive;
03096 
03097       if (IsValidSchemaDouble(aMinExclusive, &minExclusive) &&
03098           (doubleValue <= minExclusive)) {
03099         isValid = PR_FALSE;
03100         LOG(("  Not valid: Value (%f) is too small", doubleValue));
03101       }
03102     }
03103   }
03104 
03105   if (isValid && !aMaxInclusive.IsEmpty()) {
03106     // If there is a facet and value is NaN,
03107     // then it is not valid.
03108     if (aNodeValue.EqualsLiteral("NaN")) {
03109       isValid = PR_FALSE;
03110       LOG(("  Not valid: Value NaN can't be constrained by facets"));
03111     } else {
03112       double maxInclusive;
03113 
03114       if (IsValidSchemaDouble(aMaxInclusive, &maxInclusive) &&
03115           (doubleValue > maxInclusive)) {
03116         isValid = PR_FALSE;
03117         LOG(("  Not valid: Value (%f) is too big", doubleValue));
03118       }
03119     }
03120   }
03121 
03122   if (isValid && !aMinInclusive.IsEmpty()) {
03123     // If there is a facet and value is NaN,
03124     // then it is not valid.
03125     if (aNodeValue.EqualsLiteral("NaN")) {
03126       isValid = PR_FALSE;
03127       LOG(("  Not valid: Value NaN can't be constrained by facets"));
03128     } else {
03129       double minInclusive;
03130 
03131       if (IsValidSchemaDouble(aMinInclusive, &minInclusive) &&
03132           (doubleValue < minInclusive)) {
03133         isValid = PR_FALSE;
03134         LOG(("  Not valid: Value (%f) is too small", doubleValue));
03135       }
03136     }
03137   }
03138 
03139   if (isValid && aEnumerationList && (aEnumerationList->Count() > 0)) {
03140     isValid = nsSchemaValidatorUtils::HandleEnumeration(aNodeValue,
03141                                                         *aEnumerationList);
03142   }
03143 
03144 #ifdef PR_LOGGING
03145   LOG((isValid ? ("  Value is valid!") : ("  Value is not valid!")));
03146 #endif
03147 
03148  *aResult = isValid;
03149   return NS_OK;
03150 }
03151 
03152 PRBool
03153 nsSchemaValidator::IsValidSchemaDouble(const nsAString & aNodeValue,
03154                                       double *aResult)
03155 {
03156   return nsSchemaValidatorUtils::IsValidSchemaDouble(aNodeValue, aResult);
03157 }
03158 
03159 /* http://www.w3.org/TR/xmlschema-2/#decimal */
03160 nsresult
03161 nsSchemaValidator::ValidateBuiltinTypeDecimal(const nsAString & aNodeValue,
03162                                               PRUint32 aTotalDigits,
03163                                               PRUint32 aTotalFractionDigits,
03164                                               PRBool aFractionDigitsSet,
03165                                               const nsAString & aMaxExclusive,
03166                                               const nsAString & aMinExclusive,
03167                                               const nsAString & aMaxInclusive,
03168                                               const nsAString & aMinInclusive,
03169                                               nsStringArray *aEnumerationList,
03170                                               PRBool *aResult)
03171 {
03172   PRBool isValid = PR_FALSE;
03173   int strcmp;
03174 
03175   nsAutoString wholePart;
03176   nsAutoString wholePartFacet;
03177   nsAutoString fractionPart;
03178   nsAutoString fractionPartFacet;
03179 
03180   isValid = IsValidSchemaDecimal(aNodeValue, wholePart, fractionPart);
03181 
03182   // totalDigits is supposed to be positiveInteger, 1..n
03183   if (isValid && (aTotalDigits > 0)) {
03184     if (wholePart.Length() > aTotalDigits) {
03185      isValid = PR_FALSE;
03186       LOG(("  Not valid: Expected a maximum of %d digits, but found %d.",
03187            aTotalDigits, wholePart.Length()));
03188     }
03189   }
03190 
03191   // fractionDigits is nonNegativeInteger, 0..n
03192   if (isValid && aFractionDigitsSet) {
03193     if (fractionPart.Length() > aTotalFractionDigits) {
03194      isValid = PR_FALSE;
03195      LOG(("  Not valid: Expected a maximum of %d fraction digits, but found %d.",
03196           aTotalFractionDigits, fractionPart.Length()));
03197     }
03198   }
03199 
03200   if (isValid && !aMaxExclusive.IsEmpty() &&
03201       IsValidSchemaDecimal(aMaxExclusive, wholePartFacet, fractionPartFacet)) {
03202     strcmp = nsSchemaValidatorUtils::CompareStrings(wholePart, wholePartFacet);
03203     if (strcmp > 0) {
03204       isValid = PR_FALSE;
03205     } else if (strcmp == 0) {
03206       // if equal check the fraction part
03207       strcmp = CompareFractionStrings(fractionPart, fractionPartFacet);
03208       if (strcmp >= 0)
03209         isValid = PR_FALSE;
03210     }
03211 
03212     if (!isValid)
03213       LOG(("  Not valid: Value is too big"));
03214   }
03215 
03216   if (isValid && !aMinExclusive.IsEmpty() &&
03217       IsValidSchemaDecimal(aMinExclusive, wholePartFacet, fractionPartFacet)) {
03218     strcmp = nsSchemaValidatorUtils::CompareStrings(wholePart, wholePartFacet);
03219     if (strcmp < 0) {
03220       isValid = PR_FALSE;
03221     } else if (strcmp == 0) {
03222       // if equal check the fraction part
03223       strcmp = CompareFractionStrings(fractionPart, fractionPartFacet);
03224       if (strcmp <= 0)
03225         isValid = PR_FALSE;
03226     }
03227 
03228     if (!isValid)
03229       LOG(("  Not valid: Value is too small"));
03230   }
03231 
03232   if (isValid && !aMaxInclusive.IsEmpty() &&
03233       IsValidSchemaDecimal(aMaxInclusive, wholePartFacet, fractionPartFacet)) {
03234     strcmp = nsSchemaValidatorUtils::CompareStrings(wholePart, wholePartFacet);
03235     if (strcmp > 0) {
03236       isValid = PR_FALSE;
03237     } else if (strcmp == 0) {
03238       // if equal check the fraction part
03239       strcmp = CompareFractionStrings(fractionPart, fractionPartFacet);
03240       if (strcmp > 0)
03241         isValid = PR_FALSE;
03242     }
03243 
03244     if (!isValid)
03245       LOG(("  Not valid: Value is too big"));
03246   }
03247 
03248   if (isValid && !aMinInclusive.IsEmpty() &&
03249       IsValidSchemaDecimal(aMinInclusive, wholePartFacet, fractionPartFacet)) {
03250     strcmp = nsSchemaValidatorUtils::CompareStrings(wholePart, wholePartFacet);
03251     if (strcmp < 0) {
03252       isValid = PR_FALSE;
03253     } else if (strcmp == 0) {
03254       // if equal check the fraction part
03255       strcmp = CompareFractionStrings(fractionPart, fractionPartFacet);
03256       if (strcmp < 0)
03257         isValid = PR_FALSE;
03258     }
03259 
03260     if (!isValid)
03261       LOG(("  Not valid: Value is too small"));
03262   }
03263 
03264   if (isValid && aEnumerationList && (aEnumerationList->Count() > 0)) {
03265     isValid = nsSchemaValidatorUtils::HandleEnumeration(aNodeValue,
03266                                                         *aEnumerationList);
03267   }
03268 
03269 #ifdef PR_LOGGING
03270   LOG((isValid ? ("  Value is valid!") : ("  Value is not valid!")));
03271 #endif
03272 
03273  *aResult = isValid;
03274   return NS_OK;
03275 }
03276 
03277 PRBool
03278 nsSchemaValidator::IsValidSchemaDecimal(const nsAString & aNodeValue,
03279   nsAString & aWholePart, nsAString & aFractionPart)
03280 {
03281   PRBool isValid = PR_FALSE;
03282 
03283   int findString = aNodeValue.FindChar('.');
03284 
03285   if (findString == kNotFound) {
03286     aWholePart.Assign(aNodeValue);
03287   } else {
03288     aWholePart = Substring(aNodeValue, 0, findString);
03289     aFractionPart = Substring(aNodeValue, findString+1,
03290                               aNodeValue.Length() - findString - 1);
03291   }
03292 
03293   // to make test easier for example
03294   //   nsAutoString wh1, wh2, fr1, fr2;
03295   //   IsValidSchemaDecimal(NS_LITERAL_STRING("123.456"), wh1,fr1);
03296   //   IsValidSchemaDecimal(NS_LITERAL_STRING("000123.4560000"), wh2,fr2);
03297   //   if(wh1.Equals(wh2) && fr1.Equals(fr2)){ /* number are equal */ }
03298   nsSchemaValidatorUtils::RemoveLeadingZeros(aWholePart);
03299   nsSchemaValidatorUtils::RemoveTrailingZeros(aFractionPart);
03300 
03301   long temp;
03302   isValid = nsSchemaValidatorUtils::IsValidSchemaInteger(aWholePart, &temp);
03303 
03304   if (isValid && (findString != kNotFound)) {
03305     // XXX: assuming "2." is not valid
03306     if (aFractionPart.IsEmpty())
03307       isValid = PR_FALSE;
03308     else if ((aFractionPart.First() == '-') || (aFractionPart.First() == '+'))
03309       isValid = PR_FALSE;
03310     else
03311       isValid = nsSchemaValidatorUtils::IsValidSchemaInteger(aFractionPart,
03312                                                              &temp);
03313   }
03314 
03315   return isValid;
03316 }
03317 
03318 /* compares 2 strings that contain fraction parts of a decimal
03319 
03320  -1 - aString1 < aString2
03321   0 - equal
03322   1 - aString1 > aString2
03323 
03324  */
03325 int
03326 nsSchemaValidator::CompareFractionStrings(const nsAString & aString1,
03327                                           const nsAString & aString2)
03328 {
03329   int cmpresult = 0;
03330 
03331   // are the equal?
03332   if (aString1.Equals(aString2))
03333     return 0;
03334 
03335   nsAutoString compareString1;
03336   nsAutoString compareString2;
03337 
03338   // put the shorter string in compareString1
03339   if (aString1.Length() < aString2.Length()) {
03340     compareString1.Assign(aString1);
03341     compareString2.Assign(aString2);
03342   } else {
03343     compareString1.Assign(aString2);
03344     compareString2.Assign(aString1);
03345   }
03346 
03347   nsAString::const_iterator start1, end1, start2, end2;
03348   compareString1.BeginReading(start1);
03349   compareString1.EndReading(end1);
03350 
03351   compareString2.BeginReading(start2);
03352   compareString2.EndReading(end2);
03353 
03354   PRBool done = PR_FALSE;
03355 
03356   while ((start1 != end1) && !done)
03357   {
03358     if (*++start1 != *++start2)
03359       done = PR_TRUE;
03360   }
03361 
03362   // first string has been iterated through, and all matched
03363   // we know the 2 cannot be the same due to the .Equals() check above,
03364   // so this means that string2 is equal to string1 and then has some more
03365   // numbers, meaning string2 is bigger
03366   if ((start1 == end1) && !done) {
03367     cmpresult = -1;
03368   } else if (done) {
03369     // *start1 is != *start2
03370     if (*start1 < *start2)
03371       cmpresult = 1;
03372     else
03373       cmpresult = -1;
03374   }
03375 
03376   return cmpresult;
03377 }
03378 
03379 /* http://w3c.org/TR/xmlschema-2/#anyURI */
03380 nsresult
03381 nsSchemaValidator::ValidateBuiltinTypeAnyURI(const nsAString & aNodeValue,
03382                                              PRUint32 aLength,
03383                                              PRUint32 aMinLength,
03384                                              PRUint32 aMaxLength,
03385                                              nsStringArray *aEnumerationList,
03386                                              PRBool *aResult)
03387 {
03388   PRUint32 length = aNodeValue.Length();
03389   PRBool isValid = PR_FALSE;
03390 
03391   isValid = (IsValidSchemaAnyURI(aNodeValue)) &&
03392             (!aLength || length == aLength) &&
03393             (!aMinLength || length >= aMinLength) &&
03394             (!aMaxLength || length <= aMaxLength);
03395 
03396   if (isValid && aEnumerationList && (aEnumerationList->Count() > 0)) {
03397     isValid = nsSchemaValidatorUtils::HandleEnumeration(aNodeValue,
03398                                                         *aEnumerationList);
03399   }
03400 
03401   *aResult = isValid;
03402   return NS_OK;
03403 }
03404 
03405 PRBool
03406 nsSchemaValidator::IsValidSchemaAnyURI(const nsAString & aString)
03407 {
03408   PRBool isValid = PR_FALSE;
03409 
03410   if (aString.IsEmpty()) {
03411     isValid = PR_TRUE;
03412   } else {
03413     nsCOMPtr<nsIURI> uri, absUri;
03414 
03415     // Need to supply a baseURI to allow relative URIs
03416     NS_NewURI(getter_AddRefs(absUri), NS_LITERAL_STRING("http://a"));
03417     nsresult rv = NS_NewURI(getter_AddRefs(uri), aString,
03418                             (const char*)nsnull, absUri);
03419 
03420     if (rv == NS_OK)
03421       isValid = PR_TRUE;
03422   }
03423 
03424   return isValid;
03425 }
03426 
03427 // http://w3c.org/TR/xmlschema-2/#base64Binary
03428 nsresult
03429 nsSchemaValidator::ValidateBuiltinTypeBase64Binary(const nsAString & aNodeValue,
03430                                                    PRUint32 aLength,
03431                                                    PRBool aLengthDefined,
03432                                                    PRUint32 aMinLength,
03433                                                    PRBool aMinLengthDefined,
03434                                                    PRUint32 aMaxLength,
03435                                                    PRBool aMaxLengthDefined,
03436                                                    nsStringArray *aEnumerationList,
03437                                                    PRBool *aResult)
03438 {
03439   PRBool isValid = PR_FALSE;
03440   PRUint32 length;
03441 
03442   char* decodedString;
03443   isValid = IsValidSchemaBase64Binary(aNodeValue, &decodedString);
03444 
03445   if (isValid) {
03446     length = strlen(decodedString);
03447 
03448     if (aLengthDefined && (length != aLength)) {
03449       isValid = PR_FALSE;
03450       LOG(("  Not valid: Not the right length (%d)", length));
03451     }
03452 
03453     if (aMinLengthDefined && (length < aMinLength)) {
03454       isValid = PR_FALSE;
03455       LOG(("  Not valid: Length (%d) is too small", length));
03456     }
03457 
03458     if (aMaxLengthDefined && (length > aMaxLength)) {
03459       isValid = PR_FALSE;
03460       LOG(("  Not valid: Length (%d) is too large", length));
03461     }
03462   }
03463 
03464   if (isValid && aEnumerationList && (aEnumerationList->Count() > 0)) {
03465     isValid = nsSchemaValidatorUtils::HandleEnumeration(aNodeValue,
03466                                                         *aEnumerationList);
03467   }
03468 
03469 #ifdef PR_LOGGING
03470   LOG((isValid ? ("  Value is valid!") : ("  Value is not valid!")));
03471 #endif
03472 
03473   nsMemory::Free(decodedString);
03474   *aResult = isValid;
03475   return NS_OK;
03476 }
03477 
03478 PRBool
03479 nsSchemaValidator::IsValidSchemaBase64Binary(const nsAString & aString,
03480                                              char** aDecodedString)
03481 {
03482   *aDecodedString = PL_Base64Decode(NS_ConvertUTF16toUTF8(aString).get(),
03483                                     aString.Length(), nsnull);
03484   return (*aDecodedString != nsnull);
03485 }
03486 
03487 // http://www.w3.org/TR/xmlschema-2/#QName
03488 nsresult
03489 nsSchemaValidator::ValidateBuiltinTypeQName(const nsAString & aNodeValue,
03490                                             PRUint32 aLength,
03491                                             PRBool aLengthDefined,
03492                                             PRUint32 aMinLength,
03493                                             PRBool aMinLengthDefined,
03494                                             PRUint32 aMaxLength,
03495                                             PRBool aMaxLengthDefined,
03496                                             nsStringArray *aEnumerationList,
03497                                             PRBool *aResult)
03498 {
03499   PRBool isValid = PR_FALSE;
03500   PRUint32 length;
03501 
03502   isValid = IsValidSchemaQName(aNodeValue);
03503 
03504   if (isValid) {
03505     length = aNodeValue.Length();
03506 
03507     if (aLengthDefined && (length != aLength)) {
03508       isValid = PR_FALSE;
03509       LOG(("  Not valid: Not the right length (%d)", length));
03510     }
03511 
03512     if (aMinLengthDefined && (length < aMinLength)) {
03513       isValid = PR_FALSE;
03514       LOG(("  Not valid: Length (%d) is too small", length));
03515     }
03516 
03517     if (aMaxLengthDefined && (length > aMaxLength)) {
03518       isValid = PR_FALSE;
03519       LOG(("  Not valid: Length (%d) is too large", length));
03520     }
03521   }
03522 
03523   if (isValid && aEnumerationList && (aEnumerationList->Count() > 0)) {
03524     isValid = nsSchemaValidatorUtils::HandleEnumeration(aNodeValue,
03525                                                         *aEnumerationList);
03526   }
03527 
03528 #ifdef PR_LOGGING
03529   LOG((isValid ? ("  Value is valid!") : ("  Value is not valid!")));
03530 #endif
03531 
03532   *aResult = isValid;
03533   return NS_OK;
03534 }
03535 
03536 PRBool
03537 nsSchemaValidator::IsValidSchemaQName(const nsAString & aString)
03538 {
03539   PRBool isValid = PR_FALSE;
03540 
03541   nsresult rv;
03542   // split type (ns:type) into namespace and type.
03543   nsCOMPtr<nsIParserService> parserService =
03544     do_GetService("@mozilla.org/parser/parser-service;1", &rv);
03545   NS_ENSURE_SUCCESS(rv, PR_FALSE);
03546 
03547   const PRUnichar *colon;
03548   const nsAFlatString& qName = PromiseFlatString(aString);
03549   rv = parserService->CheckQName(qName, PR_TRUE, &colon);
03550   if (NS_SUCCEEDED(rv)) {
03551     isValid = PR_TRUE;
03552   }
03553 
03554   return isValid;
03555 }
03556 
03557 // http://www.w3.org/TR/xmlschema-2/#hexBinary
03558 nsresult
03559 nsSchemaValidator::ValidateBuiltinTypeHexBinary(const nsAString & aNodeValue,
03560                                                 PRUint32 aLength,
03561                                                 PRBool aLengthDefined,
03562                                                 PRUint32 aMinLength,
03563                                                 PRBool aMinLengthDefined,
03564                                                 PRUint32 aMaxLength,
03565                                                 PRBool aMaxLengthDefined,
03566                                                 nsStringArray *aEnumerationList,
03567                                                 PRBool *aResult)
03568 {
03569   PRBool isValid = IsValidSchemaHexBinary(aNodeValue);
03570 
03571   if (isValid) {
03572     // For hexBinary, length is measured in octets (8 bits) of binary data.  So
03573     // one byte of binary data is represented by two hex digits, so we
03574     // divide by 2 to get the binary data length.
03575 
03576     PRUint32 binaryDataLength = aNodeValue.Length() / 2;
03577 
03578     if (aLengthDefined && (binaryDataLength != aLength)) {
03579       isValid = PR_FALSE;
03580       LOG(("  Not valid: Not the right length (%d)", binaryDataLength));
03581     }
03582 
03583     if (isValid && aMinLengthDefined && (binaryDataLength < aMinLength)) {
03584       isValid = PR_FALSE;
03585       LOG(("  Not valid: Length (%d) is too small", binaryDataLength));
03586     }
03587 
03588     if (isValid && aMaxLengthDefined && (binaryDataLength > aMaxLength)) {
03589       isValid = PR_FALSE;
03590       LOG(("  Not valid: Length (%d) is too large", binaryDataLength));
03591     }
03592 
03593     if (isValid && aEnumerationList && (aEnumerationList->Count() > 0)) {
03594       isValid = nsSchemaValidatorUtils::HandleEnumeration(aNodeValue,
03595                                                           *aEnumerationList);
03596     }
03597   }
03598 
03599   LOG((isValid ? ("  Value is valid!") : ("  Value is not valid!")));
03600 
03601   *aResult = isValid;
03602   return NS_OK;
03603 }
03604 
03605 PRBool
03606 nsSchemaValidator::IsValidSchemaHexBinary(const nsAString & aString)
03607 {
03608   // hex binary length has to be even
03609   PRUint32 length = aString.Length();
03610 
03611   if (length % 2 != 0)
03612     return PR_FALSE;
03613 
03614   nsAString::const_iterator start, end;
03615   aString.BeginReading(start);
03616   aString.EndReading(end);
03617 
03618   PRBool isValid = PR_TRUE;
03619 
03620   // each character has to be in [0-9a-fA-F]
03621   while (start != end) {
03622     PRUnichar temp = *start++;
03623 
03624     if (!isxdigit(temp)) {
03625       isValid = PR_FALSE;
03626       break;
03627     }
03628   }
03629 
03630   return isValid;
03631 }
03632 
03633 #ifdef DEBUG
03634 void
03635 nsSchemaValidator::DumpBaseType(nsISchemaBuiltinType *aBuiltInType)
03636 {
03637   nsAutoString typeName;
03638   aBuiltInType->GetName(typeName);
03639   PRUint16 foo;
03640   aBuiltInType->GetBuiltinType(&foo);
03641 
03642   LOG(("  Base Type is %s (%d)", NS_ConvertUTF16toUTF8(typeName).get(),foo));
03643 }
03644 #endif
03645 
03646 
03647 
03648 /****************************************************
03649  * Complex Type Validation                          *
03650  ****************************************************/
03651 
03652 // http://w3c.org/TR/xmlschema-1/#Complex_Type_Definitions
03653 nsresult
03654 nsSchemaValidator::ValidateComplextype(nsIDOMNode* aNode,
03655                                        nsISchemaComplexType *aSchemaComplexType,
03656                                        PRBool *aResult)
03657 {
03658   PRBool isValid = PR_FALSE;
03659   *aResult = PR_FALSE;
03660 
03661   PRUint16 contentModel;
03662   nsresult rv = aSchemaComplexType->GetContentModel(&contentModel);
03663   NS_ENSURE_SUCCESS(rv, rv);
03664 
03665   switch(contentModel) {
03666     case nsISchemaComplexType::CONTENT_MODEL_EMPTY: {
03667       LOG(("    complex type, empty content"));
03668       rv = ValidateComplexModelEmpty(aNode, aSchemaComplexType, &isValid);
03669       break;
03670     }
03671 
03672     case nsISchemaComplexType::CONTENT_MODEL_SIMPLE: {
03673       LOG(("    complex type, simple content"));
03674       rv = ValidateComplexModelSimple(aNode, aSchemaComplexType, &isValid);
03675       break;
03676     }
03677 
03678     case nsISchemaComplexType::CONTENT_MODEL_ELEMENT_ONLY: {
03679       LOG(("    xsd:element only"));
03680       rv = ValidateComplexModelElement(aNode, aSchemaComplexType, &isValid);
03681       break;
03682     }
03683 
03684     case nsISchemaComplexType::CONTENT_MODEL_MIXED: {
03685       LOG(("    complex type, mixed content"));
03686       rv = ValidateComplexModelElement(aNode, aSchemaComplexType, &isValid);
03687       break;
03688     }
03689   }
03690 
03691   if (!isValid) {
03692     *aResult = PR_FALSE;
03693     return NS_OK;
03694   }
03695 
03696   // if we are valid, validate the attributes
03697   nsCOMPtr<nsIDOMNamedNodeMap> attrMap;
03698   rv = aNode->GetAttributes(getter_AddRefs(attrMap));
03699   NS_ENSURE_SUCCESS(rv, rv);
03700 
03701   PRUint32 attrCount = 0, ignoreAttrCount = 0, totalAttr = 0, foundAttrCount = 0;
03702 
03703   // Get total attributes on node.
03704   // We need to walk all nodes and count attribute nodes who don't get used
03705   // in schema validation - namespace declarations (xmlns=, xmlns:foo=) and
03706   // attributes nodes in the schema instance namespace
03707   attrMap->GetLength(&totalAttr);
03708   nsCOMPtr<nsIDOMNode> attrNode;
03709   nsCOMPtr<nsIDOMAttr> attr;
03710   nsAutoString name;
03711 
03712   for (PRUint32 i = 0; i < totalAttr; ++i) {
03713     rv = attrMap->Item(i, getter_AddRefs(attrNode));
03714     NS_ENSURE_SUCCESS(rv, rv);
03715 
03716     attr = do_QueryInterface(attrNode);
03717     if (attr) {
03718       // XXX: we need to make this per spec (such as Part 1 3.2.7)
03719       attr->GetName(name);
03720       if (StringBeginsWith(name, NS_LITERAL_STRING("xmlns"))) {
03721         // is the entire string xmlns or does : come right after xmlns?
03722         if (name.Length() == 5 || name.CharAt(5) == ':')
03723           ignoreAttrCount++;
03724       } else {
03725         // check if the namespace is in the schema instance namespace
03726         nsAutoString nsuri;
03727         rv = attr->GetNamespaceURI(nsuri);
03728         NS_ENSURE_SUCCESS(rv, rv);
03729 
03730         if (nsuri.EqualsLiteral(NS_SCHEMA_INSTANCE_NAMESPACE))
03731           ignoreAttrCount++;
03732       }
03733     }
03734   }
03735 
03736   // we subtract namespace declaration attributes
03737   totalAttr -= ignoreAttrCount;
03738   LOG(("    Number of attributes on node: %d (%d omitted)", totalAttr,
03739        ignoreAttrCount));
03740 
03741   // get total defined attributes on schema
03742   aSchemaComplexType->GetAttributeCount(&attrCount);
03743   LOG(("    Number of schema-defined attributes found: %d", attrCount));
03744 
03745   // iterate through all the attribute definitions on the schema and check
03746   // if they pass
03747   PRUint32 count = 0;
03748   nsCOMPtr<nsISchemaAttributeComponent> attrComp;
03749 
03750   while (isValid && (count < attrCount)) {
03751     rv = aSchemaComplexType->GetAttributeByIndex(count,
03752                                                  getter_AddRefs(attrComp));
03753     NS_ENSURE_SUCCESS(rv, rv);
03754 
03755     rv = ValidateAttributeComponent(aNode, attrComp, &foundAttrCount,
03756                                     &isValid);
03757     NS_ENSURE_SUCCESS(rv, rv);
03758 
03759     ++count;
03760   }
03761 
03762   // we walked all the attribute definitions.  If foundAttrCount is smaller
03763   // than the attributes on the node, we have undefined attributes.
03764   if (isValid && (totalAttr > foundAttrCount)) {
03765     isValid = PR_FALSE;
03766     LOG(("  --  Node contains attributes not defined in its schema!"));
03767   }
03768 
03769   *aResult = isValid;
03770   return rv;
03771 }
03772 
03773 // http://w3c.org/TR/xmlschema-1/#cElement_Declarations
03774 nsresult
03775 nsSchemaValidator::ValidateComplexModelElement(nsIDOMNode* aNode,
03776                                                nsISchemaComplexType *aSchemaComplexType,
03777                                                PRBool *aResult)
03778 {
03779   PRBool isValid = PR_FALSE;
03780 
03781   nsCOMPtr<nsISchemaModelGroup> modelGroup;
03782   nsresult rv = aSchemaComplexType->GetModelGroup(getter_AddRefs(modelGroup));
03783   NS_ENSURE_SUCCESS(rv, rv);
03784 
03785   nsCOMPtr<nsIDOMNode> leftOvers, startNode;
03786   aNode->GetFirstChild(getter_AddRefs(startNode));
03787 
03788   rv = ValidateComplexModelGroup(startNode, modelGroup,
03789                                  getter_AddRefs(leftOvers), &isValid);
03790 
03791   if (isValid && leftOvers) {
03792     // unexpected node
03793     isValid = PR_FALSE;
03794 #ifdef PR_LOGGING
03795     nsAutoString name;
03796     leftOvers->GetNodeName(name);
03797     LOG(("  -- Expected end but found more nodes (%s)!",
03798          NS_ConvertUTF16toUTF8(name).get()));
03799 #endif
03800   }
03801 
03802   *aResult = isValid;
03803   return rv;
03804 }
03805 
03806 nsresult
03807 nsSchemaValidator::ValidateComplexModelEmpty(nsIDOMNode* aNode,
03808                                     nsISchemaComplexType *aSchemaComplexType,
03809                                     PRBool *aResult)
03810 {
03811   PRBool isValid = PR_TRUE;
03812   nsresult rv = NS_OK;
03813 
03814   nsCOMPtr<nsIDOMNode> currentNode;
03815   rv = aNode->GetFirstChild(getter_AddRefs(currentNode));
03816   NS_ENSURE_SUCCESS(rv, rv);
03817 
03818   while (isValid && currentNode) {
03819     PRUint16 nodeType;
03820     currentNode->GetNodeType(&nodeType);
03821     if (nodeType == nsIDOMNode::ELEMENT_NODE ||
03822         nodeType == nsIDOMNode::TEXT_NODE) {
03823       LOG(("  --  Empty content model contains element or text!"));
03824       isValid = PR_FALSE;
03825       break;
03826     }
03827 
03828     nsCOMPtr<nsIDOMNode> node;
03829     currentNode->GetNextSibling(getter_AddRefs(node));
03830     currentNode.swap(node);
03831   }
03832   *aResult = isValid;
03833   return rv;
03834 }
03835 
03836 nsresult
03837 nsSchemaValidator::ValidateComplexModelSimple(nsIDOMNode* aNode,
03838                                               nsISchemaComplexType *aSchemaComplexType,
03839                                               PRBool *aResult)
03840 {
03841   PRBool isValid = PR_FALSE;
03842 
03843   PRUint16 derivation;;
03844   nsresult rv = aSchemaComplexType->GetDerivation(&derivation);
03845   NS_ENSURE_SUCCESS(rv, rv);
03846 
03847   // two choices for complex model with simple content: derivation through
03848   // extension or through restriction
03849   switch(derivation) {
03850     case nsISchemaComplexType::DERIVATION_EXTENSION_SIMPLE:
03851     case nsISchemaComplexType::DERIVATION_RESTRICTION_SIMPLE: {
03852 
03853 #ifdef PR_LOGGING
03854       if (derivation == nsISchemaComplexType::DERIVATION_EXTENSION_SIMPLE)
03855         LOG(("      -- deriviation by extension of a simple type"));
03856       else
03857         LOG(("      -- deriviation by restriction of a simple type"));
03858 #endif
03859 
03860       nsCOMPtr<nsISchemaSimpleType> simpleBaseType;
03861       rv = aSchemaComplexType->GetSimpleBaseType(getter_AddRefs(simpleBaseType));
03862       NS_ENSURE_SUCCESS(rv, rv);
03863 
03864       nsAutoString nodeValue;
03865       nsCOMPtr<nsIDOM3Node> domNode3 = do_QueryInterface(aNode);
03866       domNode3->GetTextContent(nodeValue);
03867 
03868       rv = ValidateSimpletype(nodeValue, simpleBaseType, &isValid);
03869       break;
03870     }
03871 
03872     default:
03873       rv = NS_ERROR_UNEXPECTED;
03874   }
03875 
03876   *aResult = isValid;
03877   return rv;
03878 }
03879 
03880 nsresult
03881 nsSchemaValidator::ValidateComplexModelGroup(nsIDOMNode* aNode,
03882                                              nsISchemaModelGroup *aSchemaModelGroup,
03883                                              nsIDOMNode **aLeftOvers,
03884                                              PRBool *aResult)
03885 {
03886   nsresult rv = NS_OK;
03887   PRBool notFound = PR_FALSE, isValid = PR_FALSE;
03888 
03889   // a model group can be of type All, Sequence or Choice
03890   // http://w3c.org/TR/xmlschema-1/#Model_Groups
03891   PRUint16 compositor;
03892   rv = aSchemaModelGroup->GetCompositor(&compositor);
03893   NS_ENSURE_SUCCESS(rv, rv);
03894 
03895   PRUint32 validatedNodes = 0;
03896   PRUint32 minOccurs;
03897   aSchemaModelGroup->GetMinOccurs(&minOccurs);
03898 
03899   PRUint32 maxOccurs;
03900   aSchemaModelGroup->GetMaxOccurs(&maxOccurs);
03901 
03902   PRUint32 particleCount;
03903   aSchemaModelGroup->GetParticleCount(&particleCount);
03904 
03905   nsCOMPtr<nsIDOMNode> currentNode(aNode), leftOvers;
03906 
03907   switch(compositor) {
03908     case nsISchemaModelGroup::COMPOSITOR_ALL: {
03909       LOG(("      - It is a All Compositor (%d)", particleCount));
03910       // xsd:all has several limitations:
03911       //  - order does not matter
03912       //  - xsd:all can only occur a maximum of once
03913       //  - it can contain only xsd:elements, who may only occur 0 or 1 times.
03914 
03915       // since an xsd:all can only happen once or never, validate it once
03916       // and return.
03917 
03918       rv = ValidateComplexAll(currentNode, aSchemaModelGroup,
03919                               getter_AddRefs(leftOvers), &notFound, &isValid);
03920       currentNode = leftOvers;
03921 
03922       // if it wasn't found but is required to happen once, it is invalid
03923       if (isValid && notFound && minOccurs == 1) {
03924         isValid = PR_FALSE;
03925 #ifdef PR_LOGGING
03926         nsCOMPtr<nsISchemaParticle> particle;
03927         aSchemaModelGroup->GetParticle(0, getter_AddRefs(particle));
03928         if (particle) {
03929           nsAutoString name;
03930           particle->GetName(name);
03931           LOG(("      - Expected one occurance of %s, but found none!",
03932                NS_ConvertUTF16toUTF8(name).get()));
03933         }
03934 #endif
03935       }
03936 
03937       break;
03938     }
03939 
03940     case nsISchemaModelGroup::COMPOSITOR_SEQUENCE: {
03941       LOG(("      - It is a Sequence (%d)", particleCount));
03942       PRUint32 iterations = 0;
03943       isValid = PR_TRUE;
03944 
03945       while (currentNode && isValid && (iterations < maxOccurs) && !notFound) {
03946         rv = ValidateComplexSequence(currentNode, aSchemaModelGroup,
03947                                      getter_AddRefs(leftOvers), &notFound,
03948                                      &isValid, &validatedNodes);
03949         if (isValid && !notFound) {
03950           iterations++;
03951         }
03952         currentNode = leftOvers;
03953       }
03954 
03955       // Special case of found nothing and expected nothing, so it's easy
03956       if (validatedNodes == 0 && iterations == 0 && minOccurs == 0) {
03957         isValid = PR_TRUE;
03958       } else if (isValid && (iterations < minOccurs) && (validatedNodes > 0)) {
03959         // if we didn't hit minOccurs and not empty sequence, invalid
03960         isValid = PR_FALSE;
03961 #ifdef PR_LOGGING
03962         nsCOMPtr<nsISchemaParticle> particle;
03963         nsAutoString name;
03964         aSchemaModelGroup->GetParticle(0, getter_AddRefs(particle));
03965 
03966         if (particle) {
03967           particle->GetName(name);
03968           LOG(("      - Expected at least %d iterations of %s, only found %d",
03969                minOccurs, NS_ConvertUTF16toUTF8(name).get(), iterations));
03970         }
03971 #endif
03972       }
03973 
03974       break;
03975     }
03976 
03977     case nsISchemaModelGroup::COMPOSITOR_CHOICE: {
03978       LOG(("      - It is a Choice"));
03979 
03980       PRUint32 iterations = 0;
03981       isValid = PR_TRUE;
03982 
03983       while (currentNode && isValid && (iterations < maxOccurs)) {
03984         rv = ValidateComplexChoice(currentNode, aSchemaModelGroup,
03985                                    getter_AddRefs(leftOvers), &notFound,
03986                                    &isValid);
03987         if (isValid) {
03988           iterations++;
03989         }
03990         currentNode = leftOvers;
03991       }
03992 
03993       // if we didn't hit minOccurs, invalid
03994       if (isValid && (iterations < minOccurs)) {
03995         isValid = PR_FALSE;
03996 #ifdef PR_LOGGING
03997         nsCOMPtr<nsISchemaParticle> particle;
03998         nsAutoString name;
03999         aSchemaModelGroup->GetParticle(0, getter_AddRefs(particle));
04000 
04001         if (particle) {
04002           particle->GetName(name);
04003           LOG(("      - Expected at least %d iterations of %s, only found %d",
04004                minOccurs, NS_ConvertUTF16toUTF8(name).get(), iterations));
04005         }
04006 #endif
04007       }
04008 
04009       break;
04010     }
04011   }
04012 
04013   leftOvers.swap(*aLeftOvers);
04014   *aResult = isValid;
04015   return rv;
04016 }
04017 
04018 nsresult
04019 nsSchemaValidator::ValidateComplexSequence(nsIDOMNode* aStartNode,
04020                                            nsISchemaModelGroup *aSchemaModelGroup,
04021                                            nsIDOMNode **aLeftOvers,
04022                                            PRBool *aNotFound, PRBool *aResult,
04023                                            PRUint32 *aValidatedNodes)
04024 {
04025   if (!aStartNode || !aSchemaModelGroup)
04026     return NS_ERROR_UNEXPECTED;
04027 
04028   PRBool isValid = PR_FALSE;
04029   PRBool notFound = PR_FALSE;
04030 
04031   // get the model group details
04032   PRUint32 minOccurs;
04033   nsresult rv = aSchemaModelGroup->GetMinOccurs(&minOccurs);
04034   NS_ENSURE_SUCCESS(rv, rv);
04035 
04036   PRUint32 maxOccurs;
04037   rv = aSchemaModelGroup->GetMaxOccurs(&maxOccurs);
04038   NS_ENSURE_SUCCESS(rv, rv);
04039 
04040   PRUint32 particleCount;
04041   rv = aSchemaModelGroup->GetParticleCount(&particleCount);
04042   NS_ENSURE_SUCCESS(rv, rv);
04043 
04044   // xsd:sequence means that the order of the particles matters
04045   PRUint32 validatedNodes = 0;
04046   PRUint32 particleCounter = 0;
04047   PRUint16 nodeType;
04048   PRBool done = PR_FALSE;
04049   nsCOMPtr<nsISchemaParticle> particle;
04050   nsCOMPtr<nsIDOMNode> currentNode(aStartNode), leftOvers, tmpNode;
04051 
04052   LOG(("====================== New Sequence ==========================="));
04053 
04054   // while valid and not done
04055   // we are done when we hit a node that doesn't fit our schema
04056   while (!done && currentNode && (particleCounter < particleCount)) {
04057     // get node type
04058     currentNode->GetNodeType(&nodeType);
04059 
04060     // if not an element node, skip
04061     if (nodeType != nsIDOMNode::ELEMENT_NODE) {
04062       currentNode->GetNextSibling(getter_AddRefs(tmpNode));
04063       currentNode = tmpNode;
04064       continue;
04065     }
04066 
04067     // get the particle
04068     rv = aSchemaModelGroup->GetParticle(particleCounter,
04069                                         getter_AddRefs(particle));
04070     NS_ENSURE_SUCCESS(rv, rv);
04071 
04072     rv = ValidateComplexParticle(currentNode, particle,
04073                                  getter_AddRefs(leftOvers), &notFound, &isValid);
04074     NS_ENSURE_SUCCESS(rv, rv);
04075 
04076     // if we found the node, increment the amount of validated nodes.
04077     if (!notFound)
04078       validatedNodes++;
04079 
04080     if (isValid) {
04081       particleCounter++;
04082     } else {
04083       done = PR_TRUE;
04084     }
04085 
04086     // valid and not found means it was optional, so ok
04087     if (isValid && notFound) {
04088       notFound = PR_FALSE;
04089     }
04090 
04091     // not valid and not found means we finish this sequence.  If any particles
04092     // are left that are required, that will be handled below.
04093     if (!isValid && notFound) {
04094       isValid = PR_TRUE;
04095       particleCounter++;
04096     }
04097 
04098     currentNode = leftOvers;
04099   }
04100 
04101   *aValidatedNodes = validatedNodes;
04102 
04103   if (validatedNodes == 0) {
04104     // we didn't walk through any nodes, thus empty sequence.  The caller
04105     // will check if enough occurances (minOccurs) on the sequence happened.
04106     // We need to continue to make sure we don't have all element
04107     // declarations with each having minOccurs=0, thus empty content is allowed.
04108     isValid = PR_TRUE;
04109     notFound = PR_TRUE;
04110   }
04111 
04112   // check if any of the remaining particles are required
04113   while (isValid && (particleCounter < particleCount)) {
04114     nsCOMPtr<nsISchemaParticle> tmpParticle;
04115     rv = aSchemaModelGroup->GetParticle(particleCounter,
04116                                         getter_AddRefs(tmpParticle));
04117     NS_ENSURE_SUCCESS(rv, rv);
04118 
04119     PRUint32 tmpMinOccurs;
04120     rv = tmpParticle->GetMinOccurs(&tmpMinOccurs);
04121     NS_ENSURE_SUCCESS(rv, rv);
04122 
04123     if (tmpMinOccurs == 0) {
04124       // this particle isn't required
04125       particleCounter++;
04126     } else {
04127       isValid = PR_FALSE;
04128 #ifdef PR_LOGGING
04129       nsAutoString particleName;
04130       tmpParticle->GetName(particleName);
04131       LOG(("        - Nodelist missing required element (%s)",
04132            NS_ConvertUTF16toUTF8(particleName).get()));
04133 #endif
04134     }
04135   }
04136 
04137   // make sure aLeftOvers points to null or an element node
04138   nsSchemaValidatorUtils::SetToNullOrElement(currentNode, aLeftOvers);
04139 
04140   *aNotFound = notFound;
04141   *aResult = isValid;
04142   return rv;
04143 }
04144 
04145 nsresult
04146 nsSchemaValidator::ValidateComplexParticle(nsIDOMNode* aNode,
04147                                            nsISchemaParticle *aSchemaParticle,
04148                                            nsIDOMNode **aLeftOvers,
04149                                            PRBool *aNotFound,
04150                                            PRBool *aResult)
04151 {
04152   PRBool isValid = PR_FALSE;
04153   PRBool notFound = PR_FALSE;
04154 
04155   PRUint16 particleType;
04156   nsresult rv = aSchemaParticle->GetParticleType(&particleType);
04157   NS_ENSURE_SUCCESS(rv, rv);
04158 
04159   PRUint32 minOccurs;
04160   rv = aSchemaParticle->GetMinOccurs(&minOccurs);
04161   NS_ENSURE_SUCCESS(rv, rv);
04162 
04163   PRUint32 maxOccurs;
04164   rv = aSchemaParticle->GetMaxOccurs(&maxOccurs);
04165   NS_ENSURE_SUCCESS(rv, rv);
04166 
04167   nsCOMPtr<nsIDOMNode> leftOvers, tmpNode;
04168 
04169   switch(particleType) {
04170     case nsISchemaParticle::PARTICLE_TYPE_ELEMENT: {
04171       LOG(("            -- Particle is an Element"));
04172       PRUint32 iterations = 0;
04173       PRBool done = PR_FALSE;
04174       nsAutoString nodeName, particleName;
04175       leftOvers = aNode;
04176 
04177       while (leftOvers && !done && (iterations < maxOccurs)) {
04178         // get node type
04179         PRUint16 nodeType;
04180         leftOvers->GetNodeType(&nodeType);
04181 
04182         // if not an element node, skip
04183         if (nodeType != nsIDOMNode::ELEMENT_NODE) {
04184           rv = leftOvers->GetNextSibling(getter_AddRefs(tmpNode));
04185           NS_ENSURE_SUCCESS(rv, rv);
04186           leftOvers = tmpNode;
04187           continue;
04188         }
04189 
04190         // use localname since SchemaLoader has already resolved all namespace
04191         // references for us.
04192         leftOvers->GetLocalName(nodeName);
04193         rv = aSchemaParticle->GetName(particleName);
04194         NS_ENSURE_SUCCESS(rv, rv);
04195 
04196         if (nodeName.Equals(particleName)) {
04197           LOG(("<%s>", NS_ConvertUTF16toUTF8(nodeName).get()));
04198           rv = ValidateComplexElement(leftOvers, aSchemaParticle, &isValid);
04199           NS_ENSURE_SUCCESS(rv, rv);
04200           LOG(("</%s> (Valid = %s)",
04201               NS_ConvertUTF16toUTF8(nodeName).get(),
04202                                     (isValid ? "true" : "false")));
04203 
04204           // set rest to the next element if node is valid
04205           if (isValid) {
04206             rv = leftOvers->GetNextSibling(getter_AddRefs(tmpNode));
04207             NS_ENSURE_SUCCESS(rv, rv);
04208             leftOvers = tmpNode;
04209           }
04210 
04211           iterations++;
04212           done = !isValid;
04213         } else {
04214           done = PR_TRUE;
04215         }
04216       }
04217 
04218       // optional and not found, so ok
04219       if (!isValid && (iterations == 0) && (minOccurs == 0)) {
04220         isValid = PR_TRUE;
04221       } else if ((iterations > 0) && (iterations < minOccurs)) {
04222         // we stopped finding the element, but haven't met the minOccurs
04223         isValid = PR_FALSE;
04224         LOG(("            -- Unexpected Node Found (%s), was expecting %s",
04225           NS_ConvertUTF16toUTF8(nodeName).get(),
04226           NS_ConvertUTF16toUTF8(particleName).get()));
04227       }
04228 
04229       notFound = (iterations == 0);
04230       break;
04231     }
04232 
04233     case nsISchemaParticle::PARTICLE_TYPE_MODEL_GROUP: {
04234       LOG(("            -- Particle is an Model Group"));
04235       nsCOMPtr<nsISchemaModelGroup> modelGroup =
04236         do_QueryInterface(aSchemaParticle);
04237 
04238       rv = ValidateComplexModelGroup(aNode, modelGroup,
04239                                      getter_AddRefs(leftOvers), &isValid);
04240       break;
04241     }
04242 
04243     case nsISchemaParticle::PARTICLE_TYPE_ANY:
04244       return Validate(aNode, aResult);
04245   }
04246 
04247   leftOvers.swap(*aLeftOvers);
04248   *aNotFound = notFound;
04249   *aResult = isValid;
04250   return rv;
04251 }
04252 
04253 nsresult
04254 nsSchemaValidator::GetElementXsiType(nsIDOMNode*     aNode,
04255                                      nsISchemaType** aType)
04256 {
04257 
04258   nsCOMPtr<nsIDOMElement> domElement = do_QueryInterface(aNode);
04259   NS_ENSURE_STATE(domElement);
04260 
04261   PRBool hasTypeAttribute = PR_FALSE;
04262   nsresult rv = domElement->HasAttributeNS(NS_LITERAL_STRING(
04263                                              NS_SCHEMA_INSTANCE_NAMESPACE),
04264                                            NS_LITERAL_STRING("type"),
04265                                            &hasTypeAttribute);
04266   NS_ENSURE_SUCCESS(rv, rv);
04267 
04268   /* XXX: This all may need to change when
04269      element.GetSchemaTypeInfo() is implemented from DOM Level 3 Core,
04270      see:
04271      http://www.w3.org/TR/DOM-Level-3-Core/core.html#Attr-schemaTypeInfo
04272   */
04273 
04274   if (hasTypeAttribute) {
04275     LOG(("  -- found xsi:type attribute"));
04276 
04277     nsAutoString typeAttribute;
04278     rv = domElement->GetAttributeNS(NS_LITERAL_STRING(
04279                                       NS_SCHEMA_INSTANCE_NAMESPACE),
04280                                     NS_LITERAL_STRING("type"),
04281                                     typeAttribute);
04282     NS_ENSURE_SUCCESS(rv, rv);
04283     LOG(("  Type is: %s", NS_ConvertUTF16toUTF8(typeAttribute).get()));
04284 
04285     if (typeAttribute.IsEmpty())
04286       return NS_ERROR_SCHEMAVALIDATOR_NO_TYPE_FOUND;
04287 
04288     // split type (ns:type) into namespace and type.
04289     nsCOMPtr<nsIParserService> parserService =
04290       do_GetService("@mozilla.org/parser/parser-service;1", &rv);
04291     NS_ENSURE_SUCCESS(rv, rv);
04292 
04293     const nsAFlatString& qName = PromiseFlatString(typeAttribute);
04294     const PRUnichar *colon;
04295     rv = parserService->CheckQName(qName, PR_TRUE, &colon);
04296     NS_ENSURE_SUCCESS(rv, rv);
04297 
04298     const PRUnichar* end;
04299     qName.EndReading(end);
04300 
04301     nsAutoString schemaTypePrefix, schemaType, schemaTypeNamespace;
04302     if (!colon) {
04303       // colon not found, so no prefix
04304       schemaType.Assign(typeAttribute);
04305 
04306       // get namespace from node
04307       aNode->GetNamespaceURI(schemaTypeNamespace);
04308     } else {
04309       schemaTypePrefix.Assign(Substring(qName.get(), colon));
04310       schemaType.Assign(Substring(colon + 1, end));
04311 
04312       // get the namespace url from the prefix
04313       nsCOMPtr<nsIDOM3Node> domNode3 = do_QueryInterface(aNode);
04314       rv = domNode3->LookupNamespaceURI(schemaTypePrefix, schemaTypeNamespace);
04315       NS_ENSURE_SUCCESS(rv, rv);
04316     }
04317 
04318     LOG(("  Type to validate against is %s:%s",
04319       NS_LossyConvertUTF16toASCII(schemaTypePrefix).get(),
04320       NS_LossyConvertUTF16toASCII(schemaType).get()));
04321 
04322     // no schemas loaded and type is not builtin, abort
04323     if (!mSchema &&
04324         !schemaTypeNamespace.EqualsLiteral(NS_SCHEMA_1999_NAMESPACE) &&
04325         !schemaTypeNamespace.EqualsLiteral(NS_SCHEMA_2001_NAMESPACE))
04326       return NS_ERROR_SCHEMAVALIDATOR_NO_SCHEMA_LOADED;
04327 
04328     // get the type
04329     rv = GetType(schemaType, schemaTypeNamespace, aType);
04330     NS_ENSURE_SUCCESS(rv, rv);
04331   }
04332 
04333   return rv;
04334 }
04335 
04336 nsresult
04337 nsSchemaValidator::ValidateComplexElement(nsIDOMNode* aNode,
04338                                           nsISchemaParticle *aSchemaParticle,
04339                                           PRBool *aResult)
04340 {
04341   PRBool isValid = PR_FALSE;
04342 
04343   nsCOMPtr<nsISchemaElement> schemaElement(do_QueryInterface(aSchemaParticle));
04344 
04345   if (!schemaElement)
04346     return NS_ERROR_UNEXPECTED;
04347 
04348   // will hold the type to validate against
04349   nsCOMPtr<nsISchemaType> type;
04350 
04351   nsresult rv = GetElementXsiType(aNode, getter_AddRefs(type));
04352   NS_ENSURE_SUCCESS(rv, rv);
04353 
04354   if (!type) {
04355     rv = schemaElement->GetType(getter_AddRefs(type));
04356     NS_ENSURE_SUCCESS(rv, rv);
04357 
04358     if (!type)
04359       return NS_ERROR_UNEXPECTED;
04360   }
04361 
04362   PRUint16 typeValue;
04363   rv = type->GetSchemaType(&typeValue);
04364   NS_ENSURE_SUCCESS(rv, rv);
04365 
04366   switch(typeValue) {
04367     case nsISchemaType::SCHEMA_TYPE_SIMPLE: {
04368       nsCOMPtr<nsISchemaSimpleType> simpleType(do_QueryInterface(type));
04369       if (simpleType) {
04370         LOG(("  Element is a simple type!"));
04371         rv = ValidateAgainstType(aNode, simpleType, &isValid);
04372       }
04373       break;
04374     }
04375 
04376     case nsISchemaType::SCHEMA_TYPE_COMPLEX: {
04377       nsCOMPtr<nsISchemaComplexType> complexType(do_QueryInterface(type));
04378       if (complexType) {
04379         LOG(("  Element is a complex type!"));
04380         rv = ValidateAgainstType(aNode, complexType, &isValid);
04381       }
04382       break;
04383     }
04384 
04385     case nsISchemaType::SCHEMA_TYPE_PLACEHOLDER: {
04386       rv = NS_ERROR_NOT_IMPLEMENTED;
04387       break;
04388     }
04389   }
04390 
04391   *aResult = isValid;
04392   return rv;
04393 }
04394 
04395 nsresult
04396 nsSchemaValidator::ValidateComplexChoice(nsIDOMNode* aStartNode,
04397                                          nsISchemaModelGroup *aSchemaModelGroup,
04398                                          nsIDOMNode **aLeftOvers,
04399                                          PRBool *aNotFound, PRBool *aResult)
04400 {
04401   // get the model group details
04402   PRUint32 minOccurs;
04403   nsresult rv = aSchemaModelGroup->GetMinOccurs(&minOccurs);
04404   NS_ENSURE_SUCCESS(rv, rv);
04405 
04406   PRUint32 maxOccurs;
04407   rv = aSchemaModelGroup->GetMaxOccurs(&maxOccurs);
04408   NS_ENSURE_SUCCESS(rv, rv);
04409 
04410   PRUint32 particleCount;
04411   rv = aSchemaModelGroup->GetParticleCount(&particleCount);
04412   NS_ENSURE_SUCCESS(rv, rv);
04413 
04414   nsCOMPtr<nsIDOMNodeList> nodeList;
04415   aStartNode->GetChildNodes(getter_AddRefs(nodeList));
04416   NS_ENSURE_SUCCESS(rv, rv);
04417 
04418   if (!nodeList)
04419     return NS_ERROR_UNEXPECTED;
04420 
04421   PRUint32 childNodesLength;
04422   rv = nodeList->GetLength(&childNodesLength);
04423   NS_ENSURE_SUCCESS(rv, rv);
04424 
04425   /*
04426     xsd:choice means one of the particles must validate.
04427   */
04428   PRBool isValid = PR_FALSE;
04429   PRBool notFound = PR_FALSE;
04430   nsCOMPtr<nsISchemaParticle> particle;
04431   nsCOMPtr<nsIDOMNode> currentNode(aStartNode), leftOvers, tmpNode;
04432   nsAutoString localName, particleName;
04433   PRUint32 particleCounter = 0;
04434 
04435   LOG(("======================== New Choice ==============================="));
04436 
04437   while (!isValid && currentNode && (particleCounter < particleCount)) {
04438     // get node type
04439     PRUint16 nodeType;
04440     currentNode->GetNodeType(&nodeType);
04441 
04442     // if not an element node, skip
04443     if (nodeType != nsIDOMNode::ELEMENT_NODE) {
04444       currentNode->GetNextSibling(getter_AddRefs(tmpNode));
04445       currentNode = tmpNode;
04446       continue;
04447     }
04448 
04449     // get the particle
04450     rv = aSchemaModelGroup->GetParticle(particleCounter, getter_AddRefs(particle));
04451     NS_ENSURE_SUCCESS(rv, rv);
04452 
04453     particle->GetName(particleName);
04454     currentNode->GetLocalName(localName);
04455 
04456     // if the particle has no name (so not an xsd:element) or the name matches
04457     // the node's localname, then we should try to validate.
04458     if (particleName.IsEmpty() || localName.Equals(particleName)) {
04459       rv = ValidateComplexParticle(currentNode, particle,
04460                                    getter_AddRefs(leftOvers), &notFound,
04461                                    &isValid);
04462 
04463       // if not valid and the names matched, we can bail early
04464       if (!isValid && localName.Equals(particleName)) {
04465         // The schema spec says that you can't have 2 particles with the same name,
04466         // so we know we don't have to continue looking for matching particles.
04467         LOG(("  Invalid: We found a matching particle, but it did not validate"));
04468         break;
04469       }
04470 
04471       currentNode = leftOvers;
04472     }
04473 
04474     particleCounter++;
04475   }
04476 
04477   if (!isValid) {
04478     // None of the particles managed to validate.
04479     notFound = PR_TRUE;
04480   }
04481 
04482   // make sure aLeftOvers points to null or an element node
04483   nsSchemaValidatorUtils::SetToNullOrElement(currentNode, aLeftOvers);
04484 
04485   *aNotFound = notFound;
04486   *aResult = isValid;
04487 
04488   return rv;
04489 }
04490 
04491 nsresult
04492 nsSchemaValidator::ValidateComplexAll(nsIDOMNode* aStartNode,
04493                                       nsISchemaModelGroup *aSchemaModelGroup,
04494                                       nsIDOMNode **aLeftOvers, PRBool *aNotFound,
04495                                       PRBool *aResult)
04496 {
04497   if (!aStartNode || !aSchemaModelGroup)
04498     return NS_ERROR_UNEXPECTED;
04499 
04500   // get the model group details
04501   PRUint32 minOccurs;
04502   nsresult rv = aSchemaModelGroup->GetMinOccurs(&minOccurs);
04503   NS_ENSURE_SUCCESS(rv, rv);
04504 
04505   PRUint32 maxOccurs;
04506   rv = aSchemaModelGroup->GetMaxOccurs(&maxOccurs);
04507   NS_ENSURE_SUCCESS(rv, rv);
04508 
04509   PRUint32 particleCount;
04510   rv = aSchemaModelGroup->GetParticleCount(&particleCount);
04511   NS_ENSURE_SUCCESS(rv, rv);
04512 
04513   // since xsd:all does not care about order, we need to record how often each
04514   // particle was hit
04515   nsDataHashtable<nsISupportsHashKey,PRUint32> particleHits;
04516   if (!particleHits.Init())
04517     return NS_ERROR_OUT_OF_MEMORY;
04518 
04519   // xsd:all means that the order of the particles does not matter, and
04520   // that particles can only occur 0 or 1 time
04521   PRBool isValid = PR_FALSE;
04522   PRBool notFound = PR_FALSE;
04523   PRBool done = PR_FALSE;
04524   nsCOMPtr<nsISchemaParticle> particle;
04525   nsCOMPtr<nsIDOMNode> currentNode(aStartNode), leftOvers, tmpNode;
04526   nsAutoString localName, particleName;
04527 
04528   for (PRUint32 i = 0; i < particleCount; ++i) {
04529     rv = aSchemaModelGroup->GetParticle(i, getter_AddRefs(particle));
04530     NS_ENSURE_SUCCESS(rv, rv);
04531 
04532     particleHits.Put(particle, 0);
04533   }
04534 
04535   LOG(("====================== New All ==========================="));
04536 
04537   PRUint32 validatedNodes = 0;
04538 
04539   // we are done when we hit a node that doesn't fit our schema
04540   while (!done && currentNode) {
04541     // get node type
04542     PRUint16 nodeType;
04543     currentNode->GetNodeType(&nodeType);
04544     currentNode->GetLocalName(localName);
04545 
04546     // if not an element node, skip
04547     if (nodeType != nsIDOMNode::ELEMENT_NODE) {
04548       currentNode->GetNextSibling(getter_AddRefs(tmpNode));
04549       currentNode = tmpNode;
04550       continue;
04551     }
04552 
04553     LOG(("      - Validating element (%s)",
04554          NS_ConvertUTF16toUTF8(localName).get()));
04555 
04556     // walk all the particles until we find one that validates
04557     PRUint32 particleNum = 0;
04558     PRBool foundParticle = PR_FALSE;
04559 
04560     while (!foundParticle && particleNum < particleCount) {
04561       rv = aSchemaModelGroup->GetParticle(particleNum, getter_AddRefs(particle));
04562       NS_ENSURE_SUCCESS(rv, rv);
04563 
04564       particle->GetName(particleName);
04565 
04566       if (particleName.Equals(localName)) {
04567         // try to validate
04568         rv = ValidateComplexParticle(currentNode, particle,
04569                                      getter_AddRefs(leftOvers), &notFound,
04570                                      &foundParticle);
04571         NS_ENSURE_SUCCESS(rv, rv);
04572       }
04573 
04574       if (foundParticle) {
04575         validatedNodes++;
04576 
04577         PRUint32 hitCount = 0;
04578         particleHits.Get(particle, &hitCount);
04579 
04580         if (hitCount > 0) {
04581           // particles in an xsd:all can only occur a maximum of once.  If we hit
04582           // a particle twice, we finish this iteration and reset the leftover
04583           // to the currentNode.  We basically say this xsd:all is done, the current
04584           // node might be the start of another compositor (assuming all required
04585           // particles are hit
04586           foundParticle = PR_TRUE;
04587           leftOvers = currentNode;
04588           done = PR_TRUE;
04589           LOG(("        -- Particle (%s) occured more than once, so ending",
04590                NS_ConvertUTF16toUTF8(particleName).get()));
04591           break;
04592         } else {
04593           hitCount++;
04594           particleHits.Put(particle, hitCount);
04595           LOG(("        -- Element validated"));
04596         }
04597       } else {
04598         particleNum++;
04599       }
04600     }
04601 
04602     // set isvalid
04603     isValid = foundParticle;
04604 
04605     if (!isValid) {
04606       done = PR_TRUE;
04607       LOG(("        -- Element could not be validated!"));
04608     }
04609 
04610     currentNode = leftOvers;
04611   }
04612 
04613   if (validatedNodes == 0) {
04614     // we didn't walk through any nodes, thus empty sequence.  The caller
04615     // will check if enough occurances (minOccurs) happened.
04616     isValid = PR_TRUE;
04617     notFound = PR_TRUE;
04618   } else {
04619     // check if any of the particles didn't occur enough.  We already checked
04620     // if a particle is hit more than once
04621     PRUint32 hits = 0;
04622     PRUint32 particleMinOccurs, particleMaxOccurs;
04623 
04624     for (PRUint32 i = 0; i < particleCount; ++i) {
04625       rv = aSchemaModelGroup->GetParticle(i, getter_AddRefs(particle));
04626       NS_ENSURE_SUCCESS(rv, rv);
04627 
04628       // we assume the schema is valid and min/max is not larger that 1
04629       particle->GetMinOccurs(&particleMinOccurs);
04630       particle->GetMaxOccurs(&particleMaxOccurs);
04631       particleHits.Get(particle, &hits);
04632 
04633       if (hits < particleMinOccurs || hits > particleMaxOccurs) {
04634         isValid = PR_FALSE;
04635 
04636         particle->GetName(particleName);
04637         LOG(("      - Particle (%s) occured %d times, but should have occured [%d, %d] times",
04638           NS_ConvertUTF16toUTF8(particleName).get(), hits, particleMinOccurs,
04639           particleMaxOccurs));
04640         break;
04641       }
04642     }
04643   }
04644 
04645   // make sure aLeftOvers points to null or an element node
04646   nsSchemaValidatorUtils::SetToNullOrElement(currentNode, aLeftOvers);
04647 
04648   *aNotFound = notFound;
04649   *aResult = isValid;
04650   return rv;
04651 }
04652 
04653 nsresult
04654 nsSchemaValidator::ValidateAttributeComponent(nsIDOMNode* aNode,
04655                                               nsISchemaAttributeComponent *aAttrComp,
04656                                               PRUint32 *aFoundAttrCount,
04657                                               PRBool *aResult)
04658 {
04659   PRBool isValid = PR_FALSE;
04660 
04661   PRUint16 componentType;
04662   nsresult rv = aAttrComp->GetComponentType(&componentType);
04663   NS_ENSURE_SUCCESS(rv, rv);
04664 
04665   nsAutoString name;
04666   rv = aAttrComp->GetName(name);
04667   NS_ENSURE_SUCCESS(rv, rv);
04668 
04669   switch(componentType) {
04670     case nsISchemaAttributeComponent::COMPONENT_TYPE_ATTRIBUTE: {
04671       nsCOMPtr<nsISchemaAttribute> attr(do_QueryInterface(aAttrComp, &rv));
04672       NS_ENSURE_SUCCESS(rv, rv);
04673 
04674       LOG(("      Attribute Component (%s) is an attribute!",
04675            NS_ConvertUTF16toUTF8(name).get()));
04676 
04677       rv = ValidateSchemaAttribute(aNode, attr, name, aFoundAttrCount, &isValid);
04678       NS_ENSURE_SUCCESS(rv, rv);
04679 
04680       break;
04681     }
04682 
04683     case nsISchemaAttributeComponent::COMPONENT_TYPE_GROUP: {
04684       nsCOMPtr<nsISchemaAttributeGroup> attrGroup(do_QueryInterface(aAttrComp, &rv));
04685       NS_ENSURE_SUCCESS(rv, rv);
04686 
04687       LOG(("      Attribute Component (%s) is an attribute group!",
04688            NS_ConvertUTF16toUTF8(name).get()));
04689 
04690       rv = ValidateSchemaAttributeGroup(aNode, attrGroup, name, aFoundAttrCount,
04691                                         &isValid);
04692       NS_ENSURE_SUCCESS(rv, rv);
04693 
04694       break;
04695     }
04696 
04697     case nsISchemaAttributeComponent::COMPONENT_TYPE_ANY: {
04698       // for now we just accept this one as being valid.
04699       // should look at the attribute namespace and validate the
04700       // attribute against it
04701       // XXX: implement this
04702       isValid = PR_TRUE;
04703       break;
04704     }
04705   }
04706 
04707   *aResult = isValid;
04708   return rv;
04709 }
04710 
04711 nsresult
04712 nsSchemaValidator::ValidateSchemaAttribute(nsIDOMNode* aNode,
04713                                            nsISchemaAttribute *aAttr,
04714                                            const nsAString & aAttrName,
04715                                            PRUint32 *aFoundAttrCount,
04716                                            PRBool *aResult)
04717 {
04718   PRUint16 use;
04719   nsresult rv = aAttr->GetUse(&use);
04720   NS_ENSURE_SUCCESS(rv, rv);
04721 
04722   nsAutoString fixedValue, attrValue;
04723   rv = aAttr->GetFixedValue(fixedValue);
04724   NS_ENSURE_SUCCESS(rv, rv);
04725 
04726   nsCOMPtr<nsISchemaSimpleType> simpleType;
04727   rv = aAttr->GetType(getter_AddRefs(simpleType));
04728   NS_ENSURE_SUCCESS(rv, rv);
04729 
04730   nsCOMPtr<nsIDOMElement> elm(do_QueryInterface(aNode));
04731 
04732   PRBool hasAttr = PR_FALSE;
04733   PRBool isValid = PR_FALSE;
04734 
04735   // XXX: We don't know if the attribute needs to be qualified or not, since
04736   // nsISchema on the 1.8.0/1.8 branches doesn't support it.  So try both
04737   // options.
04738 
04739   nsAutoString targetNamespace;
04740   aAttr->GetTargetNamespace(targetNamespace);
04741 
04742   if (!targetNamespace.IsEmpty()) {
04743     rv = elm->HasAttributeNS(targetNamespace, aAttrName, &hasAttr);
04744     NS_ENSURE_SUCCESS(rv, rv);
04745 
04746     if (hasAttr) {
04747       rv = elm->GetAttributeNS(targetNamespace, aAttrName, attrValue);
04748       NS_ENSURE_SUCCESS(rv, rv);
04749     }
04750   } else {
04751     rv = elm->HasAttribute(aAttrName, &hasAttr);
04752     NS_ENSURE_SUCCESS(rv, rv);
04753 
04754     if (hasAttr) {
04755       rv = elm->GetAttribute(aAttrName, attrValue);
04756       NS_ENSURE_SUCCESS(rv, rv);
04757     }
04758   }
04759 
04760   if (!hasAttr) {
04761     rv = elm->HasAttribute(aAttrName, &hasAttr);
04762     NS_ENSURE_SUCCESS(rv, rv);
04763 
04764     if (hasAttr) {
04765       rv = elm->GetAttribute(aAttrName, attrValue);
04766       NS_ENSURE_SUCCESS(rv, rv);
04767     }
04768   }
04769 
04770   if (!hasAttr) {
04771     // no attribute found
04772     if (use == nsISchemaAttribute::USE_OPTIONAL) {
04773       isValid = PR_TRUE;
04774       LOG(("        -- attribute not found, but optional, so fine!"));
04775     } else if (use == nsISchemaAttribute::USE_REQUIRED) {
04776       // we default to invalid
04777       LOG(("        -- attribute not found, but required!"));
04778     } else if (use == nsISchemaAttribute::USE_PROHIBITED) {
04779       // prohibited and doesn't exist is valid
04780       isValid = PR_TRUE;
04781       LOG(("        -- attribute not found, but prohibited, so fine!"));
04782     }
04783   } else if (!fixedValue.IsEmpty()) {
04784     // XXX: what about default="" ?
04785     // we assume the default or fixed value is valid for now
04786     (*aFoundAttrCount)++;
04787 
04788     if (attrValue.Equals(fixedValue)) {
04789       LOG(("        -- attribute has fixed value and it equals the attribute value."));
04790       isValid = PR_TRUE;
04791     } else {
04792       LOG(("        -- attribute has fixed value, but does not equal the attribute value!"));
04793     }
04794   } else {
04795     (*aFoundAttrCount)++;
04796     if (use == nsISchemaAttribute::USE_PROHIBITED) {
04797       // If it is is prohibited and it exists, we don't have to do anything,
04798       // since we default to invalid.
04799       LOG(("        -- attribute prohibited!"));
04800     } else {
04801       if (simpleType) {
04802         // save the type on the attribute
04803         nsCOMPtr<nsIDOMAttr> attrNode;
04804 
04805         if (NS_SUCCEEDED(elm->GetAttributeNode(aAttrName,
04806                                                getter_AddRefs(attrNode)))) {
04807           nsCOMPtr<nsIWritableVariant> holder =
04808             do_CreateInstance("@mozilla.org/variant;1");
04809           NS_ENSURE_STATE(holder);
04810 
04811           holder->SetAsInterface(nsISchemaType::GetIID(), simpleType);
04812 
04813           // and save on the node
04814           nsCOMPtr<nsIAttribute> pAttribute(do_QueryInterface(attrNode));
04815 
04816           if (pAttribute) {
04817             // we have to be really careful to set the destructor function
04818             // correctly. this also has to be a pointer to a variant
04819             nsCOMPtr<nsIAtom> key = do_GetAtom("xsdtype");
04820             NS_ENSURE_TRUE(key, NS_ERROR_OUT_OF_MEMORY);
04821 
04822             nsIVariant *pVariant = holder;
04823             NS_IF_ADDREF(pVariant);
04824             rv = pAttribute->SetProperty(key, pVariant, &VariantDTor);
04825             NS_ENSURE_SUCCESS(rv, rv);
04826           }
04827         }
04828 
04829         rv = ValidateSimpletype(attrValue, simpleType, &isValid);
04830       } else {
04831        // If no type exists (ergo no simpleType), we should use the
04832         // simple ur-type definition defined at:
04833         // (http://www.w3.org/TR/xmlschema-1/#simple-ur-type-itself).
04834         // XXX: So for now, we default to true.
04835         isValid = PR_TRUE;
04836       }
04837     }
04838   }
04839 
04840   *aResult = isValid;
04841   return rv;
04842 }
04843 
04844 nsresult
04845 nsSchemaValidator::ValidateSchemaAttributeGroup(nsIDOMNode* aNode,
04846                                                 nsISchemaAttributeGroup *aAttrGroup,
04847                                                 const nsAString & aAttrName,
04848                                                 PRUint32 *aFoundAttrCount,
04849                                                 PRBool *aResult)
04850 {
04851   PRBool isValid = PR_TRUE;
04852   PRUint32 attrCount, count = 0;
04853 
04854   nsresult rv = aAttrGroup->GetAttributeCount(&attrCount);
04855   NS_ENSURE_SUCCESS(rv, rv);
04856 
04857   nsCOMPtr<nsISchemaAttributeComponent> attrComp;
04858 
04859   while (isValid && (count < attrCount)) {
04860     rv = aAttrGroup->GetAttributeByIndex(count, getter_AddRefs(attrComp));
04861     NS_ENSURE_SUCCESS(rv, rv);
04862 
04863     rv = ValidateAttributeComponent(aNode, attrComp, aFoundAttrCount,
04864                                     &isValid);
04865     NS_ENSURE_SUCCESS(rv, rv);
04866 
04867     ++count;
04868   }
04869 
04870   *aResult = isValid;
04871   return rv;
04872 }
04873