source: trunk/src/global/txml_iarchive.hpp @ 644

Revision 644, 9.0 KB checked in by Eoin, 11 years ago (diff)

Fixed small incompatibility with boost xml archive object_id.

Line 
1
2#pragma once
3
4#include <stack>
5
6#include <boost/mpl/assert.hpp>
7#include <boost/format.hpp>
8#include <boost/lexical_cast.hpp>
9#include <boost/filesystem/path.hpp>
10#include <boost/filesystem/operations.hpp>
11
12//#include <boost/archive/xml_iarchive.hpp>
13
14#pragma warning (push)
15#pragma warning (disable : 4099)
16#       include <boost/serialization/version.hpp>
17#       include <boost/serialization/vector.hpp>
18#       include <boost/serialization/map.hpp>
19#       include <boost/serialization/split_free.hpp>
20
21#       include <boost/archive/impl/basic_text_iprimitive.ipp>
22#       include <boost/archive/impl/xml_iarchive_impl.ipp>
23//#     include <boost/archive/impl/basic_xml_iarchive.ipp>
24#       include <boost/archive/impl/archive_pointer_iserializer.ipp>
25#       include <boost/archive/shared_ptr_helper.hpp>
26#pragma warning (pop)
27
28#include "global/string_conv.hpp"
29#include "txml.hpp"
30
31#define foreach BOOST_FOREACH
32
33#ifndef TXML_ARCHIVE_LOGGING
34#       define TXML_LOG(s)
35#else
36#       include "../halEvent.hpp"
37#       define TXML_LOG(msg) \
38        hal::event_log.post(boost::shared_ptr<hal::EventDetail>( \
39                        new hal::EventMsg(msg, hal::event_logger::xml_dev)))
40#endif
41
42namespace 
43{
44
45struct i_stringstream_holder
46{
47        std::stringstream stream_;
48};
49
50}
51
52namespace hal { namespace xml
53{
54
55namespace serial = boost::serialization;
56namespace arc = boost::archive;
57
58class txml_iarchive : 
59        private i_stringstream_holder,
60        public arc::basic_text_iprimitive<std::istream>,
61        public arc::detail::common_iarchive<txml_iarchive>,
62        public boost::archive::detail::shared_ptr_helper
63{
64        typedef arc::detail::common_iarchive<txml_iarchive> detail_common_iarchive;
65
66public:
67    txml_iarchive(std::istream& is, unsigned int flags = 0) :
68                basic_text_iprimitive<std::istream>(stream_, 0 != (flags & arc::no_codecvt)),
69                detail_common_iarchive(flags),
70                boost_xml_compat_(false),
71                is_(is),               
72                previous_child_node_(0)
73    {
74                is_ >> xml_;
75
76                current_node_ = xml_.root_element();
77
78                boost_xml_compat_ = (current_node_->value_str() == "boost_serialization");
79                TXML_LOG(boost::wformat(L" << boost_serialization compatibility %1%") % (boost_xml_compat_ ? "on" : "off"));
80
81                init();
82        }
83
84    ~txml_iarchive()
85        {}
86           
87        template<class T>
88    void load(T& t)
89        {
90                std::string tstring = current_node_->first_child()->value_str();
91
92                TXML_LOG(boost::wformat(L" << basic_text_iprimitive: %1%") % from_utf8(tstring));
93
94                stream_ << tstring;
95        basic_text_iprimitive<std::istream>::load(t);
96
97                stream_.clear();
98                stream_ << std::noboolalpha;
99    }
100
101/*      void load(char* s)
102        {
103                std::string tstring = current_node_->first_child()->value_str();
104
105                std::memcpy(s, tstring.data(), tstring.size());
106                s[tstring.size()] = 0;
107                TXML_LOG(boost::wformat(L" << load char*: %1%") % from_utf8(tstring));
108        }
109
110        void load(wchar_t* t)
111        {
112                TXML_LOG(boost::wformat(L" << load wchar_t*: %1%") % from_utf8(current_node_->first_child()->value_str());
113        }
114*/
115        void load(std::string& s) 
116        {               
117                if (xml::node* child = current_node_->first_child())
118                        s = child->value_str();
119                else
120                        s = "";
121
122                TXML_LOG(boost::wformat(L" << load string: %1%") % from_utf8(s));
123        }
124
125        void load(std::wstring& ws) 
126        {
127                if (xml::node* child = current_node_->first_child())
128                        ws = from_utf8(child->value_str());
129                else
130                        ws = L"";
131
132                TXML_LOG(boost::wformat(L" << load wstring: %1%") % ws);
133        }
134
135        void load_override(arc::class_name_type& t, int) 
136        {   
137                std::string tstring = current_node_->first_child()->value_str();
138
139                TXML_LOG(boost::wformat(L" << load class_name_type: %1%") % from_utf8(tstring));
140
141                char * tptr = t;
142                std::memcpy(tptr, tstring.data(), tstring.size());
143                tptr[tstring.size()] = '\0';
144        }
145
146        void init() 
147        {
148                if (current_node_)
149                {
150                        std::string signature = read_attribute<std::string>("signature");
151                        int version = read_attribute<int>("version");
152
153                        TXML_LOG(boost::wformat(L" << siganture: %1%, version: %2%") % from_utf8(signature) % version);
154                }
155        }
156
157        template<typename T>
158        T read_attribute(const char* attribute_name, const char* fallback_name=0)
159        {
160                T type = T();
161
162                TXML_LOG(boost::wformat(L" << attribute_name: %1%") % from_utf8(attribute_name));
163
164                xml::element* e = current_node_->to_element();
165                if (!e) return type;
166
167                int result = e->query_value_attribute(attribute_name, &type);
168
169                if (result == xml::TIXML_NO_ATTRIBUTE && fallback_name != 0)
170                {
171                        TXML_LOG(boost::wformat(L" << -- fallback_name: %1%") % from_utf8(fallback_name));
172
173                        result = e->query_value_attribute(fallback_name, &type);
174                }
175
176                assert(result == xml::TIXML_SUCCESS);
177                TXML_LOG(boost::wformat(L" << -- value: %2%") % from_utf8(attribute_name) % type);
178               
179                return type;
180        }       
181
182        template<>
183        std::string read_attribute(const char* attribute_name, const char* fallback_name)
184        {
185                std::string type;
186
187                TXML_LOG(boost::wformat(L" << attribute_name: %1%") % from_utf8(attribute_name));
188
189                xml::element* e = current_node_->to_element();
190                if (!e) return type;
191
192                int result = e->query_value_attribute(attribute_name, &type);
193
194                if (result == xml::TIXML_NO_ATTRIBUTE && fallback_name != 0)
195                {
196                        TXML_LOG(boost::wformat(L" << -- fallback_name: %1%") % from_utf8(fallback_name));
197
198                        result = e->query_value_attribute(fallback_name, &type);
199                }
200
201                assert(result == xml::TIXML_SUCCESS);
202
203                TXML_LOG(boost::wformat(L" << -- value: %2%") % from_utf8(attribute_name) % from_utf8(type));
204
205                return type;
206        }       
207
208    bool load_start(const char* name)
209        {
210                if (name)
211                {
212                        TXML_LOG(boost::wformat(L" << load_start: %1%") % from_utf8(name));
213
214                        xml::node* failsafe_current = current_node_;
215
216                        boost::filesystem::path location(name);
217
218                        if (previous_child_node_ &&
219                                        previous_child_branch_ == location.parent_path())
220                        {
221                        //      TXML_LOG(boost::wformat(L" << previous_child: %1%") % previous_child_node_->to_element()->get_text());
222                                failsafe_current = previous_child_node_->next_sibling(location.filename());
223                                previous_child_node_ = 0;
224                               
225                                if (!failsafe_current) 
226                                        failsafe_current = current_node_->first_child(location.filename());;
227                        }
228                        else
229                        {
230                                foreach(std::string elem, location)
231                                {
232                                        TXML_LOG(boost::wformat(L" >> >> %1%") % from_utf8(elem));
233
234                                        if (elem == ".")
235                                        {}
236                                        else if (elem == "..")
237                                        {
238                                                failsafe_current = failsafe_current->parent();
239                                        }
240                                        else
241                                        {
242                                                failsafe_current = failsafe_current->first_child(elem);
243                                               
244                                                if (!failsafe_current) return false;
245                                        }
246                                }
247                        }
248
249                //      xml::node* n = new xml::element(leaf);                 
250
251                        if (!failsafe_current) 
252                                return false;
253                        else
254                        {
255                                current_node_ = failsafe_current;
256
257                                previous_child_branch_ = location.parent_path();
258                        }
259                }
260                return true;
261        }
262   
263    void load_end(const char *name)
264        {
265                if (name)
266                {
267                        TXML_LOG(boost::wformat(L" << load_end: %1%") % from_utf8(name));
268
269                        previous_child_node_ = current_node_;
270                }
271        }
272
273        // Anything not an attribute and not a name-value pair is an
274    // error and should be trapped here.
275    template<class T>
276    void load_override(T & t, BOOST_PFTO int)
277    {
278                BOOST_MPL_ASSERT((boost::serialization::is_wrapper<T>));
279
280        this->detail_common_iarchive::load_override(t, 0);
281        // If your program fails to compile here, its most likely due to
282        // not specifying an nvp wrapper around the variable to
283        // be serialized.
284    }
285
286        // special treatment for name-value pairs.
287    template<class T>
288    void load_override(const ::boost::serialization::nvp<T>& t, int)
289        {
290                node_stack_.push(current_node_);
291
292                if (t.name()) 
293                {
294                        TXML_LOG(boost::wformat(L" << loading: %1%") % t.name());
295                }
296
297                if (current_node_ && load_start(t.name()))
298                {
299                        this->detail_common_iarchive::load_override(t.value(), 0);
300                        load_end(t.name());
301                }
302                else
303                        TXML_LOG(boost::wformat(L" << load_aborted: %1%") % t.name());
304
305                current_node_ = node_stack_.top();
306                node_stack_.pop();
307    }
308
309        // specific overrides for attributes - not name value pairs so we
310    // want to trap them before the above "fall through"
311        void load_override(arc::class_id_optional_type&, int)
312        {}
313
314        void load_override(arc::object_id_type& t, int)
315        { 
316                if (boost_xml_compat_)
317                {
318                        std::string id = read_attribute<std::string>(arc::OBJECT_ID(), arc::OBJECT_REFERENCE());
319
320                        t = boost::lexical_cast<int>(id.substr(1));
321                }
322                else
323                        t = read_attribute<arc::object_id_type>(arc::OBJECT_ID(), arc::OBJECT_REFERENCE());             
324        }
325   
326        void load_override(arc::version_type& t, int)
327        { 
328                t = read_attribute<arc::version_type>(arc::VERSION());
329        }
330   
331        void load_override(arc::class_id_type& t, int)
332        { 
333                t = read_attribute<arc::class_id_type>(arc::CLASS_ID(), arc::CLASS_ID_REFERENCE());
334        }
335   
336        void load_override(arc::tracking_type& t, int)
337        { 
338                t = read_attribute<arc::tracking_type>(arc::TRACKING()); 
339        }
340
341        bool boost_xml_compat_;
342
343        xml::document xml_;
344
345        xml::node* current_node_;
346        xml::node* previous_child_node_;
347        boost::filesystem::path previous_child_branch_;
348
349        std::stack<xml::node*> node_stack_;
350
351        std::istream& is_;
352};
353
354} }
355
356//BOOST_SERIALIZATION_REGISTER_ARCHIVE(xml::txml_iarchive)
Note: See TracBrowser for help on using the repository browser.