Fairport  v1.0.38
fairport/ltp/object.h
Go to the documentation of this file.
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