GME  13
MgaParser.cpp
Go to the documentation of this file.
00001 
00002 #include "stdafx.h"
00003 #include "CommonMath.h"
00004 #include "Parser.h"
00005 #include "MgaParser.h"
00006 #include <xercesc/util/PlatformUtils.hpp>
00007 #include <xercesc/parsers/SAXParser.hpp>
00008 #include <stdio.h>
00009 
00010 #include "../Common/CommonCollection.h"
00011 #include <list>//slist
00012 #include <algorithm>
00013 
00014 const TCHAR * magic_exit_str = _T("Analysis done.Quit parsing.");
00015 // --------------------------- CMgaParser
00016 
00017 STDMETHODIMP CMgaParser::ParseFCOs(IMgaObject *here, BSTR filename)
00018 {
00019         return ParseFCOs2(here, filename, NULL);
00020 }
00021 
00022 STDMETHODIMP CMgaParser::ParseFCOs2(IMgaObject *here, BSTR filename, ULONGLONG hwndParent_)
00023 {
00024         CHECK_IN(here);
00025         m_maintainGuids = false;
00026 
00027         CComObjPtr<IMgaProject> p;
00028         HRESULT hr = here->get_Project(PutOut(p));
00029         if (FAILED(hr))
00030                 return hr;
00031         if ((p->ProjectStatus & 1) == 0)
00032         {
00033                 clear_GME(m_GME);
00034                 SetErrorInfo(L"Project is not open");
00035 
00036                 return E_MGA_ZOMBIE_NOPROJECT;
00037         }
00038 
00039         try
00040         {
00041                 HWND hwndParent = (HWND)hwndParent_;
00042                 if (hwndParent != 0)
00043                 {
00044                         COMTHROW( progress.CoCreateInstance(L"Mga.MgaProgressDlg") );
00045                         COMTHROW( progress->SetTitle(_bstr_t(L"Importing XML file...")) );
00046                         COMTHROW( progress->StartProgressDialog(hwndParent) );
00047                 }
00048 
00049                 ASSERT( p != NULL );
00050                 COMTHROW( p->get_Preferences(&project_prefs_orig) );
00051                 manual_relid_mode = project_prefs_orig & MGAPREF_MANUAL_RELIDS ? true : false;
00052 
00053                 m_GME = get_GME( p); // by zolmol
00054 
00055                 COMTHROW( p->Notify(APPEVENT_XML_IMPORT_FCOS_BEGIN));
00056 
00057                 COMTHROW( p->CreateTerritory(NULL, PutOut(territory), NULL) );
00058                 COMTHROW( p->BeginTransaction(territory, TRANSACTION_NON_NESTED) );
00059 
00060                 // PETER: put the 'here' object into the parser's territory
00061                 CComObjPtr<IMgaObject> target;
00062                 COMTHROW(territory->OpenObj(here, PutOut(target)));
00063 
00064                 project_prefs = project_prefs_orig | MGAPREF_IGNORECONNCHECKS;
00065                 COMTHROW( p->put_Preferences(project_prefs) );
00066 
00067                 if (resolver == NULL)
00068                 {
00069                         COMTHROW( resolver.CoCreateInstance(L"Mga.MgaResolver") );
00070                         ASSERT( resolver != NULL );
00071                 }
00072 
00073                 project = p;
00074 
00075                 CopyTo(filename, xmlfile);
00076 
00077                 m_resolveDerFuncPtr = &CMgaParser::ResolveDerivation;
00078                 XMLPlatformUtilsTerminate_RAII term;
00079                 try
00080                 {
00081                         XMLPlatformUtils::Initialize();
00082 
00083                         SAXParser parser;
00084                         parser.setValidationScheme(SAXParser::Val_Always);
00085                         parser.setDocumentHandler(this);
00086                         parser.setErrorHandler(this);
00087                         parser.setEntityResolver(this);
00088 
00089                         // Now it is delegated to fireStartFunction
00090                         //elementfuncs = elementfuncs_mga;
00091                         funcTableState = MGA;
00092 
00093                         // manual first pass
00094 
00095                         pass_count = 1;
00096 
00097                         ranges.clear();
00098                         ranges.push_front(range_type());
00099                         ranges.front().begin = 1;
00100                         ranges.front().end = (counter_type)-1;
00101                         ranges.front().previous.name = _T("start");
00102                         ranges.front().previous.object = target;
00103                         skip_element_level = 0;
00104                         
00105                         parser.parse(xmlfile.c_str());
00106 
00107                         ASSERT( ranges.front().begin == 1 );
00108                         ranges.pop_front();
00109                         elements.clear();
00110 
00111                         max_counter = counter;
00112 
00113                         // the other passes
00114 
00115                         parser.setValidationScheme(SAXParser::Val_Never);
00116 
00117                         while( !ranges.empty() && ranges.front().begin != (counter_type)-1 )
00118                         {
00119                                 // FIXME: better algorithm for infinite loop
00120                                 if( ++pass_count >= 100 )
00121                                         HR_THROW(E_TOOMANYPASSES);
00122 
00123                                 parser.parse(xmlfile.c_str());
00124                         }
00125 
00126                         ASSERT( elements.empty() );
00127                         ranges.clear();
00128                 }
00129                 catch(const XMLException &e)
00130                 {
00131                         XmlStr desc(e.getMessage());
00132 
00133                         ThrowXmlError(L"%s", desc.c_str());
00134                 }
00135                 COMTHROW( project->put_Preferences(project_prefs_orig) );
00136 
00137                 for(librecords::reverse_iterator i = libstodo.rbegin(); i != libstodo.rend(); ++i) { // copied from ParseProject in order to recognize libraries (zolmol)
00138                         COMTHROW(i->f->put_LibraryName(CComBSTR(i->libname.c_str())));
00139                         COMTHROW(i->f->put_Exempt(VARIANT_FALSE));
00140                 }
00141                 libstodo.clear();
00142 
00143                 COMTHROW( project->CommitTransaction() );
00144                 COMTHROW( project->Notify(APPEVENT_XML_IMPORT_FCOS_END));
00145                 project = NULL;
00146 
00147                 CloseAll();
00148                 clear_GME( m_GME);
00149         }
00150         catch(hresult_exception &e)
00151         {
00152                 CloseAll();
00153                 // in case we rethrew the [probably MGA originated] exception 
00154                 // we have set into errorinfo the location info
00155                 if( m_GME)
00156                         COMTHROW(m_GME->ConsoleMessage( errorinfo, MSG_ERROR));
00157                 clear_GME( m_GME);
00158 
00159                 ASSERT( FAILED(e.hr) );
00160                 if( e.hr == E_XMLPARSER )
00161                         SetErrorInfo(errorinfo);
00162                 else
00163                         SetErrorInfo2(e.hr);
00164 
00165                 return e.hr;
00166         }
00167         catch(_com_error &e)
00168         {
00169                 CloseAll();
00170                 clear_GME( m_GME);
00171 
00172                 ASSERT( FAILED(e.Error()) );
00173                 if (e.Description() != _bstr_t())
00174                         SetErrorInfo(e.Description());
00175 
00176                 return e.Error();
00177         }
00178         return S_OK;
00179 }
00180 
00181 
00182 
00183 STDMETHODIMP CMgaParser::ParseProject(IMgaProject *p, BSTR filename)
00184 {
00185         return ParseProject2(p, filename, 0);
00186 }
00187 
00188 STDMETHODIMP CMgaParser::ParseProject2(IMgaProject *p, BSTR filename, ULONGLONG hwndParent_)
00189 {
00190         CHECK_IN(p);
00191         m_maintainGuids = true; //will be set to false if p is NOT empty
00192 
00193         if ((p->ProjectStatus & 1) == 0)
00194         {
00195                 clear_GME(m_GME);
00196                 SetErrorInfo(L"Project is not open");
00197 
00198                 return E_MGA_ZOMBIE_NOPROJECT;
00199         }
00200         try
00201         {
00202                 HWND hwndParent = (HWND)hwndParent_;
00203                 if (hwndParent != 0)
00204                 {
00205                         COMTHROW( progress.CoCreateInstance(L"Mga.MgaProgressDlg") );
00206                         COMTHROW( progress->SetTitle(_bstr_t(L"Importing XML file...")) );
00207                         COMTHROW( progress->StartProgressDialog(hwndParent) );
00208                 }
00209 
00210 
00211                 project = p;
00212                 COMTHROW( project->get_Preferences(&project_prefs_orig) );
00213                 manual_relid_mode = project_prefs_orig & MGAPREF_MANUAL_RELIDS ? true : false;
00214 
00215                 m_GME = get_GME( p); // by zolmol
00216 
00217                 COMTHROW( project->Notify(APPEVENT_XML_IMPORT_BEGIN));
00218 
00219                 COMTHROW( project->CreateTerritory(NULL, PutOut(territory), NULL) );
00220                 COMTHROW( project->BeginTransaction(territory, TRANSACTION_NON_NESTED) );
00221 
00222                 CComObjPtr<IMgaFolder> rfld;
00223                 COMTHROW( project->get_RootFolder( PutOut(rfld)));
00224                 if( rfld) 
00225                 {
00226                         CComObjPtrVector<IMgaFolder> fols;
00227                         CComObjPtrVector<IMgaFCO> chld;
00228                         COMTHROW( rfld->get_ChildFCOs( PutOut( chld)));
00229                         COMTHROW( rfld->get_ChildFolders( PutOut( fols)));
00230                         
00231                         m_maintainGuids = fols.empty() && chld.empty(); // maintain guids if and only if project is empty
00232                 }
00233                 
00234                 project_prefs = project_prefs_orig | MGAPREF_IGNORECONNCHECKS;
00235                 COMTHROW( project->put_Preferences(project_prefs) );
00236 
00237                 if (resolver == NULL)
00238                 {
00239                         COMTHROW( resolver.CoCreateInstance(L"Mga.MgaResolver") );
00240                         ASSERT( resolver != NULL );
00241                 }
00242 
00243                 CopyTo(filename, xmlfile);
00244 
00245                 m_resolveDerFuncPtr = &CMgaParser::ResolveDerivation;
00246                 XMLPlatformUtilsTerminate_RAII term;
00247                 try
00248                 {
00249                         XMLPlatformUtils::Initialize();
00250 
00251                         SAXParser parser;
00252                         parser.setValidationScheme(SAXParser::Val_Always);
00253                         parser.setDocumentHandler(this);
00254                         parser.setErrorHandler(this);
00255                         parser.setEntityResolver(this);
00256 
00257                         // Now it is fireStart/End Function
00258                         //elementfuncs = elementfuncs_mga;
00259 
00260                         funcTableState = MGA;
00261 
00262                         // we do the first pass manually
00263 
00264                         pass_count = 1;
00265 
00266                         ranges.clear();
00267                         ranges.push_front(range_type());
00268                         ranges.front().begin = 1;
00269                         ranges.front().end = (counter_type)-1;
00270                         skip_element_level = 0;
00271                         
00272                         parser.parse(xmlfile.c_str());
00273 
00274                         ASSERT( ranges.front().begin == 1 );
00275                         ranges.pop_front();
00276                         elements.clear();
00277 
00278                         max_counter = counter;
00279 
00280                         // the other passes
00281 
00282                         parser.setValidationScheme(SAXParser::Val_Never);
00283 
00284                         while( !ranges.empty() && ranges.front().begin != (counter_type)-1 )
00285                         {
00286                                 // FIXME: better algorithm for infinite loop
00287                                 if( ++pass_count >= 100 )
00288                                         HR_THROW(E_TOOMANYPASSES);
00289 
00290                                 parser.parse(xmlfile.c_str());
00291                         }
00292 
00293                         ASSERT( elements.empty() );
00294                         ranges.clear();
00295                 }
00296                 catch(const XMLException &e)
00297                 {
00298                         XmlStr desc(e.getMessage());
00299 
00300                         ThrowXmlError(L"%s", desc.c_str());
00301                 }
00302 
00303                 COMTHROW( project->put_Preferences(project_prefs_orig) );
00304 
00305                 // readonly flag and library name can't be applied if done in wrong order
00306                 // because of the readonly flag is applied all way down the hierarchy
00307                 // (preventing put_LibraryName for inner libs to succeed)
00308 
00309                 // the order of libraries in libstodo is the sequential order as they appear
00310                 // in the xme file (depth first traversal), thus if the vector is traversed
00311                 // in reverse order (children libraries are always handled before their parent)
00312                 // the libroot_flag and library_flag flags can be applied with success
00313                 for(librecords::reverse_iterator i = libstodo.rbegin(); i != libstodo.rend(); ++i) {
00314                         COMTHROW(i->f->put_LibraryName(CComBSTR(i->libname.c_str())));
00315                         COMTHROW(i->f->put_Exempt(VARIANT_FALSE));
00316                 }
00317                 libstodo.clear();
00318                 
00319                 COMTHROW( project->put_GUID(projectguid) );
00320                 if (projectversion != _bstr_t("")) {
00321                         COMTHROW( project->put_Version(projectversion) );
00322                 }
00323 
00324                 project->__CommitTransaction();
00325                 project->__Notify(APPEVENT_XML_IMPORT_END);
00326                 project = NULL;
00327 
00328                 CloseAll();
00329                 clear_GME( m_GME);
00330         }
00331         catch(hresult_exception &e)
00332         {
00333                 CloseAll();
00334                 // in case we rethrew the [probably MGA originated] exception 
00335                 // we have set into errorinfo the location info
00336                 if( m_GME)
00337                         COMTHROW(m_GME->ConsoleMessage( errorinfo, MSG_ERROR));
00338                 clear_GME( m_GME);
00339 
00340                 ASSERT( FAILED(e.hr) );
00341                 if( e.hr == E_XMLPARSER )
00342                         SetErrorInfo(errorinfo);
00343                 else
00344                         SetErrorInfo2(e.hr);
00345 
00346                 return e.hr;
00347         }
00348         catch(_com_error &e)
00349         {
00350                 CloseAll();
00351                 clear_GME( m_GME);
00352 
00353                 ASSERT( FAILED(e.Error()) );
00354                 if (e.Description() != _bstr_t())
00355                         SetErrorInfo(e.Description());
00356 
00357                 return e.Error();
00358         }
00359         return S_OK;
00360 }
00361 
00362 STDMETHODIMP CMgaParser::GetXMLParadigm(BSTR filename, BSTR *paradigm)
00363 {
00364         return GetXMLInfo(filename, paradigm, _bstr_t().GetAddress(), _variant_t().GetAddress(), _bstr_t().GetAddress(), _bstr_t().GetAddress());
00365 }
00366 
00367 STDMETHODIMP CMgaParser::GetXMLInfo(BSTR filename, BSTR *paradigm, BSTR* parversion, VARIANT *parguid, BSTR* basename, BSTR* version) {
00368 
00369 //      CHECK_IN(filename);
00370         CHECK_OUT(paradigm);
00371         CHECK_OUT(parversion);
00372         CHECK_OUT(parguid);
00373         CHECK_OUT(basename);
00374         CHECK_OUT(version);
00375 
00376         try
00377         {
00378                 CopyTo(filename, xmlfile);
00379 
00380                 XMLPlatformUtilsTerminate_RAII term;
00381                 try
00382                 {
00383                         XMLPlatformUtils::Initialize();
00384 
00385                         SAXParser parser;
00386                         parser.setValidationScheme(SAXParser::Val_Never);
00387                         parser.setDocumentHandler(this);
00388                         parser.setErrorHandler(this);
00389                         parser.setEntityResolver(this);
00390 
00391                         //elementfuncs = elementfuncs_mgainfo;
00392                         funcTableState = MGA_INFO;
00393 
00394 
00395                         pass_count = 1;
00396 
00397                         ranges.clear();
00398                         ranges.push_front(range_type());
00399                         ranges.front().begin = 1;
00400                         ranges.front().end = (counter_type)-1;
00401                         skip_element_level = 0;
00402 
00403                         infoparname = paradigm;
00404                         infoparversion = parversion;
00405                         infoparguid = parguid;
00406                         infoprojname = basename;
00407                         infoversion = version;
00408 
00409                         parser.parse(xmlfile.c_str());
00410 
00411                 }
00412                 catch(const SAXException &e)
00413                 {
00414                         XmlStr msg = e.getMessage();
00415                         if (msg != magic_exit_str)
00416                         {
00417                                 ThrowXmlError(L"%s", msg.c_str());
00418                         }
00419                         // else just ignore it, we threw an exception for a good purpose:
00420                         // to quit the costly parsing operation
00421                 }
00422                 catch(const XMLException &e)
00423                 {
00424                         XmlStr desc(e.getMessage());
00425 
00426                         ThrowXmlError(L"%s", desc.c_str());
00427                 }
00428 
00429                 CloseAll();
00430         }
00431         catch(hresult_exception &e)
00432         {
00433                 CloseAll();
00434 
00435                 ASSERT( FAILED(e.hr) );
00436                 if( e.hr == E_XMLPARSER )
00437                         SetErrorInfo(errorinfo);
00438                 else
00439                         SetErrorInfo2(e.hr);
00440 
00441                 return e.hr;
00442         }
00443         return S_OK;
00444 }
00445 
00446 void CMgaParser::CloseAll()
00447 {
00448         elements.clear();
00449         ranges.clear();
00450 
00451         if( progress != NULL )
00452         {
00453                 COMTHROW(progress->StopProgressDialog());
00454                 progress = NULL;
00455         }
00456 
00457         resolver.Release();
00458 
00459         if( project != NULL )
00460         {
00461 
00462                 COMTHROW(project->put_Preferences(project_prefs_orig));
00463                 if (project->ProjectStatus & 8)
00464                 {
00465                         COMTHROW(project->AbortTransaction());
00466                 }
00467                 COMTHROW(project->Notify(APPEVENT_XML_IMPORT_END));
00468         }
00469 
00470         if( territory != NULL )
00471                 COMTHROW(territory->Destroy());
00472 
00473         territory = NULL;
00474         project = NULL;
00475 
00476         manual_relid_mode = false;
00477         relid = -2;
00478         
00479         GUID tmpguid;
00480         memset(&tmpguid, 0, sizeof(GUID));
00481         CopyTo(tmpguid, projectguid);
00482 };
00483 
00484 // ------- Passes
00485 
00486 TCHAR progress_msg[512];
00487 
00488 void CMgaParser::startElement(const XMLCh* const name, AttributeList& attributes)
00489 {
00490         ASSERT( !ranges.empty() );
00491 
00492         ++counter;
00493 
00494         if( counter % 1000 == 0 )
00495         {
00496                 _stprintf_s(progress_msg, _T("Phase: %d, number of parsed objects: %ld"), pass_count, (long)counter/2);
00497                 if (progress)
00498                         COMTHROW( progress->SetLine(0, PutInBstr(progress_msg)) );
00499 
00500                 if( pass_count == 1 )
00501                         max_counter = counter + 10000;
00502 
00503                 if (progress)
00504                         COMTHROW( progress->SetProgress(counter, 0) );
00505         }
00506 
00507         if( skip_element_level > 0 )
00508         {
00509                 ASSERT( ranges.front().begin != counter );
00510                 ++skip_element_level;
00511         }
00512         else if( ranges.front().begin <= counter && counter <= ranges.front().end )
00513         {
00514                 if( ranges.front().begin == counter )
00515                 {
00516                         ASSERT( elements.empty() );
00517                         elements.push_back(ranges.front().previous);
00518                 }
00519                 ASSERT( !elements.empty() );
00520 
00521                 try
00522                 {
00523                         CGenParser::startElement(name, attributes);
00524                 }
00525                 catch(pass_exception &e)
00526                 {
00527                         ASSERT( skip_element_level == 0 );
00528 
00529                         ranges.push_back(range_type());
00530                         ranges.back().begin = elements.back().begin;
00531                         elements.pop_back();
00532                         ranges.back().previous = elements.back();
00533                         skip_element_level = 1;
00534                         if (pass_count == 99)
00535                                 if (m_GME)
00536                                         COMTHROW(m_GME->ConsoleMessage(_bstr_t(e.wwhat()), msgtype_enum::MSG_ERROR));
00537                 }
00538         }
00539 }
00540 
00541 void CMgaParser::endElement(const XMLCh* const name)
00542 {
00543         ASSERT( !ranges.empty() );
00544 
00545         ++counter;
00546 
00547         if( skip_element_level > 0 )
00548         {
00549                 --skip_element_level;
00550 
00551                 if( skip_element_level == 0 )
00552                 {
00553                         ranges.back().end = counter;
00554                 }
00555         }
00556         else if( ranges.front().begin <= counter && counter <= ranges.front().end )
00557         {
00558                 try
00559                 {
00560                         CGenParser::endElement(name);
00561                 }
00562                 catch(pass_exception &)
00563                 {
00564                         ASSERT( skip_element_level == 0 );
00565 
00566                         ranges.push_back(range_type());
00567                         ranges.back().begin = elements.back().begin;
00568                         ranges.back().end = elements.back().end;
00569                         elements.pop_back();
00570                         ranges.back().previous = elements.back();
00571                 }
00572         }
00573 
00574         if( ranges.front().end == counter )
00575         {
00576                 ASSERT( elements.size() == 1 );
00577 
00578                 elements.clear();
00579                 ranges.pop_front();
00580 
00581                 // no more ranges, skip everything
00582                 if( ranges.empty() )
00583                 {
00584                         ranges.push_back(range_type());
00585                         ranges.back().begin = (counter_type)-1;
00586                         ranges.back().end = (counter_type)-1;
00587                 }
00588         }
00589 }
00590 
00591 // ------- Lookup
00592 
00593 void CMgaParser::LookupByID(const std::tstring &id, CComObjPtr<IMgaObject> &ret)
00594 {
00595         ASSERT( project != NULL );
00596 
00597         ret.Release();
00598 
00599         id_lookup_iterator i = id_lookup.find(id);
00600         if( i != id_lookup.end() )
00601         {
00602                 HRESULT hr = project->GetObjectByID((*i).second, PutOut(ret));
00603                 if (hr != E_MGA_BAD_ID)
00604                         // FIXME: test and enable
00605                         ; // COMTHROW(hr);
00606         }
00607 }
00608 
00609 void CMgaParser::LookupByID(const std::tstring &id, CComObjPtr<IMgaFCO> &ret)
00610 {
00611         ASSERT( project != NULL );
00612 
00613         ret.Release();
00614 
00615         id_lookup_iterator i = id_lookup.find(id);
00616         if( i != id_lookup.end() )
00617         {
00618                 HRESULT hr = project->GetFCOByID((*i).second, PutOut(ret));
00619                 if (hr != E_MGA_BAD_ID)
00620                         // FIXME: test and enable
00621                         ; // COMTHROW(hr);
00622         }
00623 }
00624 
00625 bool CMgaParser::RegisterLookup(const std::tstring &id, IMgaObject *object)
00626 {
00627         ASSERT( object != NULL );
00628 
00629         CComBstrObj &mgaid = id_lookup[id];
00630         ASSERT( mgaid.p == NULL );
00631         if (mgaid.p != NULL)
00632         {
00633                 return false;
00634         }
00635 
00636         COMTHROW( object->get_ID(PutOut(mgaid)) );
00637         return true;
00638 }
00639 
00640 void CMgaParser::RegisterLookup(const attributes_type &attributes, IMgaObject *object)
00641 {
00642         bool perm_present = false; // currently the perm attribute appears only if the object is readonly
00643         attributes_iterator i = attributes.begin();
00644         attributes_iterator e = attributes.end();
00645         while( i != e )
00646         {
00647                 if( (*i).first == _T("id") )
00648                 {
00649                         if (RegisterLookup((*i).second, object) == false)
00650                         {
00651                                 std::wstring err = L"Duplicate id '" + (*i).second + L"'";
00652                                 throw_com_error(E_MGA_INVALID_ARG, err.c_str());
00653                         }
00654 
00655                 }
00656                 else if( (*i).first == _T("guid") )
00657                 {
00658                         bool dup = !RegisterLookup((*i).second, object);
00659                         // KMS: due to a bug in MgaFolder::CopyFCOs (ObjTreeCopyFoldersToo), some mga files (and thus xme files) may have duplicate GUIDs
00660                         // If we have a Mga.dtd-type file, re-assign the dup GUIDs (==don't PutGuidDisp the parsed GUID)
00661                         // If we have a Mga2.dtd-type file, this is a hard error (consider: what if a connection, reference, or set is connected to a dup GUID?)
00662                         if (dup)
00663                         {
00664                                 // "id" not in attributes => Mga2.dtd-type file
00665                                 auto old_id = std::find_if(attributes.begin(), attributes.end(), [](const attributes_type::value_type& val) -> bool { return val.first == L"id"; });
00666                                 if (old_id == attributes.end())
00667                                 {
00668                                         std::wstring err = L"Duplicate id '" + (*i).second + L"'";
00669                                         throw_com_error(E_MGA_INVALID_ARG, err.c_str());
00670                                 }
00671                         }
00672                         // n.b. dup == true means (*i).second is not registered in lookup. This is ok, since we have a Mga.dtd-type file
00673                         if (m_maintainGuids && !dup)
00674                         {
00675                                 // when fco was created already got a fresh GUID, but we need to maintain
00676                                 // the old guid, thus we overwrite the old value with the parsed one
00677                                 COMTHROW(object->PutGuidDisp( CComBSTR( (*i).second.c_str())));
00678                         }
00679                 }
00680                 else if( (*i).first == _T("perm") )
00681                 {
00682                         // the plain presence of the attribute indicates 'ro' flag
00683                         // no need to parse the value: (*i).second
00684                         perm_present = true;
00685                 }
00686 
00687                 ++i;
00688         }
00689         
00690         readonly_stack.push_back( perm_present); // we insert a value anyway into the stack
00691 }
00692 
00693 template<typename F>
00694 static void fire(const std::tstring& namestr, CMgaParser::elementfunc elementfuncs[], F& f)
00695 {
00696         // TODO: replace with binary search or perfect hash
00697         for(unsigned int index = 0; !elementfuncs[index].name.empty(); index++)
00698         {
00699                 if( namestr == elementfuncs[index].name )
00700                 {
00701                         f(elementfuncs[index]);
00702                         break;
00703                 }
00704         }
00705 }
00706 
00707 static void fireStart(CMgaParser* that, const std::tstring& namestr, const CMgaParser::attributes_type& attributes,
00708         CMgaParser::elementfunc elementfuncs[])
00709 {
00710         fire(namestr, elementfuncs, [&](CMgaParser::elementfunc& f) { f.Start(that, attributes); });
00711 }
00712 
00713 static void fireEnd(CMgaParser* that, const std::tstring& namestr, CMgaParser::elementfunc elementfuncs[])
00714 {
00715         fire(namestr, elementfuncs, [&](CMgaParser::elementfunc& f) { f.End(that); });
00716 }
00717 
00718 void CMgaParser::fireStartFunction(const std::tstring& namestr, const attributes_type& attributes)
00719 {
00720         switch (funcTableState) {
00721         case MGA:
00722                 fireStart(this, namestr, attributes, elementfuncs_mga);
00723                 break;
00724         case MGA_INFO:
00725                 fireStart(this, namestr, attributes, elementfuncs_mgainfo);
00726                 break;
00727         case BC_MGA:
00728                 fireStart(this, namestr, attributes, elementfuncs_bcmga);
00729                 break;
00730         case SC_MGA:
00731                 fireStart(this, namestr, attributes, elementfuncs_scmga);
00732                 break;
00733         default: /* CLIP_MGA_INFO */
00734                 fireStart(this, namestr, attributes, elementfuncs_clipmgainfo);
00735         }
00736 }
00737 
00738 void CMgaParser::fireEndFunction(const std::tstring& namestr)
00739 {
00740         switch (funcTableState) {
00741         case MGA:
00742                 fireEnd(this, namestr, elementfuncs_mga);
00743                 break;
00744         case MGA_INFO:
00745                 fireEnd(this, namestr, elementfuncs_mgainfo);
00746                 break;
00747         case BC_MGA:
00748                 fireEnd(this, namestr, elementfuncs_bcmga);
00749                 break;
00750         case SC_MGA:
00751                 fireEnd(this, namestr, elementfuncs_scmga);
00752                 break;
00753         default: /* CLIP_MGA_INFO */
00754                 fireEnd(this, namestr, elementfuncs_clipmgainfo);
00755         }
00756 }
00757 
00758 CMgaParser::elementfunc CMgaParser::elementfuncs_mga[] = 
00759 {
00760         elementfunc(_T("project"), StartProject, EndNone),
00761         elementfunc(_T("name"), StartNone, EndName),
00762         elementfunc(_T("comment"), StartNone, EndComment),
00763         elementfunc(_T("author"), StartNone, EndAuthor),
00764         elementfunc(_T("value"), StartNone, EndValue),
00765         elementfunc(_T("folder"), StartFolder, EndObject),
00766         elementfunc(_T("model"), StartModel, EndObject),
00767         elementfunc(_T("atom"), StartAtom, EndObject),
00768         elementfunc(_T("regnode"), StartRegNode, EndNone),
00769         elementfunc(_T("attribute"), StartAttribute, EndNone),
00770         elementfunc(_T("connection"), StartConnection, EndObject),
00771         elementfunc(_T("connpoint"), StartConnPoint, EndNone),
00772         elementfunc(_T("constraint"), StartNone, EndConstraint),
00773         elementfunc(_T("reference"), StartReference, EndObject),
00774         elementfunc(_T("set"), StartSet, EndObject),
00775         elementfunc(_T("clipboard"), StartClipboard, EndNone),
00776         elementfunc(_T(""), NULL, NULL)
00777 };
00778 
00779 // ------- Element Handlers
00780 
00781 void CMgaParser::StartProject(const attributes_type &attributes)
00782 {
00783         ASSERT( project != NULL );
00784 
00785         GetCurrent().object = project;
00786 
00787         // get metaproject
00788         CComObjPtr<IMgaMetaProject> metaproject;
00789         if( project) COMTHROW( project->get_RootMeta(PutOut(metaproject)) );
00790         ASSERT( metaproject != NULL );
00791         
00792         // obtain the current paradigm name
00793         CComBSTR host_pn;
00794         if( metaproject) COMTHROW( metaproject->get_Name( &host_pn));
00795 
00796         // is the resolver interactive?
00797         VARIANT_BOOL int_mode = VARIANT_FALSE;
00798         COMTHROW( resolver->get_IsInteractive( &int_mode));
00799 
00800         attributes_iterator i = attributes.begin();
00801         attributes_iterator e = attributes.end();
00802         while( i != e )
00803         {
00804                 if( i->first == _T("guid") )
00805                 {
00806                         _bstr_t bstr = i->second.c_str();
00807 
00808                         GUID guid;
00809                         CopyTo(bstr, guid);
00810 
00811                         CopyTo(guid, projectguid);
00812                 }
00813                 else if( i->first == _T("version") )
00814                 {       
00815                         CComBSTR currversion;
00816                         COMTHROW( project->get_Version(&currversion) );
00817                         if (currversion.Length() == 0) {
00818                                 projectversion = i->second.c_str();
00819                         }
00820                 }
00821                 else if( i->first == _T("metaname"))
00822                 {
00823                         // if host paradigm != imported project's paradigm
00824                         if( host_pn != CComBSTR( i->second.c_str()))
00825                         {
00826                                 if( int_mode == VARIANT_TRUE) // if interactive
00827                                 {
00828                                         COMTHROW(resolver->getUserOptions());
00829                                 }
00830                         }
00831                 }
00832 
00833                 ++i;
00834         }
00835 }
00836 
00837 void CMgaParser::StartClipboard(const attributes_type &attributes)
00838 {
00839         ASSERT( project != NULL );
00840         ASSERT( GetPrevName() == _T("start") );
00841         ASSERT( GetPrevious().object != NULL );
00842         if( !GetPrevious().object) HR_THROW(E_XMLPARSER);//by ZolMol
00843 
00844         const CComObjPtr<IUnknown> &obj = GetPrevious().object;
00845         GetCurrent().object = obj;
00846 
00847         // get metaproject
00848         CComObjPtr<IMgaMetaProject> metaproject;
00849         if( project) COMTHROW( project->get_RootMeta(PutOut(metaproject)) );
00850         ASSERT( metaproject != NULL );
00851         
00852         // obtain the current paradigm name
00853         CComBSTR host_pn;
00854         if( metaproject) COMTHROW( metaproject->get_Name( &host_pn));
00855 
00856         // is the resolver interactive?
00857         VARIANT_BOOL int_mode = VARIANT_FALSE;
00858         COMTHROW( resolver->get_IsInteractive( &int_mode));
00859 
00860         CComObjPtr<IMgaModel> model;
00861         CComObjPtr<IMgaFolder> folder;
00862 
00863         if( SUCCEEDED(obj.QueryInterface(model)) )
00864                 GetCurrent().name = _T("model");
00865         else if( SUCCEEDED(obj.QueryInterface(folder)) )
00866                 GetCurrent().name = _T("folder");
00867         // Commented, thus allowing clipboard snippets to be 
00868         // dropped onto atoms/sets/references/connections too
00869         //else
00870         //      HR_THROW(E_INVALID_FILENAME);
00871 
00872         const std::tstring *parname_hint = GetByNameX(attributes, _T("paradigmnamehint"));
00873         // importing from different paradigm
00874         if( parname_hint != NULL && host_pn != CComBSTR( parname_hint->c_str()))
00875         {
00876                 if( int_mode == VARIANT_TRUE)
00877                 {
00878                         COMTHROW(resolver->getUserOptions());
00879                 }
00880         }
00881 }
00882 
00883 void CMgaParser::EndName()
00884 {
00885         if( GetPrevName() == _T("project") )
00886         {
00887             COMTHROW( project->put_Name(PutInBstr(GetCurrData())) );
00888         }
00889         else if( GetPrevName() == _T("constraint") )
00890         {
00891                 constraint_name = GetCurrData();
00892         }
00893         else if( GetPrevious().object != NULL ) 
00894         {
00895                 CComObjPtr<IMgaObject> prev;
00896                 GetPrevObj(prev);
00897                 COMTHROW( prev->put_Name(PutInBstr(GetCurrData())) );
00898         }
00899 }
00900 
00901 void CMgaParser::EndComment()
00902 {
00903         if( GetPrevName() == _T("project") )
00904         {
00905                 COMTHROW( project->put_Comment(PutInBstr(GetCurrData())) );
00906         }
00907         else
00908                 HR_THROW(E_INVALID_DTD);
00909 }
00910 
00911 void CMgaParser::EndAuthor()
00912 {
00913         if( GetPrevName() == _T("project") )
00914         {
00915             COMTHROW( project->put_Author(PutInBstr(GetCurrData())) );
00916         }
00917         else
00918                 HR_THROW(E_INVALID_DTD);
00919 }
00920 
00921 void CMgaParser::EndValue()
00922 {
00923         // skip if the object is ignored
00924         if( GetPrevious().object == NULL )
00925                 return;
00926 
00927         if( GetPrevName() == _T("constraint") )
00928         {
00929                 constraint_value = GetCurrData();
00930         }
00931         else if( GetPrevName() == _T("regnode") )
00932         {
00933                 CComObjPtr<IMgaRegNode> regnode;
00934                 GetPrevObj(regnode);
00935 
00936                 long status;
00937                 COMTHROW( regnode->get_Status(&status) );
00938 
00939                 // when we create the registry node, 
00940                 // we fill it by an empty string if not inherited or not undefined
00941                 if( status == 0 )
00942                         COMTHROW( regnode->put_Value(PutInBstr(GetCurrData())) );
00943         }
00944         else if( GetPrevName() == _T("attribute") ) 
00945         {
00946                 CComObjPtr<IMgaAttribute> attr;
00947                 GetPrevObj(attr);
00948 
00949                 long status;
00950                 COMTHROW( attr->get_Status(&status) );
00951 
00952                 // if inherited, then do not modify the value
00953                 if( status != 0 )
00954                         return;
00955 
00956                 CComObjPtr<IMgaMetaAttribute> metaattr;
00957                 COMTHROW( attr->get_Meta(PutOut(metaattr)) );
00958                 ASSERT( metaattr != NULL );
00959 
00960                 attval_enum attval;
00961                 COMTHROW( metaattr->get_ValueType(&attval) );
00962 
00963                 CComVariant v;
00964 
00965                 switch( attval )
00966                 {
00967                 case ATTVAL_STRING:
00968                 case ATTVAL_ENUM:
00969                 case ATTVAL_DYNAMIC:
00970                         v = GetCurrData().c_str();
00971                         break;
00972 
00973                 case ATTVAL_INTEGER:
00974                         v = GetCurrData().c_str();
00975                         COMTHROW( v.ChangeType(VT_I4) );
00976                         break;
00977 
00978                 case ATTVAL_DOUBLE:
00979                         {
00980                         const wchar_t* val = GetCurrData().c_str();
00981                         double special;
00982                         if (ParseSpecialDouble(val, special))
00983                         {
00984                                 v = special;
00985                         }
00986                         else
00987                         {
00988                                 double doubleVal;
00989                                 _swscanf_s_l(val, L"%lg", c_locale, &doubleVal);
00990                                 v = doubleVal;
00991                         }
00992                         }
00993                         break;
00994 
00995                 case ATTVAL_BOOLEAN:
00996                         {
00997                                 char c = tolower(*GetCurrData().c_str());
00998                                 CopyTo( (c == 't' || c == '1' || c == 'y') ? VARIANT_TRUE : VARIANT_FALSE, v);
00999                                 break;
01000                         }
01001 
01002                 case ATTVAL_REFERENCE:
01003                         {
01004                                 CComObjPtr<IMgaFCO> object;
01005                                 LookupByID(GetCurrData(), object);
01006 
01007                                 if( object == NULL )
01008                                         throw pass_exception(std::wstring(L"Referenced FCO ") + GetCurrData() + L" not found");
01009 
01010                                 CopyTo(object, v);
01011                         }
01012 
01013                 default:
01014                         HR_THROW(E_INVALID_META);
01015 
01016                 };
01017 
01018                 COMTHROW( attr->put_Value(v) );
01019         }
01020 }
01021 
01022 
01023 
01024 
01025 void CMgaParser::preparerelid(const attributes_type &attributes) {
01026         const std::tstring & relidattr = GetByName(attributes, _T("relid"));
01027         ASSERT(relid == -2);
01028         if(relidattr.size()) {
01029                 relid = _tcstol(relidattr.c_str(), NULL, 0);
01030                 if(!manual_relid_mode) {
01031                         COMTHROW(project->put_Preferences(project_prefs | MGAPREF_MANUAL_RELIDS));
01032                 }
01033                 ASSERT(relid >= 0 && 
01034                            relid <= RELID_BASE_MAX && 
01035                            GetPrevious().exnuminfo >= relid);
01036         }       
01037         else {
01038                 if(!manual_relid_mode) {
01039                         COMTHROW(project->put_Preferences(project_prefs & ~MGAPREF_MANUAL_RELIDS));
01040                 }
01041                 relid = -1;
01042         }
01043 }
01044 
01045 
01046 void CMgaParser::assignrelid(IMgaObject *obj) {
01047         ASSERT(relid != -2);
01048         if(relid > 0) {
01049                 COMTHROW(obj->put_RelID(relid));
01050         }
01051         relid = -2;
01052 }
01053 
01054 void CMgaParser::StartFolder(const attributes_type &attributes)
01055 {
01056         CComObjPtr<IMgaFolder> folder;
01057 
01058         if( GetPrevName() == _T("project") )
01059         {
01060                 COMTHROW( project->get_RootFolder(PutOut(folder)) );
01061         }
01062         else
01063         {
01064                 CComObjPtr<IMgaFolder> prev;
01065                 GetPrevObj(prev);
01066 
01067                 CComObjPtr<IMgaMetaFolder> meta;
01068                 _bstr_t fname(PutInBstrAttr(attributes, _T("kind")));
01069         const std::tstring &libn = GetByName(attributes, _T("libref"));
01070 
01071                 preparerelid(attributes);
01072 
01073                 VARIANT_BOOL previactmode;
01074                 COMTHROW(resolver->get_IsInteractive(&previactmode));
01075                 COMTHROW(resolver->put_IsInteractive(VARIANT_FALSE));
01076                 HRESULT hr = resolver->get_FolderByStr(prev, fname, PutOut(meta));
01077                 COMTHROW(resolver->put_IsInteractive(previactmode));
01078 
01079                 bool cheat = false;
01080                 if(FAILED(hr) && libn.size()) {
01081                         CComPtr<IMgaMetaProject> mp;  // it is a library, maybe a rootfolder
01082                         COMTHROW(project->get_RootMeta(&mp));
01083                         COMTHROW(mp->get_RootFolder(PutOut(meta)));
01084                         CComBSTR nn;
01085                         COMTHROW(meta->get_Name(&nn));
01086                         if(wcscmp(nn, fname)) {
01087                                 COMTHROW(hr);
01088                         }
01089                         COMTHROW(project->CheckSupress(VARIANT_TRUE));
01090                         cheat = true;
01091                 } else if (FAILED(hr)) {
01092                         _bstr_t error;
01093                         if (GetErrorInfo(error.GetAddress()))
01094                         {
01095                                 throw_com_error(hr, error);
01096                         }
01097                         COMTHROW(hr);
01098                 }
01099                 ASSERT(meta);
01100         
01101                 hr = prev->CreateFolder(meta, PutOut(folder));
01102                 if(cheat) {
01103                         if(folder) COMTHROW(folder->put_Exempt(VARIANT_TRUE));
01104                         COMTHROW(project->CheckSupress(VARIANT_FALSE));
01105                 }
01106                 COMTHROW(hr);
01107                 assignrelid(folder);
01108                 if(libn.size()) {
01109                         librecord lr;
01110                         lr.f = folder;
01111                         lr.libname = libn;
01112                         libstodo.push_back(lr);
01113                 }
01114         }
01115         ASSERT( folder != NULL );
01116         GetCurrent().object = folder;
01117 
01118         long crid = toLong(GetByName(attributes,_T("childrelidcntr")));
01119         GetCurrent().exnuminfo = crid;
01120         COMTHROW(folder->put_ChildRelIDCounter(crid));
01121 
01122         //RegisterReadOnlyStatus( attributes);
01123         RegisterLookup(attributes, folder);
01124 }
01125 
01126 void CMgaParser::ResolveDerivation(const attributes_type &attributes, deriv_type &deriv)
01127 {
01128         const std::tstring *s = GetByNameX(attributes, _T("derivedfrom"));
01129         if( s == NULL )
01130         {
01131                 deriv.from.Release();
01132                 return;
01133         }
01134 
01135         LookupByID(*s, deriv.from);
01136         if( deriv.from == NULL )
01137         {
01138                 const std::tstring* name = GetByNameX(attributes, _T("id"));
01139                 if (name == NULL)
01140                 {
01141                         name = GetByNameX(attributes, _T("guid"));
01142                 }
01143                 throw pass_exception(std::wstring(L"Subtype/instance ") + *name + L" cannot find archetype " + *s);
01144         }
01145 
01146         s = GetByNameX(attributes, _T("isinstance"));
01147         deriv.isinstance = ( s != NULL && *s == _T("yes") ) ? VARIANT_TRUE : VARIANT_FALSE;
01148 
01149         s = GetByNameX(attributes, _T("isprimary"));
01150         deriv.isprimary = ( s != NULL && *s == _T("no") ) ? false : true;
01151 }
01152 
01153 void CMgaParser::StartModel(const attributes_type &attributes)
01154 {
01155         CComObjPtr<IMgaFCO> model;
01156 
01157         deriv_type deriv;
01158         //ResolveDerivation(attributes, deriv);
01159         (*this.*m_resolveDerFuncPtr)(attributes, deriv);
01160 
01161 
01162         if( GetPrevName() == _T("folder") )
01163         {
01164                 CComObjPtr<IMgaFolder> prev;
01165                 GetPrevObj(prev);
01166 
01167                 preparerelid(attributes);
01168                 if( deriv.from != NULL )
01169                 {
01170                         COMTHROW( prev->DeriveRootObject(deriv.from, deriv.isinstance, PutOut(model)) );
01171                 }
01172                 else
01173                 {
01174                         CComObjPtr<IMgaMetaFCO> meta;
01175                         meta = resolver->KindByStr[prev, PutInBstrAttr(attributes, _T("kind")), 
01176                                 OBJTYPE_MODEL];
01177                         ASSERT( meta != NULL );
01178 
01179                         COMTHROW( prev->CreateRootObject(meta, PutOut(model)) );
01180                 }
01181                 assignrelid(model);
01182         }
01183         else
01184         {
01185                 ASSERT( GetPrevName() == _T("model") );
01186 
01187                 CComObjPtr<IMgaModel> prev;
01188                 GetPrevObj(prev);
01189 
01190                 CComObjPtr<IMgaMetaRole> role;
01191                 role = resolver->RoleByStr[prev.p,
01192                         PutInBstrAttr(attributes, _T("kind")), OBJTYPE_MODEL,
01193                         PutInBstrAttr(attributes, _T("role")), _bstr_t()];
01194                 ASSERT( role != NULL );
01195 
01196                 if( deriv.from != NULL )
01197                 {
01198                         CComObjPtr<IMgaModel> derivedfrom;
01199                         COMTHROW( deriv.from.QueryInterface(derivedfrom) );
01200 
01201                         if( deriv.isprimary )
01202                         {
01203                                 preparerelid(attributes);
01204                                 COMTHROW( prev->DeriveChildObject(derivedfrom, role, deriv.isinstance, PutOut(model)) );
01205                                 assignrelid(model);
01206                         }
01207                         else
01208                         {
01209                                 COMTHROW( prev->get_ChildDerivedFrom(derivedfrom, PutOut(model)) );
01210                         }
01211                 }
01212                 else
01213                 {
01214                         preparerelid(attributes);
01215                         COMTHROW( prev->CreateChildObject(role, PutOut(model)) );
01216                         assignrelid(model);
01217                 }
01218         }
01219         ASSERT( model != NULL );
01220 
01221         GetCurrent().object = model;
01222         long crid = toLong(GetByName(attributes,_T("childrelidcntr")));
01223         GetCurrent().exnuminfo = crid;
01224         COMTHROW(CComQIPtr<IMgaModel>(model)->put_ChildRelIDCounter(crid));
01225 
01226         //RegisterReadOnlyStatus( attributes);
01227         RegisterLookup(attributes, model);
01228 }
01229 
01230 void CMgaParser::StartAtom(const attributes_type &attributes)
01231 {
01232         CComObjPtr<IMgaFCO> atom;
01233 
01234         deriv_type deriv;
01235         //ResolveDerivation(attributes, deriv);
01236         (*this.*m_resolveDerFuncPtr)(attributes, deriv);
01237 
01238 
01239         if( GetPrevName() == _T("folder") )
01240         {
01241                 CComObjPtr<IMgaFolder> prev;
01242                 GetPrevObj(prev);
01243 
01244                 if( deriv.from != NULL )
01245                 {
01246                         COMTHROW( prev->DeriveRootObject(deriv.from, deriv.isinstance, PutOut(atom)) );
01247                 }
01248                 else
01249                 {
01250                         CComObjPtr<IMgaMetaFCO> meta;
01251                         meta = resolver->KindByStr[prev, PutInBstrAttr(attributes, _T("kind")), OBJTYPE_ATOM];
01252                         ASSERT( meta != NULL );
01253 
01254                         preparerelid(attributes);
01255                         COMTHROW( prev->CreateRootObject(meta, PutOut(atom)) );
01256                         assignrelid(atom);
01257                 }
01258         }
01259         else
01260         {
01261                 ASSERT( GetPrevName() == _T("model") );
01262 
01263                 CComObjPtr<IMgaModel> prev;
01264                 GetPrevObj(prev);
01265 
01266                 CComObjPtr<IMgaMetaRole> role;
01267                 role = resolver->RoleByStr[prev, 
01268                         PutInBstrAttr(attributes, _T("kind")), OBJTYPE_ATOM,
01269                         PutInBstrAttr(attributes, _T("role")), _bstr_t()];
01270                 ASSERT( role != NULL );
01271 
01272                 if( deriv.from != NULL )
01273                 {
01274                         CComObjPtr<IMgaAtom> derivedfrom;
01275                         COMTHROW( deriv.from.QueryInterface(derivedfrom) );
01276 
01277                         if( deriv.isprimary )
01278                         {
01279                                 preparerelid(attributes);
01280                                 COMTHROW( prev->DeriveChildObject(derivedfrom, role, deriv.isinstance, PutOut(atom)) );
01281                                 assignrelid(atom);
01282                         }
01283                         else
01284                         {
01285                                 COMTHROW( prev->get_ChildDerivedFrom(derivedfrom, PutOut(atom)) );
01286                         }
01287                 }
01288                 else
01289                 {
01290                         preparerelid(attributes);
01291                         COMTHROW( prev->CreateChildObject(role, PutOut(atom)) );
01292                         assignrelid(atom);
01293                 }
01294         }
01295 
01296         ASSERT( atom != NULL );
01297         GetCurrent().object = atom;
01298 
01299         //RegisterReadOnlyStatus( attributes);
01300         RegisterLookup(attributes, atom);
01301 }
01302 
01303 void CMgaParser::StartRegNode(const attributes_type &attributes)
01304 {
01305         CComObjPtr<IMgaRegNode> regnode;
01306 
01307         _bstr_t name = GetByName(attributes, _T("name")).c_str();
01308 
01309         if( GetPrevName() == _T("regnode") )
01310         {
01311                 CComObjPtr<IMgaRegNode> prev;
01312                 GetPrevObj(prev);
01313 
01314                 COMTHROW( prev->get_SubNodeByName(name, PutOut(regnode)) );
01315         }
01316         else if( GetPrevName() == _T("folder") )
01317         {
01318                 CComObjPtr<IMgaFolder> prev;
01319                 GetPrevObj(prev);
01320 
01321                 COMTHROW( prev->get_RegistryNode(name, PutOut(regnode)) );
01322         }
01323         else if( GetPrevName()== _T("attribute") )
01324         {
01325                 CComObjPtr<IMgaAttribute> prev;
01326                 GetPrevObj(prev);
01327 
01328                 COMTHROW( prev->get_RegistryNode(name, PutOut(regnode)) );
01329         }
01330         else
01331         {
01332                 CComObjPtr<IMgaFCO> prev;
01333                 GetPrevObj(prev);
01334 
01335                 COMTHROW( prev->get_RegistryNode(name, PutOut(regnode)) );
01336         }
01337         ASSERT( regnode != NULL );
01338 
01339         if( GetByNameX(attributes, _T("status")) == NULL )
01340                 COMTHROW( regnode->put_Value(NULL) );
01341 
01342         if( GetByName(attributes, _T("isopaque")) == _T("yes") )
01343                 COMTHROW( regnode->put_Opacity(VARIANT_TRUE) );
01344 
01345         GetCurrent().object = regnode;
01346 }
01347 
01348 void CMgaParser::StartAttribute(const attributes_type &attributes)
01349 {
01350         CComObjPtr<IMgaAttribute> attr;
01351 
01352         CComObjPtr<IMgaFCO> fco;
01353         GetPrevObj(fco);
01354 
01355         CComObjPtr<IMgaMetaAttribute> metaattr;
01356         HRESULT hr;
01357         const std::tstring* status = GetByNameX(attributes, _T("status"));
01358         if (status && *status == L"meta")
01359                 ;
01360         else
01361                 hr = resolver->get_AttrByStr(fco, PutInBstrAttr(attributes, _T("kind")), PutOut(metaattr));
01362 
01363         if (metaattr == NULL || FAILED(hr))
01364         {
01365                 GetCurrent().object = NULL;
01366                 return;
01367         }
01368 
01369         COMTHROW( fco->get_Attribute(metaattr, PutOut(attr)) );
01370 
01371         ASSERT( attr != NULL );
01372         GetCurrent().object = attr;
01373 
01374         if(status == NULL )
01375         {
01376                 // we set some value, and from the _T("value") element we set the actual value
01377 
01378                 CComVariant v;
01379                 COMTHROW( attr->get_Value(PutOut(v)) );
01380                 COMTHROW( attr->put_Value(v) );
01381         }
01382 }
01383 
01384 void CMgaParser::StartConnection(const attributes_type &attributes)
01385 {
01386         CComObjPtr<IMgaFCO> conn;
01387 
01388         deriv_type deriv;
01389         //ResolveDerivation(attributes, deriv);
01390         (*this.*m_resolveDerFuncPtr)(attributes, deriv);
01391 
01392         if( GetPrevName() == _T("folder") )
01393         {
01394                 CComObjPtr<IMgaFolder> prev;
01395                 GetPrevObj(prev);
01396 
01397                 preparerelid(attributes);
01398                 if( deriv.from != NULL )
01399                 {
01400                         COMTHROW( prev->DeriveRootObject(deriv.from, deriv.isinstance, PutOut(conn)) );
01401                 }
01402                 else
01403                 {
01404                         CComObjPtr<IMgaMetaFCO> meta;
01405                         meta = resolver->KindByStr[prev, PutInBstrAttr(attributes, _T("kind")), OBJTYPE_CONNECTION];
01406                         ASSERT( meta != NULL );
01407 
01408                         COMTHROW( prev->CreateRootObject(meta, PutOut(conn)) );
01409                 }
01410                 assignrelid(conn);
01411         }
01412         else
01413         {
01414                 ASSERT( GetPrevName() == _T("model") );
01415                 CComObjPtr<IMgaModel> prev;
01416                 GetPrevObj(prev);
01417 
01418                 CComObjPtr<IMgaMetaRole> role;
01419                 role = resolver->RoleByStr[prev, 
01420                         PutInBstrAttr(attributes, _T("kind")), OBJTYPE_CONNECTION,
01421                         PutInBstrAttr(attributes, _T("role")), _bstr_t()];
01422                 ASSERT( role != NULL );
01423 
01424                 if( deriv.from != NULL )
01425                 {
01426                         CComObjPtr<IMgaConnection> derivedfrom;
01427                         COMTHROW( deriv.from.QueryInterface(derivedfrom) );
01428 
01429                         if( deriv.isprimary )
01430                         {
01431                                 preparerelid(attributes);
01432                                 COMTHROW( prev->DeriveChildObject(derivedfrom, role, deriv.isinstance, PutOut(conn)) );
01433                                 assignrelid(conn);
01434                         }
01435                         else
01436                         {
01437                                 COMTHROW( prev->get_ChildDerivedFrom(derivedfrom, PutOut(conn)) );
01438                         }
01439                 }
01440                 else
01441                 {
01442                         preparerelid(attributes);
01443                         COMTHROW( prev->CreateChildObject(role, PutOut(conn)) );
01444                         assignrelid(conn);
01445                 }
01446         }
01447         ASSERT( conn != NULL );
01448         GetCurrent().object = conn;
01449 
01450         if( GetByName(attributes, _T("isbound")) == _T("yes") ) GetCurrent().exstrinfo = _T("skip");
01451 
01452         //RegisterReadOnlyStatus( attributes);
01453         RegisterLookup(attributes, conn);
01454 }
01455 
01456 void CMgaParser::StartConnPoint(const attributes_type &attributes)
01457 {
01458         ASSERT( GetPrevName() == _T("connection") );
01459         CComObjPtr<IMgaConnection> conn;
01460         GetPrevObj(conn);
01461 
01462         if( GetPrevious().exstrinfo == _T("skip") || GetByName(attributes, _T("isbound")) == _T("yes") ) return;
01463 
01464         CComObjPtr<IMgaFCO> target;
01465         LookupByID(GetByName(attributes, _T("target")), target);
01466         if( target == NULL )
01467                 throw pass_exception(std::wstring(L"Connection end ") + GetByName(attributes, _T("target")) + L" not found");
01468 
01469 
01470         CComObjPtr<IMgaFCOs> coll;
01471         COMTHROW(coll.CoCreateInstance(L"Mga.MgaFCOs"));
01472 
01473         const std::tstring *s = GetByNameX(attributes, _T("refs"));
01474         if( s != NULL )
01475         {
01476                 int pos = s->find_first_not_of(' ', 0);
01477                 ASSERT( pos >= 0 );
01478                 while( pos < (int) s->length() )
01479                 {
01480                         int pos2 = s->find_first_of(' ', pos);
01481                         if( pos2 < 0 )
01482                                 pos2 = s->length();
01483                         ASSERT( pos2 > pos );
01484 
01485                         CComObjPtr<IMgaFCO> ref;
01486                         LookupByID(std::tstring(*s, pos, pos2-pos), ref);
01487 
01488                         if( ref == NULL )
01489                                 throw pass_exception();
01490 
01491                         COMTHROW(coll->Append(ref));
01492 
01493                         pos = pos2+1;
01494                 }
01495         }
01496 
01497         CComObjPtr<IMgaConnPoint> connpoint;
01498 
01499         const std::tstring& role = GetByName(attributes, _T("role"));
01500         _bstr_t brole = role.c_str();
01501 
01502         // Since the Refresh operation created some derived connections
01503         // in its own way, some derived connections might have been
01504         // dumped with connroles, so that when the import happened
01505         // the number of connroles went up to 4 or 6 or ...
01506         // So to mitigate this issue the parser has been enhanced
01507         // to eliminate superfuous connroles in case of derived conns
01508         CComPtr<IMgaConnPoints> connpoints;
01509         COMTHROW( conn->get_ConnPoints( &connpoints));
01510         long c = 0;
01511         if( connpoints) COMTHROW( connpoints->get_Count( &c));
01512         for( long i = 1; i <= c; ++i)
01513         {
01514                 CComPtr<IMgaConnPoint> old_cp;
01515                 COMTHROW( connpoints->get_Item( i, &old_cp));
01516                 if( old_cp)
01517                 {
01518                         CComBSTR old_role;
01519                         COMTHROW( old_cp->get_ConnRole( &old_role));
01520                         if( old_role == static_cast<LPCOLESTR>(brole)) // check if targets are equal
01521                         {
01522                                 CComPtr<IMgaFCO> old_tgt;
01523                                 COMTHROW( old_cp->get_Target( &old_tgt));
01524                                 if( old_tgt == target)
01525                                 {
01526                                         // same role not inserted twice
01527                                         CComBSTR msg( L"Warning: Superfluous connection role ignored!");
01528                                         if( m_GME) COMTHROW( m_GME->ConsoleMessage( msg, MSG_WARNING));
01529                                         return;
01530                                 }
01531                         }
01532                 }
01533         }
01534 
01535         COMTHROW( conn->AddConnPoint(PutInBstr(GetByName(attributes, _T("role"))), 0,   // FIXME: multiplicity
01536                 target, coll, PutOut(connpoint)) );
01537 }
01538 
01539 void CMgaParser::EndConstraint()
01540 {
01541         CComObjPtr<IMgaConstraint> constraint;
01542 
01543         if( GetPrevName() == _T("folder") )
01544         {
01545                 CComObjPtr<IMgaFolder> folder;
01546                 GetPrevObj(folder);
01547 
01548                 COMTHROW( folder->DefineConstraint(PutInBstr(constraint_name), 0, // FIXME: the mask
01549                         PutInBstr(constraint_value), PutOut(constraint)) );
01550         }
01551         else
01552         {
01553                 CComObjPtr<IMgaFCO> fco;
01554                 GetPrevObj(fco);
01555 
01556                 COMTHROW( fco->DefineConstraint(PutInBstr(constraint_name), 0, // FIXME: the mask
01557                         PutInBstr(constraint_value), PutOut(constraint)) );
01558         }
01559 }
01560 
01561 void CMgaParser::StartReference(const attributes_type &attributes)
01562 {
01563         CComObjPtr<IMgaFCO> fco;
01564 
01565         deriv_type deriv;
01566         //ResolveDerivation(attributes, deriv);
01567         (*this.*m_resolveDerFuncPtr)(attributes, deriv);
01568 
01569         CComObjPtr<IMgaFCO> referred;
01570 
01571         const std::tstring *s = GetByNameX(attributes, _T("referred"));
01572         if( s != NULL )
01573         {
01574                 LookupByID(*s, referred);
01575 
01576                 if( referred == NULL )
01577                         throw pass_exception(std::wstring(L"Referenced FCO ") + GetCurrData() + L" not found");
01578         }
01579 
01580         if( GetPrevName() == _T("folder") )
01581         {
01582                 CComObjPtr<IMgaFolder> prev;
01583                 GetPrevObj(prev);
01584 
01585                 preparerelid(attributes);
01586                 if( deriv.from != NULL )
01587                 {
01588                         COMTHROW( prev->DeriveRootObject(deriv.from, deriv.isinstance, PutOut(fco)) );
01589                 }
01590                 else
01591                 {
01592                         CComObjPtr<IMgaMetaFCO> meta;
01593                         meta = resolver->KindByStr[prev, PutInBstrAttr(attributes, _T("kind")), OBJTYPE_REFERENCE];
01594                         ASSERT( meta != NULL );
01595 
01596                         COMTHROW( prev->CreateRootObject(meta, PutOut(fco)) );
01597                 }
01598                 assignrelid(fco);
01599         }
01600         else
01601         {
01602                 ASSERT( GetPrevName() == _T("model") );
01603                 CComObjPtr<IMgaModel> prev;
01604                 GetPrevObj(prev);
01605 
01606                 CComObjPtr<IMgaMetaRole> role;
01607                 role = resolver->RoleByStr[prev, 
01608                         PutInBstrAttr(attributes, _T("kind")), OBJTYPE_REFERENCE,
01609                         PutInBstrAttr(attributes, _T("role")), _bstr_t()];
01610                 ASSERT( role != NULL );
01611 
01612                 if( deriv.from != NULL )
01613                 {
01614                         CComObjPtr<IMgaReference> derivedfrom;
01615                         COMTHROW( deriv.from.QueryInterface(derivedfrom) );
01616 
01617                         if( deriv.isprimary )
01618                         {
01619                                 preparerelid(attributes);
01620                                 COMTHROW( prev->DeriveChildObject(derivedfrom, role, deriv.isinstance, PutOut(fco)) );
01621                                 assignrelid(fco);
01622                         }
01623                         else
01624                         {
01625                                 COMTHROW( prev->get_ChildDerivedFrom(derivedfrom, PutOut(fco)) );
01626                         }
01627                 }
01628                 else
01629                 {
01630                         preparerelid(attributes);
01631                         COMTHROW( prev->CreateChildObject(role, PutOut(fco)) );
01632                         assignrelid(fco);
01633                 }
01634         }
01635         ASSERT( fco != NULL );
01636 
01637         if( !(GetByName(attributes, _T("isbound")) == _T("yes")) && referred != NULL )
01638         {
01639                 CComObjPtr<IMgaReference> ref;
01640                 COMTHROW( fco.QueryInterface(ref) );
01641 
01642                 // Derived References may have incorrect refport connections from initial creation (DeriveRootObject)
01643                 if (GetByNameX(attributes, _T("derivedfrom")) != nullptr) {
01644                         auto connPoints = ref->UsedByConns;
01645                         for (int i = 1; i <= connPoints->Count; i++) {
01646                                 auto connPoint = connPoints->GetItem(i);
01647                                 // TODO?? if (connPoint->References->GetItem(1) == fco
01648                                 connPoint->Remove(); // these will be set when <connpoint> is parsed
01649                         }
01650                 }
01651 
01652                 COMTHROW( ref->put_Referred(referred) );
01653         }
01654 
01655         GetCurrent().object = fco;
01656 
01657         //RegisterReadOnlyStatus( attributes);
01658         RegisterLookup(attributes, fco);
01659 }
01660 
01661 void CMgaParser::StartSet(const attributes_type &attributes)
01662 {
01663         CComObjPtr<IMgaFCO> fco;
01664 
01665         deriv_type deriv;
01666         //ResolveDerivation(attributes, deriv);
01667         (*this.*m_resolveDerFuncPtr)(attributes, deriv);
01668 
01669         std::list< CComObjPtr<IMgaFCO> > members;//slist
01670 
01671         const std::tstring *s = GetByNameX(attributes, _T("members"));
01672         if( s != NULL )
01673         {
01674                 int pos = s->find_first_not_of(' ', 0);
01675                 ASSERT( pos >= 0 );
01676                 while( pos < (int) s->length() )
01677                 {
01678                         int pos2 = s->find_first_of(' ', pos);
01679                         if( pos2 < 0 )
01680                                 pos2 = s->length();
01681                         ASSERT( pos2 > pos );
01682 
01683                         CComObjPtr<IMgaFCO> member;
01684                         LookupByID(std::tstring(*s, pos, pos2-pos), member);
01685 
01686                         if( member == NULL )
01687                                 throw pass_exception(std::wstring(L"Set member ") + std::tstring(*s, pos, pos2-pos) + L" not found");
01688 
01689                         members.push_front(member);
01690 
01691                         pos = pos2+1;
01692                 }
01693         }
01694 
01695         if( GetPrevName() == _T("folder") )
01696         {
01697                 CComObjPtr<IMgaFolder> prev;
01698                 GetPrevObj(prev);
01699 
01700                 preparerelid(attributes);
01701                 if( deriv.from != NULL )
01702                 {
01703                         COMTHROW( prev->DeriveRootObject(deriv.from, deriv.isinstance, PutOut(fco)) );
01704                 }
01705                 else
01706                 {
01707                         CComObjPtr<IMgaMetaFCO> meta;
01708                         meta = resolver->KindByStr[prev, PutInBstrAttr(attributes, _T("kind")), OBJTYPE_SET];
01709                         ASSERT( meta != NULL );
01710 
01711                         COMTHROW( prev->CreateRootObject(meta, PutOut(fco)) );
01712                 }
01713                 assignrelid(fco);
01714         }
01715         else
01716         {
01717                 ASSERT( GetPrevName() == _T("model") );
01718                 CComObjPtr<IMgaModel> prev;
01719                 GetPrevObj(prev);
01720 
01721                 CComObjPtr<IMgaMetaRole> role;
01722                 role = resolver->RoleByStr[prev, 
01723                         PutInBstrAttr(attributes, _T("kind")), OBJTYPE_SET,
01724                         PutInBstrAttr(attributes, _T("role")), _bstr_t()];
01725                 ASSERT( role != NULL );
01726 
01727                 if( deriv.from != NULL )
01728                 {
01729                         CComObjPtr<IMgaSet> derivedfrom;
01730                         COMTHROW( deriv.from.QueryInterface(derivedfrom) );
01731 
01732                         if( deriv.isprimary )
01733                         {
01734                                 preparerelid(attributes);
01735                                 COMTHROW( prev->DeriveChildObject(derivedfrom, role, deriv.isinstance, PutOut(fco)) );
01736                                 assignrelid(fco);
01737                         }
01738                         else
01739                         {
01740                                 preparerelid(attributes);
01741                                 COMTHROW( prev->get_ChildDerivedFrom(derivedfrom, PutOut(fco)) );
01742                                 assignrelid(fco);
01743                         }
01744                 }
01745                 else
01746                 {
01747                         preparerelid(attributes);
01748                         COMTHROW( prev->CreateChildObject(role, PutOut(fco)) );
01749                         assignrelid(fco);
01750                 }
01751         }
01752         ASSERT( fco != NULL );
01753 
01754         CComObjPtr<IMgaSet> mgaset;
01755         COMTHROW( fco.QueryInterface(mgaset) );
01756 
01757         if( !(GetByName(attributes, _T("isbound")) == _T("yes")) ) {
01758                 COMTHROW( mgaset->RemoveAll() ); //by ZolMol: if not bound then the members are different, remove the inherited members
01759                 std::list< CComObjPtr<IMgaFCO> >::iterator i = members.begin();//slist
01760                 while( i != members.end() )
01761                 {
01762                         COMTHROW( mgaset->AddMember(*i) );
01763                         ++i;
01764                 }
01765         }
01766         GetCurrent().object = fco;
01767 
01768         //RegisterReadOnlyStatus( attributes);
01769         RegisterLookup(attributes, fco);
01770 }
01771 
01772 // ------- ElementFuncs -- info
01773 
01774 CMgaParser::elementfunc CMgaParser::elementfuncs_mgainfo[] = 
01775 {
01776         elementfunc(_T("project"), StartProjectInfo, EndNone),
01777         elementfunc(_T("name"), StartNone, EndNameInfo),
01778         elementfunc(_T(""), NULL, NULL)
01779 };
01780 
01781 
01782 void CMgaParser::StartProjectInfo(const attributes_type &attributes)
01783 {
01784 
01785         attributes_iterator i = attributes.begin();
01786         attributes_iterator e = attributes.end();
01787         while( i != e )
01788         {
01789                 if( i->first == _T("metaguid") )
01790                 {
01791                         _bstr_t bstr = i->second.c_str();
01792 
01793                         GUID guid;
01794                         CopyTo(bstr, guid);
01795 
01796                         CComVariant v;
01797                         CopyTo(guid, v);
01798 
01799                         v.Detach(infoparguid);
01800 
01801                 }
01802 
01803                 if( i->first == _T("metaname") )
01804                 {
01805                         *infoparname = _bstr_t(i->second.c_str()).Detach();
01806                 }
01807 
01808                 if( i->first == _T("metaversion") )
01809                 {
01810                         *infoparversion = _bstr_t(i->second.c_str()).Detach();
01811                 }
01812 
01813                 if( i->first == _T("version") )
01814                 {
01815                         *infoversion = _bstr_t(i->second.c_str()).Detach();
01816                 }
01817 
01818 
01819                 ++i;
01820         }
01821 }
01822 
01823 void CMgaParser::EndNameInfo()
01824 {
01825         if( GetPrevName() == _T("project") )
01826         {
01827                 *infoprojname = _bstr_t(GetCurrData().c_str()).Detach();
01828                 // analysis done, why waste time by processing further the xme file?
01829                 throw SAXException( magic_exit_str); // trick used & handled only by GetXMLInfo()
01830         }
01831 }
01832 
01833 CMgaParser::elementfunc CMgaParser::elementfuncs_clipmgainfo[] = 
01834 {
01835         elementfunc(_T("clipboard"), StartClipboardInfo, EndNone),
01836         elementfunc(_T(""), NULL, NULL)
01837 };
01838 
01839 void CMgaParser::StartClipboardInfo(const attributes_type &attributes)
01840 {
01841         bool closure_version_found = false;
01842         *closversion = 0;
01843         *closacckind = 0;
01844         attributes_iterator i = attributes.begin();
01845         attributes_iterator e = attributes.end();
01846         while( i != e )
01847         {
01848                 if( i->first == _T("closureversion") )
01849                 {
01850                         // if the value is _T("") then the bstr will be null, so bool introduced to correctly check the presence of "closureversion" token
01851                         closure_version_found = true;
01852 
01853                         *closversion = _bstr_t(i->second.c_str()).Detach();
01854                 }
01855                 else if( i->first == _T("acceptingkind") )
01856                 {
01857                         *closacckind = _bstr_t(i->second.c_str()).Detach();
01858                 }
01859                 ++i;
01860         }
01861         if( !closure_version_found && *closversion == 0) // not found such token
01862         {
01863                 CComBSTR bstr(L"0");
01864                 *closversion = bstr.Detach();
01865         }
01866 }
01867 
01868 STDMETHODIMP CMgaParser::GetClipXMLInfo(BSTR filename, IMgaObject *target, VARIANT_BOOL *is_acceptable, BSTR* p_acckind, BSTR* p_version) 
01869 {
01870         try
01871         {
01872                 CopyTo(filename, xmlfile);
01873 
01874                 XMLPlatformUtilsTerminate_RAII term;
01875                 try
01876                 {
01877                         XMLPlatformUtils::Initialize();
01878 
01879                         SAXParser parser;
01880                         parser.setValidationScheme(SAXParser::Val_Never);
01881                         parser.setDocumentHandler(this);
01882                         parser.setErrorHandler(this);
01883                         parser.setEntityResolver(this);
01884 
01885                         //elementfuncs = elementfuncs_clipmgainfo;
01886                         funcTableState = CLIP_MGA_INFO;
01887 
01888                         pass_count = 1;
01889 
01890                         ranges.clear();
01891                         ranges.push_front(range_type());
01892                         ranges.front().begin = 1;
01893                         ranges.front().end = (counter_type)-1;
01894                         skip_element_level = 0;
01895 
01896                         closversion = p_version; // the result stored in these returning parameters p_...
01897                         closacckind = p_acckind;
01898 
01899                         parser.parse(xmlfile.c_str());
01900 
01901                 }
01902                 catch(const XMLException &e)
01903                 {
01904                         XmlStr desc(e.getMessage());
01905 
01906                         ThrowXmlError(L"%s", desc.c_str());
01907                 }
01908 
01909                 CloseAll();
01910         }
01911         catch(hresult_exception &e)
01912         {
01913                 CloseAll();
01914 
01915                 ASSERT( FAILED(e.hr) );
01916                 if( e.hr == E_XMLPARSER )
01917                         SetErrorInfo(errorinfo);
01918                 else
01919                         SetErrorInfo2(e.hr);
01920 
01921                 return e.hr;
01922         }
01923 
01924         return S_OK;
01925 }
01926 
01927 //void CMgaParser::RegisterReadOnlyStatus( const attributes_type &attributes)
01928 //{
01929 //      readonly_stack.push_back( GetByNameX( attributes, "perm") != 0);
01930 //}
01931 
01932 bool CMgaParser::GetIntendedReadOnlyFlag( bool *p_isReadOnly)
01933 {
01934         ASSERT( !readonly_stack.empty());
01935         if( readonly_stack.empty()) return false;
01936 
01937         ASSERT( p_isReadOnly);
01938         *p_isReadOnly = readonly_stack.back();
01939         readonly_stack.pop_back();
01940 
01941         return true;
01942 }
01943 
01944 void CMgaParser::EndObject()
01945 {
01946         bool ro = false; // should be made read only?
01947         bool re = GetIntendedReadOnlyFlag( &ro); // re: is stack ok?
01948         if( ro && re)
01949         {
01950                 CComQIPtr<IMgaObject> obj( GetCurrent().object);
01951                 ASSERT( obj);
01952                 if( obj) COMTHROW( obj->PutReadOnlyAccess( VARIANT_TRUE));
01953         } // else if( re) stack error
01954 }