GME
13
|
00001 // MgaLibOps.cpp : Implementation of Mga library operations 00002 #include "stdafx.h" 00003 #include "MgaFCO.h" 00004 #include "MgaSet.h" 00005 #include "MgaReference.h" 00006 #include "MgaConnection.h" 00007 #include "MgaLibOps.h" // by ZolMol 00008 #include "MgaLibRefr.h" 00009 #include "../interfaces/Parser.h" 00010 #include <algorithm> 00011 00012 /*static*/ const wchar_t* Ozer::StorageMgr::INCLUDES_STR = L"_includes"; 00013 /*static*/ const wchar_t* Ozer::StorageMgr::INCLUDED_BY_STR = L"_includedBy"; 00014 00015 std::wstring getConnStrForLibName(FCO* fco, const TCHAR* libname) { 00016 std::wstring connStr = libname; 00017 if (_tcsnicmp(connStr.c_str(), _T("MGA="), 4) != 0 && _tcsnicmp(connStr.c_str(), _T("MGX="), 4) != 0) { 00018 CComPtr<IMgaProject> project; 00019 COMTHROW(fco->get_Project(&project)); 00020 _bstr_t bconnStr; 00021 COMTHROW(project->get_ProjectConnStr(bconnStr.GetAddress())); 00022 00023 TCHAR currentMgaPath[MAX_PATH]; 00024 TCHAR* tcfilename; 00025 if (!GetFullPathName(static_cast<const TCHAR*>(bconnStr)+4, MAX_PATH, currentMgaPath, &tcfilename) || tcfilename == 0) { 00026 } else { 00027 *(tcfilename-1) = '\0'; 00028 TCHAR combined[MAX_PATH]; 00029 PathCombine(combined, currentMgaPath, connStr.c_str()); 00030 connStr = std::wstring(_T("MGA=")) + combined; 00031 } 00032 } 00033 return connStr; 00034 } 00035 00036 HRESULT FCO::get_LibraryName(BSTR *libname) { 00037 COMTRY { 00038 CHECK_OUTSTRPAR(libname); 00039 CheckRead(); 00040 if(self[ATTRID_PERMISSIONS] & LIBROOT_FLAG) { 00041 CComBSTR nn = self[ATTRID_NAME]; 00042 *libname = nn.Detach(); 00043 } 00044 else *libname = NULL; 00045 } COMCATCH(;); 00046 } 00047 00048 00049 void setlibpermall(CoreObj &c, long newmask) { 00050 ASSERT(newmask == LIBRARY_FLAG || newmask == 0); 00051 ITERATE_THROUGH(c[ATTRID_PARENT+ATTRID_COLLECTION]) { 00052 if( newmask == 0) // remove all library flags (LIBRARY_FLAG, LIBROOT_FLAG), preserve only INSTANCE 00053 ITER[ATTRID_PERMISSIONS] = ITER[ATTRID_PERMISSIONS] & INSTANCE_FLAG; 00054 else // if applying LIBRARY_FLAG, preserve the LIBROOT_FLAG if previously present 00055 ITER[ATTRID_PERMISSIONS] = (ITER[ATTRID_PERMISSIONS] & (INSTANCE_FLAG|LIBROOT_FLAG)) | newmask; 00056 if(ITER.IsContainer()) setlibpermall(ITER, newmask); 00057 } 00058 } 00059 00060 HRESULT FCO::put_LibraryName(BSTR libname) { 00061 COMTRY_IN_TRANSACTION { 00062 CHECK_INSTRPAR(libname); 00063 CheckWrite(); 00064 if(CComBSTR(libname)) { 00065 self[ATTRID_PERMISSIONS] = LIBROOT_FLAG; 00066 self[ATTRID_NAME] = libname; 00067 setlibpermall(self, LIBRARY_FLAG); 00068 SelfMark(OBJEVENT_PROPERTIES); 00069 } 00070 else { 00071 self[ATTRID_PERMISSIONS] = 0; 00072 setlibpermall(self, 0); 00073 } 00074 } COMCATCH_IN_TRANSACTION(;); 00075 } 00076 00077 void FCO::prepareDepInfo2Coll( CComBSTR& pInfo, IMgaFolders** pResColl) 00078 { 00079 CREATECOLLECTION_FOR(IMgaFolder,q); 00080 00081 for( Ozer::DependentIterator it( pInfo); !it.isDone(); it.next()) 00082 { 00083 CComBSTR current_val = it.getCurrentBstr(); 00084 CoreObj lib; 00085 CComPtr<IMgaFolders> coll; 00086 if( SUCCEEDED( mgaproject->GetTopLibraries( current_val, &coll))) 00087 { 00088 // append coll to q 00089 long len = 0; 00090 if( coll) COMTHROW( coll->get_Count( &len)); 00091 00092 for( long i = 1; i <= len; ++i) 00093 { 00094 CComPtr<IMgaFolder> ele; 00095 COMTHROW( coll->get_Item( i, &ele)); 00096 00097 ASSERT( ele); 00098 if( ele) 00099 q->Add( ele); 00100 } 00101 } 00102 else 00103 { 00104 ASSERT( 0); 00105 } 00106 } 00107 00108 *pResColl = 0; 00109 long res_length = 0; 00110 if( q) COMTHROW( q->get_Count( &res_length)); 00111 if( res_length) 00112 *pResColl = q.Detach(); 00113 } 00114 00115 00116 void FCO::prepareColl2DepInfo( IMgaFolders* pColl, CComBSTR& pResBstr) 00117 { 00118 long len = 0; 00119 if( pColl) COMTHROW( pColl->get_Count( &len)); 00120 for( long i = 1; i <= len; ++i) 00121 { 00122 CComPtr<IMgaFolder> ele; 00123 COMTHROW( pColl->get_Item( i, &ele)); 00124 00125 ASSERT( ele); 00126 if( ele) 00127 { 00128 CComBSTR gd; 00129 COMTHROW( ele->GetGuidDisp( &gd)); 00130 00131 // '\n' delimited list created (no '\n' at the end) 00132 if( pResBstr && pResBstr.Length() > 0) 00133 COMTHROW(pResBstr.Append( "\n")); 00134 COMTHROW(pResBstr.AppendBSTR( gd)); 00135 } 00136 } 00137 } 00138 00139 HRESULT FCO::GetVirtuallyIncludedBy( IMgaFolders** pDep) 00140 { 00141 COMTRY { 00142 CHECK_OUTPAR( pDep); 00143 CheckRead(); 00144 if(self[ATTRID_PERMISSIONS] & LIBROOT_FLAG) { 00145 00146 CComBSTR info; 00147 Ozer::StorageMgr::getIncludedBy( self, info); 00148 prepareDepInfo2Coll( info, pDep); 00149 } 00150 else *pDep = NULL; 00151 } COMCATCH(;); 00152 } 00153 HRESULT FCO::SetVirtuallyIncludedBy( IMgaFolders* pDep) 00154 { 00155 COMTRY_IN_TRANSACTION { 00156 CHECK_INPAR( pDep); 00157 CheckWrite(); 00158 00159 CComBSTR info; 00160 prepareColl2DepInfo( pDep, info); 00161 Ozer::StorageMgr::setIncludedBy( self, info); 00162 00163 SelfMark(OBJEVENT_REGISTRY); 00164 00165 } COMCATCH_IN_TRANSACTION(;); 00166 } 00167 HRESULT FCO::GetVirtuallyIncludes ( IMgaFolders** pDep) 00168 { 00169 COMTRY { 00170 CHECK_OUTPAR( pDep); 00171 CheckRead(); 00172 if(self[ATTRID_PERMISSIONS] & LIBROOT_FLAG) { 00173 00174 CComBSTR info; 00175 Ozer::StorageMgr::getIncludes( self, info); 00176 prepareDepInfo2Coll( info, pDep); 00177 } 00178 else *pDep = NULL; 00179 } COMCATCH(;); 00180 } 00181 HRESULT FCO::SetVirtuallyIncludes ( IMgaFolders* pDep) 00182 { 00183 COMTRY_IN_TRANSACTION { 00184 CHECK_INPAR( pDep); 00185 CheckWrite(); 00186 00187 CComBSTR info; 00188 prepareColl2DepInfo( pDep, info); 00189 Ozer::StorageMgr::setIncludes( self, info); 00190 00191 SelfMark(OBJEVENT_REGISTRY); 00192 00193 } COMCATCH_IN_TRANSACTION(;); 00194 } 00195 /* *************************** Pointer Fixup ************************************** */ 00196 /* 00197 by ZolMol 00198 class PointerFixup 00199 { 00200 coreobjpairhash identity_map; 00201 00202 typedef struct 00203 { 00204 CoreObj target; 00205 CoreObj created; 00206 attrid_type attrid; 00207 } resolve_entry; 00208 00209 std::vector<resolve_entry> resolve_entries; 00210 00211 public: 00212 inline void identify(const CoreObj &original, const CoreObj &created) 00213 { 00214 ASSERT( original != NULL && created != NULL ); 00215 00216 identity_map.insert(coreobjpairhash::value_type(original, created)); 00217 } 00218 00219 void resolve(const CoreObj &original, const CoreObj &created, 00220 attrid_type attrid) 00221 { 00222 if( LINKREF_ATTR(attrid) ) 00223 return; 00224 00225 CoreObj target = original[attrid]; 00226 if( target == NULL ) 00227 return; 00228 00229 coreobjpairhash::iterator i = identity_map.find(target); 00230 if( i != identity_map.end() ) 00231 created[attrid] = i->second; // already created 00232 else // resolve it later 00233 { 00234 resolve_entry entry; 00235 entry.target = target; 00236 entry.created = created; 00237 entry.attrid = attrid; 00238 resolve_entries.push_back(entry); 00239 } 00240 } 00241 00242 inline void clear() 00243 { 00244 resolve_entries.clear(); 00245 identity_map.clear(); 00246 } 00247 00248 void fixPointers() 00249 { 00250 std::vector<resolve_entry>::const_iterator i = resolve_entries.begin(); 00251 while( i != resolve_entries.end() ) 00252 { 00253 CoreObj& new_target = identity_map[i->target]; 00254 ASSERT( new_target != NULL ); 00255 00256 (i->created)[i->attrid] = new_target; 00257 00258 ++i; 00259 } 00260 clear(); 00261 } 00262 }; 00263 */ 00264 /* *************************** Attach ********************************************* */ 00265 00266 // functor class for replacing ObjTreeCopyFromExt with its countless parameters 00267 LibImgHelper::DoExtTreeCopy::DoExtTreeCopy( CMgaProject* p_mgaproject 00268 , PointerFixup& p_fixup 00269 , Typedefs::LIBPAIRVEC& p_libPairs 00270 , Typedefs::LIBVEC& p_superfluousLibs) 00271 : m_mgaproject( p_mgaproject) 00272 , m_fixup( p_fixup) // a reference!, will be altered 00273 , m_libPairs( p_libPairs) // a reference!, will be altered 00274 , m_superfluousLibs( p_superfluousLibs) // a reference!, will be altered 00275 { 00276 } 00277 00278 void LibImgHelper::DoExtTreeCopy::operator ()( const CoreObj& orig, CoreObj& nobj, bool p_indupl) 00279 { 00280 metaid_type s; 00281 COMTHROW( m_mgaproject->dataproject->CreateObject(s = orig.GetMetaID(), &nobj.ComPtr())); 00282 00283 m_fixup.identify(orig, nobj); 00284 00285 00286 bool skip_this = false; 00287 if(s >= DTID_MODEL && s <= DTID_FOLDER) { 00288 setcheck( m_mgaproject, nobj, CHK_NEW); 00289 CoreObjMark(nobj, OBJEVENT_CREATED); 00290 00291 long pm = orig[ATTRID_PERMISSIONS]; 00292 if( pm & LIBROOT_FLAG) 00293 { 00294 BinGuid libn = Identifier::getPersistentIdOf( orig); 00295 for( Typedefs::LIBPAIRVEC_ITER it = m_libPairs.begin(), en = m_libPairs.end() 00296 ; it != en 00297 ; ++it) 00298 { 00299 // 00300 BinGuid lib1 = Identifier::getPersistentIdOf( it->first); 00301 if( libn == lib1) 00302 { 00303 // what about skipping to load this duplicate library? 00304 // we can't avoid yet loading such portions into memory 00305 00306 skip_this = true; 00307 //ASSERT( libn == lib1 == lib2); 00308 ASSERT( libn == Identifier::getPersistentIdOf( it->second)); 00309 m_superfluousLibs.push_back( nobj); 00310 } 00311 } 00312 } 00313 00314 } 00315 00316 CComPtr<ICoreAttributes> atts; 00317 COMTHROW(orig->get_Attributes(&atts)); 00318 MGACOLL_ITERATE(ICoreAttribute, atts) { 00319 attrid_type ai; 00320 CComPtr<ICoreMetaAttribute> mattr; 00321 COMTHROW(MGACOLL_ITER->get_MetaAttribute(&mattr)); 00322 COMTHROW(mattr->get_AttrID(&ai)); 00323 if(ai < ATTRID_COLLECTION) { 00324 if (ai == ATTRID_LOCK) 00325 continue; 00326 valtype_type mvt; 00327 COMTHROW(mattr->get_ValueType(&mvt)); 00328 if(mvt != VALTYPE_POINTER) { 00329 if(ai == ATTRID_PERMISSIONS) { 00330 //WAS: nobj[ai] = orig[ai] & INSTANCE_FLAG | LIBRARY_FLAG; 00331 //this way we preserve nested libraries: 00332 00333 // we will delete this object later, that's why 00334 // we don't apply a readonly flag to it now 00335 if( skip_this) 00336 nobj[ai] = orig[ai]; 00337 else 00338 nobj[ai] = orig[ai] & (INSTANCE_FLAG|LIBROOT_FLAG) | LIBRARY_FLAG; 00339 } 00340 else nobj[ai] = static_cast<CComVariant>(orig[ai]); 00341 } 00342 else { 00343 m_fixup.resolve(orig, nobj, ai, p_indupl || skip_this); 00344 } 00345 } 00346 else { 00347 ai -= ATTRID_COLLECTION; 00348 if(LINKREF_ATTR(ai)) { 00349 CoreObjs collmembers = orig[ai + ATTRID_COLLECTION]; 00350 ITERATE_THROUGH(collmembers) { 00351 CoreObj nchild; 00352 //ObjTreeCopyFromExt( ITER, nchild, p_indupl || skip_this); 00353 (*this)( ITER, nchild, p_indupl || skip_this); 00354 nchild[ai] = nobj; 00355 } 00356 } 00357 } 00358 } MGACOLL_ITERATE_END; 00359 } 00360 00361 void CreateLibraryImage(CMgaProject *mgaproject, LibWorker& lw, CoreObj &libimgroot, bool p_tolerateOldMga, bool *p_ptrIsOldMga, Typedefs::LIBMAP& p_results, Typedefs::LIBVEC& p_dependentLibs, CComBSTR& p_infoMsg, const CComBSTR& libname) { 00362 CComBSTR connstr = lw.getExpandedConnectionStr(); 00363 CComPtr<IMgaProject> p; 00364 PointerFixup fixup; 00365 00366 Typedefs::LIBVEC superfluous_libs; // those libs which can be deleted simply after the optimization 00367 Typedefs::LIBPAIRVEC matching_libs; // lib pairs (or triplets) which have equal guid 00368 00369 Reporter reporter( mgaproject); 00370 00371 try { 00372 COMTHROW(p.CoCreateInstance(__uuidof(MgaProject))); 00373 00374 CComBSTR paradigmname; 00375 CComVariant paradigmGUID; 00376 COMTHROW(mgaproject->get_MetaName(¶digmname)); 00377 COMTHROW(mgaproject->get_MetaGUID(¶digmGUID)); 00378 00379 // ask some info about the project to be attached 00380 bool upgraded = false; CComBSTR connstr_upgraded( "MGA="); 00381 long mga_ver( 0); 00382 // checking project version, checking if the same paradigm or subparadigm, and convert thru XML in such cases 00383 { 00384 CComBSTR par_nm; 00385 CComBSTR par_vs; // not used now 00386 CComVariant par_gd; // not used now 00387 VARIANT_BOOL ro_mode;// not used now 00388 00389 COMTHROW(p->QueryProjectInfo( connstr, &mga_ver, &par_nm, &par_vs, &par_gd, &ro_mode)); 00390 if( par_nm != paradigmname) 00391 { 00392 // must upgrade 'connstr' project into 'paradigmname' paradigm 00393 VARIANT_BOOL ro = VARIANT_TRUE; 00394 HRESULT hr = p->Open( connstr, &ro); 00395 if( FAILED( hr)) { 00396 reporter.show( CComBSTR( "Could not open the to-be-library project.")); 00397 return; 00398 } 00399 00400 // Find TEMP directory 00401 TCHAR szTempPath[MAX_PATH]; 00402 if (::GetTempPath(MAX_PATH, szTempPath) == 0) { 00403 reporter.show( CComBSTR( "Could not find TEMP directory.")); 00404 return; 00405 } 00406 00407 // Create temporary filenames 00408 TCHAR szTempXmeFileName[MAX_PATH]; 00409 TCHAR szTempMgaFileName[MAX_PATH]; 00410 if( ::GetTempFileName(szTempPath, _T("GME"), 0, szTempXmeFileName) == 0 // 0 means ERROR 00411 || ::GetTempFileName(szTempPath, _T("GME"), 0, szTempMgaFileName) == 0) { 00412 ASSERT(("Unable to get temporary filename.", false)); 00413 reporter.show( CComBSTR( "Could not get temporary filename.")); 00414 return; 00415 } 00416 00417 // Dump the to-be-library into XML 00418 CComPtr<IMgaDumper> dumper; 00419 COMTHROW( dumper.CoCreateInstance(L"Mga.MgaDumper") ); 00420 ASSERT( dumper != NULL ); 00421 00422 COMTHROW(dumper->put_FormatVersion(0)); 00423 COMTHROW(dumper->DumpProject( p, _bstr_t(szTempXmeFileName)) ); 00424 00425 COMTHROW(p->Close(VARIANT_FALSE)); 00426 00427 // Create a new 'paradigmname' project 00428 COMTHROW(connstr_upgraded.Append( szTempMgaFileName)); // connection string prepared 00429 hr = p->CreateEx(connstr_upgraded, paradigmname, paradigmGUID); 00430 if( SUCCEEDED( hr)) { 00431 CComPtr<IMgaParser> parser; 00432 COMTHROW( parser.CoCreateInstance(L"Mga.MgaParser") ); 00433 ASSERT( parser != NULL ); 00434 00435 COMTHROW(parser->ParseProject( p, _bstr_t(szTempXmeFileName)) ); 00436 COMTHROW(p->Close(VARIANT_FALSE)); 00437 upgraded = true; 00438 } 00439 else if(hr == E_MGA_PARADIGM_NOTREG || hr == E_MGA_PARADIGM_INVALID) { 00440 ASSERT(0); // how come? these are similar to mgaproject's data 00441 } 00442 } 00443 } 00444 00445 *p_ptrIsOldMga = mga_ver < 2; 00446 00447 // check version of the mga file to be attached 00448 if( mga_ver < 2) 00449 { 00450 if( p_tolerateOldMga) 00451 { 00452 MyCComBSTR msg( L"Library copy is in old MGA format. Library Refresh feature ver.1 (old) can be used only!"); 00453 COMTHROW(msg.Append( L"To benefit from the new Library Refresh ver.2 feature please open/save the library with GME, then reattach it to this project.")); 00454 reporter.show( msg); 00455 } 00456 else 00457 { 00458 MyCComBSTR msg( L"Library is in old MGA format. To update please open it as a project, save it and only then can be attached!"); 00459 reporter.show( msg); 00460 00461 COMTHROW(E_MGA_NOT_SUPPORTED); 00462 } 00463 } 00464 00465 try 00466 { 00467 p->__OpenEx( _bstr_t(upgraded?connstr_upgraded:connstr), _bstr_t(paradigmname), _variant_t(paradigmGUID)); 00468 00469 p->__BeginTransaction( NULL, TRANSACTION_READ_ONLY); 00470 00471 CComPtr<IMgaFolder> libroot; 00472 COMTHROW(p->get_RootFolder(&libroot)); 00473 CoreObj ext_libroot( libroot); 00474 00475 //*********************************************************** 00476 // Loading info about the libraries in the (attachable) file 00477 //----------------------------------------------------------- 00478 Typedefs::LIBMAP lib_results; 00479 try 00480 { 00481 LibImgHelper::recordLibs( true, ext_libroot, lib_results); // record all libs in library 00482 // the rootfolder of library is not yet a LIBROOT 00483 // so consider it a libroot now by pushing to the end of vector explicitly: 00484 //BinGuid libn = Identifier::getPersistentIdOf( ext_libroot); 00485 //lib_results[ libn ].push_back( ext_libroot); 00486 // above: commented out because we can't optimize away the newly attached library 00487 00488 LibImgHelper::matchLibs( lib_results, p_results, matching_libs, p_infoMsg); 00489 lib_results.clear(); 00490 } 00491 catch( ... ) 00492 { 00493 matching_libs.clear(); // reset collected data (integrity not assured) 00494 lib_results.clear(); 00495 00496 CComBSTR msg( "Exception while analyzing library "); 00497 COMTHROW(msg.Append( connstr)); 00498 COMTHROW(msg.Append( " !")); 00499 00500 reporter.show( msg); 00501 00502 throw hresult_exception( -1); // fail 00503 } 00504 00505 if( lw.isOptimized()) fixup.setLibPairs( matching_libs); 00506 else matching_libs.clear(); 00507 00508 LibImgHelper::DoExtTreeCopy( mgaproject, fixup, matching_libs, superfluous_libs)( ext_libroot, libimgroot, false); 00509 00510 fixup.fixPointers(); 00511 } 00512 catch(_com_error&) 00513 { 00514 CComBSTR msg( "Exception while loading external library "); 00515 COMTHROW(msg.Append( connstr)); 00516 COMTHROW(msg.Append( " .")); 00517 reporter.show( msg); 00518 00519 throw; 00520 } 00521 catch(...) 00522 { 00523 CComBSTR msg( "Exception while loading external library "); 00524 COMTHROW(msg.Append( connstr)); 00525 COMTHROW(msg.Append( " .")); 00526 reporter.show( msg); 00527 00528 throw hresult_exception( -1); // fail 00529 } 00530 00531 //************************************************* 00532 // deleting the superfluous libs 00533 //************************************************* 00534 if( lw.isOptimized()) 00535 { 00536 LibImgHelper::deleteSuperfluousLibs( superfluous_libs, reporter); 00537 } 00538 00539 libimgroot[ATTRID_NAME] = libname; 00540 libimgroot[ATTRID_PERMISSIONS] = LIBROOT_FLAG; 00541 00542 //************************************************* 00543 // collect the dependent (included by me) libraries 00544 //************************************************* 00545 if( lw.isOptimized()) 00546 { 00547 LibImgHelper::collectDep( matching_libs, reporter, p_dependentLibs); 00548 } 00549 //else {}// not optimized, is it needed? 00550 00551 superfluous_libs.clear(); 00552 matching_libs.clear(); 00553 00554 COMTHROW(p->AbortTransaction()); 00555 COMTHROW(p->Close(VARIANT_FALSE)); 00556 } catch(...) { 00557 fixup.clear(); 00558 superfluous_libs.clear(); 00559 matching_libs.clear(); 00560 if(p) { 00561 long st; 00562 COMTHROW(p->get_ProjectStatus(&st)); 00563 if(st & 8) 00564 p->AbortTransaction(); 00565 if(st & 1) 00566 p->Close(VARIANT_FALSE); 00567 }; 00568 throw; 00569 } 00570 } 00571 00572 HRESULT FCO::doAttach( BSTR libname, VARIANT_BOOL ungroup, IMgaFolder **f) { 00573 COMTRY_IN_TRANSACTION { 00574 CHECK_OUTPTRPARVALIDNULL(f); 00575 00576 Reporter reporter( mgaproject); 00577 00578 // examining toplevel libraries in project 00579 00580 // 'self' here is the rootfolder of the project 00581 Typedefs::LIBMAP top_libs; 00582 00583 LibWorker lw( mgaproject, CComBSTR(getConnStrForLibName(this, libname).c_str()), ungroup == VARIANT_TRUE); 00584 SearchTool::m_optimized = lw.isOptimized(); 00585 LibImgHelper::recordLibs( false, self, top_libs); // consider existing toplibs only (self = project) 00586 00587 // examining the attachable library 00588 CComBSTR msg( "--------------------- Creating "); 00589 if( lw.isOptimized()) 00590 COMTHROW(msg.Append( "optimized ")); 00591 COMTHROW(msg.Append("library image from [")); 00592 COMTHROW(msg.Append( lw.getExpandedConnectionStr())); 00593 COMTHROW(msg.Append("]--")); 00594 reporter.show( msg, false); 00595 00596 CoreObj libimgroot; 00597 bool accept_old_lib( false); // don't tolerate old format MGA files (attachment of such a library fails) 00598 bool is_old_lib( false); 00599 Typedefs::LIBVEC dep_libs; // those libraries which are factored out 00600 CComBSTR infmsg; // informative message about the lib pairs found 00601 CreateLibraryImage(mgaproject, lw, libimgroot, accept_old_lib, &is_old_lib, top_libs, dep_libs, infmsg, CComBSTR(libname)); 00602 if( lw.isOptimized() && infmsg && infmsg.Length() > 0) // informative message about possible guid duplications in the library 00603 reporter.show( infmsg, false); 00604 00605 assignnewchild(libimgroot); 00606 00607 if( lw.isOptimized()) 00608 { 00609 // more libraries factored out 00610 lw.flatten( self, libimgroot, dep_libs); 00611 00612 // store dependency info on factored out libs 00613 Ozer::createDeps( libimgroot, dep_libs); 00614 } 00615 else ASSERT( dep_libs.empty()); 00616 00617 docheck(mgaproject); 00618 00619 if(f) ObjForCore(libimgroot)->getinterface(f); 00620 00621 ObjTreeNotify(mgaproject, libimgroot); 00622 SelfMark(OBJEVENT_NEWCHILD); 00623 } COMCATCH_IN_TRANSACTION(;); 00624 } 00625 00626 00627 HRESULT FCO::AttachLibraryV3(BSTR libname, VARIANT_BOOL ungroup, IMgaFolder **f) { 00628 return doAttach( libname, ungroup, f); 00629 } 00630 00631 HRESULT FCO::AttachLibrary(BSTR libname, IMgaFolder **f) { 00632 return doAttach( libname, VARIANT_FALSE, f); 00633 } 00634 00635 /* *************************** Refresh ********************************************* */ 00636 00637 void steal(CoreObj &o, CoreObj &n, attrid_type ai) { 00638 ITERATE_THROUGH(o[ai + ATTRID_COLLECTION]) { 00639 ITER[ai] = n; 00640 } 00641 } 00642 00643 void redo_derivs(CMgaProject *mgaproject, CoreObj &oldnode, CoreObj &newnode, bool deriv_non_primary) { 00644 bool libnode = (newnode[ATTRID_PERMISSIONS] & LIBRARY_FLAG) ? true : false; 00645 if(long(oldnode[ATTRID_META]) != long(newnode[ATTRID_META])) { 00646 COMTHROW(E_MGA_LIB_DIFF); 00647 } 00648 if(oldnode.IsFCO()) { 00649 CoreObjs ders = oldnode[ATTRID_DERIVED+ATTRID_COLLECTION]; 00650 ITERATE_THROUGH(ders) { 00651 long perm = ITER[ATTRID_PERMISSIONS]; 00652 if(perm & LIBRARY_FLAG) continue; 00653 00654 if(!deriv_non_primary && ITER[ATTRID_RELID] >= RELIDSPACE) continue; // not primary derived 00655 // 00656 CoreObj newder; 00657 coreobjpairhash crealist; 00658 ObjTreeDerive(mgaproject, newnode, newder, crealist, perm & INSTANCE_FLAG); 00659 newder[ATTRID_ROLEMETA] = ITER[ATTRID_ROLEMETA]; // maybe 0 00660 newder[ATTRID_PARENT] = ITER[ATTRID_PARENT]; 00661 newder[ATTRID_RELID] = ITER[ATTRID_RELID]; 00662 00663 ObjTreeReconnect(newder, crealist); // Reroute references 00664 redo_derivs(mgaproject, ITER, newder, true); // RECURSION! 00665 } 00666 } 00667 if(oldnode.IsContainer()) { 00668 CoreObjs oldchildren = oldnode[ATTRID_PARENT+ATTRID_COLLECTION]; 00669 Sort<long>(oldchildren, ATTRID_RELID); 00670 CoreObjs newchildren = newnode[ATTRID_PARENT+ATTRID_COLLECTION]; 00671 Sort<long>(newchildren, ATTRID_RELID); 00672 std::vector<CoreObj> newvect; 00673 GetAll2<ICoreObjects>(newchildren, newvect); 00674 std::vector<CoreObj>::iterator iter = newvect.begin(), iter_end = newvect.end(); 00675 if(iter != iter_end) { 00676 long newrelid = (*iter)[ATTRID_RELID]; 00677 ITERATE_THROUGH(oldchildren) { 00678 long oldrelid = ITER[ATTRID_RELID]; 00679 while(newrelid < oldrelid && iter != iter_end ) 00680 { 00681 if( ++iter != iter_end ) 00682 newrelid = (*iter)[ATTRID_RELID]; 00683 } 00684 // no refresh for objects with 0 relID 00685 if(oldrelid != 0 && oldrelid == newrelid) { 00686 redo_derivs(mgaproject, ITER, *iter, false); 00687 } 00688 else if(oldrelid < RELIDSPACE && !libnode) { 00689 ITER[ATTRID_PARENT] = newnode; 00690 } 00691 } 00692 } 00693 } 00694 00695 // PETER : reroute references from the model 00696 if (libnode && oldnode.IsFCO()) { 00697 // Sets ? COnnections ? Other relations ? 00698 ITERATE_THROUGH(oldnode[ATTRID_REFERENCE + ATTRID_COLLECTION]) { 00699 if (ITER[ATTRID_PERMISSIONS] & LIBRARY_FLAG) continue; 00700 ITER[ATTRID_REFERENCE] = newnode; 00701 } 00702 } 00703 // PETER END 00704 00705 if (libnode) 00706 return; 00707 00708 ASSERT(newnode[ATTRID_RELID] == oldnode[ATTRID_RELID]); 00709 ASSERT(newnode[ATTRID_META] == oldnode[ATTRID_META]); 00710 00711 newnode[ATTRID_NAME] = oldnode[ATTRID_NAME]; 00712 if(oldnode.IsContainer()) { 00713 newnode[ATTRID_LASTRELID] = oldnode[ATTRID_LASTRELID]; 00714 } 00715 steal(oldnode, newnode, ATTRID_CONSTROWNER); 00716 00717 if(oldnode.IsFCO()) { 00718 ASSERT(newnode[ATTRID_ROLEMETA] == oldnode[ATTRID_ROLEMETA]); 00719 steal(oldnode, newnode, ATTRID_ATTRPARENT); 00720 steal(oldnode, newnode, ATTRID_XREF); 00721 steal(oldnode, newnode, ATTRID_REFERENCE); 00722 switch(oldnode.GetMetaID()) { 00723 case DTID_REFERENCE: 00724 steal(oldnode, newnode, ATTRID_SEGREF); 00725 if(!CoreObj(oldnode[ATTRID_MASTEROBJ])) { 00726 std::vector<CoreObj> peer(1); 00727 peer[0] = oldnode[ATTRID_REFERENCE]; // set the old val, it will 00728 // be updated through xref 00729 newnode[ATTRID_MASTEROBJ] = NULLCOREOBJ; 00730 putreftask(false).DoWithDeriveds(newnode, &peer); 00731 } 00732 break; 00733 case DTID_CONNECTION: 00734 { 00735 ITERATE_THROUGH(oldnode[ATTRID_CONNROLE + ATTRID_COLLECTION]) { 00736 if(!CoreObj(ITER[ATTRID_MASTEROBJ])) { 00737 CoreObj rr; 00738 if(ObjForCore(newnode)->findroleobj(CComBSTR(ITER[ATTRID_NAME]), rr)) { 00739 MgaConnPointDelete(rr); 00740 } 00741 // todo: propagate 00742 ITER[ATTRID_CONNROLE] = newnode; 00743 } 00744 } 00745 } 00746 break; 00747 case DTID_SET: 00748 { 00749 ITERATE_THROUGH(oldnode[ATTRID_SETMEMBER + ATTRID_COLLECTION]) { 00750 if(!CoreObj(ITER[ATTRID_MASTEROBJ])) { 00751 // todo: delete duplicate setnodes 00752 // todo: propagate 00753 ITER[ATTRID_SETMEMBER] = newnode; 00754 } 00755 } 00756 } 00757 break; 00758 } 00759 } 00760 } 00761 00762 HRESULT FCO::doRefresh( BSTR libname, VARIANT_BOOL ungroup, long *ptrNumOfErrors) { 00763 long placeholder; 00764 if( !ptrNumOfErrors) // invalid ptr 00765 ptrNumOfErrors = &placeholder; 00766 *ptrNumOfErrors = 0; 00767 00768 COMTRY_IN_TRANSACTION { 00769 Reporter reporter(mgaproject); 00770 if( !Identifier::isRefreshableLibRoot( self)) 00771 { 00772 MyCComBSTR msg( "Inner library can't be refreshed in this project!"); 00773 reporter.show( msg); 00774 } 00775 else 00776 { 00777 CheckWrite(); 00778 if(!(self[ATTRID_PERMISSIONS] & LIBROOT_FLAG)) { 00779 COMTHROW(E_MGA_OP_REFUSED); 00780 } 00781 00782 std::wstring connStr = getConnStrForLibName(this, libname).c_str(); 00783 LibWorker lw( mgaproject, CComBSTR(connStr.c_str()), ungroup == VARIANT_TRUE); 00784 SearchTool::m_optimized = lw.isOptimized(); 00785 00786 // examining toplevel libraries in project 00787 00788 CComPtr<IMgaFolder> prroot; 00789 COMTHROW(mgaproject->get_RootFolder(&prroot)); 00790 CoreObj corerf = CoreObj( prroot); 00791 //CoreObj crlibroot( self); 00792 // 'self' here is the refreshable library 00793 CComBSTR id_of_this_library; 00794 ObjForCore( self)->get_ID( &id_of_this_library); 00795 00796 // in the project consider existing toplibs only, [and avoid the library we are going to refresh] 00797 Typedefs::LIBMAP lib_results; 00798 LibImgHelper::recordLibs( false, corerf, lib_results, id_of_this_library); 00799 00800 // examining the refreshable library 00801 CComBSTR msg( "--------------------- Creating "); 00802 if( lw.isOptimized()) 00803 COMTHROW(msg.Append( "optimized ")); 00804 COMTHROW(msg.Append("library image from [")); 00805 COMTHROW(msg.Append( lw.getExpandedConnectionStr())); 00806 COMTHROW(msg.Append("]--")); 00807 reporter.show( msg, false); 00808 // 00809 // If required another logic could be introduced later: 00810 // If two or more copies of the same lib (or GUID conlfict) found on toplevel 00811 // then we could restrict optimization to not optimize (thus remove) such copies. 00812 // 00813 //#if(0) 00814 // Typedefs::LIBMAP my_inner_lib_results; 00815 // // in the refreshable lib examine the whole lib 00816 // LibImgHelper::recordLibs( true, self, my_inner_lib_results); 00817 // 00818 // for( Typedefs::LIBMAP_ITER it = my_inner_lib_results.begin(), endit = my_inner_lib_results.end(); it != endit; ++it) 00819 // { 00820 // for( Typedefs::LIBVEC_ITER jt = it->second.begin(), endjt = it->second.end(); jt != endjt; ++jt) 00821 // { 00822 // CComBSTR id; 00823 // LibImgHelper::GetItsGuid( *jt, &id); 00824 // Typedefs::LIBMAP_ITER kt = lib_results.find( it->first); 00825 // if( kt != lib_results.end()) // 00826 // { 00827 // ASSERT( kt->first == it->first); 00828 // // look for 'id' in vector kt->second 00829 // for( std::vector< CoreObj >::iterator lt = kt->second.begin() 00830 // ; lt != kt->second.end() 00831 // ; ++lt) 00832 // { 00833 // CComBSTR id2; 00834 // LibImgHelper::GetItsGuid( *lt, &id2); 00835 // if( id == id2) // found 00836 // { 00837 // ASSERT( 0 ); 00838 // // recordlibs should have ignored the copies which are refershed 00839 // kt->second.erase( lt); 00840 // CComBSTR nsg; 00841 // nsg.Append( id); 00842 // nsg.Append( L" has been deleted from common map."); 00843 // reporter.show( nsg, false); 00844 // break; 00845 // } 00846 // } 00847 // } 00848 // } 00849 // } 00850 //#endif 00851 00852 CComBSTR ln(libname); 00853 if(!ln) COMTHROW(get_LibraryName(&ln)); 00854 CoreObj libimgroot; 00855 bool accept_old_lib( true); // refreshment of an old format MGA file is allowed 00856 bool is_old_lib_copy( false); 00857 Typedefs::LIBVEC dep_libs; // those libraries which are factored out 00858 CComBSTR infmsg; 00859 CreateLibraryImage(mgaproject, lw, libimgroot, accept_old_lib, &is_old_lib_copy, lib_results, dep_libs, infmsg, CComBSTR(libname)); 00860 if( lw.isOptimized() && infmsg && infmsg.Length() > 0) // informative message about possible guid duplications in the library 00861 reporter.show( infmsg, false); 00862 00863 libimgroot[ATTRID_PARENT] = self[ATTRID_PARENT]; 00864 libimgroot[ATTRID_RELID] = self[ATTRID_RELID]; 00865 00866 if( is_old_lib_copy) // do a plain old refresh 00867 { 00868 MyCComBSTR msg( "Old version of Library refresh started ["); 00869 COMTHROW(msg.AppendBSTR( libname)); 00870 COMTHROW(msg.Append( "] --")); 00871 reporter.show( msg, false); 00872 00873 redo_derivs(mgaproject, self, libimgroot, false); 00874 inDeleteObject(); 00875 docheck(mgaproject); 00876 } 00877 else // do a uid based refresh 00878 { 00879 MyCComBSTR msg( "---------------------Library refresh v2 started ["); 00880 COMTHROW(msg.AppendBSTR( libname)); 00881 COMTHROW(msg.Append( "] --")); 00882 reporter.show( msg, false); 00883 00884 RefreshManager rm( mgaproject, self, libimgroot, Ozer::isIncluded( self)); 00885 ASSERT( Identifier::isLibRoot( self)); 00886 00887 rm.collectDependencies( self); 00888 rm.cutRelations( self); 00889 //redo_derivs(mgaproject, self, libimgroot, false); 00890 rm.restoreDependencies(); 00891 rm.clearDepStorage(); 00892 00893 // remove from all included libraries the 'dependent on self' info 00894 Ozer::cutInclusions( corerf, self); 00895 // including libraries of self will continue to include the newself (=libimgroot) 00896 // but we need to copy the includedness of self into newself 00897 Ozer::copyIncludedBy( self, libimgroot); 00898 00899 inDeleteObject(); 00900 00901 if( lw.isOptimized()) 00902 { 00903 // more libraries factored out 00904 lw.flatten( corerf, libimgroot, dep_libs); 00905 00906 // store dependency info on factored out libs 00907 Ozer::createDeps( libimgroot, dep_libs); 00908 } 00909 else ASSERT( dep_libs.empty()); 00910 00911 try { 00912 docheck(mgaproject); 00913 00914 MyCComBSTR msg; 00915 COMTHROW(msg.Append( "----------------------Library refresh done [")); 00916 COMTHROW(msg.AppendBSTR( libname)); 00917 COMTHROW(msg.Append("]--------")); 00918 int num = rm.getNumOfErrors( msg); 00919 *ptrNumOfErrors = num; 00920 COMTHROW(msg.Append( "--")); 00921 reporter.show( msg, false); 00922 00923 } catch(hresult_exception& ) { 00924 MyCComBSTR msg( "Check failed after refresh!"); 00925 reporter.show( msg); 00926 int num = rm.getNumOfErrors( msg); 00927 *ptrNumOfErrors = num + 1; 00928 throw; 00929 } 00930 } 00931 } // else 00932 } COMCATCH_IN_TRANSACTION( if( *ptrNumOfErrors == 0) *ptrNumOfErrors = 1; Reporter(mgaproject).show( MyCComBSTR( "----------------------Library refresh failed----------------------"))); 00933 } 00934 00935 HRESULT FCO::RefreshLibraryV3(BSTR libname, VARIANT_BOOL ungroup, long *ptrNumOfErrors) { 00936 return doRefresh( libname, ungroup, ptrNumOfErrors); 00937 } 00938 00939 HRESULT FCO::RefreshLibrary(BSTR libname) { 00940 long numOfErrs( 0); 00941 return doRefresh( libname, VARIANT_FALSE, &numOfErrs); 00942 } 00943 00944 PointerFixup::PointerFixup() 00945 : m_isOptimizing( false) 00946 { 00947 } 00948 00949 CoreObj PointerFixup::findLibRoot( const CoreObj& p_elem) 00950 { // copied from Identifier::getLibRootOf 00951 CoreObj cur = p_elem; 00952 00953 bool goon = cur != 0; 00954 while( goon) 00955 { 00956 #ifdef _DEBUG 00957 CComBSTR nm; 00958 try { 00959 auto f = ObjForCore(cur); 00960 if( f) 00961 f->get_Name( &nm); 00962 } catch( hresult_exception& ) { 00963 ASSERT(0); 00964 } 00965 nm.Append(";"); 00966 #endif 00967 long perm = cur[ATTRID_PERMISSIONS]; 00968 if( perm & LIBROOT_FLAG) 00969 return cur; 00970 00971 // if no library element, nor libroot element, must be a regular project 00972 // element, so we consider these having a BinGuid(0) as their realm uid 00973 if( (perm & LIBRARY_FLAG) == 0) 00974 return cur; 00975 00976 metaid_type mt = cur.GetMetaID(); 00977 ASSERT( mt != DTID_ROOT); 00978 cur = cur[ATTRID_PARENT]; 00979 goon = cur != 0; 00980 } 00981 00982 return CoreObj(); 00983 } 00984 00985 CoreObj PointerFixup::findCounterpart( const CoreObj& p_libElem) 00986 { 00987 CoreObj lib = findLibRoot( p_libElem); // the library the element is part of 00988 //ASSERT( lib); 00989 00990 CoreObj cntpart_lib; // the libroot's counterpart (equivalent peer) 00991 if( lib) 00992 cntpart_lib = cntPartLib( lib); 00993 00994 if( cntpart_lib) 00995 { 00996 //UniqueId u = Identifier::getDetailsOf( p_libElem); 00997 CComPtr<IMgaFCO> fco = SearchTool::findLibObj( cntpart_lib, Identifier::getDetailsOf( p_libElem)); 00998 if( fco) 00999 { 01000 //CComBSTR nm; fco->get_Name( &nm); 01001 //nm.Append( ":"); 01002 return CoreObj( fco); // this is the counterpart elem 01003 } 01004 } 01005 01006 return CoreObj(); 01007 } 01008 01009 CoreObj PointerFixup::cntPartLib( const CoreObj& lib2) 01010 { 01011 BinGuid g0 = Identifier::getPersistentIdOf( lib2); 01012 for( Typedefs::LIBPAIRVEC_ITER it = m_libPairs.begin(), en = m_libPairs.end(); it != en; ++it) 01013 { 01014 BinGuid g1 = Identifier::getPersistentIdOf( it->first); 01015 if( g0 == g1) 01016 { 01017 ASSERT( g1 == Identifier::getPersistentIdOf( it->second)); 01018 return it->second; 01019 } 01020 } 01021 01022 return CoreObj(); 01023 } 01024 01025 void PointerFixup::setLibPairs( Typedefs::LIBPAIRVEC& p_libPairs) 01026 { 01027 m_libPairs = p_libPairs; 01028 m_isOptimizing = !p_libPairs.empty(); 01029 } 01030 01031 LibWorker::LibWorker( CMgaProject* p_mgaProject 01032 , CComBSTR p_libName 01033 , bool p_optimize) 01034 : m_mgaProject( p_mgaProject) 01035 , m_libName( p_libName) 01036 , m_optimized( p_optimize) 01037 { 01038 } 01039 01040 bool LibWorker::isOptimized() const 01041 { 01042 return m_optimized; 01043 } 01044 01045 CComBSTR LibWorker::getConnectionStr() const 01046 { 01047 return m_libName; 01048 } 01049 01050 CComBSTR LibWorker::getExpandedConnectionStr() const 01051 { // the environment variable (if found) is replaced with its value 01052 CComBSTR r; 01053 std::string v; 01054 CopyTo( m_libName, v); 01055 01056 // replacing the found environment variable, %Name% syntax used 01057 size_t pos = v.find( '%'); 01058 if( pos != std::string::npos) // found 01059 { 01060 size_t npos = v.find( '%', pos + 1); //next occurence of '%' 01061 if( npos != -1 && npos > pos + 1) 01062 { 01063 // get the value of the environment variable between the two %'s 01064 char *value = getenv( v.substr( pos + 1, npos - pos - 1).c_str()); 01065 v.replace( pos, npos - pos + 1, value); 01066 } 01067 } 01068 01069 CopyTo( v, &r); 01070 return r; 01071 } 01072 01073 void LibWorker::showDetails( CoreObj& p_container, std::map< BinGuid, std::vector< CoreObj > >& p_results) 01074 { 01075 CComBSTR oid; 01076 LibImgHelper::GetItsGuid( p_container, &oid); 01077 COMTHROW(oid.Append( L" lib recorded")); 01078 if( m_mgaProject) Reporter::showIt( m_mgaProject, oid, false); 01079 01080 for( std::map< BinGuid, std::vector< CoreObj > >::iterator it = p_results.begin() 01081 ; it != p_results.end() 01082 ; ++it) 01083 { 01084 if( it->second.size() > 1) // duplicates found 01085 { 01086 BinGuid bf = it->first; 01087 MyCComBSTR m; 01088 m.appendGuid( bf); 01089 COMTHROW(m.Append( L" duplicate lib")); 01090 if( m_mgaProject) Reporter::showIt( m_mgaProject, m, false); 01091 } 01092 } 01093 } 01094 01095 01096 // static 01097 void LibImgHelper::discover( int p_recDepth 01098 , CoreObj& p_container 01099 , const CComBSTR& p_avoidThisLib 01100 , Typedefs::LIBMAP& p_results) 01101 { 01102 // recursive method 01103 // unlimited depth allowed if p_recDepth == -1 01104 // limited depth allowed if positive p_recDepth provided 01105 01106 if( p_avoidThisLib.Length() > 0) 01107 { 01108 // the caller is trying the discover the whole project EXCEPT 01109 // the library (and its internals) specified by this id 01110 CComBSTR cont_id; 01111 ObjForCore( p_container)->get_ID( &cont_id); 01112 if( p_avoidThisLib == cont_id) 01113 return; // avoid going into this library 01114 } 01115 01116 long pm = p_container[ATTRID_PERMISSIONS]; 01117 if( pm & LIBROOT_FLAG) 01118 { 01119 BinGuid libn = Identifier::getPersistentIdOf( p_container); 01120 p_results[ libn ].push_back( p_container); 01121 } 01122 01123 if( p_recDepth) // specifically: -1 or > 0 01124 { 01125 ITERATE_THROUGH( p_container[ ATTRID_FCOPARENT + ATTRID_COLLECTION]) 01126 { 01127 metaid_type mtyp = ITER.GetMetaID(); 01128 // in case p_recDepth > 0 the method will be called with decreased value 01129 if( mtyp == DTID_FOLDER) discover( p_recDepth > 0 ? p_recDepth - 1:-1, ITER, p_avoidThisLib, p_results); 01130 } 01131 } 01132 } 01133 01134 01135 // static 01136 void LibImgHelper::recordLibs( bool p_recordAllLibs 01137 , CoreObj& p_container 01138 , Typedefs::LIBMAP& p_results 01139 , const CComBSTR& p_avoidThisLibrary) 01140 { 01141 // if all libs must be recorded then allow unlimited depth: -1 01142 // otherwise (only toplevel libs need to be recorded): depth 1 is sufficient 01143 01144 LibImgHelper::discover( p_recordAllLibs ? -1:1, p_container, p_avoidThisLibrary, p_results); 01145 } 01146 01147 // static 01148 void LibImgHelper::ungroupLibs( CoreObj& p_container 01149 , Typedefs::LIBMAP& p_results 01150 , Typedefs::LIBVEC& p_depLibs) 01151 { 01152 for( Typedefs::LIBMAP_ITER it = p_results.begin(), endit = p_results.end(); it != endit; ++it) 01153 { 01154 for( Typedefs::LIBVEC_ITER jt = it->second.begin(), endjt = it->second.end(); jt != endjt; ++jt) 01155 { 01156 CoreObj librf = *jt; 01157 CoreObj librfparent = librf[ATTRID_PARENT]; 01158 CComBSTR id1, id2; 01159 LibImgHelper::GetItsGuid( p_container, &id1); 01160 LibImgHelper::GetItsGuid( librfparent, &id2); 01161 if( id1 != id2) 01162 { 01163 // move out to the root level 01164 librf[ATTRID_FCOPARENT] = p_container; 01165 01166 // take off the Library (ro) flag! 01167 librf[ATTRID_PERMISSIONS] = librf[ATTRID_PERMISSIONS] & ~LIBRARY_FLAG; 01168 01169 // collect more dependency info 01170 // this librf will depend on 'self' 01171 // = will be marked 'included by me' 01172 if( p_depLibs.end() == std::find( p_depLibs.begin(), p_depLibs.end(), librf)) 01173 p_depLibs.push_back( librf); 01174 } 01175 } 01176 } 01177 } 01178 01179 void LibWorker::flatten( CoreObj& p_rootfolder 01180 , CoreObj& p_libimgroot 01181 , Typedefs::LIBVEC& p_depLibs) 01182 { 01183 if( m_optimized) 01184 { 01185 Typedefs::LIBMAP results; 01186 LibImgHelper::recordLibs( true, p_libimgroot, results); 01187 LibImgHelper::ungroupLibs( p_rootfolder, results, p_depLibs); 01188 } 01189 } 01190 01191 //static 01192 void LibImgHelper::logCreator( CComBSTR& p_log 01193 , const Typedefs::LIBVEC& p_libsToBe 01194 , const Typedefs::LIBVEC& p_libsHosted) 01195 { 01196 if( !p_log || !p_log.Length()) 01197 { 01198 COMTHROW(p_log.Append( "Opportunities for optimization found.")); 01199 } 01200 01201 COMTHROW(p_log.Append( "<br> ...(External, Hosted) library pairs found: ")); 01202 01203 if( p_libsToBe.size() > 1) 01204 { 01205 COMTHROW(p_log.Append( "<br>Warning: attached library contains two or more (sub)libraries with similar guids!")); 01206 } 01207 01208 for( Typedefs::LIBVEC_CITER it = p_libsToBe.begin(), endit = p_libsToBe.end(); it != endit; ++it) 01209 { 01210 COMTHROW(p_log.Append( "<br>External library in attachment:")); 01211 //p_log.Append( "<br>External library being attached"); 01212 //p_log.Append( "<br>External library:"); 01213 auto it_lib = ObjForCore( *it); 01214 CComBSTR nm, id, gd; 01215 if( it_lib) 01216 { 01217 COMTHROW(it_lib->get_Name( &nm));//nm = (*it)[ATTRID_NAME]; 01218 COMTHROW(it_lib->get_ID( &id)); 01219 COMTHROW(it_lib->GetGuidDisp( &gd)); 01220 COMTHROW(p_log.Append( L" [")); 01221 COMTHROW(p_log.Append( id)); 01222 COMTHROW(p_log.Append( L"] GUID=")); 01223 COMTHROW(p_log.Append( gd)); 01224 COMTHROW(p_log.Append( L" ")); 01225 COMTHROW(p_log.Append( nm)); 01226 } 01227 else 01228 { 01229 ASSERT( 0); 01230 COMTHROW(p_log.Append( L"libNull")); 01231 } 01232 } 01233 01234 for( Typedefs::LIBVEC_CITER jt = p_libsHosted.begin(), endjt = p_libsHosted.end(); jt != endjt; ++jt) 01235 { 01236 COMTHROW(p_log.Append( "<br>Hosted library already present:")); 01237 //p_log.Append( "<br>A hosted library:"); 01238 01239 auto jt_lib = ObjForCore( *jt); 01240 CComBSTR nm, id, gd; 01241 if( jt_lib) 01242 { 01243 COMTHROW(jt_lib->get_Name( &nm));//nm = (*it)[ATTRID_NAME]; 01244 COMTHROW(jt_lib->get_ID( &id)); 01245 COMTHROW(jt_lib->GetGuidDisp( &gd)); 01246 COMTHROW(p_log.Append( " [")); 01247 COMTHROW(p_log.Append( id)); 01248 COMTHROW(p_log.Append( "] GUID=")); 01249 COMTHROW(p_log.Append( gd)); 01250 COMTHROW(p_log.Append( " ")); 01251 COMTHROW(p_log.Append( nm)); 01252 } 01253 else 01254 { 01255 ASSERT( 0); 01256 COMTHROW(p_log.Append(L"libNull")); 01257 } 01258 } 01259 } 01260 01261 //static 01262 void LibImgHelper::collectDep( Typedefs::LIBPAIRVEC& p_matchingLibs 01263 , Reporter& p_reporter 01264 , Typedefs::LIBVEC& p_dependentLibs) 01265 { 01266 for( Typedefs::LIBPAIRVEC::iterator iiit = p_matchingLibs.begin(), eeen = p_matchingLibs.end(); iiit != eeen; ++iiit) 01267 { 01268 try 01269 { 01270 // collect second parameters of the matching map into the library vector 01271 if( p_dependentLibs.end() == std::find( p_dependentLibs.begin(), p_dependentLibs.end(), iiit->second)) 01272 p_dependentLibs.push_back( iiit->second); 01273 01274 } 01275 catch( ... ) 01276 { 01277 CComBSTR msg( "Exception while applying dependency info to "); 01278 try { 01279 CComBSTR nm, id; 01280 nm = (iiit->second)[ATTRID_NAME]; 01281 auto lib = ObjForCore(iiit->second); 01282 if( lib) 01283 COMTHROW(lib->get_ID( &id)); 01284 01285 COMTHROW(msg.AppendBSTR( nm)); 01286 COMTHROW(msg.Append( " [ ")); 01287 COMTHROW(msg.AppendBSTR( id)); 01288 COMTHROW(msg.Append( " ] !")); 01289 } 01290 catch( ... ) 01291 { 01292 COMTHROW(msg.Append( "!")); 01293 } 01294 p_reporter.show( msg); 01295 } 01296 } 01297 } 01298 01299 //static 01300 void LibImgHelper::deleteSuperfluousLibs( Typedefs::LIBVEC& p_superfluousLibs, Reporter& reporter) 01301 { 01302 for( Typedefs::LIBVEC_ITER it = p_superfluousLibs.begin(), en = p_superfluousLibs.end(); it != en; ++it) 01303 { 01304 try { 01305 auto lib = ObjForCore(*it); 01306 if( lib) lib->inDeleteObject(); 01307 else throw hresult_exception( -1); 01308 } 01309 catch( ... ) 01310 { 01311 CComBSTR msg( "Exception while deleting superfluous library "); 01312 try { 01313 CComBSTR nm, id; 01314 nm = (*it)[ATTRID_NAME]; 01315 auto lib = ObjForCore(*it); 01316 if( lib) lib->get_ID( &id); 01317 01318 COMTHROW(msg.AppendBSTR( nm)); 01319 COMTHROW(msg.Append( " [ ")); 01320 COMTHROW(msg.AppendBSTR( id)); 01321 COMTHROW(msg.Append( " ] !")); 01322 } 01323 catch( ... ) 01324 { 01325 COMTHROW(msg.Append( "!")); 01326 } 01327 01328 reporter.show( msg); 01329 } 01330 } 01331 } 01332 01333 //static 01334 void LibImgHelper::matchLibs( const Typedefs::LIBMAP& p_libMap 01335 , const Typedefs::LIBMAP& p_projMap 01336 , Typedefs::LIBPAIRVEC& p_matchingPairs 01337 , CComBSTR& p_infoMsg) 01338 { 01339 for( Typedefs::LIBMAP_CITER it = p_libMap.begin(), en = p_libMap.end(); it != en; ++it) 01340 { 01341 CComBSTR nm, pm; 01342 BinGuid bg = it->first; 01343 ASSERT( !it->second.empty()); 01344 Typedefs::LIBMAP_CITER jt = p_projMap.find( bg); 01345 if( jt != p_projMap.end()) // found 01346 { 01347 //if( jt->second.size() >= 2) // more than one copy exists already 01348 //{ 01349 //} 01350 01351 // duplicate lib 01352 if( jt->second.empty()) 01353 ASSERT(0); 01354 else // make a pair from to-be-lib libroot and project-hosted libroot 01355 { 01356 //nm = it->second.front()[ATTRID_NAME]; 01357 //nm.Append( ":"); 01358 //pm = jt->second.front()[ATTRID_NAME]; 01359 //pm.Append( ":"); 01360 CoreObj frntLibToBe = it->second.front(); 01361 CoreObj frntHosted = jt->second.front(); 01362 p_matchingPairs.push_back( std::make_pair( frntLibToBe, frntHosted)); 01363 01364 LibImgHelper::logCreator( p_infoMsg, it->second, jt->second); 01365 } 01366 } 01367 } 01368 } 01369 01370 //static 01371 void LibImgHelper::GetItsGuid( CoreObj& p_coreObj 01372 , BSTR* p_guidDisp) 01373 { 01374 // 01375 // better be in sync with FCO::GetGuidDisp() in MgaFCO.cpp 01376 // 01377 // in constrast to MgaFCO::GetGuidDisp this method does not 01378 // require the CheckRead() test, thus external, zombie or 01379 // not-yet-attached objects can be provided as well in its 01380 // coreObj parameter 01381 long v1(0), v2(0), v3(0), v4(0); 01382 v1 = p_coreObj[ATTRID_GUID1]; 01383 v2 = p_coreObj[ATTRID_GUID2]; 01384 v3 = p_coreObj[ATTRID_GUID3]; 01385 v4 = p_coreObj[ATTRID_GUID4]; 01386 01387 GUID t_guid; 01388 t_guid.Data1 = v1; 01389 t_guid.Data2 = v2 >> 16; 01390 t_guid.Data3 = v2 & 0xFFFF; 01391 t_guid.Data4[0] = (v3 >> 24); 01392 t_guid.Data4[1] = (v3 >> 16) & 0xFF; 01393 t_guid.Data4[2] = (v3 >> 8) & 0xFF; 01394 t_guid.Data4[3] = v3 & 0xFF; 01395 01396 t_guid.Data4[4] = (v4 >> 24); 01397 t_guid.Data4[5] = (v4 >> 16) & 0xFF; 01398 t_guid.Data4[6] = (v4 >> 8) & 0xFF; 01399 t_guid.Data4[7] = v4 & 0xFF; 01400 01401 char buff[39]; 01402 sprintf( buff, "{%08lX-%04X-%04x-%02X%02X-%02X%02X%02X%02X%02X%02X}", 01403 t_guid.Data1, t_guid.Data2, t_guid.Data3, 01404 t_guid.Data4[0], t_guid.Data4[1], t_guid.Data4[2], t_guid.Data4[3], 01405 t_guid.Data4[4], t_guid.Data4[5], t_guid.Data4[6], t_guid.Data4[7]); 01406 01407 *p_guidDisp = CComBSTR( buff).Detach(); 01408 } 01409 01410 bool Ozer::isIncluded( CoreObj& p_fldCore) 01411 { 01412 CComBSTR idlist; 01413 StorageMgr::getIncludedBy( p_fldCore, idlist); 01414 return idlist && idlist.Length() > 0; // if included by somebody 01415 } 01416 01417 bool Ozer::loseRelation ( CoreObj& p_fldCore 01418 , const CComBSTR& p_idToRemoveFromReg 01419 , bool p_incByOrInc 01420 , bool& p_libraryBecameFree) 01421 { 01422 bool all_right = false; 01423 //long prm = p_fldCore[ATTRID_PERMISSIONS]; 01424 CComBSTR valb; 01425 01426 //p_fldCore[ATTRID_PERMISSIONS] = prm & ~READONLY_FLAG; 01427 if( p_incByOrInc) Ozer::StorageMgr::getIncludedBy( p_fldCore, valb); 01428 else Ozer::StorageMgr::getIncludes( p_fldCore, valb); 01429 //p_fldCore[ATTRID_PERMISSIONS] = prm; 01430 01431 if( valb && valb.Length() > 0) 01432 { 01433 if( removeFromList( p_idToRemoveFromReg, valb)) 01434 { 01435 // save modified value back 01436 //p_fldCore[ATTRID_PERMISSIONS] = prm & ~READONLY_FLAG; 01437 if( p_incByOrInc) Ozer::StorageMgr::setIncludedBy( p_fldCore, valb); 01438 else Ozer::StorageMgr::setIncludes( p_fldCore, valb); 01439 //p_fldCore[ATTRID_PERMISSIONS] = prm; 01440 01441 if( valb.Length() == 0) // library became free 01442 { 01443 // let's take off the read-only flag 01444 //p_fldCore[ATTRID_PERMISSIONS] = prm & ~READONLY_FLAG; 01445 p_libraryBecameFree = true; 01446 } 01447 01448 all_right = true; 01449 } 01450 else { ASSERT( 0); } 01451 } 01452 else { ASSERT( 0); }// empty registry value 01453 01454 ASSERT( all_right); 01455 return all_right; 01456 } 01457 01458 bool Ozer::addRelation( CoreObj& p_fldCore 01459 , const CComBSTR& p_idToAddToReg 01460 , bool p_incByOrInc) 01461 { 01462 // take off the Library (ro) flag 01463 //long prm = p_fldCore[ATTRID_PERMISSIONS]; 01464 //p_fldCore[ATTRID_PERMISSIONS] = prm & ~LIBRARY_FLAG & ~READONLY_FLAG; 01465 01466 // registry asked about 'IncludedBy/s' info 01467 CComBSTR valu; 01468 if( p_incByOrInc) Ozer::StorageMgr::getIncludedBy( p_fldCore, valu); 01469 else Ozer::StorageMgr::getIncludes( p_fldCore, valu); 01470 01471 // value appended 01472 if( valu && valu.Length() > 0) 01473 COMTHROW(valu.Append( L"\n")); 01474 COMTHROW(valu.AppendBSTR( p_idToAddToReg)); // p_idToAddToReg might be a list of ids !!! 01475 01476 // save value 01477 if( p_incByOrInc) Ozer::StorageMgr::setIncludedBy( p_fldCore, valu); 01478 else Ozer::StorageMgr::setIncludes( p_fldCore, valu); 01479 01480 // set saved perm values back 01481 //p_fldCore[ATTRID_PERMISSIONS] = prm; 01482 01483 return true; 01484 } 01485 01486 //static 01487 bool Ozer::removeFromList( const CComBSTR& p_erasableVal 01488 , CComBSTR& p_valueList) 01489 { 01490 bool all_right = false; 01491 01492 DependentIterator it( p_valueList); 01493 p_valueList.Empty(); // the iterator made a copy of the list 01494 01495 for( ; !it.isDone(); it.next()) 01496 { 01497 if( it.getCurrentBstr() == p_erasableVal) 01498 all_right = true; // erasable value found 01499 else 01500 { 01501 if( p_valueList && p_valueList.Length() > 0) // if not empty 01502 COMTHROW(p_valueList.Append( L"\n")); // use separator 01503 01504 COMTHROW(p_valueList.Append( it.getCurrentBstr())); 01505 } 01506 } 01507 01508 ASSERT( all_right); 01509 return all_right; 01510 } 01511 01512 01513 // copy dependencies from the old lib to the newer libs: 01514 // if libX included oldlib, then libX will include newlib too 01515 // that is why IncludedBy of newlib must be copied from oldlib 01516 void Ozer::copyIncludedBy( CoreObj& p_oldLib 01517 , CoreObj& p_newLib) 01518 { 01519 CComBSTR list; 01520 Ozer::StorageMgr::getIncludedBy( p_oldLib, list); 01521 if( list && list.Length() > 0) // save info if not empty 01522 { 01523 CComBSTR val; 01524 Ozer::StorageMgr::getIncludedBy( p_newLib, val); 01525 if( val && val.Length() > 0) 01526 { 01527 COMTHROW(list.Append( L"\n")); 01528 COMTHROW(list.AppendBSTR( val)); 01529 } 01530 Ozer::StorageMgr::setIncludedBy( p_newLib, list); 01531 } 01532 } 01533 01534 // remove IncludedBy dependency reference from included 01535 // libraries of oldlib, the new lib will add again 01536 // dependency reference for its own included libraries 01537 // (i.e. some libraries may be deleted from a new 01538 // version of a library, in such cases some of the old 01539 // included ones become 'free' or 'freelancers') 01540 void Ozer::cutInclusions( CoreObj& p_rootfolder 01541 , CoreObj& p_oldLib) 01542 { 01543 CComBSTR list; 01544 Ozer::StorageMgr::getIncludes( p_oldLib, list); 01545 if( list && list.Length() > 0) // save info if not empty 01546 { 01547 CComBSTR oldlib_guid; 01548 LibImgHelper::GetItsGuid( p_oldLib, &oldlib_guid); 01549 01550 for( DependentIterator it( list); !it.isDone(); it.next()) 01551 { 01552 CoreObj lib_i; 01553 if( lib_i = SearchTool::findTopLibrary( p_rootfolder, it.getCurrentBstr())) 01554 { 01555 // remove lib_i's IncludedBy reference to oldlib 01556 bool free; 01557 Ozer::loseRelation( lib_i, oldlib_guid, true, free); 01558 } 01559 } 01560 } 01561 } 01562 01563 // recreate the dependencies based on the vector of 01564 // factored-out ( = dependent = included) libraries 01565 void Ozer::createDeps( CoreObj& p_mainLib 01566 , Typedefs::LIBVEC& p_depnLibs) 01567 { 01568 CComBSTR m_gd; 01569 LibImgHelper::GetItsGuid( p_mainLib, &m_gd); 01570 01571 for( Typedefs::LIBVEC_ITER i = p_depnLibs.begin(), e = p_depnLibs.end(); i != e; ++i) 01572 { 01573 CComBSTR i_gd; 01574 LibImgHelper::GetItsGuid( *i, &i_gd); 01575 01576 Ozer::addRelation( p_mainLib, i_gd, false); // includes, p_mainLib includes a lib with i_gd 01577 Ozer::addRelation( *i, m_gd, true); // includedBy, *i is included by a lib with m_gd 01578 } 01579 } 01580 01581 01582 void Ozer::StorageMgr::writer( CoreObj& p_fldCore 01583 , const CComBSTR& p_node 01584 , const CComBSTR& p_value) 01585 { 01586 ObjForCore( p_fldCore)->put_RegistryValue( p_node, p_value); 01587 } 01588 01589 void Ozer::StorageMgr::reader( CoreObj& p_fldCore 01590 , const CComBSTR& p_node 01591 , CComBSTR& p_value) 01592 { 01593 ObjForCore( p_fldCore)->get_RegistryValue( p_node, &p_value); 01594 } 01595 01596 void Ozer::StorageMgr::getIncludes( CoreObj& p_fldCore 01597 , CComBSTR& p_idList) 01598 { 01599 // get_RegistryValue complains if its first parameter 01600 // is a literal, that's why we pass a variable: path 01601 CComBSTR path( INCLUDES_STR); 01602 reader( p_fldCore, path, p_idList); 01603 } 01604 01605 void Ozer::StorageMgr::setIncludes( CoreObj& p_fldCore 01606 , const CComBSTR& p_idList) 01607 { 01608 // put_RegistryValue complains if its first parameter 01609 // is a literal, that's why we pass a variable: path 01610 CComBSTR path( INCLUDES_STR); 01611 writer( p_fldCore, path, p_idList); 01612 } 01613 01614 void Ozer::StorageMgr::getIncludedBy( CoreObj& p_fldCore 01615 , CComBSTR& p_idList) 01616 { 01617 CComBSTR path( INCLUDED_BY_STR); 01618 reader( p_fldCore, path, p_idList); 01619 } 01620 01621 void Ozer::StorageMgr::setIncludedBy( CoreObj& p_fldCore 01622 , const CComBSTR& p_idList) 01623 { 01624 CComBSTR path( INCLUDED_BY_STR); 01625 writer( p_fldCore, path, p_idList); 01626 } 01627 01628 01629 Ozer::DependentIterator::DependentIterator( const CComBSTR& p_tokenizable) 01630 { 01631 CopyTo( p_tokenizable, m_tokenizable); 01632 01633 m_pos = m_tokenizable.empty()? std::string::npos : 0; 01634 m_nextPos = m_tokenizable.find('\n', m_pos + 1); 01635 } 01636 01637 Ozer::DependentIterator::DependentIterator( const std::string& p_tokenizable) 01638 : m_tokenizable( p_tokenizable) 01639 { 01640 m_pos = m_tokenizable.empty()? std::string::npos : 0; 01641 m_nextPos = m_tokenizable.find('\n', m_pos + 1); 01642 } 01643 01644 bool Ozer::DependentIterator::isDone() 01645 { 01646 return m_pos == std::string::npos; 01647 } 01648 01649 void Ozer::DependentIterator::next() 01650 { 01651 m_pos = m_nextPos; 01652 if( !isDone()) 01653 m_nextPos = m_tokenizable.find('\n', m_pos + 1); 01654 } 01655 01656 std::string Ozer::DependentIterator::getCurrentStr() 01657 { 01658 if( m_nextPos == std::string::npos) 01659 return m_tokenizable.substr( m_pos + ( m_pos == 0?0:1)); 01660 else 01661 return m_tokenizable.substr( m_pos + ( m_pos == 0?0:1), m_nextPos - m_pos - ( m_pos == 0?0:1)); 01662 } 01663 01664 CComBSTR Ozer::DependentIterator::getCurrentBstr() 01665 { 01666 CComBSTR retv; 01667 CopyTo( getCurrentStr(), &retv); 01668 return retv; 01669 }