GME  13
CoreBinFile.cpp
Go to the documentation of this file.
00001 #include "stdafx.h"
00002 #include "CoreBinFile.h"
00003 #include "CommonCollection.h"
00004 #include "..\Mga\MgaGeneric.h"
00005 
00006 
00007 /*
00008         examples:
00009 
00010                 MGA=D:\Data\metamodel.mga
00011 */
00012 
00013 // --------------------------- BinAttr
00014 
00015 BinAttrBase *BinAttrBase::Create(BinAttrBase& attr, valtype_type valtype)
00016 {
00017         ASSERT( valtype != VALTYPE_NONE );
00018 
00019         BinAttrBase *binattr = NULL;
00020 
00021         switch(valtype)
00022         {
00023         case VALTYPE_LONG:
00024                 binattr = new ((void*)(&attr)) BinAttr<VALTYPE_LONG>();
00025                 break;
00026 
00027         case VALTYPE_STRING:
00028                 binattr = new ((void*)(&attr)) BinAttr<VALTYPE_STRING>();
00029                 break;
00030 
00031         case VALTYPE_BINARY:
00032                 binattr = new ((void*)(&attr)) BinAttr<VALTYPE_BINARY>;
00033                 break;
00034 
00035         case VALTYPE_LOCK:
00036                 binattr = new ((void*)(&attr)) BinAttr<VALTYPE_LOCK>;
00037                 break;
00038 
00039         case VALTYPE_POINTER:
00040                 binattr = new ((void*)(&attr)) BinAttr<VALTYPE_POINTER>;
00041                 break;
00042 
00043         case VALTYPE_COLLECTION:
00044                 binattr = new ((void*)(&attr)) BinAttr<VALTYPE_COLLECTION>;
00045                 break;
00046 
00047         case VALTYPE_DICT:
00048                 binattr = new ((void*)(&attr)) BinAttr<VALTYPE_DICT>;
00049                 break;
00050         case VALTYPE_REAL:
00051                 binattr = new ((void*)(&attr)) BinAttr<VALTYPE_REAL>;
00052                 break;
00053 
00054         default:
00055                 HR_THROW(E_METAPROJECT);
00056         }
00057 
00058         // FIXME: can't take this if branch (is nothrow new intended?)
00059         if( binattr == NULL )
00060                 HR_THROW(E_OUTOFMEMORY);
00061 
00062         return binattr;
00063 };
00064 
00065 // --------------------------- BinObject
00066 void getMeAGuid( long *p_l1, long *p_l2, long *p_l3, long *p_l4)
00067 {
00068         GUID t_guid = GUID_NULL;
00069         COMTHROW(CoCreateGuid(&t_guid));
00070                 
00071         ASSERT(t_guid != GUID_NULL);
00072         //char buff[39];
00073         //sprintf( buff, "{%08lX-%04X-%04x-%02X%02X-%02X%02X%02X%02X%02X%02X}",
00074         //      t_guid.Data1, t_guid.Data2, t_guid.Data3,
00075         //      t_guid.Data4[0], t_guid.Data4[1], t_guid.Data4[2], t_guid.Data4[3],
00076         //      t_guid.Data4[4], t_guid.Data4[5], t_guid.Data4[6], t_guid.Data4[7]);
00077 
00078         // thus replace the old guid with a new one
00079         *p_l1 = t_guid.Data1; // Data1: 32 b, Data2, Data 3: 16 b, Data4: 64 bit
00080         *p_l2 = (t_guid.Data2 << 16) + t_guid.Data3;
00081         *p_l3 = (((((t_guid.Data4[0] << 8) + t_guid.Data4[1]) << 8) + t_guid.Data4[2]) << 8) + t_guid.Data4[3];
00082         *p_l4 = (((((t_guid.Data4[4] << 8) + t_guid.Data4[5]) << 8) + t_guid.Data4[6]) << 8) + t_guid.Data4[7];
00083 }
00084 
00085 void WalkRegistry(CCoreDictionaryAttributeValue::map_type& map, CComBSTR& path, CCoreBinFile* p_bf, BinObject& node)
00086 {
00087         binattrs_iterator i = node.binattrs.begin();
00088         binattrs_iterator e = node.binattrs.end();
00089         while( i != e)
00090         {
00091                 if( i->attrid == ATTRID_REGNOWNER + ATTRID_COLLECTION) {
00092                         // Copy, since we're going to remove from it
00093                         std::vector<objects_iterator> a = ((BinAttr<VALTYPE_COLLECTION>*)(void*)&(*i))->a;
00094                         for (auto it = a.begin(); it != a.end(); it++)
00095                         {
00096                                 objects_type::iterator regnode = p_bf->objects.find((*it)->first);
00097                                 if (regnode == p_bf->objects.end())
00098                                         throw E_BINFILE;
00099 
00100                                 CComVariant name;
00101                                 regnode->second.Find(ATTRID_NAME)->Get(p_bf, &name);
00102 #define RFLAG_HASVALUE 1
00103 #define RFLAG_OPAQUE 2
00104                                 CComVariant flag;
00105                                 regnode->second.Find(ATTRID_REGFLAGS)->Get(p_bf, &flag);
00106 
00107                                 CComBSTR newPath(path);
00108                                 if (path != L"")
00109                                         newPath += L"/";
00110                                 newPath += name.bstrVal;
00111                                 if (flag.intVal & RFLAG_HASVALUE) {
00112                                         CComVariant value;
00113                                         regnode->second.Find(ATTRID_REGNODEVALUE)->Get(p_bf, &value);
00114                                         map[newPath] = CComBSTR(value.bstrVal);
00115                                 }
00116                                 WalkRegistry(map, newPath, p_bf, regnode->second);
00117                                 p_bf->opened_object = regnode;
00118                                 regnode->second.Find(ATTRID_REGNOWNER)->Set(p_bf, CComVariant());
00119                         }
00120                         return;
00121                 }
00122                 ++i;
00123         }
00124 }
00125 
00126 void BinObject::UpgradeRegistryIfNecessary(CCoreBinFile* p_bf)
00127 {
00128         binattrs_iterator i = binattrs.begin();
00129         binattrs_iterator e = binattrs.end();
00130         while( i != e)
00131         {
00132                 if( i->attrid == ATTRID_REGNOWNER + ATTRID_COLLECTION) {
00133                         CCoreDictionaryAttributeValue::map_type map;
00134                         
00135                         WalkRegistry(map, CComBSTR(), p_bf, *this);
00136 
00137                         BinAttrBase::Create(*i, VALTYPE_DICT);
00138                         i->attrid = ATTRID_REGNODE;
00139                         CComVariant dict;
00140                         i->Get(p_bf, &dict);
00141                         ((CCoreDictionaryAttributeValue*)dict.pdispVal)->m_dict = map;
00142                         return;
00143                 }
00144                 ++i;
00145         }
00146 }
00147 
00148 void BinObject::HasGuidAndStatAttributes(GUID& t_guid, bool* p_statusFound, bool* p_oldRegFound)
00149 {
00150         int a1( 0), a2( 0), a3( 0), a4( 0);
00151 
00152         binattrs_iterator i = binattrs.begin();
00153         binattrs_iterator e = binattrs.end();
00154         while( i != e)
00155         {
00156                 switch ((i)->attrid)
00157                 {
00158                         case ATTRID_GUID1:
00159                                 t_guid.Data1 = reinterpret_cast<BinAttr<VALTYPE_LONG>*>(&(*i))->a;
00160                                 break;
00161                         case ATTRID_GUID2:
00162                                 t_guid.Data2 = (reinterpret_cast<BinAttr<VALTYPE_LONG>*>(&(*i))->a) >> 16;
00163                                 t_guid.Data3 = (reinterpret_cast<BinAttr<VALTYPE_LONG>*>(&(*i))->a) & 0xFFFF;
00164                                 break;
00165 
00166                         case ATTRID_GUID3: {
00167                                 long v3 = reinterpret_cast<BinAttr<VALTYPE_LONG>*>(&(*i))->a;
00168                                 t_guid.Data4[0] = (v3 >> 24);
00169                                 t_guid.Data4[1] = (v3 >> 16) & 0xFF;
00170                                 t_guid.Data4[2] = (v3 >> 8) & 0xFF;
00171                                 t_guid.Data4[3] = v3 & 0xFF;
00172                                 } break;
00173                         case ATTRID_GUID4: {
00174                                 long v4 = reinterpret_cast<BinAttr<VALTYPE_LONG>*>(&(*i))->a;
00175                                 t_guid.Data4[4] = (v4 >> 24);
00176                                 t_guid.Data4[5] = (v4 >> 16) & 0xFF;
00177                                 t_guid.Data4[6] = (v4 >> 8) & 0xFF;
00178                                 t_guid.Data4[7] = v4 & 0xFF;
00179                                 } break;
00180                         case ATTRID_FILESTATUS: *p_statusFound = true; break;
00181                         case ATTRID_REGNOWNER + ATTRID_COLLECTION:
00182                                 *p_oldRegFound = true; break;
00183                 };
00184 
00185                 ++i;
00186         }
00187 }
00188 
00189 // this method will create Guid attributes for mga objects
00190 // loaded from MGA files saved with a previous version of gme
00191 void BinObject::CreateGuidAttributes( CCoreBinFile* p_bf)
00192 {
00193         // create a new guid
00194         CComVariant l1, l2, l3, l4;
00195         l4.vt = l3.vt = l2.vt = l1.vt = VT_I4;
00196         getMeAGuid( &l1.lVal, &l2.lVal, &l3.lVal, &l4.lVal);
00197 
00198         // create BinAttrs of LONG type
00199         binattrs.emplace_back(ATTRID_NONE);
00200         BinAttrUnion& binattr1space = binattrs.back(); 
00201         BinAttrBase* binattr1 = BinAttrBase::Create(binattr1space, VALTYPE_LONG);
00202         binattrs.emplace_back(ATTRID_NONE);
00203         BinAttrUnion& binattr2space = binattrs.back(); 
00204         BinAttrBase* binattr2 = BinAttrBase::Create(binattr2space, VALTYPE_LONG);
00205         binattrs.emplace_back(ATTRID_NONE);
00206         BinAttrUnion& binattr3space = binattrs.back(); 
00207         BinAttrBase* binattr3 = BinAttrBase::Create(binattr3space, VALTYPE_LONG);
00208         binattrs.emplace_back(ATTRID_NONE);
00209         BinAttrUnion& binattr4space = binattrs.back(); 
00210         BinAttrBase* binattr4 = BinAttrBase::Create(binattr4space, VALTYPE_LONG);
00211 
00212 
00213         // fill the only public field
00214         binattr1->attrid = ATTRID_GUID1;
00215         binattr2->attrid = ATTRID_GUID2;
00216         binattr3->attrid = ATTRID_GUID3;
00217         binattr4->attrid = ATTRID_GUID4;
00218 
00219         // set the values
00220         binattr1->Set( p_bf, l1);
00221         binattr2->Set( p_bf, l2);
00222         binattr3->Set( p_bf, l3);
00223         binattr4->Set( p_bf, l4);
00224 
00225 }
00226 
00227 // this method will create a status attribute for mga objects
00228 // loaded from MGA files saved with a previous version of gme
00229 void BinObject::CreateStatusAttribute( CCoreBinFile* p_bf)
00230 {
00231         // create BinAttr of LONG type
00232         binattrs.emplace_back(ATTRID_NONE);
00233         BinAttrUnion& binattrspace = binattrs.back(); 
00234         BinAttrBase* binattr = BinAttrBase::Create(binattrspace, VALTYPE_LONG);
00235 
00236         // fill the only public field
00237         binattr->attrid = ATTRID_FILESTATUS;
00238 
00239         // set the value
00240         binattr->Set( p_bf, CComVariant( 0L));
00241 }
00242 
00243 void BinObject::CreateAttributes(ICoreMetaObject *metaobject)
00244 {
00245         ASSERT( metaobject != NULL );
00246         ASSERT( binattrs.empty() );
00247 
00248         CComObjPtr<ICoreMetaAttributes> metaattributes;
00249         COMTHROW( metaobject->get_Attributes(PutOut(metaattributes)) );
00250         ASSERT( metaattributes != NULL );
00251 
00252         typedef std::vector< CComObjPtr<ICoreMetaAttribute> > metaattributelist_type;
00253         metaattributelist_type metaattributelist;
00254         GetAll<ICoreMetaAttributes, ICoreMetaAttribute>(metaattributes, metaattributelist);
00255 
00256         binattrs.reserve(metaattributelist.size());
00257 
00258         metaattributelist_type::iterator i = metaattributelist.begin();
00259         metaattributelist_type::iterator e = metaattributelist.end();
00260         while( i != e )
00261         {
00262                 valtype_type valtype;
00263                 COMTHROW( (*i)->get_ValueType(&valtype) );
00264 
00265                 attrid_type attrid = ATTRID_NONE;
00266                 COMTHROW( (*i)->get_AttrID(&attrid) );
00267 
00268                 binattrs.emplace_back(ATTRID_NONE);
00269                 BinAttrUnion& binattrspace = binattrs.back(); 
00270                 BinAttrBase *binattr = BinAttrBase::Create(binattrspace, valtype);
00271 
00272                 ASSERT( attrid != ATTRID_NONE );
00273                 binattr->attrid = attrid;
00274 
00275                 ++i;
00276         }
00277 }
00278 
00279 void BinObject::DestroyAttributes()
00280 {
00281         binattrs.clear();
00282 }
00283 
00284 void BinObject::Read(CCoreBinFile *binfile)
00285 {
00286         ASSERT( binfile != NULL );
00287         ASSERT( binattrs.empty() );
00288 
00289         valtype_type valtype;
00290 
00291         // First count how many attributes this object has, so we can intelligently size this->binattrs
00292         size_t num_attrs = 0;
00293         char* cifs_save = binfile->cifs;
00294         for (;;)
00295         {
00296                 binfile->read(valtype);
00297                 if( valtype == VALTYPE_NONE )
00298                         break;
00299                 num_attrs++;
00300 
00301                 attrid_type attrid;
00302                 binfile->read(attrid);
00303 
00304                 // These need to be the same as CCoreBinFile::Read()s, but without the expense
00305                 switch(valtype)
00306                 {
00307                 case VALTYPE_LONG:
00308                         { long x; binfile->read(x); }
00309                         break;
00310 
00311                 case VALTYPE_STRING:
00312                         { int len; binfile->read(len); binfile->cifs += len; } // FIXME maybe cifs > cifs_eof
00313                         break;
00314 
00315                 case VALTYPE_DICT:
00316                 case VALTYPE_BINARY:
00317                         { int len; binfile->read(len); binfile->cifs += len; } // FIXME maybe cifs > cifs_eof
00318                         break;
00319 
00320                 case VALTYPE_LOCK:
00321                         break;
00322 
00323                 case VALTYPE_POINTER:
00324                         {
00325                                 metaid_type metaid;
00326                                 binfile->read(metaid);
00327                                 if( metaid != METAID_NONE )
00328                                 {
00329                                         objid_type objid;
00330                                         binfile->read(objid);
00331                                 }
00332                         }
00333 
00334                 case VALTYPE_COLLECTION:
00335                         break;
00336 
00337                 case VALTYPE_REAL:
00338                         { double x; binfile->read(x); }
00339                         break;
00340 
00341                 default:
00342                         HR_THROW(E_METAPROJECT);
00343                 }
00344         }
00345         binfile->cifs = cifs_save;
00346         binattrs.reserve(num_attrs);
00347 
00348         for(;;)
00349         {
00350                 binfile->read(valtype);
00351                 if( valtype == VALTYPE_NONE )
00352                         break;
00353 
00354                 binattrs.emplace_back(ATTRID_NONE);
00355                 BinAttrUnion& binattrspace = binattrs.back();
00356                 BinAttrBase *binattr = BinAttrBase::Create(binattrspace, valtype);
00357                 ASSERT( binattr != NULL );
00358 
00359                 attrid_type attrid;
00360                 binfile->read(attrid);
00361                 ASSERT( attrid != ATTRID_NONE );
00362 
00363                 binattr->attrid = attrid;
00364 
00365                 // Possible pitfall: binattr == &binattrspace. It is possible the compiler will figure this out, and call BinAttrUnion::Read() (which we don't want)
00366                 binattr->Read(binfile);
00367         }
00368         ASSERT(binattrs.size() == num_attrs);
00369 };
00370 
00371 void BinObject::Write(CCoreBinFile *binfile)
00372 {
00373         ASSERT( binfile != NULL );
00374         ASSERT( !deleted );
00375 
00376         binattrs_iterator i = binattrs.begin();
00377         binattrs_iterator e = binattrs.end();
00378         while( i != e )
00379         {
00380                 ASSERT( (i)->GetValType() != VALTYPE_NONE );
00381                 ASSERT( (i)->attrid != ATTRID_NONE );
00382 
00383                 binfile->write( (i)->GetValType() );
00384                 binfile->write( (i)->attrid );
00385                 (i)->Write(binfile);
00386 
00387                 ++i;
00388         }
00389 
00390         binfile->write((valtype_type)VALTYPE_NONE);
00391 }
00392 
00393 bool BinObject::HasEmptyPointers() const
00394 {
00395         if( deleted )
00396                 return true;
00397 
00398         binattrs_type::const_iterator i = binattrs.begin();
00399         binattrs_type::const_iterator e = binattrs.end();
00400         while( i != e )
00401         {
00402                 if( (i)->GetValType() == VALTYPE_POINTER )
00403                 {
00404                         if( !( ( ( BinAttr<VALTYPE_POINTER>*)(&*i))->isEmpty))
00405                                 return false;
00406                 }
00407                 ++i;
00408         }
00409 
00410         return true;
00411 }
00412 
00413 // --------------------------- CCoreBinFile
00414 
00415 CCoreBinFile::CCoreBinFile()
00416 {
00417         metaid = METAID_NONE;
00418         attrid = ATTRID_NONE;
00419         intrans = false;
00420         modified = false;
00421         isEmpty = true;
00422 }
00423 
00424 CCoreBinFile::~CCoreBinFile()
00425 {
00426 }
00427 
00428 // ------- MetaProject
00429 
00430 STDMETHODIMP CCoreBinFile::get_MetaProject(ICoreMetaProject **p)
00431 {
00432         CHECK_OUT(p);
00433 
00434         CopyTo(metaproject, p);
00435 
00436         return S_OK;
00437 }
00438 
00439 STDMETHODIMP CCoreBinFile::put_MetaProject(ICoreMetaProject *p)
00440 {
00441         COMTRY
00442         {
00443                 CloseMetaProject();
00444 
00445                 metaproject = p;
00446 
00447                 if( metaproject != NULL )
00448                         OpenMetaProject();
00449         }
00450         COMCATCH( CloseMetaProject() )
00451 }
00452 
00453 void CCoreBinFile::OpenMetaProject()
00454 {
00455         ASSERT( metaprojectid.empty() );
00456         ASSERT( metaproject != NULL );
00457 
00458         CComVariant tmp;
00459         COMTHROW(metaproject->get_GUID(PutOut(tmp)));
00460         CopyTo(tmp, metaprojectid);
00461 }
00462 
00463 void CCoreBinFile::CloseMetaProject()
00464 {
00465         if( IsOpened() && metaproject != NULL )
00466                 CloseProject();
00467 
00468         CloseMetaObject();
00469 
00470         metaproject = NULL;
00471         metaprojectid.clear();
00472 }
00473 
00474 // ------- MetaObject
00475 
00476 STDMETHODIMP CCoreBinFile::get_MetaObject(ICoreMetaObject **p)
00477 {
00478         CHECK_OUT(p);
00479 
00480         CopyTo(metaobject, p);
00481 
00482         return S_OK;
00483 }
00484 
00485 STDMETHODIMP CCoreBinFile::put_MetaObject(ICoreMetaObject *p)
00486 {
00487         if( metaproject == NULL )
00488                 COMRETURN(E_INVALID_USAGE);
00489 
00490         if( metaobject == p )
00491                 return S_OK;
00492 
00493         COMTRY
00494         {
00495                 if( p != NULL )
00496                 {
00497                         CComObjPtr<ICoreMetaProject> t;
00498                         COMTHROW( p->get_Project(PutOut(t)) );
00499                         if( !IsEqualObject(metaproject, t) )
00500                                 HR_THROW(E_SAMEPROJECT);
00501                 }
00502 
00503                 CloseMetaObject();
00504                 metaobject = p;
00505                 if( metaobject != NULL )
00506                         OpenMetaObject();
00507         }
00508         COMCATCH( CloseMetaObject() )
00509 }
00510 
00511 STDMETHODIMP CCoreBinFile::get_MetaID(metaid_type *p)
00512 {
00513         CHECK_OUT(p);
00514 
00515         *p = metaid;
00516 
00517         return S_OK;
00518 }
00519 
00520 STDMETHODIMP CCoreBinFile::put_MetaID(metaid_type metaid)
00521 {
00522         if( metaproject == NULL )
00523                 COMRETURN(E_INVALID_USAGE);
00524 
00525         COMTRY
00526         {
00527                 if( metaid != METAID_NONE )
00528                 {
00529                         CComObjPtr<ICoreMetaObject> p;
00530                         COMTHROW( metaproject->get_Object(metaid, PutOut(p)) );
00531                         ASSERT( p != NULL );
00532 
00533                         if( metaobject != p )
00534                         {
00535                                 CloseMetaObject();
00536                                 MoveTo(p, metaobject);
00537                                 OpenMetaObject();
00538                         }
00539                 }
00540                 else
00541                         CloseMetaObject();
00542         }
00543         COMCATCH( CloseMetaObject() )
00544 }
00545 
00546 void CCoreBinFile::OpenMetaObject()
00547 {
00548         ASSERT( metaobject != NULL );
00549 
00550         COMTHROW( metaobject->get_MetaID(&metaid) );
00551 }
00552 
00553 void CCoreBinFile::CloseMetaObject()
00554 {
00555         CloseObject();
00556         CloseMetaAttribute();
00557         metaobject = NULL;
00558         metaid = METAID_NONE;
00559 }
00560 
00561 // ------- MetaAttribute
00562 
00563 STDMETHODIMP CCoreBinFile::get_MetaAttribute(ICoreMetaAttribute **p)
00564 {
00565         CHECK_OUT(p);
00566 
00567         CopyTo(metaattribute, p);
00568 
00569         return S_OK;
00570 }
00571 
00572 STDMETHODIMP CCoreBinFile::put_MetaAttribute(ICoreMetaAttribute *p)
00573 {
00574         if( metaobject == NULL )
00575                 COMRETURN(E_INVALID_USAGE);
00576         ASSERT( metaproject != NULL );
00577 
00578         if( metaattribute == p )
00579                 return S_OK;
00580 
00581         COMTRY
00582         {
00583                 if( metaattribute != NULL )
00584                 {
00585                         CComObjPtr<ICoreMetaObject> t;
00586                         COMTHROW( metaattribute->get_Object(PutOut(t)) );
00587                         if( !IsEqualObject(metaobject, t) )
00588                         {
00589                                 metaattribute = NULL;
00590                                 return E_INVALIDARG;
00591                         }
00592                 }
00593 
00594                 CloseMetaAttribute();
00595                 metaattribute = p;
00596                 if( metaattribute != NULL )
00597                         OpenMetaAttribute();
00598         }
00599         COMCATCH( CloseMetaAttribute() )
00600 }
00601 
00602 STDMETHODIMP CCoreBinFile::get_AttrID(attrid_type *p)
00603 {
00604         CHECK_OUT(p);
00605 
00606         if( metaattribute )
00607                 return metaattribute->get_AttrID(p);
00608 
00609         *p = 0;
00610         return S_OK;
00611 }
00612 
00613 STDMETHODIMP CCoreBinFile::put_AttrID(attrid_type attrid)
00614 {
00615         if( metaobject == NULL )
00616                 COMRETURN(E_INVALID_USAGE);
00617         ASSERT( metaproject != NULL );
00618 
00619         COMTRY
00620         {
00621                 if( attrid != ATTRID_NONE )
00622                 {
00623                         CComObjPtr<ICoreMetaAttribute> p;
00624                         COMTHROW( metaobject->get_Attribute(attrid, PutOut(p)) );
00625                         ASSERT( p != NULL );
00626 
00627                         if( metaattribute != p )
00628                         {
00629                                 CloseMetaAttribute();
00630                                 metaattribute = p;
00631                                 OpenMetaAttribute();
00632                         }
00633                 }
00634                 else
00635                         CloseMetaAttribute();
00636         }
00637         COMCATCH( CloseMetaAttribute() )
00638 }
00639 
00640 void CCoreBinFile::OpenMetaAttribute()
00641 {
00642         ASSERT( metaattribute != NULL );
00643 
00644         COMTHROW( metaattribute->get_AttrID(&attrid) );
00645 
00646         if( attrid == ATTRID_NONE )
00647                 HR_THROW(E_METAPROJECT);
00648 }
00649 
00650 void CCoreBinFile::CloseMetaAttribute()
00651 {
00652         metaattribute = NULL;
00653         attrid = ATTRID_NONE;
00654 }
00655 
00656 // ------- Ios
00657 
00658 void CCoreBinFile::read(bindata &b)
00659 {
00660         int len;
00661         
00662         read(len);
00663         ASSERT( len >= 0 );
00664 
00665         try {
00666                 b.resize(len);
00667         } catch (std::bad_alloc&) {
00668                 // KMS: could get here if the project is corrupt and len is incorrect
00669                 COMTHROW(E_OUTOFMEMORY);
00670         }
00671         if( len > 0 ) {
00672                 if (len > cifs_eof - cifs) {
00673                         HR_THROW(E_FILEOPEN);
00674                 }
00675                 memcpy(&b[0], cifs, len);
00676                 cifs += len;
00677         }
00678 }
00679 
00680 void CCoreBinFile::read(unsigned char*& b, int& len)
00681 {
00682         read(len);
00683         ASSERT( len >= 0 );
00684 
00685         b = (unsigned char*)malloc(len);
00686         if (b == NULL) {
00687                 // KMS: could get here if the project is corrupt and len is incorrect
00688                 COMTHROW(E_OUTOFMEMORY);
00689         }
00690         if( len > 0 ) {
00691                 if (len > cifs_eof - cifs) {
00692                         HR_THROW(E_FILEOPEN);
00693                 }
00694                 memcpy(b, cifs, len);
00695                 cifs += len;
00696         }
00697 }
00698 
00699 void CCoreBinFile::readstring(char*& pos) {
00700         pos = cifs;
00701         int len;
00702 
00703         read(len);
00704         cifs += len;
00705 }
00706 
00707 void CCoreBinFile::read(CComBstrObj &ss)
00708 {
00709         read(ss, cifs);
00710 }
00711 
00712 void CCoreBinFile::read(CComBstrObj &ss, char*& cifs)
00713 {
00714         int len;
00715 
00716         //read(len);
00717         // use local cifs
00718         CoreBinFile_read(len, 4);
00719         ASSERT( len >= 0 );
00720 
00721         if( len > 0 ) {
00722                 if (len > cifs_eof - cifs) {
00723                         HR_THROW(E_FILEOPEN);
00724                 }
00725                 CopyTo(cifs, len, &ss.p, CP_UTF8);
00726                 cifs += len;
00727         } else {
00728                 std::string s;
00729                 CopyTo(s, ss);
00730         }
00731 }
00732 
00733 void CCoreBinFile::write(const bindata &b)
00734 {
00735         ASSERT( ofs.is_open() );
00736 
00737         int len = b.size();
00738         ASSERT( len >= 0 );
00739         
00740         write(len);
00741 
00742         if( len > 0 )
00743                 ofs.write( (const char *) &b[0], len);
00744 }
00745 
00746 void CCoreBinFile::write(const unsigned char* b, int len)
00747 {
00748         ASSERT( ofs.is_open() );
00749 
00750         ASSERT( len >= 0 );
00751         
00752         write(len);
00753 
00754         if( len > 0 )
00755                 ofs.write( (const char *) b, len);
00756 }
00757 
00758 void CCoreBinFile::write(const CComBstrObj &ss)
00759 {
00760         ASSERT( ofs.is_open() );
00761 
00762         int len = GetCharLength(ss, SysStringLen(ss.p), CP_UTF8);
00763         char* s = NULL;
00764         if (len) {
00765                 s = new char[len];
00766                 CopyTo(ss.p, s, len, CP_UTF8);
00767         }
00768 
00769         ASSERT( len >= 0 );
00770         
00771         write(len);
00772 
00773         if( len > 0 )
00774                 ofs.write( (const char *) &s[0], len);
00775         delete[] s;
00776 }
00777 
00778 void CCoreBinFile::writestring(const char* pos)
00779 {
00780         int len;
00781         memcpy(&len, pos, sizeof(len));
00782         write(len);
00783         ofs.write(pos+sizeof(int), len);
00784 }
00785 
00786 
00787 // ------- Attribute
00788 
00789 STDMETHODIMP CCoreBinFile::get_AttributeValue(VARIANT *p)
00790 {
00791         CHECK_OUT(p);
00792 
00793         if( isEmpty || !InTransaction())
00794                 COMRETURN(E_INVALID_USAGE);
00795         
00796         COMTRY
00797         {
00798                 BinAttrBase *attr = opened_object->second.Find(attrid);
00799                 ASSERT( attr != NULL );
00800 
00801                 attr->Get(this, p);
00802         }
00803         COMCATCH(;)
00804 }
00805 
00806 STDMETHODIMP CCoreBinFile::put_AttributeValue(VARIANT p)
00807 {
00808         if( isEmpty || !InTransaction())
00809                 COMRETURN(E_INVALID_USAGE);
00810         
00811         COMTRY
00812         {
00813                 BinAttrBase *attr = opened_object->second.Find(attrid);
00814 
00815         /*      std::pair<BinAttrBase *const, CComVariant> r(attr, CComVariant());
00816                 std::pair<undos_iterator, bool> t = undos.insert(r);
00817 
00818                 if( t.second )
00819                         attr->Get(this, PutOut(t.first->second));
00820                         */
00821                 attr->Set(this, p);
00822         }
00823         COMCATCH(;)
00824 }
00825 
00826 // ------- Object
00827 
00828 void CCoreBinFile::InitMaxObjIDs()
00829 {
00830         ASSERT( metaproject != NULL );
00831 
00832         maxobjids.clear();
00833 
00834         CComObjPtr<ICoreMetaObjects> metaobjects;
00835         COMTHROW( metaproject->get_Objects(PutOut(metaobjects)) );
00836         ASSERT( metaobjects != NULL );
00837 
00838         typedef std::vector< CComObjPtr<ICoreMetaObject> > metaobjectlist_type;
00839         metaobjectlist_type metaobjectlist;
00840         GetAll<ICoreMetaObjects, ICoreMetaObject>(metaobjects, metaobjectlist);
00841 
00842         metaobjectlist_type::iterator i = metaobjectlist.begin();
00843         metaobjectlist_type::iterator e = metaobjectlist.end();
00844         while( i != e )
00845         {
00846                 ASSERT( *i != NULL );
00847 
00848                 metaid_type metaid = METAID_NONE;
00849                 COMTHROW( (*i)->get_MetaID(&metaid) );
00850                 ASSERT( metaid != METAID_NONE );
00851 
00852                 ASSERT( maxobjids.find(metaid) == maxobjids.end() );
00853                 maxobjids.insert( core::pair<const metaid_type, objid_type>(metaid, OBJID_NONE) );
00854 
00855                 ++i;
00856         }
00857 }
00858 
00859 STDMETHODIMP CCoreBinFile::OpenObject(objid_type objid)
00860 {
00861         if( metaobject == NULL || !InTransaction() )
00862                 COMRETURN(E_INVALID_USAGE);
00863 
00864         ASSERT( metaid != METAID_NONE );
00865 
00866         metaobjidpair_type idpair;
00867         idpair.metaid = metaid;
00868         idpair.objid = objid;
00869 
00870         if( !isEmpty &&
00871                 metaobjidpair_equalkey()(opened_object->first, idpair) )
00872                 return S_OK;
00873 
00874         COMTRY
00875         {
00876                 opened_object = objects.find(idpair);
00877                 isEmpty = false;
00878                 if( (opened_object == objects.end()) ||
00879                         opened_object->second.deleted )
00880                 {
00881                         isEmpty = true;
00882                         HR_THROW(E_NOTFOUND);
00883                 }
00884         }
00885         COMCATCH(;)
00886 }
00887 
00888 STDMETHODIMP CCoreBinFile::CreateObject(objid_type *objid)
00889 {
00890         CHECK_OUT(objid);
00891 
00892         if( metaobject == NULL || !InTransaction() )
00893                 COMRETURN(E_INVALID_USAGE);
00894 
00895         COMTRY
00896         {
00897                 modified = true;
00898 
00899                 isEmpty = true;
00900 
00901                 ASSERT( metaid != METAID_NONE );
00902 
00903                 maxobjids_iterator i = maxobjids.find(metaid);
00904                 ASSERT( i != maxobjids.end() );
00905                 
00906                 metaobjidpair_type idpair;
00907                 idpair.metaid = metaid;
00908                 idpair.objid = ++(i->second);
00909 
00910                 ASSERT( metaobject != NULL );
00911 
00912                 std::pair<objects_iterator, bool> t = objects.insert(
00913                         objects_type::value_type(idpair,BinObject()));
00914                 ASSERT( t.second );
00915 
00916                 t.first->second.deleted = false;
00917                 t.first->second.CreateAttributes(metaobject);
00918 
00919                 created_objects.push_front(t.first);
00920 
00921                 opened_object = t.first;
00922                 isEmpty = false;
00923                 *objid = idpair.objid;
00924         }
00925         COMCATCH(;)
00926 }
00927 
00928 STDMETHODIMP CCoreBinFile::CloseObject()
00929 {
00930         isEmpty =  true;
00931         return S_OK;
00932 }
00933 
00934 STDMETHODIMP CCoreBinFile::LockObject()
00935 {
00936         if( isEmpty || !InTransaction())
00937                 COMRETURN(E_INVALID_USAGE);
00938 
00939         return S_OK;
00940 }
00941 
00942 STDMETHODIMP CCoreBinFile::DeleteObject()
00943 {
00944         if( isEmpty || !InTransaction())
00945                 COMRETURN(E_INVALID_USAGE);
00946 
00947         ASSERT( metaobject != NULL );
00948 
00949         ASSERT( opened_object->second.deleted == false );
00950 
00951         modified = true;
00952 
00953         deleted_objects.push_front(opened_object);
00954 
00955         opened_object->second.deleted = true;
00956         isEmpty = true;
00957 
00958         return S_OK;
00959 }
00960 
00961 // ------- Project
00962 
00963 void CCoreBinFile::CancelProject()
00964 {
00965         CloseMetaObject();
00966 
00967         cifs = 0;
00968         cifs_eof = 0;
00969 
00970         if( ofs.is_open() )
00971                 ofs.close();
00972 
00973         filename.clear();
00974         intrans = false;
00975         modified = false;
00976 
00977         isEmpty = true;
00978         deleted_objects.clear();
00979         created_objects.clear();
00980         maxobjids.clear();
00981         resolvelist.clear();
00982         objects.clear();
00983 }
00984 
00985 static DWORD __stdcall prog(LARGE_INTEGER TotalFileSize, LARGE_INTEGER TotalBytesTransferred,LARGE_INTEGER StreamSize,
00986 LARGE_INTEGER StreamBytesTransferred, DWORD dwStreamNumber, DWORD dwCallbackReason, HANDLE hSourceFile, HANDLE hDestinationFile, LPVOID lpData)
00987 {
00988         return PROGRESS_STOP;
00989 }
00990 
00991 
00992 void CCoreBinFile::SaveProject(const std::wstring& origfname, bool keepoldname)
00993 {
00994         ASSERT( !ofs.is_open() );
00995         ASSERT( metaprojectid.size() == 16 );
00996 
00997 
00998         std::wstring filenameout = filename;
00999         // origfname == filename => file_buffer has filename locked FILE_SHARE_READ
01000         // CopyFile because:
01001         // SetEndOfFileInformationFile
01002         // Preserves extended attributes, NTFS alternate streams, file attributes (and newer Windows: security attributes)
01003         if (origfname == filename && GetFileAttributesW(origfname.c_str()) != INVALID_FILE_ATTRIBUTES)
01004         {
01005                 filenameout += L"tmp";
01006                 BOOL cancel = FALSE;
01007                 BOOL succ = CopyFileExW(origfname.c_str(), filenameout.c_str(), &prog, NULL, &cancel, 0);
01008                 if (!succ && GetLastError() != ERROR_REQUEST_ABORTED)
01009                 {
01010                         HRESULT hr = HRESULT_FROM_WIN32(GetLastError());
01011                         _bstr_t err;
01012                         GetErrorInfo(hr, err.GetAddress());
01013                         throw_com_error(hr, _bstr_t(L"Error saving '") + filenameout.c_str() + L"': " + err);
01014                 }
01015         }
01016         // TODO:
01017         // GetNamedSecurityInfo(source, GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION)
01018         // SetNamedSecurityInfo(target, GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION)
01019 
01020         ofs.clear();
01021         ofs.open(filenameout.c_str(), std::ios::out | std::ios::binary);
01022         if( ofs.fail() || !ofs.is_open() ) {
01023                 HRESULT hr = HRESULT_FROM_WIN32(GetLastError());
01024                 ofs.close();
01025                 ofs.clear();
01026                 _bstr_t err;
01027                 GetErrorInfo(hr, err.GetAddress());
01028                 throw_com_error(hr, _bstr_t(L"Error saving '") + filenameout.c_str() + L"': " + err);
01029         }
01030 
01031         write(metaprojectid);
01032 
01033         objects_iterator i = objects.begin();
01034         objects_iterator e = objects.end();
01035         while( i != e )
01036         {
01037                 ASSERT( (*i).first.metaid != METAID_NONE );
01038                 ASSERT( (*i).first.objid != OBJID_NONE );
01039 
01040                 if( ((*i).first.metaid == METAID_ROOT && (*i).first.objid == OBJID_ROOT)
01041                         || !(*i).second.HasEmptyPointers() )
01042                 {
01043                         write( (metaid_type)(*i).first.metaid );
01044                         write( (objid_type)(*i).first.objid );
01045 
01046                         (*i).second.Write(this);
01047                 }
01048 
01049                 ++i;
01050         }
01051 
01052         write((metaid_type)METAID_NONE);
01053 
01054         if( ofs.fail() )
01055                 HR_THROW(E_FILEOPEN);
01056 
01057         ofs.close();
01058 
01059         if( ofs.fail() )
01060                 HR_THROW(E_FILEOPEN);
01061 
01062         file_buffer.~membuf();
01063         new ((void*)&file_buffer) membuf();
01064 
01065         if (origfname == filename)
01066         {
01067                 BOOL succ = MoveFileExW(filenameout.c_str(), filename.c_str(), MOVEFILE_REPLACE_EXISTING);
01068                 if (!succ)
01069                 {
01070                         HR_THROW(HRESULT_FROM_WIN32(GetLastError()));
01071                 }
01072         }
01073 
01074         if (file_buffer.open((keepoldname ? origfname : filename).c_str()) != 0) {
01075                 HR_THROW(HRESULT_FROM_WIN32(GetLastError()));
01076         }
01077         cifs = file_buffer.getBegin();
01078         cifs_eof = file_buffer.getEnd();
01079 }
01080 
01081 // KMS: due to a bug in MgaFolder::CopyFCOs (ObjTreeCopyFoldersToo) fixed in r2297, some mga files may have duplicate GUIDs
01082 static void SetNewGuid(CCoreBinFile* p_bf, BinObject& o)
01083 {
01084         CComVariant l1, l2, l3, l4;
01085         l4.vt = l3.vt = l2.vt = l1.vt = VT_I4;
01086         getMeAGuid( &l1.lVal, &l2.lVal, &l3.lVal, &l4.lVal);
01087 
01088         binattrs_iterator i = o.binattrs.begin();
01089         binattrs_iterator e = o.binattrs.end();
01090         while( i != e)
01091         {
01092                 switch (i->attrid)
01093                 {
01094                 case ATTRID_GUID1:
01095                         i->Set(p_bf, l1);
01096                         break;
01097                 case ATTRID_GUID2:
01098                         i->Set(p_bf, l2);
01099                         break;
01100                 case ATTRID_GUID3:
01101                         i->Set(p_bf, l3);
01102                         break;
01103                 case ATTRID_GUID4:
01104                         i->Set(p_bf, l4);
01105                         break;
01106                 default:
01107                         break;
01108                 }
01109                 i++;
01110         }
01111 }
01112 
01113 struct GUID_hash {
01114         size_t operator()(const GUID& guid) const
01115         {
01116                 int* iGuid = (int*)(void*)&guid;
01117                 return iGuid[0] ^ iGuid[1] ^ iGuid[2] ^ iGuid[3];
01118         }
01119 };
01120 
01121 void CCoreBinFile::LoadProject()
01122 {
01123         InitMaxObjIDs();
01124 
01125         if (file_buffer.open(filename.c_str()) != 0) {
01126                 HRESULT hr = HRESULT_FROM_WIN32(GetLastError());
01127                 _bstr_t err;
01128                 GetErrorInfo(hr, err.GetAddress());
01129                 throw_com_error(hr, _bstr_t(L"Error opening '") + filename.c_str() + L"': " + err);
01130         }
01131         cifs = file_buffer.getBegin();
01132         cifs_eof = file_buffer.getEnd();
01133 
01134         std::unordered_map<GUID, bool, GUID_hash> guids;
01135 
01136         bindata guid;
01137         read(guid);
01138 
01139         if( !(guid == metaprojectid) )
01140                 HR_THROW(E_PROJECT_MISMATCH);
01141 
01142         ASSERT( resolvelist.empty() );
01143         bool oldReg_found = false;
01144 
01145         for(;;)
01146         {
01147                 metaid_type metaid;
01148                 read(metaid);
01149                 if( metaid == METAID_NONE )
01150                         break;
01151 
01152                 objid_type objid;
01153                 read(objid);
01154                 ASSERT( objid != OBJID_NONE );
01155 
01156                 maxobjids_iterator i = maxobjids.find(metaid);
01157                 if (i == maxobjids.end())
01158                 {
01159                         // e.g. 0x79==121: registry node from old-style registry
01160                         i = maxobjids.insert(maxobjids_type::value_type(metaid, 1)).first;
01161                 }
01162 
01163                 if( i->second < objid )
01164                         i->second = objid;
01165 
01166                 metaobjidpair_type idpair;
01167                 idpair.metaid = metaid;
01168                 idpair.objid = objid;
01169 
01170                 std::pair<objects_iterator, bool> t = objects.insert(
01171                         objects_type::value_type(idpair,BinObject()));
01172                 ASSERT( t.second );
01173 
01174                 opened_object = t.first;
01175                 isEmpty = false;
01176                 opened_object->second.deleted = false;
01177                 opened_object->second.Read(this);
01178                 
01179                 // if the object read is folder or fco and it does NOT have guid attributes (old version mga file)
01180                 if( metaid >= DTID_MODEL && metaid <= DTID_FOLDER)      // 101 .. 106
01181                 {
01182                         bool stat_found( false);
01183 
01184                         GUID zero_guid = {0};
01185                         GUID guid = {0};
01186                         opened_object->second.HasGuidAndStatAttributes(guid, &stat_found, &oldReg_found);
01187 
01188                         if(guid == zero_guid) // we will create guid attributes for it
01189                                 opened_object->second.CreateGuidAttributes( this);
01190 
01191                         std::pair<std::hash_map<GUID, bool>::iterator, bool> guid_insert = guids.emplace(std::make_pair(guid, true));
01192                         if (guid_insert.second == false)
01193                         {
01194                                 SetNewGuid(this, opened_object->second);
01195                         }
01196 
01197                         if( !stat_found && ( metaid == DTID_MODEL || metaid == DTID_FOLDER)) // we will create status attribute for M and F
01198                                 opened_object->second.CreateStatusAttribute( this);
01199                 }
01200         }
01201 
01202         resolvelist_type::iterator i = resolvelist.begin();
01203         resolvelist_type::iterator e = resolvelist.end();
01204         while( i != e )
01205         {
01206                 opened_object = i->obj;
01207                 isEmpty = false;
01208                 
01209                 // ASSERT( !isEmpty ); 
01210 
01211                 BinAttrBase *base = opened_object->second.Find(i->attrid);
01212                 ASSERT( base != NULL );
01213 
01214                 ASSERT( base->GetValType() == VALTYPE_POINTER );
01215 
01216                 objects_iterator j = objects.find( i->idpair );
01217                 if( j == objects.end() )
01218                         HR_THROW(E_BINFILE);
01219 
01220                 ((BinAttr<VALTYPE_POINTER>*)base)->Set(this, j);
01221 
01222                 ++i;
01223         }
01224 
01225         isEmpty = true;
01226         resolvelist.clear();
01227 
01228         if (oldReg_found) {
01229                 for (auto it = objects.begin(); it != objects.end(); it++)
01230                 {
01231                         if (it->first.metaid >= DTID_MODEL && it->first.metaid <= DTID_FOLDER)  // 101 .. 106
01232                         {
01233                                 it->second.UpgradeRegistryIfNecessary(this);
01234                         }
01235                 }
01236                 for (auto it = objects.begin(); it != objects.end(); )
01237                 {
01238                         if (it->first.metaid == DTID_REGNODE)
01239                                 objects.erase(it++);
01240                         else
01241                                 it++;
01242                 }
01243         }
01244 
01245         ofs.clear();
01246           // FIXME: set read_only correctly
01247         read_only = false;
01248 }
01249 
01250 STDMETHODIMP CCoreBinFile::OpenProject(BSTR connection, VARIANT_BOOL *ro_mode) {
01251         if( IsOpened() || metaproject == NULL )
01252                 COMRETURN(E_INVALID_USAGE);
01253 
01254         COMTRY
01255         {
01256                 if (SysStringLen(connection))
01257                         filename = connection;
01258                 if (!(std::wstring(filename, 0, 4) == L"MGA="))
01259                         throw_com_error(E_INVALID_USAGE, L"Connection string must start with MGA=");
01260 
01261                 filename.erase(0, 4);
01262 
01263                 LoadProject();
01264 
01265 
01266                 modified = false;
01267                 if(ro_mode) *ro_mode = read_only ? VARIANT_TRUE : VARIANT_FALSE;
01268 
01269                 ASSERT( IsOpened() );
01270         }
01271         COMCATCH( CancelProject(); )
01272 }
01273 
01274 STDMETHODIMP CCoreBinFile::CreateProject(BSTR connection)
01275 {
01276         if( IsOpened() || metaproject == NULL )
01277                 COMRETURN(E_INVALID_USAGE);
01278 
01279         COMTRY
01280         {
01281                 if (SysStringLen(connection))
01282                         filename = connection;
01283                 if( !(std::wstring(filename, 0, 4) == L"MGA=") )
01284                         throw_com_error(E_INVALID_USAGE, L"Connection string must start with MGA=");
01285 
01286 
01287                 filename.erase(0, 4);
01288 
01289                 InitMaxObjIDs();
01290 
01291                 CComObjPtr<ICoreMetaObject> mo;
01292                 COMTHROW( metaproject->get_Object(METAID_ROOT, PutOut(mo)) );
01293                 ASSERT( mo != NULL );
01294 
01295                 maxobjids_iterator i = maxobjids.find(METAID_ROOT);
01296                 i->second = OBJID_ROOT;
01297                 
01298                 metaobjidpair_type idpair;
01299                 idpair.metaid = METAID_ROOT;
01300                 idpair.objid = OBJID_ROOT;
01301 
01302                 std::pair<objects_iterator, bool> t = objects.insert(
01303                         objects_type::value_type(idpair,BinObject()));
01304                 ASSERT( t.second );
01305 
01306                 t.first->second.deleted = false;
01307                 t.first->second.CreateAttributes(mo);
01308 
01309                 if (filename.empty())
01310                         filename = L".";
01311 
01312                 modified = false;
01313 
01314                 ASSERT( IsOpened() );
01315         }
01316         COMCATCH( CancelProject(); )
01317 }
01318 
01319 STDMETHODIMP CCoreBinFile::SaveProject(BSTR connection, VARIANT_BOOL keepoldname = VARIANT_TRUE) 
01320 {
01321         std::wstring origfname = filename;
01322         COMTRY
01323         {
01324                 std::wstring fn;
01325                 if (SysStringLen(connection))
01326                         fn = connection;
01327 
01328                 if( !fn.empty() ) 
01329                 {
01330                         if( !(std::wstring(fn, 0, 4) == L"MGA=") )
01331                         {
01332                                 throw_com_error(E_INVALID_USAGE, L"Connection string must start with MGA=");
01333                         }
01334 
01335                         fn.erase(0, 4);
01336                         filename = fn;
01337                         if(filename.empty())
01338                                 filename = L".";
01339                 }
01340                 if (filename == L".")
01341                         COMTHROW(E_NAMEMISSING);
01342                 SaveProject(origfname, keepoldname != VARIANT_FALSE);
01343                 if (keepoldname != VARIANT_FALSE)
01344                         filename = origfname;
01345         }
01346         COMCATCH( filename = origfname;)
01347 }
01348 
01349 STDMETHODIMP CCoreBinFile::CloseProject( VARIANT_BOOL abort) {
01350         if( !IsOpened() || metaproject == NULL )
01351                 COMRETURN(E_INVALID_USAGE);
01352 
01353         COMTRY
01354         {
01355                 if( abort == VARIANT_FALSE && modified && !(filename == L".")) 
01356                 {
01357                         HRESULT hr = SaveProject(NULL);
01358                         if (FAILED(hr))
01359                                 HR_THROW(hr);
01360                 }
01361 
01362                 ASSERT( IsOpened() );
01363 
01364                 CancelProject();
01365         }
01366         COMCATCH(;)
01367 }
01368 
01369 STDMETHODIMP CCoreBinFile::BeginTransaction()
01370 {
01371         if( !IsOpened() || InTransaction() )
01372                 COMRETURN(E_INVALID_USAGE);
01373 
01374         ASSERT( deleted_objects.empty() );
01375         ASSERT( created_objects.empty() );
01376 
01377         intrans = true;
01378 
01379         return S_OK;
01380 }
01381 
01382 STDMETHODIMP CCoreBinFile::CommitTransaction()
01383 {
01384         if( !InTransaction() )
01385                 COMRETURN(E_INVALID_USAGE);
01386 
01387         ASSERT( IsOpened() );
01388 
01389         CloseObject();
01390 
01391         auto i = deleted_objects.begin();
01392         auto e = deleted_objects.end();
01393         while( i != e )
01394         {
01395                 ASSERT( (*i)->second.deleted );
01396 
01397                 objects.erase(*i);
01398 
01399                 ++i;
01400         }
01401 
01402         undos.clear();
01403         deleted_objects.clear();
01404         created_objects.clear();
01405 
01406         intrans = false;
01407 
01408         return S_OK;
01409 }
01410 
01411 STDMETHODIMP CCoreBinFile::AbortTransaction()
01412 {
01413         if( !InTransaction() )
01414                 COMRETURN(E_INVALID_USAGE);
01415 
01416         ASSERT( IsOpened() );
01417 
01418         CloseObject();
01419 
01420         undos_iterator j = undos.begin();
01421         undos_iterator f = undos.end();
01422         while( j != f )
01423         {
01424                 j->first->Set(this, j->second);
01425 
01426                 ++j;
01427         }
01428 
01429         auto i = deleted_objects.begin();
01430         auto e = deleted_objects.end();
01431         while( i != e )
01432         {
01433                 ASSERT( (*i)->second.deleted );
01434 
01435                 (*i)->second.deleted = false;
01436 
01437                 ++i;
01438         }
01439 
01440         i = created_objects.begin();
01441         e = created_objects.end();
01442         while( i != e )
01443         {
01444                 ASSERT( !(*i)->second.deleted );
01445 
01446                 objects.erase(*i);
01447 
01448                 ++i;
01449         }
01450 
01451         undos.clear();
01452         deleted_objects.clear();
01453         created_objects.clear();
01454 
01455         intrans = false;
01456 
01457         return S_OK;
01458 }
01459 
01460 STDMETHODIMP CCoreBinFile::get_StorageType(long *p)
01461 {
01462         CHECK_OUT(p);
01463 
01464         *p = 0;
01465         return S_OK;
01466 }
01467