GME  13
CoreBinFile.h
Go to the documentation of this file.
00001 
00002 #ifndef MGA_COREBINFILE_H
00003 #define MGA_COREBINFILE_H
00004 
00005 #include "CoreDictionaryAttributeValue.h"
00006 
00007 #include <fstream>//fstream.h
00008 #include <list>//slist
00009 #include <map>
00010 #include <vector>
00011 #include <algorithm>
00012 #include <memory>
00013 
00014 #include "windows.h"
00015 class membuf
00016 {
00017         public:
00018         membuf() : 
00019                 begin(0), end(0), hFile(INVALID_HANDLE_VALUE), hFileMappingObject(INVALID_HANDLE_VALUE)
00020                 { }
00021         
00022         int open(const wchar_t* filename) {
00023                 ASSERT(hFile == INVALID_HANDLE_VALUE);
00024                 hFile = CreateFileW(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
00025                 if (hFile == INVALID_HANDLE_VALUE) {
00026                         return 1;
00027                 }
00028                 DWORD filesize = GetFileSize(hFile, NULL);
00029                 if (filesize == INVALID_FILE_SIZE || filesize == 0) {
00030                         return 1;
00031                 }
00032                 hFileMappingObject = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
00033                 if (hFileMappingObject == INVALID_HANDLE_VALUE) {
00034                         return 1;
00035                 }
00036                 begin = (char*)MapViewOfFile(hFileMappingObject, FILE_MAP_READ, 0, 0, 0);
00037                 if (begin == NULL) {
00038                         return 1;
00039                 }
00040                 end = begin + filesize;
00041                 return 0;
00042         }
00043 
00044         ~membuf() {
00045                 if (begin)
00046                         UnmapViewOfFile(begin);
00047                 if (hFileMappingObject != INVALID_HANDLE_VALUE)
00048                         CloseHandle(hFileMappingObject);
00049                 if (hFile != INVALID_HANDLE_VALUE)
00050                         CloseHandle(hFile);
00051         }
00052 
00053         char* getBegin() const {
00054                 return begin;
00055         }
00056         char* getEnd() const {
00057                 return end;
00058         }
00059 
00060         private:
00061                 membuf(const membuf&);
00062                 membuf& operator=(const membuf&);
00063 
00064                 HANDLE hFile,hFileMappingObject;
00065                 char* begin, * end;
00066 };
00067 
00068 class CCoreBinFile;
00069 class BinAttrUnion;
00070 
00071 // --------------------------- BinAttr
00072 class __declspec(novtable) BinAttrBase
00073 {
00074 public:
00075         BinAttrBase() : attrid(ATTRID_NONE) { }
00076         BinAttrBase(attrid_type attrid) : attrid(attrid) { }
00077         virtual ~BinAttrBase() { }
00078 
00079         attrid_type attrid;
00080 
00081         static BinAttrBase *Create(BinAttrBase& attr, valtype_type valtype);
00082 
00083         virtual valtype_type GetValType() const NOTHROW = 0;
00084         virtual void Set(CCoreBinFile *binfile, VARIANT p) = 0;
00085         virtual void Get(CCoreBinFile *binfile, VARIANT *p) = 0;
00086         virtual void Write(CCoreBinFile *binfile) = 0;
00087         virtual void Read(CCoreBinFile *binfile) = 0;
00088         // virtual move constructor
00089         virtual void move(BinAttrUnion&& dest) = 0;
00090 };
00091 
00092 class __declspec(novtable) BinAttrUnion : public BinAttrBase
00093 {
00094 public:
00095         BinAttrUnion() { }
00096         explicit BinAttrUnion(attrid_type attrid) : BinAttrBase(attrid) { }
00097         virtual ~BinAttrUnion() { }
00098 
00099         virtual valtype_type GetValType() const NOTHROW { DebugBreak(); return 0; }
00100         virtual void Set(CCoreBinFile *binfile, VARIANT p) { DebugBreak(); }
00101         virtual void Get(CCoreBinFile *binfile, VARIANT *p) { DebugBreak(); }
00102         virtual void Write(CCoreBinFile *binfile) { DebugBreak(); }
00103         virtual void Read(CCoreBinFile *binfile) { DebugBreak(); }
00104         virtual void move(BinAttrUnion&& dest) { DebugBreak(); }
00105 
00106         // that is a subtype of BinAttrUnion
00107         // that must not be BinAttrUnion because of __declspec(novtable)
00108         BinAttrUnion(BinAttrUnion&& that) {
00109                 // volatile to read the vtable of that
00110                 BinAttrUnion* volatile that_ = &that;
00111                 that_->move(std::move(*this));
00112         }
00113 
00114         BinAttrUnion& operator=(BinAttrUnion&& that) {
00115                 BinAttrUnion* volatile that_ = &that;
00116                 that_->move(std::move(*this));
00117                 return *this;
00118         }
00119         BinAttrUnion(const BinAttrUnion& that) {
00120                 // FIXME
00121         }
00122         // BinAttrUnion is guaranteed to have enough space to contain any BinAttr<*>
00123         // (Ideally we'd do union { char [sizeof(BinAttrBase) - sizeof(BinAttr<*>) }, but that requires method definitions for BinAttr<*>::* to be separated from the declaration)
00124 #ifdef _DEBUG
00125         char pad[12 + 2 * sizeof(void*)];
00126 #else
00127         char pad[4 + sizeof(void*)];
00128 #endif
00129 };
00130 
00131 typedef std::vector<BinAttrUnion> binattrs_type;
00132 typedef binattrs_type::iterator binattrs_iterator;
00133 
00134 template<valtype_enum VALTYPE>
00135 class BinAttr;
00136 
00137 
00138 // --------------------------- BinObject
00139 
00140 class BinObject
00141 {
00142 public:
00143         ~BinObject() { DestroyAttributes(); }
00144 
00145         // binattrs actually contains elements of type BinAttr<*>
00146         binattrs_type binattrs;
00147         bool deleted;
00148 
00149         void HasGuidAndStatAttributes(GUID& guid, bool* p_statusFound, bool* p_oldRegFound);
00150         void CreateGuidAttributes( CCoreBinFile* p_bf);
00151         void CreateStatusAttribute( CCoreBinFile* p_bf);
00152         void UpgradeRegistryIfNecessary(CCoreBinFile* binFile);
00153 
00154         BinAttrBase *Find(attrid_type attrid)
00155         {
00156                 binattrs_iterator i = binattrs.begin();
00157                 binattrs_iterator e = binattrs.end();
00158                 while( i != e && (i)->attrid != attrid )
00159                         ++i;
00160 
00161                 if( i == e )
00162                         HR_THROW(E_BINFILE);
00163 
00164                 return &*i;
00165         }
00166 
00167         void CreateAttributes(ICoreMetaObject *metaobject);
00168         void DestroyAttributes();
00169         void Read(CCoreBinFile *binfile);
00170         void Write(CCoreBinFile *binfile);
00171 
00172         bool HasEmptyPointers() const;
00173 };
00174 
00175 typedef stdext::hash_map< metaobjidpair_type
00176                         , BinObject
00177                         , metaobjid2pair_hashfunc
00178                         > objects_type;
00179 typedef objects_type::iterator objects_iterator;
00180 
00181 
00182 // --------------------------- CCoreBinFile
00183 
00184 class ATL_NO_VTABLE CCoreBinFile : 
00185         public CComObjectRootEx<CComSingleThreadModel>,
00186         public IDispatchImpl<ICoreStorage, &__uuidof(ICoreStorage), &__uuidof(__MGACoreLib)>,
00187         public ISupportErrorInfoImpl<&__uuidof(ICoreStorage)>,
00188         public CComCoClass<CCoreBinFile, &__uuidof(CoreBinFile)>
00189 {
00190 public:
00191         CCoreBinFile();
00192         ~CCoreBinFile();
00193 
00194 BEGIN_COM_MAP(CCoreBinFile)
00195         COM_INTERFACE_ENTRY(ICoreStorage)
00196         COM_INTERFACE_ENTRY(IDispatch)
00197         COM_INTERFACE_ENTRY(ISupportErrorInfo)
00198 END_COM_MAP()
00199 
00200 DECLARE_REGISTRY_RESOURCEID(IDR_COREBINFILE)
00201 
00202 // ------- MetaProject
00203 
00204 public:
00205         CComObjPtr<ICoreMetaProject> metaproject;
00206         bindata metaprojectid;
00207 
00208         STDMETHODIMP get_MetaProject(ICoreMetaProject **p);
00209         STDMETHODIMP put_MetaProject(ICoreMetaProject *p);
00210 
00211         void OpenMetaProject();
00212         void CloseMetaProject() NOTHROW;
00213 
00214 // ------- MetaObject
00215 
00216 public:
00217         CComObjPtr<ICoreMetaObject> metaobject;
00218         metaid_type metaid;
00219 
00220         STDMETHODIMP get_MetaObject(ICoreMetaObject **p);
00221         STDMETHODIMP put_MetaObject(ICoreMetaObject *p);
00222 
00223         STDMETHODIMP get_MetaID(metaid_type *p);
00224         STDMETHODIMP put_MetaID(metaid_type p);
00225 
00226         void OpenMetaObject();
00227         void CloseMetaObject() NOTHROW;
00228 
00229 // ------- MetaAttribute
00230 
00231 public:
00232         CComObjPtr<ICoreMetaAttribute> metaattribute;
00233         attrid_type attrid;
00234 
00235         STDMETHODIMP get_MetaAttribute(ICoreMetaAttribute **p);
00236         STDMETHODIMP put_MetaAttribute(ICoreMetaAttribute *p);
00237 
00238         STDMETHODIMP get_AttrID(attrid_type *p);
00239         STDMETHODIMP put_AttrID(attrid_type p);
00240 
00241         void OpenMetaAttribute();
00242         void CloseMetaAttribute() NOTHROW;
00243 
00244 // ------- Ios
00245 
00246 public:
00247         char* cifs;
00248         char* cifs_eof;
00249 
00250         std::ofstream ofs;
00251 
00252 public:
00253 #define CoreBinFile_read(a, size) if (size > cifs_eof - cifs) HR_THROW(E_FILEOPEN); memcpy(&a, cifs, size); cifs += size;
00254         void read(unsigned char &a) { CoreBinFile_read(a, sizeof(unsigned char)); }
00255         void read(short &a) { CoreBinFile_read(a, sizeof(short)); }
00256         void read(int &a) { CoreBinFile_read(a, sizeof(int)); }
00257         void read(long &a)  { CoreBinFile_read(a, sizeof(long)); }
00258         void read(double &a)  { CoreBinFile_read(a, sizeof(double)); }
00259         void read(CComBstrObj &a);
00260         void read(CComBstrObj &ss, char*& cifs);
00261         void read(bindata &a);
00262         void read(unsigned char*& b, int& len);
00263         void readstring(char*& pos);
00264 
00265         void write(unsigned char a) { ofs.write((const char*)&a, sizeof(unsigned char)); }
00266         void write(short a) { ofs.write((const char*)&a, sizeof(short)); }
00267         void write(int a) { ofs.write((const char*)&a, sizeof(int)); }
00268         void write(long a) { ofs.write((const char*)&a, sizeof(long)); }
00269         void write(double a) { ofs.write((const char*)&a, sizeof(double)); }
00270         void write(const CComBstrObj &a);
00271         void write(const bindata &a);
00272         void write(const unsigned char* a, int len);
00273         void write(const wchar_t* a, int len) {
00274                 write((const unsigned char*)a, len * sizeof(wchar_t));
00275         }
00276         void writestring(const char* pos);
00277 // ------- Attribute
00278 
00279 public:
00280         typedef std::map<BinAttrBase*, CComVariant> undos_type;
00281         typedef undos_type::iterator undos_iterator;
00282 
00283         undos_type undos;
00284 
00285         STDMETHODIMP get_AttributeValue(VARIANT *p);
00286         STDMETHODIMP put_AttributeValue(VARIANT p);
00287 
00288 // ------- Object
00289 
00290 public:
00291         objects_type objects;
00292         objects_iterator opened_object;
00293         bool isEmpty;
00294 
00295         typedef core::hash_map<metaid_type, objid_type> maxobjids_type;
00296         typedef maxobjids_type::iterator maxobjids_iterator;
00297 
00298         maxobjids_type maxobjids;
00299         core::forward_list<objects_iterator> deleted_objects;
00300         core::forward_list<objects_iterator> created_objects;
00301 
00302         struct resolve_type
00303         {
00304                 objects_iterator obj;
00305                 attrid_type attrid;
00306                 metaobjidpair_type idpair;
00307         };
00308 
00309         typedef core::forward_list<resolve_type> resolvelist_type;
00310         resolvelist_type resolvelist;
00311 
00312         void InitMaxObjIDs();
00313 
00314 public:
00315         STDMETHODIMP OpenObject(objid_type objid);
00316         STDMETHODIMP CreateObject(objid_type *objid);
00317         STDMETHODIMP CloseObject() NOTHROW;
00318 
00319         STDMETHODIMP DeleteObject();
00320         STDMETHODIMP LockObject();
00321 
00322 // ------- Project
00323 
00324 public:
00325         std::wstring filename;
00326         bool read_only;
00327         bool intrans;
00328         bool modified;
00329 
00330         membuf file_buffer;
00331         bool IsOpened() const { return !filename.empty(); }
00332         bool InTransaction() const { return intrans; }
00333 
00334         void CancelProject() NOTHROW;
00335         void SaveProject(const std::wstring& origfname, bool keepoldname);
00336         void LoadProject();
00337 
00338 public:
00339         STDMETHODIMP OpenProject(BSTR connection, VARIANT_BOOL *ro_mode);
00340         STDMETHODIMP CreateProject(BSTR connection);
00341         STDMETHODIMP CloseProject( VARIANT_BOOL abort = VARIANT_FALSE) NOTHROW;
00342         STDMETHODIMP SaveProject(BSTR connection, VARIANT_BOOL keepoldname);
00343         STDMETHODIMP DeleteProject() { return E_NOTIMPL; }
00344 
00345         STDMETHODIMP BeginTransaction();
00346         STDMETHODIMP CommitTransaction();
00347         STDMETHODIMP AbortTransaction();
00348 
00349         STDMETHODIMP get_StorageType(long *p);
00350 };
00351 
00352 // --------------------------- BinAttr<VALTYPE_LONG>
00353 
00354 template<>
00355 class BinAttr<VALTYPE_LONG> : public BinAttrBase
00356 {
00357 public:
00358         BinAttr() : a(0) { }
00359 
00360         long a;
00361 
00362         virtual valtype_type GetValType() const NOTHROW { return VALTYPE_LONG; }
00363         virtual void Set(CCoreBinFile *binfile, VARIANT p)
00364         { ASSERT( binfile != NULL ); binfile->modified = true; CopyTo(p, a); }
00365 
00366         virtual void Get(CCoreBinFile *binfile, VARIANT *p) { CopyTo(a, p); }
00367         virtual void Write(CCoreBinFile *binfile) { binfile->write(a); }
00368         virtual void Read(CCoreBinFile *binfile) { binfile->read(a); }
00369 
00370     BinAttr(BinAttr<VALTYPE_LONG>&& that) : BinAttrBase(that.attrid), a(that.a) { }
00371     virtual void move(BinAttrUnion&& dest) {
00372         new (&dest) BinAttr<VALTYPE_LONG>(std::move(*this));
00373     }
00374 };
00375 
00376 // --------------------------- BinAttr<VALTYPE_REAL>
00377 
00378 template<>
00379 class BinAttr<VALTYPE_REAL> : public BinAttrBase
00380 {
00381 public:
00382         BinAttr() : a(0) { }
00383 
00384         double a;
00385 
00386         virtual valtype_type GetValType() const NOTHROW { return VALTYPE_REAL; }
00387         virtual void Set(CCoreBinFile *binfile, VARIANT p)
00388         { ASSERT( binfile != NULL ); binfile->modified = true; CopyTo(p, a); }
00389 
00390         virtual void Get(CCoreBinFile *binfile, VARIANT *p) { CopyTo(a, p); }
00391         virtual void Write(CCoreBinFile *binfile) { binfile->write(a); }
00392         virtual void Read(CCoreBinFile *binfile) { binfile->read(a); }
00393         BinAttr(BinAttr<VALTYPE_REAL>&& that) : BinAttrBase(that.attrid), a(that.a) { }
00394         virtual void move(BinAttrUnion&& dest) {
00395                 new (&dest) BinAttr<VALTYPE_REAL>(std::move(*this));
00396         }
00397 };
00398 
00399 // --------------------------- BinAttr<VALTYPE_STRING>
00400 
00401 template<>
00402 class BinAttr<VALTYPE_STRING> : public BinAttrBase
00403 {
00404 public:
00405         BinAttr() : pos(NULL) { }
00406 
00407         CComBstrObj a;
00408         // Lazy read: if pos is non-null, a is invalid and 
00409         //    pos points to the pascal-style UTF-8 string in the memory-mapped mga file
00410         char* pos;
00411 
00412         virtual valtype_type GetValType() const NOTHROW { return VALTYPE_STRING; }
00413         virtual void Set(CCoreBinFile *binfile, VARIANT p)
00414         { 
00415                 ASSERT( binfile != NULL ); 
00416                 binfile->modified = true; 
00417                 CopyTo(p, a);
00418                 pos = NULL;
00419         }
00420 
00421         virtual void Get(CCoreBinFile *binfile, VARIANT *p) {
00422                 if (pos != NULL) {
00423                         binfile->read(this->a, this->pos);
00424                         this->pos = NULL;
00425                 }
00426                 CopyTo(a, p);
00427         }
00428         virtual void Write(CCoreBinFile *binfile) {
00429                 if (pos != NULL) {
00430                         binfile->read(this->a, this->pos);
00431                         this->pos = NULL;
00432                 }
00433                 binfile->write(a);
00434         }
00435         virtual void Read(CCoreBinFile *binfile) {
00436                 binfile->readstring(pos);
00437                 // to disable lazy read:
00438                 //binfile->read(a, pos);
00439                 //pos = NULL;
00440         }
00441         BinAttr(BinAttr<VALTYPE_STRING>&& that) : BinAttrBase(that.attrid), a(std::move(that.a)), pos(that.pos) { }
00442         virtual void move(BinAttrUnion&& dest) {
00443                 new (&dest) BinAttr<VALTYPE_STRING>(std::move(*this));
00444         }
00445 };
00446 
00447 // --------------------------- BinAttr<VALTYPE_BINARY>
00448 
00449 template<class Type>
00450 struct free_deleter {
00451         void operator()(Type* p) { free(p); }
00452 };
00453 
00454 template<>
00455 class BinAttr<VALTYPE_BINARY> : public BinAttrBase
00456 {
00457 public:
00458         BinAttr() : data(0), need_free(false) { }
00459         virtual ~BinAttr() { if (need_free) free(data); }
00460 
00461         unsigned char* data;
00462         // memcpy: if lazy read, data is not guaranteed to be properly aligned for int*
00463         int get_len() const { int ret; memcpy(&ret, data, sizeof(int)); return ret; }
00464         void put_len(int len) { memcpy(data, &len, sizeof(len)); }
00465         __declspec(property(get=get_len, put=put_len)) int len;
00466         unsigned char* get_value() const { return (data + sizeof(len)); }
00467         __declspec(property(get=get_value)) unsigned char* value;
00468         bool need_free;
00469 
00470         virtual valtype_type GetValType() const NOTHROW { return VALTYPE_BINARY; }
00471         virtual void Set(CCoreBinFile *binfile, VARIANT v)
00472         {
00473                 ASSERT( binfile != NULL );
00474                 binfile->modified = true;
00475                 if( v.vt == (VT_I4 | VT_ARRAY) )
00476                 {
00477                         if (need_free) free(data);
00478                         data = (unsigned char*)malloc(sizeof(len) + sizeof(long) * GetArrayLength(v));
00479                         need_free = true;
00480                         len = sizeof(long) * GetArrayLength(v);
00481                         CopyTo(v, (long*)(value), (long*)(value) + len/sizeof(long));
00482                 }
00483                 else
00484                 {
00485                         if (GetArrayLength(v)==0)
00486                         {
00487                                 if (need_free) free(data);
00488                                 data = 0;
00489                         }
00490                         else
00491                         {
00492                                 int len = GetArrayLength(v);
00493                                 if (need_free) free(data);
00494                                 data = (unsigned char*) malloc(sizeof(this->len) + len);
00495                                 need_free = true;
00496                                 this->len = len;
00497                                 CopyTo(v, value, value + len);
00498                         }
00499                 }
00500         }
00501 
00502         virtual void Get(CCoreBinFile *binfile, VARIANT *p) { 
00503                 if (data == 0) {
00504                         unsigned char* pnull=NULL;
00505                         CopyTo(pnull, pnull, p);
00506                 } else
00507                         CopyTo(value, value + len, p);
00508         }
00509         virtual void Write(CCoreBinFile *binfile) { 
00510                 if (data)
00511                 {
00512                         if (!need_free)
00513                         {
00514                                 // need to get data off the disk; the file is going away
00515                                 unsigned char* olddata = this->data;
00516                                 int len = this->len;
00517                                 this->data = (unsigned char*)malloc(sizeof(len) + len);
00518                                 this->need_free = true;
00519                                 this->len = len;
00520                                 memcpy(value, olddata+sizeof(len), len);
00521                         }
00522                         binfile->write(value, len);
00523                 }
00524                 else
00525                         binfile->write((unsigned char*)NULL, 0);
00526         }
00527         virtual void Read(CCoreBinFile *binfile) { 
00528                 data = (unsigned char*)binfile->cifs;
00529                 int len = this->len;
00530                 // to test without lazy read:
00531                 //data = (unsigned char*)malloc(sizeof(len) + len);
00532                 //need_free = true;
00533                 //this->len = len;
00534                 //memcpy(value, binfile->cifs+sizeof(len), len);
00535                 binfile->cifs += sizeof(len) + len;
00536         }
00537         BinAttr(BinAttr<VALTYPE_BINARY>&& that) : BinAttrBase(that.attrid), data(that.data), need_free(that.need_free) { that.need_free = false; }
00538         virtual void move(BinAttrUnion&& dest) {
00539                 new (&dest) BinAttr<VALTYPE_BINARY>(std::move(*this));
00540         }
00541 };
00542 
00543 // --------------------------- BinAttr<VALTYPE_DICT>
00544 
00545 template<>
00546 class BinAttr<VALTYPE_DICT> : public BinAttrBase
00547 {
00548 public:
00549         BinAttr() : data(0) {
00550                 CCoreDictionaryAttributeValue *val = NULL;
00551                 typedef CComObject< CCoreDictionaryAttributeValue > COMTYPE;
00552                 HRESULT hr = COMTYPE::CreateInstance((COMTYPE **)&val);
00553                 COMTHROW(hr);
00554                 dict = val;
00555         }
00556         virtual ~BinAttr() { }
00557 
00558         char* data;
00559         // memcpy: if lazy read, data is not guaranteed to be properly aligned for int*
00560         int read_len(char*& offset) const { int ret; memcpy(&ret, offset, sizeof(int)); offset += sizeof(int); return ret; }
00561 
00562         CComPtr<ICoreDictionaryAttributeValue> dict;
00563 
00564         virtual valtype_type GetValType() const NOTHROW { return VALTYPE_DICT; }
00565         virtual void Set(CCoreBinFile *binfile, VARIANT v)
00566         {
00567                 ASSERT( binfile != NULL );
00568                 ASSERT(v.vt == VT_DISPATCH);
00569                 binfile->modified = true;
00570                 dict = 0;
00571                 v.pdispVal->QueryInterface(&dict);
00572         }
00573 
00574         virtual void Get(CCoreBinFile *binfile, VARIANT *p) {
00575                 if (dict == 0) {
00576                         // lazy read
00577                         CCoreDictionaryAttributeValue* val = NULL;
00578                         typedef CComObject< CCoreDictionaryAttributeValue > COMTYPE;
00579                         HRESULT hr = COMTYPE::CreateInstance((COMTYPE **)&val);
00580                         COMTHROW(hr);
00581 
00582                         char* data = this->data;
00583                         int size = read_len(data);
00584                         while (data < this->data + size)
00585                         {
00586                                 int keysize = read_len(data);
00587                                 CComBSTR key(keysize / sizeof(wchar_t));
00588                                 memcpy(key.m_str, data, keysize);
00589                                 data += keysize;
00590                                 int valuesize = read_len(data);
00591                                 CComBSTR value(valuesize / sizeof(wchar_t));
00592                                 memcpy(value.m_str, data, valuesize);
00593                                 data += valuesize;
00594                                 val->m_dict.emplace(
00595                                         std::unordered_map<CComBSTR, CComBSTR, CComBSTR_Length>::value_type(std::move(key), std::move(value)));
00596                         }
00597 
00598                         this->dict = val;
00599                         this->data = 0;
00600                 }
00601                 CComVariant ret = dict;
00602                 COMTHROW(ret.Detach(p));
00603         }
00604         virtual void Write(CCoreBinFile *binfile) {
00605                 int size = 0;
00606 
00607                 if (dict == NULL)
00608                 {
00609                         // need to read before write, since the file is going away
00610                         CComVariant p;
00611                         Get(binfile, &p);
00612                 }
00613 
00614                 const CCoreDictionaryAttributeValue* cdict = (const CCoreDictionaryAttributeValue*)(const ICoreDictionaryAttributeValue*)dict;
00615                 for (auto it = cdict->m_dict.begin(); it != cdict->m_dict.end(); it++) {
00616                         size += sizeof(int);
00617                         size += it->first.Length() * sizeof(wchar_t);
00618                         size += sizeof(int);
00619                         size += it->second.Length() * sizeof(wchar_t);
00620                 }
00621                 binfile->write(size);
00622 
00623                 for (auto it = cdict->m_dict.begin(); it != cdict->m_dict.end(); it++) {
00624                         // binfile->write((int)it->first.Length());
00625                         binfile->write(it->first, it->first.Length());
00626                         // binfile->write((int)it->second.Length());
00627                         binfile->write(it->second, it->second.Length());
00628                 }
00629         }
00630         virtual void Read(CCoreBinFile *binfile) { 
00631                 dict = 0;
00632                 data = (char*)binfile->cifs;
00633                 int len = read_len(binfile->cifs);
00634                 binfile->cifs += len;
00635         }
00636         BinAttr(BinAttr<VALTYPE_DICT>&& that) : BinAttrBase(that.attrid), data(that.data), dict(std::move(that.dict)) { }
00637         virtual void move(BinAttrUnion&& dest) {
00638                 new (&dest) BinAttr<VALTYPE_DICT>(std::move(*this));
00639         }
00640 };
00641 
00642 // --------------------------- BinAttr<VALTYPE_LOCK>
00643 
00644 template<>
00645 class BinAttr<VALTYPE_LOCK> : public BinAttrBase
00646 {
00647 public:
00648         BinAttr() : a(0) { }
00649 
00650         lockval_type a;
00651 
00652         virtual valtype_type GetValType() const NOTHROW { return VALTYPE_LOCK; }
00653         virtual void Set(CCoreBinFile *binfile, VARIANT p) { CopyTo(p, a); }
00654         virtual void Get(CCoreBinFile *binfile, VARIANT *p) { CopyTo(a, p); }
00655         virtual void Write(CCoreBinFile *binfile) { }
00656         virtual void Read(CCoreBinFile *binfile) { a = 0; }
00657         BinAttr(BinAttr<VALTYPE_LOCK>&& that) : BinAttrBase(that.attrid), a(that.a) { }
00658         virtual void move(BinAttrUnion&& dest) {
00659                 new (&dest) BinAttr<VALTYPE_LOCK>(std::move(*this)); 
00660         }
00661 };
00662 // --------------------------- BinAttr<VALTYPE_COLLECTION>
00663 
00664 template<>
00665 class BinAttr<VALTYPE_COLLECTION> : public BinAttrBase
00666 {
00667 public:
00668         std::unique_ptr<std::vector<objects_iterator>> backing;
00669         std::vector<objects_iterator>& getbacking() const { return *backing.get(); }
00670         __declspec(property(get = getbacking )) std::vector<objects_iterator>& a;
00671 
00672         BinAttr() : backing(new std::vector<objects_iterator>()) { }
00673         virtual valtype_type GetValType() const NOTHROW { return VALTYPE_COLLECTION; }
00674         virtual void Set(CCoreBinFile *binfile, VARIANT p) { ASSERT(false); }
00675         virtual void Get(CCoreBinFile *binfile, VARIANT *p)
00676         {
00677                 ASSERT( p != NULL && p->vt == VT_EMPTY );
00678 
00679                 std::vector<metaobjidpair_type> idpairs;
00680 
00681                 std::vector<objects_iterator>::const_iterator i = a.begin();
00682                 std::vector<objects_iterator>::const_iterator e = a.end();
00683                 while( i != e )
00684                 {
00685                         idpairs.push_back( (*i)->first );
00686 
00687                         ++i;
00688                 }
00689 
00690                 CopyTo(idpairs, p);
00691         }
00692         virtual void Write(CCoreBinFile *binfile) { }
00693         virtual void Read(CCoreBinFile *binfile) { }
00694     BinAttr(BinAttr<VALTYPE_COLLECTION>&& that) : BinAttrBase(that.attrid), backing(std::move(that.backing)) { }
00695         virtual void move(BinAttrUnion&& dest) {
00696                 new (&dest) BinAttr<VALTYPE_COLLECTION>(std::move(*this));
00697         }
00698 };
00699 
00700 // --------------------------- BinAttr<VALTYPE_POINTER>
00701 
00702 template<>
00703 class BinAttr<VALTYPE_POINTER> : public BinAttrBase
00704 {
00705 public:
00706         BinAttr() : isEmpty(true) { }
00707 
00708         objects_iterator a;
00709         bool isEmpty;
00710 
00711         virtual valtype_type GetValType() const NOTHROW { return VALTYPE_POINTER; }
00712 
00713         void Set(CCoreBinFile *binfile, objects_iterator b)
00714         {
00715                 ASSERT( binfile != NULL );
00716                 ASSERT( isEmpty ); 
00717                 ASSERT( b != binfile->objects.end());
00718 
00719                 binfile->modified = true;
00720 
00721                 a = b;
00722                 isEmpty = false;
00723 
00724                 ASSERT( binfile->opened_object->second.Find(attrid) == this );
00725 
00726                 BinAttrBase *base = a->second.Find(attrid + ATTRID_COLLECTION);
00727                 ASSERT( base != NULL );
00728                 
00729                 ASSERT( base->GetValType() == VALTYPE_COLLECTION );
00730                 std::vector<objects_iterator> &objs = ((BinAttr<VALTYPE_COLLECTION>*)base)->a;
00731 
00732         #ifdef DEBUG_CONTAINERS
00733                 std::vector<objects_iterator>::iterator i = find(objs.begin(), objs.end(), a);
00734                 ASSERT( i == objs.end() );
00735         #endif
00736 
00737                 objs.push_back(binfile->opened_object);
00738         }
00739 
00740         virtual void Set(CCoreBinFile *binfile, VARIANT p)
00741         {
00742                 if( !isEmpty )
00743                 {
00744                         BinAttrBase *base = a->second.Find(attrid + ATTRID_COLLECTION);
00745                         ASSERT( base != NULL );
00746                         
00747                         ASSERT( base->GetValType() == VALTYPE_COLLECTION );
00748                         std::vector<objects_iterator> &objs = ((BinAttr<VALTYPE_COLLECTION>*)base)->a;
00749 
00750                         ASSERT( binfile->opened_object->second.Find(attrid) == this );
00751 
00752                         std::vector<objects_iterator>::iterator i = std::find(objs.begin(), objs.end(), binfile->opened_object);
00753                         ASSERT( i != objs.end() );
00754 
00755                         objs.erase(i);
00756                 }
00757 
00758                 isEmpty = true;
00759 
00760                 metaobjidpair_type idpair;
00761                 CopyTo(p, idpair);
00762 
00763                 if( idpair.metaid == METAID_NONE )
00764                 {
00765                         ASSERT( idpair.objid == OBJID_NONE );
00766                 }
00767                 else
00768                 {
00769                         ASSERT( idpair.objid != OBJID_NONE );
00770 
00771                         Set(binfile, binfile->objects.find(idpair));
00772                 }
00773         }
00774         virtual void Get(CCoreBinFile *binfile, VARIANT *p)
00775         {
00776                 if( isEmpty )
00777                 {
00778                         metaobjidpair_type idpair;
00779                         idpair.metaid = METAID_NONE;
00780                         idpair.objid = OBJID_NONE;
00781                         CopyTo(idpair, p);
00782                 }
00783                 else
00784                         CopyTo(a->first, p);
00785         }
00786 
00787         virtual void Write(CCoreBinFile *binfile)
00788         {
00789                 if( isEmpty )
00790                 {
00791                         binfile->write((metaid_type)METAID_NONE);
00792                 }
00793                 else
00794                 {
00795                         ASSERT( a->first.metaid != METAID_NONE );
00796                         ASSERT( a->first.objid != OBJID_NONE );
00797 
00798                         binfile->write((metaid_type)a->first.metaid);
00799                         binfile->write((objid_type)a->first.objid);
00800                 }
00801         }
00802 
00803         virtual void Read(CCoreBinFile *binfile)
00804         {
00805                 ASSERT( isEmpty );
00806 
00807                 metaid_type metaid;
00808                 binfile->read(metaid);
00809 
00810                 if( metaid != METAID_NONE )
00811                 {
00812                         objid_type objid;
00813                         binfile->read(objid);
00814 
00815                         ASSERT( objid != OBJID_NONE );
00816 
00817                         binfile->resolvelist.push_front(CCoreBinFile::resolve_type());
00818                         CCoreBinFile::resolve_type &b = binfile->resolvelist.front();
00819 
00820                         ASSERT( !binfile->isEmpty );
00821 
00822                         b.obj = binfile->opened_object;
00823                         b.attrid = attrid;
00824                         b.idpair.metaid = metaid;
00825                         b.idpair.objid = objid;
00826                 }
00827         }
00828         BinAttr(BinAttr<VALTYPE_POINTER>&& that) : BinAttrBase(that.attrid), a(std::move(that.a)), isEmpty(that.isEmpty) { }
00829         virtual void move(BinAttrUnion&& dest) {
00830                 new (&dest) BinAttr<VALTYPE_POINTER>(std::move(*this));
00831         }
00832 };
00833 
00834 
00835 static_assert(sizeof(BinAttr<VALTYPE_LONG>) <= sizeof(BinAttrUnion), "BinAttrUnion is too small.");
00836 static_assert(sizeof(BinAttr<VALTYPE_REAL>) <= sizeof(BinAttrUnion), "BinAttrUnion is too small.");
00837 static_assert(sizeof(BinAttr<VALTYPE_STRING>) <= sizeof(BinAttrUnion), "BinAttrUnion is too small.");
00838 static_assert(sizeof(BinAttr<VALTYPE_POINTER>) <= sizeof(BinAttrUnion), "BinAttrUnion is too small.");
00839 static_assert(sizeof(BinAttr<VALTYPE_BINARY>) <= sizeof(BinAttrUnion), "BinAttrUnion is too small.");
00840 static_assert(sizeof(BinAttr<VALTYPE_COLLECTION>) <= sizeof(BinAttrUnion), "BinAttrUnion is too small.");
00841 
00842 
00843 #endif//MGA_COREBINFILE_H