basic_iarchive.cpp 18 KB

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