GME
13
|
00001 #include "stdafx.h" 00002 #include "CommonMath.h" 00003 #include <algorithm> 00004 #include <stdio.h> 00005 #include <io.h> 00006 #include <stdlib.h> 00007 #include <direct.h> 00008 #include <fstream> 00009 #include <time.h> 00010 #include <sys/timeb.h> 00011 #include "CoreXmlFile.h" 00012 #include "CommonCollection.h" 00013 #include "SvnLoginDlg.h" 00014 #include "FilesInUseDlg.h" 00015 #include "FilesInUseDetailsDlg.h" 00016 #include "DomErrorPrinter.h" 00017 #include <xercesc/util/OutOfMemoryException.hpp> 00018 #include <xercesc/framework/LocalFileFormatTarget.hpp> 00019 #include "HiClient.h" 00020 #include "SvnTestDlg.h" 00021 #include "FileHelp.h" 00022 #include "DirSupplier.h" 00023 #include "Transcoder.h" 00024 #include "CommitDialog.h" 00025 #include "ProgressWindow.h" 00026 #include "Mga.h" 00027 00028 using namespace XERCES_CPP_NAMESPACE; 00029 using std::string; 00030 00031 #include "xml_smart_ptr.h" 00032 00033 #define DETAILS_ABOUT_XMLBACKEND 0 00034 #define RESOLVE_PTRS_2ND_ATTEMPT 0 00035 00036 std::string g_userName; 00037 std::string g_passWord; 00038 00039 const char* OpCodeStr[] = 00040 { 00041 "DELETED" 00042 , "MOVED" 00043 , "DERIVED" 00044 , "REFERRED" 00045 , "CONNECTED" 00046 , "TAKESPARTINCONN" 00047 , "REF_REDIRECTED" 00048 , "TOTAL" 00049 }; // keep these in sync with OpCode 00050 00051 /*static*/ const char * OperatingOptions::m_usrConfName = "config.opt"; 00052 /*static*/ const char * OperatingOptions::m_sysConfName = "project.opt"; 00053 /*static*/ const char * OperatingOptions::m_sysConfDefContentsPlain = "\ 00054 # comments must be prefixed by a hashmark\n\ 00055 #UseCache=false\n\ 00056 #AutomaticLogin=true\n\ 00057 #UseAccountInfo=true\n\ 00058 #account=ya\n\ 00059 #phrase=\n\ 00060 \n\ 00061 # specifies maximum time of tolerance (in minutes) for old entries\n\ 00062 # if set to 0 then a max time-to-live is not imposed on entries\n\ 00063 PurgeDelayed=17.7777222\n\ 00064 \n\ 00065 # shows checkout status upon load\n\ 00066 OnLoadShowStatus = false\n\ 00067 \n\ 00068 # use this option to avoid seeing the 'Keep files checked out'\n\ 00069 DefCheckInOnSave = true\n\ 00070 \n\ 00071 # use this option to avoid seeing 'Some files need to be checked out'\n\ 00072 DefCheckOutOnAction = true\n\ 00073 \n\ 00074 # to overwrite these settings with user-specific preferences create a file\n\ 00075 # called config.opt, in your local checkout directory\n\ 00076 "; 00077 00078 /*static*/ const char * OperatingOptions::m_sysConfDefContentsSvn = "\ 00079 # comments must be prefixed by a hashmark\n\ 00080 #UseCache=false\n\ 00081 #AutomaticLogin=true\n\ 00082 #UseAccountInfo=true\n\ 00083 #account=ya\n\ 00084 #phrase=\n\ 00085 \n\ 00086 # specifies maximum time of tolerance (in minutes) for old entries\n\ 00087 # if set to 0 then a max time-to-live is not imposed on entries\n\ 00088 PurgeDelayed=17.7777222\n\ 00089 \n\ 00090 # shows checkout status upon load\n\ 00091 OnLoadShowStatus = false\n\ 00092 \n\ 00093 # use this option to avoid seeing the 'Keep files checked out'\n\ 00094 DefCheckInOnSave = true\n\ 00095 \n\ 00096 # use this option to avoid seeing 'Some files need to be checked out'\n\ 00097 DefCheckOutOnAction = true\n\ 00098 \n\ 00099 # use this option to override the url or it's protocol part only thus you\n\ 00100 # may select from https and svn+ssh protocols and their corresponding urls\n\ 00101 #PreferredUrl = https://.... \n\ 00102 #PreferredUrl = svn+ssh://... \n\ 00103 \n\ 00104 # Speed-up commits to the repository by aggregation.\n\ 00105 UseBulkCommit = true \n\ 00106 \n\ 00107 # to overwrite these settings with user-specific preferences create a file\n\ 00108 # called config.opt, in your local checkout directory\n\ 00109 "; 00110 00111 /*static*/ const char * HelperFiles::sessionFolderName = "session"; 00112 /*static*/ const char * HelperFiles::signFileName = "sign.txt"; 00113 /*static*/ const char * HelperFiles::protFileName = "list_"; 00114 /*static*/ const char * HelperFiles::protFileExt = ".txt"; 00115 00116 /*static*/ const XMLCh * ParserLiterals::Main::deleted = L"deleted"; 00117 /*static*/ const XMLCh * ParserLiterals::Main::metaId = L"MetaId"; 00118 /*static*/ const XMLCh * ParserLiterals::Main::id = L"Id"; 00119 /*static*/ const XMLCh * ParserLiterals::Main::parent = L"Parent"; 00120 00121 /*static*/ const XMLCh * ParserLiterals::Signer::users = L"users"; 00122 /*static*/ const XMLCh * ParserLiterals::Signer::user = L"user"; 00123 /*static*/ const XMLCh * ParserLiterals::Signer::name = L"name"; 00124 /*static*/ const XMLCh * ParserLiterals::Signer::since = L"since"; 00125 /*static*/ const XMLCh * ParserLiterals::Signer::until = L"until"; 00126 00127 /*static*/ const XMLCh * ParserLiterals::Protector::item = L"item"; 00128 /*static*/ const XMLCh * ParserLiterals::Protector::when = L"when"; 00129 /*static*/ const XMLCh * ParserLiterals::Protector::oper = L"oper"; 00130 /*static*/ const XMLCh * ParserLiterals::Protector::gd = L"gd"; 00131 /*static*/ const XMLCh * ParserLiterals::Protector::objects = L"objects"; 00132 00133 /*static*/ const XMLCh * ParserLiterals::newln = L"\n"; 00134 /*static*/ const XMLCh * ParserLiterals::empty = L""; 00135 00136 /*static*/ const char * CCoreXmlFile::m_contentConst = "contents"; 00137 00138 bool XmlObjComp::operator()( XmlObject * p1, XmlObject * p2) const 00139 { 00140 if( (!p1) && (!p2)) return false; 00141 if( !p1) return true; 00142 if( !p2) return false; 00143 return GUID_less()( p1->m_guid, p2->m_guid); 00144 } 00145 00146 void bin2string( const unsigned char * bytes, int len, std::string& str ) 00147 { 00148 char hex[3]; 00149 str.clear(); 00150 for( int i=0; i<len; ++i ) 00151 { 00152 sprintf( hex, "%02x", bytes[i] ); 00153 str += hex; 00154 } 00155 } 00156 00157 unsigned char hexCharToInt( char ch ) 00158 { 00159 if( ch>='0' && ch<='9' ) 00160 return ch - '0'; 00161 00162 if( ch == 'a' || ch == 'A' ) 00163 return 10; 00164 if( ch == 'b' || ch == 'B' ) 00165 return 11; 00166 if( ch == 'c' || ch == 'C' ) 00167 return 12; 00168 if( ch == 'd' || ch == 'D' ) 00169 return 13; 00170 if( ch == 'e' || ch == 'E' ) 00171 return 14; 00172 if( ch == 'f' || ch == 'F' ) 00173 return 15; 00174 ASSERT(false); 00175 return 0; 00176 } 00177 00178 void string2bin( const char * str, unsigned char * bytes ) 00179 { 00180 int l = strlen(str) / 2; 00181 for( int i=0; i<l; ++i ) 00182 { 00183 unsigned char c1 = hexCharToInt( str[i*2] ); 00184 unsigned char c2 = hexCharToInt( str[i*2 + 1] ); 00185 //unsigned char c; 00186 //sscanf( str + i*2, "%02x", &c ); // do not work in release veriosn... 00187 bytes[i] = 16 * c1 + c2; 00188 } 00189 } 00190 00191 void guid2str( GUID guid, std::string& str ) 00192 { 00193 if( guid == GUID_NULL ) 00194 str = "null"; 00195 else 00196 bin2string( (unsigned char*)&guid, sizeof(GUID), str ); 00197 } 00198 00199 GUID str2guid( const char * str ) 00200 { 00201 int len = strlen(str); 00202 if( len == 0 || strcmp( str, "null" ) == 0 ) 00203 return GUID_NULL; 00204 else 00205 { 00206 GUID guid; 00207 string2bin( str, (unsigned char*)&guid ); 00208 return guid; 00209 } 00210 } 00211 00212 // 00213 // obsolete since MgaGeneric.cpp does not contain any 00214 // attribTokens (like 'MGA Version' was) with space inside 00215 // 00216 //void replaceSpaceWithUnderscore( std::string& str ) 00217 //{ 00218 // for( unsigned int i=0; i < str.size(); ++i ) 00219 // if( str[i] == ' ' ) 00220 // str[i] = '_'; 00221 //} 00222 // 00223 //void replaceUnderscoreWithSpace( char * str ) 00224 //{ 00225 // if( str == NULL ) 00226 // return; 00227 // 00228 // int n = strlen(str); 00229 // for( int i=0; i<n; ++i ) 00230 // if( str[i] == '_' ) 00231 // str[i] = ' '; 00232 //} 00233 00234 00236 // XmlAttrBase class 00238 00239 XmlAttrBase * XmlAttrBase::create(valtype_type valtype) 00240 { 00241 ASSERT( valtype != VALTYPE_NONE ); 00242 00243 XmlAttrBase * xmlattr = NULL; 00244 00245 switch(valtype) 00246 { 00247 case VALTYPE_LONG: 00248 xmlattr = new XmlAttrLong(); 00249 break; 00250 00251 case VALTYPE_STRING: 00252 xmlattr = new XmlAttrString(); 00253 break; 00254 00255 case VALTYPE_BINARY: 00256 xmlattr = new XmlAttrBinary(); 00257 break; 00258 00259 case VALTYPE_LOCK: 00260 xmlattr = new XmlAttrLock(); 00261 break; 00262 00263 case VALTYPE_POINTER: 00264 xmlattr = new XmlAttrPointer(); 00265 break; 00266 00267 case VALTYPE_COLLECTION: 00268 xmlattr = new XmlAttrCollection(); 00269 break; 00270 00271 case VALTYPE_REAL: 00272 xmlattr = new XmlAttrReal(); 00273 break; 00274 00275 case VALTYPE_DICT: 00276 xmlattr = new XmlAttrDict(); 00277 break; 00278 00279 default: 00280 HR_THROW(E_METAPROJECT); 00281 } 00282 00283 if( xmlattr == NULL ) 00284 HR_THROW(E_OUTOFMEMORY); 00285 00286 return xmlattr; 00287 } 00288 00289 XmlAttrBase::XmlAttrBase() 00290 { 00291 } 00292 00293 XmlAttrBase::~XmlAttrBase() 00294 { 00295 } 00296 00297 XmlAttrDict::XmlAttrDict() 00298 { 00299 CCoreDictionaryAttributeValue *val = NULL; 00300 typedef CComObject< CCoreDictionaryAttributeValue > COMTYPE; 00301 HRESULT hr = COMTYPE::CreateInstance((COMTYPE **)&val); 00302 COMTHROW(hr); 00303 m_value = val; 00304 } 00305 00306 void XmlAttrDict::fromVariant(VARIANT v) 00307 { 00308 ASSERT(v.vt == VT_DISPATCH); 00309 m_value = 0; 00310 v.pdispVal->QueryInterface(&m_value); 00311 } 00312 00313 void XmlAttrDict::toVariant(VARIANT* v) const 00314 { 00315 CComVariant ret = m_value; 00316 COMTHROW(ret.Detach(v)); 00317 } 00318 00319 void XmlAttrDict::fromString(const char* str, const wchar_t* strw) 00320 { 00321 DebugBreak(); 00322 } 00323 00324 void XmlAttrDict::toString(std::string& str) const 00325 { 00326 DebugBreak(); 00327 } 00328 00329 00331 // XmlAttrLong class 00333 00334 XmlAttrLong::XmlAttrLong() 00335 { 00336 m_value = 0; 00337 } 00338 00339 valtype_type XmlAttrLong::getType() const 00340 { 00341 return VALTYPE_LONG; 00342 } 00343 00344 void XmlAttrLong::fromVariant(VARIANT p) 00345 { 00346 CopyTo(p, m_value); 00347 } 00348 00349 void XmlAttrLong::toVariant(VARIANT *p) const 00350 { 00351 CopyTo(m_value, p); 00352 } 00353 00354 void XmlAttrLong::fromString(const char * str, const wchar_t* strw) 00355 { 00356 if( str == NULL || strlen(str)==0 ) 00357 m_value = 0; 00358 else 00359 m_value = atoi( str ); 00360 } 00361 00362 void XmlAttrLong::toString(std::string& str) const 00363 { 00364 char buf[25]; 00365 sprintf( buf, "%ld", m_value ); 00366 str = buf; 00367 } 00368 00370 // XmlAttrReal class 00372 00373 XmlAttrReal::XmlAttrReal() 00374 { 00375 m_value = 0; 00376 } 00377 00378 valtype_type XmlAttrReal::getType() const 00379 { 00380 return VALTYPE_REAL; 00381 } 00382 00383 void XmlAttrReal::fromVariant(VARIANT p) 00384 { 00385 CopyTo(p, m_value); 00386 } 00387 00388 void XmlAttrReal::toVariant(VARIANT *p) const 00389 { 00390 CopyTo(m_value, p); 00391 } 00392 00393 void XmlAttrReal::fromString(const char * str, const wchar_t* strw) 00394 { 00395 if( str == NULL || strlen(str)==0 ) 00396 m_value = 0; 00397 else 00398 { 00399 if (!ParseSpecialDouble(strw, m_value)) 00400 m_value = atof( str ); 00401 } 00402 } 00403 00404 void XmlAttrReal::toString(std::string& str) const 00405 { 00406 char buf[100]; 00407 sprintf(buf, "%.17g", m_value); 00408 str = buf; 00409 } 00410 00412 // XmlAttrString class 00414 00415 valtype_type XmlAttrString::getType() const 00416 { 00417 return VALTYPE_STRING; 00418 } 00419 00420 void XmlAttrString::fromVariant(VARIANT p) 00421 { 00422 CopyTo(p, m_value); 00423 } 00424 00425 void XmlAttrString::toVariant(VARIANT *p) const 00426 { 00427 CopyTo(m_value, p); 00428 } 00429 00430 void XmlAttrString::fromString(const char * str, const wchar_t* strw) 00431 { 00432 if( str == NULL ) 00433 m_value = ""; 00434 else 00435 m_value = str; 00436 } 00437 00438 void XmlAttrString::toString(std::string& str) const 00439 { 00440 str = m_value; 00441 } 00442 00444 // XmlAttrBinary class 00446 00447 valtype_type XmlAttrBinary::getType() const 00448 { 00449 return VALTYPE_BINARY; 00450 } 00451 00452 void XmlAttrBinary::fromVariant(VARIANT p) 00453 { 00454 CopyTo(p, m_value); 00455 } 00456 00457 void XmlAttrBinary::toVariant(VARIANT *p) const 00458 { 00459 CopyTo(m_value, p); 00460 } 00461 00462 void XmlAttrBinary::fromString(const char * str, const wchar_t* strw) 00463 { 00464 if( str == NULL || strlen(str) == 0 ) 00465 m_value.clear(); 00466 else 00467 { 00468 int len = strlen(str)/2; 00469 unsigned char * buff = new unsigned char[len]; 00470 string2bin( str, buff ); 00471 m_value.resize( len ); 00472 for( int i=0; i<len; ++i ) 00473 m_value [i] = buff[i]; 00474 delete [] buff; 00475 } 00476 } 00477 00478 void XmlAttrBinary::toString(std::string& str) const 00479 { 00480 if (m_value.empty()) { 00481 str.clear(); 00482 } 00483 else { 00484 bin2string( &m_value[0], m_value.size(), str ); 00485 } 00486 } 00487 00489 // XmlAttrLock class 00491 00492 XmlAttrLock::XmlAttrLock() 00493 { 00494 m_value = LOCKING_NONE; 00495 } 00496 00497 valtype_type XmlAttrLock::getType() const 00498 { 00499 return VALTYPE_LOCK; 00500 } 00501 00502 void XmlAttrLock::fromVariant(VARIANT p) 00503 { 00504 CopyTo(p, m_value); 00505 } 00506 00507 void XmlAttrLock::toVariant(VARIANT *p) const 00508 { 00509 CopyTo(m_value, p); 00510 } 00511 00512 void XmlAttrLock::fromString(const char * str, const wchar_t* strw) 00513 { 00514 if( str == NULL || strlen(str) == 0 ) 00515 m_value = LOCKING_NONE; 00516 else 00517 m_value = atoi( str ); 00518 } 00519 00520 void XmlAttrLock::toString(std::string& str) const 00521 { 00522 char buf[25]; 00523 sprintf( buf, "%d", m_value ); 00524 str = buf; 00525 } 00526 00528 // XmlAttrPointer class 00530 00531 XmlAttrPointer::XmlAttrPointer() 00532 { 00533 m_parent = NULL; 00534 } 00535 00536 valtype_type XmlAttrPointer::getType() const 00537 { 00538 return VALTYPE_POINTER; 00539 } 00540 00542 // XmlAttrCollection class 00544 00545 valtype_type XmlAttrCollection::getType() const 00546 { 00547 return VALTYPE_COLLECTION; 00548 } 00549 00551 // XmlObject class 00553 00554 XmlObject::XmlObject(ICoreMetaObject *metaobject, bool createAllAttributes ) 00555 { 00556 m_deleted = false; 00557 m_modified = false; 00558 m_loaded = createAllAttributes; 00559 00560 COMTHROW( metaobject->get_MetaID( &m_metaid ) ); 00561 if( m_loaded ) 00562 createAttributes(metaobject,ATTR_ALL); 00563 else 00564 createAttributes(metaobject,ATTR_PRIMARY); 00565 CoCreateGuid(&m_guid); 00566 } 00567 00568 XmlObject::~XmlObject() 00569 { 00570 for( AttribMapIter it = m_attributes.begin(); it != m_attributes.end(); ++it ) 00571 delete it->second; 00572 } 00573 00574 bool XmlObject::isContainer() 00575 { 00576 return( m_metaid==METAID_ROOT || m_metaid==DTID_MODEL || m_metaid==DTID_FOLDER ); 00577 } 00578 00579 00580 void XmlObject::createAttributes(ICoreMetaObject *metaobject, int attrSet ) 00581 { 00582 // TODO: memoize 00583 00584 ASSERT( metaobject != NULL ); 00585 ASSERT( attrSet>=ATTR_PRIMARY && attrSet<=ATTR_ALL ); 00586 00587 CComObjPtr<ICoreMetaAttributes> metaattributes; 00588 COMTHROW( metaobject->get_Attributes(PutOut(metaattributes)) ); 00589 ASSERT( metaattributes != NULL ); 00590 00591 typedef std::vector< CComObjPtr<ICoreMetaAttribute> > metaattributelist_type; 00592 metaattributelist_type metaattributelist; 00593 GetAll<ICoreMetaAttributes, ICoreMetaAttribute>(metaattributes, metaattributelist); 00594 00595 for( metaattributelist_type::iterator i=metaattributelist.begin(); i!=metaattributelist.end(); ++i ) 00596 { 00597 valtype_type valtype; 00598 COMTHROW( (*i)->get_ValueType(&valtype) ); 00599 if( attrSet==ATTR_ALL || 00600 (attrSet==ATTR_PRIMARY && (valtype==VALTYPE_POINTER || valtype==VALTYPE_COLLECTION || valtype==VALTYPE_LOCK)) || 00601 (attrSet==ATTR_SECONDARY && (valtype!=VALTYPE_LOCK && valtype!=VALTYPE_POINTER && valtype!=VALTYPE_COLLECTION))) 00602 { 00603 attrid_type attrId = ATTRID_NONE; 00604 COMTHROW( (*i)->get_AttrID(&attrId) ); 00605 ASSERT( attrId != ATTRID_NONE ); 00606 // TODO: remove indirection from AttribMap::value_type::value (too many mallocs) 00607 m_attributes.insert( AttribMap::value_type(attrId,XmlAttrBase::create(valtype)) ); 00608 } 00609 } 00610 } 00611 00612 void XmlObject::deleteSecondaryAttribs() 00613 { 00614 for( AttribMapIter it = m_attributes.begin(); it != m_attributes.end(); ) 00615 { 00616 valtype_type type =it->second->getType(); 00617 if( type!=VALTYPE_LOCK && type!=VALTYPE_POINTER && type!=VALTYPE_COLLECTION ) 00618 { 00619 delete it->second; 00620 m_attributes.erase(it++); 00621 } 00622 else 00623 ++it; 00624 00625 } 00626 } 00627 00628 00630 // CCoreXmlFile class 00632 00633 CCoreXmlFile::CCoreXmlFile() 00634 : m_console( true) 00635 { 00636 m_opened = false; 00637 m_inTransaction = false; 00638 m_modified = false; 00639 m_metaAttributeId = ATTRID_NONE; 00640 m_metaAttributeValType = VALTYPE_NONE; 00641 m_openedObject = NULL; 00642 m_sourceControl = SC_NONE; 00643 m_savedOnce = false; 00644 m_hashFileNames = false; 00645 m_hashInfoFound = false; 00646 m_hashVal = -1; 00647 m_needsSessionRefresh = true; 00648 fillParentMap(); 00649 00650 XMLPlatformUtils::Initialize(); 00651 } 00652 00653 CCoreXmlFile::~CCoreXmlFile() 00654 { 00655 clearAll(); 00656 XMLPlatformUtils::Terminate(); 00657 } 00658 00659 STDMETHODIMP CCoreXmlFile::get_MetaProject(ICoreMetaProject **p) 00660 { 00661 CHECK_OUT(p); 00662 CopyTo(m_metaProject, p); 00663 return S_OK; 00664 } 00665 00666 STDMETHODIMP CCoreXmlFile::put_MetaProject(ICoreMetaProject *p) 00667 { 00668 COMTRY 00669 { 00670 closeMetaProject(); 00671 m_metaProject = p; 00672 } 00673 COMCATCH( closeMetaProject() ) 00674 } 00675 00676 STDMETHODIMP CCoreXmlFile::get_MetaObject(ICoreMetaObject **p) 00677 { 00678 CHECK_OUT(p); 00679 CopyTo(m_metaObject, p); 00680 return S_OK; 00681 } 00682 00683 STDMETHODIMP CCoreXmlFile::put_MetaObject(ICoreMetaObject *p) 00684 { 00685 if( m_metaProject == NULL ) 00686 COMRETURN(E_INVALID_USAGE); 00687 00688 if( m_metaObject == p ) 00689 return S_OK; 00690 00691 COMTRY 00692 { 00693 if( p != NULL ) 00694 { 00695 // check the metaproject of the object, it must be the same as the metaproject 00696 // of the storage 00697 CComObjPtr<ICoreMetaProject> t; 00698 COMTHROW( p->get_Project(PutOut(t)) ); 00699 if( !IsEqualObject(m_metaProject, t) ) 00700 HR_THROW(E_SAMEPROJECT); 00701 } 00702 00703 closeMetaObject(); 00704 m_metaObject = p; 00705 if( m_metaObject != NULL ) 00706 openMetaObject(); 00707 } 00708 COMCATCH( closeMetaObject() ) 00709 } 00710 00711 STDMETHODIMP CCoreXmlFile::get_MetaID(metaid_type *p) 00712 { 00713 CHECK_OUT(p); 00714 *p = m_metaObjectId; 00715 return S_OK; 00716 } 00717 00718 STDMETHODIMP CCoreXmlFile::put_MetaID(metaid_type metaid) 00719 { 00720 if( m_metaProject == NULL ) 00721 COMRETURN(E_INVALID_USAGE); 00722 00723 COMTRY 00724 { 00725 if( metaid != METAID_NONE ) 00726 { 00727 CComObjPtr<ICoreMetaObject> p; 00728 COMTHROW( m_metaProject->get_Object(metaid, PutOut(p)) ); 00729 ASSERT( p != NULL ); 00730 00731 if( m_metaObject != p ) 00732 { 00733 closeMetaObject(); 00734 MoveTo(p, m_metaObject); 00735 openMetaObject(); 00736 } 00737 } 00738 else 00739 closeMetaObject(); 00740 } 00741 COMCATCH( closeMetaObject() ) 00742 } 00743 00744 STDMETHODIMP CCoreXmlFile::get_MetaAttribute(ICoreMetaAttribute **p) 00745 { 00746 CHECK_OUT(p); 00747 CopyTo(m_metaAttribute, p); 00748 return S_OK; 00749 } 00750 00751 STDMETHODIMP CCoreXmlFile::put_MetaAttribute(ICoreMetaAttribute *p) 00752 { 00753 if( m_metaObject == NULL ) 00754 COMRETURN(E_INVALID_USAGE); 00755 ASSERT( m_metaProject != NULL ); 00756 00757 if( m_metaAttribute == p ) 00758 return S_OK; 00759 00760 COMTRY 00761 { 00762 if( m_metaAttribute != NULL ) 00763 { 00764 // the metaobject of the given metaattribute must be the same as the metaobject of 00765 // the storage 00766 CComObjPtr<ICoreMetaObject> t; 00767 COMTHROW( m_metaAttribute->get_Object(PutOut(t)) ); 00768 if( !IsEqualObject(m_metaObject, t) ) 00769 { 00770 m_metaAttribute = NULL; 00771 return E_INVALIDARG; 00772 } 00773 } 00774 00775 closeMetaAttribute(); 00776 m_metaAttribute = p; 00777 if( m_metaAttribute != NULL ) 00778 openMetaAttribute(); 00779 } 00780 COMCATCH( closeMetaAttribute() ) 00781 } 00782 00783 STDMETHODIMP CCoreXmlFile::get_AttrID(attrid_type *p) 00784 { 00785 CHECK_OUT(p); 00786 if( m_metaAttribute ) 00787 return m_metaAttribute->get_AttrID(p); 00788 *p = 0; 00789 return S_OK; 00790 } 00791 00792 STDMETHODIMP CCoreXmlFile::put_AttrID(attrid_type attrid) 00793 { 00794 if( m_metaObject == NULL ) 00795 COMRETURN(E_INVALID_USAGE); 00796 ASSERT( m_metaProject != NULL ); 00797 00798 COMTRY 00799 { 00800 if( attrid != ATTRID_NONE ) 00801 { 00802 CComObjPtr<ICoreMetaAttribute> p; 00803 COMTHROW( m_metaObject->get_Attribute(attrid, PutOut(p)) ); 00804 ASSERT( p != NULL ); 00805 00806 if( m_metaAttribute != p ) 00807 { 00808 closeMetaAttribute(); 00809 m_metaAttribute = p; 00810 openMetaAttribute(); 00811 } 00812 } 00813 else 00814 closeMetaAttribute(); 00815 } 00816 COMCATCH( closeMetaAttribute() ) 00817 } 00818 00819 STDMETHODIMP CCoreXmlFile::get_AttributeValue(VARIANT *p) 00820 { 00821 CHECK_OUT(p); 00822 00823 if( m_openedObject == NULL || !m_inTransaction ) 00824 COMRETURN(E_INVALID_USAGE); 00825 00826 COMTRY 00827 { 00828 AttribMapIter it = m_openedObject->m_attributes.find( m_metaAttributeId ); 00829 if( m_metaAttributeValType == VALTYPE_POINTER ) 00830 { 00831 getPointer( (XmlAttrPointer*)it->second, p ); 00832 } 00833 else if( m_metaAttributeValType == VALTYPE_COLLECTION ) 00834 { 00835 getCollection( (XmlAttrCollection*)it->second, p ); 00836 } 00837 else if( m_metaAttributeValType == VALTYPE_LOCK ) 00838 { 00839 it->second->toVariant(p); 00840 } 00841 else 00842 { 00843 if( !m_openedObject->m_loaded ) 00844 { 00845 fullReadContainer(getContainer(m_openedObject)); 00846 it = m_openedObject->m_attributes.find( m_metaAttributeId ); 00847 00848 // if the attribute was not found -> throw 00849 if( m_openedObject->m_attributes.end() == it) 00850 COMTHROW(E_INVALID_USAGE); 00851 } 00852 00853 it->second->toVariant(p); 00854 } 00855 } 00856 COMCATCH(;) 00857 } 00858 00859 void CCoreXmlFile::applySmallChange( XmlObjSet& p_conts) 00860 { 00861 for( XmlObjSet::const_iterator it = p_conts.begin(); it != p_conts.end(); ++it) 00862 { 00863 XmlObject * p = *it; 00864 AttribMapIter ait = p->m_attributes.find( ATTRID_RELID); 00865 if( ait != p->m_attributes.end()) 00866 { 00867 long relid = ((XmlAttrLong*)(ait->second))->m_value; 00868 ((XmlAttrLong*)(ait->second))->m_value = relid + 1; 00869 long reljd = ((XmlAttrLong*)(ait->second))->m_value; 00870 ASSERT( relid + 1 == reljd); 00871 } 00872 } 00873 } 00874 00875 bool CCoreXmlFile::specialUserInquiryHandled( VARIANT p) 00876 { 00877 static const std::string magic_str = "UpdateSourceControlInfo"; 00878 static const std::string magi2_str = "WhoControlsThisObj"; 00879 static const std::string magi3_str = "ShowActiveUsers"; 00880 00881 bool ret = false; 00882 00883 string str; 00884 CopyTo(p, str); 00885 00886 bool b1 = str.find( magic_str) == 0; 00887 bool b2 = str.find( magi2_str) == 0; 00888 bool b3 = str.find( magi3_str) == 0; 00889 if( b1 || b2 || b3) 00890 { 00891 ret = true; 00892 00893 if( b1 || b2) 00894 { 00895 //DOMBuilder * parser = NULL; 00896 //DOMImplementationLS * domimpl = DOMImplementationRegistry::getDOMImplementation( XMLString::transcode("XML 1.0"));//NULL 00897 //ASSERT( domimpl != NULL ); 00898 00899 //parser = domimpl->createDOMBuilder( DOMImplementationLS::MODE_SYNCHRONOUS, NULL ); 00900 //ASSERT( parser != NULL ); 00901 00902 //XERCES_CPP_NAMESPACE::DOMDocument * doc = parser->parseURI( "F:\\t\\at\\an\\tesztam2\\f7bed9e2cbf62a418ec4e0df0ffe18a5.1xml"); 00903 //if( 0 == doc->getDocumentElement()) 00904 //{ 00905 // DOMNodeList* list = doc->getChildNodes(); 00906 00907 // int c = (int) list->getLength(); 00908 // for( int i = c-1; i >= 0 ; --i) 00909 // { 00910 // DOMNode * node = list->item(i); 00911 // if( node->getNodeType() == DOMNode::NodeType::TEXT_NODE) 00912 // { 00913 // DOMText * txt = (DOMText*) node; 00914 // const XMLCh* p = txt->getData(); 00915 // } 00916 // if( node->getNodeType() == DOMNode::ELEMENT_NODE) 00917 // { 00918 // DOMElement* elem = (DOMElement*)node; 00919 // const XMLCh* tn = elem->getTagName(); 00920 // } 00921 // } 00922 //} 00923 00924 std::string id = str.substr( b1?magic_str.length():magi2_str.length()); 00925 if( id != "") 00926 { 00927 // must be in sync with the current id creation (format) 00928 metaobjidpair_type objid; 00929 sscanf( id.c_str(), "id-%04lx-%08lx", &objid.metaid, &objid.objid); 00930 00931 XmlObject * obj = objectFromObjId( objid); 00932 if( obj && obj->isContainer()) b1?updateSourceControlInfo( obj) : whoControlsThis( obj); 00933 } 00934 else b1?updateSourceControlInfo():whoControlsThis(); // whole project 00935 } 00936 else if( b3) 00937 { 00938 std::string res( "The following users worked on the project since your log-in:\r\n"); 00939 std::vector< LoggedIn> lus = allusers(); 00940 for( std::vector< LoggedIn>::iterator it = lus.begin(), en = lus.end(); it != en; ++it) 00941 { 00942 res += std::string(1, '\t') + std::string(1, it->m_fl) + "\t\"" + it->m_nm + "\"\r\n"; 00943 } 00944 00945 if( lus.size() > 0) 00946 { 00947 //AfxMessageBox( res.c_str(), MB_ICONINFORMATION); 00948 CSvnTestDlg d; 00949 res.append( "Note: 'I' means Inactive, 'A' means Active users."); 00950 d.setContent( res.c_str()); 00951 d.DoModal(); 00952 } 00953 else 00954 AfxMessageBox( "No user login info found!"); 00955 } 00956 } 00957 00958 return ret; 00959 } 00960 00961 STDMETHODIMP CCoreXmlFile::put_AttributeValue(VARIANT p) 00962 { 00963 AFX_MANAGE_STATE(AfxGetStaticModuleState()); 00964 00965 if( m_openedObject == NULL || !m_inTransaction ) 00966 COMRETURN(E_INVALID_USAGE); 00967 00968 // root's guid changes evry time the project is modified we should igonre it 00969 // it casues some meta interpreter problems! 00970 if( m_metaAttributeId == ATTRID_GUID ) 00971 return S_OK; 00972 00973 if( 0&&m_metaAttributeId == ATTRID_LASTRELID) // never mind ATTRID_LASTRELID, thus 00974 return S_OK; // adding a child, won't affect parents 00975 00976 // setting root's ATTRID_MDATE to "updatesourcecontrolinfo" means we have to update sourcecontrolinfo 00977 // and ignore attribute setting 00978 if( m_metaAttributeId == ATTRID_MDATE ) 00979 { 00980 if( specialUserInquiryHandled( p)) 00981 return S_OK; 00982 } 00983 00984 #ifdef _DEBUG 00985 #if(DETAILS_ABOUT_XMLBACKEND) 00986 time_t time1, time2; 00987 struct tm *tm1, *tm2; 00988 time( &time1); tm1 = localtime( &time1); 00989 //sendMsg( std::string( "CommitBegin ") + asctime( tm1 ), MSG_INFO); 00990 #endif 00991 #endif 00992 00993 // ignore UpdateSourceControlInfo regnode 00994 if( m_openedObject && m_metaAttributeId == ATTRID_FILESTATUS) 00995 return S_OK; 00996 00997 // TODO: return with specific error code 00998 //if( m_openedObject->m_readOnly ) 00999 // COMRETURN(E_INVALID_USAGE); 01000 #ifdef _DEBUG 01001 #if(DETAILS_ABOUT_XMLBACKEND) 01002 std::string iiid, mylo; 01003 std::string gd; guid2str( m_openedObject->m_guid, gd); 01004 char* kind[] = {"100", "M", "A", "R", "C", "S", "F", "connrole", "connseg" 01005 , "109", "110", "StrAttr", "IntAttr", "FloatAttr", "BoolAttr", "RrefAttr", "116", "117", "118", "119" 01006 , "Constraint", "RegNode", "SetNode", "123", "124", "125", "126", "127" }; 01007 01008 char buff[5];sprintf( buff, "%i", m_metaAttributeId); 01009 01010 char * mavt[] = { "VALTYPE_None", "VALTYPE_COLL", "VALTYPE_Pointer", "VALTYPE_LOCK", "VALTYPE_LONG" 01011 , "VALTYPE_STR", "VALTYPE_BIN", "VALTYPE_REAL", "VALTYPE_8", "VALTYPE_9", "VALTYPE_10", "VALTYPE_11" 01012 , "VALTYPE_12", "VALTYPE_13", "VALTYPE_14"}; 01013 01014 if( m_userOpts.m_createLog) iiid = gd + " {" + ((m_openedObject->m_metaid<=100)?"Root": kind[m_openedObject->m_metaid-100]) + "} [ " + buff + " ](" + mavt[m_metaAttributeValType] + ")"; 01015 01016 if( m_userOpts.m_createLog) mylo += iiid; 01017 #endif 01018 #endif 01019 01020 COMTRY 01021 { 01022 AttribMapIter it = m_openedObject->m_attributes.find( m_metaAttributeId ); 01023 if( m_metaAttributeValType == VALTYPE_POINTER ) 01024 { 01025 if( m_metaAttributeId == ATTRID_PARENT) 01026 { 01027 // -- 01028 // this could be used to fine tune ATTRID_LASTRELID 01029 // m_userOpts.m_doModelParentLock 01030 // -- 01031 // delete handled separately in cases of models and non-model fcos 01032 // if a, r, s, c is deleted the parent model is checked out 01033 // among these a, r, s can be ports 01034 // models are tricky because upon deleting a model its parent 01035 // does not get checked out 01036 // in addition a model also can be a port 01037 metaid_type &mt = m_openedObject->m_metaid; 01038 XmlObject * grand_parent = 0; // will be used only if it is determined to be a port 01039 XmlObject * parent = 0; // will be used only if it is determined to be a port 01040 01041 // simply get its father: 01042 AttribMapIter it3 = m_openedObject->m_attributes.find( ATTRID_PARENT ); 01043 ASSERT( it3 != m_openedObject->m_attributes.end() ); 01044 XmlObject * cont = parent = ((XmlAttrPointer*)(it3->second))->m_parent; 01045 01046 // is removal (delete), is movement or is childbirth :) ? 01047 metaobjidpair_type idpair;CopyTo(p, idpair); 01048 bool is_removal = idpair.metaid == 0 && idpair.objid == 0; // VARIANT p is 0 => removal 01049 bool is_movemnt = !is_removal && parent != 0; 01050 01051 if( is_removal || is_movemnt) // check if latent changes prevent this operation from happening 01052 { 01053 std::string scapegoat; 01054 if( findOnProtectedLists( m_openedObject->m_guid, scapegoat)) 01055 { 01056 std::string msg = std::string( "Element ") + makelink( m_openedObject) + " found on a protected list of user \"" + scapegoat + "\" thus it can't be moved/deleted!"; 01057 sendMsg( msg, MSG_ERROR); 01058 AfxMessageBox( msg.c_str(), MB_ICONSTOP); 01059 throw hresult_exception(E_FAIL); 01060 } 01061 protect( m_openedObject, is_removal?ELEM_DELETED:ELEM_MOVED); 01062 01063 ASSERT( m_userOpts.m_doConnEndPointLock); // currently we assume this especially 01064 ASSERT( m_userOpts.m_doConnSegmentLock); // by not dealing too much with ports 01065 01066 #ifdef _DEBUG 01067 #if(DETAILS_ABOUT_XMLBACKEND) 01068 if( m_userOpts.m_createLog) {std::string nn,mm; parent->m_attributes.find( ATTRID_NAME )->second->toString( nn); 01069 m_openedObject->m_attributes.find(ATTRID_NAME)->second->toString(mm); 01070 mylo += (is_removal?" <br>-deleting ":" <br>-moving ") + mm + " in " + nn + "- <br>" ;} 01071 #endif 01072 #endif 01073 01074 } 01075 01076 if( is_removal) { 01077 m_deldObjs.push_back( m_openedObject); 01078 if( m_openedObject->m_metaid== DTID_REFERENCE) { 01079 //setPointer( m_openedObject, ATTRID_REFERENCE, 0); 01080 } 01081 } 01082 01083 // when inserting Atoms, Refs, Sets in a archetype model, this gets down 01084 // to deriveds too, so they will be checked out too. 01085 // if models are inserted into archetype models, the subtypes of the archetype 01086 // do not necessarily change. That's why we need to deal with these. 01087 // LAST_RELID modification is done only on the archetype parent 01088 // if this has been derived to SParent, and SSParent, ... 01089 // upon inserting a model into Parent LAST_RELID changes are not performed 01090 // on SParent, SSParent, because the newly inserted element has different relid (>RELIDSPACE) 01091 // so we need to make sure we slightly alter the subtyped parents too 01092 if( !is_removal && !is_movemnt && m_openedObject->m_metaid == DTID_MODEL) // a model is inserted 01093 { 01094 XmlObjSet derd_from_cont; 01095 if( cont) 01096 getDeriveds( cont, derd_from_cont); // or from its father 01097 else 01098 getDeriveds( objectFromObjId( idpair), derd_from_cont); 01099 if( !derd_from_cont.empty()) 01100 applySmallChange( derd_from_cont); 01101 for( XmlObjSet::const_iterator it = derd_from_cont.begin(); it != derd_from_cont.end(); ++it) 01102 if( m_modifiedObjects.end() == m_modifiedObjects.find( *it)) // not found 01103 m_modifiedObjects.insert( *it); 01104 01105 } 01106 } 01107 // 01108 // we have alternatives as follows regarding consistency maintanance: 01109 // 1. We could require any NewTarget object (where the reference will point) 01110 // to be neither locked, neither latent changed (aka modified already (by other users)) 01111 // thus we could be sure, that NewTarget version we see is still the latest one. 01112 // BeforeSave: NewTarget has been added as "REFERRED" to the protectList 01113 // so it is not possible for others to delete it anymore. 01114 // NewTarget is not necessarily checked out (only if we decide so) 01115 // Reference will change, so it is needed to be checked out, thus locked. 01116 // AfterSave : Reference changed, checked back, for others became a latent change. 01117 // NewTarget will remain unchanged, (even if we checked it out, upon checkin 01118 // the same file contents are saved back, no new version is created. 01119 // No deletion/removal can happen until this protection goes away from the list 01120 // Pro: - upon redirection no complex operations take place 01121 // Con: - NewTarget is required to be untouched by others 01122 // 2. We could check upon any redirection the state of the protectionlists, 01123 // to see if NewTarget was deleted. If was moved elsewhere, that is not too relevant. 01124 // BeforeSave: NewTarget has been added as "REFERRED" to the protectionlist, thus 01125 // preventing later deletion by others. 01126 // Reference will change, so it is needed to be checked out, thus locked. 01127 // NewTarget would not be changed, its state is not required to be anything 01128 // special. 01129 // AfterSave: Reference changed, checked back, for others became a latent change. 01130 // NewTarget will remain unchanged, (unless something special in case it can be performed) 01131 // No deletion can happen on NewTarget, because it has been referred, so its on the protection list. 01132 // Pro: - NewTarget is not necessarily required to be available to us when referred, allows for better 01133 // parralel work of the team. 01134 // Con: - checking all users protection lists upon for REFERRED event could be slow 01135 // - additional checks might be required to ensure that NewTarget's port children 01136 // are not deleted by other users, while we would connect them through Reference's 01137 // reference ports, this might lead to inconsistent connections (src/dst could be non-existent) 01138 // Let us implement #1 with the NewTarget checked out option, to make sure we see the latest version of it. 01139 // Extension later: if our NewTarget is not the latest (we can't modify it), then we browse the 01140 // protection list to make sure it was NOT deleted, and only then allow referral to it. 01141 // When the paradigm allows references to point to references, and if NewTarget is also 01142 // a reference, we must make sure, that it hasn't been redirected either. 01143 // m_userOpts.m_doRefTargetLock=true must be used in this case 01144 if( m_metaAttributeId == ATTRID_REFERENCE) // 505 01145 { 01146 // redirection needs to be taken care of !!! 01147 // it affects connections, going through these refs 01148 metaid_type &mt = m_openedObject->m_metaid; 01149 01150 // simply get its target, if filled 01151 AttribMapIter it3 = m_openedObject->m_attributes.find( ATTRID_REFERENCE ); 01152 ASSERT( it3 != m_openedObject->m_attributes.end() ); 01153 XmlObject * old_target = ((XmlAttrPointer*)(it3->second))->m_parent; 01154 01155 // is removal (delete), is movement or is childbirth :) ? 01156 //metaobjidpair_type idpair;CopyTo(p, idpair); 01157 //bool is_removal = idpair.metaid == 0 && idpair.objid == 0; // VARIANT p is 0 => removal 01158 bool is_redirection = old_target != 0; // clear is also redirection 01159 if( is_redirection) 01160 { 01161 protect( m_openedObject, ELEM_REF_REDIRECTED); // might be useful for connections 01162 01163 // commented on Sept.3. 01164 //XmlObjSet to_be_checked_out_containers; 01165 //XmlObjSet fdfdf; 01166 // 01167 // find all references to this reference 01168 // to prevent breaking connections which 01169 //fdfdf.insert( m_openedObject); 01170 // upon a reference delete first the ATTRID_PARENT = 0 comes, later comes the 01171 // ATTRID_REFERENCE = 0, so this might confuse getMyDepObjConts, it will 01172 // find its container be 0 01173 if( std::find( m_deldObjs.begin(), m_deldObjs.end(), m_openedObject) != m_deldObjs.end()) // found 01174 { 01175 int l = 0; 01176 ++l; 01177 } 01178 //getMyDepObjConts( fdfdf, to_be_checked_out_containers, true); 01179 //m_modifiedObjects.insert( to_be_checked_out_containers.begin(), to_be_checked_out_containers.end()); 01180 } 01181 01182 metaobjidpair_type idpair;CopyTo(p, idpair); 01183 XmlObject * new_target_obj = objectFromObjId( idpair); 01184 01185 if( new_target_obj) protect( new_target_obj, ELEM_REFERRED); 01186 01187 ASSERT( m_userOpts.m_doRefTargetLock);// currently we assume this 01188 01189 if( m_userOpts.m_doRefTargetLock) 01190 { 01191 // new target also to be locked in this case (is it a model/or nonmodel?) 01192 if( new_target_obj) m_modifiedObjects.insert( new_target_obj); 01193 } 01194 } 01195 // DERIVATION 01196 // Let B be a base container, derived into D. B has C1 and C2 children. C2 has 01197 // C3 and C4 as children. B's parent is A. 01198 // When B is derived locks are required for B, C1, C2, C3, C4. 01199 // Small modification is made to all these objects (this will prevent 01200 // further standalone subtyping of Cx-s) 01201 // A's standalone subtyping will be prevented by the modified inner objects (B, Cx-s) 01202 // Before Save: objects are locked 01203 // After Save: objects become RO (read-only) 01204 // After reopen: objects are already basetypes of D, DC1 (secondary derived peer of C1) 01205 // DC2, ..., DC4, thus conflicts are prevented by their presence. 01206 // Q: What happens if after reopen a user deleted D and derives A? 01207 if( m_metaAttributeId == ATTRID_DERIVED) // 510, 517? 01208 { 01209 metaobjidpair_type idpair;CopyTo(p, idpair); 01210 bool is_derivation = idpair.metaid != 0 && idpair.objid != 0; // VARIANT p is 0 => detach 01211 XmlObject * base_obj = objectFromObjId( idpair); 01212 if( is_derivation && base_obj != 0) 01213 { 01214 AttribMapIter it3 = m_openedObject->m_attributes.find( ATTRID_RELID ); 01215 ASSERT( it3 != m_openedObject->m_attributes.end() ); 01216 long relid = ((XmlAttrLong*)(it3->second))->m_value; 01217 bool secondary_deriv = relid > RELID_BASE_MAX; 01218 01219 #ifdef _DEBUG 01220 #if(DETAILS_ABOUT_XMLBACKEND) 01221 if( m_userOpts.m_createLog) { 01222 if( relid > RELID_BASE_MAX) 01223 mylo += " <br>- !!!! secondary derivation took place !!!! - <br>" ; 01224 else 01225 mylo += " <br>- !!!! primary derivation took place !!!! - <br>" ; 01226 } 01227 #endif 01228 #endif 01229 if( !secondary_deriv) 01230 { 01231 // 01232 // m_userOpts.m_doBaseTypeLock // this could be used too 01233 // 01234 // try to lock the hierarchy of base_obj to prevent concurrent derivations 01235 // of objects on different levels: e.g. parent derd by userA, child derd by userB 01236 XmlObjSet checkOutBases; 01237 XmlObjSet fdfdf; 01238 XmlObjSet to_be_checked_out_containers; 01239 // find all dependents of parent (? and m_openedObject) 01240 // where the deleted port can be seen 01241 //fdfdf.insert( parent); 01242 //fdfdf.insert( m_openedObject); 01243 fdfdf.insert( base_obj); 01244 01245 protect( base_obj, ELEM_DERIVED); 01246 01247 getBasesOf( fdfdf, checkOutBases); 01248 getAllUpAndDown( fdfdf, to_be_checked_out_containers);to_be_checked_out_containers.insert( checkOutBases.begin(), checkOutBases.end()); 01249 // perform a dummy operation on all containers 01250 for( XmlObjSet::const_iterator it = to_be_checked_out_containers.begin(); it != to_be_checked_out_containers.end(); ++it) 01251 { 01252 XmlObject * p = *it; 01253 AttribMapIter ait = p->m_attributes.find( ATTRID_RELID); 01254 if( ait != p->m_attributes.end()) 01255 { 01256 // dummy operation 01257 long relid = ((XmlAttrLong*)(ait->second))->m_value; 01258 ((XmlAttrLong*)(ait->second))->m_value = relid + 1; 01259 long reljd = ((XmlAttrLong*)(ait->second))->m_value; 01260 ASSERT( relid + 1 == reljd); 01261 } 01262 } 01263 m_modifiedObjects.insert( to_be_checked_out_containers.begin(), to_be_checked_out_containers.end()); 01264 } 01265 } 01266 } 01267 // CONNECTION 01268 // Let S and D be source and destination. 01269 // Four scenarios exist regarding their connectibility: 01270 // Connection between: 01271 // 1.S and/or D as standalone objects 01272 // 2.S and/or D exposed as ports in their parents (MS and MD their parents) 01273 // 3.S and/or D exposed as ports of a reference to MS respectively MD 01274 // (Let RMS and RMD be these references.) 01275 // 4.S and/or D exposed as ports of a reference to RMS respectively RMD 01276 // (Yes, references to references, which in turn reference a model, are also 01277 // suitable for creating connections.) 01278 // 01279 // If S and D are checkoutable, that means we see their latest version 01280 // (more specifically MS and MD except if S and D are models) 01281 // For cases 3 and 4 add RMS and RRMS respectively RMD, RRMD. 01282 // If checkoutable is false, then protection lists could be analyzed for 01283 // DEL/MOVE events. 01284 // For cases 3 and 4 add REDIR event checkup on RMS/RRMS resp. RMD/RRMD. 01285 // Before Save: objects are locked, plus the parent of the connection. 01286 // After Save: all objects become lockables again (checkoutable) except 01287 // the connection parent. 01288 // CEnd, CSeq policy means that we lock S, D, RMS, RMD (in 3rd case), 01289 // RRMS and RRMD (in 4th case) 01290 if( m_openedObject->m_metaid == DTID_CONNROLE && m_metaAttributeId == ATTRID_FCOREFATTR) // 525 or ATTRID_XREF 01291 { 01292 metaobjidpair_type idpair;CopyTo(p, idpair); 01293 bool is_conn = idpair.metaid != 0 && idpair.objid != 0; // VARIANT p is 0 => owner connection is being deleted 01294 XmlObject * end_obj = objectFromObjId( idpair); 01295 01296 protect( end_obj, ELEM_CONNECTED); 01297 01298 if( is_conn && end_obj != 0 && m_userOpts.m_doConnEndPointLock) 01299 { 01300 m_modifiedObjects.insert( end_obj); 01301 #ifdef _DEBUG 01302 #if(DETAILS_ABOUT_XMLBACKEND) 01303 if( m_userOpts.m_createLog) { 01304 std::string nn,mm; end_obj->m_attributes.find( ATTRID_NAME )->second->toString( nn); 01305 end_obj->m_attributes.find(ATTRID_NAME)->second->toString(mm); 01306 mylo += "<br>connecting through endpoint " + mm + " thus locking it <br>" ; 01307 } 01308 #endif 01309 #endif 01310 01311 } 01312 } 01313 01314 if( m_openedObject->m_metaid == DTID_CONNROLESEG && m_metaAttributeId == ATTRID_SEGREF) // 511, the Reference Involved 01315 { 01316 metaobjidpair_type idpair;CopyTo(p, idpair); 01317 bool is_filled = idpair.metaid != 0 && idpair.objid != 0; // VARIANT p is 0 => owner connection is being deleted 01318 bool is_a_ref = idpair.metaid == DTID_REFERENCE; // a conn seg must point by its SEGREF to a Ref 01319 XmlObject * segment_ref = objectFromObjId( idpair); 01320 01321 protect( segment_ref, ELEM_TAKESPARTINCONN); 01322 01323 if( is_filled && is_a_ref && segment_ref != 0 && m_userOpts.m_doConnSegmentLock) 01324 { 01325 m_modifiedObjects.insert( segment_ref); 01326 #ifdef _DEBUG 01327 #if(DETAILS_ABOUT_XMLBACKEND) 01328 if( m_userOpts.m_createLog) { 01329 std::string nn,mm; segment_ref->m_attributes.find( ATTRID_NAME )->second->toString( nn); 01330 segment_ref->m_attributes.find(ATTRID_NAME)->second->toString(mm); 01331 mylo += "<br>connecting through segment ref " + mm + " thus locking it <br>" ; 01332 } 01333 #endif 01334 #endif 01335 01336 } 01337 } 01338 01339 m_modifiedObjects.insert( m_openedObject ); 01340 01341 // handle special case: if this is the containment parent and this object is an inner 01342 // we have to check out the parent too 01343 ParentMap::iterator it2 = m_parentMap.find( m_openedObject->m_metaid ); 01344 ASSERT( it2 != m_parentMap.end() ); 01345 if( it2->second == m_metaAttributeId && !m_openedObject->isContainer() ) 01346 { 01347 XmlObject * cont = getContainer(m_openedObject); 01348 if (NULL != cont) { 01349 m_modifiedObjects.insert( cont ); 01350 } 01351 } 01352 01353 XmlAttrPointer * pointerAttr = (XmlAttrPointer*)it->second; 01354 if( m_undoMap.find(it->second) == m_undoMap.end() ) 01355 { 01356 std::pair<UndoMapIter, bool> t = m_undoMap.insert( UndoMap::value_type(it->second,UndoItem(m_openedObject, m_metaAttributeId, CComVariant()) )); 01357 getPointer( pointerAttr, PutOut(t.first->second.m_value) ); 01358 } 01359 XmlObject * parnt = setPointer( p ); 01360 } 01361 else if( m_metaAttributeValType == VALTYPE_COLLECTION ) 01362 { 01363 ASSERT( false ); 01364 } 01365 else if( m_metaAttributeValType == VALTYPE_LOCK ) 01366 { 01367 if( m_undoMap.find(it->second) == m_undoMap.end() ) 01368 { 01369 std::pair<UndoMapIter, bool> t = m_undoMap.insert( UndoMap::value_type(it->second,UndoItem(m_openedObject, m_metaAttributeId, CComVariant()) )); 01370 it->second->toVariant( PutOut(t.first->second.m_value) ); 01371 } 01372 01373 it->second->fromVariant(p); 01374 01375 //TODO: if locks go down to 0 it could be written out to the file 01376 } 01377 else // VALTYPE_BIN, VALTYPE_STR, VALTYPE_LONG, VALTYPE_REAL, VALTYPE_DICT 01378 { 01379 #ifdef _DEBUG 01380 #if(DETAILS_ABOUT_XMLBACKEND) 01381 if( m_userOpts.m_createLog) { 01382 mylo += " - valtype_StLoRe " ; 01383 } 01384 #endif 01385 #endif 01386 m_modifiedObjects.insert( m_openedObject ); 01387 01388 if( !m_openedObject->m_loaded ) 01389 { 01390 fullReadContainer(getContainer(m_openedObject)); 01391 it = m_openedObject->m_attributes.find( m_metaAttributeId ); 01392 } 01393 01394 // save previous value to m_undoMap (if this is the first modification) 01395 if( m_undoMap.find(it->second) == m_undoMap.end() ) 01396 { 01397 std::pair<UndoMapIter, bool> t = m_undoMap.insert( UndoMap::value_type(it->second,UndoItem(m_openedObject, m_metaAttributeId, CComVariant()) )); 01398 it->second->toVariant( PutOut(t.first->second.m_value) ); 01399 } 01400 it->second->fromVariant(p); 01401 } 01402 01403 #ifdef _DEBUG 01404 #if(DETAILS_ABOUT_XMLBACKEND) 01405 if( m_userOpts.m_createLog) { 01406 mylo += "\r\n"; 01407 if( m_metaAttributeValType != VALTYPE_LOCK) //3 01408 mylog += mylo; 01409 } 01410 //#endif 01411 //#endif 01412 std::string gd_str; guid2str( m_openedObject->m_guid, gd_str); 01413 char* kind[] = {"100", "M", "A", "R", "C", "S", "F", "connrole", "connseg" 01414 , "109", "110", "StrAttr", "IntAttr", "FloatAttr", "BoolAttr", "RrefAttr", "116", "117", "118", "119" 01415 , "Constraint", "RegNode", "SetNode", "123", "124", "125", "126", "127" }; 01416 01417 char * oper[] = { "VALTYPE_None", "VALTYPE_COLL", "VALTYPE_Pointer", "VALTYPE_LOCK", "VALTYPE_LONG" 01418 , "VALTYPE_STR", "VALTYPE_BIN", "VALTYPE_REAL", "VALTYPE_8", "VALTYPE_9", "VALTYPE_10", "VALTYPE_11" 01419 , "VALTYPE_12", "VALTYPE_13", "VALTYPE_14"}; 01420 01421 char mattrid[5];sprintf( mattrid, "%i", m_metaAttributeId); 01422 std::string kind_str = ((m_openedObject->m_metaid<=100)?"Root": kind[m_openedObject->m_metaid-100]); 01423 std::string oper_str = oper[m_metaAttributeValType]; 01424 01425 time( &time2); tm2 = localtime( &time2); 01426 double dur = difftime( time2, time1); 01427 char buff[100]; 01428 sprintf( buff, "putAttribute [[%6.0f secs]] %s {%s} [ %s ] (%s)", dur, gd_str.c_str(), kind_str.c_str(), mattrid, oper_str.c_str()); 01429 01430 if( m_userOpts.m_measureTime) 01431 sendMsg( buff, MSG_INFO); 01432 #endif 01433 #endif 01434 01435 m_openedObject->m_modified = true; 01436 m_modified = true; 01437 } 01438 COMCATCH(;) 01439 } 01440 01441 STDMETHODIMP CCoreXmlFile::OpenObject(objid_type objid) 01442 { 01443 if( m_metaObject == NULL || !m_inTransaction ) 01444 COMRETURN(E_INVALID_USAGE); 01445 01446 metaobjidpair_type idpair; 01447 idpair.metaid = m_metaObjectId; 01448 idpair.objid = objid; 01449 01450 COMTRY 01451 { 01452 m_openedObject = objectFromObjId(idpair); 01453 01454 if( !m_openedObject || m_openedObject->m_deleted ) 01455 m_openedObject = NULL; 01456 } 01457 COMCATCH(;) 01458 } 01459 01460 STDMETHODIMP CCoreXmlFile::CreateObject(objid_type *objid) 01461 { 01462 CHECK_OUT(objid); 01463 01464 if( m_metaObject == NULL || !m_inTransaction ) 01465 COMRETURN(E_INVALID_USAGE); 01466 01467 ASSERT( m_metaObjectId != METAID_ROOT ); 01468 01469 COMTRY 01470 { 01471 // create and add new object 01472 XmlObject * obj = new XmlObject(m_metaObject,true); 01473 addObject( obj ); 01474 01475 m_createdObjects.push_back(obj); 01476 01477 m_modified = true; 01478 m_openedObject = obj; 01479 *objid = (long)obj; 01480 01481 if( obj->m_metaid==DTID_MODEL || obj->m_metaid==DTID_FOLDER ) 01482 { 01483 resetSourceControlInfo( obj ); 01484 resetSourceControlStat( obj, true ); 01485 } 01486 } 01487 COMCATCH(;) 01488 } 01489 01490 STDMETHODIMP CCoreXmlFile::CloseObject() 01491 { 01492 m_openedObject = NULL; 01493 return S_OK; 01494 } 01495 01496 STDMETHODIMP CCoreXmlFile::LockObject() 01497 { 01498 return S_OK; 01499 } 01500 01501 STDMETHODIMP CCoreXmlFile::DeleteObject() 01502 { 01503 if( m_openedObject == NULL || !m_inTransaction ) 01504 COMRETURN(E_INVALID_USAGE); 01505 01506 m_openedObject->m_deleted = true; 01507 m_deletedObjects.insert( m_openedObject ); 01508 01509 m_modified = true; 01510 01511 //m_modifiedObjects.insert( m_openedObject ); 01512 // TODO: add container 01513 //try { 01514 // if( m_openedObject->isContainer()) 01515 // { 01516 // // obj has its own file 01517 // std::string path; 01518 // getSourceSafePath( m_openedObject, path); 01519 // CComBSTR vssPath = path.c_str(); 01520 01521 // // obtain file handle in VSS 01522 // CComObjPtr<IVSSItem> item; 01523 // COMTHROW( m_vssDatabase->get_VSSItem( vssPath, false, &(item.p)) ); 01524 01525 // FILE * f = fopen( (m_folderPath + "\\tombstone.txt").c_str(), "a+b"); 01526 // if( f) 01527 // { 01528 // std::string fname; 01529 // getContainerFileName( m_openedObject, fname, false); 01530 // fprintf( f, "%s\n", fname.c_str()); 01531 // fclose( f); 01532 // } 01533 // // this solution is not good, since for all users but this the local .xml file 01534 // // will be unaffected: if the vss entry is renamed, upon getLatest an obsolete 01535 // // file won't be overwritten by its newer (which shows that it is deleted) version 01536 // //CComBSTR nm; 01537 // //COMTHROW( item->get_Name( &nm)); 01538 // //nm.Append( ".del"); // append this extension to the filename 01539 // //COMTHROW( item->put_Name( nm)); 01540 // } 01541 //} catch( hresult_exception&) { 01542 // int l = 0; 01543 // ++l; 01544 //} 01545 CloseObject(); 01546 01547 return S_OK; 01548 } 01549 01550 void CCoreXmlFile::resetSettings() 01551 { 01552 m_hashFileNames = false; 01553 m_hashInfoFound = false; 01554 m_hashVal = -1; 01555 m_svn.reset(); 01556 } 01557 01558 STDMETHODIMP CCoreXmlFile::OpenProject(BSTR connection, VARIANT_BOOL *ro_mode) 01559 { 01560 if( m_opened || m_metaProject == NULL ) 01561 COMRETURN(E_INVALID_USAGE); 01562 01563 AFX_MANAGE_STATE(AfxGetStaticModuleState( )); 01564 01565 COMTRY { 01566 resetSettings(); 01567 01568 parseConnectionString( connection ); 01569 setFileNames(); 01570 01571 m_userOpts.reset(); 01572 m_userOpts.load( m_folderPath); 01573 m_userOpts.display( this); 01574 01575 readProjectFile(); 01576 01577 bool cache_loading_succeeded = false; 01578 if( m_userOpts.m_partialLoad) { 01579 cache_loading_succeeded = readBinaryCache(); 01580 } 01581 // if usecache option is false or if cache not read succesfully 01582 01583 //if( !m_userOpts.m_partialLoad) 01584 if( !m_userOpts.m_partialLoad || !cache_loading_succeeded) // part_load was not requested or it was, but failed 01585 //if( !m_userOpts.m_partialLoad || !readBinaryCache()) 01586 //if( true ) 01587 { 01588 // binary cache is not found, get latest and read all 01589 if( m_sourceControl != SC_NONE ) { 01590 getLatestVersion(); 01591 } 01592 01593 readAll( true ); 01594 //if( m_userOpts.m_partialLoad) writeBinaryCache(); 01595 } 01596 else 01597 { 01598 if( m_sourceControl != SC_NONE ) { 01599 getLatestVersion(); 01600 } 01601 01602 readAll( false ); 01604 //if( m_sourceControl != SC_NONE ) 01605 // getLatestAndLoad(); 01606 } 01607 01608 // Check for the new session folder, create one on-demand 01609 std::string sessionFolder = m_folderPath + "\\" + HelperFiles::sessionFolderName; 01610 DWORD atts = ::GetFileAttributes(sessionFolder.c_str()); 01611 if (atts == INVALID_FILE_ATTRIBUTES || !(atts & FILE_ATTRIBUTE_DIRECTORY) ) { 01612 sendMsg( "Detecting old session format. Upgrading to newer one (dedicated session folder).", MSG_INFO); 01613 01614 BOOL succ = ::CreateDirectory( sessionFolder.c_str(), NULL); 01615 if( succ != TRUE) 01616 { 01617 sendMsg( "Exception: Could not create session folder: " + sessionFolder, MSG_ERROR); 01618 AfxMessageBox( (std::string( "Could not create session folder: ") + sessionFolder).c_str()); 01619 HR_THROW(E_FILEOPEN); 01620 } 01621 // add to server 01622 if (m_sourceControl == SC_SUBVERSION) 01623 succ = addSVN( sessionFolder, true /*=recursive*/); 01624 if( !succ) { 01625 sendMsg( "Exception: Could not add session folder to server.", MSG_ERROR); 01626 AfxMessageBox( "Could not add session folder to server."); 01627 HR_THROW(E_FILEOPEN); 01628 } 01629 01630 // initial commit 01631 if (m_sourceControl == SC_SUBVERSION) 01632 succ = commitSVN( m_folderPath, std::string("auto: OpenProject()"), true); 01633 if( !succ) { 01634 sendMsg( "Exception: Could not commit session folder.", MSG_ERROR); 01635 AfxMessageBox( "Could not commit session folder."); 01636 HR_THROW(E_FILEOPEN); 01637 } 01638 } 01639 01640 // m_sourceControl has to be filled for these methods below (setParent) 01641 m_signer.setParent( this); 01642 m_signer.in(); // signing on does username verification also 01643 m_protectList.setParent( this); 01644 01645 // purge my protect list 01646 m_protectList.onLoad(); 01647 01648 m_opened = true; 01649 m_modified = false; 01650 m_savedOnce = true; 01651 01652 if(ro_mode!=NULL) 01653 *ro_mode = VARIANT_FALSE; 01654 01655 CloseProgressWindow(); 01656 if (m_root == NULL) 01657 return E_FILEOPEN; 01658 01659 } 01660 COMCATCH(CloseProgressWindow();) 01661 } 01662 01663 STDMETHODIMP CCoreXmlFile::CreateProject(BSTR connection) 01664 { 01665 AFX_MANAGE_STATE(AfxGetStaticModuleState( )); 01666 01667 COMTRY { 01668 resetSettings(); 01669 01670 if( m_opened || m_metaProject == NULL ) 01671 COMRETURN(E_INVALID_USAGE); 01672 01673 parseConnectionString( connection ); 01674 setFileNames(); 01675 m_hashInfoFound = true; // upon creation we select the hash/nonhash question 01676 // user options can't be provided in this scenario 01677 //m_userOpts.load( m_folderPath, this); 01678 01679 // clear data structures 01680 clearAll(); 01681 01682 // query the metaobject for the root 01683 CComObjPtr<ICoreMetaObject> mo; 01684 COMTHROW( m_metaProject->get_Object(METAID_ROOT, PutOut(mo)) ); 01685 ASSERT( mo != NULL ); 01686 01687 // create the root 01688 m_root = new XmlObject(mo,true); 01689 addObject( m_root ); 01690 01691 if( m_svnUrl.size() > 0) 01692 createSubversionedFolder(); 01693 else //AfxMessageBox( "Project has not been created under a source control system"); 01694 createNonversioned(); 01695 01696 createProjectFile(); 01697 01698 // m_sourceControl has to be filled for these methods below (setParent) 01699 m_signer.setParent( this); 01700 m_signer.in(); // signing on does username verification also 01701 m_protectList.setParent( this); 01702 01703 m_opened = true; 01704 m_modified = false; 01705 01706 CloseProgressWindow(); 01707 } COMCATCH(CloseProgressWindow();) 01708 01709 return S_OK; 01710 } 01711 01712 STDMETHODIMP CCoreXmlFile::SaveProject(BSTR connection, VARIANT_BOOL keepoldname = VARIANT_TRUE) 01713 { 01714 AFX_MANAGE_STATE(AfxGetStaticModuleState()); 01715 01716 COMTRY { 01717 // reload options in order to allow 'change-of-mind' for users 01718 m_userOpts.reset(); 01719 m_userOpts.load( m_folderPath); 01720 m_userOpts.display( this); 01721 01722 if( m_userOpts.m_partialLoad) writeBinaryCache(); 01723 writeAll(); 01724 01725 if( m_sourceControl != SC_NONE ) 01726 { 01727 if( !m_savedOnce ) 01728 checkInAll(true); 01729 else 01730 checkInAll(); 01731 01732 } 01733 01734 m_modified = false; 01735 m_savedOnce = true; 01736 01737 CloseProgressWindow(); 01738 } COMCATCH(CloseProgressWindow();) 01739 01740 return S_OK; 01741 } 01742 01743 STDMETHODIMP CCoreXmlFile::CloseProject( VARIANT_BOOL abort) 01744 { 01745 AFX_MANAGE_STATE(AfxGetStaticModuleState()); 01746 01747 if( !m_opened || m_metaProject == NULL ) 01748 COMRETURN(E_INVALID_USAGE); 01749 01750 COMTRY 01751 { 01752 /*if( abort == VARIANT_FALSE && m_modified ) 01753 SaveProject(NULL); 01754 01755 if( m_sourceControl != SC_NONE ) 01756 checkInAll();*/ 01757 01758 // FIXME Delete if Creat was no successful? 01759 01760 // purge my protect list 01761 m_protectList.onLoad(); 01762 01763 m_signer.off(); 01764 clearAll(); 01765 resetSettings(); 01766 XMLPlatformUtils::Terminate(); 01767 CloseProgressWindow(); 01768 } 01769 COMCATCH(CloseProgressWindow();) 01770 } 01771 01772 STDMETHODIMP CCoreXmlFile::DeleteProject() 01773 { 01774 TCHAR dir[MAX_PATH + 1]; 01775 _tcscpy(dir, m_folderPath.c_str()); 01776 dir[m_folderPath.length()] = L'\0'; 01777 01778 SHFILEOPSTRUCT file_op = { 01779 NULL, 01780 FO_DELETE, 01781 dir, 01782 "", 01783 FOF_NOCONFIRMATION | 01784 FOF_NOERRORUI | 01785 FOF_SILENT, 01786 false, 01787 0, 01788 "" }; 01789 return SHFileOperation(&file_op) ? E_FAIL : S_OK; 01790 } 01791 01792 STDMETHODIMP CCoreXmlFile::BeginTransaction() 01793 { 01794 AFX_MANAGE_STATE(AfxGetStaticModuleState()); 01795 01796 if( !m_opened || m_inTransaction ) 01797 COMRETURN(E_INVALID_USAGE); 01798 m_inTransaction = true; 01799 m_trivialChanges = true; 01800 m_fullLockNeeded = false; 01801 m_needsSessionRefresh = true; 01802 return S_OK; 01803 } 01804 01805 STDMETHODIMP CCoreXmlFile::CommitTransaction() 01806 { 01807 AFX_MANAGE_STATE(AfxGetStaticModuleState()); 01808 01809 COMTRY { 01810 if( !m_inTransaction ) 01811 COMRETURN(E_INVALID_USAGE); 01812 01813 ASSERT( m_opened ); 01814 01815 bool failed = false; 01816 01817 #ifdef _DEBUG 01818 #if(DETAILS_ABOUT_XMLBACKEND) 01819 time_t time1, time2, time3; 01820 struct tm *tm1, *tm2, *tm3; 01821 time( &time1); tm1 = localtime( &time1); 01822 //if( m_userOpts.m_measureTime) sendMsg( std::string( "CommitBegin ") + asctime( tm1 ), MSG_INFO); 01823 #endif 01824 #endif 01825 01826 XmlObjSet to_be_checked_out_containers; 01827 getCheckOutContainers(m_modifiedObjects, to_be_checked_out_containers); 01828 01829 #ifdef _DEBUG 01830 #if(DETAILS_ABOUT_XMLBACKEND) 01831 time( &time2); tm2 = localtime( &time2); 01832 //if( m_userOpts.m_measureTime) sendMsg( std::string( "CommitMidle ") + asctime( tm2 ), MSG_INFO); 01833 #endif 01834 #endif 01835 01836 CloseObject(); 01837 01838 //m_needClose = false; 01839 01840 if( !checkOutFiles(to_be_checked_out_containers) ) 01841 { 01842 #ifdef _DEBUG 01843 #if(DETAILS_ABOUT_XMLBACKEND) 01844 time( &time3); 01845 tm3 = localtime( &time3); 01846 01847 double dur = difftime( time3, time1); 01848 char buff[100]; 01849 sprintf( buff, " [Took total of %6.0f secs]", dur ); 01850 01851 if( m_userOpts.m_measureTime) sendMsg( std::string( "CommitAbort ") + asctime( tm3) + buff, MSG_INFO); 01852 #endif 01853 #endif 01854 CloseProgressWindow(); 01855 return E_FAIL; 01856 } 01857 else 01858 { 01859 m_trivialChanges = true; 01860 m_fullLockNeeded = false; 01861 m_createdObjects.clear(); 01862 m_deletedObjects.clear(); 01863 m_modifiedObjects.clear(); 01864 m_undoMap.clear(); 01865 m_inTransaction = false; 01866 01867 #ifdef _DEBUG 01868 #if(DETAILS_ABOUT_XMLBACKEND) 01869 01870 if( m_userOpts.m_createLog) { 01871 //while( -1 != mylog.find( "\r\n")) 01872 //{ 01873 // int p = mylog.find( "\r\n"); 01874 // mylog.replace( p, 2, "<br>"); 01875 //} 01876 if( mylog.size() != 0 && mylog != "<br>") 01877 sendMsg( mylog, MSG_INFO); 01878 mylog.clear(); // clear the log 01879 } 01880 #endif 01881 #endif 01882 //if( m_needClose ) 01883 // m_gme->CloseProject( TRUE ); 01884 01885 #ifdef _DEBUG 01886 #if(DETAILS_ABOUT_XMLBACKEND) 01887 time( &time3); 01888 tm3 = localtime( &time3); 01889 01890 double dur = difftime( time3, time1); 01891 char buff[100]; 01892 sprintf( buff, " [Took total of %6.0f secs]", dur ); 01893 01894 if( m_userOpts.m_measureTime) sendMsg( std::string( "CommitSucce ") + asctime( tm3) + buff, MSG_INFO); 01895 #endif 01896 #endif 01897 m_protectList.onCommited(); 01898 CloseProgressWindow(); 01899 return S_OK; 01900 } 01901 } COMCATCH(CloseProgressWindow();) 01902 } 01903 01904 STDMETHODIMP CCoreXmlFile::AbortTransaction() 01905 { 01906 AFX_MANAGE_STATE(AfxGetStaticModuleState()); 01907 01908 COMTRY { 01909 if( !m_inTransaction ) 01910 COMRETURN(E_INVALID_USAGE); 01911 01912 ASSERT( m_opened ); 01913 01914 // undelete deleted objects 01915 for( XmlObjSetIter it=m_deletedObjects.begin(); it!=m_deletedObjects.end(); ++it ) 01916 (*it)->m_deleted = false; 01917 01918 // delete created objects 01919 int minIndex = m_objects.size(); 01920 for( XmlObjVecIter it2=m_createdObjects.begin(); it2!=m_createdObjects.end(); ++it2 ) 01921 { 01922 XmlObject* obj = *it2; 01923 m_objectsByGUID.erase(obj->m_guid); 01924 if( obj->m_index < minIndex ) 01925 minIndex = obj->m_index; 01926 } 01927 m_objects.resize( minIndex ); 01928 01929 // rollback attributum changes 01930 for( UndoMapIter it3=m_undoMap.begin(); it3!=m_undoMap.end(); ++it3 ) 01931 { 01932 XmlObject * obj = it3->second.m_object; 01933 if( it3->first->getType() == VALTYPE_POINTER ) 01934 { 01935 XmlAttrPointer * pointerAttr = (XmlAttrPointer*)it3->first; 01936 metaobjidpair_type idpair; 01937 CopyTo(it3->second.m_value, idpair); 01938 XmlObject * parent = objectFromObjId(idpair); 01939 setPointer( obj, it3->second.m_attrId, parent ); 01940 } 01941 else 01942 { 01943 it3->first->fromVariant(it3->second.m_value); 01944 } 01945 } 01946 m_protectList.onAborted(); 01947 m_undoMap.clear(); 01948 01949 m_deletedObjects.clear(); 01950 m_createdObjects.clear(); 01951 m_modifiedObjects.clear(); 01952 m_trivialChanges = true; 01953 m_fullLockNeeded = false; 01954 CloseObject(); 01955 m_inTransaction = false; 01956 01957 CloseProgressWindow(); 01958 } COMCATCH(CloseProgressWindow();) 01959 01960 return S_OK; 01961 } 01962 01963 STDMETHODIMP CCoreXmlFile::get_StorageType(long *p) 01964 { 01965 CHECK_OUT(p); 01966 *p = 0; 01967 return S_OK; 01968 } 01969 01970 void CCoreXmlFile::fillParentMap() 01971 { 01972 m_parentMap.clear(); 01973 01974 m_parentMap.insert( ParentMap::value_type( DTID_CONSTRAINT , ATTRID_CONSTROWNER ) ); 01975 m_parentMap.insert( ParentMap::value_type( DTID_REGNODE , ATTRID_REGNOWNER ) ); 01976 m_parentMap.insert( ParentMap::value_type( DTID_FOLDER , ATTRID_PARENT ) ); 01977 m_parentMap.insert( ParentMap::value_type( DTID_MODEL , ATTRID_PARENT ) ); 01978 m_parentMap.insert( ParentMap::value_type( DTID_ATOM , ATTRID_PARENT ) ); 01979 m_parentMap.insert( ParentMap::value_type( DTID_REFERENCE , ATTRID_PARENT ) ); 01980 m_parentMap.insert( ParentMap::value_type( DTID_SET , ATTRID_PARENT ) ); 01981 m_parentMap.insert( ParentMap::value_type( DTID_SETNODE , ATTRID_SETMEMBER ) ); 01982 m_parentMap.insert( ParentMap::value_type( DTID_CONNECTION , ATTRID_PARENT ) ); 01983 m_parentMap.insert( ParentMap::value_type( DTID_CONNROLE , ATTRID_CONNROLE ) ); 01984 m_parentMap.insert( ParentMap::value_type( DTID_CONNROLESEG, ATTRID_CONNSEG ) ); 01985 m_parentMap.insert( ParentMap::value_type( DTID_STRATTR , ATTRID_ATTRPARENT ) ); 01986 m_parentMap.insert( ParentMap::value_type( DTID_INTATTR , ATTRID_ATTRPARENT ) ); 01987 m_parentMap.insert( ParentMap::value_type( DTID_FLOATATTR , ATTRID_ATTRPARENT ) ); 01988 m_parentMap.insert( ParentMap::value_type( DTID_BOOLATTR , ATTRID_ATTRPARENT ) ); 01989 m_parentMap.insert( ParentMap::value_type( DTID_REFATTR , ATTRID_ATTRPARENT ) ); 01990 } 01991 01992 void CCoreXmlFile::closeMetaProject() 01993 { 01994 closeMetaObject(); 01995 CloseProject(); 01996 m_metaProject = NULL; 01997 } 01998 01999 void CCoreXmlFile::openMetaObject() 02000 { 02001 ASSERT( m_metaObject != NULL ); 02002 COMTHROW( m_metaObject->get_MetaID(&m_metaObjectId) ); 02003 } 02004 02005 void CCoreXmlFile::closeMetaObject() 02006 { 02007 CloseObject(); 02008 closeMetaAttribute(); 02009 m_metaObject = NULL; 02010 m_metaObjectId = METAID_NONE; 02011 } 02012 02013 void CCoreXmlFile::openMetaAttribute() 02014 { 02015 ASSERT( m_metaAttribute != NULL ); 02016 COMTHROW( m_metaAttribute->get_AttrID(&m_metaAttributeId) ); 02017 COMTHROW( m_metaAttribute->get_ValueType(&m_metaAttributeValType) ); 02018 02019 if( m_metaAttributeId == ATTRID_NONE ) 02020 HR_THROW(E_METAPROJECT); 02021 } 02022 02023 void CCoreXmlFile::closeMetaAttribute() 02024 { 02025 m_metaAttribute = NULL; 02026 m_metaAttributeId = ATTRID_NONE; 02027 m_metaAttributeValType = VALTYPE_NONE; 02028 } 02029 02030 void CCoreXmlFile::parseConnectionString( BSTR connection ) 02031 { 02032 // connection string format: 02033 // START = PAIRMGX | PAIR2 02034 // PAIR2 = PAIR PAIR2 | empty 02035 // PAIR = KEY '=' VAL 02036 // PAIRMGX = 'MGX=' string 02037 // KEY = string 02038 // VAL = '"' string '"' 02039 // 02040 // valid key values: MGX, 02041 // 02042 // example: 02043 // MGX="C:\temp\test1" vssdatabase="frfre" vsspath="dede" user="fdasfdsfds" password="defrefre" 02044 // MGX="C:\temp\test1" svn="svn://localhost/" 02045 std::string conn; 02046 CopyTo(connection, conn); 02047 const char * connectionString = conn.c_str(); 02048 02049 if( strncmp( connectionString, "MGX=", 4 ) != 0 ) 02050 HR_THROW(E_INVALID_USAGE); 02051 02052 int size = conn.size(); 02053 std::string key; 02054 std::string val; 02055 bool keyCollecting = true; 02056 bool startedValue = false; 02057 02058 m_contentPath = ""; 02059 m_folderPath = ""; 02060 m_svnUrl = ""; 02061 02062 std::string to_hash = ""; 02063 std::string to_hash_with_val = ""; 02064 02065 for( int i=0; i<size; ++i ) 02066 { 02067 char ch = connectionString[i]; 02068 if( keyCollecting ) 02069 { 02070 if( ch == '=' ) 02071 { 02072 keyCollecting = false; 02073 startedValue = false; 02074 val = ""; 02075 } 02076 else 02077 { 02078 if( ch != ' ' && ch != '\t' ) 02079 key += ch; 02080 } 02081 } 02082 else 02083 { 02084 if( startedValue ) 02085 { 02086 if( ch != '\"' ) 02087 val += ch; 02088 else 02089 { 02090 // key-val pair is finished 02091 if( stricmp( key.c_str(), "MGX" ) == 0 ) 02092 m_folderPath = val; 02093 else if( stricmp( key.c_str(), "user" ) == 0 ) 02094 m_vssUser = val; 02095 else if( stricmp( key.c_str(), "password" ) == 0 ) 02096 m_vssPassword = val; 02097 else if( stricmp( key.c_str(), "svn" ) == 0 ) 02098 m_svnUrl = val; 02099 else if( stricmp( key.c_str(), "hash") == 0 ) 02100 to_hash = val; 02101 else if( stricmp( key.c_str(), "hval") == 0 ) 02102 to_hash_with_val = val; 02103 02104 keyCollecting = true; 02105 key = ""; 02106 } 02107 } 02108 else 02109 { 02110 if( ch == '\"' ) 02111 startedValue = true; 02112 02113 } 02114 } 02115 } 02116 02117 if( to_hash == "true") 02118 { 02119 m_contentPath = m_folderPath + "\\" + m_contentConst; 02120 m_hashFileNames = true; 02121 m_hashInfoFound = true; 02122 if( to_hash_with_val == "4096") 02123 m_hashVal = 5; 02124 else if( to_hash_with_val == "256") 02125 m_hashVal = 2; 02126 //else if( to_hash_with_val == "3") 02127 // m_hashVal = 3; 02128 //else if( to_hash_with_val == "4") 02129 // m_hashVal = 4; 02130 else 02131 HR_THROW( E_FILEOPEN); 02132 } 02133 else 02134 m_hashFileNames = false; 02135 } 02136 02137 bool CCoreXmlFile::isUrlSvnSsh() 02138 { 02139 return m_svnUrl.substr( 0, 10) == "svn+ssh://"; 02140 } 02141 02142 std::string CCoreXmlFile::userNameFromSvnSshUrl() 02143 { 02144 size_t at_pos = m_svnUrl.find( '@'); 02145 if( m_svnUrl.substr( 0, 10) == "svn+ssh://" && at_pos > 10 && at_pos != std::string::npos) // uname found 02146 { 02147 return m_svnUrl.substr( 10, at_pos - 10); 02148 } 02149 return ""; 02150 } 02151 02152 void CCoreXmlFile::svnSshHandling() 02153 { 02154 if( m_svnUrl.substr( 0, 10) == "svn+ssh://" && m_svnUrl.find( '@') == std::string::npos) // uname not found 02155 { 02156 if( m_vssUser.empty()) 02157 { 02158 AfxMessageBox( "Could not process further with \"svn+ssh://\" scheme if username is not provided\n\ 02159 either in the Credential Dialog or embedded in the url as \"svn+ssh://username@host.example.com\"."); 02160 HR_THROW( E_UNKNOWN_STORAGE); 02161 } 02162 else 02163 m_svnUrl = std::string( "svn+ssh://") + m_vssUser + "@" + m_svnUrl.substr( 10); 02164 } 02165 } 02166 02167 std::string CCoreXmlFile::svnSshMangling( const std::string& p_url) 02168 { 02169 std::string ret; 02170 size_t at_pos = p_url.find( '@'); 02171 if( p_url.substr( 0, 10) == "svn+ssh://" && at_pos != std::string::npos) // uname found 02172 { 02173 ret = std::string( "svn+ssh://") + p_url.substr( at_pos + 1); 02174 return ret; 02175 } 02176 return p_url; 02177 } 02178 02179 void CCoreXmlFile::svnOptions() 02180 { 02181 if( !m_svnUrl.empty()) 02182 { 02183 if( !m_hashInfoFound) 02184 { 02185 m_hashFileNames = IDYES == AfxMessageBox( "Use hashed subdirectories?", MB_YESNO); 02186 if( m_hashFileNames) 02187 { 02188 m_hashVal = (IDYES == AfxMessageBox( "Does the project have 4096 subdirectories (1+2 digit hashing)?", MB_YESNO))?5:2; 02189 if( m_hashVal == 2) AfxMessageBox( "Defaulting to a project with 256 subdirectories (2 digit hashing).", MB_ICONINFORMATION); 02190 //if( m_hashVal == 2) 02191 //{ 02192 // m_hashVal = (IDYES == AfxMessageBox( "Use 4 digit hashed subdirectories?", MB_YESNO))?4:2; 02193 // if( m_hashVal == 2) 02194 // m_hashVal = (IDYES == AfxMessageBox( "Use 3 digit hashed subdirectories?", MB_YESNO))?3:2; 02195 //} 02196 } 02197 } 02198 } 02199 } 02200 02201 void CCoreXmlFile::setFileNames( bool p_reset /* = false */) 02202 { 02203 char drive[_MAX_DRIVE]; 02204 char dir[_MAX_DIR]; 02205 char fname[_MAX_FNAME]; 02206 char ext[_MAX_EXT]; 02207 02208 // a conn string like 'c:\\t\\v\\p' comes in in m_folderPath 02209 // which is then divided in 'c' as drive, 't\\v' as dir 02210 // and 'p' as fname (although p is a directory) and '' as ext 02211 _splitpath( m_folderPath.c_str(), drive, dir, fname, ext ); 02212 02213 if( p_reset) 02214 { 02215 // m_projectFileName will be reset to a valid .mgx filename 02216 char buf[_MAX_PATH]; 02217 _finddata_t fileInfo; 02218 02219 sprintf( buf, "%s\\*.mgx", m_folderPath.c_str() ); 02220 02221 long searchHandle = _findfirst( buf, &fileInfo ); // findfirst in project dir 02222 long ret = searchHandle; 02223 long count = 0; 02224 while( ret != -1 && ++count) 02225 ret = _findnext( searchHandle, &fileInfo ); // findnext 02226 02227 if( count > 1) 02228 sendMsg( "Multiple .mgx files were found in directory " + m_folderPath, MSG_ERROR); 02229 else if( count == 0) 02230 sendMsg( "No .mgx file was found in directory " + m_folderPath, MSG_ERROR); 02231 else 02232 { 02233 // new m_projectFileName value set, a real one 02234 m_projectFileName = m_folderPath; 02235 m_projectFileName += "\\"; 02236 m_projectFileName += fileInfo.name; // m_projectName or m_vssPath or m_parentFolderPath do NOT change 02237 02238 sendMsg( "Loading project file: " + m_projectFileName, MSG_INFO); 02239 _findclose( searchHandle ); 02240 } 02241 return; 02242 } 02243 02244 m_parentFolderPath = drive; 02245 m_parentFolderPath += dir; 02246 if( m_parentFolderPath[m_parentFolderPath.size()-1] == '\\' ) 02247 m_parentFolderPath.resize(m_parentFolderPath.size()-1); 02248 02249 // this is the name of the project directory : 'p' in the example above 02250 m_projectName = fname; 02251 02252 m_cacheFileName = m_folderPath + "\\project.bin"; 02253 02254 // the name of the project file siting in the project dir: 'c:\\t\\u\\p\\project.mgx' 02255 m_projectFileName = m_folderPath + "\\project.mgx"; 02256 02257 m_vssPath = m_vssParentPath; 02258 m_vssPath += "/"; 02259 m_vssPath += m_projectName; 02260 } 02261 02262 void CCoreXmlFile::getContainerFileName(XmlObject * obj, std::string& str, bool fullpath) 02263 { 02264 ASSERT( obj->isContainer() ); 02265 02266 std::string guidStr; 02267 guid2str( obj->m_guid, guidStr ); 02268 02269 if( fullpath ) 02270 { 02271 str = m_folderPath; 02272 str += "\\"; 02273 } 02274 else 02275 str = ""; 02276 02277 if( m_hashFileNames && obj->m_metaid != METAID_ROOT) // hashing not applied for the root folder 02278 { 02279 str += m_contentConst; 02280 str += "\\"; 02281 if( m_hashVal == 5) // 1+2 setup 02282 { 02283 str += guidStr.substr( 0, 1); 02284 str += "\\"; 02285 str += guidStr.substr( 1, 2); 02286 str += "\\"; 02287 } 02288 else if( m_hashVal == 2) 02289 { 02290 str += guidStr.substr( 0, 2); 02291 str += "\\"; 02292 } 02293 else if( m_hashVal == 3) 02294 { 02295 str += guidStr.substr( 0, 1) + "\\" + guidStr.substr( 1, 1) + "\\" + guidStr.substr( 2, 1) + "\\"; 02296 } 02297 else if( m_hashVal == 4) 02298 { 02299 str += guidStr.substr( 0, 1) + "\\" + guidStr.substr( 1, 1) + "\\" + guidStr.substr( 2, 1) + "\\" + guidStr.substr( 3, 1) + "\\"; 02300 } 02301 //str += guidStr.substr( 0, 2); 02302 //str += "\\"; 02303 } 02304 02305 str += guidStr; 02306 str += ".xml"; 02307 } 02308 02309 void CCoreXmlFile::getContainerName(XmlObject * obj, string& name, string& type) 02310 { 02311 CComObjPtr<ICoreMetaObject> metaobject; 02312 CComBSTR metaToken; 02313 02314 COMTHROW( m_metaProject->get_Object( obj->m_metaid, PutOut(metaobject) ) ); 02315 COMTHROW( metaobject->get_Token( &metaToken ) ); 02316 02317 CopyTo(metaToken, type); 02318 02319 name = ""; 02320 AttribMapIter it; 02321 for( it=obj->m_attributes.begin(); it!=obj->m_attributes.end(); ++it ) 02322 { 02323 XmlAttrBase * attr = it->second; 02324 CComObjPtr<ICoreMetaAttribute> metaAttrib; 02325 CComBSTR attribToken; 02326 string attribToken2; 02327 string attrVal; 02328 02329 COMTHROW( metaobject->get_Attribute( it->first, PutOut(metaAttrib) ) ); 02330 metaAttrib->get_Token( &attribToken ); 02331 02332 CopyTo(attribToken, attribToken2); 02333 02334 if( stricmp( attribToken2.c_str(), "name" ) == 0 && attr->getType() == VALTYPE_STRING ) 02335 { 02336 XmlAttrBase * attr = it->second; 02337 attr->toString(name); 02338 break; 02339 } 02340 } 02341 } 02342 02343 // method used to clear all objects before a new attempt to read a project. 02344 // it is used by ~CCoreXmlFile, or ::CloseProject also. 02345 void CCoreXmlFile::clearAll() 02346 { 02347 for( XmlObjVecIter i=m_objects.begin(); i!=m_objects.end(); ++i ) 02348 delete (*i); 02349 m_objects.clear(); 02350 m_objectsByGUID.clear(); 02351 m_openedObject = NULL; 02352 m_root = NULL; 02353 } 02354 02355 void CCoreXmlFile::addObject(XmlObject * obj) 02356 { 02357 obj->m_index = m_objects.size(); 02358 m_objects.push_back( obj ); 02359 m_objectsByGUID.insert( GUIDToXmlObjectMap::value_type( obj->m_guid, obj ) ); 02360 } 02361 02362 void CCoreXmlFile::deleteObject(XmlObject * obj) 02363 { 02364 // remove pointers 02365 for(AttribMapIter it=obj->m_attributes.begin(); it!=obj->m_attributes.end(); ++it) 02366 { 02367 if( it->second->getType() == VALTYPE_POINTER ) 02368 { 02369 // remove it from parent object's collection 02370 XmlAttrPointer * pointer = (XmlAttrPointer*)it->second; 02371 if( pointer->m_parent != NULL ) 02372 { 02373 AttribMapIter it2 = pointer->m_parent->m_attributes.find( it->first + ATTRID_COLLECTION ); 02374 ASSERT( it2 != pointer->m_parent->m_attributes.end() ); 02375 ASSERT( it2->second->getType() == VALTYPE_COLLECTION ); 02376 ((XmlAttrCollection*)it2->second)->m_children.erase(obj); 02377 } 02378 } 02379 else if( it->second->getType() == VALTYPE_COLLECTION ) 02380 { 02381 XmlAttrCollection * collection = (XmlAttrCollection*)it->second; 02382 for( XmlObjSetIter it2=collection->m_children.begin(); it2!=collection->m_children.end(); ++it2 ) 02383 { 02384 // set parent of this child to NULL 02385 XmlObject * obj2 = (*it2); 02386 AttribMapIter it3 = obj2->m_attributes.find( it->first - ATTRID_COLLECTION ); 02387 ASSERT( it3 != obj2->m_attributes.end() ); 02388 ASSERT( it3->second->getType() == VALTYPE_POINTER ); 02389 ((XmlAttrPointer *)(it3->second))->m_parent = NULL; 02390 } 02391 } 02392 } 02393 02394 obj->m_deleted = true; 02395 } 02396 02397 void CCoreXmlFile::setPointer(XmlObject * obj, attrid_type attribId, XmlObject * parent) 02398 { 02399 ASSERT( obj!=NULL ); 02400 02401 AttribMapIter it = obj->m_attributes.find(attribId); 02402 ASSERT( it!=obj->m_attributes.end() ); 02403 02404 XmlAttrPointer * attr = (XmlAttrPointer*)it->second; 02405 02406 // remove item from old parent's list 02407 if( attr->m_parent != NULL ) 02408 { 02409 // find collection attribute of parent 02410 AttribMapIter it2 = attr->m_parent->m_attributes.find( attribId + ATTRID_COLLECTION ); 02411 ASSERT( it2 != attr->m_parent->m_attributes.end() ); 02412 ASSERT( it2->second->getType() == VALTYPE_COLLECTION ); 02413 02414 // remove this form the list 02415 ((XmlAttrCollection *)it2->second)->m_children.erase(obj); 02416 } 02417 02418 // set pointer attribute 02419 attr->m_parent = parent; 02420 02421 // add item to new parent's list 02422 if( parent != NULL ) 02423 { 02424 AttribMapIter it3 = parent->m_attributes.find( attribId + ATTRID_COLLECTION ); 02425 ASSERT( it3 != parent->m_attributes.end() ); 02426 ASSERT( it3->second->getType() == VALTYPE_COLLECTION ); 02427 ((XmlAttrCollection *)it3->second)->m_children.insert(obj); 02428 } 02429 } 02430 02431 XmlObject * CCoreXmlFile::setPointer(VARIANT p) 02432 { 02433 metaobjidpair_type idpair; 02434 CopyTo(p, idpair); 02435 XmlObject * parent = objectFromObjId(idpair); 02436 setPointer( m_openedObject, m_metaAttributeId, parent ); 02437 return parent; 02438 } 02439 02440 void CCoreXmlFile::updateCollections() 02441 { 02442 for( XmlObjVecIter it=m_objects.begin(); it!=m_objects.end(); ++it ) 02443 { 02444 XmlObject * obj = (*it); 02445 for( AttribMapIter j=obj->m_attributes.begin(); j!=obj->m_attributes.end(); ++j) 02446 { 02447 if( j->second->getType() == VALTYPE_POINTER ) 02448 { 02449 XmlAttrPointer * pointer = (XmlAttrPointer*)j->second; 02450 if( pointer->m_parent != NULL ) 02451 { 02452 AttribMapIter k = pointer->m_parent->m_attributes.find( j->first + ATTRID_COLLECTION ); 02453 ASSERT( k != pointer->m_parent->m_attributes.end() ); 02454 ((XmlAttrCollection*)k->second)->m_children.insert( obj ); 02455 } 02456 } 02457 } 02458 } 02459 } 02460 02461 void CCoreXmlFile::resolvePointers(UnresolvedPointerVec& pointers) 02462 { 02463 #ifdef DEBUG 02464 #if(RESOLVE_PTRS_2ND_ATTEMPT) 02465 UnresolvedPointerVec again_unresolved; 02466 #endif 02467 #endif 02468 02469 for( UnresolvedPointerVecIt it=pointers.begin(); it!=pointers.end(); ++it ) 02470 { 02471 if( it->m_pointedObjGuid == GUID_NULL ) 02472 { 02473 setPointer( it->m_object, it->m_attrib, NULL ); 02474 } 02475 else 02476 { 02477 GUIDToXmlObjectMapIter it2 = m_objectsByGUID.find( it->m_pointedObjGuid ); 02478 if( it2 != m_objectsByGUID.end() ) 02479 { 02480 setPointer( it->m_object, it->m_attrib, it2->second ); 02481 } 02482 else 02483 { 02484 // TODO: invalid pointer, what to do? 02485 #ifdef DEBUG 02486 #if(RESOLVE_PTRS_2ND_ATTEMPT) 02487 again_unresolved.push_back( *it); 02488 #endif 02489 #endif 02490 } 02491 } 02492 } 02493 02494 // analyze unresolved pointers in debug mode: 02495 #ifdef DEBUG 02496 #if(RESOLVE_PTRS_2ND_ATTEMPT) 02497 int still_unresolved = again_unresolved.size(); 02498 ASSERT( still_unresolved == 0); // notify user!!! 02499 02500 for( UnresolvedPointerVecIt it=again_unresolved.begin(); it!=again_unresolved.end(); ++it ) 02501 { 02502 int k = 0; 02503 ++k; 02504 if( it->m_object->m_metaid == DTID_CONNROLE && it->m_attrib == ATTRID_FCOREFATTR) // XREF, 525 02505 { 02506 // connEnd can't be resolved 02507 // find the connection it belongs to -> simply find its parent 02508 XmlObject * obj = it->m_object; int l = 0; 02509 while( obj != 0 && (obj->m_metaid != DTID_CONNECTION || obj->m_metaid == DTID_MODEL || obj->m_metaid == DTID_FOLDER)) 02510 { 02511 ParentMap::iterator it1 = m_parentMap.find( obj->m_metaid ); 02512 ASSERT( it1 != m_parentMap.end() ); 02513 AttribMapIter it2 = obj->m_attributes.find( it1->second ); 02514 ASSERT( it2 != obj->m_attributes.end() ); 02515 obj = ((XmlAttrPointer*)(it2->second))->m_parent; 02516 ++l; 02517 } 02518 ASSERT( l == 1); 02519 02520 if( obj != 0 && obj->m_metaid == DTID_CONNECTION) // OK 02521 { 02522 int k = 0; 02523 ++k; 02524 AttribMapIter pit = obj->m_attributes.find( ATTRID_PARENT); 02525 ASSERT( pit != obj->m_attributes.end()); 02526 XmlObject * parent = ((XmlAttrPointer*)(pit->second))->m_parent; 02527 // delete it: set its parent to 0 02528 ASSERT(0); // notify user 02529 setPointer( obj, ATTRID_PARENT, 0); 02530 } 02531 } 02532 02533 if( it->m_object->m_metaid == DTID_CONNROLESEG && it->m_attrib == ATTRID_SEGREF) // 511 02534 { 02535 XmlObject * obj = it->m_object; int l = 0; 02536 while( obj != 0 && (obj->m_metaid != DTID_CONNECTION || obj->m_metaid == DTID_MODEL || obj->m_metaid == DTID_FOLDER)) 02537 { 02538 ParentMap::iterator it1 = m_parentMap.find( obj->m_metaid ); 02539 ASSERT( it1 != m_parentMap.end() ); 02540 AttribMapIter it2 = obj->m_attributes.find( it1->second ); 02541 ASSERT( it2 != obj->m_attributes.end() ); 02542 obj = ((XmlAttrPointer*)(it2->second))->m_parent; 02543 ++l; 02544 } 02545 ASSERT( l == 2); 02546 02547 if( obj != 0 && obj->m_metaid == DTID_CONNECTION) // OK 02548 { 02549 int k = 0; 02550 ++k; 02551 // delete it: set its parent to 0 02552 ASSERT(0); // notify user 02553 setPointer( obj, ATTRID_PARENT, 0); 02554 } 02555 } 02556 02557 if( it->m_object->m_metaid == DTID_REFERENCE && it->m_attrib == ATTRID_REFERENCE) // 505 02558 { 02559 // referred object is not found 02560 int k = 0; 02561 ++k; 02562 ASSERT(0); // notify user 02563 // involved connections may have existed... :( 02564 } 02565 if( it->m_attrib == ATTRID_PARENT) // 602 02566 { 02567 // a child Y may have been lost its parent X, when another user deleted model X, not knowing 02568 // that it has a Y child also 02569 // this refers to the case when children are added without locking parent (when not used ATTRID_LASTRELID) 02570 int k = 0; 02571 ++k; 02572 ASSERT(0); // notify user 02573 } 02574 } 02575 #endif 02576 #endif 02577 } 02578 02579 void CCoreXmlFile::resetSourceControlInfo( XmlObject * obj) 02580 { 02581 ASSERT( obj->m_metaid==DTID_MODEL || obj->m_metaid==DTID_FOLDER ); 02582 02583 // set FILESTATUS attributes 02584 AttribMapIter fsit = obj->m_attributes.find( ATTRID_FILESTATUS ); 02585 if( obj->m_attributes.end() != fsit) 02586 { 02587 XmlAttrLong * along = (XmlAttrLong*) fsit->second; 02588 along->m_value &= 0xFFFFFF00; // clear my bits (the lowest byte) 02589 } 02590 } 02591 02592 void CCoreXmlFile::resetSourceControlForAll() 02593 { 02594 // collect containers 02595 XmlObjVec containers; 02596 for( XmlObjVecIter it=m_objects.begin(); it!=m_objects.end(); ++it ) 02597 { 02598 XmlObject * obj = (*it); 02599 02600 if( obj->m_metaid==DTID_MODEL || obj->m_metaid==DTID_FOLDER ) 02601 containers.push_back( obj ); 02602 } 02603 02604 for( XmlObjVecIter it=containers.begin(); it!=containers.end(); ++it ) 02605 { 02606 resetSourceControlInfo( *it ); 02607 resetSourceControlStat( *it, false ); 02608 } 02609 } 02610 02611 void CCoreXmlFile::resetSourceControlStat(XmlObject * obj, bool p_freshObj) 02612 { 02613 ASSERT( obj->m_metaid==DTID_MODEL || obj->m_metaid==DTID_FOLDER ); 02614 02615 // set FILESTATUS attributes 02616 AttribMapIter fsit = obj->m_attributes.find( ATTRID_FILESTATUS ); 02617 if( obj->m_attributes.end() != fsit) 02618 { 02619 XmlAttrLong * along = (XmlAttrLong*) fsit->second; 02620 along->m_value &= 0xFFFF00FF; // clear my flags (the 2nd byte) 02621 02622 // new objects get special status, 02623 // otherwise the default is 0 (only for the 2nd byte) 02624 int l = 1; 02625 l |= p_freshObj ? 4:8; 02626 along->m_value |= ( p_freshObj ? FS_NOTYETSAVED : 0x0); 02627 } 02628 } 02629 02630 void CCoreXmlFile::getPointer(XmlAttrPointer * attr, VARIANT * p) 02631 { 02632 ASSERT( attr!= NULL ); 02633 metaobjidpair_type id; 02634 objIdFromObject( attr->m_parent, id ); 02635 CopyTo(id, p); 02636 } 02637 02638 void CCoreXmlFile::getCollection(XmlAttrCollection * attr, VARIANT * p) 02639 { 02640 ASSERT( attr!= NULL ); 02641 std::vector<metaobjidpair_type> idpairs; 02642 for( XmlObjSetIter it = attr->m_children.begin(); it != attr->m_children.end(); ++it ) 02643 { 02644 metaobjidpair_type id; 02645 objIdFromObject( *it, id ); 02646 idpairs.push_back( id ); 02647 } 02648 CopyTo(idpairs, p); 02649 } 02650 02651 // TODO: test! 02652 XmlObject * CCoreXmlFile::getContainer(XmlObject * obj) 02653 { 02654 ASSERT( obj != NULL ); 02655 XmlObject * container = obj; 02656 while( container!=NULL && !container->isContainer() ) 02657 { 02658 ParentMap::iterator it = m_parentMap.find( container->m_metaid ); 02659 ASSERT( it != m_parentMap.end() ); 02660 AttribMapIter it2 = container->m_attributes.find( it->second ); 02661 ASSERT( it2 != container->m_attributes.end() ); 02662 container = ((XmlAttrPointer*)(it2->second))->m_parent; 02663 } 02664 return container; 02665 } 02666 02667 // TODO: test! 02668 void CCoreXmlFile::getContainedObjects(XmlObject * obj, XmlObjVec& vec) 02669 { 02670 ASSERT( obj != NULL ); 02671 vec.push_back(obj); 02672 02673 for(AttribMapIter it=obj->m_attributes.begin(); it!=obj->m_attributes.end(); ++it) 02674 { 02675 if( it->second->getType() == VALTYPE_COLLECTION ) 02676 { 02677 XmlAttrCollection * coll = (XmlAttrCollection *)it->second; 02678 for( XmlObjSetIter it2=coll->m_children.begin(); it2!=coll->m_children.end(); ++it2 ) 02679 { 02680 XmlObject * obj2 = (*it2); 02681 if( obj2->m_metaid != DTID_MODEL && obj2->m_metaid != DTID_FOLDER ) 02682 { 02683 ParentMap::iterator it3 = m_parentMap.find( obj2->m_metaid ); 02684 ASSERT( it3 != m_parentMap.end() ); 02685 if( it3->first + ATTRID_COLLECTION == it->first ) 02686 getContainedObjects(obj2,vec); 02687 } 02688 } 02689 } 02690 } 02691 } 02692 02693 void CCoreXmlFile::getMyDepObjConts( XmlObjSet& objects, XmlObjSet& containers, bool thorough) 02694 { 02695 XmlObjSet processedObjects; 02696 for( XmlObjSetIter it=objects.begin(); it!=objects.end(); ++it ) 02697 getMyDepObj( *it, containers, processedObjects, thorough ); 02698 02699 for( XmlObjSetIter jt = processedObjects.begin(); jt != processedObjects.end(); ++jt) 02700 { 02701 XmlObject * cont = getContainer( *jt); 02702 //ASSERT( cont); 02703 // cont can be 0, e.g. if an reference object is deleted, so its parent becomes 0, 02704 // then its ATTR_REF pointer is set to 0, that's why end up in this method 02705 if( cont && containers.find( cont) == containers.end()) // not inserted yet 02706 containers.insert( cont); 02707 } 02708 } 02709 02710 void CCoreXmlFile::getMyDepObj(XmlObject * obj, XmlObjSet& containers, XmlObjSet& processedObjects, bool thorough) 02711 { 02712 if( obj!= NULL && processedObjects.find(obj)==processedObjects.end() ) // not processed yet 02713 { 02714 processedObjects.insert(obj); 02715 XmlObject * container = obj;//getContainer(obj); 02716 if( container != NULL ) 02717 { 02718 //containers.insert( container ); 02719 for(AttribMapIter it=container->m_attributes.begin(); thorough && it!=container->m_attributes.end(); ++it) 02720 { 02721 attrid_type at = it->first; 02722 02723 // go through the collections only if non-trivial changes happened 02724 // 02725 // for a generic fco these collections are: 02726 //CREATE_COLLECTION(ATTRID_CONSTROWNER, "Constraints", "Constraints"); 02727 //CREATE_COLLECTION(ATTRID_REGNOWNER, "RegNodes", "Registry Nodes"); 02728 //CREATE_COLLECTION(ATTRID_ATTRPARENT,"Attributes", "Attributes"); 02729 //CREATE_COLLECTION(ATTRID_REFERENCE, "References", "Referenced by"); 02730 //CREATE_COLLECTION(ATTRID_XREF, "XReferences", "Cross refs"); 02731 //CREATE_COLLECTION(ATTRID_DERIVED, "SubTypes", "SubTypes/Instances"); 02732 // 02733 // for a MODEL additonal collection is: 02734 //CREATE_COLLECTION(ATTRID_PARENT, "Children", "Child Objects"); 02735 // 02736 // for a REFERENCE additional collection is: 02737 //CREATE_COLLECTION(ATTRID_SEGREF, "Segments", "Connection Segments"); 02738 //CREATE_COLLECTION(ATTRID_MASTEROBJ, "MasterOf", "Master Of Objects"); 02739 // 02740 // for a SET is 02741 //CREATE_COLLECTION(ATTRID_SETMEMBER, "Members", "Set Members"); 02742 02743 if( at == ATTRID_PARENT + ATTRID_COLLECTION) { } // this time children disregarded 02744 else if( at == ATTRID_CONSTROWNER + ATTRID_COLLECTION) { } 02745 else if( at == ATTRID_REGNOWNER + ATTRID_COLLECTION) { } 02746 else if( at == ATTRID_ATTRPARENT + ATTRID_COLLECTION) { } 02747 else 02748 if( it->second->getType() == VALTYPE_COLLECTION) 02749 { 02750 // XREF, DERIVED, REFERENCE, SEGREF, MASTEROBJ, SETMEMBER 02751 XmlAttrCollection * coll = (XmlAttrCollection*)it->second; 02752 for( XmlObjSetIter it2=coll->m_children.begin(); it2!=coll->m_children.end(); ++it2 ) 02753 { 02754 XmlObject * obj2 = (*it2); 02755 if( obj2 != NULL ) 02756 getMyDepObj( obj2, containers, processedObjects, thorough ); 02757 } 02758 } 02759 } 02760 } 02761 } 02762 } 02763 02764 void CCoreXmlFile::getBasesOfObj( XmlObject * obj, XmlObjSet& containers) 02765 { 02766 if( obj!= NULL) 02767 { 02768 if( obj->m_metaid == DTID_MODEL && containers.find( obj) == containers.end()) 02769 containers.insert( obj); 02770 02771 AttribMapIter derattr = obj->m_attributes.find( ATTRID_DERIVED); 02772 if( derattr != obj->m_attributes.end()) 02773 { 02774 XmlObject * base = ((XmlAttrPointer*)(derattr->second))->m_parent; 02775 if( base) 02776 { 02777 getBasesOfObj( base, containers); 02778 } 02779 } 02780 } 02781 } 02782 02783 void CCoreXmlFile::getBasesOf( XmlObjSet& objects, XmlObjSet& containers) 02784 { 02785 // collect baseobj, base of baseobj, ... 02786 for( XmlObjSetIter it=objects.begin(); it!=objects.end(); ++it ) 02787 getBasesOfObj( *it, containers); 02788 } 02789 02790 void CCoreXmlFile::getDeriveds( XmlObject * obj, XmlObjSet& containers) 02791 { 02792 if( obj!= NULL) 02793 { 02794 for(AttribMapIter it=obj->m_attributes.begin(); it!=obj->m_attributes.end(); ++it) 02795 { 02796 attrid_type at = it->first; 02797 valtype_type vt = it->second->getType(); 02798 02799 if( at == ATTRID_DERIVED + ATTRID_COLLECTION && it->second->getType() == VALTYPE_COLLECTION) // all deriveds 02800 { 02801 XmlAttrCollection * coll = (XmlAttrCollection*)it->second; 02802 for( XmlObjSetIter it2=coll->m_children.begin(); it2!=coll->m_children.end(); ++it2 ) 02803 { 02804 XmlObject * obj2 = (*it2); 02805 if( obj2 != NULL && obj2->m_metaid == DTID_MODEL) // folders cannot be derived 02806 { 02807 if( obj2->m_metaid == DTID_MODEL && containers.find( obj2) == containers.end()) 02808 containers.insert( obj2); 02809 getDeriveds( obj2, containers); // find deriveds from deriveds also 02810 } 02811 } 02812 } 02813 } 02814 } 02815 } 02816 02817 void CCoreXmlFile::getAllUpAndDown( XmlObjSet& objects, XmlObjSet& containers) 02818 { 02819 // first go up 02820 // let's not go up 02821 // we don't go up anymore 02822 for( XmlObjSetIter it=objects.begin(); 0 && it!=objects.end(); ++it ) 02823 { 02824 XmlObject * iobj = *it; 02825 XmlObject * cont = 0; 02826 AttribMapIter ait; 02827 while( iobj) 02828 { 02829 ait = iobj->m_attributes.find( ATTRID_PARENT ); 02830 ASSERT( ait != iobj->m_attributes.end() ); 02831 cont = ((XmlAttrPointer*)(ait->second))->m_parent; 02832 02833 if( cont && cont->m_metaid == DTID_MODEL) 02834 { 02835 if( cont && containers.find( cont) == containers.end()) // not inserted yet 02836 containers.insert( cont); 02837 iobj = cont; 02838 } 02839 else // 0 or DTID_FOLDER 02840 iobj = 0; 02841 } 02842 } 02843 02844 // then go down 02845 for( XmlObjSetIter it=objects.begin(); it!=objects.end(); ++it ) 02846 getAllTheWayDown( *it, containers); 02847 } 02848 02849 void CCoreXmlFile::getAllTheWayDown( XmlObject * obj, XmlObjSet& containers) 02850 { 02851 if( obj!= NULL) 02852 { 02853 if( obj->m_metaid == DTID_MODEL && containers.find( obj) == containers.end()) 02854 containers.insert( obj); 02855 for(AttribMapIter it=obj->m_attributes.begin(); it!=obj->m_attributes.end(); ++it) 02856 { 02857 attrid_type at = it->first; 02858 valtype_type vt = it->second->getType(); 02859 02860 if( at == ATTRID_PARENT + ATTRID_COLLECTION && it->second->getType() == VALTYPE_COLLECTION)// children 02861 { 02862 XmlAttrCollection * coll = (XmlAttrCollection*)it->second; 02863 for( XmlObjSetIter it2=coll->m_children.begin(); it2!=coll->m_children.end(); ++it2 ) 02864 { 02865 XmlObject * obj2 = (*it2); 02866 if( obj2 != NULL && ( obj2->m_metaid == DTID_MODEL || obj2->m_metaid == DTID_FOLDER)) 02867 getAllTheWayDown( obj2, containers); 02868 } 02869 } 02870 } 02871 } 02872 } 02873 02874 void CCoreXmlFile::getCheckOutContainers(XmlObjSet& objects, XmlObjSet& containers, bool thorough) 02875 { 02876 XmlObjSet processedObjects; 02877 for( XmlObjSetIter it=objects.begin(); it!=objects.end(); ++it ) 02878 getDependentContainers( *it, containers, processedObjects, thorough ); 02879 } 02880 02881 void CCoreXmlFile::getDependentContainers(XmlObject * obj, XmlObjSet& containers, XmlObjSet& processedObjects, bool thorough) 02882 { 02883 if( obj!= NULL && processedObjects.find(obj)==processedObjects.end() ) // not processed yet 02884 { 02885 processedObjects.insert(obj); 02886 XmlObject * container = getContainer(obj); 02887 if( container != NULL ) 02888 { 02889 // TODO: to be though over thoroughly. E.g. if there is deletion 02890 // do the attributes change in such an order, that not all containers get into 02891 // the list (as the relationships cease to exist we lose the chance to find 02892 // the container) 02893 // Do we need to store the container??? Think about it! 02894 containers.insert( container ); 02895 for(AttribMapIter it=container->m_attributes.begin(); (m_userOpts.m_alwaysFullLock || m_fullLockNeeded || thorough) && it!=container->m_attributes.end(); ++it) 02896 { 02897 attrid_type at = it->first; 02898 valtype_type vt = it->second->getType(); 02899 02900 // this optimizes it: 02901 if( at == ATTRID_CONSTROWNER + ATTRID_COLLECTION) { } // no need for all of these 02902 else if( at == ATTRID_REGNOWNER + ATTRID_COLLECTION) { } 02903 else if( at == ATTRID_ATTRPARENT + ATTRID_COLLECTION) { } 02904 else if( it->second->getType() == VALTYPE_COLLECTION) // go through the collections 02905 { 02906 XmlAttrCollection * coll = (XmlAttrCollection*)it->second; 02907 for( XmlObjSetIter it2=coll->m_children.begin(); it2!=coll->m_children.end(); ++it2 ) 02908 { 02909 XmlObject * obj2 = (*it2); 02910 if( obj2 != NULL ) 02911 getDependentContainers( obj2, containers, processedObjects ); 02912 } 02913 } 02914 } 02915 } 02916 } 02917 } 02918 02919 /* 02920 Ask user if files need to be checked out. 02921 02922 Returns true if all the files has been checked out successfully. 02923 */ 02924 bool CCoreXmlFile::checkOutFiles(XmlObjSet& containers) 02925 { 02926 AFX_MANAGE_STATE(AfxGetStaticModuleState( )); 02927 02928 if( containers.size() == 0 ) 02929 return true; 02930 02931 #ifdef _DEBUG 02932 #if(DETAILS_ABOUT_XMLBACKEND) 02933 char buff[329]; 02934 sprintf( buff, " ..--== size[ModifiedObjects] = %i, size[checkOutContainers] = %i ==--..", m_modifiedObjects.size(), containers.size()); 02935 sendMsg( buff, MSG_INFO); 02936 #endif 02937 #endif 02938 02939 // PETER - SVNSPEEDHACK BEGIN 02940 if( m_sourceControl == SC_SUBVERSION) { 02941 XmlObjSetIter it; 02942 std::vector< std::string> readOnlyFiles; 02943 02944 for( it=containers.begin(); it!=containers.end(); ++it ) { 02945 if( isContainerReadOnly(*it) ){ 02946 string fileName; 02947 getContainerFileName( *it, fileName, true ); 02948 readOnlyFiles.push_back( fileName ); 02949 } 02950 } 02951 02952 if (readOnlyFiles.empty()) { 02953 return true; 02954 } 02955 02956 std::string msg; 02957 bool succ = m_svn->speedLock(readOnlyFiles, msg); 02958 02959 if (succ) { 02960 return true; 02961 } 02962 else { 02963 sendMsg( "Could not check out all files needed to complete operation.", MSG_ERROR); 02964 sendMsg( msg, MSG_INFO); 02965 sendMsg( "Rollback follows.", MSG_INFO); 02966 return false; 02967 } 02968 } 02969 // PETER - SVNSPEEDHACK END 02970 02971 XmlObjSetIter it; 02972 XmlObjSet containersUsedByOthers; 02973 02974 // count the files need to be checked out 02975 XmlObjSet readOnlyFiles; 02976 bool checkdOutByOthers = false; 02977 for( it=containers.begin(); it!=containers.end(); ++it ) 02978 { 02979 XmlObject * obj = *it; 02980 ASSERT( obj != NULL ); 02981 02982 if( isContainerReadOnly(obj) ) 02983 { 02984 readOnlyFiles.insert( obj ); 02985 if( m_sourceControl != SC_NONE ) 02986 { 02987 // check if checked out by other users 02988 if( isContinerCheckedOut( obj ) ) 02989 { 02990 containersUsedByOthers.insert( obj ); 02991 checkdOutByOthers = true; 02992 } 02993 } 02994 } 02995 } 02996 02997 if( readOnlyFiles.size() == 0 ) 02998 return true; 02999 03000 // if there is no source control nothing we can do, notify the user and roll back transaction 03001 if( m_sourceControl == SC_NONE ) 03002 { 03003 AfxMessageBox( "Cannot perform this operation because some read only files need modification. Maybe the project is under source control. Try to open it again and login to the source control database!" ); 03004 return false; 03005 } 03006 03007 // if there are files checkd out by other we are done, roll back transaction 03008 if( checkdOutByOthers ) 03009 { 03010 CFilesInUseDlg dlg; // plain dlg 03011 if( dlg.DoModal() == IDOK ) 03012 showUsedFiles( containersUsedByOthers ); 03013 return false; 03014 } 03015 03016 // ask user for check out confirmation 03017 if( m_userOpts.m_defCheckOutOnAction || AfxMessageBox( "To perform this operation some files will be checked out. Do you want to continue?", MB_YESNO ) == IDYES ) 03018 { 03019 if( m_userOpts.m_defCheckOutOnAction) 03020 sendMsg( std::string( "ACCELERATION: Files checked out automatically based on policy configured."), MSG_INFO); 03021 03022 // don't create a mess by checking out modifications done by others 03023 // commented by zolmol 03024 //getLatestVersion(); 03025 03026 XmlObjSet latent_files; 03027 bool needClose = filesModifiedByOthersV3( readOnlyFiles, latent_files); 03028 if( needClose) 03029 { 03030 //sendMsg( "This part of the project has been modified by other users, it is highly recomended to close and reopen your project to synchronize it!", MSG_ERROR ); 03031 //sendMsg( "Precise conflict, big chance of overlapping modifications. Not allowed!", MSG_ERROR ); 03032 sendMsg( "Update with save operation by other users changed this part of the project. Your changes are not allowed unless you close and reopen the project!", MSG_ERROR ); 03033 03034 CFilesInUseDlg dlg( 0, true); // dlg with latent msg 03035 if( dlg.DoModal() == IDOK ) 03036 showUsedFiles( latent_files, true ); 03037 return false; 03038 } 03039 03040 03041 // check out files 03042 try 03043 { 03044 for( it=readOnlyFiles.begin(); it!=readOnlyFiles.end(); ++it ) 03045 checkOutContainer( *it ); 03046 03047 } 03048 catch(...) 03049 { 03050 // couldn't checkout all things, what's next? 03051 // undocheckout or checkoutrollback needed for those which succesfully were checkedout 03052 // roll back transaction, and notify user about what happened 03053 sendMsg( "Could not check out all files needed to complete operation.", MSG_ERROR); 03054 sendMsg( "Rollback follows.", MSG_INFO); 03055 03056 for( it=readOnlyFiles.begin(); it!=readOnlyFiles.end(); ++it ) 03057 rollBackTheCheckOutContainer( *it ); // it has a try catch block inside, thus it is safe 03058 03059 sendMsg( "Rollback finished. See details above.", MSG_INFO); 03060 return false; 03061 } 03062 03063 03064 return true; 03065 } 03066 else 03067 return false; 03068 } 03069 03070 XmlObject * CCoreXmlFile::objectFromObjId(metaobjidpair_type idpair) 03071 { 03072 if( idpair.metaid == METAID_NONE && idpair.objid == OBJID_NONE ) 03073 return NULL; 03074 03075 if( idpair.metaid == METAID_ROOT ) 03076 return m_root; 03077 else 03078 return (XmlObject*)idpair.objid; 03079 } 03080 03081 void CCoreXmlFile::objIdFromObject(XmlObject * obj, metaobjidpair_type& idpair) 03082 { 03083 if( obj == NULL ) 03084 { 03085 idpair.metaid = METAID_NONE; 03086 idpair.objid = OBJID_NONE; 03087 } 03088 else 03089 { 03090 idpair.metaid = obj->m_metaid; 03091 if( idpair.metaid == METAID_ROOT ) 03092 idpair.objid = 1; 03093 else 03094 idpair.objid = (long)obj; // pointer to long conversion, is a truncation on 64bit systems 03095 } 03096 } 03097 03098 void CCoreXmlFile::timestampOfCache( FILETIME* p_fTime) 03099 { 03100 WIN32_FILE_ATTRIBUTE_DATA attr; 03101 if( GetFileAttributesEx( m_cacheFileName.c_str(), GetFileExInfoStandard, &attr ) ) 03102 { 03103 *p_fTime = attr.ftLastWriteTime; 03104 } 03105 } 03106 03107 void CCoreXmlFile::writeBinaryCache() 03108 { 03109 FILE * f = fopen( m_cacheFileName.c_str(), "wb" ); 03110 if( f==NULL ) 03111 { 03112 sendMsg( "Exception: Could not create binary cache file!", MSG_ERROR); 03113 HR_THROW(E_FILEOPEN); 03114 } 03115 03116 XmlObjVecIter i; 03117 metaid_type mid; 03118 03119 // write out GUIDs and metaids 03120 int n = m_objects.size(); 03121 fwrite( &n, sizeof(n), 1, f ); 03122 for( i = m_objects.begin(); i != m_objects.end(); ++i ) 03123 { 03124 mid = (*i)->m_metaid; 03125 fwrite( &mid, sizeof(mid), 1, f ); 03126 fwrite( &((*i)->m_guid), sizeof(GUID), 1, f ); 03127 } 03128 03129 // write out pointers 03130 int x; 03131 for( i=m_objects.begin(); i!=m_objects.end(); ++i ) 03132 { 03133 XmlObject * obj = (*i); 03134 for( AttribMapIter j=obj->m_attributes.begin(); j!=obj->m_attributes.end(); ++j) 03135 { 03136 if( j->second->getType() == VALTYPE_POINTER ) 03137 { 03138 XmlAttrPointer * pointer = (XmlAttrPointer*)j->second; 03139 if( pointer->m_parent == NULL ) 03140 x = -1; 03141 else 03142 x = pointer->m_parent->m_index; 03143 fwrite( &x, sizeof(x), 1, f ); 03144 } 03145 } 03146 } 03147 03148 fclose(f); 03149 } 03150 03151 bool CCoreXmlFile::readBinaryCache() 03152 { 03153 FILE * f = fopen( m_cacheFileName.c_str(), "rb" ); 03154 if( f==NULL ) 03155 return false; 03156 03157 clearAll(); 03158 03159 // read GUIDs and metaids and create objects 03160 int n,i; 03161 fread( &n, sizeof(n), 1, f ); 03162 for( i=0; i<n; ++i ) 03163 { 03164 metaid_type metaid; 03165 GUID guid; 03166 03167 fread( &metaid, sizeof(metaid), 1, f ); 03168 fread( &guid, sizeof(GUID), 1, f ); 03169 03170 CComObjPtr<ICoreMetaObject> metaobject; 03171 COMTHROW( m_metaProject->get_Object(metaid, PutOut(metaobject)) ); 03172 03173 XmlObject * obj = new XmlObject(metaobject,false); 03174 obj->m_guid = guid; 03175 addObject(obj); 03176 03177 if( metaid == METAID_ROOT ) 03178 m_root = obj; 03179 } 03180 03181 UnresolvedPointerVec pointers; 03182 int x; 03183 for( XmlObjVecIter it=m_objects.begin(); it!=m_objects.end(); ++it ) 03184 { 03185 XmlObject * obj = (*it); 03186 for( AttribMapIter j=obj->m_attributes.begin(); j!=obj->m_attributes.end(); ++j) 03187 { 03188 if( j->second->getType() == VALTYPE_POINTER ) 03189 { 03190 XmlAttrPointer * pointer = (XmlAttrPointer*)j->second; 03191 03192 UnresolvedPointer p; 03193 p.m_object = obj; 03194 p.m_attrib = j->first; 03195 03196 fread( &x, sizeof(x), 1, f ); 03197 if( x == -1 ) 03198 p.m_pointedObjGuid = GUID_NULL; 03199 else 03200 p.m_pointedObjGuid = m_objects[x]->m_guid; 03201 03202 pointers.push_back( p ); 03203 } 03204 } 03205 } 03206 03207 resolvePointers( pointers ); 03208 03209 // read and set pointers 03210 /*int x; 03211 for( XmlObjVecIter it=m_objects.begin(); it!=m_objects.end(); ++it ) 03212 { 03213 XmlObject * obj = (*it); 03214 for( AttribMapIter j=obj->m_attributes.begin(); j!=obj->m_attributes.end(); ++j) 03215 { 03216 if( j->second->getType() == VALTYPE_POINTER ) 03217 { 03218 XmlAttrPointer * pointer = (XmlAttrPointer*)j->second; 03219 03220 fread( &x, sizeof(x), 1, f ); 03221 if( x == 0 ) 03222 pointer->m_parent = NULL; 03223 else 03224 pointer->m_parent = m_objects[x]; 03225 } 03226 } 03227 }*/ 03228 03229 03230 03231 fclose(f); 03232 03233 //updateCollections(); 03234 03235 return true; 03236 } 03237 03238 void CCoreXmlFile::createProjectFile() 03239 { 03240 // create projet file 03241 FILE * f = fopen( m_projectFileName.c_str(), "wt" ); 03242 if( f == NULL ) 03243 { 03244 sendMsg( "Exception: Could not create project file '" + m_projectFileName + "'!", MSG_ERROR); 03245 AfxMessageBox( (std::string( "Could not create file ") + m_projectFileName).c_str()); 03246 HR_THROW(E_FILEOPEN); 03247 } 03248 fprintf( f, "<GME " ); 03249 if( m_svnUrl.size() > 0) 03250 fprintf( f, "svn=\"%s\"", svnSshMangling( m_svnUrl).c_str()); 03251 if( m_hashFileNames) 03252 fprintf( f, " hash=\"true\" hval=\"%s\"", (m_hashVal == 5)?"1+2":(m_hashVal == 2)?"2": (m_hashVal == 3)? "3":"4"); 03253 else 03254 fprintf( f, " hash=\"false\"" ); 03255 fprintf( f, ">\n" ); 03256 fprintf( f, "</GME>\n" ); 03257 fclose( f ); 03258 03259 if( isSV()) 03260 { 03261 bool s1 = addSVN( m_projectFileName); 03262 bool s2 = commitSVN( m_projectFileName, std::string("auto: createProjectFile()"), true); 03263 03264 if( !s1 || !s2) 03265 { 03266 AfxMessageBox( "Subversion error! Cannot add project to Subversion. Errocode = 2!"); 03267 } 03268 } 03269 03270 makeSureFileExistsInVerSys( OperatingOptions::m_sysConfName, isSV() ? OperatingOptions::m_sysConfDefContentsSvn : OperatingOptions::m_sysConfDefContentsPlain); 03271 } 03272 03273 void CCoreXmlFile::readProjectFile() 03274 { 03275 // Project file is an xml file, with a GME tag. 03276 // possible attributes: VSSDatabase, VSSPath 03277 // example: <GME VSSDatabase="\\bogyom\GMEXMLBackEndTest\sorucesafedb\srcsafe.ini" VSSPath="$\test1"></GME> 03278 03279 std::auto_ptr<DOMLSParser> parser(getFreshParser( "ProjectFileReader")); 03280 03281 ASSERT( parser.get() != NULL ); 03282 if(parser.get() == NULL) 03283 { 03284 sendMsg( "Exception: Could not create parser!", MSG_ERROR); 03285 HR_THROW(E_FILEOPEN); 03286 } 03287 03288 std::auto_ptr<DOMErrorHandler> err_handler(new DOMErrorPrinter( &m_console)); 03289 parser->getDomConfig()->setParameter(XMLUni::fgDOMErrorHandler, err_handler.get()); 03290 03291 bool fexists = FileHelp::fileExist( m_projectFileName); 03292 bool suc = false; 03293 XERCES_CPP_NAMESPACE::DOMDocument * doc = 0; 03294 if( fexists) doc = enclosedParse( m_projectFileName, parser.get(), &suc); 03295 if( !doc || !suc) 03296 { 03297 //sendMsg( "Could not find or parse project file " + m_projectFileName, MSG_ERROR); 03298 setFileNames( true); // reset the file name to a newly found one 03299 doc = enclosedParse( m_projectFileName, parser.get(), &suc); 03300 if( !doc || !suc) 03301 { 03302 if( fexists) sendMsg( "Could not parse project file '" + m_projectFileName + "'!", MSG_ERROR); 03303 else sendMsg( "Could not find project file '" + m_projectFileName + "' in directory " + m_folderPath, MSG_ERROR); 03304 HR_THROW(E_FILEOPEN); 03305 } 03306 } 03307 DOMElement * e = doc->getDocumentElement(); 03308 if( e == NULL) 03309 { 03310 sendMsg( "Null document element error during parsing of '" + m_projectFileName + "'!", MSG_ERROR); 03311 HR_THROW(E_FILEOPEN); 03312 } 03313 03314 smart_XMLCh x_vssDatabase = XMLString::transcode("VSSDatabase"); 03315 smart_XMLCh x_svnLocator = XMLString::transcode("svn"); 03316 smart_XMLCh x_hashedDirs = XMLString::transcode("hash"); 03317 smart_XMLCh x_hashValue = XMLString::transcode("hval"); 03318 03319 smart_Ch vssDatabase = XMLString::transcode(e->getAttribute( x_vssDatabase)); 03320 smart_Ch svnLocator = XMLString::transcode(e->getAttribute( x_svnLocator)); 03321 smart_Ch hashedDirs = XMLString::transcode(e->getAttribute( x_hashedDirs)); 03322 smart_Ch hashValue = XMLString::transcode(e->getAttribute( x_hashValue)); 03323 03324 if( !strcmp( hashedDirs, "true")) 03325 { 03326 m_hashFileNames = true; 03327 m_hashInfoFound = true; // this will skip asking questions about hashing 03328 03329 if ( !strcmp( hashValue, "4096"))m_hashVal = 5; 03330 else if( !strcmp( hashValue, "256")) m_hashVal = 2; 03331 else if( !strcmp( hashValue, "1+2")) m_hashVal = 5; 03332 else if( !strcmp( hashValue, "2")) m_hashVal = 2; 03333 else if( !strcmp( hashValue, "3")) m_hashVal = 3; 03334 else if( !strcmp( hashValue, "4")) m_hashVal = 4; 03335 else m_hashInfoFound = false; // unkown value 03336 } 03337 else if( !strcmp( hashedDirs, "false")) 03338 { 03339 m_hashFileNames = false; 03340 m_hashInfoFound = true; // this will skip asking questions about hashing 03341 } 03342 03343 if( strlen( svnLocator) != 0 ) 03344 { 03345 m_svnUrl = svnLocator; 03346 if( m_svnUrl != m_userOpts.m_prefUrl && !m_userOpts.m_prefUrl.empty()) // pref not empty and !equal 03347 { 03348 sendMsg( "Preferred url substitutes that loaded from the project file!", MSG_INFO); 03349 m_svnUrl = m_userOpts.m_prefUrl; 03350 } 03351 03352 m_vssUser = m_userOpts.m_useAccountInfo? m_userOpts.m_defUserName.c_str(): userNameFromSvnSshUrl(); 03353 m_vssPassword = m_userOpts.m_useAccountInfo? m_userOpts.m_defPassword.c_str(): ""; 03354 03355 m_sourceControl = SC_SUBVERSION; 03356 03357 svnSetup( false); //false => won't throw if cancelled 03358 // fills m_vssUser, m_vssPassword 03359 03360 // upon Open, the connection string might not have the full URL in it, so 03361 // that information is only available after readProjectFile (m_svnUrl) 03362 } 03363 } 03364 03365 void CCoreXmlFile::writeAll() 03366 { 03367 for( XmlObjVecIter it=m_objects.begin(); it!=m_objects.end(); ++it ) 03368 { 03369 XmlObject * obj = (*it); 03370 if( obj->isContainer() && obj->m_loaded ) 03371 writeXMLFile( obj ); 03372 03373 // we would need to write only those which have been modified, right? 03374 // yes! inside that method, files are open with 'w', which succeeds 03375 // only if the file is checked out, so non-modified containers are not 03376 // written out. Although not all checked out files are modified. 03377 } 03378 } 03379 03380 void CCoreXmlFile::timeSync( const char * fileName, XmlObject * container) 03381 { 03382 // get last write time of the recently updated and _closed_ (!) file 03383 WIN32_FILE_ATTRIBUTE_DATA attr; 03384 if( GetFileAttributesEx( fileName, GetFileExInfoStandard, &attr )) 03385 { 03386 applyLastWrTime( container, true, CTime( attr.ftLastWriteTime )); 03387 } 03388 } 03389 03390 void CCoreXmlFile::writeXMLFile(XmlObject * container) 03391 { 03392 if( !container->isContainer() ) 03393 HR_THROW(E_INVALID_USAGE); 03394 03395 std::string fileName; 03396 getContainerFileName(container, fileName); 03397 03398 // we wish we could predict the time the file will be closed 03399 // because that will become the file's 'Modified At' attribute 03400 // the obj->m_lastWriteTime needs to reflect exactly this time 03401 time_t currentTime1 = time( ¤tTime1 ); 03402 CTime currentTime2( currentTime1 + 1 ); 03403 03404 bool f_existed = false; 03405 if( FileHelp::isFileReadOnly2( fileName, &f_existed)) 03406 { 03407 return; // file exists, is read-only, no chance of writing into it 03408 // it also means there was no change 03409 } 03410 03411 // open file 03412 // previously the "w" mode used by fopen guarranteed that only read-write files are opened 03413 // now with Transcoder, exceptions will be thrown whenever a file can't be opened because it is read-only. 03414 // That's why it is a good thing to check (above) for read-onlyness 03415 Transcoder ofs; 03416 try 03417 { 03418 bool deleted = false; 03419 // Is this object deleted according to its current state? 03420 // That's important to understand: if user does undo on a deleted object 03421 // its state might return to normal, thus the deleted object might become 03422 // undeleted at any time until the user closes the project. 03423 // During projectclose the deleted state objects -at that time- are really 03424 // discarded, see ::DeleteObject code for handling these. 03425 AttribMapIter parit = container->m_attributes.find( ATTRID_PARENT); 03426 if( parit != container->m_attributes.end() && container->m_metaid != DTID_ROOT) 03427 { 03428 // if a model has its parent 0, then it is deleted: 03429 deleted = 0 == ((XmlAttrPointer*)(parit->second))->m_parent; 03430 } 03431 03432 if( !deleted) 03433 { 03434 ofs.init( fileName.c_str(), "UTF-8"); // create a transcoder fstream 03435 // Transcoder dumps by default the xml version and encoding 03436 03437 // write objects recursively 03438 writeObject( container, ofs, true, "", currentTime2 ); 03439 ofs.finalize(); 03440 } 03441 // deleted containers will have a file of 0 size 03442 if( deleted) // really overwrite the file 03443 { 03444 std::ofstream zero; 03445 zero.open( fileName.c_str(), std::ios_base::out | std::ios_base::trunc); // 'w' 03446 zero.close(); 03447 } 03448 03449 // now it's time to get file's exact 'Modified At' attribute 03450 // which can be set into the objects as the real m_lastWriteTime 03451 // alternative: if we could set the file's modification attribute 03452 // to a certain time, we'd save the effort-time to go over the 03453 // hierarchy (but the good news is that only the container's 03454 // m_lastWriteTime needs to be updated, subobjects don't matter) 03455 timeSync( fileName.c_str(), container); 03456 03457 // add to source control if not added yet 03458 try 03459 { 03460 // TODO: a good candidate for another thread 03461 addToSourceControl( container, f_existed ); 03462 } 03463 catch(...) 03464 { 03465 sendMsg( "Failed while adding to version control file: " + fileName, MSG_WARNING); 03466 } 03467 } 03468 catch( hresult_exception& e) 03469 { 03470 if( e.hr == E_INVALID_FILENAME) // file could not be opened, thrown by Transcoder::init() 03471 sendMsg( "Error while saving. Could not open file " + fileName, MSG_ERROR); 03472 else 03473 sendMsg( "Unknown error while saving file " + fileName, MSG_ERROR); 03474 } 03475 catch( ...) 03476 { 03477 sendMsg( "Generic error while saving file " + fileName, MSG_ERROR); 03478 } 03479 } 03480 03481 void CCoreXmlFile::applyLastWrTime(XmlObject * obj, bool container, CTime lastWriteTime ) 03482 { 03483 obj->m_lastWriteTime = lastWriteTime; 03484 03485 // apply the proper time for children too? currently only the container 03486 // file times are compared (Versioning System's last checked in version vs. 03487 // the local file OR local file vs. the XmlObject's m_lastWriteTime) 03488 // so kids with no file associated need not have so precise time 03489 } 03490 03491 void CCoreXmlFile::writeObject(XmlObject * obj, Transcoder& ofs, bool container, const char * prefix, CTime lastWriteTime ) 03492 { 03493 std::string str; 03494 CComObjPtr<ICoreMetaObject> metaobject; 03495 CComBSTR metaToken; 03496 03497 obj->m_lastWriteTime = lastWriteTime; 03498 03499 COMTHROW( m_metaProject->get_Object( obj->m_metaid, PutOut(metaobject) ) ); 03500 COMTHROW( metaobject->get_Token( &metaToken ) ); 03501 guid2str( obj->m_guid, str ); 03502 03503 bool spec_root = metaToken == "Root"; // or: m_metaid==METAID_ROOT 03504 03505 // the multiline case? for details see Mga\MgaGeneric.cpp 03506 // and http://escher.isis.vanderbilt.edu/JIRA/browse/GME-151 03507 // those VALTYPE_STRING type of attributes which are shown in the GME 03508 // environment as multiline strings are affected: StrValue and RegNodeValue 03509 // the objects which own these kinds of attibutes are: StrAttr and RegNode 03510 bool spec_care = metaToken == "StrAttr" || metaToken == "RegNode" || spec_root; 03511 std::string spec_value; 03512 std::string spec_preamble( spec_root?"Comment=":""); 03513 // there might be multiple attrs of <Root> which will be multiline (in the future) 03514 // thus, we with regard to that we need to distinguish the CDATA sections somehow. 03515 // only when Root is the owner, we will use a preable in the CDATA section for Comment 03516 03517 ofs << Transcoder::NoEscape << prefix << "<" << metaToken << " MetaId=\"" << obj->m_metaid << "\" Id=\"" << str << "\""; 03518 if( obj->m_deleted ) 03519 ofs << " deleted=\"true\""; 03520 03521 // write pointers, attributes 03522 AttribMapIter it; 03523 for( it=obj->m_attributes.begin(); it!=obj->m_attributes.end(); ++it ) 03524 { 03525 XmlAttrBase * attr = it->second; 03526 CComObjPtr<ICoreMetaAttribute> metaAttrib; 03527 CComBSTR attribToken; 03528 std::string attrVal; 03529 03530 COMTHROW( metaobject->get_Attribute( it->first, PutOut(metaAttrib) ) ); 03531 metaAttrib->get_Token( &attribToken ); 03532 if( attribToken == "fstate") 03533 { // do not dump file state attr into files 03534 continue; 03535 } 03536 03537 if( attr->getType() == VALTYPE_POINTER ) 03538 { 03539 ParentMap::iterator it2 = m_parentMap.find( obj->m_metaid ); 03540 if( it2==m_parentMap.end() || it2->second!=it->first || container ) 03541 { 03542 XmlAttrPointer * pointer = (XmlAttrPointer*)attr; 03543 if( pointer->m_parent != NULL ) 03544 guid2str( pointer->m_parent->m_guid, attrVal ); 03545 } 03546 } 03547 else if( attr->getType() != VALTYPE_COLLECTION && attr->getType() != VALTYPE_LOCK 03548 && attr->getType() != VALTYPE_DICT) 03549 { 03550 XmlAttrBase * attr = it->second; 03551 attr->toString(attrVal); 03552 } 03553 03554 if( !attrVal.empty() ) 03555 { 03556 // attribToken not converted any more with replaceSpaceWithUnderscore -- zolmol 03557 #ifdef DEBUG 03558 std::string at; CopyTo( attribToken, at); 03559 ATLASSERT(("Check MgaGeneric.cpp for attribute tokens containing spaces", at.find(' ') == -1)); 03560 #endif 03561 03562 bool spec_attr = spec_care && (attribToken == "StrValue" || attribToken == "RegNodeValue" || attribToken == "Comment"); 03563 03564 if( spec_attr) // spec_care is also true 03565 spec_value = attrVal; // store the (possibly multiline) original value, without encoding 03566 else // regular dump: 03567 ofs << " " << attribToken << "=\"" << Transcoder::StdEscape << attrVal << Transcoder::NoEscape << "\""; 03568 } 03569 } 03570 ofs << Transcoder::NoEscape << ">"; 03571 if( spec_care) // right after the element, without whitespace, (in sync with readObject()) 03572 { 03573 // only a little attention is paid to possbile 03574 // occurences of ']]>' in the data 03575 if( spec_value.find( "]]>") != std::string::npos) 03576 { 03577 sendMsg( "Special character string ']]>' found among one element's properties, will be replaced by ']] >'", MSG_INFO); 03578 spec_value.replace( spec_value.find( "]]>"), 3, "]] >"); 03579 } 03580 // encoding not needed since it goes to CDATA 03581 ofs << "<![CDATA[" << spec_preamble << spec_value << "]]>"; 03582 } 03583 ofs << "\n"; 03584 03585 03586 // write out children 03587 // child is written if it is not the root, a model or a folder 03588 // and the parent of the child is a us according to m_parentMap 03589 std::string newPrefix = prefix; 03590 newPrefix += "\t"; 03591 for( it=obj->m_attributes.begin(); it!=obj->m_attributes.end(); ++it ) 03592 { 03593 XmlAttrBase * attr = it->second; 03594 if( attr->getType() == VALTYPE_COLLECTION ) 03595 { 03596 XmlAttrCollection * coll = (XmlAttrCollection*)attr; 03597 for( XmlObjSetIter it2=coll->m_children.begin(); it2!=coll->m_children.end(); ++it2 ) 03598 { 03599 XmlObject * obj2 = (*it2); 03600 if( obj2!=NULL && !obj2->isContainer() ) 03601 { 03602 ParentMap::iterator it3 = m_parentMap.find( obj2->m_metaid ); 03603 ASSERT( it3 != m_parentMap.end() ); 03604 if( it3->second + ATTRID_COLLECTION == it->first ) 03605 writeObject( obj2, ofs, false, newPrefix.c_str(), lastWriteTime ); 03606 } 03607 } 03608 } 03609 else if (attr->getType() == VALTYPE_DICT) 03610 { 03611 CComObjPtr<ICoreMetaAttribute> metaAttrib; 03612 CComBSTR attribToken; 03613 std::string attrVal; 03614 03615 COMTHROW( metaobject->get_Attribute( it->first, PutOut(metaAttrib) ) ); 03616 metaAttrib->get_Token( &attribToken ); 03617 XmlAttrDict* dict = (XmlAttrDict*)it->second; 03618 CCoreDictionaryAttributeValue* dictValue = (CCoreDictionaryAttributeValue*)(ICoreDictionaryAttributeValue*)dict->m_value; 03619 ofs << Transcoder::NoEscape << "<Dict token=\"" << attribToken << "\">"; 03620 for (auto i = dictValue->m_dict.begin(); i != dictValue->m_dict.end(); i++) 03621 { 03622 ofs << Transcoder::NoEscape << "<Key>"; 03623 ofs << Transcoder::StdEscape << static_cast<const char*>(_bstr_t(i->first)); 03624 ofs << Transcoder::NoEscape << "</Key>"; 03625 ofs << Transcoder::NoEscape << "<Value>"; 03626 ofs << Transcoder::StdEscape << static_cast<const char*>(_bstr_t(i->second)); 03627 ofs << Transcoder::NoEscape << "</Value>"; 03628 } 03629 ofs << Transcoder::NoEscape << "</Dict>"; 03630 } 03631 03632 } 03633 03634 ofs << Transcoder::NoEscape << prefix << "</" << metaToken << ">\n"; 03635 } 03636 03637 03638 void CCoreXmlFile::fullReadContainer(XmlObject * container) 03639 { 03640 std::string fileName; 03641 getContainerFileName(container, fileName); 03642 03643 UnresolvedPointerVec pointers; 03644 readXMLFile( fileName.c_str(), pointers, true ); 03645 // shouldn't we call this? probably not, since pointer skeletons have been loaded already 03646 // and all pointers are considered unresolved after readXMLFile() 03647 //resolvePointers( pointers); 03648 //ASSERT( pointers.size() == 0); 03649 } 03650 03651 void CCoreXmlFile::readXMLFile( const char * fileName, UnresolvedPointerVec& pointers, bool fullLoad ) 03652 { 03653 // get last write time 03654 WIN32_FILE_ATTRIBUTE_DATA attr; 03655 BOOL res = GetFileAttributesEx( fileName, GetFileExInfoStandard, &attr ); 03656 03657 // attr is valid and filesize = 0 03658 if( res && attr.nFileSizeHigh == 0 && attr.nFileSizeLow == 0) 03659 return; 03660 03661 CTime lastWriteTime( attr.ftLastWriteTime ); 03662 03663 std::auto_ptr<DOMLSParser> parser; 03664 std::auto_ptr<DOMErrorHandler> err_handler; 03665 try 03666 { 03667 DOMImplementationLS * domimpl = 0; 03668 newDOMObjs( &domimpl, parser, err_handler); 03669 03670 if( !domimpl || !parser.get()) 03671 { 03672 sendMsg( std::string( "Could not create parser for file ") + fileName + "!", MSG_ERROR); 03673 HR_THROW(E_FILEOPEN); 03674 } 03675 03676 bool suc; 03677 // TODO: a good candidate for another thread... 03678 XERCES_CPP_NAMESPACE::DOMDocument * doc = enclosedParse( fileName, parser.get(), &suc); 03679 if( !doc || !suc) 03680 { 03681 sendMsg( std::string( "Could not parse file ") + fileName + "!", MSG_ERROR); 03682 HR_THROW(E_FILEOPEN); 03683 } 03684 03685 DOMElement * doc_e = doc->getDocumentElement(); 03686 if( doc_e == NULL) 03687 { 03688 // todo linenumbers 03689 // this might be totally useless 03690 bool might_be_ok = false; 03691 DOMNodeList* list = doc->getChildNodes(); 03692 03693 if( list) for( int i = (int) list->getLength() - 1; i >= 0 ; --i) 03694 { 03695 might_be_ok = true; 03696 DOMNode * node = list->item(i); 03697 if( node->getNodeType() == DOMNode::TEXT_NODE) 03698 { 03699 DOMText * txt = (DOMText*) node; 03700 const XMLCh* p = txt->getData(); 03701 } 03702 if( node->getNodeType() == DOMNode::ELEMENT_NODE) 03703 { 03704 DOMElement* elem = (DOMElement*)node; 03705 const XMLCh* tn = elem->getTagName(); 03706 } 03707 } 03708 if( !might_be_ok) 03709 sendMsg( std::string( "Null document element was found while parsing file ") + fileName + "!", MSG_ERROR); 03710 03711 // reload it, might be nonzero now (only in fairy tales probably) 03712 doc_e = doc->getDocumentElement(); 03713 } 03714 03715 if( doc_e == NULL) 03716 { 03717 sendMsg( std::string( "Exception: Null document element during parsing of ") + fileName + "!", MSG_ERROR); 03718 HR_THROW(E_FILEOPEN); 03719 } 03720 03721 readObject( doc_e, pointers, NULL, fullLoad, lastWriteTime ); 03722 } 03723 catch(...) 03724 { 03725 sendMsg( std::string( "Exception during reading ") + fileName + " file!", MSG_ERROR); 03726 HR_THROW(E_FILEOPEN); 03727 } 03728 } 03729 03730 void CCoreXmlFile::readObject(DOMElement * e, UnresolvedPointerVec& pointers, XmlObject * parent, bool fullLoad, CTime lastWriteTime ) 03731 { 03732 if( e == NULL) 03733 { 03734 sendMsg( "Exception: readObject invoked with null element!", MSG_ERROR); 03735 HR_THROW(E_FILEOPEN); 03736 } 03737 // what is the deleted container policy? if XML attribute is used code below is needed 03738 #ifdef DEBUG 03739 // if the object is deleted do not deal with it 03740 // possible optimization: limit analysis to ( parent == 0) case only (when incoming parameter is 0) 03741 const XMLCh* x_deleted = ParserLiterals::Main::deleted; 03742 smart_Ch deletedStr = XMLString::transcode( e->getAttribute( x_deleted)); 03743 bool deleted = (strcmp( deletedStr, "true" ) == 0); 03744 if( deleted) 03745 { 03746 ASSERT(0); // deleted XML attribute is no longer present in deleted XML files 03747 return; 03748 } 03749 #endif 03750 03751 const XMLCh* x_metaId = ParserLiterals::Main::metaId; 03752 const XMLCh* x_id = ParserLiterals::Main::id; 03753 03754 // get metaid, and id 03755 smart_Ch metaIdStr = XMLString::transcode( e->getAttribute( x_metaId)); 03756 smart_Ch objGUIDStr = XMLString::transcode( e->getAttribute( x_id)); 03757 03758 long metaid = atoi( metaIdStr); 03759 GUID guid = str2guid( objGUIDStr ); 03760 03761 // is container deleted/obsolete? 03762 // if nonrootfolder and its explicit parent must be 0 03763 if( metaid != METAID_ROOT && parent == 0) 03764 { 03765 // is its XML Parent attribute empty 03766 const XMLCh* x_parent = ParserLiterals::Main::parent; 03767 smart_Ch parent_xml_attr = XMLString::transcode( e->getAttribute( x_parent)); 03768 03769 // is object obsolete? 03770 bool obs = parent_xml_attr == 0 || strcmp( parent_xml_attr, "") == 0; 03771 03772 if( obs) return; 03773 } 03774 03775 // get meta object 03776 CComObjPtr<ICoreMetaObject> metaobject; 03777 #pragma warning( disable: 4244) // conversion from 'long' to 'short', possible loss of data 03778 COMTHROW( m_metaProject->get_Object( metaid, PutOut(metaobject) ) ); 03779 #pragma warning( default: 4244) // conversion from 'long' to 'short', possible loss of data 03780 03781 CComBSTR metaobj_token; 03782 COMTHROW(metaobject->get_Token(&metaobj_token)); 03783 03784 // the multiline case? ----- for details see writeObject() 03785 bool spec_care = !wcscmp(metaobj_token, L"StrAttr") || !wcscmp(metaobj_token, L"RegNode") || !wcscmp(metaobj_token, L"Root"); 03786 std::string spec_value; 03787 std::wstring spec_valuew; 03788 03789 // find or create object 03790 XmlObject * obj = NULL; 03791 GUIDToXmlObjectMapIter it = m_objectsByGUID.find( guid ); 03792 if( it != m_objectsByGUID.end() ) 03793 { 03794 obj = it->second; 03795 if( !obj->m_loaded && fullLoad ) 03796 { 03797 obj->createAttributes(metaobject,XmlObject::ATTR_SECONDARY); 03798 obj->m_loaded = true; 03799 } 03800 } 03801 else 03802 { 03803 obj = new XmlObject(metaobject,fullLoad); 03804 obj->m_guid = guid; 03805 addObject( obj ); 03806 if( metaid == METAID_ROOT ) 03807 m_root = obj; 03808 } 03809 03810 obj->m_deleted = false; 03811 obj->m_lastWriteTime = lastWriteTime; 03812 03813 // read attributes 03814 AttribMapIter it2; 03815 for( it2 = obj->m_attributes.begin(); it2 != obj->m_attributes.end(); ++it2 ) 03816 { 03817 CComObjPtr<ICoreMetaAttribute> metaAttrib; 03818 CComBSTR attribToken; 03819 03820 COMTHROW( metaobject->get_Attribute( it2->first, PutOut(metaAttrib) ) ); 03821 // TODO: memoize 03822 COMTHROW( metaAttrib->get_Token( &attribToken )); 03823 03824 // see http://escher.isis.vanderbilt.edu/JIRA/browse/GME-152 03825 // it won't find 'MGA Version' of rootfolder if space2underscore and 03826 // underscore2space conversions are in effect 03827 const wchar_t* attrValW = e->getAttribute(attribToken); 03828 smart_Ch attrVal = XMLString::transcode(attrValW); 03829 03830 // multiline case? 03831 bool spec_value_found = false; // will ensure smooth upgrade from old style xmlbackend 03832 bool spec_attr = spec_care && ( !wcscmp(attribToken, L"StrValue") || !wcscmp(attribToken, L"RegNodeValue") || !wcscmp(attribToken, L"Comment")); 03833 if( spec_attr) 03834 { 03835 // the implementation below with getChildNodes() is more tolerant of XML COMMENTs, XML Whitespaces... 03836 // than using the getFirstChild() method, which can be easily tricked by whitespaces 03837 DOMNodeList * children = e->getChildNodes(); 03838 // find the first CDATA section among the kids: it should be the first node! (based on writeObject()'s impl) 03839 for( int i = 0; i < (int) children->getLength(); ++i ) 03840 { 03841 DOMNode * node = children->item(i); 03842 if( node->getNodeType() == DOMNode::CDATA_SECTION_NODE ) // the first CDATA element is taken 03843 { 03844 const XMLCh* text = ((DOMCDATASection*)node)->getTextContent(); 03845 smart_Ch sp_va = XMLString::transcode(text); 03846 03847 spec_valuew = text; 03848 spec_value = sp_va; 03849 spec_value_found = true; 03850 03851 break; 03852 } 03853 } 03854 } 03855 03856 // removed unnecessary conversion of attrVal with replaceUnderscoreWithSpace! -- zolmol 03857 03858 XmlAttrBase * attr = it2->second; 03859 if( attr->getType() == VALTYPE_POINTER ) 03860 { 03861 UnresolvedPointer p; 03862 p.m_object = obj; 03863 p.m_attrib = it2->first; 03864 if( attrVal==NULL || strlen(attrVal)==0 ) 03865 p.m_pointedObjGuid = GUID_NULL; 03866 else 03867 p.m_pointedObjGuid = str2guid( attrVal ); 03868 pointers.push_back( p ); 03869 } 03870 else if( attr->getType() != VALTYPE_LOCK && attr->getType() != VALTYPE_COLLECTION 03871 && attr->getType() != VALTYPE_DICT) 03872 { 03873 it2->second->fromString(attrVal, attrValW); 03874 03875 // use the spec_value only if really found the CDATA node 03876 if( spec_attr && spec_value_found) // spec_care is also true 03877 { 03878 if (!wcscmp(attribToken, L"Comment")) 03879 { 03880 const std::string comm_spec = "Comment="; 03881 if( 0 == spec_value.find( comm_spec)) // CDATA section looks like this: <![CDATA[Comment=....]]> 03882 it2->second->fromString( spec_value.substr( comm_spec.length()).c_str(), NULL); 03883 else 03884 ASSERT(0); 03885 } 03886 else 03887 it2->second->fromString( spec_value.c_str(), NULL); 03888 } 03889 } 03890 } 03891 03892 // implicit parent pointer 03893 if( parent != NULL ) 03894 { 03895 ParentMap::iterator it3 = m_parentMap.find( obj->m_metaid ); 03896 UnresolvedPointer p; 03897 p.m_object = obj; 03898 p.m_attrib = it3->second; 03899 p.m_pointedObjGuid = parent->m_guid; 03900 pointers.push_back(p); 03901 } 03902 03903 // read children 03904 DOMNodeList * children = e->getChildNodes(); 03905 for( int i=0; i< (int) children->getLength(); ++i ) 03906 { 03907 DOMNode * node = children->item(i); 03908 //if spec_care was true the first child was CDATA, but we process anyway the ELEMENTs only 03909 if( node->getNodeType() == DOMNode::ELEMENT_NODE ) 03910 { 03911 if (wcscmp(node->getLocalName(), L"Dict") == 0) 03912 { 03913 // TODO: read token attribute (but only regnodes are stored in Dict for now) 03914 auto it = obj->m_attributes.find(ATTRID_REGNODE); 03915 if (it == obj->m_attributes.end()) 03916 COMTHROW(E_FILEOPEN); 03917 XmlAttrDict* dict = (XmlAttrDict*)it->second; 03918 CCoreDictionaryAttributeValue* dictValue = (CCoreDictionaryAttributeValue*)(ICoreDictionaryAttributeValue*)dict->m_value; 03919 DOMNodeList* dictEntries = node->getChildNodes(); 03920 for (XMLSize_t i = 0; i+1 < dictEntries->getLength(); i += 2) 03921 { 03922 if (dictEntries->item(i)->getNodeType() != DOMNode::ELEMENT_NODE) 03923 COMTHROW(E_FILEOPEN); 03924 if (dictEntries->item(i+1)->getNodeType() != DOMNode::ELEMENT_NODE) 03925 COMTHROW(E_FILEOPEN); 03926 if (((DOMElement*)dictEntries->item(i))->getChildNodes()->getLength() != 1) 03927 COMTHROW(E_FILEOPEN); 03928 CComBSTR value; 03929 if (((DOMElement*)dictEntries->item(i+1))->getChildNodes()->getLength() == 1) 03930 { 03931 if (((DOMElement*)dictEntries->item(i+1))->getChildNodes()->item(0)->getNodeType() != DOMNode::TEXT_NODE) 03932 COMTHROW(E_FILEOPEN); 03933 DOMText* valueText = (DOMText*)((DOMElement*)dictEntries->item(i+1))->getChildNodes()->item(0); 03934 value = valueText->getData(); 03935 } 03936 if (((DOMElement*)dictEntries->item(i))->getChildNodes()->item(0)->getNodeType() != DOMNode::TEXT_NODE) 03937 COMTHROW(E_FILEOPEN); 03938 DOMText* key = (DOMText*)((DOMElement*)dictEntries->item(i))->getChildNodes()->item(0); 03939 dictValue->m_dict.insert(CCoreDictionaryAttributeValue::map_type::value_type(key->getData(), std::move(value))); 03940 } 03941 } 03942 else 03943 readObject( (DOMElement*)node, pointers, obj, fullLoad, lastWriteTime ); 03944 } 03945 } 03946 } 03947 03948 void CCoreXmlFile::loadFrom( const std::string& p_dir, UnresolvedPointerVec& p_pointers, bool p_fullLoad ) 03949 { 03950 char buf[_MAX_PATH]; 03951 _finddata_t fileInfo; 03952 03953 sprintf( buf, "%s\\*.xml", p_dir.c_str() ); 03954 03955 long searchHandle = _findfirst( buf, &fileInfo ); 03956 long ret = searchHandle; 03957 while( ret != -1 ) 03958 { 03959 sprintf( buf, "%s\\%s", p_dir.c_str(), fileInfo.name ); 03960 readXMLFile( buf, p_pointers, p_fullLoad ); 03961 ret = _findnext( searchHandle, &fileInfo ); 03962 } 03963 _findclose( searchHandle ); 03964 } 03965 03966 void CCoreXmlFile::loadDirs( const std::string& p_dir, UnresolvedPointerVec& p_pointers, bool p_fullLoad ) 03967 { 03968 char buf[_MAX_PATH]; 03969 _finddata_t item; 03970 03971 loadFrom( p_dir, p_pointers, p_fullLoad); // load .xml files if any 03972 03973 // find all subdirs 03974 sprintf( buf, "%s\\*", p_dir.c_str() ); 03975 long searchHandle = _findfirst( buf, &item ); 03976 long ret = searchHandle; 03977 while( ret != -1 ) 03978 { 03979 if( (item.attrib & _A_SUBDIR) == _A_SUBDIR) 03980 { 03981 std::string f( item.name); 03982 if( f != ".." && f != ".") 03983 { 03984 sprintf( buf, "%s\\%s", p_dir.c_str(), item.name ); 03985 //sendMsg( buf, MSG_INFO); 03986 //readXMLFile( buf, pointers, fullLoad ); 03987 03988 // invoke loadDirs for the subdir 03989 loadDirs( buf, p_pointers, p_fullLoad); 03990 } 03991 } 03992 ret = _findnext( searchHandle, &item ); 03993 } 03994 _findclose( searchHandle ); 03995 } 03996 03997 03998 void CCoreXmlFile::readAll( bool fullLoad ) 03999 { 04000 UnresolvedPointerVec pointers; 04001 04002 UpdateProgress(_T("Parse XML database")); 04003 04004 // todo: preconditions 04005 #ifdef _DEBUG 04006 #if(DETAILS_ABOUT_XMLBACKEND) 04007 if( m_userOpts.m_measureTime) 04008 { 04009 sendMsg( std::string( "Loading ") + m_folderPath, MSG_INFO); 04010 } 04011 #endif 04012 #endif 04013 04014 clearAll(); 04015 04016 // load all dirs 04017 loadDirs( m_folderPath, pointers, fullLoad); 04018 04019 #ifdef _DEBUG 04020 #if(DETAILS_ABOUT_XMLBACKEND) 04021 if( m_userOpts.m_measureTime) { sendMsg( "resolvePointers", MSG_INFO); } 04022 #endif 04023 #endif 04024 04025 resolvePointers( pointers ); 04026 04027 #ifdef _DEBUG 04028 #if(DETAILS_ABOUT_XMLBACKEND) 04029 if( m_userOpts.m_measureTime) { sendMsg( "resetSourceControl", MSG_INFO); } 04030 04031 _timeb b1, b2; 04032 _ftime( &b1); 04033 #endif 04034 #endif 04035 04036 resetSourceControlForAll(); 04037 04038 #ifdef _DEBUG 04039 #if(DETAILS_ABOUT_XMLBACKEND) 04040 _ftime( &b2); 04041 04042 if( m_userOpts.m_measureTime) { 04043 char msg_buf[250]; 04044 sprintf( msg_buf, "[createSourceControlInfoRegNodes took = %li secs %hi millisecs]", b2.time-b1.time, b2.millitm-b1.millitm); 04045 sendMsg( std::string( msg_buf), MSG_INFO); 04046 } 04047 #endif 04048 #endif 04049 04050 if( m_userOpts.m_onLoadShowStatus) 04051 { 04052 #ifdef _DEBUG 04053 #if(DETAILS_ABOUT_XMLBACKEND) 04054 if( m_userOpts.m_measureTime) { sendMsg( "updateSourceControlRegnodes begn", MSG_INFO); } 04055 04056 _timeb b3, b4; 04057 04058 _ftime( &b3); 04059 #endif 04060 #endif 04061 updateSourceControlInfo(); // show current status upon 'OpenProject' 04062 04063 #ifdef _DEBUG 04064 #if(DETAILS_ABOUT_XMLBACKEND) 04065 _ftime( &b4); 04066 04067 if( m_userOpts.m_measureTime) { sendMsg( "updateSourceControlRegnodes done", MSG_INFO); } 04068 04069 if( m_userOpts.m_measureTime) { 04070 char msg_buf[250]; 04071 sprintf( msg_buf, "[UpdateSourceControlInfo took = %li secs %hi millisecs]", b4.time-b3.time, b4.millitm-b3.millitm); 04072 sendMsg( std::string( msg_buf), MSG_INFO); 04073 } 04074 #endif 04075 #endif 04076 } 04077 UpdateProgress(_T(" DONE.\r\n")); 04078 } 04079 04080 void CCoreXmlFile::getLatestAndLoad() 04081 { 04082 char buf[_MAX_PATH]; 04083 _finddata_t fileInfo; 04084 time_t currentTime1 = time( ¤tTime1 ); 04085 CTime currentTime2( currentTime1 - 100 ); 04086 04087 FILETIME last_cache_write_time; 04088 timestampOfCache( &last_cache_write_time); 04089 04090 // get latest version from source control 04091 getLatestVersion(); 04092 04093 // itarete on files and read new and modified files 04094 sprintf( buf, "%s\\*.xml", m_folderPath.c_str() ); 04095 long searchHandle = _findfirst( buf, &fileInfo ); 04096 long ret = searchHandle; 04097 while( ret != -1 ) 04098 { 04099 sprintf( buf, "%s\\%s", m_folderPath.c_str(), fileInfo.name ); 04100 04101 WIN32_FILE_ATTRIBUTE_DATA attr; 04102 if( GetFileAttributesEx( buf, GetFileExInfoStandard, &attr ) ) 04103 { 04104 // A GOOD TEST STILL NEEDED BELOW:::: 04105 // this test is also not good, because the cache write time although is older 04106 // then modelopen time (in which session the cache file was written out) 04107 // but the cache file reflects only the state of the project in modelopen time 04108 if( 1 == CompareFileTime( &attr.ftLastWriteTime, &last_cache_write_time)) // attr.ftLastWriteTime > last_cache_write_time 04109 { 04110 // this is a new or modified file, read it 04111 UnresolvedPointerVec pointers; 04112 readXMLFile( buf, pointers, false ); 04113 resolvePointers( pointers); 04114 } 04115 // earlier this was used: 04116 // this might bave been a bad test: 04117 //CTime modTime( attr.ftLastWriteTime ); 04118 //if( modTime >= currentTime2 ) { } 04119 } 04120 04121 ret = _findnext( searchHandle, &fileInfo ); 04122 } 04123 _findclose( searchHandle ); 04124 } 04125 04126 bool CCoreXmlFile::getUserCredentialInfo( int p_svnText, bool p_requireLogin) 04127 { 04128 bool aborted = false; 04129 if( p_svnText != 0) 04130 { 04131 bool is_ssh_hinted = isUrlSvnSsh(); 04132 CSvnLoginDlg dlg( is_ssh_hinted? 2 : 0); 04133 dlg.m_project = m_projectFileName.c_str(); 04134 dlg.m_database = m_svnUrl.c_str(); 04135 dlg.m_user = m_userOpts.m_useAccountInfo? m_userOpts.m_defUserName.c_str(): userNameFromSvnSshUrl().c_str(); 04136 dlg.m_password = m_userOpts.m_useAccountInfo? m_userOpts.m_defPassword.c_str(): ""; 04137 if( !is_ssh_hinted) // https etc. 04138 dlg.disableSshOption(); 04139 04140 if( m_userOpts.m_useAccountInfo && m_userOpts.m_automaticLogin || dlg.DoModal() == IDOK ) 04141 { 04142 m_vssUser = dlg.m_user; 04143 m_vssPassword = dlg.m_password; 04144 return true; 04145 } 04146 aborted = dlg.wasAborted(); 04147 } 04148 04149 // we are sure that not IDOK was pressed 04150 if( p_requireLogin) 04151 AfxMessageBox( "Could not process further without login information.", MB_ICONEXCLAMATION); 04152 04153 if( aborted || p_requireLogin) 04154 HR_THROW( E_UNKNOWN_STORAGE); // this will imply a relatively silent abort, with no further assertions 04155 04156 return false; 04157 } 04158 04159 bool CCoreXmlFile::isContainerReadOnly(XmlObject * obj) 04160 { 04161 ASSERT( obj != NULL ); 04162 04163 std::string fileName; 04164 getContainerFileName( obj, fileName ); 04165 04166 if( FileHelp::fileExist( fileName)) 04167 return FileHelp::isFileReadOnly( fileName); 04168 else 04169 { 04170 // the file does not exiest (not written out yet) 04171 return false; 04172 } 04173 } 04174 04175 bool CCoreXmlFile::isContinerCheckedOut(XmlObject * obj) 04176 { 04177 ASSERT( m_sourceControl != SC_NONE ); 04178 04179 if( isSV()) 04180 { 04181 // freshly added, test this. 98765 04182 std::string fileName; 04183 getContainerFileName( obj, fileName, true ); 04184 return isCheckedOutByElseSVN( fileName); 04185 } 04186 04187 return false; 04188 } 04189 04190 void CCoreXmlFile::checkOutContainer(XmlObject * obj) 04191 { 04192 ASSERT( m_sourceControl != SC_NONE ); 04193 04194 if( isSV()) 04195 { 04196 std::string file_name; 04197 getContainerFileName( obj, file_name, true); 04198 applyLockSVN( file_name); 04199 } 04200 } 04201 04202 void CCoreXmlFile::rollBackTheCheckOutContainer(XmlObject * obj) 04203 { 04204 ASSERT( m_sourceControl != SC_NONE ); 04205 04206 std::string fileName; 04207 getContainerFileName( obj, fileName); 04208 04209 try 04210 { 04211 if( isSV()) 04212 { 04213 bool sc = removeLockSVN( fileName); 04214 if( !sc) HR_THROW( E_FAIL); 04215 } 04216 } 04217 catch(...) 04218 { 04219 sendMsg( "Could not rollback the lock for " + fileName, MSG_WARNING); 04220 } 04221 } 04222 04223 void CCoreXmlFile::addToSourceControl(XmlObject * container, bool p_fileExisted) 04224 { 04225 ASSERT( container->isContainer() ); 04226 04227 std::string fileName; 04228 getContainerFileName(container, fileName); 04229 04230 if( isSV()) 04231 { 04232 bool sc_add = true; 04233 bool sc_pro = true; 04234 bool sc_com = true; 04235 if( !p_fileExisted) // if( !isVersionedInSVN( fileName)) // do add and lockable only for new files 04236 { 04237 sc_add = addSVN( fileName); 04238 sc_pro = lockablePropertySVN( fileName); 04239 // TODO: use svn_client_propset_local to add locking to all the files 04240 } 04241 04242 if( !m_userOpts.m_useBulkCommit) // if bulk commit then avoid individual commits 04243 sc_com = commitSVN( fileName, std::string("auto: addToSourceControl()"), !p_fileExisted); 04244 04245 if( !(sc_com && sc_pro && sc_add)) 04246 { 04247 if( !sc_add) sendMsg( "Could not add file " + fileName, MSG_ERROR); 04248 else if( !sc_pro) sendMsg( "Could not set lockable property for " + fileName, MSG_ERROR); 04249 else if( !sc_com) sendMsg( "Could not commit file " + fileName, MSG_ERROR); 04250 throw hresult_exception(E_FAIL); 04251 } 04252 } 04253 } 04254 04255 /* ****************************************************************************** */ 04256 /* C L A S S P R O T E C T E N T R Y */ 04257 /* ****************************************************************************** */ 04258 ProtectEntry::ProtectEntry( GUID p_gd, OpCode p_op, CTime p_time) 04259 : m_guid( p_gd) 04260 , m_op( p_op) 04261 , m_time( p_time) 04262 { } 04263 04264 /* ****************************************************************************** */ 04265 /* C L A S S P U B L I C S T O R A G E */ 04266 /* ****************************************************************************** */ 04267 PublicStorage::PublicStorage() 04268 : m_parent( 0) 04269 { 04270 } 04271 04272 void PublicStorage::setParent( CCoreXmlFile* p_parent) 04273 { 04274 m_parent = p_parent; 04275 } 04276 04277 void PublicStorage::init( const std::string& p_initialContent) 04278 { 04279 if( !m_parent) 04280 return; 04281 04282 if( !m_parent->makeSureFileExistsInVerSys( m_fileName, p_initialContent)) 04283 { 04284 m_parent->sendMsg( "Could not find files in Versioning System", MSG_ERROR); 04285 return; 04286 } 04287 04288 if( isSV()) 04289 m_ccsItem = m_localFileName.c_str(); // ok, as long as m_localFileName doesn't change 04290 } 04291 04292 void PublicStorage::acquireSVN( const char * obj) 04293 { 04294 if( FileHelp::isFileReadOnly( obj)) 04295 { 04296 m_parent->updateSVN( obj); // SVN needs updating before any lock can be placed 04297 m_parent->applyLockSVN( obj); 04298 //ASSERT( !m_parent->isFileReadOnly( obj)); 04299 } 04300 } 04301 04302 void PublicStorage::releaseSVN( const char * obj) 04303 { 04304 bool sc = m_parent->commitSVN( obj, std::string("auto: PublicStorage::releaseSVN()"), false); 04305 ASSERT( sc); 04306 if( !sc) 04307 { 04308 m_parent->sendMsg( std::string( "Could not commit file ") + obj, MSG_ERROR); 04309 } 04310 04311 if( !FileHelp::isFileReadOnly( obj)) // probably the file did not change, so that's why the commit did not remove the lock 04312 { 04313 bool sc = m_parent->removeLockSVN( obj); 04314 ASSERT( sc); 04315 ASSERT( FileHelp::isFileReadOnly( obj)); 04316 } 04317 } 04318 04319 void PublicStorage::acquireFile() 04320 { 04321 if( isSV()) 04322 { 04323 acquireSVN( m_ccsItem); 04324 } 04325 } 04326 04327 void PublicStorage::releaseFile() 04328 { 04329 if( isSV()) 04330 { 04331 releaseSVN( m_ccsItem); 04332 } 04333 } 04334 04335 std::string PublicStorage::userName() { return m_parent->userName(); } 04336 bool PublicStorage::isSV() { return m_parent->isSV(); } 04337 04338 04339 /* ****************************************************************************** */ 04340 /* C L A S S S I G N M A N A G E R */ 04341 /* ****************************************************************************** */ 04342 04343 void SignManager::setParent( CCoreXmlFile* p_parent) 04344 { 04345 PublicStorage::setParent( p_parent); 04346 04347 m_fileName = std::string(HelperFiles::sessionFolderName) + "/" + HelperFiles::signFileName; 04348 m_localFileName = m_parent->m_folderPath + "\\" + HelperFiles::sessionFolderName + "\\" + HelperFiles::signFileName; 04349 04350 PublicStorage::init( "<users/>"); 04351 } 04352 04353 bool SignManager::anybodyElseHolding() 04354 { 04355 if( isSV()) 04356 { 04357 return m_parent->isCheckedOutByElseSVN( m_ccsItem); 04358 } 04359 return false; 04360 } 04361 04362 void SignManager::in_or_off( bool in) 04363 { 04364 const char * msg_in = "Could not sign in yet. Press OK to try again."; 04365 const char * msg_out= "Could not sign out yet. Press OK to try again."; 04366 04367 if(!isSV()) return; 04368 try 04369 { 04370 bool lost_patience = false; // once this will turn true further attempts will cease 04371 bool successful_acquisition = false; 04372 04373 while( !successful_acquisition && !lost_patience) 04374 { 04375 bool chance_for_acquisition = false; 04376 04377 while( !chance_for_acquisition && !lost_patience) 04378 { 04379 chance_for_acquisition = !anybodyElseHolding(); 04380 if( !chance_for_acquisition) 04381 { 04382 // others hold a lock to the signin file 04383 // notify user and retry if needed 04384 if( IDCANCEL == AfxMessageBox( in?msg_in:msg_out, MB_OKCANCEL)) 04385 lost_patience = true; // quit, no further attempts 04386 } 04387 } 04388 04389 if( chance_for_acquisition) // user did not give up, no one holding the file, chance to acquire it 04390 { 04391 try { 04392 acquireFile(); 04393 successful_acquisition = true; 04394 } 04395 catch(hresult_exception&) { 04396 // somebody else acquired it in the meantime 04397 if( IDCANCEL == AfxMessageBox( in?msg_in:msg_out, MB_OKCANCEL)) 04398 lost_patience = true; // quit, no further attempts 04399 } 04400 } 04401 // else: lost_patience turned true, so this loop will terminate too 04402 } 04403 04404 if( successful_acquisition) 04405 { 04406 if( isSV()) { 04407 std::string owner; 04408 m_parent->infoSVN( this->m_ccsItem, false, std::string(), std::string(), owner); 04409 if( owner != userName()) { 04410 if( IDYES == AfxMessageBox( CString( "Username mismatch found. The signature file recently locked by you, reports to be locked by user: '") + owner.c_str() + "' while you have identified initially yourself as '" + userName().c_str() + "'.\nWould you like to continue with '" + owner.c_str() + "' username?", MB_YESNO)) { 04411 m_parent->replaceUserName( owner); 04412 } 04413 } 04414 } 04415 04416 try { 04417 update( in, SignFileEntry( userName(), CTime::GetCurrentTime())); 04418 } catch(hresult_exception&) { // handled cases throw HRESULT from inside 04419 m_parent->sendMsg( "Could not update signature file! Exception happened.", MSG_ERROR); 04420 } 04421 04422 releaseFile(); 04423 } 04424 } 04425 catch(...) 04426 { 04427 AfxMessageBox( "Could not proceed with sign in/off. Exception happened."); 04428 } 04429 } 04430 04431 void SignManager::update( bool p_in, const SignFileEntry& p_entry) 04432 { 04433 DOMImplementationLS * domimpl = NULL; 04434 DOMLSParser * parser = m_parent->getFreshParser( "SignatureFileUpdater", &domimpl); 04435 04436 ASSERT( parser != NULL ); 04437 if( !parser) { 04438 m_parent->sendMsg( "DOMBuilder pointer is NULL!", MSG_ERROR); 04439 HR_THROW(E_FILEOPEN); 04440 } 04441 04442 // 04443 // Parsing 04444 XERCES_CPP_NAMESPACE::DOMDocument * doc = 0; 04445 try { 04446 04447 doc = parser->parseURI( m_localFileName.c_str() ); 04448 04449 } 04450 catch( const OutOfMemoryException&) { 04451 04452 doc = 0; 04453 04454 m_parent->sendMsg( "OutOfMemoryException during parsing.", MSG_ERROR); 04455 } 04456 catch (const SAXException&) { 04457 04458 doc = 0; 04459 04460 m_parent->sendMsg( "SAXException during parsing.", MSG_ERROR); 04461 } 04462 catch (const XMLException& e) 04463 { 04464 doc = 0; 04465 04466 smart_Ch e_msg = XMLString::transcode( e.getMessage()); 04467 m_parent->sendMsg( (std::string( "XMLException during parsing. Message: ") + e_msg).c_str(), MSG_ERROR); 04468 } 04469 catch (const DOMException& e) 04470 { 04471 doc = 0; 04472 04473 const unsigned int maxChars = 2047; 04474 XMLCh errText[maxChars + 1]; 04475 04476 if( DOMImplementation::loadDOMExceptionMsg( e.code, errText, maxChars)) 04477 { 04478 smart_Ch e_msg = XMLString::transcode( errText); 04479 m_parent->sendMsg( (std::string( "DOMException during parsing. Message: ") + e_msg).c_str(), MSG_ERROR); 04480 } 04481 else 04482 { 04483 smart_Ch e_msg = XMLString::transcode( e.getMessage()); 04484 m_parent->sendMsg( (std::string( "DOMException during parsing. Message: ") + e_msg).c_str(), MSG_ERROR); 04485 } 04486 } 04487 catch (...) { 04488 04489 doc = 0; 04490 04491 m_parent->sendMsg( "GenException during parsing.", MSG_ERROR); 04492 } 04493 04494 if( doc == NULL ) 04495 { 04496 m_parent->sendMsg( "DOMDocument pointer is NULL. Parsing of signature file failed.", MSG_ERROR); 04497 HR_THROW(E_FILEOPEN); 04498 } 04499 04500 // 04501 // The updating process itself: 04502 try 04503 { 04504 DOMElement * doc_e = 0; 04505 try { 04506 doc_e = doc->getDocumentElement(); 04507 } 04508 catch( const XMLException& ) { doc_e = 0; } 04509 catch( const DOMException& ) { doc_e = 0; } 04510 catch( ... ) { doc_e = 0; } 04511 04512 if( doc_e == NULL) 04513 { 04514 m_parent->sendMsg( "Exception: Null document element in signature file!", MSG_ERROR); 04515 HR_THROW(E_FILEOPEN); 04516 } 04517 04518 const XMLCh* x_users = ParserLiterals::Signer::users; 04519 ASSERT( XMLString::equals( x_users, doc_e->getTagName())); 04520 04521 const XMLCh* x_user = ParserLiterals::Signer::user; 04522 04523 DOMNodeList *uss = doc_e->getElementsByTagName( x_user); 04524 04525 const XMLCh* x_name = ParserLiterals::Signer::name; 04526 const XMLCh* x_since= ParserLiterals::Signer::since; 04527 const XMLCh* x_until= ParserLiterals::Signer::until; 04528 const XMLCh* x_empty= ParserLiterals::empty; 04529 const XMLCh* x_newln= ParserLiterals::newln; 04530 04531 smart_XMLCh x_time = XMLString::transcode( (LPCTSTR) p_entry.m_time.Format( _T("[%Y-%m-%d %H:%M:%S]"))); 04532 smart_XMLCh x_username = XMLString::transcode( p_entry.m_username.c_str()); 04533 04534 bool found_already = false; 04535 int len = (int) uss->getLength(); 04536 for( int i = 0; i < len; ++i) 04537 { 04538 DOMNode * node = uss->item(i); 04539 DOMElement* us = (DOMElement*) node; // user 04540 04541 smart_Ch name = XMLString::transcode( us->getAttribute( x_name)); 04542 04543 if( 0 == stricmp( name, p_entry.m_username.c_str())) // user info found 04544 { 04545 if( found_already) // this is the 2nd entry with that username 04546 { 04547 doc_e->removeChild( node); 04548 continue; 04549 } 04550 04551 // update accordingly 04552 if( p_in) // sign on 04553 { 04554 // found: already signed in 04555 // update this element 04556 us->setAttribute( x_since, x_time); 04557 us->setAttribute( x_until, x_empty); 04558 found_already = true; // no need for adding a new entry 04559 } 04560 else // sign off 04561 { 04562 // if entry is removed: 04563 //doc_e->removeChild( node); 04564 04565 // update the logoff attribute 04566 us->setAttribute( x_until, x_time); 04567 found_already = true; 04568 } 04569 } 04570 } 04571 04572 // if this is the first time the user logs in (entry not found yet): 04573 if( !found_already && p_in) 04574 { 04575 if( len == 0) // first ever user 04576 { 04577 DOMText* ntxt = doc->createTextNode( x_newln); 04578 doc_e->appendChild( ntxt); 04579 } 04580 04581 DOMElement *nch = doc->createElement( x_user); 04582 nch->setAttribute( x_name , x_username); 04583 nch->setAttribute( x_since, x_time); 04584 nch->setAttribute( x_until, x_empty); 04585 doc_e->appendChild( nch); 04586 04587 DOMText* ntxt = doc->createTextNode( x_newln); 04588 doc_e->appendChild( ntxt); 04589 } 04590 04591 } 04592 catch(...) 04593 { 04594 if( parser) delete parser; 04595 m_parent->sendMsg( "Exception during signature file update!", MSG_ERROR); 04596 04597 HR_THROW(E_FILEOPEN); 04598 } 04599 04600 // 04601 // do a DOM save as follows: 04602 try 04603 { 04604 smart_XMLCh x_filenm = XMLString::transcode( m_localFileName.c_str()); 04605 XMLFormatTarget* outfile = new LocalFileFormatTarget( x_filenm); 04606 DOMLSOutput* theOutput = domimpl->createLSOutput(); 04607 theOutput->setByteStream(outfile); 04608 04609 DOMLSSerializer* writer = domimpl->createLSSerializer(); 04610 if( writer && writer->getDomConfig()->canSetParameter( XMLUni::fgDOMXMLDeclaration, false)) 04611 writer->getDomConfig()->setParameter( XMLUni::fgDOMXMLDeclaration, false); 04612 04613 04614 04615 writer->write( doc, theOutput ); 04616 delete outfile; 04617 delete writer; 04618 theOutput->release(); 04619 // delete the parser object 04620 delete parser; 04621 } 04622 catch(...) 04623 { 04624 if( parser) delete parser; 04625 m_parent->sendMsg( "DOMWriter exception during signature file update!", MSG_ERROR); 04626 04627 04628 HR_THROW(E_FILEOPEN); 04629 } 04630 } 04631 04632 SignManager::SignFileDataVec SignManager::getUserData() 04633 { 04634 SignFileDataVec res; 04635 04636 DOMLSParser * parser = m_parent->getFreshParser( "SignatureFileAnalyzer"); 04637 04638 ASSERT( parser != NULL ); 04639 if( !parser) 04640 { 04641 m_parent->sendMsg( "Exception: Could not create parser!", MSG_ERROR); 04642 return res; 04643 } 04644 04645 try { 04646 XERCES_CPP_NAMESPACE::DOMDocument * doc = parser->parseURI( m_localFileName.c_str()); 04647 if( doc == NULL ) 04648 { 04649 m_parent->sendMsg( "Exception: Could not parse signature file!", MSG_ERROR); 04650 HR_THROW(E_FILEOPEN); 04651 } 04652 04653 DOMElement * doc_e = doc->getDocumentElement(); 04654 if( doc_e == NULL) 04655 { 04656 m_parent->sendMsg( "Exception: Null document element in signature file!", MSG_ERROR); 04657 HR_THROW(E_FILEOPEN); 04658 } 04659 04660 const XMLCh* x_users = ParserLiterals::Signer::users; 04661 ASSERT( XMLString::equals( x_users, doc_e->getTagName())); 04662 04663 const XMLCh* x_user = ParserLiterals::Signer::user; 04664 const XMLCh* x_name = ParserLiterals::Signer::name; 04665 const XMLCh* x_since= ParserLiterals::Signer::since; 04666 const XMLCh* x_until= ParserLiterals::Signer::until; 04667 04668 DOMNodeList *uss = doc_e->getElementsByTagName( x_user); 04669 04670 for( int i = 0; i < (int) uss->getLength(); ++i) 04671 { 04672 DOMNode * node = uss->item(i); 04673 DOMElement* us = (DOMElement*) node; // user 04674 04675 smart_Ch name = XMLString::transcode( us->getAttribute( x_name)); 04676 smart_Ch since= XMLString::transcode( us->getAttribute( x_since)); 04677 smart_Ch until= XMLString::transcode( us->getAttribute( x_until)); 04678 04679 SignFileData data = SignFileData(std::string(name), std::string(since), std::string(until)); 04680 if( std::find( res.begin(), res.end(), data) == res.end()) // not found 04681 res.push_back( data); 04682 04683 } 04684 04685 // delete the parser object 04686 delete parser; 04687 04688 } catch(...) { 04689 if( parser) delete parser; 04690 m_parent->sendMsg( "Parser exception during singature file analysis!", MSG_ERROR); 04691 } 04692 04693 return res; 04694 } 04695 04696 /* ****************************************************************************** */ 04697 /* C L A S S P R O T E C T L I S T */ 04698 /* ****************************************************************************** */ 04699 04700 void ProtectList::setParent( CCoreXmlFile* p_parent) 04701 { 04702 PublicStorage::setParent( p_parent); 04703 04704 m_fileName = getProtListFileName( userName()); 04705 m_localFileName = m_parent->m_folderPath + "\\" + HelperFiles::sessionFolderName + "\\" + HelperFiles::protFileName + userName() + HelperFiles::protFileExt; 04706 04707 PublicStorage::init( "<objects/>"); 04708 } 04709 04710 std::string ProtectList::getProtListFileName( const std::string& p_username) 04711 { 04712 return std::string( HelperFiles::sessionFolderName) + "/" + HelperFiles::protFileName + p_username + HelperFiles::protFileExt; 04713 } 04714 04715 void ProtectList::onLoad() 04716 { 04717 ASSERT( m_parent); 04718 if( !m_parent) return; 04719 if(!isSV()) return; 04720 04721 try 04722 { 04723 acquireFile(); 04724 // those items which are older than the last sync time for all users 04725 // can be removed from the list, the last sync time is the earliest of 04726 // all currently active logins 04727 purgeProtList( m_parent->lastSyncTimeForAllUsers()); 04728 releaseFile(); 04729 } catch(hresult_exception&) { 04730 m_parent->sendMsg( "Could not purge old items from protection loglist.", MSG_ERROR); 04731 } 04732 } 04733 04734 void ProtectList::onAborted() 04735 { 04736 if(!isSV()) return; 04737 clearProtList(); 04738 } 04739 04740 void ProtectList::onCommited() 04741 { 04742 if(!isSV()) return; 04743 if( !needed()) return; 04744 04745 try { 04746 acquireFile(); // this file is better checkedin after modifications, because other 04747 // users strictly need to see the last (most up to date) version of it 04748 04749 writeProtList(); // much costly than text based writeProtLisp() 04750 04751 releaseFile(); 04752 04753 clearProtList(); 04754 04755 } catch(hresult_exception&) { 04756 m_parent->sendMsg( "Could not save <item> entries to my loglist.", MSG_ERROR); 04757 } 04758 } 04759 04760 void ProtectList::addEntry( const ProtectEntry& p_pe) 04761 { 04762 if(!isSV()) return; 04763 04764 m_list.push_back( p_pe); 04765 } 04766 04767 bool ProtectList::needed() 04768 { 04769 return !m_list.empty(); 04770 } 04771 04772 void ProtectList::clearProtList() 04773 { 04774 // called when Abort or Commit happens 04775 m_list.clear(); // clears the whole list 04776 } 04777 04778 // let's just dump items into the file, without the enclosing 'objects' tag 04779 // a text based, fast approach 04780 void ProtectList::writeProtLisp() 04781 { 04782 FILE * f = fopen( (m_localFileName+"3").c_str(), "a+b"); 04783 if( !f) return; 04784 04785 // create <items> for all entries found in m_list 04786 for( unsigned int i = 0; i < m_list.size(); ++i) 04787 { 04788 string gd; 04789 guid2str( m_list[i].m_guid, gd ); 04790 04791 fprintf( f, "\r\n<item gd=\"%s\" oper=\"%s\" when=\"%s\"/>", gd.c_str(), OpCodeStr[ m_list[i].m_op], (LPCTSTR) m_list[i].m_time.Format( _T("[%Y-%m-%d %H:%M:%S]"))); 04792 } 04793 04794 fclose(f); 04795 } 04796 04797 void ProtectList::writeProtList() 04798 { 04799 DOMImplementationLS * domimpl = NULL; 04800 DOMLSParser * parser = NULL; 04801 04802 try { 04803 04804 parser = m_parent->getFreshParser( "ProtectionListWriter", &domimpl); 04805 04806 if( !domimpl || !parser) 04807 { 04808 m_parent->sendMsg( "Exception: Could not create parser!", MSG_ERROR); 04809 HR_THROW(E_FILEOPEN); 04810 } 04811 04812 XERCES_CPP_NAMESPACE::DOMDocument * doc = parser->parseURI( m_localFileName.c_str() ); 04813 if( doc == NULL ) 04814 { 04815 m_parent->sendMsg( "Exception: Could not parse file '" + m_localFileName + "'!", MSG_ERROR); 04816 HR_THROW(E_FILEOPEN); 04817 } 04818 04819 DOMElement * doc_e = doc->getDocumentElement(); 04820 if( doc_e == NULL) 04821 { 04822 m_parent->sendMsg( "Exception: Null document element in file '" + m_localFileName + "'!", MSG_ERROR); 04823 HR_THROW(E_FILEOPEN); 04824 } 04825 04826 const XMLCh* ITEM_xiteral = ParserLiterals::Protector::item; 04827 const XMLCh* WHEN_xiteral = ParserLiterals::Protector::when; 04828 const XMLCh* OPER_xiteral = ParserLiterals::Protector::oper; 04829 const XMLCh* GUID_xiteral = ParserLiterals::Protector::gd; 04830 const XMLCh* OBJS_xiteral = ParserLiterals::Protector::objects; 04831 04832 ASSERT( XMLString::equals( OBJS_xiteral, doc_e->getTagName())); 04833 04834 DOMNodeList *uss = doc_e->getElementsByTagName( ITEM_xiteral); 04835 04836 // create <items> for all entries found in m_list 04837 for( unsigned int i = 0; i < m_list.size(); ++i) 04838 { 04839 string gd; 04840 guid2str( m_list[i].m_guid, gd ); 04841 04842 smart_XMLCh val_gd = XMLString::transcode( gd.c_str()); 04843 smart_XMLCh val_tm = XMLString::transcode( (LPCTSTR) m_list[i].m_time.Format( _T("[%Y-%m-%d %H:%M:%S]"))); 04844 smart_XMLCh val_op = XMLString::transcode( OpCodeStr[ m_list[i].m_op]); 04845 smart_XMLCh x_newln= XMLString::transcode( "\n"); 04846 04847 DOMElement *nch = doc->createElement( ITEM_xiteral); 04848 nch->setAttribute( GUID_xiteral, val_gd); 04849 nch->setAttribute( WHEN_xiteral, val_tm); 04850 nch->setAttribute( OPER_xiteral, val_op); 04851 04852 doc_e->appendChild( nch); 04853 04854 DOMText* ntxt = doc->createTextNode( x_newln); // as fprintf(f, "\n"); 04855 doc_e->appendChild( ntxt); 04856 } 04857 04858 //do a DOM save as follows: 04859 smart_XMLCh x_fname = XMLString::transcode( m_localFileName.c_str()); 04860 XMLFormatTarget* outfile = new LocalFileFormatTarget( x_fname); 04861 DOMLSOutput* theOutput = domimpl->createLSOutput(); 04862 theOutput->setByteStream(outfile); 04863 04864 DOMLSSerializer * writer = domimpl->createLSSerializer(); 04865 04866 04867 if( writer->getDomConfig()->canSetParameter( XMLUni::fgDOMWRTDiscardDefaultContent, true)) 04868 writer->getDomConfig()->setParameter( XMLUni::fgDOMWRTDiscardDefaultContent, true); 04869 if( writer->getDomConfig()->canSetParameter( XMLUni::fgDOMXMLDeclaration, false)) 04870 writer->getDomConfig()->setParameter( XMLUni::fgDOMXMLDeclaration, false); 04871 04872 doc->normalizeDocument(); 04873 04874 writer->write(doc, theOutput); 04875 04876 delete outfile; 04877 delete writer; 04878 theOutput->release(); 04879 // delete the parser object 04880 delete parser; 04881 } 04882 catch(...) 04883 { 04884 m_parent->sendMsg( "Exception while writing protection file '" + m_localFileName + "'!", MSG_ERROR); 04885 if( parser) delete parser; 04886 return; 04887 } 04888 } 04889 04890 void ProtectList::purgeProtList( CTime& p_lastSyncTime) 04891 { 04892 DOMImplementationLS * domimpl = NULL; 04893 DOMLSParser * parser = NULL; 04894 04895 try { 04896 04897 parser = m_parent->getFreshParser( "ProtectionListPurger", &domimpl); 04898 04899 if( !domimpl || !parser) 04900 { 04901 m_parent->sendMsg( "Exception: Could not create parser!", MSG_ERROR); 04902 HR_THROW(E_FILEOPEN); 04903 } 04904 04905 XERCES_CPP_NAMESPACE::DOMDocument * doc = parser->parseURI( m_localFileName.c_str() ); 04906 if( doc == NULL ) 04907 { 04908 m_parent->sendMsg( "Exception: Could not parse file '" + m_localFileName + "'!", MSG_ERROR); 04909 HR_THROW(E_FILEOPEN); 04910 } 04911 04912 DOMElement * doc_e = doc->getDocumentElement(); 04913 if( doc_e == NULL) 04914 { 04915 m_parent->sendMsg( "Exception: Null document element in file '" + m_localFileName + "'!", MSG_ERROR); 04916 HR_THROW(E_FILEOPEN); 04917 } 04918 04919 const XMLCh* ITEM_xiteral = ParserLiterals::Protector::item; 04920 const XMLCh* WHEN_xiteral = ParserLiterals::Protector::when; 04921 const XMLCh* OBJS_xiteral = ParserLiterals::Protector::objects; 04922 const XMLCh* x_newline = ParserLiterals::newln; 04923 04924 ASSERT( XMLString::equals( OBJS_xiteral, doc_e->getTagName())); 04925 04926 DOMNodeList *uss = doc_e->getElementsByTagName( ITEM_xiteral); 04927 04928 // handle outdated items 04929 bool outdated; 04930 04931 for( int i = (int) uss->getLength() - 1; i >= 0; --i) 04932 { 04933 DOMNode * node = uss->item(i); 04934 DOMElement* us = (DOMElement*) node; // user 04935 04936 outdated = false; 04937 04938 smart_Ch when = XMLString::transcode( us->getAttribute( WHEN_xiteral)); 04939 04940 int y(-1), M(-1), d(-1), h(-1), m(-1), s(-1); 04941 if( 6 == sscanf( when, "[%u-%u-%u %u:%u:%u]", &y, &M, &d, &h, &m, &s)) 04942 { 04943 CTime whn(y, M, d, h, m, s); // when did happen that event 04944 if( whn < p_lastSyncTime) 04945 { 04946 outdated = true; 04947 doc_e->removeChild( node); // because of this we loop --i 04948 } 04949 } 04950 } 04951 04952 doc->normalizeDocument(); 04953 DOMElement * doc_f = doc->getDocumentElement(); 04954 if( doc_f == NULL) 04955 { 04956 m_parent->sendMsg( "Exception: Null document element in file '" + m_localFileName + "' after normalization!", MSG_ERROR); 04957 HR_THROW(E_FILEOPEN); 04958 } 04959 04960 // replace sequences of '\n' with just one 04961 DOMNodeList* list = doc_f->getChildNodes(); 04962 04963 for( int i = (int) list->getLength() - 1; i >= 0 ; --i) 04964 { 04965 DOMNode * node = list->item(i); 04966 if( node->getNodeType() == DOMNode::TEXT_NODE) 04967 { 04968 DOMText * txt = (DOMText*) node; 04969 04970 smart_Ch nlines = XMLString::transcode( txt->getData()); 04971 std::string newlines( nlines); 04972 04973 if( newlines.size() > 1 && std::string::npos == newlines.find_first_not_of( '\n')) // nothing else just '\n' characters 04974 { 04975 txt->setData( x_newline); 04976 } 04977 } 04978 } 04979 04980 //do a DOM save as follows: 04981 smart_XMLCh x_fname = XMLString::transcode( m_localFileName.c_str()); 04982 XMLFormatTarget* outfile = new LocalFileFormatTarget( x_fname); 04983 04984 DOMLSOutput* theOutput = domimpl->createLSOutput(); 04985 theOutput->setByteStream(outfile); 04986 04987 DOMLSSerializer* writer = domimpl->createLSSerializer(); 04988 04989 if( writer == NULL) 04990 { 04991 m_parent->sendMsg( "Exception: Could not create DOM Writer for '" + m_localFileName + "'!", MSG_ERROR); 04992 HR_THROW(E_FILEOPEN); 04993 } 04994 04995 if( writer->getDomConfig()->canSetParameter( XMLUni::fgDOMWRTDiscardDefaultContent, true)) 04996 writer->getDomConfig()->setParameter( XMLUni::fgDOMWRTDiscardDefaultContent, true); 04997 if( writer->getDomConfig()->canSetParameter( XMLUni::fgDOMXMLDeclaration, false)) 04998 writer->getDomConfig()->setParameter( XMLUni::fgDOMXMLDeclaration, false); 04999 doc->normalizeDocument(); 05000 05001 writer->write( doc, theOutput ); 05002 delete outfile; 05003 delete writer; 05004 05005 // delete the parser object 05006 delete parser; 05007 } 05008 catch(...) 05009 { 05010 m_parent->sendMsg( "Exception while purging protection file '" + m_localFileName + "'!", MSG_ERROR); 05011 if( parser) delete parser; 05012 return; 05013 } 05014 } 05015 05016 /* ****************************************************************************** */ 05017 /* C L A S S */ 05018 /* ****************************************************************************** */ 05019 05020 void CCoreXmlFile::protect( XmlObject * obj, OpCode oc) 05021 { 05022 // the time stamp could be aqcuired only once, when commitToDisk happens 05023 if( obj) m_protectList.addEntry( ProtectEntry( obj->m_guid, oc, CTime::GetCurrentTime())); 05024 } 05025 05026 bool CCoreXmlFile::findOnProtectedLists( GUID p_gd, std::string& p_scapegoatUser) 05027 { 05028 if(!isSV()) return false; 05029 05030 std::string str_gd; guid2str( p_gd, str_gd); 05031 05032 std::vector< LoggedIn> ulist = allusers(); 05033 05034 bool found = false; 05035 for( std::vector< LoggedIn>::iterator it = ulist.begin() 05036 ; !found && it != ulist.end() 05037 ; ++it) 05038 { 05039 if( it->m_nm == userName()) continue; // ignore my file 05040 // std::string fname = refreshProtectionFile( it->m_nm); // refresh my copy of this user's prot file 05041 std::string fname = ProtectList::getProtListFileName( it->m_nm ); 05042 05043 if( found = findInFile( m_folderPath + "\\" + fname, str_gd)) 05044 p_scapegoatUser = it->m_nm; 05045 } 05046 05047 return found; 05048 } 05049 05050 std::vector< LoggedIn> CCoreXmlFile::allusers() 05051 { 05052 // refreshSignFile(); 05053 refreshSessionFolder(); 05054 return getUsersFromSignFile(); 05055 } 05056 05057 /* 05058 bool CCoreXmlFile::refreshSignFile() 05059 { 05060 return refreshOneFile( HelperFiles::signFileName); 05061 } 05062 */ 05063 05064 void CCoreXmlFile::replaceUserName( const std::string& p_userName) 05065 { 05066 m_vssUser = p_userName; 05067 m_svn->replaceUserName(p_userName); 05068 } 05069 05070 std::string CCoreXmlFile::userName() 05071 { 05072 if( isSV()) 05073 { 05074 return m_vssUser; 05075 } 05076 else 05077 return ""; 05078 } 05079 05080 bool CCoreXmlFile::isSV() { return m_sourceControl == CCoreXmlFile::SC_SUBVERSION; } 05081 05082 bool CCoreXmlFile::userFilter( CTimeSpan& p_elapsed) 05083 { 05084 //return p_elapsed.GetTotalMinutes() < 60*24*2; // less than 2 days ago 05085 return true; 05086 } 05087 05088 std::vector< LoggedIn> CCoreXmlFile::getUsersFromSignFile() 05089 { 05090 std::vector< LoggedIn> res; 05091 SignManager::SignFileDataVec udata = m_signer.getUserData(); 05092 for( SignManager::SignFileDataVec::const_iterator it = udata.begin(); 05093 it != udata.end(); 05094 ++it) 05095 { 05096 //const char * date_last_logged_out = it->m_until.c_str(); 05097 char status = it->m_until == ""?'A':'I'; // if logged in its logout date is "" 05098 05099 const char * date_last_logged_in = it->m_since.c_str(); 05100 int y(-1), M(-1), d(-1), h(-1), m(-1), s(-1); 05101 if( 6 == sscanf( date_last_logged_in, "[%u-%u-%u %u:%u:%u]", &y, &M, &d, &h, &m, &s)) 05102 { 05103 CTime whn(y, M, d, h, m, s); // when did last login occur 05104 CTime now = CTime::GetCurrentTime(); 05105 CTimeSpan elapsed = now - whn; 05106 if( userFilter( elapsed)) 05107 if( std::find( res.begin(), res.end(), LoggedIn( it->m_user, status)) == res.end()) // not found 05108 res.push_back( LoggedIn( it->m_user, status)); // store its name 05109 } 05110 } 05111 return res; 05112 } 05113 05114 CTime CCoreXmlFile::lastSyncTimeForAllUsers() 05115 { 05116 // 05117 //refreshSignFile(); // not needed now, we just signed on 05118 return findEarliestLogin( 0, 0, (int) ( m_userOpts.m_purgeDelayFactor * 60)); // days, hours, minutes 05119 } 05120 05121 CTime CCoreXmlFile::findEarliestLogin( int p_nbOfDays, int p_nbOfHours, int p_nbOfMinutes) 05122 { 05123 CTime earliest = CTime::GetCurrentTime(); 05124 CTime earliest_at_most( earliest - CTimeSpan( p_nbOfDays, p_nbOfHours, p_nbOfMinutes, 0)); // no further back than p_nbOfDays days / p_nbOfHours 05125 bool avoid_limitation = earliest == earliest_at_most; // if no timespan provided we will not limit the earliest time 05126 05127 SignManager::SignFileDataVec udata = m_signer.getUserData(); 05128 for( std::vector< SignFileData>::const_iterator it = udata.begin(); 05129 it != udata.end(); 05130 ++it) 05131 { 05132 const char * date_last_logged_in = it->m_since.c_str(); 05133 const std::string &date_last_logged_out = it->m_until; 05134 int y(-1), M(-1), d(-1), h(-1), m(-1), s(-1); 05135 if( 6 == sscanf( date_last_logged_in, "[%u-%u-%u %u:%u:%u]", &y, &M, &d, &h, &m, &s)) 05136 { 05137 CTime whn(y, M, d, h, m, s); // when did last login occur 05138 if( whn < earliest && "" == date_last_logged_out) // means user is currently active 05139 earliest = whn; 05140 } 05141 } 05142 05143 // we have now the earliest login 05144 // but we might limit its range if we have been provided a proper timespan 05145 if( earliest < earliest_at_most && !avoid_limitation) 05146 earliest = earliest_at_most; 05147 05148 return earliest; 05149 } 05150 05151 void CCoreXmlFile::refreshSessionFolder() 05152 { 05153 if( isSV() && m_needsSessionRefresh) 05154 { 05155 updateSVN( HelperFiles::sessionFolderName ); 05156 m_needsSessionRefresh = false; 05157 } 05158 } 05159 05160 /* 05161 bool CCoreXmlFile::refreshOneFile( const std::string& p_fname) 05162 { 05163 if( isSV()) 05164 { 05165 updateSVN( p_fname); 05166 } 05167 return false; 05168 } 05169 05170 05171 std::string CCoreXmlFile::refreshProtectionFile( const std::string& p_username) 05172 { 05173 std::string fname = ProtectList::getProtListFileName( p_username); 05174 refreshOneFile( fname); 05175 return fname; 05176 } 05177 05178 */ 05179 05180 bool CCoreXmlFile::findInFile( const std::string& fname, const std::string& str_gd) 05181 { 05182 std::ifstream g; 05183 g.open( fname.c_str(), std::ios_base::in| std::ios_base::binary); 05184 if( !g.is_open()) return false; 05185 char buff[1024]; 05186 const char * to_find = str_gd.c_str();// why won't work this? (" gd=\"" + str_gd + "\"").c_str(); 05187 const char * to_fin2 = " oper=\""; 05188 char oper_buff[100]; 05189 bool found = false; 05190 while( !g.eof() && !found) 05191 { 05192 g.getline( &buff[0], 1024, '\n'); 05193 if( strlen( buff) < 1023) 05194 { 05195 //if( g.rdstate() != 0) 05196 // g.clear(); 05197 05198 found = 0 != strstr( buff, to_find); 05199 if( found) 05200 { 05201 char * oper = strstr( buff, to_fin2); 05202 if( strlen(oper) < 100) 05203 sscanf( oper, " oper=\"%s\" ", &oper_buff); 05204 } 05205 } 05206 else 05207 ASSERT(0); 05208 } 05209 g.close(); 05210 05211 return found; 05212 } 05213 05214 bool CCoreXmlFile::makeSureFileExistsInVerSys( const std::string& p_fname, const std::string& p_initialcontent, bool p_needsLock /*= true*/) 05215 { 05216 std::string fulllocalfname = m_folderPath + "\\" + p_fname; 05217 bool found = false; 05218 05219 try 05220 { 05221 if( isSV()) 05222 { 05223 found = FileHelp::fileExist( fulllocalfname) && isVersionedInSVN( fulllocalfname); 05224 } 05225 05226 if( !found) 05227 { 05228 FILE * f = fopen( fulllocalfname.c_str(), "w"); 05229 if( !f) throw hresult_exception(E_FAIL); 05230 05231 fprintf( f, "%s", p_initialcontent.c_str()); 05232 fclose( f); 05233 05234 // add newly created file 05235 if( isSV()) 05236 { 05237 //bool ok = isVersionedInSVN( fulllocalfname); 05238 bool sc_add = true; 05239 bool sc_pro = true; 05240 bool sc_com = true; 05241 sc_add = addSVN( fulllocalfname); 05242 if( p_needsLock) // apply lock attribute except if directed otherwise 05243 sc_pro = lockablePropertySVN( fulllocalfname); 05244 sc_com = commitSVN( fulllocalfname, std::string("auto: makeSureFileExistsInVerSys()"), true); 05245 05246 if( !( sc_add && sc_pro && sc_com)) 05247 { 05248 if( !sc_add) sendMsg( "Could not add file " + fulllocalfname, MSG_ERROR); 05249 else if( !sc_pro) sendMsg( "Could not apply lockable property for file " + fulllocalfname, MSG_ERROR); 05250 else if( !sc_com) sendMsg( "Could not commit file " + fulllocalfname, MSG_ERROR); 05251 throw hresult_exception(E_FAIL); 05252 } 05253 } 05254 05255 found = true; 05256 } 05257 } 05258 catch( hresult_exception& e) 05259 { 05260 char buff[200]; sprintf( buff, "Could not get \"%s\" file from source control. Exception code: 0x%x", fulllocalfname.c_str(), e.hr); 05261 sendMsg( buff, MSG_ERROR); 05262 return false; 05263 } 05264 return found; 05265 } 05266 05267 void CCoreXmlFile::getLatestVersion() 05268 { 05269 if( isSV()) 05270 { 05271 bool succ = m_svn->getLatest(m_folderPath); 05272 if (!succ) { 05273 AfxMessageBox( "Could not get latest version from server!"); 05274 HR_THROW( E_UNKNOWN_STORAGE); // furthermore will be silently handled 05275 } 05276 } 05277 } 05278 05279 void CCoreXmlFile::checkInAll() 05280 { 05281 AFX_MANAGE_STATE(AfxGetStaticModuleState( )); 05282 05283 if( !m_userOpts.m_defCheckInOnSave && AfxMessageBox( "Project saved. Keep modified files checked out, thus hold locks explicitly?", MB_YESNO ) == IDYES ) // easier question??? 05284 checkInAll( true ); // keep files checked out 05285 else 05286 { 05287 if( m_userOpts.m_defCheckInOnSave) 05288 sendMsg( std::string( "ACCELERATION: No file is left checked out based on policy configured."), MSG_INFO); 05289 05290 checkInAll( false ); // check in 05291 } 05292 } 05293 05294 void CCoreXmlFile::checkInAll( bool keepCheckedOut ) 05295 { 05296 if( isSV()) 05297 {// sometimes there is nothing to commit here, let's try for a while to not execute this 05298 // if keepCheckedOut => use --no-unlock: won't unlock the targets 05299 //bool sc_com = commitSVN( m_folderPath, true, keepCheckedOut); 05300 //if( !sc_com) 05301 { 05302 //sendMsg( "Nothing committed or could not commit all in directory " + m_folderPath, MSG_WARNING); 05303 } 05304 std::string comment; 05305 CCommitDialog cDlg; 05306 if (m_userOpts.m_autoCommit) { 05307 comment = "AutoCommit"; 05308 } else if (cDlg.DoModal() == IDOK) { 05309 CT2CA comment_str(cDlg.m_comment); 05310 comment = comment_str; 05311 } 05312 if( m_userOpts.m_useBulkCommit) 05313 { 05314 bool sc_com = bulkCommitSVN( m_folderPath, std::string(comment), keepCheckedOut); 05315 if( !sc_com) 05316 { 05317 sendMsg( "Nothing committed or could not commit all in directory " + m_folderPath, MSG_WARNING); 05318 } 05319 } 05320 } 05321 } 05322 05323 void CCoreXmlFile::createNonversioned() 05324 { 05325 int succ = CreateDirectory( m_folderPath.c_str(), NULL); 05326 05327 if( succ) 05328 succ = createHashedFolders(); 05329 05330 if( !succ) 05331 { 05332 sendMsg( "Exception: Could not create initial directory structure!", MSG_ERROR); 05333 AfxMessageBox( "Could not create initial directory structure"); 05334 HR_THROW(E_FILEOPEN); 05335 } 05336 } 05337 05338 int CCoreXmlFile::createHashedFolders() 05339 { 05340 if( !m_hashFileNames) return 1; 05341 05342 int succ = CreateDirectory( m_contentPath.c_str(), NULL); 05343 05344 DirSupplier ds( m_hashFileNames, m_hashVal); 05345 if( m_hashVal == 2) 05346 { 05347 for( Dir256Iterator it = ds.begin256(); succ && it != ds.end256(); ++it) 05348 succ = CreateDirectory( (m_contentPath + "\\" + *it).c_str(), NULL); 05349 } 05350 else if( m_hashVal == 5) 05351 { 05352 for( Dir16Iterator it = ds.begin16(); succ && it != ds.end16(); ++it) 05353 { 05354 succ = CreateDirectory( (m_contentPath + "\\" + *it).c_str(), NULL); 05355 for( Dir256Iterator jt = ds.begin256(); succ && jt != ds.end256(); ++jt) 05356 succ = CreateDirectory( (m_contentPath + "\\" + *it + "\\" + *jt).c_str(), NULL); 05357 } 05358 } 05359 05360 return succ; 05361 } 05362 05363 void CCoreXmlFile::commitHashedFolders() 05364 { 05365 if( !m_hashFileNames) return; 05366 05367 if( m_hashVal == 5) 05368 { 05369 // we will create 4096 dirs like 0/00, 0/01, ... 0/ff, 1/00, 1/01, ... f/ff 05370 const char ans[] = "0123456789abcdef"; 05371 char lev1[2] = { 'x', 0}; 05372 char lev2[5] = { 'y', '\\', 'z', 't', 0}; 05373 int err = 0; 05374 05375 for( short i = 0; !err && i != 16; ++i) 05376 { 05377 lev1[0] = ans[i]; // form a name 05378 socoAdd( lev1, true /*=recursive*/); 05379 socoCommit( lev1, std::string("auto: commitHashedFolders()"), true); 05380 } 05381 } 05382 else if( m_hashVal == 2) 05383 { 05384 // we will create 256 dirs like 00, 01, ..ff 05385 const char ans[] = "0123456789abcdef"; 05386 char lev[3] = { 'z', 't', 0}; 05387 int err = 0; 05388 05389 05390 // add and commit 05391 for( short i = 0; !err && i != 16; ++i) 05392 { 05393 lev[0] = ans[i]; // form a name 05394 for( short j = 0; !err && j != 16; ++j) 05395 { 05396 lev[1] = ans[j]; 05397 socoAdd( lev, true /*=recursive*/); 05398 socoCommit( lev, std::string("auto: commitHashedFolders()"), true); 05399 } 05400 } 05401 } 05402 } 05403 05404 void CCoreXmlFile::socoAdd ( const std::string& p_path, bool p_recursive) 05405 { 05406 if( isSV()) 05407 { 05408 addSVN( p_path, p_recursive); 05409 } 05410 else 05411 { 05412 // nop 05413 } 05414 } 05415 05416 void CCoreXmlFile::socoCommit( const std::string& p_path, const std::string& p_comment, bool p_initial) 05417 { 05418 if( isSV()) 05419 { 05420 bool sc = commitSVN( p_path, p_comment, p_initial /*initial commit*/); 05421 if( !sc) 05422 { 05423 sendMsg( "Could not commit " + p_path + " into versioning system.", MSG_ERROR); 05424 } 05425 } 05426 else 05427 { 05428 // nop 05429 } 05430 } 05431 05432 05433 void CCoreXmlFile::testSubversion() 05434 { 05435 //if( IDNO == AfxMessageBox( "Would you like to skip the test of svn connection?", MB_YESNO)) 05436 //{ 05437 // std::string tst, last_author, curr_owner; 05438 // bool sc = infoSVN( m_svnUrl, false /*no recursive*/, tst, last_author, std::string() /* =curr_owner*/); 05439 // if( sc) 05440 // { 05441 // AfxMessageBox( tst.c_str()); 05442 // if( last_author != m_vssUser) 05443 // AfxMessageBox( (std::string( "There is a username confusion here!\n'") + last_author + "' is told to be the last modifier of " + m_svnUrl + ", while the credentials provided indicate '" + m_vssUser + "'!").c_str()); 05444 // } 05445 // else 05446 // AfxMessageBox( "svn info command failed"); 05447 //} 05448 } 05449 05450 void CCoreXmlFile::createSubversionClientImpl() 05451 { 05452 m_svn = std::auto_ptr<HiClient>(new HiClient(m_vssUser, m_vssPassword)); 05453 m_svn->setLog(m_userOpts.m_createSvnLog, m_userOpts.m_svnLogFileName); 05454 } 05455 05456 void CCoreXmlFile::svnSetup( bool p_createOrOpen) 05457 { 05458 if( getUserCredentialInfo( 1, p_createOrOpen)) // fills m_vssUser, m_vssPassword, p_createOrOpen == requireLogin 05459 { 05460 svnSshHandling(); 05461 svnOptions(); 05462 createSubversionClientImpl(); 05463 } 05464 else 05465 { 05466 AfxMessageBox( "You did not provide login data. You may work locally but might lose synchronization with the version controlled project. You won't be able to modify read-only files.", MB_ICONEXCLAMATION ); 05467 m_sourceControl = SC_NONE; 05468 } 05469 //testSubversion(); 05470 } 05471 05472 void CCoreXmlFile::createSubversionedFolder() 05473 { 05474 m_sourceControl = SC_SUBVERSION; 05475 //m_hashInfoFound = false; 05476 05477 svnSetup( true); // true => strictly requires login data, throws if dlg is canceled 05478 // fills m_vssUser, m_vssPassword 05479 05480 if( !isVersionedInSVN( m_svnUrl, /*isDir = */true)) 05481 { 05482 sendMsg( "Exception: Location directory '" + m_svnUrl + "' does not exist on the SVN server!", MSG_ERROR); 05483 AfxMessageBox( (std::string( "Location directory '") + m_svnUrl + "' does not exist on the SVN server").c_str()); 05484 HR_THROW(E_FILEOPEN); 05485 } 05486 if( isVersionedInSVN( m_svnUrl + "/" + m_projectName, /*isDir = */true, /* suppressErrorMsg = */true)) 05487 { 05488 sendMsg( "Exception: Project '" + m_projectName + "' already found at '" + m_svnUrl + "'. Project creation aborted.", MSG_ERROR); 05489 AfxMessageBox( (std::string( "Project '") + m_projectName + "' already found at '" + m_svnUrl + "'. Project creation aborted.").c_str()); 05490 HR_THROW(E_FILEOPEN); 05491 } 05492 bool main_created = mkdirSVN( m_svnUrl, m_projectName, m_folderPath); 05493 if( !main_created) 05494 { 05495 sendMsg( "Exception: Could not create on server directory: " + m_svnUrl + "/" + m_projectName, MSG_ERROR); 05496 AfxMessageBox( (std::string( "Could not create on server directory: ") + m_svnUrl + "/" + m_projectName).c_str()); 05497 HR_THROW(E_FILEOPEN); 05498 } 05499 05500 05501 // session folder 05502 std::string sessionFolder = m_folderPath + "\\" + HelperFiles::sessionFolderName; 05503 BOOL succ = ::CreateDirectory( sessionFolder.c_str(), NULL); 05504 if( succ != TRUE) 05505 { 05506 sendMsg( "Exception: Could not create session folder: " + sessionFolder, MSG_ERROR); 05507 AfxMessageBox( (std::string( "Could not create session folder: ") + sessionFolder).c_str()); 05508 HR_THROW(E_FILEOPEN); 05509 } 05510 05511 // add session folder to server 05512 succ = addSVN( sessionFolder, true /*=recursive*/); 05513 if( !succ) { 05514 sendMsg( "Exception: Could not add session folder to server.", MSG_ERROR); 05515 AfxMessageBox( "Could not add session folder to server."); 05516 HR_THROW(E_FILEOPEN); 05517 } 05518 // hashed folder structure (optional) 05519 if( m_hashFileNames) 05520 { 05521 05522 // commit session folder (see previous comment) 05523 succ = commitSVN( sessionFolder, std::string("auto: createSubversionedFolder()"), true); 05524 if( !succ) { 05525 sendMsg( "Exception: Could not commit session folder.", MSG_ERROR); 05526 AfxMessageBox( "Could not commit session folder."); 05527 HR_THROW(E_FILEOPEN); 05528 } 05529 05530 succ = createHashedFolders(); 05531 if( !succ) { 05532 sendMsg( "Exception: Could not create initial directory structure.", MSG_ERROR); 05533 AfxMessageBox( "Could not create initial directory structure."); 05534 HR_THROW(E_FILEOPEN); 05535 } 05536 05537 // add to server 05538 succ = addSVN( m_contentPath, true /*=recursive*/); 05539 if( !succ) { 05540 sendMsg( std::string("Exception: Could not add initial directory '") + m_folderPath + "' to server.", MSG_ERROR); 05541 AfxMessageBox( "Could not add initial directory structure to server."); 05542 HR_THROW(E_FILEOPEN); 05543 } 05544 } 05545 05546 // initial commit 05547 succ = commitSVN( m_folderPath, std::string("auto: createSubversionedFolder()"), true); 05548 if( !succ) { 05549 sendMsg( "Exception: Could not commit initial directory structure.", MSG_ERROR); 05550 AfxMessageBox( "Could not commit initial directory structure."); 05551 HR_THROW(E_FILEOPEN); 05552 } 05553 } 05554 05555 void CCoreXmlFile::getSVLastCommiter(XmlObject * obj, string& user) 05556 { 05557 ASSERT( m_sourceControl == SC_SUBVERSION ); 05558 ASSERT( obj->isContainer() ); 05559 05560 std::string fname; 05561 getContainerFileName( obj, fname, true); 05562 05563 m_svn->info(fname, false, false, std::string(), user, std::string()); 05564 } 05565 05566 void CCoreXmlFile::getSVCurrentOwner(XmlObject * obj, string& user, bool& newfile) // getSVCheckOutUser 05567 { 05568 ASSERT( m_sourceControl == SC_SUBVERSION ); 05569 ASSERT( obj->isContainer() ); 05570 05571 std::string fname; 05572 getContainerFileName( obj, fname, true); 05573 05574 std::string holder; 05575 bool ret = false; 05576 05577 bool verd = m_svn->isVersioned(fname, false, true); 05578 if(verd) 05579 { 05580 newfile = false; 05581 ret = m_svn->isLockedByUser(fname, holder); 05582 } 05583 else 05584 newfile = true; 05585 05586 if(ret) 05587 { 05588 user = holder; 05589 } 05590 05591 long lInfo( 0x0), lStat( 0x0); 05592 if( !holder.empty()) 05593 { 05594 if( holder != m_vssUser) 05595 lInfo = FS_OTHER; // checked out by other user 05596 else // readonly, but we could apply a lock onto it (then we released the lock) 05597 lInfo = FS_LOCAL; // checked out by local user 05598 } 05599 else 05600 { 05601 lInfo = 0x0; // not checked out 05602 } 05603 05604 05605 bool ismodbyothers = fileModifiedByOthers( obj); // fileModifiedByOthers( fname, obj->m_lastWriteTime); 05606 05607 if( ismodbyothers) 05608 lStat = FS_MODIFIEDBYOTHERS; 05609 else if( newfile) 05610 lStat = FS_NOTYETSAVED; 05611 else 05612 lStat = 0x0; 05613 05614 setSourceControlNodes( obj, lInfo, lStat); 05615 } 05616 05617 bool CCoreXmlFile::isCheckedOutByElseSVN( const std::string& p_file) 05618 { 05619 bool versioned = m_svn->isVersioned(p_file, false, false); 05620 ASSERT(versioned); 05621 //ASSERT( m_svn->isVersioned( p_file)); 05622 std::string holder; 05623 bool locked = m_svn->isLockedByUser(p_file, holder); 05624 if(locked) 05625 { 05626 return holder != m_vssUser; // not us 05627 } 05628 return false; 05629 //return m_svn->isLockedByOthers( p_file); 05630 } 05631 05632 //void CCoreXmlFile::checkOutSVN( const std::string& p_file) 05633 //{ 05634 // // todo simplify, streamline this 05635 // if( applyLockSVN( p_file)) 05636 // { 05637 // // not checked out by somebody else 05638 // } 05639 // else 05640 // { 05641 // ASSERT( 0); 05642 // throw "checked out file"; 05643 // } 05644 //} 05645 05646 bool CCoreXmlFile::applyLockSVN( const std::string& p_file) // throws hresult_exception 05647 { 05648 bool succ = false; 05649 05650 succ = m_svn->tryLock(p_file); 05651 if(!succ) 05652 { 05653 AfxMessageBox( (p_file + " lock() returned false in applyLockSVN").c_str()); 05654 HR_THROW(E_FAIL); 05655 } 05656 05657 return succ; 05658 } 05659 05660 bool CCoreXmlFile::removeLockSVN( const std::string& p_file) 05661 { 05662 return m_svn->unLock(p_file); 05663 } 05664 05665 bool CCoreXmlFile::mkdirSVN( const std::string& p_url, const std::string& p_dirName, const std::string& p_localDestPath) 05666 { 05667 std::string dir = p_url + "/" + p_dirName; 05668 05669 bool sc = m_svn->mkDirOnServer( dir); 05670 if(!sc) return false; 05671 05672 sc = m_svn->lightCheckOut( dir, p_localDestPath); 05673 return sc; 05674 } 05675 05676 bool CCoreXmlFile::lockablePropertySVN( const std::string& p_file) 05677 { 05678 return m_svn->lockableProp(p_file); 05679 } 05680 05681 bool CCoreXmlFile::addSVN( const std::string& p_entity, bool p_recursive /*= false*/) 05682 { 05683 return m_svn->add( p_entity, p_recursive); 05684 } 05685 05686 // 05687 // IDL: UseTheseStrings( [in] short size, [in, out, size_is(size)] BSTR names[]); 05688 05689 HRESULT UseTheseStrings( short size, BSTR names[]) 05690 { 05691 for (int i = 0; i < size; ++i) { 05692 CW2A name(names[i]); 05693 MessageBox(NULL, name, "Msg", MB_OK); 05694 } 05695 return S_OK; 05696 } 05697 05698 void CCoreXmlFile::findAllRwObjs( const std::string& p_folderPath, std::vector< std::string>& rw_file_vec) 05699 { 05700 for( XmlObjVecIter it=m_objects.begin(); it!=m_objects.end(); ++it ) 05701 { 05702 XmlObject * obj = (*it); 05703 //if( obj->isContainer() && obj->m_loaded ) 05704 // writeXMLFile( obj ); 05705 if( !obj->isContainer() ) 05706 continue; 05707 05708 std::string fileName; 05709 getContainerFileName( obj, fileName); 05710 05711 // we wish we could predict the time the file will be closed 05712 // because that will become the file's 'Modified At' attribute 05713 // the obj->m_lastWriteTime needs to reflect exactly this time 05714 bool f_existed = false; 05715 if( FileHelp::isFileReadOnly2( fileName, &f_existed)) 05716 { 05717 continue; // file exists, is read-only, no chance of writing into it 05718 // it also means there was no change 05719 } 05720 05721 rw_file_vec.push_back( fileName); 05722 } 05723 } 05724 05725 bool CCoreXmlFile::bulkCommitSVN( const std::string& p_dir, const std::string& p_comment, bool p_noUnlock /* = false*/) // noUnlock <==> keeplocked 05726 { 05727 bool res = m_svn->commitAll(p_dir, p_comment, p_noUnlock); 05728 if( !p_noUnlock) // if noUnlock was not requested, then a file should be unlocked after commit 05729 // except, when it was not changed: in this case it needs a manual unlock 05730 { 05731 // find all 'rw' files, those need to be unlocked 05732 //std::vector< std::string> rwfiles; 05733 //findAllRwObjs( p_dir, rwfiles); 05734 05735 //if( 0 < rwfiles.size()) 05736 //{ 05737 // VARIANT var_arr; 05738 // fillUpVariantArray( rwfiles, &var_arr); 05739 05740 // VARIANT_BOOL succ_vt; 05741 // m_comSvn->BulkUnLock( var_arr, &succ_vt); 05742 //} 05743 // the approach above does not work, because Client::sub_unlock will 05744 // not unlock several files at once, even though its parameter Target 05745 // would allow this. 05746 // 05747 // we will unlock files one by one: 05748 std::string fileName; 05749 for( XmlObjVecIter it=m_objects.begin(); it!=m_objects.end(); ++it ) 05750 { 05751 if( !(*it)->isContainer() ) 05752 continue; 05753 05754 getContainerFileName( *it, fileName); 05755 05756 bool f_existed = false; 05757 if( FileHelp::isFileReadOnly2( fileName, &f_existed)) 05758 continue; // file exists, is read-only, means no lock on it 05759 05760 // unlock one file at a time 05761 // FIXME: fails for newly-added files when the commit fails 05762 bool succ = m_svn->unLock(fileName); 05763 if(!succ) 05764 AfxMessageBox( "Commit/Unlock pair failed"); 05765 } 05766 } 05767 return true; 05768 } 05769 05770 bool CCoreXmlFile::commitSVN( const std::string& p_dirOrFile, const std::string& p_comment, bool p_initialCommit /* = false*/, bool p_noUnlock /* = false*/) // noUnlock <==> keeplocked 05771 { 05772 bool sc = m_svn->commitAll( p_dirOrFile, p_comment, p_noUnlock); 05773 // if noUnlock was not requested, then a file should be unlocked after commit 05774 // except, when it was not changed: in this case it needs a manual unlock 05775 if( !sc && !p_noUnlock) 05776 { 05777 if( FileHelp::isFile( p_dirOrFile) && !FileHelp::isFileReadOnly( p_dirOrFile)) 05778 { 05779 bool succ = m_svn->unLock( p_dirOrFile); 05780 if (succ) 05781 { 05782 sc = true; 05783 } 05784 else 05785 { 05786 AfxMessageBox("Commit/Unlock pair failed"); 05787 } 05788 } 05789 } 05790 return sc; 05791 } 05792 05793 bool CCoreXmlFile::updateSVN( const std::string& p_dirOrFile) 05794 { 05795 return m_svn->getLatest( p_dirOrFile); 05796 } 05797 05798 bool CCoreXmlFile::isVersionedInSVN( const std::string& p_file, bool p_isADir /*= false*/, bool p_suppressErrorMsg /*=false*/) 05799 { 05800 return m_svn->isVersioned( p_file, p_isADir, p_suppressErrorMsg); 05801 } 05802 05803 bool CCoreXmlFile::infoSVN( const std::string& p_url, bool p_recursive, std::string& p_resultMsg, std::string& p_author, std::string& p_holder) 05804 { 05805 return m_svn->info(p_url, p_recursive, true, p_resultMsg, p_author, p_holder); 05806 } 05807 05808 void CCoreXmlFile::showUsedFiles( XmlObjSet& containers, bool p_latentMessage /* = false */ ) 05809 { 05810 if(isSV()) 05811 { 05812 CFilesInUseDetailsDlg dlg( 0, p_latentMessage); 05813 char buf[300]; 05814 XmlObjSet::iterator it; 05815 for( it=containers.begin(); it!=containers.end(); ++it ) 05816 { 05817 string user; bool nfile; 05818 if( p_latentMessage) // info about latently changed files 05819 { 05820 getSVLastCommiter( *it, user); 05821 } 05822 else // info about owned files 05823 { 05824 getSVCurrentOwner( *it, user, nfile); // to handle when nfile is true 05825 } 05826 05827 if( user.size() > 0 ) 05828 { 05829 string name, type; 05830 getContainerName( *it, name, type ); 05831 sprintf( buf, "%s\t%s (%s)", user.c_str(), name.c_str(), type.c_str() ); 05832 dlg.m_fileList.push_back( buf ); 05833 } 05834 else dlg.m_fileList.push_back( "A file not yet found in the Versioning System"); // by zolmol 05835 } 05836 dlg.DoModal(); 05837 } 05838 else 05839 { 05840 AfxMessageBox( "No detailed information available." ); 05841 } 05842 } 05843 05844 void CCoreXmlFile::setSourceControlNodes( XmlObject * container, long lInfo, long lStat) 05845 { 05846 ASSERT( container->isContainer() ); 05847 05848 AttribMapIter itfs = container->m_attributes.find( ATTRID_FILESTATUS); 05849 if( itfs != container->m_attributes.end()) 05850 { 05851 ASSERT( itfs->second->getType() == VALTYPE_LONG); 05852 XmlAttrLong * along = (XmlAttrLong*) itfs->second; 05853 along->m_value = lInfo + lStat; 05854 } 05855 } 05856 05857 void CCoreXmlFile::whoControlsThis( XmlObject * container /*= 0*/) 05858 { 05859 if( !container) return; 05860 ASSERT( container->isContainer() ); 05861 05862 if(isSV()) 05863 { 05864 std::string user, nm, msg; 05865 bool newfile = false; 05866 05867 getSVCurrentOwner( container, user, newfile ); // does a status info refresh too 05868 05869 AttribMapIter itnm = container->m_attributes.find( ATTRID_NAME); 05870 if( itnm != container->m_attributes.end()) 05871 itnm->second->toString( nm); 05872 //nm = makelink( container); 05873 05874 if( newfile) 05875 msg = "Container \"" + nm + "\" is not yet saved into the repository."; 05876 else if( user.empty()) 05877 msg = "Container \"" + nm + "\" is not held exclusively."; 05878 else 05879 msg = "Container \"" + nm + "\" is held exclusively by \"" + user + "\""; 05880 05881 AfxMessageBox( msg.c_str(), MB_ICONINFORMATION); 05882 //bool ismodbyothers = fileModifiedByOthers( container); 05883 } 05884 else 05885 AfxMessageBox( "Container is not held exclusively since the project is not under sourcecontrol."); 05886 } 05887 05888 void CCoreXmlFile::updateSourceControlInfo( XmlObject * container ) 05889 { 05890 ASSERT( container->isContainer() ); 05891 05892 if( isSV()) 05893 { 05894 string file_name; 05895 getContainerFileName( container, file_name, true ); 05896 05897 bool fexists = FileHelp::fileExist( file_name); 05898 05899 long lInfo( 0x0), lStat( 0x0); 05900 05901 if( fexists && FileHelp::isFileReadOnly( file_name)) 05902 { 05903 if( isCheckedOutByElseSVN( file_name)) 05904 { 05905 lInfo = FS_OTHER; // checked out by other user 05906 } 05907 else // readonly, but we could apply a lock onto it (then we released the lock) 05908 { 05909 lInfo = 0x0; // not checked out 05910 } 05911 } 05912 else if( fexists) 05913 { 05914 lInfo = FS_LOCAL; // checked out by local user 05915 } 05916 05917 05918 bool newfile = !fexists; 05919 bool ismodbyothers = fexists && fileModifiedByOthers( container); 05920 05921 if( ismodbyothers) 05922 lStat = FS_MODIFIEDBYOTHERS; 05923 else if( newfile) 05924 lStat = FS_NOTYETSAVED; 05925 else 05926 lStat = 0x0; 05927 05928 setSourceControlNodes( container, lInfo, lStat); 05929 } 05930 } 05931 05932 void CCoreXmlFile::updateSourceControlInfo() 05933 { 05934 for( XmlObjVecIter it=m_objects.begin(), en = m_objects.end(); it!=en; ++it ) 05935 { 05936 XmlObject * obj = (*it); 05937 if( obj->isContainer() ) 05938 updateSourceControlInfo( obj ); 05939 } 05940 } 05941 05942 void CCoreXmlFile::dumpSourceControlInfo() 05943 { 05944 FILE * f = fopen( "c:\\temp\\out.txt", "w" ); 05945 05946 for( XmlObjVecIter it=m_objects.begin(); it!=m_objects.end(); ++it ) 05947 { 05948 XmlObject * obj = (*it); 05949 if( obj->isContainer() ) 05950 { 05951 string guid, str; 05952 guid2str( obj->m_guid, guid ); 05953 //getSourceControlInfo( obj, str ); 05954 05955 string st2; 05956 //getSourceControlStat( obj, st2 ); 05957 05958 fprintf( f, "%s\t%s\t%s\n", guid.c_str(), str.c_str(), st2.c_str() ); 05959 } 05960 } 05961 05962 fclose(f); 05963 } 05964 05965 bool CCoreXmlFile::filesModifiedByOthers() 05966 { 05967 for( XmlObjVecIter it=m_objects.begin(); it!=m_objects.end(); ++it ) 05968 { 05969 XmlObject * obj = (*it); 05970 if( obj->isContainer() ) 05971 { 05972 string filename; 05973 getContainerFileName(obj, filename); 05974 05975 // get last write time 05976 WIN32_FILE_ATTRIBUTE_DATA attr; 05977 BOOL res = GetFileAttributesEx( filename.c_str(), GetFileExInfoStandard, &attr ); 05978 // inserted by zolmol: 05979 DWORD dwerror = res ? ERROR_SUCCESS : GetLastError(); // res == 0 in case of failure 05980 if( dwerror == ERROR_FILE_NOT_FOUND) // != ERROR_SUCCESS) 05981 { 05982 // in case of new objects have been introduced the respective files 05983 // are not found (FILE_NOT_FOUND) and the obj->lastwritetime is 0 05984 ASSERT( obj->m_lastWriteTime == 0); 05985 continue; 05986 } // end of zolmol code 05987 05988 CTime lastWriteTime( attr.ftLastWriteTime ); 05989 05990 if( lastWriteTime > obj->m_lastWriteTime ) 05991 return true; 05992 } 05993 } 05994 return false; 05995 } 05996 05997 bool CCoreXmlFile::filesModifiedByOthersV3( XmlObjSet& p_readOnlyFiles, XmlObjSet& p_latentFiles) 05998 { 05999 // the p_readOnlyFiles param indicates which files 06000 // are intended to be checked out at all (if any) 06001 // this will help determining more permissively 06002 // whether a safe checkout is to be allowed or not 06003 bool ret_prm = false; 06004 06005 // the permissive return_value calculation 06006 for( XmlObjSetIter it=p_readOnlyFiles.begin(); it!=p_readOnlyFiles.end(); ++it ) 06007 { 06008 XmlObject * obj = (*it); 06009 if( obj->isContainer() ) 06010 { 06011 bool ret = false; 06012 try { 06013 ret = fileModifiedByOthers( obj); 06014 } catch( hresult_exception& ) { 06015 ret = false; 06016 std::string link = makelink( obj); 06017 sendMsg( std::string( "Orphan found: ") + link, MSG_ERROR); 06018 } 06019 06020 // collect latent changed files 06021 if( ret && p_latentFiles.end() == p_latentFiles.find( obj)) 06022 p_latentFiles.insert( obj); 06023 06024 ret_prm = ret_prm || ret; // once became true, should remain true 06025 } 06026 } 06027 06028 return ret_prm; 06029 } 06030 06031 bool CCoreXmlFile::fileModifiedByOthers( XmlObject * obj ) 06032 { 06033 ASSERT( obj); 06034 ASSERT( obj->isContainer()); 06035 06036 string filename; 06037 getContainerFileName(obj, filename); 06038 06039 // get last write time 06040 WIN32_FILE_ATTRIBUTE_DATA attr; 06041 BOOL res = GetFileAttributesEx( filename.c_str(), GetFileExInfoStandard, &attr ); 06042 // inserted by zolmol: 06043 DWORD dwerror = res ? ERROR_SUCCESS : GetLastError(); // res == 0 in case of failure 06044 if( dwerror == ERROR_FILE_NOT_FOUND) // != ERROR_SUCCESS) 06045 { 06046 // in case of new objects have been introduced the respective files 06047 // are not found (FILE_NOT_FOUND) and the obj->lastwritetime is 0 06048 ASSERT( obj->m_lastWriteTime == 0); 06049 return false; 06050 } // end of zolmol code 06051 bool mydec = false; 06052 CTime lastWriteTime( attr.ftLastWriteTime ); 06053 bool rv = lastWriteTime > obj->m_lastWriteTime; 06054 if( isSV()) 06055 { 06056 // FIXME: this may fail 06057 bool repo_entry_modified; 06058 m_svn->statusOnServer(filename, false, std::string(), &rv, &repo_entry_modified); 06059 } 06060 return rv; 06061 } 06062 06063 void CCoreXmlFile::sendMsg( const std::string& p_msgStr, int p_msgType) 06064 { 06065 m_console.sendMsg( p_msgStr, p_msgType); 06066 } 06067 06068 std::string CCoreXmlFile::makelink( XmlObject * ptr) 06069 { 06070 if( !ptr) return "nullobject"; 06071 06072 // name 06073 std::string nm; 06074 ptr->m_attributes.find( ATTRID_NAME)->second->toString( nm); 06075 06076 // objid 06077 metaobjidpair_type idpr; 06078 objIdFromObject( ptr, idpr); 06079 06080 // something similar to FCO::get_ID() found in MgaFCO.cpp 06081 char id[20]; 06082 sprintf( id, "id-%04lx-%08lx", idpr.metaid, idpr.objid); 06083 06084 return std::string( "<A HREF=\"mga:") + id + "\">" + (nm.size()>0?nm:"noname") + "</A>"; 06085 } 06086 06087 void CCoreXmlFile::newDOMObjs( XERCES_CPP_NAMESPACE::DOMImplementationLS** p_domImpl, std::auto_ptr<XERCES_CPP_NAMESPACE::DOMLSParser>& p_domParser, std::auto_ptr<XERCES_CPP_NAMESPACE::DOMErrorHandler>& p_domErrHandler) 06088 { 06089 DOMImplementationLS * domimpl = DOMImplementationRegistry::getDOMImplementation( smart_XMLCh(XMLString::transcode("XML 1.0")));//NULL 06090 ASSERT( domimpl != NULL ); 06091 06092 DOMLSParser * parser = !domimpl? 0: domimpl->createLSParser( DOMImplementationLS::MODE_SYNCHRONOUS, NULL ); 06093 ASSERT( parser != NULL ); 06094 06095 DOMErrorHandler* err_handler = new DOMErrorPrinter( &m_console); 06096 ASSERT( err_handler != NULL); 06097 if( parser && err_handler) 06098 parser->getDomConfig()->setParameter(XMLUni::fgDOMErrorHandler, err_handler); 06099 06100 *p_domImpl = domimpl; 06101 p_domParser = std::auto_ptr<XERCES_CPP_NAMESPACE::DOMLSParser>(parser); 06102 p_domErrHandler = std::auto_ptr<XERCES_CPP_NAMESPACE::DOMErrorHandler>(err_handler); 06103 } 06104 06105 XERCES_CPP_NAMESPACE::DOMDocument* CCoreXmlFile::enclosedParse( const std::string& p_fileName, DOMLSParser* p_parser, bool *p_success) 06106 { 06107 ASSERT( p_parser); 06108 ASSERT( p_success); 06109 if( p_success) *p_success = p_parser != 0; 06110 if( !p_parser) return 0; 06111 06112 XERCES_CPP_NAMESPACE::DOMDocument* doc = 0; 06113 06114 try { 06115 doc = p_parser->parseURI( p_fileName.c_str()); 06116 } 06117 catch( const OutOfMemoryException&) { 06118 sendMsg( "Exception: Out of memory during parsing of " + p_fileName + "!", MSG_ERROR); 06119 if( p_success) *p_success = false; 06120 } 06121 catch (const XMLException& e) { 06122 smart_Ch e_msg = XMLString::transcode( e.getMessage()); 06123 sendMsg( "An error occurred during parsing of " + p_fileName + ". Message: " + e_msg, MSG_ERROR); 06124 if( p_success) *p_success = false; 06125 } 06126 catch (const DOMException& e) { 06127 const unsigned int maxChars = 2047; 06128 XMLCh errText[maxChars + 1]; 06129 if( DOMImplementation::loadDOMExceptionMsg( e.code, errText, maxChars)) 06130 { 06131 smart_Ch e_msg = XMLString::transcode( errText); 06132 sendMsg( "An error occurred during parsing of " + p_fileName + ". Message: " + e_msg, MSG_ERROR); 06133 } 06134 else 06135 { 06136 smart_Ch e_msg = XMLString::transcode( e.getMessage()); 06137 sendMsg( "An error occurred during parsing of " + p_fileName + ". Message: " + e_msg, MSG_ERROR); 06138 } 06139 06140 if( p_success) *p_success = false; 06141 } 06142 catch (...) 06143 { 06144 sendMsg( "Unknown exception occurred during parsing of " + p_fileName + "!", MSG_ERROR); 06145 if( p_success) *p_success = false; 06146 } 06147 06148 return doc; 06149 } 06150 06151 DOMLSParser* CCoreXmlFile::getFreshParser( const std::string& p_whoIsTheUser, DOMImplementationLS ** p_ptrRetDomImpl /* = 0 */) 06152 { 06153 DOMImplementationLS * domimpl = NULL; 06154 DOMLSParser* parser = NULL; 06155 06156 06157 // 06158 // DOM implementation factory creation 06159 // 06160 const char di_msg[] = "Exception: Could not create DOMImplementation for "; 06161 try { 06162 06163 domimpl = DOMImplementationRegistry::getDOMImplementation(NULL); 06164 06165 } catch(...) { 06166 06167 // was not initialized already? let's do our best 06168 XMLPlatformUtils::Initialize(); 06169 06170 // try again 06171 try { 06172 06173 domimpl = DOMImplementationRegistry::getDOMImplementation(NULL); // 2nd attempt, hoping that XMLPlatformUtils::Initialize() was missing the time before 06174 06175 if( domimpl) sendMsg( "Warning: DOMImplementation created in the second attempt only for " + p_whoIsTheUser, MSG_WARNING); 06176 06177 } catch(...) { 06178 06179 domimpl = 0; 06180 06181 sendMsg( di_msg + p_whoIsTheUser, MSG_ERROR); 06182 06183 } 06184 } 06185 06186 ASSERT( domimpl != NULL ); 06187 06188 // 06189 // can the DOMBuilder/parser be created ? 06190 // 06191 try { 06192 06193 parser = !domimpl? 0: domimpl->createLSParser( DOMImplementationLS::MODE_SYNCHRONOUS, NULL ); 06194 06195 } 06196 catch(const DOMException& e) { 06197 06198 parser = 0; 06199 06200 const unsigned int maxChars = 2047; 06201 XMLCh errText[maxChars + 1]; 06202 const char s_msg[] = "DOMException during parser object creation for "; 06203 const char m_msg[] = ". Message: "; 06204 06205 if( DOMImplementation::loadDOMExceptionMsg( e.code, errText, maxChars)) 06206 { 06207 smart_Ch e_msg = XMLString::transcode( errText); 06208 sendMsg( s_msg + p_whoIsTheUser + m_msg + e_msg, MSG_ERROR); 06209 } 06210 else 06211 { 06212 smart_Ch e_msg = XMLString::transcode( e.getMessage()); 06213 sendMsg( s_msg + p_whoIsTheUser + m_msg + e_msg, MSG_ERROR); 06214 } 06215 } 06216 catch(...) { 06217 06218 parser = 0; 06219 06220 sendMsg( "Exception: Could not create parser for " + p_whoIsTheUser, MSG_ERROR); 06221 } 06222 06223 if( domimpl != 0 && parser != 0) 06224 { 06225 if( p_ptrRetDomImpl != 0) // if user interested in the DomImpl 06226 *p_ptrRetDomImpl = domimpl; // then fill the ptr 06227 06228 return parser; 06229 } 06230 return 0; 06231 }