#ifndef __POOMRECORDMANAGER_H__ #define __POOMRECORDMANAGER_H__ #include #include #include #include #include "debug.h" #include "StringUtils.h" #include "VectorUtils.h" struct TypeInfo { TypeInfo() : flags(0) {} TypeInfo(const std::string& name, DWORD flags) : name(name), flags(flags) {} std::string name; DWORD flags; }; struct TagInfo { TagInfo() : fieldid(0) {} TagInfo(const std::string& name, DWORD fieldid) : name(name), fieldid(fieldid) {} std::string name; DWORD fieldid; }; typedef std::map TypeInfoMap; typedef std::map FieldInfoMap; typedef std::map TagInfoMap; class FieldInfo { public: enum { IS_STRING=1, IS_UNSIGNED=2, IS_SIGNED=4, IS_INTEGER=6, IS_BYTESIZED=8, IS_WORDSIZED=16, IS_DWORDSIZED=32 }; FieldInfo() { _typeinfo[CEVT_I2 ]= TypeInfo("I2", IS_SIGNED|IS_WORDSIZED); _typeinfo[CEVT_UI2 ]= TypeInfo("UI2", IS_UNSIGNED|IS_WORDSIZED); _typeinfo[CEVT_I4 ]= TypeInfo("I4", IS_SIGNED|IS_DWORDSIZED); _typeinfo[CEVT_UI4 ]= TypeInfo("UI4", IS_UNSIGNED|IS_DWORDSIZED); _typeinfo[CEVT_FILETIME ]= TypeInfo("FILETIME", 0); _typeinfo[CEVT_LPWSTR ]= TypeInfo("LPWSTR", IS_STRING); _typeinfo[CEVT_BLOB ]= TypeInfo("BLOB", 0); #ifdef EDB _typeinfo[CEVT_AUTO_I4 ]= TypeInfo("AUTO_I4", IS_SIGNED|IS_DWORDSIZED); _typeinfo[CEVT_AUTO_I8 ]= TypeInfo("AUTO_I8", IS_SIGNED); _typeinfo[CEVT_RECID ]= TypeInfo("RECID", IS_UNSIGNED|IS_DWORDSIZED); _typeinfo[CEVT_STREAM ]= TypeInfo("STREAM", 0); #endif _typeinfo[CEVT_BOOL ]= TypeInfo("BOOL", IS_UNSIGNED|IS_BYTESIZED); _typeinfo[CEVT_R8 ]= TypeInfo("R8", IS_SIGNED); _taginfo["a"]= TagInfo("a", 0xd1001f); // home street _taginfo["m"]= TagInfo("m", 0x96001f); // mobile nr _taginfo["h"]= TagInfo("h", 0x99001f); // home nr _taginfo["w"]= TagInfo("w", 0x97001f); // work nr _taginfo["n"]= TagInfo("n", 0x80001f); // fileas 0x82001f=first, 0x84001f=surname for (TagInfoMap::const_iterator i= _taginfo.begin() ; i!=_taginfo.end() ; i++) _fieldinfo[(*i).second.fieldid]= (*i).second; } bool isString(DWORD fieldid) const { TypeInfoMap::const_iterator i= _typeinfo.find(fieldid&0xFFFF); if (i==_typeinfo.end()) return false; return (*i).second.flags&IS_STRING; } bool isSigned(DWORD fieldid) const { TypeInfoMap::const_iterator i= _typeinfo.find(fieldid&0xFFFF); if (i==_typeinfo.end()) return false; return ((*i).second.flags&IS_SIGNED)!=0; } bool isUnsigned(DWORD fieldid) const { TypeInfoMap::const_iterator i= _typeinfo.find(fieldid&0xFFFF); if (i==_typeinfo.end()) return false; return ((*i).second.flags&IS_UNSIGNED)!=0; } bool isByteSized(DWORD fieldid) const { TypeInfoMap::const_iterator i= _typeinfo.find(fieldid&0xFFFF); if (i==_typeinfo.end()) return false; return ((*i).second.flags&IS_BYTESIZED)!=0; } bool isWordSized(DWORD fieldid) const { TypeInfoMap::const_iterator i= _typeinfo.find(fieldid&0xFFFF); if (i==_typeinfo.end()) return false; return ((*i).second.flags&IS_WORDSIZED)!=0; } bool isDwordSized(DWORD fieldid) const { TypeInfoMap::const_iterator i= _typeinfo.find(fieldid&0xFFFF); if (i==_typeinfo.end()) return false; return ((*i).second.flags&IS_DWORDSIZED)!=0; } DWORD TagToFieldid(const std::string& tag) const { TagInfoMap::const_iterator i= _taginfo.find(tag); if (i==_taginfo.end()) return 0; return (*i).second.fieldid; } DwordVector GetNameDefaults() const { DwordVector l; l.push_back(0x3001f); return l; } DwordVector GetNumberDefaults() const { DwordVector l; l.push_back(0x3001f); return l; } private: TypeInfoMap _typeinfo; FieldInfoMap _fieldinfo; TagInfoMap _taginfo; }; extern const FieldInfo gfi; class Field { public: Field() { _fieldid= 0; _dwvalue= 0; } Field& operator=(const Field& f) { _fieldid= f._fieldid; _value= f._value; _dwvalue= f._dwvalue; return *this; } bool SetField(DWORD fieldid, const std::string& value) { return SetField(fieldid, ToWString(value)); } bool SetField(DWORD fieldid, const std::Wstring& value) { _fieldid= fieldid; _value= value; if (gfi.isUnsigned(_fieldid)) _dwvalue= wcstoul(value.c_str(), 0, 0); else if (gfi.isSigned(_fieldid)) _dwvalue= wcstol(value.c_str(), 0, 0); return _fieldid!=0; } bool ParseFromString(const std::string& strfield) { debug("field.parsefromstring(%s)\n", strfield.c_str()); size_t cidx= strfield.find(':'); if (cidx==strfield.npos) return SetField(gfi.TagToFieldid("n"), strfield); else return SetField(gfi.TagToFieldid(strfield.substr(0, cidx)), strfield.substr(cidx+1)); } bool ParseFromByteVector(ByteVector::const_iterator &begin, ByteVector::const_iterator end) { if (end-begin<4) return false; _fieldid= BV_GetDword(begin); _dwvalue= BV_GetDword(begin); if (gfi.isString(_fieldid)) { std::string *pstr= BV_GetString(begin, _dwvalue); _value= ToWString(*pstr); delete pstr; } return true; } bool ParseFromPropval(const CEPROPVAL* pVal) { _fieldid= pVal->propid; if (gfi.isString(_fieldid)) { _value= pVal->val.lpwstr; } else if (gfi.isByteSized(_fieldid)) { _dwvalue= pVal->val.boolVal; } else if (gfi.isWordSized(_fieldid)) { _dwvalue= pVal->val.uiVal; } else if (gfi.isDwordSized(_fieldid)) { _dwvalue= pVal->val.ulVal; } else { debug("unimplemented fieldid: %08lx\n", _fieldid); } return true; } void EncodeAsByteVector(ByteVector& bv) const { BV_AppendDword(bv, _fieldid); if (gfi.isString(_fieldid)) { BV_AppendDword(bv, _value.size()); BV_AppendString(bv, ToString(_value)); } else { BV_AppendDword(bv, _dwvalue); } } bool EncodeAsPropval(ByteVector& propval) const { int ofs= propval.size(); propval.resize(ofs+sizeof(CEPROPVAL)); CEPROPVAL *pVal= (CEPROPVAL*)&propval[ofs]; pVal->propid= _fieldid; if (gfi.isString(_fieldid)) { pVal->val.lpwstr= const_cast(_value.c_str()); } else { pVal->val.ulVal= _dwvalue; } return true; } #if 0 void EncodeAsCeval(CEVALUNION *cv) const { switch(_fieldid&0xffff) { case CEVT_I2: cv->iVal= _dwvalue; break; case CEVT_UI2: cv->uiVal= _dwvalue; break; case CEVT_I4: cv->lVal= _dwvalue; break; case CEVT_UI4: case CEVT_AUTO_I4: cv->ulVal= _dwvalue; break; case CEVT_FILETIME: cv->filetime; break; case CEVT_LPWSTR: cv->lpwstr= _wcsdup(ToWString(_value).c_str()); break; case CEVT_BLOB: case CEVT_AUTO_I8: case CEVT_RECID: case CEVT_STREAM: cv->blob; break; case CEVT_BOOL: cv->boolVal= _dwvalue; break; case CEVT_R8: cv->dblVal; break; } } #endif void dump() const { if (gfi.isString(_fieldid)) { debug("%08lx: '%ls'\n", _fieldid, _value.c_str()); } else if (gfi.isUnsigned(_fieldid)) { debug("%08lx: 0x%08lx (%u)\n", _fieldid, _dwvalue, _dwvalue); } else if (gfi.isSigned(_fieldid)) { debug("%08lx: %s0x%08lx (%d)\n", _fieldid, ((long)_dwvalue<0?"-":""), ((long)_dwvalue<0?-_dwvalue:_dwvalue), _dwvalue); } else { debug("%08lx: ???\n", _fieldid); } } DWORD fieldid() const { return _fieldid; } void SetFieldid(DWORD id) { _fieldid= id; } std::Wstring value() const { return _value; } private: DWORD _fieldid; std::Wstring _value; DWORD _dwvalue; }; typedef std::vector FieldList; class Record { public: Record() { } // parse a string of this format: // name=tag:value,tag:value // where name and value may be quoted bool ParseFromString(const std::string& strrec) { size_t eqidx= strrec.find('='); if (!ParseFieldsFromString(strrec.substr(0,eqidx), gfi.GetNameDefaults())) return false; if (!ParseFieldsFromString(strrec.substr(eqidx+1), gfi.GetNumberDefaults())) return false; return true; } bool CompleteRecord() { typedef std::map IDFieldMap; IDFieldMap fieldsbytype; for (FieldList::const_iterator i= _fields.begin() ; i!= _fields.end() ; i++) fieldsbytype[(*i).fieldid()] = *i; IDFieldMap::iterator notfound=fieldsbytype.end(); if (fieldsbytype.find(0x80001f)!=notfound && fieldsbytype.find(0x82001f)==notfound && fieldsbytype.find(0x84001f)==notfound) { _fields.resize(_fields.size()+1); _fields.back().SetField(0x82001f, fieldsbytype[0x80001f].value()); } else if (fieldsbytype.find(0x80001f)==notfound && (fieldsbytype.find(0x82001f)!=notfound || fieldsbytype.find(0x84001f)!=notfound)) { _fields.resize(_fields.size()+1); std::Wstring displayas; if (fieldsbytype.find(0x84001f)!=notfound) { if (!displayas.empty()) displayas += L", "; displayas += fieldsbytype[0x84001f].value(); } if (fieldsbytype.find(0x82001f)!=notfound) { if (!displayas.empty()) displayas += L", "; displayas += fieldsbytype[0x82001f].value(); } _fields.back().SetField(0x80001f, displayas); } return true; } bool ParseFieldsFromString(const std::string& strfields, const DwordVector& defaults) { DwordVector::const_iterator dfl= defaults.begin(); StringList strs; if (!SplitString(strfields, strs, true, ",")) return false; for (StringList::const_iterator i= strs.begin() ; i!=strs.end() ; i++) { _fields.resize(_fields.size()+1); if (!_fields.back().ParseFromString(*i)) { if ((*i).find(':')==(*i).npos) { if (dfl==defaults.end()) return false; if (!_fields.back().SetField(*dfl, *i)) return false; dfl++; } } } return true; } bool ParseFromByteVector(const ByteVector& brec) { ByteVector::const_iterator pos= brec.begin(); while (pos!=brec.end()) { _fields.resize(_fields.size()+1); if (!_fields.back().ParseFromByteVector(pos, brec.end())) return false; } return true; } bool ParseFromPropval(const CEPROPVAL* pPropval, int count) { for (int i=0 ; i