QxOrm
1.5.0
C++ Object Relational Mapping library
|
00001 /*****************************************************************************/ 00083 /*****************************************************************************/ 00084 00085 #ifdef _QX_ENABLE_BOOST_SERIALIZATION 00086 #if _QX_SERIALIZE_PORTABLE_BINARY 00087 #ifndef _QX_PORTABLE_BINARY_IARCHIVE_H_ 00088 #define _QX_PORTABLE_BINARY_IARCHIVE_H_ 00089 00090 #ifdef _MSC_VER 00091 #pragma once 00092 #endif // _MSC_VER 00093 00094 #ifdef _MSC_VER 00095 #pragma warning(push) 00096 #pragma warning(disable:4996) 00097 #pragma warning(disable:4661) 00098 #endif // _MSC_VER 00099 00100 #include <istream> 00101 00102 // basic headers 00103 #include <boost/version.hpp> 00104 #include <boost/utility/enable_if.hpp> 00105 #include <boost/archive/basic_binary_iprimitive.hpp> 00106 #include <boost/archive/basic_binary_iarchive.hpp> 00107 00108 #if BOOST_VERSION >= 103500 && BOOST_VERSION < 105600 00109 #include <boost/archive/shared_ptr_helper.hpp> 00110 #endif 00111 00112 // endian and fpclassify 00113 #if BOOST_VERSION < 103600 00114 #include <boost/integer/endian.hpp> 00115 #include <boost/math/fpclassify.hpp> 00116 #elif BOOST_VERSION < 104800 00117 #include <boost/spirit/home/support/detail/integer/endian.hpp> 00118 #include <boost/spirit/home/support/detail/math/fpclassify.hpp> 00119 #else 00120 #include <boost/spirit/home/support/detail/endian/endian.hpp> 00121 #include <boost/spirit/home/support/detail/math/fpclassify.hpp> 00122 #endif 00123 00124 // namespace alias 00125 #if BOOST_VERSION < 103800 00126 namespace fp = boost::math; 00127 #else 00128 namespace fp = boost::spirit::math; 00129 #endif 00130 00131 // namespace alias endian 00132 #if BOOST_VERSION < 104800 00133 namespace endian = boost::detail; 00134 #else 00135 namespace endian = boost::spirit::detail; 00136 #endif 00137 00138 #if BOOST_VERSION >= 104500 && !defined BOOST_NO_STD_WSTRING 00139 // used for wstring to utf8 conversion 00140 #include <boost/program_options/config.hpp> 00141 #include <boost/program_options/detail/convert.hpp> 00142 #endif 00143 00144 // generic type traits for numeric types 00145 #include <boost/type_traits/is_integral.hpp> 00146 #include <boost/type_traits/is_unsigned.hpp> 00147 #include <boost/type_traits/is_arithmetic.hpp> 00148 #include <boost/type_traits/is_floating_point.hpp> 00149 00150 #include "portable_archive_exception.hpp" 00151 00152 // hint from Johan Rade: on VMS there is still support for 00153 // the VAX floating point format and this macro detects it 00154 #if defined(__vms) && defined(__DECCXX) && !__IEEE_FLOAT 00155 #error "VAX floating point format is not supported!" 00156 #endif 00157 00158 namespace eos { 00159 00160 // forward declaration 00161 class portable_iarchive; 00162 00163 typedef boost::archive::basic_binary_iprimitive< 00164 portable_iarchive 00165 #if BOOST_VERSION < 103400 00166 , std::istream 00167 #else 00168 , std::istream::char_type 00169 , std::istream::traits_type 00170 #endif 00171 > portable_iprimitive; 00172 00187 class portable_iarchive : public portable_iprimitive 00188 00189 // the example derives from common_oarchive but that lacks the 00190 // load_override functions so we chose to stay one level higher 00191 , public boost::archive::basic_binary_iarchive<portable_iarchive> 00192 00193 #if BOOST_VERSION >= 103500 && BOOST_VERSION < 105600 00194 // mix-in helper class for serializing shared_ptr 00195 , public boost::archive::detail::shared_ptr_helper 00196 #endif 00197 { 00198 // only needed for Robert's hack in basic_binary_iarchive::init 00199 friend class boost::archive::basic_binary_iarchive<portable_iarchive>; 00200 00201 // workaround for gcc: use a dummy struct 00202 // as additional argument type for overloading 00203 template <int> struct dummy { dummy(int) {}}; 00204 00205 // loads directly from stream 00206 inline signed char load_signed_char() 00207 { 00208 signed char c; 00209 portable_iprimitive::load(c); 00210 return c; 00211 } 00212 00213 // archive initialization 00214 void init(unsigned flags) 00215 { 00216 using namespace boost::archive; 00217 archive_version_type input_library_version(3); 00218 00219 // it is vital to have version information! 00220 // if we don't have any we assume boost 1.33 00221 if (flags & no_header) 00222 set_library_version(input_library_version); 00223 00224 // extract and check the magic eos byte 00225 else if (load_signed_char() != magic_byte) 00226 throw archive_exception(archive_exception::invalid_signature); 00227 00228 else 00229 { 00230 // extract version information 00231 operator>>(input_library_version); 00232 00233 // throw if file version is newer than we are 00234 if (input_library_version > archive_version) 00235 throw archive_exception(archive_exception::unsupported_version); 00236 00237 // else set the library version accordingly 00238 else set_library_version(input_library_version); 00239 } 00240 } 00241 00242 public: 00254 portable_iarchive(std::istream& is, unsigned flags = 0) 00255 #if BOOST_VERSION < 103400 00256 : portable_iprimitive(is, flags & boost::archive::no_codecvt) 00257 #else 00258 : portable_iprimitive(*is.rdbuf(), flags & boost::archive::no_codecvt) 00259 #endif 00260 , boost::archive::basic_binary_iarchive<portable_iarchive>(flags) 00261 { 00262 init(flags); 00263 } 00264 00265 #if BOOST_VERSION >= 103400 00266 portable_iarchive(std::streambuf& sb, unsigned flags = 0) 00267 : portable_iprimitive(sb, flags & boost::archive::no_codecvt) 00268 , boost::archive::basic_binary_iarchive<portable_iarchive>(flags) 00269 { 00270 init(flags); 00271 } 00272 #endif 00273 00275 void load(std::string& s) 00276 { 00277 portable_iprimitive::load(s); 00278 } 00279 00280 #ifndef BOOST_NO_STD_WSTRING 00281 00293 void load(std::wstring& s) 00294 { 00295 std::string utf8; 00296 load(utf8); 00297 s = boost::from_utf8(utf8); 00298 } 00299 #endif 00300 00314 void load(bool& b) 00315 { 00316 switch (signed char c = load_signed_char()) 00317 { 00318 case 0: b = false; break; 00319 case 1: b = load_signed_char(); break; 00320 default: throw portable_archive_exception(c); 00321 } 00322 } 00323 00331 template <typename T> 00332 typename boost::enable_if<boost::is_integral<T> >::type 00333 load(T & t, dummy<2> = 0) 00334 { 00335 // get the number of bytes in the stream 00336 if (signed char size = load_signed_char()) 00337 { 00338 // check for negative value in unsigned type 00339 if (size < 0 && boost::is_unsigned<T>::value) 00340 throw portable_archive_exception(); 00341 00342 // check that our type T is large enough 00343 else if ((unsigned) abs(size) > sizeof(T)) 00344 throw portable_archive_exception(size); 00345 00346 // reconstruct the value 00347 T temp = size < 0 ? -1 : 0; 00348 load_binary(&temp, abs(size)); 00349 00350 // load the value from little endian - it is then converted 00351 // to the target type T and fits it because size <= sizeof(T) 00352 t = endian::load_little_endian<T, sizeof(T)>(&temp); 00353 } 00354 00355 else t = 0; // zero optimization 00356 } 00357 00385 template <typename T> 00386 typename boost::enable_if<boost::is_floating_point<T> >::type 00387 load(T & t, dummy<3> = 0) 00388 { 00389 typedef typename fp::detail::fp_traits<T>::type traits; 00390 00391 // if you end here there are three possibilities: 00392 // 1. you're serializing a long double which is not portable 00393 // 2. you're serializing a double but have no 64 bit integer 00394 // 3. your machine is using an unknown floating point format 00395 // after reading the note above you still might decide to 00396 // deactivate this static assert and try if it works out. 00397 typename traits::bits bits; 00398 BOOST_STATIC_ASSERT(sizeof(bits) == sizeof(T)); 00399 BOOST_STATIC_ASSERT(std::numeric_limits<T>::is_iec559); 00400 00401 load(bits); 00402 traits::set_bits(t, bits); 00403 00404 // if the no_infnan flag is set we must throw here 00405 if (get_flags() & no_infnan && !fp::isfinite(t)) 00406 throw portable_archive_exception(t); 00407 00408 // if you end here your floating point type does not support 00409 // denormalized numbers. this might be the case even though 00410 // your type conforms to IEC 559 (and thus to IEEE 754) 00411 if (std::numeric_limits<T>::has_denorm == std::denorm_absent 00412 && fp::fpclassify(t) == (int) FP_SUBNORMAL) // GCC4 00413 throw portable_archive_exception(t); 00414 } 00415 00416 // in boost 1.44 version_type was splitted into library_version_type and 00417 // item_version_type, plus a whole bunch of additional strong typedefs. 00418 template <typename T> 00419 typename boost::disable_if<boost::is_arithmetic<T> >::type 00420 load(T& t, dummy<4> = 0) 00421 { 00422 // we provide a generic load routine for all types that feature 00423 // conversion operators into an unsigned integer value like those 00424 // created through BOOST_STRONG_TYPEDEF(X, some unsigned int) like 00425 // library_version_type, collection_size_type, item_version_type, 00426 // class_id_type, object_id_type, version_type and tracking_type 00427 load((typename boost::uint_t<sizeof(T)*CHAR_BIT>::least&)(t)); 00428 } 00429 }; 00430 00431 } // namespace eos 00432 00433 // this is required by export which registers all of your 00434 // classes with all the inbuilt archives plus our archive. 00435 #if BOOST_VERSION < 103500 00436 #define BOOST_ARCHIVE_CUSTOM_IARCHIVE_TYPES eos::portable_iarchive 00437 #else 00438 BOOST_SERIALIZATION_REGISTER_ARCHIVE(eos::portable_iarchive) 00439 #endif 00440 00441 // if you include this header multiple times and your compiler is picky 00442 // about multiple template instantiations (eg. gcc is) then you need to 00443 // define NO_EXPLICIT_TEMPLATE_INSTANTIATION before every include but one 00444 // or you move the instantiation section into an implementation file 00445 #ifndef NO_EXPLICIT_TEMPLATE_INSTANTIATION 00446 00447 #ifndef _QX_BOOST_ARCHIVE_SERIALIZER_IMPL_DEFINED_ 00448 #define _QX_BOOST_ARCHIVE_SERIALIZER_IMPL_DEFINED_ 00449 00450 #include <boost/archive/impl/basic_binary_iarchive.ipp> 00451 #include <boost/archive/impl/basic_binary_oarchive.ipp> 00452 #include <boost/archive/impl/basic_binary_iprimitive.ipp> 00453 #include <boost/archive/impl/basic_binary_oprimitive.ipp> 00454 00455 #if _QX_SERIALIZE_TEXT 00456 #include <boost/archive/impl/basic_text_oprimitive.ipp> 00457 #include <boost/archive/impl/basic_text_iprimitive.ipp> 00458 #include <boost/archive/impl/basic_text_oarchive.ipp> 00459 #include <boost/archive/impl/basic_text_iarchive.ipp> 00460 #endif // _QX_SERIALIZE_TEXT 00461 00462 #if (BOOST_VERSION < 104000) 00463 #include <boost/archive/impl/archive_pointer_iserializer.ipp> 00464 #include <boost/archive/impl/archive_pointer_oserializer.ipp> 00465 #elif !defined BOOST_ARCHIVE_SERIALIZER_INCLUDED 00466 #include <boost/archive/impl/archive_serializer_map.ipp> 00467 #define BOOST_ARCHIVE_SERIALIZER_INCLUDED 00468 #endif // (BOOST_VERSION < 104000) 00469 00470 #endif // _QX_BOOST_ARCHIVE_SERIALIZER_IMPL_DEFINED_ 00471 00472 namespace boost { namespace archive { 00473 00474 // explicitly instantiate for this type of binary stream 00475 template class basic_binary_iarchive<eos::portable_iarchive>; 00476 00477 template class basic_binary_iprimitive< 00478 eos::portable_iarchive 00479 #if BOOST_VERSION < 103400 00480 , std::istream 00481 #else 00482 , std::istream::char_type 00483 , std::istream::traits_type 00484 #endif 00485 >; 00486 00487 #if (! _QX_USE_EXPORT_DLL_BOOST_SERIALIZATION_SINGLETON) 00488 #if (BOOST_VERSION < 104000) 00489 template class detail::archive_pointer_iserializer<eos::portable_iarchive>; 00490 #else // (BOOST_VERSION < 104000) 00491 template class detail::archive_serializer_map<eos::portable_iarchive>; 00492 #endif // (BOOST_VERSION < 104000) 00493 #endif // (! _QX_USE_EXPORT_DLL_BOOST_SERIALIZATION_SINGLETON) 00494 00495 } } // namespace boost::archive 00496 00497 #endif // NO_EXPLICIT_TEMPLATE_INSTANTIATION 00498 00499 #ifdef _MSC_VER 00500 #pragma warning(pop) 00501 #endif // _MSC_VER 00502 00503 #endif // _QX_PORTABLE_BINARY_IARCHIVE_H_ 00504 #endif // _QX_SERIALIZE_PORTABLE_BINARY 00505 #endif // _QX_ENABLE_BOOST_SERIALIZATION