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

source code of boost/libs/serialization/src/basic_iarchive.cpp