GME  13
MgaLibOps.cpp
Go to the documentation of this file.
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(&paradigmname));
00377                 COMTHROW(mgaproject->get_MetaGUID(&paradigmGUID));
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 }