GME
13
|
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 }