Fairport
v1.0.38
|
00001 00002 00003 00004 00005 00006 #ifndef FAIRPORT_LTP_NAMEID_H 00007 #define FAIRPORT_LTP_NAMEID_H 00008 00009 #include <string> 00010 #include <algorithm> 00011 00012 #include "fairport/util/primitives.h" 00013 00014 #include "fairport/ndb/database_iface.h" 00015 00016 #include "fairport/ltp/propbag.h" 00017 00018 namespace fairport 00019 { 00020 00023 00030 class named_prop 00031 { 00032 public: 00036 named_prop(const guid& g, long id) 00037 : m_guid(g), m_is_string(false), m_id(id) { } 00041 named_prop(const guid& g, const std::wstring& name) 00042 : m_guid(g), m_is_string(true), m_id(0), m_name(name) { } 00043 00046 const guid& get_guid() const { return m_guid; } 00049 bool is_string() const { return m_is_string; } 00053 long get_id() const { return m_id; } 00057 const std::wstring& get_name() const { return m_name; } 00058 00059 private: 00060 guid m_guid; 00061 bool m_is_string; 00062 long m_id; 00063 std::wstring m_name; 00064 }; 00065 00075 class name_id_map : private boost::noncopyable 00076 { 00077 public: 00082 name_id_map(const shared_db_ptr& db) 00083 : m_bag(db->lookup_node(nid_name_id_map)), m_buckets(m_bag.read_prop<slong>(0x1)), m_entry_stream(m_bag.open_prop_stream(0x3)), m_guid_stream(m_bag.open_prop_stream(0x2)), m_string_stream(m_bag.open_prop_stream(0x4)) { } 00084 00089 bool name_exists(const guid& g, const std::wstring& name) const 00090 { return named_prop_exists(named_prop(g, name)); } 00095 bool id_exists(const guid& g, long id) const 00096 { return named_prop_exists(named_prop(g, id)); } 00100 bool named_prop_exists(const named_prop& p) const; 00104 bool prop_id_exists(prop_id id) const; 00107 size_t get_prop_count() const; 00108 00111 std::vector<prop_id> get_prop_list() const; 00112 00118 prop_id lookup(const guid& g, const std::wstring& name) const 00119 { return lookup(named_prop(g, name)); } 00125 prop_id lookup(const guid& g, long id) const 00126 { return lookup(named_prop(g, id)); } 00131 prop_id lookup(const named_prop& p) const; 00132 00137 named_prop lookup(prop_id id) const; 00138 00139 private: 00140 // helper functions 00141 named_prop construct(const disk::nameid& entry) const; 00142 named_prop construct(ulong index) const; 00147 guid read_guid(ushort guid_index) const; 00148 ushort get_guid_index(const guid& g) const; 00149 std::wstring read_wstring(ulong string_offset) const; 00150 ulong compute_hash_base(const named_prop& n) const; 00151 ulong compute_hash_value(ushort guid_index, const named_prop& n) const 00152 { return (n.is_string() ? ((guid_index << 1) | 1) : (guid_index << 1)) ^ compute_hash_base(n); } 00153 prop_id get_bucket_prop(ulong hash_value) const 00154 { return static_cast<prop_id>((hash_value % m_buckets) + 0x1000); } 00155 00156 property_bag m_bag; 00157 ulong m_buckets; 00158 mutable prop_stream m_entry_stream; 00159 mutable prop_stream m_guid_stream; 00160 mutable prop_stream m_string_stream; 00161 }; 00162 00163 inline fairport::named_prop fairport::name_id_map::construct(const disk::nameid& entry) const 00164 { 00165 if(nameid_is_string(entry)) 00166 return named_prop(read_guid(disk::nameid_get_guid_index(entry)), read_wstring(entry.string_offset)); 00167 else 00168 return named_prop(read_guid(disk::nameid_get_guid_index(entry)), entry.id); 00169 } 00170 00171 inline fairport::named_prop fairport::name_id_map::construct(ulong index) const 00172 { 00173 disk::nameid entry; 00174 m_entry_stream.seekg(index * sizeof(disk::nameid), std::ios_base::beg); 00175 m_entry_stream.read((char*)&entry, sizeof(entry)); 00176 return construct(entry); 00177 } 00178 00179 inline fairport::guid fairport::name_id_map::read_guid(ushort guid_index) const 00180 { 00181 if(guid_index == 0) 00182 return ps_none; 00183 if(guid_index == 1) 00184 return ps_mapi; 00185 if(guid_index == 2) 00186 return ps_public_strings; 00187 00188 guid g; 00189 m_guid_stream.seekg((guid_index-3) * sizeof(guid), std::ios_base::beg); 00190 m_guid_stream.read((char*)&g, sizeof(g)); 00191 return g; 00192 } 00193 00194 inline fairport::ushort fairport::name_id_map::get_guid_index(const guid& g) const 00195 { 00196 if(memcmp(&g, &ps_none, sizeof(g)) == 0) 00197 return 0; 00198 if(memcmp(&g, &ps_mapi, sizeof(g)) == 0) 00199 return 1; 00200 if(memcmp(&g, &ps_public_strings, sizeof(g)) == 0) 00201 return 2; 00202 00203 guid g_disk; 00204 ushort num = 0; 00205 m_guid_stream.seekg(0, std::ios_base::beg); 00206 while(m_guid_stream.read((char*)&g_disk, sizeof(g_disk))) 00207 { 00208 if(memcmp(&g, &g_disk, sizeof(g)) == 0) 00209 return num + 3; 00210 ++num; 00211 } 00212 00213 // didn't find it 00214 m_guid_stream.clear(); 00215 throw key_not_found<guid>(g); 00216 } 00217 00218 inline std::wstring fairport::name_id_map::read_wstring(ulong string_offset) const 00219 { 00220 m_string_stream.seekg(string_offset, std::ios_base::beg); 00221 00222 ulong size; 00223 m_string_stream.read((char*)&size, sizeof(size)); 00224 00225 std::vector<byte> buffer(size); 00226 m_string_stream.read(reinterpret_cast<char *>(&buffer[0]), size); 00227 00228 return bytes_to_wstring(buffer); 00229 } 00230 00231 inline fairport::ulong fairport::name_id_map::compute_hash_base(const named_prop& n) const { 00232 if(n.is_string()) 00233 { 00234 std::vector<byte> bytes(wstring_to_bytes(n.get_name())); 00235 return disk::compute_crc(&bytes[0], bytes.size()); 00236 } 00237 else 00238 { 00239 return n.get_id(); 00240 } 00241 } 00242 00243 inline bool fairport::name_id_map::named_prop_exists(const named_prop& p) const 00244 { 00245 try 00246 { 00247 lookup(p); 00248 return true; 00249 } 00250 catch(std::exception&) 00251 { 00252 return false; 00253 } 00254 } 00255 00256 inline bool fairport::name_id_map::prop_id_exists(prop_id id) const 00257 { 00258 if(id >= 0x8000) 00259 return static_cast<size_t>((id - 0x8000)) < get_prop_count(); 00260 00261 // id < 0x8000 is a ps_mapi prop 00262 return true; 00263 } 00264 00265 inline std::vector<prop_id> fairport::name_id_map::get_prop_list() const 00266 { 00267 disk::nameid entry; 00268 std::vector<prop_id> props; 00269 00270 m_entry_stream.seekg(0, std::ios_base::beg); 00271 while(m_entry_stream.read((char*)&entry, sizeof(entry)) != 0) 00272 props.push_back(nameid_get_prop_index(entry) + 0x8000); 00273 00274 m_entry_stream.clear(); 00275 00276 return props; 00277 } 00278 00279 inline size_t fairport::name_id_map::get_prop_count() const 00280 { 00281 m_entry_stream.seekg(0, std::ios_base::end); 00282 00283 return static_cast<size_t>(m_entry_stream.tellg()) / sizeof(disk::nameid); 00284 } 00285 00286 inline fairport::prop_id fairport::name_id_map::lookup(const named_prop& p) const 00287 { 00288 ushort guid_index; 00289 00290 try 00291 { 00292 guid_index = get_guid_index(p.get_guid()); 00293 } 00294 catch(key_not_found<guid>&) 00295 { 00296 throw key_not_found<named_prop>(p); 00297 } 00298 00299 // special handling of ps_mapi 00300 if(guid_index == 1) 00301 { 00302 if(p.is_string()) throw key_not_found<named_prop>(p); 00303 if(p.get_id() >= 0x8000) throw key_not_found<named_prop>(p); 00304 return static_cast<prop_id>(p.get_id()); 00305 } 00306 00307 ulong hash_value = compute_hash_value(guid_index, p); 00308 ulong hash_base = compute_hash_base(p); 00309 00310 if(!m_bag.prop_exists(get_bucket_prop(hash_value))) 00311 throw key_not_found<named_prop>(p); 00312 00313 prop_stream bucket(const_cast<name_id_map*>(this)->m_bag.open_prop_stream(get_bucket_prop(hash_value))); 00314 disk::nameid_hash_entry entry; 00315 while(bucket.read((char*)&entry, sizeof(entry)) != 0) 00316 { 00317 if( (entry.hash_base == hash_base) && 00318 (disk::nameid_is_string(entry) == p.is_string()) && 00319 (disk::nameid_get_guid_index(entry) == guid_index) 00320 ) 00321 { 00322 // just double check the string.. 00323 if(p.is_string()) 00324 { 00325 if(construct(disk::nameid_get_prop_index(entry)).get_name() != p.get_name()) 00326 continue; 00327 } 00328 00329 // found it! 00330 return disk::nameid_get_prop_index(entry) + 0x8000; 00331 } 00332 } 00333 00334 throw key_not_found<named_prop>(p); 00335 } 00336 00337 inline fairport::named_prop fairport::name_id_map::lookup(prop_id id) const 00338 { 00339 if(id < 0x8000) 00340 return named_prop(ps_mapi, id); 00341 00342 ulong index = id - 0x8000; 00343 00344 if(index > get_prop_count()) 00345 throw key_not_found<prop_id>(id); 00346 00347 return construct(index); 00348 } 00349 00350 } // end namespace fairport 00351 00352 #endif