Macro adjustments, date/time class, typed XML attributes.
authorScott Cantor <cantor.2@osu.edu>
Mon, 8 May 2006 03:54:41 +0000 (03:54 +0000)
committerScott Cantor <cantor.2@osu.edu>
Mon, 8 May 2006 03:54:41 +0000 (03:54 +0000)
14 files changed:
xmltooling/AbstractXMLObject.cpp
xmltooling/AbstractXMLObject.h
xmltooling/Makefile.am
xmltooling/PluginManager.h
xmltooling/base.h
xmltooling/io/AbstractXMLObjectUnmarshaller.cpp
xmltooling/signature/KeyInfo.h
xmltooling/signature/Signature.h
xmltooling/signature/impl/KeyInfoImpl.cpp
xmltooling/signature/impl/KeyInfoSchemaValidators.cpp
xmltooling/signature/impl/XMLSecSignatureImpl.cpp
xmltooling/util/DateTime.cpp [new file with mode: 0644]
xmltooling/util/DateTime.h [new file with mode: 0644]
xmltooling/xmltooling.vcproj

index 23e563b..3111c8d 100644 (file)
@@ -60,6 +60,61 @@ XMLCh* AbstractXMLObject::prepareForAssignment(XMLCh* oldValue, const XMLCh* new
     return oldValue;            
 }
 
+QName* AbstractXMLObject::prepareForAssignment(QName* oldValue, const QName* newValue)
+{
+    if (!oldValue) {
+        if (newValue) {
+            releaseThisandParentDOM();
+            Namespace newNamespace(newValue->getNamespaceURI(), newValue->getPrefix());\r
+            addNamespace(newNamespace);\r
+            return new QName(*newValue);
+        }
+        return NULL;
+    }
+
+    delete oldValue;
+    releaseThisandParentDOM();
+    if (newValue) {
+        Namespace newNamespace(newValue->getNamespaceURI(), newValue->getPrefix());\r
+        addNamespace(newNamespace);\r
+        return new QName(*newValue);\r
+    }
+    return NULL;
+}
+
+DateTime* AbstractXMLObject::prepareForAssignment(DateTime* oldValue, const DateTime* newValue)
+{
+    if (!oldValue) {
+        if (newValue) {
+            releaseThisandParentDOM();
+            return new DateTime(*newValue);
+        }
+        return NULL;
+    }
+
+    delete oldValue;
+    releaseThisandParentDOM();
+    return newValue ? new DateTime(*newValue) : NULL;
+}
+
+DateTime* AbstractXMLObject::prepareForAssignment(DateTime* oldValue, time_t newValue)
+{
+    delete oldValue;
+    releaseThisandParentDOM();
+    DateTime* ret = new DateTime(newValue);
+    ret->parseDateTime();
+    return ret;
+}
+
+DateTime* AbstractXMLObject::prepareForAssignment(DateTime* oldValue, const XMLCh* newValue)
+{
+    delete oldValue;
+    releaseThisandParentDOM();
+    DateTime* ret = new DateTime(newValue);
+    ret->parseDateTime();
+    return ret;
+}
+
 XMLObject* AbstractXMLObject::prepareForAssignment(XMLObject* oldValue, XMLObject* newValue)
 {
     if (newValue && newValue->hasParent())
index 5ead42f..ba34176 100644 (file)
@@ -24,6 +24,7 @@
 #define __xmltooling_abstractxmlobj_h__\r
 \r
 #include <xmltooling/XMLObject.h>\r
+#include <xmltooling/util/DateTime.h>\r
 \r
 #if defined (_MSC_VER)\r
     #pragma warning( push )\r
@@ -97,9 +98,10 @@ namespace xmltooling {
         AbstractXMLObject(const AbstractXMLObject& src);\r
         \r
         /**\r
-         * A helper function for derived classes.\r
+         * A helper function for derived classes, for assignment of strings.\r
+         *\r
          * This 'normalizes' newString, and then if it is different from oldString,\r
-         * it invalidates the DOM, frees the old string, and return the new.\r
+         * it invalidates the DOM, frees the old string, and returns the new.\r
          * If not different, it frees the new string and just returns the old value.\r
          * \r
          * @param oldValue - the current value\r
@@ -110,6 +112,54 @@ namespace xmltooling {
         XMLCh* prepareForAssignment(XMLCh* oldValue, const XMLCh* newValue);\r
 \r
         /**\r
+         * A helper function for derived classes, for assignment of date/time data.\r
+         *\r
+         * It invalidates the DOM, frees the old object, and returns the new.\r
+         * \r
+         * @param oldValue - the current value\r
+         * @param newValue - the new value\r
+         * \r
+         * @return the value that should be assigned\r
+         */\r
+        DateTime* prepareForAssignment(DateTime* oldValue, const DateTime* newValue);\r
+\r
+        /**\r
+         * A helper function for derived classes, for assignment of date/time data.\r
+         *\r
+         * It invalidates the DOM, frees the old object, and returns the new.\r
+         * \r
+         * @param oldValue - the current value\r
+         * @param newValue - the epoch to assign as the new value\r
+         * \r
+         * @return the value that should be assigned\r
+         */\r
+        DateTime* prepareForAssignment(DateTime* oldValue, time_t newValue);\r
+\r
+        /**\r
+         * A helper function for derived classes, for assignment of date/time data.\r
+         *\r
+         * It invalidates the DOM, frees the old object, and returns the new.\r
+         * \r
+         * @param oldValue - the current value\r
+         * @param newValue - the new value in string form\r
+         * \r
+         * @return the value that should be assigned\r
+         */\r
+        DateTime* prepareForAssignment(DateTime* oldValue, const XMLCh* newValue);\r
+\r
+        /**\r
+         * A helper function for derived classes, for assignment of QName data.\r
+         *\r
+         * It invalidates the DOM, frees the old object, and returns the new.\r
+         * \r
+         * @param oldValue - the current value\r
+         * @param newValue - the new value\r
+         * \r
+         * @return the value that should be assigned\r
+         */\r
+        QName* prepareForAssignment(QName* oldValue, const QName* newValue);\r
+\r
+        /**\r
          * A helper function for derived classes, for assignment of (singleton) XML objects.\r
          * \r
          * It is indifferent to whether either the old or the new version of the value is null. \r
index 17b0d43..044e60b 100644 (file)
@@ -53,6 +53,7 @@ siginclude_HEADERS = \
     signature/VerifyingContext.h
 
 utilinclude_HEADERS = \
+    util/DateTime.h \
     util/NDC.h \
     util/ParserPool.h \
     util/XMLConstants.h \
@@ -92,6 +93,7 @@ libxmltooling_la_SOURCES = \
     io/AbstractXMLObjectUnmarshaller.cpp \
     signature/impl/KeyInfoImpl.cpp \
     signature/impl/KeyInfoSchemaValidators.cpp \
+    util/DateTime.cpp \
     util/NDC.cpp \
     util/ParserPool.cpp \
     util/XMLConstants.cpp \
index d876cce..3c76be4 100644 (file)
 \r
 #include <map>\r
 #include <string>\r
-#include <xercesc/dom/DOM.hpp>\r
 \r
-using namespace xercesc;\r
+#if defined (_MSC_VER)\r
+    #pragma warning( push )\r
+    #pragma warning( disable : 4250 4251 )\r
+#endif\r
 \r
 namespace xmltooling {\r
 \r
@@ -73,7 +75,7 @@ namespace xmltooling {
 \r
         /**\r
          * Builds a new instance of a plugin of a given type, configuring it\r
-         * with the supplied element, if any.\r
+         * with the supplied parameters.\r
          * \r
          * @param type  the name of the plugin type\r
          * @param p     parameters to configure plugin\r
@@ -92,4 +94,8 @@ namespace xmltooling {
 \r
 };\r
 \r
+#if defined (_MSC_VER)\r
+    #pragma warning( pop )\r
+#endif\r
+\r
 #endif /* __xmltooling_plugin_h__ */\r
index f9e81db..89320f2 100644 (file)
 #define END_XMLOBJECT }
 
 /**
- * Declares abstract get/set methods for a named XML attribute.
+ * Declares abstract get/set methods for a typed XML attribute.
  * 
  * @param proper    the proper name of the attribute
  * @param upcased   the upcased name of the attribute
+ * @param type      the attribute's data type
  */
-#define DECL_XMLOBJECT_ATTRIB(proper,upcased) \
+#define DECL_XMLOBJECT_ATTRIB(proper,upcased,type) \
     public: \
         XMLTOOLING_DOXYGEN(proper attribute name) \
         static const XMLCh upcased##_ATTRIB_NAME[]; \
         XMLTOOLING_DOXYGEN(Returns the proper attribute.) \
-        virtual const XMLCh* get##proper() const=0; \
+        virtual const type* get##proper() const=0; \
         XMLTOOLING_DOXYGEN(Sets the proper attribute.) \
-        virtual void set##proper(const XMLCh* proper)=0
+        virtual void set##proper(const type* proper)=0
 
 /**
- * Implements get/set methods and a private member for a named XML attribute.
+ * Declares abstract get/set methods for a string XML attribute.
  * 
  * @param proper    the proper name of the attribute
+ * @param upcased   the upcased name of the attribute
  */
-#define IMPL_XMLOBJECT_ATTRIB(proper) \
-    private: \
-        XMLCh* m_##proper; \
+#define DECL_STRING_ATTRIB(proper,upcased) \
+    DECL_XMLOBJECT_ATTRIB(proper,upcased,XMLCh)
+
+/**
+ * Declares abstract get/set methods for a string XML attribute.
+ * 
+ * @param proper    the proper name of the attribute
+ * @param upcased   the upcased name of the attribute
+ */
+#define DECL_DATETIME_ATTRIB(proper,upcased) \
+    DECL_XMLOBJECT_ATTRIB(proper,upcased,xmltooling::DateTime); \
+    XMLTOOLING_DOXYGEN(Sets the proper attribute.) \
+    virtual void set##proper(time_t proper)=0; \
+    XMLTOOLING_DOXYGEN(Sets the proper attribute.) \
+    virtual void set##proper(const XMLCh* proper)=0
+
+/**
+ * Declares abstract get/set methods for an integer XML attribute.
+ * 
+ * @param proper    the proper name of the attribute
+ * @param upcased   the upcased name of the attribute
+ */
+#define DECL_INTEGER_ATTRIB(proper,upcased) \
+    public: \
+        XMLTOOLING_DOXYGEN(proper attribute name) \
+        static const XMLCh upcased##_ATTRIB_NAME[]; \
+        XMLTOOLING_DOXYGEN(Returns the proper attribute.) \
+        virtual int get##proper() const=0; \
+        XMLTOOLING_DOXYGEN(Sets the proper attribute.) \
+        virtual void set##proper(int proper)=0
+
+/**
+ * Implements get/set methods and a private member for a typed XML attribute.
+ * 
+ * @param proper    the proper name of the attribute
+ * @param type      the attribute's data type
+ */
+#define IMPL_XMLOBJECT_ATTRIB(proper,type) \
+    protected: \
+        type* m_##proper; \
     public: \
-        const XMLCh* get##proper() const { \
+        const type* get##proper() const { \
             return m_##proper; \
         } \
-        void set##proper(const XMLCh* proper) { \
+        void set##proper(const type* proper) { \
             m_##proper = prepareForAssignment(m_##proper,proper); \
         }
 
 /**
+ * Implements get/set methods and a private member for a string XML attribute.
+ * 
+ * @param proper    the proper name of the attribute
+ */
+#define IMPL_STRING_ATTRIB(proper) \
+    IMPL_XMLOBJECT_ATTRIB(proper,XMLCh)
+
+/**
+ * Implements get/set methods and a private member for a DateTime XML attribute.
+ * 
+ * @param proper    the proper name of the attribute
+ */
+#define IMPL_DATETIME_ATTRIB(proper) \
+    IMPL_XMLOBJECT_ATTRIB(proper,xmltooling::DateTime); \
+    void set##proper(time_t proper) { \
+        m_##proper = prepareForAssignment(m_##proper,proper); \
+    } \
+    void set##proper(const XMLCh* proper) { \
+        m_##proper = prepareForAssignment(m_##proper,proper); \
+    }
+
+/**
+ * Implements get/set methods and a private member for an integer XML attribute.
+ * 
+ * @param proper    the proper name of the attribute
+ */
+#define IMPL_INTEGER_ATTRIB(proper) \
+    protected: \
+        int m_##proper; \
+    public: \
+        int get##proper() const { \
+            return m_##proper; \
+        } \
+        void set##proper(int proper) { \
+            if (m_##proper != proper) { \
+                releaseThisandParentDOM(); \
+                m_##proper = proper; \
+            } \
+        }
+
+/**
+ * Declares abstract get/set methods for a typed XML child object in a foreign namespace.
+ * 
+ * @param proper    the proper name of the child type
+ * @param ns        the C++ namespace for the type
+ */
+#define DECL_TYPED_FOREIGN_CHILD(proper,ns) \
+    public: \
+        XMLTOOLING_DOXYGEN(Returns the proper child.) \
+        virtual ns::proper* get##proper() const=0; \
+        XMLTOOLING_DOXYGEN(Sets the proper child.) \
+        virtual void set##proper(ns::proper* child)=0
+
+/**
  * Declares abstract get/set methods for a typed XML child object.
  * 
  * @param proper    the proper name of the child type
  */
-#define DECL_XMLOBJECT_CHILD(proper) \
+#define DECL_TYPED_CHILD(proper) \
     public: \
         XMLTOOLING_DOXYGEN(Returns the proper child.) \
         virtual proper* get##proper() const=0; \
         virtual void set##proper(proper* child)=0
 
 /**
+ * Declares abstract get/set methods for a generic XML child object.
+ * 
+ * @param proper    the proper name of the child
+ */
+#define DECL_XMLOBJECT_CHILD(proper) \
+    public: \
+        XMLTOOLING_DOXYGEN(Returns the proper child.) \
+        virtual xmltooling::XMLObject* get##proper() const=0; \
+        XMLTOOLING_DOXYGEN(Sets the proper child.) \
+        virtual void set##proper(xmltooling::XMLObject* child)=0
+
+
+/**
  * Implements get/set methods and a private list iterator member for a typed XML child object.
  * 
  * @param proper    the proper name of the child type
  */
-#define IMPL_XMLOBJECT_CHILD(proper) \
-    private: \
+#define IMPL_TYPED_CHILD(proper) \
+    protected: \
         proper* m_##proper; \
-        std::list<XMLObject*>::iterator m_pos_##proper; \
+        std::list<xmltooling::XMLObject*>::iterator m_pos_##proper; \
     public: \
         proper* get##proper() const { \
             return m_##proper; \
         }
 
 /**
+ * Implements get/set methods and a private list iterator member for a generic XML child object.
+ * 
+ * @param proper    the proper name of the child
+ */
+#define IMPL_XMLOBJECT_CHILD(proper) \
+    protected: \
+        xmltooling::XMLObject* m_##proper; \
+        std::list<xmltooling::XMLObject*>::iterator m_pos_##proper; \
+    public: \
+        xmltooling::XMLObject* get##proper() const { \
+            return m_##proper; \
+        } \
+        void set##proper(xmltooling::XMLObject* child) { \
+            prepareForAssignment(m_##proper,child); \
+            *m_pos_##proper = m_##proper = child; \
+        }
+
+/**
  * Declares abstract get/set methods for a typed XML child collection.
  * 
  * @param proper    the proper name of the child type
  */
-#define DECL_XMLOBJECT_CHILDREN(proper) \
+#define DECL_TYPED_CHILDREN(proper) \
     public: \
         XMLTOOLING_DOXYGEN(Returns modifiable proper collection.) \
         virtual VectorOf(proper) get##proper##s()=0; \
         virtual const std::vector<proper*>& get##proper##s() const=0
 
 /**
+ * Declares abstract get/set methods for a generic XML child collection.
+ * 
+ * @param proper    the proper name of the child
+ */
+#define DECL_XMLOBJECT_CHILDREN(proper) \
+    public: \
+        XMLTOOLING_DOXYGEN(Returns modifiable proper collection.) \
+        virtual VectorOf(xmltooling::XMLObject) get##proper##s()=0; \
+        XMLTOOLING_DOXYGEN(Returns reference to immutable proper collection.) \
+        virtual const std::vector<xmltooling::XMLObject*>& get##proper##s() const=0
+
+/**
  * Implements get method and a private vector member for a typed XML child collection.
  * 
  * @param proper    the proper name of the child type
  * @param fence     insertion fence for new objects of the child collection in backing list
  */
-#define IMPL_XMLOBJECT_CHILDREN(proper,fence) \
-    private: \
+#define IMPL_TYPED_CHILDREN(proper,fence) \
+    protected: \
         std::vector<proper*> m_##proper##s; \
     public: \
         VectorOf(proper) get##proper##s() { \
         } 
 
 /**
- * Implements marshalling for an attribute
+ * Implements get method and a private vector member for a generic XML child collection.
+ * 
+ * @param proper    the proper name of the child
+ * @param fence     insertion fence for new objects of the child collection in backing list
+ */
+#define IMPL_XMLOBJECT_CHILDREN(proper,fence) \
+    protected: \
+        std::vector<xmltooling::XMLObject*> m_##proper##s; \
+    public: \
+        VectorOf(xmltooling::XMLObject) get##proper##s() { \
+            return VectorOf(xmltooling::XMLObject)(this, m_##proper##s, &m_children, fence); \
+        } \
+        const std::vector<xmltooling::XMLObject*>& get##proper##s() const { \
+            return m_##proper##s; \
+        } 
+
+/**
+ * Implements marshalling for a string attribute
  * 
  * @param proper        the proper name of the attribute
  * @param ucase         the upcased name of the attribute
  * @param namespaceURI  the XML namespace of the attribute
  */
-#define MARSHALL_XMLOBJECT_ATTRIB(proper,ucase,namespaceURI) \
+#define MARSHALL_STRING_ATTRIB(proper,ucase,namespaceURI) \
     if(get##proper()) { \
         domElement->setAttributeNS(namespaceURI, ucase##_ATTRIB_NAME, get##proper()); \
     }
 
 /**
+ * Implements marshalling for a DateTime attribute
+ * 
+ * @param proper        the proper name of the attribute
+ * @param ucase         the upcased name of the attribute
+ * @param namespaceURI  the XML namespace of the attribute
+ */
+#define MARSHALL_DATETIME_ATTRIB(proper,ucase,namespaceURI) \
+    if(get##proper()) { \
+        domElement->setAttributeNS(namespaceURI, ucase##_ATTRIB_NAME, get##proper()->getRawData()); \
+    }
+
+/**
+ * Implements marshalling for an integer attribute
+ * 
+ * @param proper        the proper name of the attribute
+ * @param ucase         the upcased name of the attribute
+ * @param namespaceURI  the XML namespace of the attribute
+ */
+#define MARSHALL_INTEGER_ATTRIB(proper,ucase,namespaceURI) \
+    char buf##proper[64]; \
+    sprintf(buf##proper,"%d",get##proper()); \
+    auto_ptr_XMLCh wide##proper(buf##proper); \
+    domElement->setAttributeNS(namespaceURI, ucase##_ATTRIB_NAME, wide##proper.get())
+
+/**
+ * Implements marshalling for a QName attribute
+ * 
+ * @param proper        the proper name of the attribute
+ * @param ucase         the upcased name of the attribute
+ * @param namespaceURI  the XML namespace of the attribute
+ */
+#define MARSHALL_QNAME_ATTRIB(proper,ucase,namespaceURI) \
+    if(get##proper()) { \
+        auto_ptr_XMLCh qstr(get##proper()->toString().c_str()); \
+        domElement->setAttributeNS(namespaceURI, ucase##_ATTRIB_NAME, qstr.get()); \
+    }
+
+/**
  * Implements marshalling for an ID attribute
  * 
  * @param proper        the proper name of the attribute
  * @param ucase         the upcased name of the attribute
  * @param namespaceURI  the XML namespace of the attribute
  */
-#define MARSHALL_XMLOBJECT_ID_ATTRIB(proper,ucase,namespaceURI) \
+#define MARSHALL_ID_ATTRIB(proper,ucase,namespaceURI) \
     if(get##proper()) { \
         domElement->setAttributeNS(namespaceURI, ucase##_ATTRIB_NAME, get##proper()); \
         domElement->setIdAttributeNS(namespaceURI, ucase##_ATTRIB_NAME); \
     }
 
 /**
- * Implements unmarshalling process branch for an attribute
+ * Implements unmarshalling process branch for a string attribute
  * 
  * @param proper        the proper name of the attribute
  * @param ucase         the upcased name of the attribute
  * @param namespaceURI  the XML namespace of the attribute
  */
-#define PROC_XMLOBJECT_ATTRIB(proper,ucase,namespaceURI) \
+#define PROC_STRING_ATTRIB(proper,ucase,namespaceURI) \
     if (xmltooling::XMLHelper::isNodeNamed(attribute, namespaceURI, ucase##_ATTRIB_NAME)) { \
         set##proper(attribute->getValue()); \
         return; \
  * @param ucase         the upcased name of the attribute
  * @param namespaceURI  the XML namespace of the attribute
  */
-#define PROC_XMLOBJECT_ID_ATTRIB(proper,ucase,namespaceURI) \
+#define PROC_ID_ATTRIB(proper,ucase,namespaceURI) \
     if (xmltooling::XMLHelper::isNodeNamed(attribute, namespaceURI, ucase##_ATTRIB_NAME)) { \
         set##proper(attribute->getValue()); \
         static_cast<DOMElement*>(attribute->getParentNode())->setIdAttributeNode(attribute); \
     }
 
 /**
+ * Implements unmarshalling process branch for a DateTime attribute
+ * 
+ * @param proper        the proper name of the attribute
+ * @param ucase         the upcased name of the attribute
+ * @param namespaceURI  the XML namespace of the attribute
+ */
+#define PROC_DATETIME_ATTRIB(proper,ucase,namespaceURI) \
+    PROC_STRING_ATTRIB(proper,ucase,namespaceURI)
+
+/**
+ * Implements unmarshalling process branch for a DateTime attribute
+ * 
+ * @param proper        the proper name of the attribute
+ * @param ucase         the upcased name of the attribute
+ * @param namespaceURI  the XML namespace of the attribute
+ */
+#define PROC_QNAME_ATTRIB(proper,ucase,namespaceURI) \
+    if (xmltooling::XMLHelper::isNodeNamed(attribute, namespaceURI, ucase##_ATTRIB_NAME)) { \
+        set##proper(XMLHelper::getAttributeValueAsQName(attribute)); \
+        return; \
+    }
+
+/**
+ * Implements unmarshalling process branch for an integer attribute
+ * 
+ * @param proper        the proper name of the attribute
+ * @param ucase         the upcased name of the attribute
+ * @param namespaceURI  the XML namespace of the attribute
+ */
+#define PROC_INTEGER_ATTRIB(proper,ucase,namespaceURI) \
+    if (xmltooling::XMLHelper::isNodeNamed(attribute, namespaceURI, ucase##_ATTRIB_NAME)) { \
+        set##proper(XMLString::parseInt(attribute->getValue())); \
+        return; \
+    }
+
+
+/**
  * Implements unmarshalling process branch for typed child collection element
  * 
  * @param proper        the proper name of the child type
  * @param namespaceURI  the XML namespace of the child element
+ * @param force         bypass use of hint and just cast down to check child
  */
-#define PROC_XMLOBJECT_CHILDREN(proper,namespaceURI) \
-    if (xmltooling::XMLHelper::isNodeNamed(root,namespaceURI,proper::LOCAL_NAME)) { \
+#define PROC_TYPED_CHILDREN(proper,namespaceURI,force) \
+    if (force || xmltooling::XMLHelper::isNodeNamed(root,namespaceURI,proper::LOCAL_NAME)) { \
         proper* typesafe=dynamic_cast<proper*>(childXMLObject); \
         if (typesafe) { \
             get##proper##s().push_back(typesafe); \
  * 
  * @param proper        the proper name of the child type
  * @param namespaceURI  the XML namespace of the child element
+ * @param force         bypass use of hint and just cast down to check child
  */
-#define PROC_XMLOBJECT_CHILD(proper,namespaceURI) \
-    if (xmltooling::XMLHelper::isNodeNamed(root,namespaceURI,proper::LOCAL_NAME)) { \
+#define PROC_TYPED_CHILD(proper,namespaceURI,force) \
+    if (force || xmltooling::XMLHelper::isNodeNamed(root,namespaceURI,proper::LOCAL_NAME)) { \
         proper* typesafe=dynamic_cast<proper*>(childXMLObject); \
         if (typesafe) { \
             set##proper(typesafe); \
  */
 #define DECL_XMLOBJECTIMPL_SIMPLE(linkage,cname) \
     class linkage cname##Impl \
-        : public cname, \
+        : public virtual cname, \
             public xmltooling::AbstractSimpleElement, \
             public xmltooling::AbstractChildlessElement, \
             public xmltooling::AbstractDOMCachingXMLObject, \
         throw xmltooling::ValidationException(#cname" must have "#proper1" or "#proper2".")
 
 /**
+ * Validator code that checks for one of a pair of
+ * required attributes, content, or singletons, but disallows both.
+ * 
+ * @param cname     the name of the XMLObject specialization
+ * @param proper1   the proper name of the first attribute, content, or singleton member 
+ * @param proper2   the proper name of the second attribute, content, or singleton member 
+ */
+#define XMLOBJECTVALIDATOR_ONLYONEOF(cname,proper1,proper2) \
+    if ((!ptr->get##proper1() && !ptr->get##proper2()) || (ptr->get##proper1() && ptr->get##proper2())) \
+        throw xmltooling::ValidationException(#cname" must have "#proper1" or "#proper2" but not both.")
+
+/**
  * Validator code that checks for one of a set of three
  * required attributes, content, or singletons.
  * 
         throw xmltooling::ValidationException(#cname" must have "#proper1", "#proper2", or "#proper3".")
 
 /**
+ * Validator code that checks for one of a set of three
+ * required attributes, content, or singletons but disallows more than one.
+ * 
+ * @param cname     the name of the XMLObject specialization
+ * @param proper1   the proper name of the first attribute, content, or singleton member
+ * @param proper2   the proper name of the second attribute, content, or singleton member
+ * @param proper3   the proper name of the third attribute, content, or singleton member
+ */
+#define XMLOBJECTVALIDATOR_ONLYONEOF3(cname,proper1,proper2,proper3) \
+    int c##proper1##proper2##proper3=0; \
+    if (ptr->get##proper1()!=NULL) \
+        c##proper1##proper2##proper3++; \
+    if (ptr->get##proper2()!=NULL) \
+        c##proper1##proper2##proper3++; \
+    if (ptr->get##proper3()!=NULL) \
+        c##proper1##proper2##proper3++; \
+    if (c##proper1##proper2##proper3 != 1) \
+        throw xmltooling::ValidationException(#cname" must have only one of "#proper1", "#proper2", or "#proper3".")
+
+/**
  * Validator code that checks a co-constraint (if one present, the other must be)
  * between a pair of attributes, content, or singletons.
  * 
index 3afab8c..e44e37d 100644 (file)
@@ -177,5 +177,5 @@ void AbstractXMLObjectUnmarshaller::unmarshallChildElements(const DOMElement* do
 
 void AbstractXMLObjectUnmarshaller::processChildElement(XMLObject* child, const DOMElement* childRoot)
 {
-    throw UnmarshallingException("Child elements are not permitted on this object.");
+    throw UnmarshallingException("Invalid child element: $1",params(1,child->getElementQName().toString().c_str()));
 }
index 00cc9d6..3981b3d 100644 (file)
@@ -59,67 +59,67 @@ namespace xmlsignature {
     DECL_XMLOBJECT_SIMPLE(XMLTOOL_API,PGPKeyPacket,Packet,XML Digital Signature version 20020212 PGPKeyPacket element);
 
     BEGIN_XMLOBJECT(XMLTOOL_API,DSAKeyValue,xmltooling::XMLObject,XML Digital Signature version 20020212 DSAKeyValue element);
-        DECL_XMLOBJECT_CHILD(P);
-        DECL_XMLOBJECT_CHILD(Q);
-        DECL_XMLOBJECT_CHILD(G);
-        DECL_XMLOBJECT_CHILD(Y);
-        DECL_XMLOBJECT_CHILD(J);
-        DECL_XMLOBJECT_CHILD(Seed);
-        DECL_XMLOBJECT_CHILD(PgenCounter);
+        DECL_TYPED_CHILD(P);
+        DECL_TYPED_CHILD(Q);
+        DECL_TYPED_CHILD(G);
+        DECL_TYPED_CHILD(Y);
+        DECL_TYPED_CHILD(J);
+        DECL_TYPED_CHILD(Seed);
+        DECL_TYPED_CHILD(PgenCounter);
         /** DSAKeyValueType local name */
         static const XMLCh TYPE_NAME[];
     END_XMLOBJECT;
 
     BEGIN_XMLOBJECT(XMLTOOL_API,RSAKeyValue,xmltooling::XMLObject,XML Digital Signature version 20020212 RSAKeyValue element);
-        DECL_XMLOBJECT_CHILD(Modulus);
-        DECL_XMLOBJECT_CHILD(Exponent);
+        DECL_TYPED_CHILD(Modulus);
+        DECL_TYPED_CHILD(Exponent);
         /** RSAKeyValueType local name */
         static const XMLCh TYPE_NAME[];
     END_XMLOBJECT;
 
     BEGIN_XMLOBJECT(XMLTOOL_API,KeyValue,xmltooling::SimpleElement,XML Digital Signature version 20020212 KeyValue element);
-        DECL_XMLOBJECT_CHILD(DSAKeyValue);
-        DECL_XMLOBJECT_CHILD(RSAKeyValue);
-        DECL_XMLOBJECT_CHILD(XMLObject);
+        DECL_TYPED_CHILD(DSAKeyValue);
+        DECL_TYPED_CHILD(RSAKeyValue);
+        DECL_XMLOBJECT_CHILD(OtherKeyValue);
         /** KeyValueType local name */
         static const XMLCh TYPE_NAME[];
     END_XMLOBJECT;
 
     BEGIN_XMLOBJECT(XMLTOOL_API,Transform,xmltooling::ElementProxy,XML Digital Signature version 20020212 Transform element);
-        DECL_XMLOBJECT_ATTRIB(Algorithm,ALGORITHM);
-        DECL_XMLOBJECT_CHILDREN(XPath);
+        DECL_STRING_ATTRIB(Algorithm,ALGORITHM);
+        DECL_TYPED_CHILDREN(XPath);
         /** TransformType local name */
         static const XMLCh TYPE_NAME[];
     END_XMLOBJECT;
 
     BEGIN_XMLOBJECT(XMLTOOL_API,Transforms,xmltooling::XMLObject,XML Digital Signature version 20020212 Transforms element);
-        DECL_XMLOBJECT_CHILDREN(Transform);
+        DECL_TYPED_CHILDREN(Transform);
         /** TransformsType local name */
         static const XMLCh TYPE_NAME[];
     END_XMLOBJECT;
 
     BEGIN_XMLOBJECT(XMLTOOL_API,RetrievalMethod,xmltooling::XMLObject,XML Digital Signature version 20020212 RetrievalMethod element);
-        DECL_XMLOBJECT_ATTRIB(URI,URI);
-        DECL_XMLOBJECT_ATTRIB(Type,TYPE);
-        DECL_XMLOBJECT_CHILD(Transforms);
+        DECL_STRING_ATTRIB(URI,URI);
+        DECL_STRING_ATTRIB(Type,TYPE);
+        DECL_TYPED_CHILD(Transforms);
         /** RetrievalMethodType local name */
         static const XMLCh TYPE_NAME[];
     END_XMLOBJECT;
 
     BEGIN_XMLOBJECT(XMLTOOL_API,X509IssuerSerial,xmltooling::XMLObject,XML Digital Signature version 20020212 X509IssuerSerial element);
-        DECL_XMLOBJECT_CHILD(X509IssuerName);
-        DECL_XMLOBJECT_CHILD(X509SerialNumber);
+        DECL_TYPED_CHILD(X509IssuerName);
+        DECL_TYPED_CHILD(X509SerialNumber);
         /** X509IssuerSerialType local name */
         static const XMLCh TYPE_NAME[];
     END_XMLOBJECT;
 
     BEGIN_XMLOBJECT(XMLTOOL_API,X509Data,xmltooling::XMLObject,XML Digital Signature version 20020212 X509Data element);
-        DECL_XMLOBJECT_CHILDREN(X509IssuerSerial);
-        DECL_XMLOBJECT_CHILDREN(X509SKI);
-        DECL_XMLOBJECT_CHILDREN(X509SubjectName);
-        DECL_XMLOBJECT_CHILDREN(X509Certificate);
-        DECL_XMLOBJECT_CHILDREN(X509CRL);
-        DECL_XMLOBJECT_CHILDREN(XMLObject);
+        DECL_TYPED_CHILDREN(X509IssuerSerial);
+        DECL_TYPED_CHILDREN(X509SKI);
+        DECL_TYPED_CHILDREN(X509SubjectName);
+        DECL_TYPED_CHILDREN(X509Certificate);
+        DECL_TYPED_CHILDREN(X509CRL);
+        DECL_XMLOBJECT_CHILDREN(OtherX509Data);
         /** X509DataType local name */
         static const XMLCh TYPE_NAME[];
     END_XMLOBJECT;
@@ -136,23 +136,23 @@ namespace xmlsignature {
     END_XMLOBJECT;
 
     BEGIN_XMLOBJECT(XMLTOOL_API,PGPData,xmltooling::XMLObject,XML Digital Signature version 20020212 PGPData element);
-        DECL_XMLOBJECT_CHILD(PGPKeyID);
-        DECL_XMLOBJECT_CHILD(PGPKeyPacket);
-        DECL_XMLOBJECT_CHILDREN(XMLObject);
+        DECL_TYPED_CHILD(PGPKeyID);
+        DECL_TYPED_CHILD(PGPKeyPacket);
+        DECL_XMLOBJECT_CHILDREN(PGPDataExtension);
         /** PGPDataType local name */
         static const XMLCh TYPE_NAME[];
     END_XMLOBJECT;
 
     BEGIN_XMLOBJECT(XMLTOOL_API,KeyInfo,xmltooling::XMLObject,XML Digital Signature version 20020212 KeyInfo element);
-        DECL_XMLOBJECT_ATTRIB(Id,ID);
-        DECL_XMLOBJECT_CHILDREN(X509Data);
-        DECL_XMLOBJECT_CHILDREN(KeyName);
-        DECL_XMLOBJECT_CHILDREN(KeyValue);
-        DECL_XMLOBJECT_CHILDREN(RetrievalMethod);
-        DECL_XMLOBJECT_CHILDREN(MgmtData);
-        DECL_XMLOBJECT_CHILDREN(PGPData);
-        DECL_XMLOBJECT_CHILDREN(SPKIData);
-        DECL_XMLOBJECT_CHILDREN(XMLObject);
+        DECL_STRING_ATTRIB(Id,ID);
+        DECL_TYPED_CHILDREN(X509Data);
+        DECL_TYPED_CHILDREN(KeyName);
+        DECL_TYPED_CHILDREN(KeyValue);
+        DECL_TYPED_CHILDREN(RetrievalMethod);
+        DECL_TYPED_CHILDREN(MgmtData);
+        DECL_TYPED_CHILDREN(PGPData);
+        DECL_TYPED_CHILDREN(SPKIData);
+        DECL_XMLOBJECT_CHILDREN(Other);
         /** KeyInfoType local name */
         static const XMLCh TYPE_NAME[];
     END_XMLOBJECT;
index 82b0c5b..8717c6f 100644 (file)
@@ -77,6 +77,13 @@ namespace xmlsignature {
          * @throws SignatureException   thrown if the verifying operation fails\r
          */\r
         virtual void verify(const VerifyingContext& ctx) const=0;\r
+        \r
+        /**\r
+         * Type-safe clone operation.\r
+         * \r
+         * @return  copy of object\r
+         */\r
+        virtual Signature* cloneSignature() const=0;\r
 \r
     protected:\r
         Signature() {}\r
@@ -111,7 +118,8 @@ namespace xmlsignature {
         }\r
     };\r
 \r
-    DECL_XMLTOOLING_EXCEPTION(SignatureException,XMLTOOL_EXCEPTIONAPI(XMLTOOL_API),xmlsignature,xmltooling::XMLToolingException,Exceptions in signature processing);\r
+    DECL_XMLTOOLING_EXCEPTION(XMLSecurityException,XMLTOOL_EXCEPTIONAPI(XMLTOOL_API),xmlsignature,xmltooling::XMLToolingException,Exceptions in XML Security processing);\r
+    DECL_XMLTOOLING_EXCEPTION(SignatureException,XMLTOOL_EXCEPTIONAPI(XMLTOOL_API),xmlsignature,xmlsignature::XMLSecurityException,Exceptions in signature processing);\r
 \r
 };\r
 \r
index f86ebd9..4643bf7 100644 (file)
@@ -1,7 +1,7 @@
 /*
-*  Copyright 2001-2006 Internet2
+ *  Copyright 2001-2006 Internet2
  * 
-* Licensed under the Apache License, Version 2.0 (the "License");
+ * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
@@ -45,7 +45,7 @@ using namespace std;
 
 namespace xmlsignature {
     
-    class XMLTOOL_DLLLOCAL DSAKeyValueImpl : public DSAKeyValue,
+    class XMLTOOL_DLLLOCAL DSAKeyValueImpl : public virtual DSAKeyValue,
         public AbstractComplexElement,
         public AbstractDOMCachingXMLObject,
         public AbstractValidatingXMLObject,
@@ -110,28 +110,28 @@ namespace xmlsignature {
         }
         
         IMPL_XMLOBJECT_CLONE(DSAKeyValue);
-        IMPL_XMLOBJECT_CHILD(P);
-        IMPL_XMLOBJECT_CHILD(Q);
-        IMPL_XMLOBJECT_CHILD(G);
-        IMPL_XMLOBJECT_CHILD(Y);
-        IMPL_XMLOBJECT_CHILD(J);
-        IMPL_XMLOBJECT_CHILD(Seed);
-        IMPL_XMLOBJECT_CHILD(PgenCounter);
+        IMPL_TYPED_CHILD(P);
+        IMPL_TYPED_CHILD(Q);
+        IMPL_TYPED_CHILD(G);
+        IMPL_TYPED_CHILD(Y);
+        IMPL_TYPED_CHILD(J);
+        IMPL_TYPED_CHILD(Seed);
+        IMPL_TYPED_CHILD(PgenCounter);
 
     protected:
         void processChildElement(XMLObject* childXMLObject, const DOMElement* root) {
-            PROC_XMLOBJECT_CHILD(P,XMLConstants::XMLSIG_NS);
-            PROC_XMLOBJECT_CHILD(Q,XMLConstants::XMLSIG_NS);
-            PROC_XMLOBJECT_CHILD(G,XMLConstants::XMLSIG_NS);
-            PROC_XMLOBJECT_CHILD(Y,XMLConstants::XMLSIG_NS);
-            PROC_XMLOBJECT_CHILD(J,XMLConstants::XMLSIG_NS);
-            PROC_XMLOBJECT_CHILD(Seed,XMLConstants::XMLSIG_NS);
-            PROC_XMLOBJECT_CHILD(PgenCounter,XMLConstants::XMLSIG_NS);
-            throw UnmarshallingException("Invalid child element: $1",params(1,childXMLObject->getElementQName().toString().c_str()));
+            PROC_TYPED_CHILD(P,XMLConstants::XMLSIG_NS,false);
+            PROC_TYPED_CHILD(Q,XMLConstants::XMLSIG_NS,false);
+            PROC_TYPED_CHILD(G,XMLConstants::XMLSIG_NS,false);
+            PROC_TYPED_CHILD(Y,XMLConstants::XMLSIG_NS,false);
+            PROC_TYPED_CHILD(J,XMLConstants::XMLSIG_NS,false);
+            PROC_TYPED_CHILD(Seed,XMLConstants::XMLSIG_NS,false);
+            PROC_TYPED_CHILD(PgenCounter,XMLConstants::XMLSIG_NS,false);
+            AbstractXMLObjectUnmarshaller::processChildElement(childXMLObject,root);
         }
     };
 
-    class XMLTOOL_DLLLOCAL RSAKeyValueImpl : public RSAKeyValue,
+    class XMLTOOL_DLLLOCAL RSAKeyValueImpl : public virtual RSAKeyValue,
         public AbstractComplexElement,
         public AbstractDOMCachingXMLObject,
         public AbstractValidatingXMLObject,
@@ -166,18 +166,18 @@ namespace xmlsignature {
         }
         
         IMPL_XMLOBJECT_CLONE(RSAKeyValue);
-        IMPL_XMLOBJECT_CHILD(Modulus);
-        IMPL_XMLOBJECT_CHILD(Exponent);
+        IMPL_TYPED_CHILD(Modulus);
+        IMPL_TYPED_CHILD(Exponent);
 
     protected:
         void processChildElement(XMLObject* childXMLObject, const DOMElement* root) {
-            PROC_XMLOBJECT_CHILD(Modulus,XMLConstants::XMLSIG_NS);
-            PROC_XMLOBJECT_CHILD(Exponent,XMLConstants::XMLSIG_NS);
-            throw UnmarshallingException("Invalid child element: $1",params(1,childXMLObject->getElementQName().toString().c_str()));
+            PROC_TYPED_CHILD(Modulus,XMLConstants::XMLSIG_NS,false);
+            PROC_TYPED_CHILD(Exponent,XMLConstants::XMLSIG_NS,false);
+            AbstractXMLObjectUnmarshaller::processChildElement(childXMLObject,root);
         }
     };
 
-    class XMLTOOL_DLLLOCAL KeyValueImpl : public KeyValue,
+    class XMLTOOL_DLLLOCAL KeyValueImpl : public virtual KeyValue,
         public AbstractSimpleElement,
         public AbstractComplexElement,
         public AbstractDOMCachingXMLObject,
@@ -201,45 +201,45 @@ namespace xmlsignature {
                 setDSAKeyValue(src.getDSAKeyValue()->cloneDSAKeyValue());
             if (src.getRSAKeyValue())
                 setRSAKeyValue(src.getRSAKeyValue()->cloneRSAKeyValue());
-            if (src.getXMLObject())
-                setXMLObject(src.getXMLObject()->clone());
+            if (src.getOtherKeyValue())
+                setOtherKeyValue(src.getOtherKeyValue()->clone());
         }
         
         void init() {
             m_DSAKeyValue=NULL;
             m_RSAKeyValue=NULL;
-            m_XMLObject=NULL;
+            m_OtherKeyValue=NULL;
             m_children.push_back(NULL);
             m_children.push_back(NULL);
             m_children.push_back(NULL);
             m_pos_DSAKeyValue=m_children.begin();
             m_pos_RSAKeyValue=m_pos_DSAKeyValue;
             ++m_pos_RSAKeyValue;
-            m_pos_XMLObject=m_pos_RSAKeyValue;
-            ++m_pos_XMLObject;
+            m_pos_OtherKeyValue=m_pos_RSAKeyValue;
+            ++m_pos_OtherKeyValue;
         }
         
         IMPL_XMLOBJECT_CLONE(KeyValue);
-        IMPL_XMLOBJECT_CHILD(DSAKeyValue);
-        IMPL_XMLOBJECT_CHILD(RSAKeyValue);
-        IMPL_XMLOBJECT_CHILD(XMLObject);
+        IMPL_TYPED_CHILD(DSAKeyValue);
+        IMPL_TYPED_CHILD(RSAKeyValue);
+        IMPL_XMLOBJECT_CHILD(OtherKeyValue);
         IMPL_XMLOBJECT_CONTENT;
 
     protected:
         void processChildElement(XMLObject* childXMLObject, const DOMElement* root) {
-            PROC_XMLOBJECT_CHILD(DSAKeyValue,XMLConstants::XMLSIG_NS);
-            PROC_XMLOBJECT_CHILD(RSAKeyValue,XMLConstants::XMLSIG_NS);
+            PROC_TYPED_CHILD(DSAKeyValue,XMLConstants::XMLSIG_NS,false);
+            PROC_TYPED_CHILD(RSAKeyValue,XMLConstants::XMLSIG_NS,false);
             
             // Unknown child.
             const XMLCh* nsURI=root->getNamespaceURI();
             if (!XMLString::equals(nsURI,XMLConstants::XMLSIG_NS) && nsURI && *nsURI)
-                setXMLObject(childXMLObject);
+                setOtherKeyValue(childXMLObject);
             
-            throw UnmarshallingException("Invalid child element: $1",params(1,childXMLObject->getElementQName().toString().c_str()));
+            AbstractXMLObjectUnmarshaller::processChildElement(childXMLObject,root);
         }
     };
 
-    class XMLTOOL_DLLLOCAL TransformImpl : public Transform,
+    class XMLTOOL_DLLLOCAL TransformImpl : public virtual Transform,
         public AbstractDOMCachingXMLObject,
         public AbstractElementProxy,
         public AbstractValidatingXMLObject,
@@ -271,32 +271,32 @@ namespace xmlsignature {
         }
         
         IMPL_XMLOBJECT_CLONE(Transform);
-        IMPL_XMLOBJECT_ATTRIB(Algorithm);
-        IMPL_XMLOBJECT_CHILDREN(XPath,m_children.end());
+        IMPL_STRING_ATTRIB(Algorithm);
+        IMPL_TYPED_CHILDREN(XPath,m_children.end());
         IMPL_XMLOBJECT_CONTENT;
 
     protected:
         void marshallAttributes(DOMElement* domElement) const {
-            MARSHALL_XMLOBJECT_ATTRIB(Algorithm,ALGORITHM,NULL);
+            MARSHALL_STRING_ATTRIB(Algorithm,ALGORITHM,NULL);
         }
 
         void processChildElement(XMLObject* childXMLObject, const DOMElement* root) {
-            PROC_XMLOBJECT_CHILDREN(XPath,XMLConstants::XMLSIG_NS);
+            PROC_TYPED_CHILDREN(XPath,XMLConstants::XMLSIG_NS,false);
             
             // Unknown child.
             const XMLCh* nsURI=root->getNamespaceURI();
             if (!XMLString::equals(nsURI,XMLConstants::XMLSIG_NS) && nsURI && *nsURI)
                 getXMLObjects().push_back(childXMLObject);
             
-            throw UnmarshallingException("Invalid child element: $1",params(1,childXMLObject->getElementQName().toString().c_str()));
+            AbstractXMLObjectUnmarshaller::processChildElement(childXMLObject,root);
         }
 
         void processAttribute(const DOMAttr* attribute) {
-            PROC_XMLOBJECT_ATTRIB(Algorithm,ALGORITHM,NULL);
+            PROC_STRING_ATTRIB(Algorithm,ALGORITHM,NULL);
         }
     };
 
-    class XMLTOOL_DLLLOCAL TransformsImpl : public Transforms,
+    class XMLTOOL_DLLLOCAL TransformsImpl : public virtual Transforms,
         public AbstractComplexElement,
         public AbstractDOMCachingXMLObject,
         public AbstractValidatingXMLObject,
@@ -321,16 +321,16 @@ namespace xmlsignature {
         }
         
         IMPL_XMLOBJECT_CLONE(Transforms);
-        IMPL_XMLOBJECT_CHILDREN(Transform,m_children.end());
+        IMPL_TYPED_CHILDREN(Transform,m_children.end());
 
     protected:
         void processChildElement(XMLObject* childXMLObject, const DOMElement* root) {
-            PROC_XMLOBJECT_CHILDREN(Transform,XMLConstants::XMLSIG_NS);
-            throw UnmarshallingException("Invalid child element: $1",params(1,childXMLObject->getElementQName().toString().c_str()));
+            PROC_TYPED_CHILDREN(Transform,XMLConstants::XMLSIG_NS,false);
+            AbstractXMLObjectUnmarshaller::processChildElement(childXMLObject,root);
         }
     };
 
-    class XMLTOOL_DLLLOCAL RetrievalMethodImpl : public RetrievalMethod,
+    class XMLTOOL_DLLLOCAL RetrievalMethodImpl : public virtual RetrievalMethod,
         public AbstractComplexElement,
         public AbstractDOMCachingXMLObject,
         public AbstractValidatingXMLObject,
@@ -365,28 +365,28 @@ namespace xmlsignature {
         }
         
         IMPL_XMLOBJECT_CLONE(RetrievalMethod);
-        IMPL_XMLOBJECT_ATTRIB(URI);
-        IMPL_XMLOBJECT_ATTRIB(Type);
-        IMPL_XMLOBJECT_CHILD(Transforms);
+        IMPL_STRING_ATTRIB(URI);
+        IMPL_STRING_ATTRIB(Type);
+        IMPL_TYPED_CHILD(Transforms);
 
     protected:
         void marshallAttributes(DOMElement* domElement) const {
-            MARSHALL_XMLOBJECT_ATTRIB(URI,URI,NULL);
-            MARSHALL_XMLOBJECT_ATTRIB(Type,TYPE,NULL);
+            MARSHALL_STRING_ATTRIB(URI,URI,NULL);
+            MARSHALL_STRING_ATTRIB(Type,TYPE,NULL);
         }
 
         void processChildElement(XMLObject* childXMLObject, const DOMElement* root) {
-            PROC_XMLOBJECT_CHILD(Transforms,XMLConstants::XMLSIG_NS);
-            throw UnmarshallingException("Invalid child element: $1",params(1,childXMLObject->getElementQName().toString().c_str()));
+            PROC_TYPED_CHILD(Transforms,XMLConstants::XMLSIG_NS,false);
+            AbstractXMLObjectUnmarshaller::processChildElement(childXMLObject,root);
         }
 
         void processAttribute(const DOMAttr* attribute) {
-            PROC_XMLOBJECT_ATTRIB(URI,URI,NULL);
-            PROC_XMLOBJECT_ATTRIB(Type,TYPE,NULL);
+            PROC_STRING_ATTRIB(URI,URI,NULL);
+            PROC_STRING_ATTRIB(Type,TYPE,NULL);
         }
     };
 
-    class XMLTOOL_DLLLOCAL X509IssuerSerialImpl : public X509IssuerSerial,
+    class XMLTOOL_DLLLOCAL X509IssuerSerialImpl : public virtual X509IssuerSerial,
         public AbstractComplexElement,
         public AbstractDOMCachingXMLObject,
         public AbstractValidatingXMLObject,
@@ -421,18 +421,18 @@ namespace xmlsignature {
         }
         
         IMPL_XMLOBJECT_CLONE(X509IssuerSerial);
-        IMPL_XMLOBJECT_CHILD(X509IssuerName);
-        IMPL_XMLOBJECT_CHILD(X509SerialNumber);
+        IMPL_TYPED_CHILD(X509IssuerName);
+        IMPL_TYPED_CHILD(X509SerialNumber);
 
     protected:
         void processChildElement(XMLObject* childXMLObject, const DOMElement* root) {
-            PROC_XMLOBJECT_CHILD(X509IssuerName,XMLConstants::XMLSIG_NS);
-            PROC_XMLOBJECT_CHILD(X509SerialNumber,XMLConstants::XMLSIG_NS);
-            throw UnmarshallingException("Invalid child element: $1",params(1,childXMLObject->getElementQName().toString().c_str()));
+            PROC_TYPED_CHILD(X509IssuerName,XMLConstants::XMLSIG_NS,false);
+            PROC_TYPED_CHILD(X509SerialNumber,XMLConstants::XMLSIG_NS,false);
+            AbstractXMLObjectUnmarshaller::processChildElement(childXMLObject,root);
         }
     };
 
-    class XMLTOOL_DLLLOCAL X509DataImpl : public X509Data,
+    class XMLTOOL_DLLLOCAL X509DataImpl : public virtual X509Data,
         public AbstractComplexElement,
         public AbstractDOMCachingXMLObject,
         public AbstractValidatingXMLObject,
@@ -480,37 +480,37 @@ namespace xmlsignature {
                         continue;
                     }
 
-                    getXMLObjects().push_back((*i)->clone());
+                    getOtherX509Datas().push_back((*i)->clone());
                 }
             }
         }
         
         IMPL_XMLOBJECT_CLONE(X509Data);
-        IMPL_XMLOBJECT_CHILDREN(X509IssuerSerial,m_children.end());
-        IMPL_XMLOBJECT_CHILDREN(X509SKI,m_children.end());
-        IMPL_XMLOBJECT_CHILDREN(X509SubjectName,m_children.end());
-        IMPL_XMLOBJECT_CHILDREN(X509Certificate,m_children.end());
-        IMPL_XMLOBJECT_CHILDREN(X509CRL,m_children.end());
-        IMPL_XMLOBJECT_CHILDREN(XMLObject,m_children.end());
+        IMPL_TYPED_CHILDREN(X509IssuerSerial,m_children.end());
+        IMPL_TYPED_CHILDREN(X509SKI,m_children.end());
+        IMPL_TYPED_CHILDREN(X509SubjectName,m_children.end());
+        IMPL_TYPED_CHILDREN(X509Certificate,m_children.end());
+        IMPL_TYPED_CHILDREN(X509CRL,m_children.end());
+        IMPL_XMLOBJECT_CHILDREN(OtherX509Data,m_children.end());
 
     protected:
         void processChildElement(XMLObject* childXMLObject, const DOMElement* root) {
-            PROC_XMLOBJECT_CHILDREN(X509IssuerSerial,XMLConstants::XMLSIG_NS);
-            PROC_XMLOBJECT_CHILDREN(X509SKI,XMLConstants::XMLSIG_NS);
-            PROC_XMLOBJECT_CHILDREN(X509SubjectName,XMLConstants::XMLSIG_NS);
-            PROC_XMLOBJECT_CHILDREN(X509Certificate,XMLConstants::XMLSIG_NS);
-            PROC_XMLOBJECT_CHILDREN(X509CRL,XMLConstants::XMLSIG_NS);
+            PROC_TYPED_CHILDREN(X509IssuerSerial,XMLConstants::XMLSIG_NS,false);
+            PROC_TYPED_CHILDREN(X509SKI,XMLConstants::XMLSIG_NS,false);
+            PROC_TYPED_CHILDREN(X509SubjectName,XMLConstants::XMLSIG_NS,false);
+            PROC_TYPED_CHILDREN(X509Certificate,XMLConstants::XMLSIG_NS,false);
+            PROC_TYPED_CHILDREN(X509CRL,XMLConstants::XMLSIG_NS,false);
             
             // Unknown child.
             const XMLCh* nsURI=root->getNamespaceURI();
             if (!XMLString::equals(nsURI,XMLConstants::XMLSIG_NS) && nsURI && *nsURI)
-                getXMLObjects().push_back(childXMLObject);
+                getOtherX509Datas().push_back(childXMLObject);
             
-            throw UnmarshallingException("Invalid child element: $1",params(1,childXMLObject->getElementQName().toString().c_str()));
+            AbstractXMLObjectUnmarshaller::processChildElement(childXMLObject,root);
         }
     };
 
-    class XMLTOOL_DLLLOCAL SPKIDataImpl : public SPKIData,
+    class XMLTOOL_DLLLOCAL SPKIDataImpl : public virtual SPKIData,
         public AbstractComplexElement,
         public AbstractDOMCachingXMLObject,
         public AbstractValidatingXMLObject,
@@ -571,11 +571,11 @@ namespace xmlsignature {
                     throw UnmarshallingException("Extension element must follow ds:SPKISexp element.");
             }
             
-            throw UnmarshallingException("Invalid child element: $1",params(1,childXMLObject->getElementQName().toString().c_str()));
+            AbstractXMLObjectUnmarshaller::processChildElement(childXMLObject,root);
         }
     };
 
-    class XMLTOOL_DLLLOCAL PGPDataImpl : public PGPData,
+    class XMLTOOL_DLLLOCAL PGPDataImpl : public virtual PGPData,
         public AbstractComplexElement,
         public AbstractDOMCachingXMLObject,
         public AbstractValidatingXMLObject,
@@ -597,8 +597,8 @@ namespace xmlsignature {
                 setPGPKeyID(src.getPGPKeyID()->clonePGPKeyID());
             if (src.getPGPKeyPacket())
                 setPGPKeyPacket(src.getPGPKeyPacket()->clonePGPKeyPacket());
-            VectorOf(XMLObject) v=getXMLObjects();
-            for (vector<XMLObject*>::const_iterator i=src.m_XMLObjects.begin(); i!=src.m_XMLObjects.end(); i++) {
+            VectorOf(XMLObject) v=getPGPDataExtensions();
+            for (vector<XMLObject*>::const_iterator i=src.m_PGPDataExtensions.begin(); i!=src.m_PGPDataExtensions.end(); i++) {
                 if (*i) {
                     v.push_back((*i)->clone());
                 }
@@ -616,25 +616,25 @@ namespace xmlsignature {
         }
         
         IMPL_XMLOBJECT_CLONE(PGPData);
-        IMPL_XMLOBJECT_CHILD(PGPKeyID);
-        IMPL_XMLOBJECT_CHILD(PGPKeyPacket);
-        IMPL_XMLOBJECT_CHILDREN(XMLObject,m_children.end());
+        IMPL_TYPED_CHILD(PGPKeyID);
+        IMPL_TYPED_CHILD(PGPKeyPacket);
+        IMPL_XMLOBJECT_CHILDREN(PGPDataExtension,m_children.end());
 
     protected:
         void processChildElement(XMLObject* childXMLObject, const DOMElement* root) {
-            PROC_XMLOBJECT_CHILD(PGPKeyID,XMLConstants::XMLSIG_NS);
-            PROC_XMLOBJECT_CHILD(PGPKeyPacket,XMLConstants::XMLSIG_NS);
+            PROC_TYPED_CHILD(PGPKeyID,XMLConstants::XMLSIG_NS,false);
+            PROC_TYPED_CHILD(PGPKeyPacket,XMLConstants::XMLSIG_NS,false);
 
             // Unknown child.
             const XMLCh* nsURI=root->getNamespaceURI();
             if (!XMLString::equals(nsURI,XMLConstants::XMLSIG_NS) && nsURI && *nsURI)
-                getXMLObjects().push_back(childXMLObject);
+                getPGPDataExtensions().push_back(childXMLObject);
 
-            throw UnmarshallingException("Invalid child element: $1",params(1,childXMLObject->getElementQName().toString().c_str()));
+            AbstractXMLObjectUnmarshaller::processChildElement(childXMLObject,root);
         }
     };
 
-    class XMLTOOL_DLLLOCAL KeyInfoImpl : public KeyInfo,
+    class XMLTOOL_DLLLOCAL KeyInfoImpl : public virtual KeyInfo,
         public AbstractComplexElement,
         public AbstractSimpleElement,
         public AbstractDOMCachingXMLObject,
@@ -702,47 +702,47 @@ namespace xmlsignature {
                         continue;
                     }
 
-                    getXMLObjects().push_back((*i)->clone());
+                    getOthers().push_back((*i)->clone());
                 }
             }
         }
         
         IMPL_XMLOBJECT_CLONE(KeyInfo);
-        IMPL_XMLOBJECT_ATTRIB(Id);
-        IMPL_XMLOBJECT_CHILDREN(KeyName,m_children.end());
-        IMPL_XMLOBJECT_CHILDREN(KeyValue,m_children.end());
-        IMPL_XMLOBJECT_CHILDREN(RetrievalMethod,m_children.end());
-        IMPL_XMLOBJECT_CHILDREN(X509Data,m_children.end());
-        IMPL_XMLOBJECT_CHILDREN(MgmtData,m_children.end());
-        IMPL_XMLOBJECT_CHILDREN(SPKIData,m_children.end());
-        IMPL_XMLOBJECT_CHILDREN(PGPData,m_children.end());
-        IMPL_XMLOBJECT_CHILDREN(XMLObject,m_children.end());
+        IMPL_STRING_ATTRIB(Id);
+        IMPL_TYPED_CHILDREN(KeyName,m_children.end());
+        IMPL_TYPED_CHILDREN(KeyValue,m_children.end());
+        IMPL_TYPED_CHILDREN(RetrievalMethod,m_children.end());
+        IMPL_TYPED_CHILDREN(X509Data,m_children.end());
+        IMPL_TYPED_CHILDREN(MgmtData,m_children.end());
+        IMPL_TYPED_CHILDREN(SPKIData,m_children.end());
+        IMPL_TYPED_CHILDREN(PGPData,m_children.end());
+        IMPL_XMLOBJECT_CHILDREN(Other,m_children.end());
         IMPL_XMLOBJECT_CONTENT;
 
     protected:
         void marshallAttributes(DOMElement* domElement) const {
-            MARSHALL_XMLOBJECT_ID_ATTRIB(Id,ID,NULL);
+            MARSHALL_ID_ATTRIB(Id,ID,NULL);
         }
 
         void processChildElement(XMLObject* childXMLObject, const DOMElement* root) {
-            PROC_XMLOBJECT_CHILDREN(X509Data,XMLConstants::XMLSIG_NS);
-            PROC_XMLOBJECT_CHILDREN(KeyName,XMLConstants::XMLSIG_NS);
-            PROC_XMLOBJECT_CHILDREN(KeyValue,XMLConstants::XMLSIG_NS);
-            PROC_XMLOBJECT_CHILDREN(RetrievalMethod,XMLConstants::XMLSIG_NS);
-            PROC_XMLOBJECT_CHILDREN(MgmtData,XMLConstants::XMLSIG_NS);
-            PROC_XMLOBJECT_CHILDREN(SPKIData,XMLConstants::XMLSIG_NS);
-            PROC_XMLOBJECT_CHILDREN(PGPData,XMLConstants::XMLSIG_NS);
+            PROC_TYPED_CHILDREN(X509Data,XMLConstants::XMLSIG_NS,false);
+            PROC_TYPED_CHILDREN(KeyName,XMLConstants::XMLSIG_NS,false);
+            PROC_TYPED_CHILDREN(KeyValue,XMLConstants::XMLSIG_NS,false);
+            PROC_TYPED_CHILDREN(RetrievalMethod,XMLConstants::XMLSIG_NS,false);
+            PROC_TYPED_CHILDREN(MgmtData,XMLConstants::XMLSIG_NS,false);
+            PROC_TYPED_CHILDREN(SPKIData,XMLConstants::XMLSIG_NS,false);
+            PROC_TYPED_CHILDREN(PGPData,XMLConstants::XMLSIG_NS,false);
             
             // Unknown child.
             const XMLCh* nsURI=root->getNamespaceURI();
             if (!XMLString::equals(nsURI,XMLConstants::XMLSIG_NS) && nsURI && *nsURI)
-                getXMLObjects().push_back(childXMLObject);
+                getOthers().push_back(childXMLObject);
             
-            throw UnmarshallingException("Invalid child element: $1",params(1,childXMLObject->getElementQName().toString().c_str()));
+            AbstractXMLObjectUnmarshaller::processChildElement(childXMLObject,root);
         }
 
         void processAttribute(const DOMAttr* attribute) {
-            PROC_XMLOBJECT_ID_ATTRIB(Id,ID,NULL);
+            PROC_ID_ATTRIB(Id,ID,NULL);
         }
     };
     
index e2dc57d..ec4dbaa 100644 (file)
@@ -64,7 +64,7 @@ namespace xmlsignature {
     END_XMLOBJECTVALIDATOR;
 
     BEGIN_XMLOBJECTVALIDATOR(XMLTOOL_DLLLOCAL,KeyValue);
-        XMLOBJECTVALIDATOR_ONEOF3(KeyValue,DSAKeyValue,RSAKeyValue,XMLObject);
+        XMLOBJECTVALIDATOR_ONLYONEOF3(KeyValue,DSAKeyValue,RSAKeyValue,OtherKeyValue);
     END_XMLOBJECTVALIDATOR;
 
     BEGIN_XMLOBJECTVALIDATOR(XMLTOOL_DLLLOCAL,Transform);
@@ -90,7 +90,7 @@ namespace xmlsignature {
             const XMLCh* ns=xmlObject->getElementQName().getNamespaceURI();
             if (XMLString::equals(ns,XMLConstants::XMLSIG_NS) || !ns || !*ns) {
                 throw ValidationException(
-                    "X509Data contains an illegal extension element ($1).",
+                    "Object contains an illegal extension child element ($1).",
                     params(1,xmlObject->getElementQName().toString().c_str())
                     );
             }
@@ -100,7 +100,7 @@ namespace xmlsignature {
     BEGIN_XMLOBJECTVALIDATOR(XMLTOOL_DLLLOCAL,X509Data);
         if (!ptr->hasChildren())
             throw ValidationException("X509Data must have at least one child element.");
-        vector<XMLObject*> anys=ptr->getXMLObjects();
+        const vector<XMLObject*>& anys=ptr->getOtherX509Datas();
         for_each(anys.begin(),anys.end(),checkWildcardNS());
     END_XMLOBJECTVALIDATOR;
 
@@ -115,7 +115,7 @@ namespace xmlsignature {
     BEGIN_XMLOBJECTVALIDATOR(XMLTOOL_DLLLOCAL,KeyInfo);
         if (!ptr->hasChildren())
             throw ValidationException("KeyInfo must have at least one child element.");
-        vector<XMLObject*> anys=ptr->getXMLObjects();
+        const vector<XMLObject*>& anys=ptr->getOthers();
         for_each(anys.begin(),anys.end(),checkWildcardNS());
     END_XMLOBJECTVALIDATOR;
 
index bf169bb..4bd7653 100644 (file)
@@ -57,6 +57,7 @@ namespace xmlsignature {
         \r
         void releaseDOM();\r
         XMLObject* clone() const;\r
+        Signature* cloneSignature() const;\r
 \r
         DOMElement* marshall(DOMDocument* document=NULL, MarshallingContext* ctx=NULL) const;\r
         DOMElement* marshall(DOMElement* parentElement, MarshallingContext* ctx=NULL) const;\r
@@ -109,6 +110,11 @@ void XMLSecSignatureImpl::releaseDOM()
 \r
 XMLObject* XMLSecSignatureImpl::clone() const\r
 {\r
+    return cloneSignature();\r
+}\r
+\r
+Signature* XMLSecSignatureImpl::cloneSignature() const\r
+{\r
     XMLSecSignatureImpl* ret=new XMLSecSignatureImpl();\r
 \r
     ret->m_c14n=XMLString::replicate(m_c14n);\r
diff --git a/xmltooling/util/DateTime.cpp b/xmltooling/util/DateTime.cpp
new file mode 100644 (file)
index 0000000..7877c50
--- /dev/null
@@ -0,0 +1,1621 @@
+/*\r
+ *  Copyright 2001-2006 Internet2\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *     http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+/**\r
+ * DateTime.cpp\r
+ * \r
+ * Manipulation of XML date/time data. \r
+ */\r
+\r
+/*\r
+ * This is mostly copied from Xerces-C, but they don't seem inclined to produce a usable\r
+ * class, so I had to incorporate my own version of it for now. I can't inherit it\r
+ * since the fields I need are private.\r
+ */\r
+\r
+#include "internal.h"\r
+#include "util/DateTime.h"\r
+\r
+#ifndef WIN32\r
+# include <errno.h>\r
+#endif\r
+\r
+#include <ctime>\r
+#include <xercesc/util/Janitor.hpp>\r
+#include <xercesc/util/NumberFormatException.hpp>\r
+\r
+using namespace xmltooling;\r
+using namespace std;\r
+\r
+//\r
+// constants used to process raw data (fBuffer)\r
+//\r
+// [-]{CCYY-MM-DD}'T'{HH:MM:SS.MS}['Z']\r
+//                                [{+|-}hh:mm']\r
+//\r
+\r
+static const XMLCh DURATION_STARTER     = chLatin_P;              // 'P'\r
+static const XMLCh DURATION_Y           = chLatin_Y;              // 'Y'\r
+static const XMLCh DURATION_M           = chLatin_M;              // 'M'\r
+static const XMLCh DURATION_D           = chLatin_D;              // 'D'\r
+static const XMLCh DURATION_H           = chLatin_H;              // 'H'\r
+static const XMLCh DURATION_S           = chLatin_S;              // 'S'\r
+\r
+static const XMLCh DATE_SEPARATOR       = chDash;                 // '-'\r
+static const XMLCh TIME_SEPARATOR       = chColon;                // ':'\r
+static const XMLCh TIMEZONE_SEPARATOR   = chColon;                // ':'\r
+static const XMLCh DATETIME_SEPARATOR   = chLatin_T;              // 'T'\r
+static const XMLCh MILISECOND_SEPARATOR = chPeriod;               // '.'\r
+\r
+static const XMLCh UTC_STD_CHAR         = chLatin_Z;              // 'Z'\r
+static const XMLCh UTC_POS_CHAR         = chPlus;                 // '+'\r
+static const XMLCh UTC_NEG_CHAR         = chDash;                 // '-'\r
+\r
+static const XMLCh UTC_SET[]            = {UTC_STD_CHAR           //"Z+-"\r
+                                         , UTC_POS_CHAR\r
+                                         , UTC_NEG_CHAR\r
+                                         , chNull};\r
+\r
+static const int YMD_MIN_SIZE    = 10;   // CCYY-MM-DD\r
+static const int YMONTH_MIN_SIZE = 7;    // CCYY_MM\r
+static const int TIME_MIN_SIZE   = 8;    // hh:mm:ss\r
+static const int TIMEZONE_SIZE   = 5;    // hh:mm\r
+static const int DAY_SIZE        = 5;    // ---DD\r
+//static const int MONTH_SIZE      = 6;    // --MM--\r
+static const int MONTHDAY_SIZE   = 7;    // --MM-DD\r
+static const int NOT_FOUND       = -1;\r
+\r
+//define constants to be used in assigning default values for\r
+//all date/time excluding duration\r
+static const int YEAR_DEFAULT  = 2000;\r
+static const int MONTH_DEFAULT = 01;\r
+static const int DAY_DEFAULT   = 15;\r
+\r
+// order-relation on duration is a partial order. The dates below are used to\r
+// for comparison of 2 durations, based on the fact that\r
+// duration x and y is x<=y iff s+x<=s+y\r
+// see 3.2.6 duration W3C schema datatype specs\r
+//\r
+// the dates are in format: {CCYY,MM,DD, H, S, M, MS, timezone}\r
+const int DateTime::DATETIMES[][TOTAL_SIZE] =\r
+{\r
+    {1696, 9, 1, 0, 0, 0, 0, UTC_STD},\r
+       {1697, 2, 1, 0, 0, 0, 0, UTC_STD},\r
+       {1903, 3, 1, 0, 0, 0, 0, UTC_STD},\r
+       {1903, 7, 1, 0, 0, 0, 0, UTC_STD}\r
+};\r
+\r
+// ---------------------------------------------------------------------------\r
+//  local methods\r
+// ---------------------------------------------------------------------------\r
+static inline int fQuotient(int a, int b)\r
+{\r
+    div_t div_result = div(a, b);\r
+    return div_result.quot;\r
+}\r
+\r
+static inline int fQuotient(int temp, int low, int high)\r
+{\r
+    return fQuotient(temp - low, high - low);\r
+}\r
+\r
+static inline int mod(int a, int b, int quotient)\r
+{\r
+       return (a - quotient*b) ;\r
+}\r
+\r
+static inline int modulo (int temp, int low, int high)\r
+{\r
+    //modulo(a - low, high - low) + low\r
+    int a = temp - low;\r
+    int b = high - low;\r
+    return (mod (a, b, fQuotient(a, b)) + low) ;\r
+}\r
+\r
+static inline bool isLeapYear(int year)\r
+{\r
+    return((year%4 == 0) && ((year%100 != 0) || (year%400 == 0)));\r
+}\r
+\r
+static int maxDayInMonthFor(int year, int month)\r
+{\r
+\r
+    if ( month == 4 || month == 6 || month == 9 || month == 11 )\r
+    {\r
+        return 30;\r
+    }\r
+    else if ( month==2 )\r
+    {\r
+        if ( isLeapYear(year) )\r
+            return 29;\r
+        else\r
+            return 28;\r
+    }\r
+    else\r
+    {\r
+        return 31;\r
+    }\r
+\r
+}\r
+\r
+// ---------------------------------------------------------------------------\r
+//  static methods : for duration\r
+// ---------------------------------------------------------------------------\r
+/**\r
+ * Compares 2 given durations. (refer to W3C Schema Datatypes "3.2.6 duration")\r
+ *\r
+ * 3.2.6.2 Order relation on duration\r
+ *\r
+ *     In general, the order-relation on duration is a partial order since there is no\r
+ *  determinate relationship between certain durations such as one month (P1M) and 30 days (P30D).\r
+ *  The order-relation of two duration values x and y is x < y iff s+x < s+y for each qualified\r
+ *  dateTime s in the list below.\r
+ *\r
+ *     These values for s cause the greatest deviations in the addition of dateTimes and durations\r
+ *\r
+ **/\r
+int DateTime::compare(const DateTime* const pDate1\r
+                       , const DateTime* const pDate2\r
+                       , bool  strict)\r
+{\r
+    //REVISIT: this is unoptimazed vs of comparing 2 durations\r
+    //         Algorithm is described in 3.2.6.2 W3C Schema Datatype specs\r
+    //\r
+\r
+    int resultA, resultB = XMLDateTime::INDETERMINATE;\r
+\r
+    //try and see if the objects are equal\r
+    if ( (resultA = compareOrder(pDate1, pDate2)) == XMLDateTime::EQUAL)\r
+        return XMLDateTime::EQUAL;\r
+\r
+    //long comparison algorithm is required\r
+    DateTime tempA, *pTempA = &tempA;\r
+    DateTime tempB, *pTempB = &tempB;\r
+\r
+    addDuration(pTempA, pDate1, 0);\r
+    addDuration(pTempB, pDate2, 0);\r
+    resultA = compareOrder(pTempA, pTempB);\r
+    if ( resultA == XMLDateTime::INDETERMINATE )\r
+        return XMLDateTime::INDETERMINATE;\r
+\r
+    addDuration(pTempA, pDate1, 1);\r
+    addDuration(pTempB, pDate2, 1);\r
+    resultB = compareOrder(pTempA, pTempB);\r
+    resultA = compareResult(resultA, resultB, strict);\r
+    if ( resultA == XMLDateTime::INDETERMINATE )\r
+        return XMLDateTime::INDETERMINATE;\r
+\r
+    addDuration(pTempA, pDate1, 2);\r
+    addDuration(pTempB, pDate2, 2);\r
+    resultB = compareOrder(pTempA, pTempB);\r
+    resultA = compareResult(resultA, resultB, strict);\r
+    if ( resultA == XMLDateTime::INDETERMINATE )\r
+        return XMLDateTime::INDETERMINATE;\r
+\r
+    addDuration(pTempA, pDate1, 3);\r
+    addDuration(pTempB, pDate2, 3);\r
+    resultB = compareOrder(pTempA, pTempB);\r
+    resultA = compareResult(resultA, resultB, strict);\r
+\r
+    return resultA;\r
+\r
+}\r
+\r
+//\r
+// Form a new DateTime with duration and baseDate array\r
+// Note: C++        Java\r
+//       fNewDate   duration\r
+//       fDuration  date\r
+//\r
+\r
+void DateTime::addDuration(DateTime*             fNewDate\r
+                            , const DateTime* const fDuration\r
+                            , int index)\r
+\r
+{\r
+\r
+    //REVISIT: some code could be shared between normalize() and this method,\r
+    //         however is it worth moving it? The structures are different...\r
+    //\r
+\r
+    fNewDate->reset();\r
+    //add months (may be modified additionaly below)\r
+    int temp = DATETIMES[index][Month] + fDuration->fValue[Month];\r
+    fNewDate->fValue[Month] = modulo(temp, 1, 13);\r
+    int carry = fQuotient(temp, 1, 13);\r
+\r
+    //add years (may be modified additionaly below)\r
+    fNewDate->fValue[CentYear] =\r
+        DATETIMES[index][CentYear] + fDuration->fValue[CentYear] + carry;\r
+\r
+    //add seconds\r
+    temp = DATETIMES[index][Second] + fDuration->fValue[Second];\r
+    carry = fQuotient (temp, 60);\r
+    fNewDate->fValue[Second] =  mod(temp, 60, carry);\r
+               \r
+    //add minutes\r
+    temp = DATETIMES[index][Minute] + fDuration->fValue[Minute] + carry;\r
+    carry = fQuotient(temp, 60);\r
+    fNewDate->fValue[Minute] = mod(temp, 60, carry);\r
+\r
+    //add hours\r
+    temp = DATETIMES[index][Hour] + fDuration->fValue[Hour] + carry;\r
+    carry = fQuotient(temp, 24);\r
+    fNewDate->fValue[Hour] = mod(temp, 24, carry);\r
+               \r
+    fNewDate->fValue[Day] =\r
+        DATETIMES[index][Day] + fDuration->fValue[Day] + carry;\r
+\r
+    while ( true )\r
+    {\r
+        temp = maxDayInMonthFor(fNewDate->fValue[CentYear], fNewDate->fValue[Month]);\r
+        if ( fNewDate->fValue[Day] < 1 )\r
+        { //original fNewDate was negative\r
+            fNewDate->fValue[Day] +=\r
+                maxDayInMonthFor(fNewDate->fValue[CentYear], fNewDate->fValue[Month]-1);\r
+            carry = -1;\r
+        }\r
+        else if ( fNewDate->fValue[Day] > temp )\r
+        {\r
+            fNewDate->fValue[Day] -= temp;\r
+            carry = 1;\r
+        }\r
+        else\r
+        {\r
+            break;\r
+        }\r
+\r
+        temp = fNewDate->fValue[Month] + carry;\r
+        fNewDate->fValue[Month] = modulo(temp, 1, 13);\r
+        fNewDate->fValue[CentYear] += fQuotient(temp, 1, 13);\r
+    }\r
+\r
+    //fNewDate->fValue[utc] = UTC_STD_CHAR;\r
+    fNewDate->fValue[utc] = UTC_STD;\r
+}\r
+\r
+int DateTime::compareResult(int resultA\r
+                             , int resultB\r
+                             , bool strict)\r
+{\r
+\r
+    if ( resultB == XMLDateTime::INDETERMINATE )\r
+    {\r
+        return XMLDateTime::INDETERMINATE;\r
+    }\r
+    else if ( (resultA != resultB) &&\r
+              strict                )\r
+    {\r
+        return XMLDateTime::INDETERMINATE;\r
+    }\r
+    else if ( (resultA != resultB) &&\r
+              !strict               )\r
+    {\r
+        if ( (resultA != XMLDateTime::EQUAL) &&\r
+             (resultB != XMLDateTime::EQUAL)  )\r
+        {\r
+            return XMLDateTime::INDETERMINATE;\r
+        }\r
+        else\r
+        {\r
+            return (resultA != XMLDateTime::EQUAL)? resultA : resultB;\r
+        }\r
+    }\r
+\r
+    return resultA;\r
+       \r
+}\r
+\r
+// ---------------------------------------------------------------------------\r
+//  static methods : for others\r
+// ---------------------------------------------------------------------------\r
+int DateTime::compare(const DateTime* const pDate1\r
+                       , const DateTime* const pDate2)\r
+{\r
+\r
+    if (pDate1->fValue[utc] == pDate2->fValue[utc])\r
+    {\r
+        return DateTime::compareOrder(pDate1, pDate2);\r
+    }\r
+\r
+    int c1, c2;\r
+\r
+    if ( pDate1->isNormalized())\r
+    {\r
+        c1 = compareResult(pDate1, pDate2, false, UTC_POS);\r
+        c2 = compareResult(pDate1, pDate2, false, UTC_NEG);\r
+        return getRetVal(c1, c2);\r
+    }\r
+    else if ( pDate2->isNormalized())\r
+    {\r
+        c1 = compareResult(pDate1, pDate2, true, UTC_POS);\r
+        c2 = compareResult(pDate1, pDate2, true, UTC_NEG);\r
+        return getRetVal(c1, c2);\r
+    }\r
+\r
+    return XMLDateTime::INDETERMINATE; \r
+}\r
+\r
+int DateTime::compareResult(const DateTime* const pDate1\r
+                             , const DateTime* const pDate2\r
+                             , bool  set2Left\r
+                             , int   utc_type)\r
+{\r
+    DateTime tmpDate = (set2Left ? *pDate1 : *pDate2);\r
+\r
+    tmpDate.fTimeZone[hh] = 14;\r
+    tmpDate.fTimeZone[mm] = 0;\r
+    tmpDate.fValue[utc] = utc_type;\r
+    tmpDate.normalize();\r
+\r
+    return (set2Left? DateTime::compareOrder(&tmpDate, pDate2) :\r
+                      DateTime::compareOrder(pDate1, &tmpDate));\r
+}\r
+\r
+int DateTime::compareOrder(const DateTime* const lValue\r
+                            , const DateTime* const rValue)\r
+                            //, MemoryManager* const memMgr)\r
+{\r
+    //\r
+    // If any of the them is not normalized() yet,\r
+    // we need to do something here.\r
+    //\r
+    DateTime lTemp = *lValue;\r
+    DateTime rTemp = *rValue;\r
+\r
+    lTemp.normalize();\r
+    rTemp.normalize();\r
+\r
+    for ( int i = 0 ; i < TOTAL_SIZE; i++ )\r
+    {\r
+        if ( lTemp.fValue[i] < rTemp.fValue[i] )\r
+        {\r
+            return XMLDateTime::LESS_THAN;\r
+        }\r
+        else if ( lTemp.fValue[i] > rTemp.fValue[i] )\r
+        {\r
+            return XMLDateTime::GREATER_THAN;\r
+        }\r
+    }\r
+\r
+    if ( lTemp.fHasTime)\r
+    {\r
+        if ( lTemp.fMiliSecond < rTemp.fMiliSecond )\r
+        {\r
+            return XMLDateTime::LESS_THAN;\r
+        }\r
+        else if ( lTemp.fMiliSecond > rTemp.fMiliSecond )\r
+        {\r
+            return XMLDateTime::GREATER_THAN;\r
+        }\r
+    }\r
+\r
+    return XMLDateTime::EQUAL;\r
+}\r
+\r
+// ---------------------------------------------------------------------------\r
+//  ctor and dtor\r
+// ---------------------------------------------------------------------------\r
+DateTime::~DateTime()\r
+{\r
+    delete[] fBuffer;\r
+}\r
+\r
+DateTime::DateTime()\r
+: fStart(0)\r
+, fEnd(0)\r
+, fBufferMaxLen(0)\r
+, fBuffer(0)\r
+, fMiliSecond(0)\r
+, fHasTime(false)\r
+{\r
+    reset();\r
+}\r
+\r
+DateTime::DateTime(const XMLCh* const aString)\r
+: fStart(0)\r
+, fEnd(0)\r
+, fBufferMaxLen(0)\r
+, fBuffer(0)\r
+, fMiliSecond(0)\r
+, fHasTime(false)\r
+{\r
+    setBuffer(aString);\r
+}\r
+\r
+DateTime::DateTime(time_t epoch)\r
+: fStart(0)\r
+, fEnd(0)\r
+, fBufferMaxLen(0)\r
+, fBuffer(0)\r
+, fMiliSecond(0)\r
+, fHasTime(false)\r
+{\r
+#ifndef HAVE_GMTIME_R\r
+    struct tm* ptime=gmtime(&epoch);\r
+#else\r
+    struct tm res;\r
+    struct tm* ptime=gmtime_r(&epoch,&res);\r
+#endif\r
+    char timebuf[32];\r
+    strftime(timebuf,32,"%Y-%m-%dT%H:%M:%SZ",ptime);\r
+    auto_ptr_XMLCh timeptr(timebuf);\r
+    setBuffer(timeptr.get());\r
+}\r
+\r
+// -----------------------------------------------------------------------\r
+// Copy ctor and Assignment operators\r
+// -----------------------------------------------------------------------\r
+\r
+DateTime::DateTime(const DateTime &toCopy)\r
+: fBufferMaxLen(0)\r
+, fBuffer(0)\r
+{\r
+    copy(toCopy);\r
+}\r
+\r
+DateTime& DateTime::operator=(const DateTime& rhs)\r
+{\r
+    if (this == &rhs)\r
+        return *this;\r
+\r
+    copy(rhs);\r
+    return *this;\r
+}\r
+\r
+// -----------------------------------------------------------------------\r
+// Implementation of Abstract Interface\r
+// -----------------------------------------------------------------------\r
+\r
+//\r
+// We may simply return the handle to fBuffer\r
+//\r
+const XMLCh*  DateTime::getRawData() const\r
+{\r
+    //assertBuffer();\r
+    return fBuffer;\r
+}\r
+\r
+\r
+const XMLCh*  DateTime::getFormattedString() const\r
+{\r
+    return getRawData();\r
+}\r
+\r
+int DateTime::getSign() const\r
+{\r
+    return 0;\r
+}\r
+\r
+time_t DateTime::getEpoch() const\r
+{\r
+    struct tm t;\r
+    t.tm_sec=getSecond();\r
+    t.tm_min=getMinute();\r
+    t.tm_hour=getHour();\r
+    t.tm_mday=getDay();\r
+    t.tm_mon=getMonth()-1;\r
+    t.tm_year=getYear()-1900;\r
+    t.tm_isdst=0;\r
+#if defined(HAVE_TIMEGM)\r
+    return timegm(&t);\r
+#else\r
+    // Windows, and hopefully most others...?\r
+    return mktime(&t) - timezone;\r
+#endif\r
+}\r
+\r
+// ---------------------------------------------------------------------------\r
+//  Parsers\r
+// ---------------------------------------------------------------------------\r
+\r
+//\r
+// [-]{CCYY-MM-DD}'T'{HH:MM:SS.MS}[TimeZone]\r
+//\r
+void DateTime::parseDateTime()\r
+{\r
+    initParser();\r
+    getDate();\r
+\r
+    //fStart is supposed to point to 'T'\r
+    if (fBuffer[fStart++] != DATETIME_SEPARATOR)\r
+        ThrowXML1(SchemaDateTimeException\r
+                , XMLExcepts::DateTime_gDay_invalid\r
+                , fBuffer);\r
+\r
+    getTime();\r
+    validateDateTime();\r
+    normalize();\r
+    fHasTime = true;\r
+}\r
+\r
+//\r
+// [-]{CCYY-MM-DD}[TimeZone]\r
+//\r
+void DateTime::parseDate()\r
+{\r
+    initParser();\r
+    getDate();\r
+    parseTimeZone();\r
+    validateDateTime();\r
+    normalize();\r
+}\r
+\r
+void DateTime::parseTime()\r
+{\r
+    initParser();\r
+\r
+    // time initialize to default values\r
+    fValue[CentYear]= YEAR_DEFAULT;\r
+    fValue[Month]   = MONTH_DEFAULT;\r
+    fValue[Day]     = DAY_DEFAULT;\r
+\r
+    getTime();\r
+\r
+    validateDateTime();\r
+    normalize();\r
+    fHasTime = true;\r
+}\r
+\r
+//\r
+// {---DD}[TimeZone]\r
+//  01234\r
+//\r
+void DateTime::parseDay()\r
+{\r
+    initParser();\r
+\r
+    if (fBuffer[0] != DATE_SEPARATOR ||\r
+        fBuffer[1] != DATE_SEPARATOR ||\r
+        fBuffer[2] != DATE_SEPARATOR  )\r
+    {\r
+        ThrowXML1(SchemaDateTimeException\r
+                , XMLExcepts::DateTime_gDay_invalid\r
+                , fBuffer);\r
+    }\r
+\r
+    //initialize values\r
+    fValue[CentYear] = YEAR_DEFAULT;\r
+    fValue[Month]    = MONTH_DEFAULT;\r
+    fValue[Day]      = parseInt(fStart+3, fStart+5);\r
+\r
+    if ( DAY_SIZE < fEnd )\r
+    {\r
+        int sign = findUTCSign(DAY_SIZE);\r
+        if ( sign < 0 )\r
+        {\r
+            ThrowXML1(SchemaDateTimeException\r
+                    , XMLExcepts::DateTime_gDay_invalid\r
+                    , fBuffer);\r
+        }\r
+        else\r
+        {\r
+            getTimeZone(sign);\r
+        }\r
+    }\r
+\r
+    validateDateTime();\r
+    normalize();\r
+}\r
+\r
+//\r
+// {--MM--}[TimeZone]\r
+// {--MM}[TimeZone]\r
+//  012345\r
+//\r
+void DateTime::parseMonth()\r
+{\r
+    initParser();\r
+\r
+    if (fBuffer[0] != DATE_SEPARATOR ||\r
+        fBuffer[1] != DATE_SEPARATOR  )\r
+    {\r
+        ThrowXML1(SchemaDateTimeException\r
+                , XMLExcepts::DateTime_gMth_invalid\r
+                , fBuffer);\r
+    }\r
+\r
+    //set constants\r
+    fValue[CentYear] = YEAR_DEFAULT;\r
+    fValue[Day]      = DAY_DEFAULT;\r
+    fValue[Month]    = parseInt(2, 4);\r
+\r
+    // REVISIT: allow both --MM and --MM-- now. \r
+    // need to remove the following lines to disallow --MM-- \r
+    // when the errata is officially in the rec. \r
+    fStart = 4;\r
+    if ( fEnd >= fStart+2 && fBuffer[fStart] == DATE_SEPARATOR && fBuffer[fStart+1] == DATE_SEPARATOR ) \r
+    { \r
+        fStart += 2; \r
+    } \r
+\r
+    //\r
+    // parse TimeZone if any\r
+    //\r
+    if ( fStart < fEnd )\r
+    {\r
+        int sign = findUTCSign(fStart);\r
+        if ( sign < 0 )\r
+        {\r
+            ThrowXML1(SchemaDateTimeException\r
+                    , XMLExcepts::DateTime_gMth_invalid\r
+                    , fBuffer);\r
+        }\r
+        else\r
+        {\r
+            getTimeZone(sign);\r
+        }\r
+    }\r
+\r
+    validateDateTime();\r
+    normalize();\r
+}\r
+\r
+//\r
+//[-]{CCYY}[TimeZone]\r
+// 0  1234\r
+//\r
+void DateTime::parseYear()\r
+{\r
+    initParser();\r
+\r
+    // skip the first '-' and search for timezone\r
+    //\r
+    int sign = findUTCSign((fBuffer[0] == chDash) ? 1 : 0);\r
+\r
+    if (sign == NOT_FOUND)\r
+    {\r
+        fValue[CentYear] = parseIntYear(fEnd);\r
+    }\r
+    else\r
+    {\r
+        fValue[CentYear] = parseIntYear(sign);\r
+        getTimeZone(sign);\r
+    }\r
+\r
+    //initialize values\r
+    fValue[Month] = MONTH_DEFAULT;\r
+    fValue[Day]   = DAY_DEFAULT;   //java is 1\r
+\r
+    validateDateTime();\r
+    normalize();\r
+}\r
+\r
+//\r
+//{--MM-DD}[TimeZone]\r
+// 0123456\r
+//\r
+void DateTime::parseMonthDay()\r
+{\r
+    initParser();\r
+\r
+    if (fBuffer[0] != DATE_SEPARATOR ||\r
+        fBuffer[1] != DATE_SEPARATOR ||\r
+        fBuffer[4] != DATE_SEPARATOR )\r
+    {\r
+        ThrowXML1(SchemaDateTimeException\r
+                , XMLExcepts::DateTime_gMthDay_invalid\r
+                , fBuffer);\r
+    }\r
+\r
+\r
+    //initialize\r
+    fValue[CentYear] = YEAR_DEFAULT;\r
+    fValue[Month]    = parseInt(2, 4); \r
+    fValue[Day]      = parseInt(5, 7);\r
+\r
+    if ( MONTHDAY_SIZE < fEnd )\r
+    {\r
+        int sign = findUTCSign(MONTHDAY_SIZE);\r
+        if ( sign<0 )\r
+        {\r
+            ThrowXML1(SchemaDateTimeException\r
+                    , XMLExcepts::DateTime_gMthDay_invalid\r
+                    , fBuffer);\r
+        }\r
+        else\r
+        {\r
+            getTimeZone(sign);\r
+        }\r
+    }\r
+\r
+    validateDateTime();\r
+    normalize();\r
+}\r
+\r
+void DateTime::parseYearMonth()\r
+{\r
+    initParser();\r
+\r
+    // get date\r
+    getYearMonth();\r
+    fValue[Day] = DAY_DEFAULT;\r
+    parseTimeZone();\r
+\r
+    validateDateTime();\r
+    normalize();\r
+}\r
+\r
+//\r
+//PnYn MnDTnH nMnS: -P1Y2M3DT10H30M\r
+//\r
+// [-]{'P'{[n'Y'][n'M'][n'D']['T'][n'H'][n'M'][n'S']}}\r
+//\r
+//  Note: the n above shall be >= 0\r
+//        if no time element found, 'T' shall be absent\r
+//\r
+void DateTime::parseDuration()\r
+{\r
+    initParser();\r
+\r
+    // must start with '-' or 'P'\r
+    //\r
+    XMLCh c = fBuffer[fStart++];\r
+    if ( (c != DURATION_STARTER) &&\r
+         (c != chDash)            )\r
+    {\r
+        ThrowXML1(SchemaDateTimeException\r
+                , XMLExcepts::DateTime_dur_Start_dashP\r
+                , fBuffer);\r
+    }\r
+\r
+    // 'P' must ALWAYS be present in either case\r
+    if ( (c == chDash) &&\r
+         (fBuffer[fStart++]!= DURATION_STARTER ))\r
+    {\r
+        ThrowXML1(SchemaDateTimeException\r
+                , XMLExcepts::DateTime_dur_noP\r
+                , fBuffer);\r
+    }\r
+\r
+    // java code\r
+    //date[utc]=(c=='-')?'-':0;\r
+    //fValue[utc] = UTC_STD;\r
+    fValue[utc] = (fBuffer[0] == chDash? UTC_NEG : UTC_STD);\r
+\r
+    int negate = ( fBuffer[0] == chDash ? -1 : 1);\r
+\r
+    //\r
+    // No negative value is allowed after 'P'\r
+    //\r
+    // eg P-1234, invalid\r
+    //\r
+    if (indexOf(fStart, fEnd, chDash) != NOT_FOUND)\r
+    {\r
+        ThrowXML1(SchemaDateTimeException\r
+                , XMLExcepts::DateTime_dur_DashNotFirst\r
+                , fBuffer);\r
+    }\r
+\r
+    //at least one number and designator must be seen after P\r
+    bool designator = false;\r
+\r
+    int endDate = indexOf(fStart, fEnd, DATETIME_SEPARATOR);\r
+    if ( endDate == NOT_FOUND )\r
+    {\r
+        endDate = fEnd;  // 'T' absent\r
+    }\r
+\r
+    //find 'Y'\r
+    int end = indexOf(fStart, endDate, DURATION_Y);\r
+    if ( end != NOT_FOUND )\r
+    {\r
+        //scan year\r
+        fValue[CentYear] = negate * parseInt(fStart, end);\r
+        fStart = end+1;\r
+        designator = true;\r
+    }\r
+\r
+    end = indexOf(fStart, endDate, DURATION_M);\r
+    if ( end != NOT_FOUND )\r
+    {\r
+        //scan month\r
+        fValue[Month] = negate * parseInt(fStart, end);\r
+        fStart = end+1;\r
+        designator = true;\r
+    }\r
+\r
+    end = indexOf(fStart, endDate, DURATION_D);\r
+    if ( end != NOT_FOUND )\r
+    {\r
+        //scan day\r
+        fValue[Day] = negate * parseInt(fStart,end);\r
+        fStart = end+1;\r
+        designator = true;\r
+    }\r
+\r
+    if ( (fEnd == endDate) &&   // 'T' absent\r
+         (fStart != fEnd)   )   // something after Day\r
+    {\r
+        ThrowXML1(SchemaDateTimeException\r
+                , XMLExcepts::DateTime_dur_inv_b4T\r
+                , fBuffer);\r
+    }\r
+\r
+    if ( fEnd != endDate ) // 'T' present\r
+    {\r
+        //scan hours, minutes, seconds\r
+        //\r
+\r
+        // skip 'T' first\r
+        end = indexOf(++fStart, fEnd, DURATION_H);\r
+        if ( end != NOT_FOUND )\r
+        {\r
+            //scan hours\r
+            fValue[Hour] = negate * parseInt(fStart, end);\r
+            fStart = end+1;\r
+            designator = true;\r
+        }\r
+\r
+        end = indexOf(fStart, fEnd, DURATION_M);\r
+        if ( end != NOT_FOUND )\r
+        {\r
+            //scan min\r
+            fValue[Minute] = negate * parseInt(fStart, end);\r
+            fStart = end+1;\r
+            designator = true;\r
+        }\r
+\r
+        end = indexOf(fStart, fEnd, DURATION_S);\r
+        if ( end != NOT_FOUND )\r
+        {\r
+            //scan seconds\r
+            int mlsec = indexOf (fStart, end, MILISECOND_SEPARATOR);\r
+\r
+            /***\r
+             * Schema Errata: E2-23\r
+             * at least one digit must follow the decimal point if it appears. \r
+             * That is, the value of the seconds component must conform \r
+             * to the following pattern: [0-9]+(.[0-9]+)? \r
+             */\r
+            if ( mlsec != NOT_FOUND )\r
+            {\r
+                /***\r
+                 * make usure there is something after the '.' and before the end.\r
+                 */\r
+                if ( mlsec+1 == end )\r
+                {\r
+                    ThrowXML1(SchemaDateTimeException\r
+                            , XMLExcepts::DateTime_dur_inv_seconds\r
+                            , fBuffer);\r
+                }\r
+\r
+                fValue[Second]     = negate * parseInt(fStart, mlsec);\r
+                fMiliSecond        = negate * parseMiliSecond(mlsec+1, end);\r
+            }\r
+            else\r
+            {\r
+                fValue[Second] = negate * parseInt(fStart,end);\r
+            }\r
+\r
+            fStart = end+1;\r
+            designator = true;\r
+        }\r
+\r
+        // no additional data should appear after last item\r
+        // P1Y1M1DT is illigal value as well\r
+        if ( (fStart != fEnd) ||\r
+              fBuffer[--fStart] == DATETIME_SEPARATOR )\r
+        {\r
+            ThrowXML1(SchemaDateTimeException\r
+                    , XMLExcepts::DateTime_dur_NoTimeAfterT\r
+                    , fBuffer);\r
+        }\r
+    }\r
+\r
+    if ( !designator )\r
+    {\r
+        ThrowXML1(SchemaDateTimeException\r
+                , XMLExcepts::DateTime_dur_NoElementAtAll\r
+                , fBuffer);\r
+    }\r
+\r
+}\r
+\r
+// ---------------------------------------------------------------------------\r
+//  Scanners\r
+// ---------------------------------------------------------------------------\r
+\r
+//\r
+// [-]{CCYY-MM-DD}\r
+//\r
+// Note: CCYY could be more than 4 digits\r
+//       Assuming fStart point to the beginning of the Date Section\r
+//       fStart updated to point to the position right AFTER the second 'D'\r
+//       Since the lenght of CCYY might be variable, we can't check format upfront\r
+//\r
+void DateTime::getDate()\r
+{\r
+\r
+    // Ensure enough chars in buffer\r
+    if ( (fStart+YMD_MIN_SIZE) > fEnd)\r
+        ThrowXML1(SchemaDateTimeException\r
+                , XMLExcepts::DateTime_date_incomplete\r
+                , fBuffer);\r
+\r
+    getYearMonth();    // Scan YearMonth and\r
+                       // fStart point to the next '-'\r
+\r
+    if (fBuffer[fStart++] != DATE_SEPARATOR)\r
+    {\r
+        ThrowXML1(SchemaDateTimeException\r
+                , XMLExcepts::DateTime_date_invalid\r
+                , fBuffer);\r
+        //("CCYY-MM must be followed by '-' sign");\r
+    }\r
+\r
+    fValue[Day] = parseInt(fStart, fStart+2);\r
+    fStart += 2 ;  //fStart points right after the Day\r
+\r
+    return;\r
+}\r
+\r
+//\r
+// hh:mm:ss[.msssss]['Z']\r
+// hh:mm:ss[.msssss][['+'|'-']hh:mm]\r
+// 012345678\r
+//\r
+// Note: Assuming fStart point to the beginning of the Time Section\r
+//       fStart updated to point to the position right AFTER the second 's'\r
+//                                                  or ms if any\r
+//\r
+void DateTime::getTime()\r
+{\r
+\r
+    // Ensure enough chars in buffer\r
+    if ( (fStart+TIME_MIN_SIZE) > fEnd)\r
+        ThrowXML1(SchemaDateTimeException\r
+                , XMLExcepts::DateTime_time_incomplete\r
+                , fBuffer);\r
+        //"Imcomplete Time Format"\r
+\r
+    // check (fixed) format first\r
+    if ((fBuffer[fStart + 2] != TIME_SEPARATOR) ||\r
+        (fBuffer[fStart + 5] != TIME_SEPARATOR)  )\r
+    {\r
+        ThrowXML1(SchemaDateTimeException\r
+                , XMLExcepts::DateTime_time_invalid\r
+                , fBuffer);\r
+        //("Error in parsing time" );\r
+    }\r
+\r
+    //\r
+    // get hours, minute and second\r
+    //\r
+    fValue[Hour]   = parseInt(fStart + 0, fStart + 2);\r
+    fValue[Minute] = parseInt(fStart + 3, fStart + 5);\r
+    fValue[Second] = parseInt(fStart + 6, fStart + 8);\r
+    fStart += 8;\r
+\r
+    // to see if any ms and/or utc part after that\r
+    if (fStart >= fEnd)\r
+        return;\r
+\r
+    //find UTC sign if any\r
+    int sign = findUTCSign(fStart);\r
+\r
+    //parse miliseconds\r
+    int milisec = (fBuffer[fStart] == MILISECOND_SEPARATOR)? fStart : NOT_FOUND;\r
+    if ( milisec != NOT_FOUND )\r
+    {\r
+        fStart++;   // skip the '.'\r
+        // make sure we have some thing between the '.' and fEnd\r
+        if (fStart >= fEnd)\r
+        {\r
+            ThrowXML1(SchemaDateTimeException\r
+                    , XMLExcepts::DateTime_ms_noDigit\r
+                    , fBuffer);\r
+            //("ms shall be present once '.' is present" );\r
+        }\r
+\r
+        if ( sign == NOT_FOUND )\r
+        {\r
+            fMiliSecond = parseMiliSecond(fStart, fEnd);  //get ms between '.' and fEnd\r
+            fStart = fEnd;\r
+        }\r
+        else\r
+        {\r
+            fMiliSecond = parseMiliSecond(fStart, sign);  //get ms between UTC sign and fEnd\r
+        }\r
+       }\r
+    else if(sign == 0 || sign != fStart)\r
+    {\r
+        // seconds has more than 2 digits\r
+        ThrowXML1(SchemaDateTimeException\r
+                , XMLExcepts::DateTime_min_invalid\r
+                , fBuffer);\r
+    }\r
+\r
+    //parse UTC time zone (hh:mm)\r
+    if ( sign > 0 ) {\r
+        getTimeZone(sign);\r
+    }\r
+\r
+}\r
+\r
+//\r
+// [-]{CCYY-MM}\r
+//\r
+// Note: CCYY could be more than 4 digits\r
+//       fStart updated to point AFTER the second 'M' (probably meet the fEnd)\r
+//\r
+void DateTime::getYearMonth()\r
+{\r
+\r
+    // Ensure enough chars in buffer\r
+    if ( (fStart+YMONTH_MIN_SIZE) > fEnd)\r
+        ThrowXML1(SchemaDateTimeException\r
+                , XMLExcepts::DateTime_ym_incomplete\r
+                , fBuffer);\r
+        //"Imcomplete YearMonth Format";\r
+\r
+    // skip the first leading '-'\r
+    int start = ( fBuffer[0] == chDash ) ? fStart + 1 : fStart;\r
+\r
+    //\r
+    // search for year separator '-'\r
+    //\r
+    int yearSeparator = indexOf(start, fEnd, DATE_SEPARATOR);\r
+    if ( yearSeparator == NOT_FOUND)\r
+        ThrowXML1(SchemaDateTimeException\r
+                , XMLExcepts::DateTime_ym_invalid\r
+                , fBuffer);\r
+        //("Year separator is missing or misplaced");\r
+\r
+    fValue[CentYear] = parseIntYear(yearSeparator);\r
+    fStart = yearSeparator + 1;  //skip the '-' and point to the first M\r
+\r
+    //\r
+    //gonna check we have enough byte for month\r
+    //\r
+    if ((fStart + 2) > fEnd )\r
+        ThrowXML1(SchemaDateTimeException\r
+                , XMLExcepts::DateTime_ym_noMonth\r
+                , fBuffer);\r
+        //"no month in buffer"\r
+\r
+    fValue[Month] = parseInt(fStart, yearSeparator + 3);\r
+    fStart += 2;  //fStart points right after the MONTH\r
+\r
+    return;\r
+}\r
+\r
+void DateTime::parseTimeZone()\r
+{\r
+    if ( fStart < fEnd )\r
+    {\r
+        int sign = findUTCSign(fStart);\r
+        if ( sign < 0 )\r
+        {\r
+            ThrowXML1(SchemaDateTimeException\r
+                    , XMLExcepts::DateTime_tz_noUTCsign\r
+                    , fBuffer);\r
+            //("Error in month parsing");\r
+        }\r
+        else\r
+        {\r
+            getTimeZone(sign);\r
+        }\r
+    }\r
+\r
+    return;\r
+}\r
+\r
+//\r
+// 'Z'\r
+// ['+'|'-']hh:mm\r
+//\r
+// Note: Assuming fStart points to the beginning of TimeZone section\r
+//       fStart updated to meet fEnd\r
+//\r
+void DateTime::getTimeZone(const int sign)\r
+{\r
+\r
+    if ( fBuffer[sign] == UTC_STD_CHAR )\r
+    {\r
+        if ((sign + 1) != fEnd )\r
+        {\r
+            ThrowXML1(SchemaDateTimeException\r
+                    , XMLExcepts::DateTime_tz_stuffAfterZ\r
+                    , fBuffer);\r
+            //"Error in parsing time zone");\r
+        }              \r
+\r
+        return;        \r
+    }\r
+\r
+    //\r
+    // otherwise, it has to be this format\r
+    // '[+|-]'hh:mm\r
+    //    1   23456 7\r
+    //   sign      fEnd\r
+    //\r
+    if ( ( ( sign + TIMEZONE_SIZE + 1) != fEnd )      ||\r
+         ( fBuffer[sign + 3] != TIMEZONE_SEPARATOR ) )\r
+    {\r
+        ThrowXML1(SchemaDateTimeException\r
+                , XMLExcepts::DateTime_tz_invalid\r
+                , fBuffer);\r
+        //("Error in parsing time zone");\r
+    }\r
+\r
+    fTimeZone[hh] = parseInt(sign+1, sign+3);          \r
+    fTimeZone[mm] = parseInt(sign+4, fEnd);\r
+                       \r
+    return;\r
+}\r
+\r
+// ---------------------------------------------------------------------------\r
+//  Validator and normalizer\r
+// ---------------------------------------------------------------------------\r
+\r
+/**\r
+ * If timezone present - normalize dateTime  [E Adding durations to dateTimes]\r
+ *\r
+ * @param date   CCYY-MM-DDThh:mm:ss+03\r
+ * @return CCYY-MM-DDThh:mm:ssZ\r
+ */\r
+void DateTime::normalize()\r
+{\r
+\r
+    if ((fValue[utc] == UTC_UNKNOWN) ||\r
+        (fValue[utc] == UTC_STD)      )\r
+        return;\r
+\r
+    int negate = (fValue[utc] == UTC_POS)? -1: 1;\r
+\r
+    // add mins\r
+    int temp = fValue[Minute] + negate * fTimeZone[mm];\r
+    int carry = fQuotient(temp, 60);\r
+    fValue[Minute] = mod(temp, 60, carry);\r
+\r
+    //add hours\r
+    temp = fValue[Hour] + negate * fTimeZone[hh] + carry;\r
+    carry = fQuotient(temp, 24);\r
+    fValue[Hour] = mod(temp, 24, carry);\r
+\r
+    fValue[Day] += carry;\r
+\r
+    while (1)\r
+    {\r
+        temp = maxDayInMonthFor(fValue[CentYear], fValue[Month]);\r
+        if (fValue[Day] < 1)\r
+        {\r
+            fValue[Day] += maxDayInMonthFor(fValue[CentYear], fValue[Month] - 1);\r
+            carry = -1;\r
+        }\r
+        else if ( fValue[Day] > temp )\r
+        {\r
+            fValue[Day] -= temp;\r
+            carry = 1;\r
+        }\r
+        else\r
+        {\r
+            break;\r
+        }\r
+\r
+        temp = fValue[Month] + carry;\r
+        fValue[Month] = modulo(temp, 1, 13);\r
+        fValue[CentYear] += fQuotient(temp, 1, 13);\r
+    }\r
+\r
+    // set to normalized\r
+    fValue[utc] = UTC_STD;\r
+\r
+    return;\r
+}\r
+\r
+void DateTime::validateDateTime() const\r
+{\r
+\r
+    //REVISIT: should we throw an exception for not valid dates\r
+    //          or reporting an error message should be sufficient?\r
+    if ( fValue[CentYear] == 0 )\r
+    {\r
+        ThrowXML1(SchemaDateTimeException\r
+                , XMLExcepts::DateTime_year_zero\r
+                , fBuffer);\r
+        //"The year \"0000\" is an illegal year value");\r
+    }\r
+\r
+    if ( fValue[Month] < 1  ||\r
+         fValue[Month] > 12  )\r
+    {\r
+        ThrowXML1(SchemaDateTimeException\r
+                , XMLExcepts::DateTime_mth_invalid\r
+                , fBuffer);\r
+               //"The month must have values 1 to 12");\r
+    }\r
+\r
+    //validate days\r
+    if ( fValue[Day] > maxDayInMonthFor( fValue[CentYear], fValue[Month]) ||\r
+         fValue[Day] == 0 )\r
+    {\r
+        ThrowXML1(SchemaDateTimeException\r
+                , XMLExcepts::DateTime_day_invalid\r
+                , fBuffer);\r
+        //"The day must have values 1 to 31");\r
+    }\r
+\r
+    //validate hours\r
+    if ((fValue[Hour] < 0)  ||\r
+        (fValue[Hour] > 24) ||\r
+        ((fValue[Hour] == 24) && ((fValue[Minute] !=0) ||\r
+                                  (fValue[Second] !=0) ||\r
+                                  (fMiliSecond    !=0))))\r
+    {\r
+        ThrowXML1(SchemaDateTimeException\r
+                , XMLExcepts::DateTime_hour_invalid\r
+                , fBuffer);\r
+        //("Hour must have values 0-23");\r
+    }\r
+\r
+    //validate minutes\r
+    if ( fValue[Minute] < 0 ||\r
+         fValue[Minute] > 59 )\r
+    {\r
+        ThrowXML1(SchemaDateTimeException\r
+                , XMLExcepts::DateTime_min_invalid\r
+                , fBuffer);\r
+        //"Minute must have values 0-59");\r
+    }\r
+\r
+    //validate seconds\r
+    if ( fValue[Second] < 0 ||\r
+         fValue[Second] > 60 )\r
+    {\r
+        ThrowXML1(SchemaDateTimeException\r
+                , XMLExcepts::DateTime_second_invalid\r
+                , fBuffer);\r
+        //"Second must have values 0-60");\r
+    }\r
+\r
+    //validate time-zone hours\r
+    if ( (abs(fTimeZone[hh]) > 14) ||\r
+         ((abs(fTimeZone[hh]) == 14) && (fTimeZone[mm] != 0)) )\r
+    {\r
+        ThrowXML1(SchemaDateTimeException\r
+                , XMLExcepts::DateTime_tz_hh_invalid\r
+                , fBuffer);\r
+        //"Time zone should have range -14..+14");\r
+    }\r
+\r
+    //validate time-zone minutes\r
+    if ( abs(fTimeZone[mm]) > 59 )\r
+    {\r
+        ThrowXML1(SchemaDateTimeException\r
+                , XMLExcepts::DateTime_min_invalid\r
+                , fBuffer);\r
+        //("Minute must have values 0-59");\r
+    }\r
+       \r
+    return;\r
+}\r
+\r
+// -----------------------------------------------------------------------\r
+// locator and converter\r
+// -----------------------------------------------------------------------\r
+int DateTime::indexOf(const int start, const int end, const XMLCh ch) const\r
+{\r
+    for ( int i = start; i < end; i++ )\r
+        if ( fBuffer[i] == ch )\r
+            return i;\r
+\r
+    return NOT_FOUND;\r
+}\r
+\r
+int DateTime::findUTCSign (const int start)\r
+{\r
+    int  pos;\r
+    for ( int index = start; index < fEnd; index++ )\r
+    {\r
+        pos = XMLString::indexOf(UTC_SET, fBuffer[index]);\r
+        if ( pos != NOT_FOUND)\r
+        {\r
+            fValue[utc] = pos+1;   // refer to utcType, there is 1 diff\r
+            return index;\r
+        }\r
+    }\r
+\r
+    return NOT_FOUND;\r
+}\r
+\r
+//\r
+// Note:\r
+//    start: starting point in fBuffer\r
+//    end:   ending point in fBuffer (exclusive)\r
+//    fStart NOT updated\r
+//\r
+int DateTime::parseInt(const int start, const int end) const\r
+{\r
+    unsigned int retVal = 0;\r
+    for (int i=start; i < end; i++) {\r
+\r
+        if (fBuffer[i] < chDigit_0 || fBuffer[i] > chDigit_9)\r
+            ThrowXML(NumberFormatException, XMLExcepts::XMLNUM_Inv_chars);\r
+\r
+        retVal = (retVal * 10) + (unsigned int) (fBuffer[i] - chDigit_0);\r
+    }\r
+\r
+    return (int) retVal;\r
+}\r
+\r
+//\r
+// Note:\r
+//    start: pointing to the first digit after the '.'\r
+//    end:   pointing to one position after the last digit\r
+//    fStart NOT updated\r
+//\r
+double DateTime::parseMiliSecond(const int start, const int end) const\r
+{\r
+\r
+    unsigned int  miliSecLen = (end-1) - (start-1) + 1; //to include the '.'\r
+    XMLCh* miliSecData = new XMLCh[miliSecLen + 1];\r
+    ArrayJanitor<XMLCh> janMili(miliSecData);\r
+    XMLString::copyNString(miliSecData, &(fBuffer[start-1]), miliSecLen);\r
+    *(miliSecData + miliSecLen) = chNull;\r
+\r
+    char *nptr = XMLString::transcode(miliSecData);\r
+    ArrayJanitor<char> jan(nptr);\r
+    size_t   strLen = strlen(nptr);\r
+    char *endptr = 0;\r
+    errno = 0;\r
+\r
+    //printf("milisec=<%s>\n", nptr);\r
+\r
+    double retVal = strtod(nptr, &endptr);\r
+\r
+    // check if all chars are valid char\r
+    if ( (endptr - nptr) != strLen)\r
+        ThrowXML(NumberFormatException, XMLExcepts::XMLNUM_Inv_chars);\r
+\r
+    // we don't check underflow occurs since\r
+    // nothing we can do about it.\r
+    return retVal;\r
+}\r
+\r
+//\r
+// [-]CCYY\r
+//\r
+// Note: start from fStart\r
+//       end (exclusive)\r
+//       fStart NOT updated\r
+//\r
+int DateTime::parseIntYear(const int end) const\r
+{\r
+    // skip the first leading '-'\r
+    int start = ( fBuffer[0] == chDash ) ? fStart + 1 : fStart;\r
+\r
+    int length = end - start;\r
+    if (length < 4)\r
+    {\r
+        ThrowXML1(SchemaDateTimeException\r
+                , XMLExcepts::DateTime_year_tooShort\r
+                , fBuffer);\r
+        //"Year must have 'CCYY' format");\r
+    }\r
+    else if (length > 4 &&\r
+             fBuffer[start] == chDigit_0)\r
+    {\r
+        ThrowXML1(SchemaDateTimeException\r
+                , XMLExcepts::DateTime_year_leadingZero\r
+                , fBuffer);\r
+        //"Leading zeros are required if the year value would otherwise have fewer than four digits;\r
+        // otherwise they are forbidden");\r
+    }\r
+\r
+    bool negative = (fBuffer[0] == chDash);\r
+    int  yearVal = parseInt((negative ? 1 : 0), end);\r
+    return ( negative ? (-1) * yearVal : yearVal );\r
+}\r
+\r
+/***\r
+ * E2-41\r
+ *\r
+ *  3.2.7.2 Canonical representation\r
+ * \r
+ *  Except for trailing fractional zero digits in the seconds representation, \r
+ *  '24:00:00' time representations, and timezone (for timezoned values), \r
+ *  the mapping from literals to values is one-to-one. Where there is more \r
+ *  than one possible representation, the canonical representation is as follows: \r
+ *  redundant trailing zero digits in fractional-second literals are prohibited. \r
+ *  An hour representation of '24' is prohibited. Timezoned values are canonically\r
+ *  represented by appending 'Z' to the nontimezoned representation. (All \r
+ *  timezoned dateTime values are UTC.) \r
+ *\r
+ *  .'24:00:00' -> '00:00:00'\r
+ *  .milisecond: trailing zeros removed\r
+ *  .'Z'\r
+ *\r
+ ***/\r
+XMLCh* DateTime::getDateTimeCanonicalRepresentation() const\r
+{\r
+    XMLCh *miliStartPtr, *miliEndPtr;\r
+    searchMiliSeconds(miliStartPtr, miliEndPtr);\r
+    size_t miliSecondsLen = miliEndPtr - miliStartPtr;\r
+\r
+    XMLCh* retBuf = new XMLCh[21 + miliSecondsLen + 2];\r
+    XMLCh* retPtr = retBuf;\r
+\r
+    // (-?) cc+yy-mm-dd'T'hh:mm:ss'Z'    ('.'s+)?\r
+    //      2+  8       1      8   1\r
+    //\r
+    int additionalLen = fillYearString(retPtr, CentYear);\r
+    if(additionalLen != 0)\r
+    {\r
+        // very bad luck; have to resize the buffer...\r
+        XMLCh *tmpBuf = new XMLCh[additionalLen+21+miliSecondsLen +2];\r
+        XMLString::moveChars(tmpBuf, retBuf, 4+additionalLen);\r
+        retPtr = tmpBuf+(retPtr-retBuf);\r
+        delete[] retBuf;\r
+        retBuf = tmpBuf;\r
+    }\r
+    *retPtr++ = DATE_SEPARATOR;\r
+    fillString(retPtr, Month, 2);\r
+    *retPtr++ = DATE_SEPARATOR;\r
+    fillString(retPtr, Day, 2);\r
+    *retPtr++ = DATETIME_SEPARATOR;\r
+\r
+    fillString(retPtr, Hour, 2);\r
+    if (fValue[Hour] == 24)\r
+    {\r
+        *(retPtr - 2) = chDigit_0;\r
+        *(retPtr - 1) = chDigit_0;\r
+    }\r
+    *retPtr++ = TIME_SEPARATOR;\r
+    fillString(retPtr, Minute, 2);\r
+    *retPtr++ = TIME_SEPARATOR;\r
+    fillString(retPtr, Second, 2);\r
+\r
+    if (miliSecondsLen)\r
+    {\r
+        *retPtr++ = chPeriod;\r
+        XMLString::copyNString(retPtr, miliStartPtr, miliSecondsLen);\r
+        retPtr += miliSecondsLen;\r
+    }\r
+\r
+    *retPtr++ = UTC_STD_CHAR;\r
+    *retPtr = chNull;\r
+\r
+    return retBuf;\r
+}\r
+\r
+/***\r
+ * 3.2.8 time\r
+ *\r
+ *  . either the time zone must be omitted or, \r
+ *    if present, the time zone must be Coordinated Universal Time (UTC) indicated by a "Z".   \r
+ *\r
+ *  . Additionally, the canonical representation for midnight is 00:00:00.\r
+ *\r
+***/\r
+XMLCh* DateTime::getTimeCanonicalRepresentation() const\r
+{\r
+    XMLCh *miliStartPtr, *miliEndPtr;\r
+    searchMiliSeconds(miliStartPtr, miliEndPtr);\r
+    size_t miliSecondsLen = miliEndPtr - miliStartPtr;\r
+\r
+    XMLCh* retBuf = new XMLCh[10 + miliSecondsLen + 2];\r
+    XMLCh* retPtr = retBuf;\r
+\r
+    // 'hh:mm:ss'Z'    ('.'s+)?\r
+    //      8    1\r
+    //\r
+\r
+    fillString(retPtr, Hour, 2);\r
+    if (fValue[Hour] == 24)\r
+    {\r
+        *(retPtr - 2) = chDigit_0;\r
+        *(retPtr - 1) = chDigit_0;\r
+    }\r
+    *retPtr++ = TIME_SEPARATOR;\r
+    fillString(retPtr, Minute, 2);\r
+    *retPtr++ = TIME_SEPARATOR;\r
+    fillString(retPtr, Second, 2);\r
+\r
+    if (miliSecondsLen)\r
+    {\r
+        *retPtr++ = chPeriod;\r
+        XMLString::copyNString(retPtr, miliStartPtr, miliSecondsLen);\r
+        retPtr += miliSecondsLen;\r
+    }\r
+\r
+    *retPtr++ = UTC_STD_CHAR;\r
+    *retPtr = chNull;\r
+\r
+    return retBuf;\r
+}\r
+\r
+void DateTime::fillString(XMLCh*& ptr, valueIndex ind, int expLen) const\r
+{\r
+    XMLCh strBuffer[16];\r
+    assert(expLen < 16);\r
+    XMLString::binToText(fValue[ind], strBuffer, expLen, 10);\r
+    int   actualLen = XMLString::stringLen(strBuffer);\r
+    int   i;\r
+    //append leading zeros\r
+    for (i = 0; i < expLen - actualLen; i++)\r
+    {\r
+        *ptr++ = chDigit_0;\r
+    }\r
+\r
+    for (i = 0; i < actualLen; i++)\r
+    {\r
+        *ptr++ = strBuffer[i];\r
+    }\r
+\r
+}\r
+\r
+int DateTime::fillYearString(XMLCh*& ptr, valueIndex ind) const\r
+{\r
+    XMLCh strBuffer[16];\r
+    // let's hope we get no years of 15 digits...\r
+    XMLString::binToText(fValue[ind], strBuffer, 15, 10);\r
+    int   actualLen = XMLString::stringLen(strBuffer);\r
+    // don't forget that years can be negative...\r
+    int negativeYear = 0;\r
+    if(strBuffer[0] == chDash)\r
+    {\r
+        *ptr++ = strBuffer[0];\r
+        negativeYear = 1;\r
+    }\r
+    int   i;\r
+    //append leading zeros\r
+    for (i = 0; i < 4 - actualLen+negativeYear; i++)\r
+    {\r
+        *ptr++ = chDigit_0;\r
+    }\r
+\r
+    for (i = negativeYear; i < actualLen; i++)\r
+    {\r
+        *ptr++ = strBuffer[i];\r
+    }\r
+    if(actualLen > 4)\r
+        return actualLen-4;\r
+    return 0;\r
+}\r
+\r
+/***\r
+ *\r
+ *   .check if the rawData has the mili second component\r
+ *   .capture the substring\r
+ *\r
+ ***/\r
+void DateTime::searchMiliSeconds(XMLCh*& miliStartPtr, XMLCh*& miliEndPtr) const\r
+{\r
+    miliStartPtr = miliEndPtr = 0;\r
+\r
+    int milisec = XMLString::indexOf(fBuffer, MILISECOND_SEPARATOR);\r
+    if (milisec == -1)\r
+        return;\r
+\r
+    miliStartPtr = fBuffer + milisec + 1;\r
+    miliEndPtr   = miliStartPtr;\r
+    while (*miliEndPtr)\r
+    {\r
+        if ((*miliEndPtr < chDigit_0) || (*miliEndPtr > chDigit_9))\r
+            break;\r
+\r
+        miliEndPtr++;\r
+    }\r
+\r
+    //remove trailing zeros\r
+    while( *(miliEndPtr - 1) == chDigit_0)\r
+        miliEndPtr--;\r
+\r
+    return;\r
+}\r
+\r
diff --git a/xmltooling/util/DateTime.h b/xmltooling/util/DateTime.h
new file mode 100644 (file)
index 0000000..aceaf22
--- /dev/null
@@ -0,0 +1,233 @@
+/*\r
+ *  Copyright 2001-2006 Internet2\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *     http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+/**\r
+ * @file DateTime.h\r
+ * \r
+ * Manipulation of XML date/time data. \r
+ */\r
+\r
+#ifndef _XML_DATETIME_H\r
+#define _XML_DATETIME_H\r
+\r
+#include <xmltooling/base.h>\r
+\r
+#if defined (_MSC_VER)\r
+    #pragma warning( push )\r
+    #pragma warning( disable : 4244 )\r
+#endif\r
+\r
+#include <xercesc/util/XMLDateTime.hpp>\r
+\r
+#if defined (_MSC_VER)\r
+    #pragma warning( pop )\r
+#endif\r
+\r
+namespace xmltooling\r
+{\r
+    /**\r
+     * Class for manipulating XML date/time information.\r
+     * \r
+     * This is mostly copied from Xerces-C, but they haven't produced a usable date/time\r
+     * class, so we had to incorporate a version of it for now. It can't be inherited\r
+     * since the fields needed are private.\r
+     */\r
+    class XMLTOOL_API DateTime\r
+    {\r
+    public:\r
+        /// @cond OFF\r
+        DateTime();\r
+        DateTime(const XMLCh* const);\r
+        DateTime(time_t epoch);\r
+        DateTime(const DateTime&);\r
+        DateTime& operator=(const DateTime&);\r
+        ~DateTime();\r
+    \r
+        inline void setBuffer(const XMLCh* const);\r
+    \r
+        const XMLCh* getRawData() const;\r
+        const XMLCh* getFormattedString() const;\r
+        int getSign() const;\r
+    \r
+        XMLCh* getDateTimeCanonicalRepresentation() const;\r
+        XMLCh* getTimeCanonicalRepresentation() const;\r
+    \r
+        void parseDateTime();\r
+        void parseDate();\r
+        void parseTime();\r
+        void parseDay();\r
+        void parseMonth();\r
+        void parseYear();\r
+        void parseMonthDay();\r
+        void parseYearMonth();\r
+        void parseDuration();\r
+    \r
+        static int compare(const DateTime* const, const DateTime* const);\r
+        static int compare(const DateTime* const, const DateTime* const, bool);\r
+        static int compareOrder(const DateTime* const, const DateTime* const);                                    \r
+    \r
+        int getYear() const {return fValue[CentYear];}\r
+        int getMonth() const {return fValue[Month];}\r
+        int getDay() const {return fValue[Day];}\r
+        int getHour() const {return fValue[Hour];}\r
+        int getMinute() const {return fValue[Minute];}\r
+        int getSecond() const {return fValue[Second];}\r
+        time_t getEpoch() const;\r
+    \r
+        /// @endcond\r
+    private:\r
+        enum valueIndex {\r
+            CentYear   = 0,\r
+            Month      ,\r
+            Day        ,\r
+            Hour       ,\r
+            Minute     ,\r
+            Second     ,\r
+            MiliSecond ,  //not to be used directly\r
+            utc        ,\r
+            TOTAL_SIZE\r
+        };\r
+    \r
+        enum utcType {\r
+            UTC_UNKNOWN = 0,\r
+            UTC_STD        ,          // set in parse() or normalize()\r
+            UTC_POS        ,          // set in parse()\r
+            UTC_NEG                   // set in parse()\r
+        };\r
+    \r
+        enum timezoneIndex {\r
+            hh = 0,\r
+            mm ,\r
+            TIMEZONE_ARRAYSIZE\r
+        };\r
+    \r
+        static int compareResult(int, int, bool);\r
+        static void addDuration(DateTime* pDuration, const DateTime* const pBaseDate, int index);\r
+        static int compareResult(const DateTime* const, const DateTime* const, bool, int);\r
+        static inline int getRetVal(int, int);\r
+    \r
+        inline void reset();\r
+        //inline void assertBuffer() const;\r
+        inline void copy(const DateTime&);\r
+        \r
+        inline void initParser();\r
+        inline bool isNormalized() const;\r
+    \r
+        void getDate();\r
+        void getTime();\r
+        void getYearMonth();\r
+        void getTimeZone(const int);\r
+        void parseTimeZone();\r
+    \r
+        int findUTCSign(const int start);\r
+        int indexOf(const int start, const int end, const XMLCh ch) const;\r
+        int parseInt(const int start, const int end) const;\r
+        int parseIntYear(const int end) const;\r
+        double parseMiliSecond(const int start, const int end) const;\r
+    \r
+        void validateDateTime() const;\r
+        void normalize();\r
+        void fillString(XMLCh*& ptr, valueIndex ind, int expLen) const;\r
+        int  fillYearString(XMLCh*& ptr, valueIndex ind) const;\r
+        void searchMiliSeconds(XMLCh*& miliStartPtr, XMLCh*& miliEndPtr) const;\r
+    \r
+       bool operator==(const DateTime& toCompare) const;\r
+    \r
+        static const int DATETIMES[][TOTAL_SIZE];\r
+        int fValue[TOTAL_SIZE];\r
+        int fTimeZone[TIMEZONE_ARRAYSIZE];\r
+        int fStart;\r
+        int fEnd;\r
+        int fBufferMaxLen;\r
+        XMLCh* fBuffer;\r
+    \r
+        double fMiliSecond;\r
+        bool fHasTime;\r
+    };\r
+\r
+    inline void DateTime::setBuffer(const XMLCh* const aString)\r
+    {\r
+        reset();\r
+        fEnd = XMLString::stringLen(aString);\r
+        if (fEnd > 0) {\r
+            if (fEnd > fBufferMaxLen) {\r
+                delete[] fBuffer;\r
+                fBufferMaxLen = fEnd + 8;\r
+                fBuffer = new XMLCh[fBufferMaxLen+1];\r
+            }\r
+            memcpy(fBuffer, aString, (fEnd+1) * sizeof(XMLCh));\r
+        }\r
+    }\r
+    \r
+    inline void DateTime::reset()\r
+    {\r
+        for ( int i=0; i < XMLDateTime::TOTAL_SIZE; i++ )\r
+            fValue[i] = 0;\r
+    \r
+        fMiliSecond   = 0;\r
+        fHasTime      = false;\r
+        fTimeZone[hh] = fTimeZone[mm] = 0;\r
+        fStart = fEnd = 0;\r
+    \r
+        if (fBuffer)\r
+            *fBuffer = 0;\r
+    }\r
+    \r
+    inline void DateTime::copy(const DateTime& rhs)\r
+    {\r
+        for ( int i = 0; i < XMLDateTime::TOTAL_SIZE; i++ )\r
+            fValue[i] = rhs.fValue[i];\r
+    \r
+        fMiliSecond   = rhs.fMiliSecond;\r
+        fHasTime      = rhs.fHasTime;\r
+        fTimeZone[hh] = rhs.fTimeZone[hh];\r
+        fTimeZone[mm] = rhs.fTimeZone[mm];\r
+        fStart = rhs.fStart;\r
+        fEnd   = rhs.fEnd;\r
+    \r
+        if (fEnd > 0) {\r
+            if (fEnd > fBufferMaxLen) {\r
+                delete[] fBuffer;\r
+                fBufferMaxLen = rhs.fBufferMaxLen;\r
+                fBuffer = new XMLCh[fBufferMaxLen+1];\r
+            }\r
+            memcpy(fBuffer, rhs.fBuffer, (fEnd+1) * sizeof(XMLCh));\r
+        }\r
+    }\r
+    \r
+    inline void DateTime::initParser()\r
+    {\r
+        fStart = 0;   // to ensure scan from the very first beginning\r
+                      // in case the pointer is updated accidentally by someone else.\r
+    }\r
+    \r
+    inline bool DateTime::isNormalized() const\r
+    {\r
+        return (fValue[XMLDateTime::utc] == XMLDateTime::UTC_STD ? true : false);\r
+    }\r
+    \r
+    inline int DateTime::getRetVal(int c1, int c2)\r
+    {\r
+        if ((c1 == XMLDateTime::LESS_THAN && c2 == XMLDateTime::GREATER_THAN) ||\r
+            (c1 == XMLDateTime::GREATER_THAN && c2 == XMLDateTime::LESS_THAN))\r
+            return XMLDateTime::INDETERMINATE;\r
+    \r
+        return (c1 != XMLDateTime::INDETERMINATE) ? c1 : c2;\r
+    }\r
+\r
+}\r
+\r
+#endif\r
index 3b729cc..525480e 100644 (file)
                                Name="util"\r
                                >\r
                                <File\r
+                                       RelativePath=".\util\DateTime.cpp"\r
+                                       >\r
+                               </File>\r
+                               <File\r
                                        RelativePath=".\util\NDC.cpp"\r
                                        >\r
                                </File>\r
                                Name="util"\r
                                >\r
                                <File\r
+                                       RelativePath=".\util\DateTime.h"\r
+                                       >\r
+                               </File>\r
+                               <File\r
                                        RelativePath=".\util\NDC.h"\r
                                        >\r
                                </File>\r