Index Source Files Annotated Class List Alphabetical Class List Class Hierarchy Graphical Class Hierarchy

# DataDictionary.cpp

Go to the documentation of this file.

    00001 /****************************************************************************
    00002 ** Copyright (c) quickfixengine.org  All rights reserved.
    00003 **
    00004 ** This file is part of the QuickFIX FIX Engine
    00005 **
    00006 ** This file may be distributed under the terms of the quickfixengine.org
    00007 ** license as defined by quickfixengine.org and appearing in the file
    00008 ** LICENSE included in the packaging of this file.
    00009 **
    00010 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
    00011 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
    00012 **
    00013 ** See http://www.quickfixengine.org/LICENSE for licensing information.
    00014 **
    00015 ** Contact ask@quickfixengine.org if any conditions of this licensing are
    00016 ** not clear to you.
    00017 **
    00018 ****************************************************************************/
    00019
    00020 #ifdef _MSC_VER
    00021 #include "stdafx.h"
    00022 #else
    00023 #include "config.h"
    00024 #endif
    00025 #include "CallStack.h"
    00026
    00027 #include "DataDictionary.h"
    00028 #include "Message.h"
    00029 #include <fstream>
    00030 #include <memory>
    00031
    00032 #ifdef HAVE_LIBXML
    00033 #include "LIBXML_DOMDocument.h"
    00034 #elif _MSC_VER
    00035 #include "MSXML_DOMDocument.h"
    00036 #else
    00037 #include "LIBXML_DOMDocument.h"
    00038 #endif
    00039
    00040 #ifdef _MSC_VER
    00041 #define RESET_AUTO_PTR(OLD, NEW) OLD = NEW;
    00042 #else
    00043 #define RESET_AUTO_PTR(OLD, NEW) OLD.reset( NEW.release() );
    00044 #endif
    00045
    00046 namespace FIX
    00047 {
    00048 DataDictionary::DataDictionary()
    00049 : m_hasVersion( false ), m_checkFieldsOutOfOrder( true ),
    00050   m_checkFieldsHaveValues( true ), m_checkUserDefinedFields( true ),
    00051   m_orderedFieldsArray(0) {}
    00052
    00053 DataDictionary::DataDictionary( std::istream& stream )
    00054 throw( ConfigError )
    00055 : m_hasVersion( false ), m_checkFieldsOutOfOrder( true ),
    00056   m_checkFieldsHaveValues( true ), m_checkUserDefinedFields( true ),
    00057   m_orderedFieldsArray(0)
    00058 {
    00059   readFromStream( stream );
    00060 }
    00061
    00062 DataDictionary::DataDictionary( const std::string& url )
    00063 throw( ConfigError )
    00064 : m_hasVersion( false ), m_checkFieldsOutOfOrder( true ),
    00065   m_checkFieldsHaveValues( true ), m_checkUserDefinedFields( true ),
    00066   m_orderedFieldsArray(0)
    00067 {
    00068   readFromURL( url );
    00069 }
    00070
    00071 DataDictionary::DataDictionary( const DataDictionary& copy )
    00072 {
    00073   *this = copy;
    00074 }
    00075
    00076 DataDictionary::~DataDictionary()
    00077 {
    00078   FieldToGroup::iterator i;
    00079   for ( i = m_groups.begin(); i != m_groups.end(); ++i )
    00080     delete i->second.second;
    00081   if( m_orderedFieldsArray )
    00082     delete [] m_orderedFieldsArray;
    00083 }
    00084
    00085 DataDictionary& DataDictionary::operator=( const DataDictionary& rhs )
    00086 { QF_STACK_PUSH(DataDictionary::operator=)
    00087
    00088   m_hasVersion = rhs.m_hasVersion;
    00089   m_checkFieldsOutOfOrder = rhs.m_checkFieldsOutOfOrder;
    00090   m_checkFieldsHaveValues = rhs.m_checkFieldsHaveValues;
    00091   m_checkUserDefinedFields = rhs.m_checkUserDefinedFields;
    00092   m_beginString = rhs.m_beginString;
    00093   m_messageFields = rhs.m_messageFields;
    00094   m_requiredFields = rhs.m_requiredFields;
    00095   m_messages = rhs.m_messages;
    00096   m_fields = rhs.m_fields;
    00097   m_orderedFields = rhs.m_orderedFields;
    00098   m_orderedFieldsArray = 0;
    00099   m_headerFields = rhs.m_headerFields;
    00100   m_trailerFields = rhs.m_trailerFields;
    00101   m_fieldTypes = rhs.m_fieldTypes;
    00102   m_fieldValues = rhs.m_fieldValues;
    00103   m_fieldNames = rhs.m_fieldNames;
    00104   m_names = rhs.m_names;
    00105   m_valueNames = rhs.m_valueNames;
    00106
    00107   FieldToGroup::const_iterator i = rhs.m_groups.begin();
    00108   for ( ; i != rhs.m_groups.end(); ++i )
    00109   {
    00110     addGroup( i->first.first, i->first.second,
    00111               i->second.first, *i->second.second );
    00112   }
    00113   return *this;
    00114
    00115   QF_STACK_POP
    00116 }
    00117
    00118 void DataDictionary::validate( const Message& message,
    00119                                const DataDictionary* const pSessionDD,
    00120                                const DataDictionary* const pAppDD )
    00121 throw( FIX::Exception )
    00122 { QF_STACK_PUSH( DataDictionary::validate )
    00123
    00124   const bool bodyOnly = pSessionDD == 0;
    00125   const Header& header = message.getHeader();
    00126   const BeginString& beginString = FIELD_GET_REF( header, BeginString );
    00127   const MsgType& msgType = FIELD_GET_REF( header, MsgType );
    00128   if ( pSessionDD != 0 && pSessionDD->m_hasVersion )
    00129   {
    00130     if( pSessionDD->getVersion() != beginString )
    00131     {
    00132       throw UnsupportedVersion();
    00133     }
    00134   }
    00135
    00136   int field = 0;
    00137   if( (pSessionDD !=0 && pSessionDD->m_checkFieldsOutOfOrder)
    00138       || (pAppDD != 0 && pAppDD->m_checkFieldsOutOfOrder) )
    00139   {
    00140     if ( !message.hasValidStructure(field) )
    00141       throw TagOutOfOrder(field);
    00142   }
    00143
    00144   if ( pAppDD != 0 && pAppDD->m_hasVersion )
    00145   {
    00146     pAppDD->checkMsgType( msgType );
    00147     pAppDD->checkHasRequired( message.getHeader(), message, message.getTrailer(), msgType );
    00148   }
    00149
    00150   if( !bodyOnly )
    00151   {
    00152     pSessionDD->iterate( message.getHeader(), msgType );
    00153     pSessionDD->iterate( message.getTrailer(), msgType );
    00154   }
    00155
    00156   pAppDD->iterate( message, msgType );
    00157
    00158   QF_STACK_POP
    00159 }
    00160
    00161 void DataDictionary::iterate( const FieldMap& map, const MsgType& msgType ) const
    00162 { QF_STACK_PUSH(DataDictionary::iterate)
    00163
    00164   int lastField = 0;
    00165
    00166   FieldMap::iterator i;
    00167   for ( i = map.begin(); i != map.end(); ++i )
    00168   {
    00169     const FieldBase& field = i->second;
    00170     if( i != map.begin() && (field.getField() == lastField) )
    00171       throw RepeatedTag( lastField );
    00172     checkHasValue( field );
    00173
    00174     if ( m_hasVersion )
    00175     {
    00176       checkValidFormat( field );
    00177       checkValue( field );
    00178     }
    00179
    00180     if ( m_beginString.getValue().length() && shouldCheckTag(field) )
    00181     {
    00182       checkValidTagNumber( field );
    00183       if ( !Message::isHeaderField( field, this )
    00184            && !Message::isTrailerField( field, this ) )
    00185       {
    00186         checkIsInMessage( field, msgType );
    00187         checkGroupCount( field, map, msgType );
    00188       }
    00189     }
    00190     lastField = field.getField();
    00191   }
    00192
    00193   QF_STACK_POP
    00194 }
    00195
    00196 void DataDictionary::readFromURL( const std::string& url )
    00197 throw( ConfigError )
    00198 { QF_STACK_PUSH(DataDictionary::readFromURL)
    00199
    00200 #ifdef HAVE_LIBXML
    00201   DOMDocumentPtr pDoc = DOMDocumentPtr(new LIBXML_DOMDocument());
    00202 #elif _MSC_VER
    00203   DOMDocumentPtr pDoc = DOMDocumentPtr(new MSXML_DOMDocument());
    00204 #else
    00205   DOMDocumentPtr pDoc = DOMDocumentPtr(new LIBXML_DOMDocument());
    00206 #endif
    00207
    00208   if(!pDoc->load(url))
    00209     throw ConfigError(url + ": Could not parse data dictionary file");
    00210
    00211   try
    00212   {
    00213     readFromDocument( pDoc );
    00214   }
    00215   catch( ConfigError& e )
    00216   {
    00217     throw ConfigError( url + ": " + e.what() );
    00218   }
    00219
    00220   QF_STACK_POP
    00221 }
    00222
    00223 void DataDictionary::readFromStream( std::istream& stream )
    00224 throw( ConfigError )
    00225 { QF_STACK_PUSH(DataDictionary::readFromStream)
    00226
    00227 #ifdef HAVE_LIBXML
    00228   DOMDocumentPtr pDoc = DOMDocumentPtr(new LIBXML_DOMDocument());
    00229 #elif _MSC_VER
    00230   DOMDocumentPtr pDoc = DOMDocumentPtr(new MSXML_DOMDocument());
    00231 #else
    00232   DOMDocumentPtr pDoc = DOMDocumentPtr(new LIBXML_DOMDocument());
    00233 #endif
    00234
    00235   if(!pDoc->load(stream))
    00236     throw ConfigError("Could not parse data dictionary stream");
    00237
    00238   readFromDocument( pDoc );
    00239
    00240   QF_STACK_POP
    00241 }
    00242
    00243 void DataDictionary::readFromDocument( DOMDocumentPtr pDoc )
    00244 throw( ConfigError )
    00245 { QF_STACK_PUSH(DataDictionary::readFromDocument)
    00246
    00247   // VERSION
    00248   DOMNodePtr pFixNode = pDoc->getNode("/fix");
    00249   if(!pFixNode.get())
    00250     throw ConfigError("Could not parse data dictionary file"
    00251                       ", or no <fix> node found at root");
    00252   DOMAttributesPtr attrs = pFixNode->getAttributes();
    00253   std::string type = "FIX";
    00254   if(attrs->get("type", type))
    00255   {
    00256     if(type != "FIX" && type != "FIXT")
    00257       throw ConfigError("type attribute must be FIX or FIXT");
    00258   }
    00259   std::string major;
    00260   if(!attrs->get("major", major))
    00261     throw ConfigError("major attribute not found on <fix>");
    00262   std::string minor;
    00263   if(!attrs->get("minor", minor))
    00264     throw ConfigError("minor attribute not found on <fix>");
    00265   setVersion(type + "." + major + "." + minor);
    00266
    00267   // FIELDS
    00268   DOMNodePtr pFieldsNode = pDoc->getNode("/fix/fields");
    00269   if(!pFieldsNode.get())
    00270     throw ConfigError("<fields> section not found in data dictionary");
    00271
    00272   DOMNodePtr pFieldNode = pFieldsNode->getFirstChildNode();
    00273   if(!pFieldNode.get()) throw ConfigError("No fields defined");
    00274
    00275   while(pFieldNode.get())
    00276   {
    00277     if(pFieldNode->getName() == "field")
    00278     {
    00279       DOMAttributesPtr attrs = pFieldNode->getAttributes();
    00280       std::string name;
    00281       if(!attrs->get("name", name))
    00282         throw ConfigError("<field> does not have a name attribute");
    00283       std::string number;
    00284       if(!attrs->get("number", number))
    00285         throw ConfigError("<field> " + name + " does not have a number attribute");
    00286       int num = atol(number.c_str());
    00287       std::string type;
    00288       if(!attrs->get("type", type))
    00289         throw ConfigError("<field> " + name + " does not have a type attribute");
    00290       addField(num);
    00291       addFieldType(num, XMLTypeToType(type));
    00292       addFieldName(num, name);
    00293
    00294       DOMNodePtr pFieldValueNode = pFieldNode->getFirstChildNode();
    00295       while(pFieldValueNode.get())
    00296       {
    00297         if(pFieldValueNode->getName() == "value")
    00298         {
    00299           DOMAttributesPtr attrs = pFieldValueNode->getAttributes();
    00300           std::string enumeration;
    00301           if(!attrs->get("enum", enumeration))
    00302             throw ConfigError("<value> does not have enum attribute in field " + name);
    00303           addFieldValue(num, enumeration);
    00304           std::string description;
    00305           if(attrs->get("description", description))
    00306             addValueName(num, enumeration, description);
    00307         }
    00308         RESET_AUTO_PTR(pFieldValueNode, pFieldValueNode->getNextSiblingNode());
    00309       }
    00310     }
    00311     RESET_AUTO_PTR(pFieldNode, pFieldNode->getNextSiblingNode());
    00312   }
    00313
    00314   // HEADER
    00315   if( type == "FIXT" || (type == "FIX" && major < "5") )
    00316   {
    00317     DOMNodePtr pHeaderNode = pDoc->getNode("/fix/header");
    00318     if(!pHeaderNode.get())
    00319       throw ConfigError("<header> section not found in data dictionary");
    00320
    00321     DOMNodePtr pHeaderFieldNode = pHeaderNode->getFirstChildNode();
    00322     if(!pHeaderFieldNode.get()) throw ConfigError("No header fields defined");
    00323
    00324     while(pHeaderFieldNode.get())
    00325     {
    00326       if(pHeaderFieldNode->getName() == "field" || pHeaderFieldNode->getName() == "group" )
    00327       {
    00328         DOMAttributesPtr attrs = pHeaderFieldNode->getAttributes();
    00329         std::string name;
    00330         if(!attrs->get("name", name))
    00331           throw ConfigError("<field> does not have a name attribute");
    00332         std::string required = "false";
    00333         attrs->get("required", required);
    00334         addHeaderField(lookupXMLFieldNumber(pDoc.get(), name), required == "true");
    00335       }
    00336       if(pHeaderFieldNode->getName() == "group")
    00337       {
    00338         DOMAttributesPtr attrs = pHeaderFieldNode->getAttributes();
    00339         std::string required;
    00340         attrs->get("required", required);
    00341         bool isRequired = (required == "Y" || required == "y");
    00342         addXMLGroup(pDoc.get(), pHeaderFieldNode.get(), "_header_", *this, isRequired);
    00343       }
    00344
    00345       RESET_AUTO_PTR(pHeaderFieldNode, pHeaderFieldNode->getNextSiblingNode());
    00346     }
    00347   }
    00348
    00349   // TRAILER
    00350     if( type == "FIXT" || (type == "FIX" && major < "5") )
    00351     {
    00352     DOMNodePtr pTrailerNode = pDoc->getNode("/fix/trailer");
    00353     if(!pTrailerNode.get())
    00354       throw ConfigError("<trailer> section not found in data dictionary");
    00355
    00356     DOMNodePtr pTrailerFieldNode = pTrailerNode->getFirstChildNode();
    00357     if(!pTrailerFieldNode.get()) throw ConfigError("No trailer fields defined");
    00358
    00359     while(pTrailerFieldNode.get())
    00360     {
    00361       if(pTrailerFieldNode->getName() == "field" || pTrailerFieldNode->getName() == "group" )
    00362       {
    00363         DOMAttributesPtr attrs = pTrailerFieldNode->getAttributes();
    00364         std::string name;
    00365         if(!attrs->get("name", name))
    00366           throw ConfigError("<field> does not have a name attribute");
    00367         std::string required = "false";
    00368         attrs->get("required", required);
    00369         addTrailerField(lookupXMLFieldNumber(pDoc.get(), name), required == "true");
    00370       }
    00371       if(pTrailerFieldNode->getName() == "group")
    00372       {
    00373         DOMAttributesPtr attrs = pTrailerFieldNode->getAttributes();
    00374         std::string required;
    00375         attrs->get("required", required);
    00376         bool isRequired = (required == "Y" || required == "y");
    00377         addXMLGroup(pDoc.get(), pTrailerFieldNode.get(), "_trailer_", *this, isRequired);
    00378       }
    00379
    00380       RESET_AUTO_PTR(pTrailerFieldNode, pTrailerFieldNode->getNextSiblingNode());
    00381     }
    00382   }
    00383
    00384   // MSGTYPE
    00385   DOMNodePtr pMessagesNode = pDoc->getNode("/fix/messages");
    00386   if(!pMessagesNode.get())
    00387     throw ConfigError("<messages> section not found in data dictionary");
    00388
    00389   DOMNodePtr pMessageNode = pMessagesNode->getFirstChildNode();
    00390   if(!pMessageNode.get()) throw ConfigError("No messages defined");
    00391
    00392   while(pMessageNode.get())
    00393   {
    00394     if(pMessageNode->getName() == "message")
    00395     {
    00396       DOMAttributesPtr attrs = pMessageNode->getAttributes();
    00397       std::string msgtype;
    00398       if(!attrs->get("msgtype", msgtype))
    00399         throw ConfigError("<field> does not have a name attribute");
    00400       addMsgType(msgtype);
    00401
    00402       std::string name;
    00403       if(attrs->get("name", name))
    00404         addValueName( 35, msgtype, name );
    00405
    00406       DOMNodePtr pMessageFieldNode = pMessageNode->getFirstChildNode();
    00407       if( !pMessageFieldNode.get() )
    00408         throw ConfigError("<message> contains no fields");
    00409       while( pMessageFieldNode.get() )
    00410       {
    00411         if(pMessageFieldNode->getName() == "field"
    00412            || pMessageFieldNode->getName() == "group")
    00413         {
    00414           DOMAttributesPtr attrs = pMessageFieldNode->getAttributes();
    00415           std::string name;
    00416           if(!attrs->get("name", name))
    00417             throw ConfigError("<field> does not have a name attribute");
    00418           int num = lookupXMLFieldNumber(pDoc.get(), name);
    00419           addMsgField(msgtype, num);
    00420
    00421           std::string required;
    00422           if(attrs->get("required", required)
    00423              && (required == "Y" || required == "y"))
    00424           {
    00425             addRequiredField(msgtype, num);
    00426           }
    00427         }
    00428         else if(pMessageFieldNode->getName() == "component")
    00429         {
    00430           DOMAttributesPtr attrs = pMessageFieldNode->getAttributes();
    00431           std::string required;
    00432           attrs->get("required", required);
    00433           bool isRequired = (required == "Y" || required == "y");
    00434           addXMLComponentFields(pDoc.get(), pMessageFieldNode.get(),
    00435                                 msgtype, *this, isRequired);
    00436         }
    00437         if(pMessageFieldNode->getName() == "group")
    00438         {
    00439           DOMAttributesPtr attrs = pMessageFieldNode->getAttributes();
    00440           std::string required;
    00441           attrs->get("required", required);
    00442           bool isRequired = (required == "Y" || required == "y");
    00443           addXMLGroup(pDoc.get(), pMessageFieldNode.get(), msgtype, *this, isRequired);
    00444         }
    00445         RESET_AUTO_PTR(pMessageFieldNode,
    00446                        pMessageFieldNode->getNextSiblingNode());
    00447       }
    00448     }
    00449     RESET_AUTO_PTR(pMessageNode, pMessageNode->getNextSiblingNode());
    00450   }
    00451
    00452   QF_STACK_POP
    00453 }
    00454
    00455 int* DataDictionary::getOrderedFields() const
    00456 { QF_STACK_PUSH(DataDictionary::getOrderedFields)
    00457
    00458   if( m_orderedFieldsArray ) return m_orderedFieldsArray;
    00459   m_orderedFieldsArray = new int[m_orderedFields.size() + 1];
    00460
    00461   int* i = m_orderedFieldsArray;
    00462   OrderedFields::const_iterator iter;
    00463   for( iter = m_orderedFields.begin(); iter != m_orderedFields.end(); *(i++) = *(iter++) ) {}
    00464   *i = 0;
    00465   return m_orderedFieldsArray;
    00466
    00467   QF_STACK_POP
    00468 }
    00469
    00470 int DataDictionary::lookupXMLFieldNumber( DOMDocument* pDoc, DOMNode* pNode ) const
    00471 { QF_STACK_PUSH(DataDictionary::lookupXMLFieldNumber)
    00472
    00473   DOMAttributesPtr attrs = pNode->getAttributes();
    00474   std::string name;
    00475   if(!attrs->get("name", name))
    00476     throw ConfigError("No name given to field");
    00477   return lookupXMLFieldNumber( pDoc, name );
    00478
    00479   QF_STACK_POP
    00480 }
    00481
    00482 int DataDictionary::lookupXMLFieldNumber
    00483 ( DOMDocument* pDoc, const std::string& name ) const
    00484 { QF_STACK_PUSH(DataDictionary::lookupXMLFieldNumber)
    00485
    00486   NameToField::const_iterator i = m_names.find(name);
    00487   if( i == m_names.end() )
    00488     throw ConfigError("Field " + name + " not defined in fields section");
    00489   return i->second;
    00490
    00491   QF_STACK_POP
    00492 }
    00493
    00494 int DataDictionary::addXMLComponentFields( DOMDocument* pDoc, DOMNode* pNode,
    00495                                             const std::string& msgtype,
    00496                                             DataDictionary& DD,
    00497                                             bool componentRequired )
    00498 { QF_STACK_PUSH(DataDictionary::addXMLComponentFields)
    00499
    00500   int firstField = 0;
    00501
    00502   DOMAttributesPtr attrs = pNode->getAttributes();
    00503   std::string name;
    00504   if(!attrs->get("name", name))
    00505     throw ConfigError("No name given to component");
    00506
    00507   DOMNodePtr pComponentNode =
    00508     pDoc->getNode("/fix/components/component[@name='" + name + "']");
    00509   if(pComponentNode.get() == 0)
    00510     throw ConfigError("Component not found");
    00511
    00512   DOMNodePtr pComponentFieldNode = pComponentNode->getFirstChildNode();
    00513   while(pComponentFieldNode.get())
    00514   {
    00515     if(pComponentFieldNode->getName() == "field"
    00516        || pComponentFieldNode->getName() == "group")
    00517     {
    00518       DOMAttributesPtr attrs = pComponentFieldNode->getAttributes();
    00519       std::string name;
    00520       if(!attrs->get("name", name))
    00521         throw ConfigError("No name given to field");
    00522       int field = lookupXMLFieldNumber(pDoc, name);
    00523       if( firstField == 0 ) firstField = field;
    00524
    00525       std::string required;
    00526       if(attrs->get("required", required)
    00527          && (required == "Y" || required =="y")
    00528          && componentRequired)
    00529       {
    00530         addRequiredField(msgtype, field);
    00531       }
    00532
    00533       DD.addField(field);
    00534       DD.addMsgField(msgtype, field);
    00535     }
    00536     if(pComponentFieldNode->getName() == "component")
    00537     {
    00538       DOMAttributesPtr attrs = pComponentFieldNode->getAttributes();
    00539       std::string required;
    00540       attrs->get("required", required);
    00541       bool isRequired = (required == "Y" || required == "y");
    00542       addXMLComponentFields(pDoc, pComponentFieldNode.get(),
    00543                             msgtype, *this, isRequired);
    00544     }
    00545     if(pComponentFieldNode->getName() == "group")
    00546     {
    00547       DOMAttributesPtr attrs = pComponentFieldNode->getAttributes();
    00548       std::string required;
    00549       attrs->get("required", required);
    00550       bool isRequired = (required == "Y" || required == "y");
    00551       addXMLGroup(pDoc, pComponentFieldNode.get(), msgtype, DD, isRequired);
    00552     }
    00553     RESET_AUTO_PTR(pComponentFieldNode,
    00554       pComponentFieldNode->getNextSiblingNode());
    00555   }
    00556   return firstField;
    00557
    00558   QF_STACK_POP
    00559 }
    00560
    00561 void DataDictionary::addXMLGroup( DOMDocument* pDoc, DOMNode* pNode,
    00562                                   const std::string& msgtype,
    00563                                   DataDictionary& DD, bool groupRequired  )
    00564 { QF_STACK_PUSH(DataDictionary::addXMLGroup)
    00565
    00566   DOMAttributesPtr attrs = pNode->getAttributes();
    00567   std::string name;
    00568   if(!attrs->get("name", name))
    00569     throw ConfigError("No name given to group");
    00570   int group = lookupXMLFieldNumber( pDoc, name );
    00571   int delim = 0;
    00572   int field = 0;
    00573   DataDictionary groupDD;
    00574   DOMNodePtr node = pNode->getFirstChildNode();
    00575   while(node.get())
    00576   {
    00577     if( node->getName() == "field" )
    00578     {
    00579       field = lookupXMLFieldNumber( pDoc, node.get() );
    00580       groupDD.addField( field );
    00581
    00582       DOMAttributesPtr attrs = node->getAttributes();
    00583       std::string required;
    00584       if( attrs->get("required", required)
    00585          && ( required == "Y" || required =="y" )
    00586          && groupRequired )
    00587       {
    00588         groupDD.addRequiredField(msgtype, field);
    00589       }
    00590     }
    00591     else if( node->getName() == "component" )
    00592     {
    00593       field = addXMLComponentFields( pDoc, node.get(), msgtype, groupDD, false );
    00594     }
    00595     else if( node->getName() == "group" )
    00596     {
    00597       field = lookupXMLFieldNumber( pDoc, node.get() );
    00598       groupDD.addField( field );
    00599       DOMAttributesPtr attrs = node->getAttributes();
    00600       std::string required;
    00601       if( attrs->get("required", required )
    00602          && ( required == "Y" || required =="y" )
    00603          && groupRequired)
    00604       {
    00605         groupDD.addRequiredField(msgtype, field);
    00606       }
    00607             bool isRequired = false;
    00608             if( attrs->get("required", required) )
    00609                   isRequired = (required == "Y" || required == "y");
    00610       addXMLGroup( pDoc, node.get(), msgtype, groupDD, isRequired );
    00611     }
    00612     if( delim == 0 ) delim = field;
    00613     RESET_AUTO_PTR(node, node->getNextSiblingNode());
    00614   }
    00615
    00616   if( delim ) DD.addGroup( msgtype, group, delim, groupDD );
    00617
    00618   QF_STACK_POP
    00619 }
    00620
    00621 TYPE::Type DataDictionary::XMLTypeToType( const std::string& type ) const
    00622 { QF_STACK_PUSH(DataDictionary::XMLTypeToType)
    00623
    00624   if ( m_beginString < "FIX.4.2" && type == "CHAR" )
    00625     return TYPE::String;
    00626
    00627   if ( type == "STRING" ) return TYPE::String;
    00628   if ( type == "CHAR" ) return TYPE::Char;
    00629   if ( type == "PRICE" ) return TYPE::Price;
    00630   if ( type == "INT" ) return TYPE::Int;
    00631   if ( type == "AMT" ) return TYPE::Amt;
    00632   if ( type == "QTY" ) return TYPE::Qty;
    00633   if ( type == "CURRENCY" ) return TYPE::Currency;
    00634   if ( type == "MULTIPLEVALUESTRING" ) return TYPE::MultipleValueString;
    00635   if ( type == "MULTIPLESTRINGVALUE" ) return TYPE::MultipleStringValue;
    00636   if ( type == "MULTIPLECHARVALUE" ) return TYPE::MultipleCharValue;
    00637   if ( type == "EXCHANGE" ) return TYPE::Exchange;
    00638   if ( type == "UTCTIMESTAMP" ) return TYPE::UtcTimeStamp;
    00639   if ( type == "BOOLEAN" ) return TYPE::Boolean;
    00640   if ( type == "LOCALMKTDATE" ) return TYPE::LocalMktDate;
    00641   if ( type == "DATA" ) return TYPE::Data;
    00642   if ( type == "FLOAT" ) return TYPE::Float;
    00643   if ( type == "PRICEOFFSET" ) return TYPE::PriceOffset;
    00644   if ( type == "MONTHYEAR" ) return TYPE::MonthYear;
    00645   if ( type == "DAYOFMONTH" ) return TYPE::DayOfMonth;
    00646   if ( type == "UTCDATE" ) return TYPE::UtcDate;
    00647   if ( type == "UTCDATEONLY" ) return TYPE::UtcDateOnly;
    00648   if ( type == "UTCTIMEONLY" ) return TYPE::UtcTimeOnly;
    00649   if ( type == "NUMINGROUP" ) return TYPE::NumInGroup;
    00650   if ( type == "PERCENTAGE" ) return TYPE::Percentage;
    00651   if ( type == "SEQNUM" ) return TYPE::SeqNum;
    00652   if ( type == "LENGTH" ) return TYPE::Length;
    00653   if ( type == "COUNTRY" ) return TYPE::Country;
    00654   if ( type == "TIME" ) return TYPE::UtcTimeStamp;
    00655   return TYPE::Unknown;
    00656
    00657   QF_STACK_POP
    00658 }
    00659 }