Imported Upstream version 1.57.0
[platform/upstream/boost.git] / libs / serialization / src / basic_iarchive.cpp
1 /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
2 // basic_archive.cpp:
3
4 // (C) Copyright 2002 Robert Ramey - http://www.rrsd.com . 
5 // Use, modification and distribution is subject to the Boost Software
6 // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
7 // http://www.boost.org/LICENSE_1_0.txt)
8
9 //  See http://www.boost.org for updates, documentation, and revision history.
10
11 #include <boost/config.hpp> // msvc 6.0 needs this to suppress warnings
12
13 #include <boost/assert.hpp>
14 #include <set>
15 #include <list>
16 #include <vector>
17 #include <cstddef> // size_t, NULL
18
19 #include <boost/config.hpp>
20 #if defined(BOOST_NO_STDC_NAMESPACE)
21 namespace std{ 
22     using ::size_t; 
23 } // namespace std
24 #endif
25
26 #include <boost/integer_traits.hpp>
27 #include <boost/serialization/state_saver.hpp>
28 #include <boost/serialization/throw_exception.hpp>
29 #include <boost/serialization/tracking.hpp>
30
31 #define BOOST_ARCHIVE_SOURCE
32 // include this to prevent linker errors when the
33 // same modules are marked export and import.
34 #define BOOST_SERIALIZATION_SOURCE
35
36 #include <boost/archive/archive_exception.hpp>
37
38 #include <boost/archive/detail/decl.hpp>
39 #include <boost/archive/basic_archive.hpp>
40 #include <boost/archive/detail/basic_iserializer.hpp>
41 #include <boost/archive/detail/basic_pointer_iserializer.hpp>
42 #include <boost/archive/detail/basic_iarchive.hpp>
43
44 #include <boost/archive/detail/auto_link_archive.hpp>
45
46 using namespace boost::serialization;
47
48 namespace boost {
49 namespace archive {
50 namespace detail {
51
52 class basic_iarchive_impl {
53     friend class basic_iarchive;
54     library_version_type m_archive_library_version;
55     unsigned int m_flags;
56
57     //////////////////////////////////////////////////////////////////////
58     // information about each serialized object loaded
59     // indexed on object_id
60     struct aobject
61     {
62         void * address;
63         bool loaded_as_pointer;
64         class_id_type class_id;
65         aobject(
66             void *a,
67             class_id_type class_id_
68         ) :
69             address(a),
70             loaded_as_pointer(false),
71             class_id(class_id_)
72         {}
73         aobject() : 
74             address(NULL),
75             loaded_as_pointer(false),
76             class_id(-2) 
77         {}
78     };
79     typedef std::vector<aobject> object_id_vector_type;
80     object_id_vector_type object_id_vector;
81
82     //////////////////////////////////////////////////////////////////////
83     // used to implement the reset_object_address operation.
84     struct moveable_objects {
85         object_id_type start;
86         object_id_type end;
87         object_id_type recent;
88         bool is_pointer;
89         moveable_objects() :
90             start(0),
91             end(0),
92             recent(0),
93             is_pointer(false)
94         {}
95     } m_moveable_objects;
96
97     void reset_object_address(
98         const void * new_address, 
99         const void *old_address
100     );
101
102     //////////////////////////////////////////////////////////////////////
103     // used by load object to look up class id given basic_serializer
104     struct cobject_type
105     {
106         const basic_iserializer * m_bis;
107         const class_id_type m_class_id;
108         cobject_type(
109             std::size_t class_id,
110             const basic_iserializer & bis
111         ) : 
112             m_bis(& bis),
113             m_class_id(class_id)
114         {}
115         cobject_type(const cobject_type & rhs) : 
116             m_bis(rhs.m_bis),
117             m_class_id(rhs.m_class_id)
118         {}
119         // the following cannot be defined because of the const
120         // member.  This will generate a link error if an attempt
121         // is made to assign.  This should never be necessary
122         cobject_type & operator=(const cobject_type & rhs);
123         bool operator<(const cobject_type &rhs) const
124         {
125             return *m_bis < *(rhs.m_bis);
126         }
127     };
128     typedef std::set<cobject_type> cobject_info_set_type;
129     cobject_info_set_type cobject_info_set;
130
131     //////////////////////////////////////////////////////////////////////
132     // information about each serialized class indexed on class_id
133     class cobject_id 
134     {
135     public:
136         cobject_id & operator=(const cobject_id & rhs){
137             bis_ptr = rhs.bis_ptr;
138             bpis_ptr = rhs.bpis_ptr;
139             file_version = rhs.file_version;
140             tracking_level = rhs.tracking_level;
141             initialized = rhs.initialized;
142             return *this;
143         }
144         const basic_iserializer * bis_ptr;
145         const basic_pointer_iserializer * bpis_ptr;
146         version_type file_version;
147         tracking_type tracking_level;
148         bool initialized;
149
150         cobject_id(const basic_iserializer & bis_) :
151             bis_ptr(& bis_),
152             bpis_ptr(NULL),
153             file_version(0),
154             tracking_level(track_never),
155             initialized(false)
156         {}
157         cobject_id(const cobject_id &rhs): 
158             bis_ptr(rhs.bis_ptr),
159             bpis_ptr(rhs.bpis_ptr),
160             file_version(rhs.file_version),
161             tracking_level(rhs.tracking_level),
162             initialized(rhs.initialized)
163         {}
164     };
165     typedef std::vector<cobject_id> cobject_id_vector_type;
166     cobject_id_vector_type cobject_id_vector;
167
168     //////////////////////////////////////////////////////////////////////
169     // address of the most recent object serialized as a poiner
170     // whose data itself is now pending serialization
171     struct pending {
172         void * object;
173         const basic_iserializer * bis;
174         version_type version;
175         pending() :
176             object(NULL),
177             bis(NULL),
178             version(0)
179         {}
180     } m_pending;
181
182     basic_iarchive_impl(unsigned int flags) :
183         m_archive_library_version(BOOST_ARCHIVE_VERSION()),
184         m_flags(flags)
185     {}
186     ~basic_iarchive_impl(){}
187     void set_library_version(library_version_type archive_library_version){
188         m_archive_library_version = archive_library_version;
189     }
190     bool
191     track(
192         basic_iarchive & ar,
193         void * & t
194     );
195     void
196     load_preamble(
197         basic_iarchive & ar,
198         cobject_id & co
199     );
200     class_id_type register_type(
201         const basic_iserializer & bis
202     );
203
204     // redirect through virtual functions to load functions for this archive
205     template<class T>
206     void load(basic_iarchive & ar, T & t){
207         ar.vload(t);
208     }
209
210 //public:
211     void
212     next_object_pointer(void * t){
213         m_pending.object = t;
214     }
215     void delete_created_pointers();
216     class_id_type register_type(
217         const basic_pointer_iserializer & bpis
218     );
219     void load_object(
220         basic_iarchive & ar,
221         void * t,
222         const basic_iserializer & bis
223     );
224     const basic_pointer_iserializer * load_pointer(
225         basic_iarchive & ar,
226         void * & t, 
227         const basic_pointer_iserializer * bpis,
228         const basic_pointer_iserializer * (*finder)(
229             const boost::serialization::extended_type_info & type
230         )
231
232     );
233 };
234
235 inline void 
236 basic_iarchive_impl::reset_object_address(
237     void const * const new_address, 
238     void const * const old_address
239 ){
240     if(m_moveable_objects.is_pointer)
241         return;
242
243     // this code handles a couple of situations.
244     // a) where reset_object_address is applied to an untracked object.
245     //    In such a case the call is really superfluous and its really an
246     //    an error.  But we don't have access to the types here so we can't
247     //    know that.  However, this code will effectively turn this situation
248     //    into a no-op and every thing will work fine - albeat with a small
249     //    execution time penalty.
250     // b) where the call to reset_object_address doesn't immediatly follow
251     //    the << operator to which it corresponds.  This would be a bad idea
252     //    but the code may work anyway.  Naturally, a bad practice on the part
253     //    of the programmer but we can't detect it - as above.  So maybe we
254     //    can save a few more people from themselves as above.
255     object_id_type i;
256     for(i = m_moveable_objects.recent; i < m_moveable_objects.end; ++i){
257         if(old_address == object_id_vector[i].address)
258             break;
259     }
260     for(; i < m_moveable_objects.end; ++i){
261         void const * const this_address = object_id_vector[i].address;
262         // calculate displacement from this level
263         // warning - pointer arithmetic on void * is in herently non-portable
264         // but expected to work on all platforms in current usage
265         if(this_address > old_address){
266             std::size_t member_displacement
267                 = reinterpret_cast<std::size_t>(this_address) 
268                 - reinterpret_cast<std::size_t>(old_address);
269             object_id_vector[i].address = reinterpret_cast<void *>(
270                 reinterpret_cast<std::size_t>(new_address) + member_displacement
271             );
272         }
273         else{
274             std::size_t member_displacement
275                 = reinterpret_cast<std::size_t>(old_address)
276                 - reinterpret_cast<std::size_t>(this_address); 
277             object_id_vector[i].address = reinterpret_cast<void *>(
278                 reinterpret_cast<std::size_t>(new_address) - member_displacement
279             );
280        }
281     }
282 }
283
284 inline void 
285 basic_iarchive_impl::delete_created_pointers()
286 {
287     object_id_vector_type::iterator i;
288     for(
289         i = object_id_vector.begin();
290         i != object_id_vector.end(); 
291         ++i
292     ){
293         if(i->loaded_as_pointer){
294             // borland complains without this minor hack
295             const int j = i->class_id;
296             const cobject_id & co = cobject_id_vector[j];
297             //const cobject_id & co = cobject_id_vector[i->class_id];
298             // with the appropriate input serializer, 
299             // delete the indicated object
300             co.bis_ptr->destroy(i->address);
301         }
302     }
303 }
304
305 inline class_id_type
306 basic_iarchive_impl::register_type(
307     const basic_iserializer & bis
308 ){
309     class_id_type cid(cobject_info_set.size());
310     cobject_type co(cid, bis);
311     std::pair<cobject_info_set_type::const_iterator, bool>
312         result = cobject_info_set.insert(co);
313
314     if(result.second){
315         cobject_id_vector.push_back(cobject_id(bis));
316         BOOST_ASSERT(cobject_info_set.size() == cobject_id_vector.size());
317     }
318     cid = result.first->m_class_id;
319     // borland complains without this minor hack
320     const int tid = cid;
321     cobject_id & coid = cobject_id_vector[tid];
322     coid.bpis_ptr = bis.get_bpis_ptr();
323     return cid;
324 }
325
326 void
327 basic_iarchive_impl::load_preamble(
328     basic_iarchive & ar,
329     cobject_id & co
330 ){
331     if(! co.initialized){
332         if(co.bis_ptr->class_info()){
333             class_id_optional_type cid(class_id_type(0));
334             load(ar, cid);    // to be thrown away
335             load(ar, co.tracking_level);
336             load(ar, co.file_version);
337         }
338         else{
339             // override tracking with indicator from class information
340             co.tracking_level = co.bis_ptr->tracking(m_flags);
341             co.file_version = version_type(
342                 co.bis_ptr->version()
343             );
344         }
345         co.initialized = true;
346     }
347 }
348
349 bool
350 basic_iarchive_impl::track(
351     basic_iarchive & ar,
352     void * & t
353 ){
354     object_id_type oid;
355     load(ar, oid);
356
357     // if its a reference to a old object
358     if(object_id_type(object_id_vector.size()) > oid){
359         // we're done
360         t = object_id_vector[oid].address;
361         return false;
362     }
363     return true;
364 }
365
366 inline void
367 basic_iarchive_impl::load_object(
368     basic_iarchive & ar,
369     void * t,
370     const basic_iserializer & bis
371 ){
372     m_moveable_objects.is_pointer = false;
373     serialization::state_saver<bool> ss_is_pointer(m_moveable_objects.is_pointer);
374     // if its been serialized through a pointer and the preamble's been done
375     if(t == m_pending.object && & bis == m_pending.bis){
376         // read data
377         (bis.load_object_data)(ar, t, m_pending.version);
378         return;
379     }
380
381     const class_id_type cid = register_type(bis);
382     const int i = cid;
383     cobject_id & co = cobject_id_vector[i];
384
385     load_preamble(ar, co);
386
387     // save the current move stack position in case we want to truncate it
388     boost::serialization::state_saver<object_id_type> ss_start(m_moveable_objects.start);
389
390     // note: extra line used to evade borland issue
391     const bool tracking = co.tracking_level;
392
393     object_id_type this_id;
394     m_moveable_objects.start =
395     this_id = object_id_type(object_id_vector.size());
396
397     // if we tracked this object when the archive was saved
398     if(tracking){ 
399         // if it was already read
400         if(!track(ar, t))
401             // we're done
402             return;
403         // add a new enty into the tracking list
404         object_id_vector.push_back(aobject(t, cid));
405         // and add an entry for this object
406         m_moveable_objects.end = object_id_type(object_id_vector.size());
407     }
408     // read data
409     (bis.load_object_data)(ar, t, co.file_version);
410     m_moveable_objects.recent = this_id;
411 }
412
413 inline const basic_pointer_iserializer *
414 basic_iarchive_impl::load_pointer(
415     basic_iarchive &ar,
416     void * & t,
417     const basic_pointer_iserializer * bpis_ptr,
418     const basic_pointer_iserializer * (*finder)(
419         const boost::serialization::extended_type_info & type_
420     )
421 ){
422     m_moveable_objects.is_pointer = true;
423     serialization::state_saver<bool> w(m_moveable_objects.is_pointer);
424
425     class_id_type cid;
426     load(ar, cid);
427
428     if(NULL_POINTER_TAG == cid){
429         t = NULL;
430         return bpis_ptr;
431     }
432
433     // if its a new class type - i.e. never been registered
434     if(class_id_type(cobject_info_set.size()) <= cid){
435         // if its either abstract
436         if(NULL == bpis_ptr
437         // or polymorphic
438         || bpis_ptr->get_basic_serializer().is_polymorphic()){
439             // is must have been exported
440             char key[BOOST_SERIALIZATION_MAX_KEY_SIZE];
441             class_name_type class_name(key);
442             load(ar, class_name);
443             // if it has a class name
444             const serialization::extended_type_info *eti = NULL;
445             if(0 != key[0])
446                 eti = serialization::extended_type_info::find(key);
447             if(NULL == eti)
448                 boost::serialization::throw_exception(
449                     archive_exception(archive_exception::unregistered_class)
450                 );
451             bpis_ptr = (*finder)(*eti);
452         }
453         BOOST_ASSERT(NULL != bpis_ptr);
454         // class_id_type new_cid = register_type(bpis_ptr->get_basic_serializer());
455         BOOST_VERIFY(register_type(bpis_ptr->get_basic_serializer()) == cid);
456         int i = cid;
457         cobject_id_vector[i].bpis_ptr = bpis_ptr;
458     }
459     int i = cid;
460     cobject_id & co = cobject_id_vector[i];
461     bpis_ptr = co.bpis_ptr;
462
463     load_preamble(ar, co);
464
465     // extra line to evade borland issue
466     const bool tracking = co.tracking_level;
467     // if we're tracking and the pointer has already been read
468     if(tracking && ! track(ar, t))
469         // we're done
470         return bpis_ptr;
471
472     // save state
473     serialization::state_saver<object_id_type> w_start(m_moveable_objects.start);
474
475     // allocate space on the heap for the object - to be constructed later
476     t = bpis_ptr->heap_allocation();
477     BOOST_ASSERT(NULL != t);
478
479     if(! tracking){
480         bpis_ptr->load_object_ptr(ar, t, co.file_version);
481     }
482     else{
483         serialization::state_saver<void *> x(m_pending.object);
484         serialization::state_saver<const basic_iserializer *> y(m_pending.bis);
485         serialization::state_saver<version_type> z(m_pending.version);
486
487         m_pending.bis = & bpis_ptr->get_basic_serializer();
488         m_pending.version = co.file_version;
489
490         // predict next object id to be created
491         const unsigned int ui = object_id_vector.size();
492
493         serialization::state_saver<object_id_type> w_end(m_moveable_objects.end);
494
495         
496         // add to list of serialized objects so that we can properly handle
497         // cyclic strucures
498         object_id_vector.push_back(aobject(t, cid));
499
500         // remember that that the address of these elements could change
501         // when we make another call so don't use the address
502         bpis_ptr->load_object_ptr(
503             ar,
504             t,
505             m_pending.version
506         );
507         object_id_vector[ui].loaded_as_pointer = true;
508     }
509
510     return bpis_ptr;
511 }
512
513 } // namespace detail
514 } // namespace archive
515 } // namespace boost
516
517 //////////////////////////////////////////////////////////////////////
518 // implementation of basic_iarchive functions
519 namespace boost {
520 namespace archive {
521 namespace detail {
522
523 BOOST_ARCHIVE_DECL(void)
524 basic_iarchive::next_object_pointer(void *t){
525     pimpl->next_object_pointer(t);
526 }
527
528 BOOST_ARCHIVE_DECL(BOOST_PP_EMPTY())
529 basic_iarchive::basic_iarchive(unsigned int flags) : 
530     pimpl(new basic_iarchive_impl(flags))
531 {}
532
533 BOOST_ARCHIVE_DECL(BOOST_PP_EMPTY())
534 basic_iarchive::~basic_iarchive()
535 {
536     delete pimpl;
537 }
538
539 BOOST_ARCHIVE_DECL(void)
540 basic_iarchive::set_library_version(library_version_type archive_library_version){
541     pimpl->set_library_version(archive_library_version);
542 }
543
544 BOOST_ARCHIVE_DECL(void)
545 basic_iarchive::reset_object_address(
546     const void * new_address, 
547     const void * old_address
548 ){
549     pimpl->reset_object_address(new_address, old_address);
550 }
551
552 BOOST_ARCHIVE_DECL(void)
553 basic_iarchive::load_object(
554     void *t, 
555     const basic_iserializer & bis
556 ){
557     pimpl->load_object(*this, t, bis);
558 }
559
560 // load a pointer object
561 BOOST_ARCHIVE_DECL(const basic_pointer_iserializer *)
562 basic_iarchive::load_pointer(
563     void * &t, 
564     const basic_pointer_iserializer * bpis_ptr,
565     const basic_pointer_iserializer * (*finder)(
566         const boost::serialization::extended_type_info & type_
567     )
568
569 ){
570     return pimpl->load_pointer(*this, t, bpis_ptr, finder);
571 }
572
573 BOOST_ARCHIVE_DECL(void)
574 basic_iarchive::register_basic_serializer(const basic_iserializer & bis){
575     pimpl->register_type(bis);
576 }
577
578 BOOST_ARCHIVE_DECL(void)
579 basic_iarchive::delete_created_pointers()
580 {
581     pimpl->delete_created_pointers();
582 }
583
584 BOOST_ARCHIVE_DECL(boost::archive::library_version_type) 
585 basic_iarchive::get_library_version() const{
586     return pimpl->m_archive_library_version;
587 }
588
589 BOOST_ARCHIVE_DECL(unsigned int) 
590 basic_iarchive::get_flags() const{
591     return pimpl->m_flags;
592 }
593
594 } // namespace detail
595 } // namespace archive
596 } // namespace boost