1/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
2// basic_oarchive.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 for warning suppression
12
13#include <boost/assert.hpp>
14#include <set>
15#include <cstddef> // NULL
16
17#include <boost/limits.hpp>
18
19// including this here to work around an ICC in intel 7.0
20// normally this would be part of basic_oarchive.hpp below.
21#define BOOST_ARCHIVE_SOURCE
22// include this to prevent linker errors when the
23// same modules are marked export and import.
24#define BOOST_SERIALIZATION_SOURCE
25#include <boost/serialization/config.hpp>
26#include <boost/serialization/state_saver.hpp>
27#include <boost/serialization/throw_exception.hpp>
28#include <boost/serialization/extended_type_info.hpp>
29
30#include <boost/archive/detail/decl.hpp>
31#include <boost/archive/basic_archive.hpp>
32#include <boost/archive/detail/basic_oserializer.hpp>
33#include <boost/archive/detail/basic_pointer_oserializer.hpp>
34#include <boost/archive/detail/basic_oarchive.hpp>
35#include <boost/archive/archive_exception.hpp>
36
37#ifdef BOOST_MSVC
38# pragma warning(push)
39# pragma warning(disable : 4251 4231 4660 4275)
40#endif
41
42using namespace boost::serialization;
43
44namespace boost {
45namespace archive {
46namespace detail {
47
48class basic_oarchive_impl {
49 friend class basic_oarchive;
50 unsigned int m_flags;
51
52 //////////////////////////////////////////////////////////////////////
53 // information about each serialized object saved
54 // keyed on address, class_id
55 struct aobject
56 {
57 const void * address;
58 class_id_type class_id;
59 object_id_type object_id;
60
61 bool operator<(const aobject &rhs) const
62 {
63 BOOST_ASSERT(NULL != address);
64 BOOST_ASSERT(NULL != rhs.address);
65 if( address < rhs.address )
66 return true;
67 if( address > rhs.address )
68 return false;
69 return class_id < rhs.class_id;
70 }
71 aobject(
72 const void *a,
73 class_id_type class_id_,
74 object_id_type object_id_
75 ) :
76 address(a),
77 class_id(class_id_),
78 object_id(object_id_)
79 {}
80 aobject() : address(NULL){}
81 };
82 // keyed on class_id, address
83 typedef std::set<aobject> object_set_type;
84 object_set_type object_set;
85
86 //////////////////////////////////////////////////////////////////////
87 // information about each serialized class saved
88 // keyed on type_info
89 struct cobject_type
90 {
91 const basic_oserializer * m_bos_ptr;
92 const class_id_type m_class_id;
93 bool m_initialized;
94 cobject_type(
95 std::size_t class_id,
96 const basic_oserializer & bos
97 ) :
98 m_bos_ptr(& bos),
99 m_class_id(class_id),
100 m_initialized(false)
101 {}
102 cobject_type(const basic_oserializer & bos) :
103 m_bos_ptr(& bos),
104 m_initialized(false)
105 {}
106 cobject_type(
107 const cobject_type & rhs
108 ) :
109 m_bos_ptr(rhs.m_bos_ptr),
110 m_class_id(rhs.m_class_id),
111 m_initialized(rhs.m_initialized)
112 {}
113 // the following cannot be defined because of the const
114 // member. This will generate a link error if an attempt
115 // is made to assign. This should never be necessary
116 // use this only for lookup argument
117 cobject_type & operator=(const cobject_type &rhs);
118 bool operator<(const cobject_type &rhs) const {
119 return *m_bos_ptr < *(rhs.m_bos_ptr);
120 }
121 };
122 // keyed on type_info
123 typedef std::set<cobject_type> cobject_info_set_type;
124 cobject_info_set_type cobject_info_set;
125
126 // list of objects initially stored as pointers - used to detect errors
127 // keyed on object id
128 std::set<object_id_type> stored_pointers;
129
130 // address of the most recent object serialized as a pointer
131 // whose data itself is now pending serialization
132 const void * pending_object;
133 const basic_oserializer * pending_bos;
134
135 basic_oarchive_impl(unsigned int flags) :
136 m_flags(flags),
137 pending_object(NULL),
138 pending_bos(NULL)
139 {}
140
141 const cobject_type &
142 find(const basic_oserializer & bos);
143 const basic_oserializer *
144 find(const serialization::extended_type_info &ti) const;
145
146//public:
147 const cobject_type &
148 register_type(const basic_oserializer & bos);
149 void save_object(
150 basic_oarchive & ar,
151 const void *t,
152 const basic_oserializer & bos
153 );
154 void save_pointer(
155 basic_oarchive & ar,
156 const void * t,
157 const basic_pointer_oserializer * bpos
158 );
159};
160
161//////////////////////////////////////////////////////////////////////
162// basic_oarchive implementation functions
163
164// given a type_info - find its bos
165// return NULL if not found
166inline const basic_oserializer *
167basic_oarchive_impl::find(const serialization::extended_type_info & ti) const {
168 #ifdef BOOST_MSVC
169 # pragma warning(push)
170 # pragma warning(disable : 4511 4512)
171 #endif
172 class bosarg :
173 public basic_oserializer
174 {
175 bool class_info() const BOOST_OVERRIDE {
176 BOOST_ASSERT(false);
177 return false;
178 }
179 // returns true if objects should be tracked
180 bool tracking(const unsigned int) const BOOST_OVERRIDE {
181 BOOST_ASSERT(false);
182 return false;
183 }
184 // returns class version
185 version_type version() const BOOST_OVERRIDE {
186 BOOST_ASSERT(false);
187 return version_type(0);
188 }
189 // returns true if this class is polymorphic
190 bool is_polymorphic() const BOOST_OVERRIDE {
191 BOOST_ASSERT(false);
192 return false;
193 }
194 void save_object_data(
195 basic_oarchive & /*ar*/, const void * /*x*/
196 ) const BOOST_OVERRIDE {
197 BOOST_ASSERT(false);
198 }
199 public:
200 bosarg(const serialization::extended_type_info & eti) :
201 boost::archive::detail::basic_oserializer(eti)
202 {}
203 };
204 #ifdef BOOST_MSVC
205 #pragma warning(pop)
206 #endif
207 bosarg bos(ti);
208 cobject_info_set_type::const_iterator cit
209 = cobject_info_set.find(x: cobject_type(bos));
210 // it should already have been "registered" - see below
211 if(cit == cobject_info_set.end()){
212 // if an entry is not found in the table it is because a pointer
213 // of a derived class has been serialized through its base class
214 // but the derived class hasn't been "registered"
215 return NULL;
216 }
217 // return pointer to the real class
218 return cit->m_bos_ptr;
219}
220
221inline const basic_oarchive_impl::cobject_type &
222basic_oarchive_impl::find(const basic_oserializer & bos)
223{
224 std::pair<cobject_info_set_type::iterator, bool> cresult =
225 cobject_info_set.insert(x: cobject_type(cobject_info_set.size(), bos));
226 return *(cresult.first);
227}
228
229inline const basic_oarchive_impl::cobject_type &
230basic_oarchive_impl::register_type(
231 const basic_oserializer & bos
232){
233 cobject_type co(cobject_info_set.size(), bos);
234 std::pair<cobject_info_set_type::const_iterator, bool>
235 result = cobject_info_set.insert(x: co);
236 return *(result.first);
237}
238
239inline void
240basic_oarchive_impl::save_object(
241 basic_oarchive & ar,
242 const void *t,
243 const basic_oserializer & bos
244){
245 // if its been serialized through a pointer and the preamble's been done
246 if(t == pending_object && pending_bos == & bos){
247 // just save the object data
248 ar.end_preamble();
249 (bos.save_object_data)(ar, x: t);
250 return;
251 }
252
253 // get class information for this object
254 const cobject_type & co = register_type(bos);
255 if(bos.class_info()){
256 if( ! co.m_initialized){
257 ar.vsave(t: class_id_optional_type(co.m_class_id));
258 ar.vsave(t: tracking_type(bos.tracking(flags: m_flags)));
259 ar.vsave(t: version_type(bos.version()));
260 (const_cast<cobject_type &>(co)).m_initialized = true;
261 }
262 }
263
264 // we're not tracking this type of object
265 if(! co.m_bos_ptr->tracking(flags: m_flags)){
266 // just windup the preamble - no object id to write
267 ar.end_preamble();
268 // and save the data
269 (co.m_bos_ptr->save_object_data)(ar, x: t);
270 return;
271 }
272
273 // look for an existing object id
274 object_id_type oid(object_set.size());
275 // lookup to see if this object has already been written to the archive
276 basic_oarchive_impl::aobject ao(t, co.m_class_id, oid);
277 std::pair<basic_oarchive_impl::object_set_type::const_iterator, bool>
278 aresult = object_set.insert(x: ao);
279 oid = aresult.first->object_id;
280
281 // if its a new object
282 if(aresult.second){
283 // write out the object id
284 ar.vsave(t: oid);
285 ar.end_preamble();
286 // and data
287 (co.m_bos_ptr->save_object_data)(ar, x: t);
288 return;
289 }
290
291 // check that it wasn't originally stored through a pointer
292 if(stored_pointers.end() != stored_pointers.find(x: oid)){
293 // this has to be a user error. loading such an archive
294 // would create duplicate objects
295 boost::serialization::throw_exception(
296 e: archive_exception(archive_exception::pointer_conflict)
297 );
298 }
299 // just save the object id
300 ar.vsave(t: object_reference_type(oid));
301 ar.end_preamble();
302}
303
304// colle
305inline void
306basic_oarchive_impl::save_pointer(
307 basic_oarchive & ar,
308 const void * t,
309 const basic_pointer_oserializer * bpos_ptr
310){
311 const basic_oserializer & bos = bpos_ptr->get_basic_serializer();
312 std::size_t original_count = cobject_info_set.size();
313 const cobject_type & co = register_type(bos);
314 if(! co.m_initialized){
315 ar.vsave(t: co.m_class_id);
316 // if its a previously unregistered class
317 if((cobject_info_set.size() > original_count)){
318 if(bos.is_polymorphic()){
319 const serialization::extended_type_info *eti = & bos.get_eti();
320 const char * key = NULL;
321 if(NULL != eti)
322 key = eti->get_key();
323 if(NULL != key){
324 // the following is required by IBM C++ compiler which
325 // makes a copy when passing a non-const to a const. This
326 // is permitted by the standard but rarely seen in practice
327 const class_name_type cn(key);
328 if(cn.size() > (BOOST_SERIALIZATION_MAX_KEY_SIZE - 1))
329 boost::serialization::throw_exception(
330 e: boost::archive::archive_exception(
331 boost::archive::archive_exception::
332 invalid_class_name)
333 );
334 // write out the external class identifier
335 ar.vsave(t: cn);
336 }
337 else
338 // without an external class name
339 // we won't be able to de-serialize it so bail now
340 boost::serialization::throw_exception(
341 e: archive_exception(archive_exception::unregistered_class)
342 );
343 }
344 }
345 if(bos.class_info()){
346 ar.vsave(t: tracking_type(bos.tracking(flags: m_flags)));
347 ar.vsave(t: version_type(bos.version()));
348 }
349 (const_cast<cobject_type &>(co)).m_initialized = true;
350 }
351 else{
352 ar.vsave(t: class_id_reference_type(co.m_class_id));
353 }
354
355 // if we're not tracking
356 if(! co.m_bos_ptr->tracking(flags: m_flags)){
357 // just save the data itself
358 ar.end_preamble();
359 serialization::state_saver<const void *> x(pending_object);
360 serialization::state_saver<const basic_oserializer *> y(pending_bos);
361 pending_object = t;
362 pending_bos = & bpos_ptr->get_basic_serializer();
363 bpos_ptr->save_object_ptr(ar, x: t);
364 return;
365 }
366
367 object_id_type oid(object_set.size());
368 // lookup to see if this object has already been written to the archive
369 basic_oarchive_impl::aobject ao(t, co.m_class_id, oid);
370 std::pair<basic_oarchive_impl::object_set_type::const_iterator, bool>
371 aresult = object_set.insert(x: ao);
372 oid = aresult.first->object_id;
373 // if the saved object already exists
374 if(! aresult.second){
375 // append the object id to he preamble
376 ar.vsave(t: object_reference_type(oid));
377 // and windup.
378 ar.end_preamble();
379 return;
380 }
381
382 // append id of this object to preamble
383 ar.vsave(t: oid);
384 ar.end_preamble();
385
386 // and save the object itself
387 serialization::state_saver<const void *> x(pending_object);
388 serialization::state_saver<const basic_oserializer *> y(pending_bos);
389 pending_object = t;
390 pending_bos = & bpos_ptr->get_basic_serializer();
391 bpos_ptr->save_object_ptr(ar, x: t);
392 // add to the set of object initially stored through pointers
393 stored_pointers.insert(x: oid);
394}
395
396} // namespace detail
397} // namespace archive
398} // namespace boost
399
400//////////////////////////////////////////////////////////////////////
401// implementation of basic_oarchive functions
402
403namespace boost {
404namespace archive {
405namespace detail {
406
407BOOST_ARCHIVE_DECL
408basic_oarchive::basic_oarchive(unsigned int flags)
409 : pimpl(new basic_oarchive_impl(flags))
410{}
411
412BOOST_ARCHIVE_DECL
413basic_oarchive::~basic_oarchive()
414{}
415
416BOOST_ARCHIVE_DECL void
417basic_oarchive::save_object(
418 const void *x,
419 const basic_oserializer & bos
420){
421 pimpl->save_object(ar&: *this, t: x, bos);
422}
423
424BOOST_ARCHIVE_DECL void
425basic_oarchive::save_pointer(
426 const void * t,
427 const basic_pointer_oserializer * bpos_ptr
428){
429 pimpl->save_pointer(ar&: *this, t, bpos_ptr);
430}
431
432BOOST_ARCHIVE_DECL void
433basic_oarchive::register_basic_serializer(const basic_oserializer & bos){
434 pimpl->register_type(bos);
435}
436
437BOOST_ARCHIVE_DECL library_version_type
438basic_oarchive::get_library_version() const{
439 return BOOST_ARCHIVE_VERSION();
440}
441
442BOOST_ARCHIVE_DECL unsigned int
443basic_oarchive::get_flags() const{
444 return pimpl->m_flags;
445}
446
447BOOST_ARCHIVE_DECL void
448basic_oarchive::end_preamble(){
449}
450
451BOOST_ARCHIVE_DECL helper_collection &
452basic_oarchive::get_helper_collection(){
453 return *this;
454}
455
456} // namespace detail
457} // namespace archive
458} // namespace boost
459
460#ifdef BOOST_MSVC
461#pragma warning(pop)
462#endif
463

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