1 #ifndef BOOST_ARCHIVE_DETAIL_ISERIALIZER_HPP
2 #define BOOST_ARCHIVE_DETAIL_ISERIALIZER_HPP
3 
4 // MS compatible compilers support #pragma once
5 #if defined(BOOST_MSVC)
6 # pragma once
7 #if !defined(__clang__)
8 #pragma inline_depth(255)
9 #pragma inline_recursion(on)
10 #endif
11 #endif
12 
13 #if defined(__MWERKS__)
14 #pragma inline_depth(255)
15 #endif
16 
17 /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
18 // iserializer.hpp: interface for serialization system.
19 
20 // (C) Copyright 2002 Robert Ramey - http://www.rrsd.com .
21 // Use, modification and distribution is subject to the Boost Software
22 // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
23 // http://www.boost.org/LICENSE_1_0.txt)
24 
25 //  See http://www.boost.org for updates, documentation, and revision history.
26 
27 #include <new>     // for placement new
28 #include <cstddef> // size_t, NULL
29 
30 #include <boost/config.hpp>
31 #include <boost/detail/workaround.hpp>
32 #if defined(BOOST_NO_STDC_NAMESPACE)
33 namespace std{
34     using ::size_t;
35 } // namespace std
36 #endif
37 
38 #include <boost/static_assert.hpp>
39 
40 #include <boost/mpl/eval_if.hpp>
41 #include <boost/mpl/identity.hpp>
42 #include <boost/mpl/greater_equal.hpp>
43 #include <boost/mpl/equal_to.hpp>
44 #include <boost/core/no_exceptions_support.hpp>
45 
46 #ifndef BOOST_SERIALIZATION_DEFAULT_TYPE_INFO
47     #include <boost/serialization/extended_type_info_typeid.hpp>
48 #endif
49 #include <boost/serialization/throw_exception.hpp>
50 #include <boost/serialization/smart_cast.hpp>
51 #include <boost/serialization/static_warning.hpp>
52 
53 #include <boost/type_traits/is_pointer.hpp>
54 #include <boost/type_traits/is_enum.hpp>
55 #include <boost/type_traits/is_const.hpp>
56 #include <boost/type_traits/remove_const.hpp>
57 #include <boost/type_traits/remove_extent.hpp>
58 #include <boost/type_traits/is_polymorphic.hpp>
59 
60 #include <boost/serialization/assume_abstract.hpp>
61 
62 #if !defined(BOOST_MSVC) && \
63     (BOOST_WORKAROUND(__IBMCPP__, < 1210) || \
64     defined(__SUNPRO_CC) && (__SUNPRO_CC < 0x590))
65     #define BOOST_SERIALIZATION_DONT_USE_HAS_NEW_OPERATOR 1
66 #else
67     #define BOOST_SERIALIZATION_DONT_USE_HAS_NEW_OPERATOR 0
68 #endif
69 
70 #if ! BOOST_SERIALIZATION_DONT_USE_HAS_NEW_OPERATOR
71 #include <boost/type_traits/has_new_operator.hpp>
72 #endif
73 
74 #include <boost/serialization/serialization.hpp>
75 #include <boost/serialization/version.hpp>
76 #include <boost/serialization/level.hpp>
77 #include <boost/serialization/tracking.hpp>
78 #include <boost/serialization/type_info_implementation.hpp>
79 #include <boost/serialization/nvp.hpp>
80 #include <boost/serialization/void_cast.hpp>
81 #include <boost/serialization/collection_size_type.hpp>
82 #include <boost/serialization/singleton.hpp>
83 #include <boost/serialization/wrapper.hpp>
84 #include <boost/serialization/array_wrapper.hpp>
85 
86 // the following is need only for dynamic cast of polymorphic pointers
87 #include <boost/archive/archive_exception.hpp>
88 #include <boost/archive/detail/basic_iarchive.hpp>
89 #include <boost/archive/detail/basic_iserializer.hpp>
90 #include <boost/archive/detail/basic_pointer_iserializer.hpp>
91 #include <boost/archive/detail/archive_serializer_map.hpp>
92 #include <boost/archive/detail/check.hpp>
93 
94 #include <boost/core/addressof.hpp>
95 
96 namespace boost {
97 
98 namespace serialization {
99     class extended_type_info;
100 } // namespace serialization
101 
102 namespace archive {
103 
104 // an accessor to permit friend access to archives.  Needed because
105 // some compilers don't handle friend templates completely
106 class load_access {
107 public:
108     template<class Archive, class T>
load_primitive(Archive & ar,T & t)109     static void load_primitive(Archive &ar, T &t){
110         ar.load(t);
111     }
112 };
113 
114 namespace detail {
115 
116 #ifdef BOOST_MSVC
117 #  pragma warning(push)
118 #  pragma warning(disable : 4511 4512)
119 #endif
120 
121 template<class Archive, class T>
122 class iserializer : public basic_iserializer
123 {
124 private:
destroy(void * address) const125     void destroy(/*const*/ void *address) const BOOST_OVERRIDE {
126         boost::serialization::access::destroy(static_cast<T *>(address));
127     }
128 public:
iserializer()129     explicit iserializer() :
130         basic_iserializer(
131             boost::serialization::singleton<
132                 typename
133                 boost::serialization::type_info_implementation< T >::type
134             >::get_const_instance()
135         )
136     {}
137     BOOST_DLLEXPORT void load_object_data(
138         basic_iarchive & ar,
139         void *x,
140         const unsigned int file_version
141     ) const BOOST_OVERRIDE BOOST_USED;
class_info() const142     bool class_info() const BOOST_OVERRIDE {
143         return boost::serialization::implementation_level< T >::value
144             >= boost::serialization::object_class_info;
145     }
tracking(const unsigned int) const146     bool tracking(const unsigned int /* flags */) const BOOST_OVERRIDE {
147         return boost::serialization::tracking_level< T >::value
148                 == boost::serialization::track_always
149             || ( boost::serialization::tracking_level< T >::value
150                 == boost::serialization::track_selectively
151                 && serialized_as_pointer());
152     }
version() const153     version_type version() const BOOST_OVERRIDE {
154         return version_type(::boost::serialization::version< T >::value);
155     }
is_polymorphic() const156     bool is_polymorphic() const BOOST_OVERRIDE {
157         return boost::is_polymorphic< T >::value;
158     }
~iserializer()159     ~iserializer() BOOST_OVERRIDE {}
160 };
161 
162 #ifdef BOOST_MSVC
163 #  pragma warning(pop)
164 #endif
165 
166 template<class Archive, class T>
load_object_data(basic_iarchive & ar,void * x,const unsigned int file_version) const167 BOOST_DLLEXPORT void iserializer<Archive, T>::load_object_data(
168     basic_iarchive & ar,
169     void *x,
170     const unsigned int file_version
171 ) const {
172     // note: we now comment this out. Before we permited archive
173     // version # to be very large.  Now we don't.  To permit
174     // readers of these old archives, we have to suppress this
175     // code.  Perhaps in the future we might re-enable it but
176     // permit its suppression with a runtime switch.
177     #if 0
178     // trap case where the program cannot handle the current version
179     if(file_version > static_cast<const unsigned int>(version()))
180         boost::serialization::throw_exception(
181             archive::archive_exception(
182                 boost::archive::archive_exception::unsupported_class_version,
183                 get_debug_info()
184             )
185         );
186     #endif
187     // make sure call is routed through the higest interface that might
188     // be specialized by the user.
189     boost::serialization::serialize_adl(
190         boost::serialization::smart_cast_reference<Archive &>(ar),
191         * static_cast<T *>(x),
192         file_version
193     );
194 }
195 
196 #ifdef BOOST_MSVC
197 #  pragma warning(push)
198 #  pragma warning(disable : 4511 4512)
199 #endif
200 
201 // the purpose of this code is to allocate memory for an object
202 // without requiring the constructor to be called.  Presumably
203 // the allocated object will be subsequently initialized with
204 // "placement new".
205 // note: we have the boost type trait has_new_operator but we
206 // have no corresponding has_delete_operator.  So we presume
207 // that the former being true would imply that the a delete
208 // operator is also defined for the class T.
209 
210 template<class T>
211 struct heap_allocation {
212     // boost::has_new_operator< T > doesn't work on these compilers
213     #if BOOST_SERIALIZATION_DONT_USE_HAS_NEW_OPERATOR
214         // This doesn't handle operator new overload for class T
invoke_newboost::archive::detail::heap_allocation215         static T * invoke_new(){
216             return static_cast<T *>(operator new(sizeof(T)));
217         }
invoke_deleteboost::archive::detail::heap_allocation218         static void invoke_delete(T *t){
219             (operator delete(t));
220         }
221     #else
222         // note: we presume that a true value for has_new_operator
223         // implies the existence of a class specific delete operator as well
224         // as a class specific new operator.
225         struct has_new_operator {
226             static T * invoke_new() {
227                 return static_cast<T *>((T::operator new)(sizeof(T)));
228             }
229             static void invoke_delete(T * t) {
230                 // if compilation fails here, the likely cause that the class
231                 // T has a class specific new operator but no class specific
232                 // delete operator which matches the following signature.
233                 // note that this solution addresses the issue that two
234                 // possible signatures.  But it doesn't address the possibility
235                 // that the class might have class specific new with NO
236                 // class specific delete at all.  Patches (compatible with
237                 // C++03) welcome!
238                 (operator delete)(t);
239             }
240         };
241         struct doesnt_have_new_operator {
242             static T* invoke_new() {
243                 return static_cast<T *>(operator new(sizeof(T)));
244             }
245             static void invoke_delete(T * t) {
246                 // Note: I'm reliance upon automatic conversion from T * to void * here
247                 (operator delete)(t);
248             }
249         };
250         static T * invoke_new() {
251             typedef typename
252                 mpl::eval_if<
253                     boost::has_new_operator< T >,
254                     mpl::identity<has_new_operator >,
255                     mpl::identity<doesnt_have_new_operator >
256                 >::type typex;
257             return typex::invoke_new();
258         }
259         static void invoke_delete(T *t) {
260             typedef typename
261                 mpl::eval_if<
262                     boost::has_new_operator< T >,
263                     mpl::identity<has_new_operator >,
264                     mpl::identity<doesnt_have_new_operator >
265                 >::type typex;
266             typex::invoke_delete(t);
267         }
268     #endif
heap_allocationboost::archive::detail::heap_allocation269     explicit heap_allocation(){
270         m_p = invoke_new();
271     }
~heap_allocationboost::archive::detail::heap_allocation272     ~heap_allocation(){
273         if (0 != m_p)
274             invoke_delete(m_p);
275     }
getboost::archive::detail::heap_allocation276     T* get() const {
277         return m_p;
278     }
279 
releaseboost::archive::detail::heap_allocation280     T* release() {
281         T* p = m_p;
282         m_p = 0;
283         return p;
284     }
285 private:
286     T* m_p;
287 };
288 
289 template<class Archive, class T>
290 class pointer_iserializer :
291     public basic_pointer_iserializer
292 {
293 private:
heap_allocation() const294     void * heap_allocation() const BOOST_OVERRIDE {
295         detail::heap_allocation<T> h;
296         T * t = h.get();
297         h.release();
298         return t;
299     }
get_basic_serializer() const300     const basic_iserializer & get_basic_serializer() const BOOST_OVERRIDE {
301         return boost::serialization::singleton<
302             iserializer<Archive, T>
303         >::get_const_instance();
304     }
305     BOOST_DLLEXPORT void load_object_ptr(
306         basic_iarchive & ar,
307         void * x,
308         const unsigned int file_version
309     ) const BOOST_OVERRIDE BOOST_USED;
310 public:
311     // this should alway be a singleton so make the constructor protected
312     pointer_iserializer();
313     ~pointer_iserializer() BOOST_OVERRIDE;
314 };
315 
316 #ifdef BOOST_MSVC
317 #  pragma warning(pop)
318 #endif
319 
320 // note: BOOST_DLLEXPORT is so that code for polymorphic class
321 // serialized only through base class won't get optimized out
322 template<class Archive, class T>
load_object_ptr(basic_iarchive & ar,void * t,const unsigned int file_version) const323 BOOST_DLLEXPORT void pointer_iserializer<Archive, T>::load_object_ptr(
324     basic_iarchive & ar,
325     void * t,
326     const unsigned int file_version
327 ) const
328 {
329     Archive & ar_impl =
330         boost::serialization::smart_cast_reference<Archive &>(ar);
331 
332     // note that the above will throw std::bad_alloc if the allocation
333     // fails so we don't have to address this contingency here.
334 
335     // catch exception during load_construct_data so that we don't
336     // automatically delete the t which is most likely not fully
337     // constructed
338     BOOST_TRY {
339         // this addresses an obscure situation that occurs when
340         // load_constructor de-serializes something through a pointer.
341         ar.next_object_pointer(t);
342         boost::serialization::load_construct_data_adl<Archive, T>(
343             ar_impl,
344             static_cast<T *>(t),
345             file_version
346         );
347     }
348     BOOST_CATCH(...){
349         // if we get here the load_construct failed.  The heap_allocation
350         // will be automatically deleted so we don't have to do anything
351         // special here.
352         BOOST_RETHROW;
353     }
354     BOOST_CATCH_END
355 
356     ar_impl >> boost::serialization::make_nvp(NULL, * static_cast<T *>(t));
357 }
358 
359 template<class Archive, class T>
pointer_iserializer()360 pointer_iserializer<Archive, T>::pointer_iserializer() :
361     basic_pointer_iserializer(
362         boost::serialization::singleton<
363             typename
364             boost::serialization::type_info_implementation< T >::type
365         >::get_const_instance()
366     )
367 {
368     boost::serialization::singleton<
369         iserializer<Archive, T>
370     >::get_mutable_instance().set_bpis(this);
371     archive_serializer_map<Archive>::insert(this);
372 }
373 
374 template<class Archive, class T>
~pointer_iserializer()375 pointer_iserializer<Archive, T>::~pointer_iserializer(){
376     archive_serializer_map<Archive>::erase(this);
377 }
378 
379 template<class Archive>
380 struct load_non_pointer_type {
381     // note this bounces the call right back to the archive
382     // with no runtime overhead
383     struct load_primitive {
384         template<class T>
invokeboost::archive::detail::load_non_pointer_type::load_primitive385         static void invoke(Archive & ar, T & t){
386             load_access::load_primitive(ar, t);
387         }
388     };
389     // note this bounces the call right back to the archive
390     // with no runtime overhead
391     struct load_only {
392         template<class T>
invokeboost::archive::detail::load_non_pointer_type::load_only393         static void invoke(Archive & ar, const T & t){
394             // short cut to user's serializer
395             // make sure call is routed through the higest interface that might
396             // be specialized by the user.
397             boost::serialization::serialize_adl(
398                 ar,
399                 const_cast<T &>(t),
400                 boost::serialization::version< T >::value
401             );
402         }
403     };
404 
405     // note this save class information including version
406     // and serialization level to the archive
407     struct load_standard {
408         template<class T>
invokeboost::archive::detail::load_non_pointer_type::load_standard409         static void invoke(Archive &ar, const T & t){
410             void * x = boost::addressof(const_cast<T &>(t));
411             ar.load_object(
412                 x,
413                 boost::serialization::singleton<
414                     iserializer<Archive, T>
415                 >::get_const_instance()
416             );
417         }
418     };
419 
420     struct load_conditional {
421         template<class T>
invokeboost::archive::detail::load_non_pointer_type::load_conditional422         static void invoke(Archive &ar, T &t){
423             //if(0 == (ar.get_flags() & no_tracking))
424                 load_standard::invoke(ar, t);
425             //else
426             //    load_only::invoke(ar, t);
427         }
428     };
429 
430     template<class T>
invokeboost::archive::detail::load_non_pointer_type431     static void invoke(Archive & ar, T &t){
432         typedef typename mpl::eval_if<
433                 // if its primitive
434                 mpl::equal_to<
435                     boost::serialization::implementation_level< T >,
436                     mpl::int_<boost::serialization::primitive_type>
437                 >,
438                 mpl::identity<load_primitive>,
439             // else
440             typename mpl::eval_if<
441             // class info / version
442             mpl::greater_equal<
443                         boost::serialization::implementation_level< T >,
444                         mpl::int_<boost::serialization::object_class_info>
445                     >,
446             // do standard load
447             mpl::identity<load_standard>,
448         // else
449         typename mpl::eval_if<
450             // no tracking
451                     mpl::equal_to<
452                         boost::serialization::tracking_level< T >,
453                         mpl::int_<boost::serialization::track_never>
454                 >,
455                 // do a fast load
456                 mpl::identity<load_only>,
457             // else
458             // do a fast load only tracking is turned off
459             mpl::identity<load_conditional>
460         > > >::type typex;
461         check_object_versioning< T >();
462         check_object_level< T >();
463         typex::invoke(ar, t);
464     }
465 };
466 
467 template<class Archive>
468 struct load_pointer_type {
469     struct abstract
470     {
471         template<class T>
register_typeboost::archive::detail::load_pointer_type::abstract472         static const basic_pointer_iserializer * register_type(Archive & /* ar */){
473             // it has? to be polymorphic
474             BOOST_STATIC_ASSERT(boost::is_polymorphic< T >::value);
475             return static_cast<basic_pointer_iserializer *>(NULL);
476          }
477     };
478 
479     struct non_abstract
480     {
481         template<class T>
register_typeboost::archive::detail::load_pointer_type::non_abstract482         static const basic_pointer_iserializer * register_type(Archive & ar){
483             return ar.register_type(static_cast<T *>(NULL));
484         }
485     };
486 
487     template<class T>
register_typeboost::archive::detail::load_pointer_type488     static const basic_pointer_iserializer * register_type(Archive &ar, const T* const /*t*/){
489         // there should never be any need to load an abstract polymorphic
490         // class pointer.  Inhibiting code generation for this
491         // permits abstract base classes to be used - note: exception
492         // virtual serialize functions used for plug-ins
493         typedef typename
494             mpl::eval_if<
495                 boost::serialization::is_abstract<const T>,
496                 boost::mpl::identity<abstract>,
497                 boost::mpl::identity<non_abstract>
498             >::type typex;
499         return typex::template register_type< T >(ar);
500     }
501 
502     template<class T>
pointer_tweakboost::archive::detail::load_pointer_type503     static T * pointer_tweak(
504         const boost::serialization::extended_type_info & eti,
505         void const * const t,
506         const T &
507     ) {
508         // tweak the pointer back to the base class
509         void * upcast = const_cast<void *>(
510             boost::serialization::void_upcast(
511                 eti,
512                 boost::serialization::singleton<
513                     typename
514                     boost::serialization::type_info_implementation< T >::type
515                 >::get_const_instance(),
516                 t
517             )
518         );
519         if(NULL == upcast)
520             boost::serialization::throw_exception(
521                 archive_exception(archive_exception::unregistered_class)
522             );
523         return static_cast<T *>(upcast);
524     }
525 
526     template<class T>
check_loadboost::archive::detail::load_pointer_type527     static void check_load(T * const /* t */){
528         check_pointer_level< T >();
529         check_pointer_tracking< T >();
530     }
531 
532     static const basic_pointer_iserializer *
findboost::archive::detail::load_pointer_type533     find(const boost::serialization::extended_type_info & type){
534         return static_cast<const basic_pointer_iserializer *>(
535             archive_serializer_map<Archive>::find(type)
536         );
537     }
538 
539     template<class Tptr>
invokeboost::archive::detail::load_pointer_type540     static void invoke(Archive & ar, Tptr & t){
541         check_load(t);
542         const basic_pointer_iserializer * bpis_ptr = register_type(ar, t);
543         const basic_pointer_iserializer * newbpis_ptr = ar.load_pointer(
544             // note major hack here !!!
545             // I tried every way to convert Tptr &t (where Tptr might
546             // include const) to void * &.  This is the only way
547             // I could make it work. RR
548             (void * & )t,
549             bpis_ptr,
550             find
551         );
552         // if the pointer isn't that of the base class
553         if(newbpis_ptr != bpis_ptr){
554             t = pointer_tweak(newbpis_ptr->get_eti(), t, *t);
555         }
556     }
557 };
558 
559 template<class Archive>
560 struct load_enum_type {
561     template<class T>
invokeboost::archive::detail::load_enum_type562     static void invoke(Archive &ar, T &t){
563         // convert integers to correct enum to load
564         int i;
565         ar >> boost::serialization::make_nvp(NULL, i);
566         t = static_cast< T >(i);
567     }
568 };
569 
570 template<class Archive>
571 struct load_array_type {
572     template<class T>
invokeboost::archive::detail::load_array_type573     static void invoke(Archive &ar, T &t){
574         typedef typename remove_extent< T >::type value_type;
575 
576         // convert integers to correct enum to load
577         // determine number of elements in the array. Consider the
578         // fact that some machines will align elements on boundaries
579         // other than characters.
580         std::size_t current_count = sizeof(t) / (
581             static_cast<char *>(static_cast<void *>(&t[1]))
582             - static_cast<char *>(static_cast<void *>(&t[0]))
583         );
584         boost::serialization::collection_size_type count;
585         ar >> BOOST_SERIALIZATION_NVP(count);
586         if(static_cast<std::size_t>(count) > current_count)
587             boost::serialization::throw_exception(
588                 archive::archive_exception(
589                     boost::archive::archive_exception::array_size_too_short
590                 )
591             );
592         // explict template arguments to pass intel C++ compiler
593         ar >> serialization::make_array<
594             value_type,
595             boost::serialization::collection_size_type
596         >(
597             static_cast<value_type *>(&t[0]),
598             count
599         );
600     }
601 };
602 
603 } // detail
604 
605 template<class Archive, class T>
load(Archive & ar,T & t)606 inline void load(Archive & ar, T &t){
607     // if this assertion trips. It means we're trying to load a
608     // const object with a compiler that doesn't have correct
609     // function template ordering.  On other compilers, this is
610     // handled below.
611     detail::check_const_loading< T >();
612     typedef
613         typename mpl::eval_if<is_pointer< T >,
614             mpl::identity<detail::load_pointer_type<Archive> >
615         ,//else
616         typename mpl::eval_if<is_array< T >,
617             mpl::identity<detail::load_array_type<Archive> >
618         ,//else
619         typename mpl::eval_if<is_enum< T >,
620             mpl::identity<detail::load_enum_type<Archive> >
621         ,//else
622             mpl::identity<detail::load_non_pointer_type<Archive> >
623         >
624         >
625         >::type typex;
626     typex::invoke(ar, t);
627 }
628 
629 } // namespace archive
630 } // namespace boost
631 
632 #endif // BOOST_ARCHIVE_DETAIL_ISERIALIZER_HPP
633