Fairport
v1.0.38
|
00001 00002 00003 00004 00005 00006 00007 00008 00009 00010 00011 00012 00013 #ifndef FAIRPORT_LTP_OBJECT_H 00014 #define FAIRPORT_LTP_OBJECT_H 00015 00016 #include <functional> 00017 #ifdef __GNUC__ 00018 #include <tr1/type_traits> 00019 #include <tr1/functional> 00020 #else 00021 #include <type_traits> 00022 #endif 00023 #include <algorithm> 00024 #define BOOST_ALL_NO_LIB 1 00025 #ifdef _MSC_VER 00026 #pragma warning(push) 00027 #pragma warning(disable:4244 6328) 00028 #endif 00029 #include <boost/iostreams/concepts.hpp> 00030 #include <boost/date_time/gregorian/gregorian.hpp> 00031 #include <boost/date_time/posix_time/posix_time.hpp> 00032 #include <boost/iostreams/stream.hpp> 00033 #ifdef _MSC_VER 00034 #pragma warning(pop) 00035 #endif 00036 00037 #include "fairport/util/primitives.h" 00038 #include "fairport/util/errors.h" 00039 00040 #include "fairport/ltp/heap.h" 00041 00042 #include "fairport/ndb/node.h" 00043 00044 namespace fairport 00045 { 00046 00049 00061 class hnid_stream_device : public boost::iostreams::device<boost::iostreams::input_seekable> 00062 { 00063 public: 00065 std::streamsize read(char* pbuffer, std::streamsize n) 00066 { if(m_is_hid) return m_hid_device.read(pbuffer, n); else return m_node_device.read(pbuffer, n); } 00068 std::streampos seek(boost::iostreams::stream_offset off, std::ios_base::seekdir way) 00069 { if(m_is_hid) return m_hid_device.seek(off, way); else return m_node_device.seek(off, way); } 00070 00072 hnid_stream_device(const hid_stream_device& hid_device) : m_hid_device(hid_device), m_is_hid(true) { } 00074 hnid_stream_device(const node_stream_device& node_device) : m_node_device(node_device), m_is_hid(false) { } 00075 00076 private: 00077 hid_stream_device m_hid_device; 00078 node_stream_device m_node_device; 00079 bool m_is_hid; 00080 00081 std::streamsize m_pos; 00082 }; 00083 00087 typedef boost::iostreams::stream<hnid_stream_device> prop_stream; 00088 00099 class const_property_object 00100 { 00101 public: 00102 virtual ~const_property_object() { } 00105 virtual std::vector<prop_id> get_prop_list() const = 0; 00110 virtual prop_type get_prop_type(prop_id id) const = 0; 00114 virtual bool prop_exists(prop_id id) const = 0; 00119 virtual size_t size(prop_id id) const = 0; 00120 00129 template<typename T> 00130 T read_prop(prop_id id) const; 00131 00141 template<typename T> 00142 std::vector<T> read_prop_array(prop_id id) const; 00143 00156 virtual hnid_stream_device open_prop_stream(prop_id id) = 0; 00157 00158 protected: 00160 virtual byte get_value_1(prop_id id) const = 0; 00162 virtual ushort get_value_2(prop_id id) const = 0; 00164 virtual ulong get_value_4(prop_id id) const = 0; 00166 virtual ulonglong get_value_8(prop_id id) const = 0; 00168 virtual std::vector<byte> get_value_variable(prop_id id) const = 0; 00169 }; 00170 00171 } // end fairport namespace 00172 00173 template<typename T> 00174 inline T fairport::const_property_object::read_prop(prop_id id) const 00175 { 00176 #ifdef _MSC_VER 00177 #pragma warning(suppress:4127) 00178 #endif 00179 if(!std::tr1::is_pod<T>::value) 00180 throw std::invalid_argument("T must be a POD or one of the specialized classes"); 00181 00182 if(sizeof(T) == sizeof(ulonglong)) 00183 { 00184 ulonglong t = get_value_8(id); 00185 return *(reinterpret_cast<T*>(&t)); 00186 } 00187 else if(sizeof(T) == sizeof(ulong)) 00188 { 00189 ulong t = get_value_4(id); 00190 return *(reinterpret_cast<T*>(&t)); 00191 } 00192 else if(sizeof(T) == sizeof(ushort)) 00193 { 00194 ushort t = get_value_2(id); 00195 return *(reinterpret_cast<T*>(&t)); 00196 } 00197 else if(sizeof(T) == sizeof(byte)) 00198 { 00199 byte t = get_value_1(id); 00200 return *(reinterpret_cast<T*>(&t)); 00201 } 00202 else 00203 { 00204 std::vector<byte> buffer = get_value_variable(id); 00205 return *(reinterpret_cast<T*>(&buffer[0])); 00206 } 00207 } 00208 00209 template<typename T> 00210 inline std::vector<T> fairport::const_property_object::read_prop_array(prop_id id) const 00211 { 00212 #ifdef _MSC_VER 00213 #pragma warning(suppress:4127) 00214 #endif 00215 if(!std::tr1::is_pod<T>::value) 00216 throw std::invalid_argument("T must be a POD or one of the specialized classes"); 00217 00218 std::vector<byte> buffer = get_value_variable(id); 00219 return std::vector<T>(reinterpret_cast<T*>(&buffer[0]), reinterpret_cast<T*>(&buffer[0] + buffer.size())); 00220 } 00221 00222 namespace fairport 00223 { 00224 00225 template<> 00226 inline bool const_property_object::read_prop<bool>(prop_id id) const 00227 { 00228 return get_value_4(id) != 0; 00229 } 00230 00231 template<> 00232 inline std::vector<bool> fairport::const_property_object::read_prop_array<bool>(prop_id id) const 00233 { 00234 std::vector<ulong> values = read_prop_array<ulong>(id); 00235 std::vector<bool> results(values.size()); 00236 std::transform(values.begin(), values.end(), results.begin(), std::tr1::bind(std::not_equal_to<ulong>(), 0, std::tr1::placeholders::_1)); 00237 return results; 00238 } 00239 00240 template<> 00241 inline boost::posix_time::ptime const_property_object::read_prop<boost::posix_time::ptime>(prop_id id) const 00242 { 00243 if(get_prop_type(id) == prop_type_apptime) 00244 { 00245 double time_value = read_prop<double>(id); 00246 return boost::posix_time::from_time_t(vt_date_to_time_t(time_value)); 00247 } 00248 else 00249 { 00250 ulonglong time_value = read_prop<ulonglong>(id); 00251 return boost::posix_time::from_time_t(filetime_to_time_t(time_value)); 00252 } 00253 } 00254 00255 template<> 00256 inline std::vector<boost::posix_time::ptime> const_property_object::read_prop_array<boost::posix_time::ptime>(prop_id id) const 00257 { 00258 if(get_prop_type(id) == prop_type_mv_apptime) 00259 { 00260 std::vector<double> time_values = read_prop_array<double>(id); 00261 std::vector<time_t> result(time_values.size()); 00262 std::vector<boost::posix_time::ptime> ptime_result(time_values.size()); 00263 std::transform(time_values.begin(), time_values.end(), result.begin(), vt_date_to_time_t); 00264 std::transform(result.begin(), result.end(), ptime_result.begin(), boost::posix_time::from_time_t); 00265 return ptime_result; 00266 } 00267 else 00268 { 00269 std::vector<ulonglong> time_values = read_prop_array<ulonglong>(id); 00270 std::vector<time_t> result(time_values.size()); 00271 std::vector<boost::posix_time::ptime> ptime_result(time_values.size()); 00272 std::transform(time_values.begin(), time_values.end(), result.begin(), filetime_to_time_t); 00273 std::transform(result.begin(), result.end(), ptime_result.begin(), boost::posix_time::from_time_t); 00274 return ptime_result; 00275 } 00276 00277 } 00278 00279 template<> 00280 inline std::vector<byte> const_property_object::read_prop<std::vector<byte> >(prop_id id) const 00281 { 00282 return get_value_variable(id); 00283 } 00284 00285 template<> 00286 inline std::vector<std::vector<byte> > const_property_object::read_prop_array<std::vector<byte> >(prop_id id) const 00287 { 00288 std::vector<byte> buffer = get_value_variable(id); 00289 #ifdef FAIRPORT_VALIDATION_LEVEL_WEAK 00290 if(buffer.size() < sizeof(ulong)) 00291 throw std::length_error("mv prop too short"); 00292 #endif 00293 disk::mv_toc* ptoc = reinterpret_cast<disk::mv_toc*>(&buffer[0]); 00294 std::vector<std::vector<byte> > results; 00295 00296 #ifdef FAIRPORT_VALIDATION_LEVEL_WEAK 00297 if(buffer.size() < (sizeof(ulong) + ptoc->count * sizeof(ulong))) 00298 throw std::length_error("mv prop too short"); 00299 #endif 00300 00301 for(ulong i = 0; i < ptoc->count; ++i) 00302 { 00303 ulong start = ptoc->offsets[i]; 00304 ulong end = (i == (ptoc->count - 1)) ? buffer.size() : ptoc->offsets[i+1]; 00305 #ifdef FAIRPORT_VALIDATION_LEVEL_WEAK 00306 if(end < start) 00307 throw std::length_error("inconsistent mv prop toc"); 00308 #endif 00309 results.push_back(std::vector<byte>(&buffer[start], &buffer[start] + (end-start))); 00310 } 00311 00312 return results; 00313 } 00314 00315 template<> 00316 inline std::wstring const_property_object::read_prop<std::wstring>(prop_id id) const 00317 { 00318 std::vector<byte> buffer = get_value_variable(id); 00319 00320 if(get_prop_type(id) == prop_type_string) 00321 { 00322 std::string s(buffer.begin(), buffer.end()); 00323 return codepage_1252_to_wstring(s); 00324 } 00325 else 00326 { 00327 return bytes_to_wstring(buffer); 00328 } 00329 } 00330 00331 template<> 00332 inline std::vector<std::wstring> const_property_object::read_prop_array<std::wstring>(prop_id id) const 00333 { 00334 std::vector<std::vector<byte> > buffer = read_prop_array<std::vector<byte> >(id); 00335 std::vector<std::wstring> results; 00336 00337 for(size_t i = 0; i < buffer.size(); ++i) 00338 { 00339 if(get_prop_type(id) == prop_type_mv_string) 00340 { 00341 std::string s(buffer[i].begin(), buffer[i].end()); 00342 results.push_back(codepage_1252_to_wstring(s)); 00343 } 00344 else 00345 { 00346 results.push_back(bytes_to_wstring(buffer[i])); 00347 } 00348 } 00349 00350 return results; 00351 } 00352 00353 template<> 00354 inline std::string const_property_object::read_prop<std::string>(prop_id id) const 00355 { 00356 std::vector<byte> buffer = get_value_variable(id); 00357 00358 if(get_prop_type(id) == prop_type_string) 00359 { 00360 return std::string(buffer.begin(), buffer.end()); 00361 } 00362 else 00363 { 00364 if(buffer.size()) 00365 { 00366 // Note that this code does the wrong thing for non-Latin-1 00367 // characters. Use with caution. 00368 std::wstring s(bytes_to_wstring(buffer)); 00369 return std::string(s.begin(), s.end()); 00370 } 00371 return std::string(); 00372 } 00373 } 00374 00375 template<> 00376 inline std::vector<std::string> const_property_object::read_prop_array<std::string>(prop_id id) const 00377 { 00378 std::vector<std::vector<byte> > buffer = read_prop_array<std::vector<byte> >(id); 00379 std::vector<std::string> results; 00380 00381 for(size_t i = 0; i < buffer.size(); ++i) 00382 { 00383 if(get_prop_type(id) == prop_type_mv_string) 00384 { 00385 results.push_back(std::string(buffer[i].begin(), buffer[i].end())); 00386 } 00387 else 00388 { 00389 if(buffer[i].size()) 00390 { 00391 std::wstring s(bytes_to_wstring(buffer[i])); 00392 results.push_back(std::string(s.begin(), s.end())); 00393 } 00394 results.push_back(std::string()); 00395 } 00396 } 00397 00398 return results; 00399 } 00400 00401 } // end fairport namespace 00402 00403 #endif