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

Revision 647, 9.0 KB checked in by Eoin, 11 years ago (diff)
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                init();
78        }
79
80    ~txml_iarchive()
81        {}
82           
83        template<class T>
84    void load(T& t)
85        {
86                std::string tstring = current_node_->first_child()->value_str();
87
88                TXML_LOG(boost::wformat(L" << basic_text_iprimitive: %1%") % from_utf8(tstring));
89
90                stream_ << tstring;
91        basic_text_iprimitive<std::istream>::load(t);
92
93                stream_.clear();
94                stream_ << std::noboolalpha;
95    }
96
97/*      void load(char* s)
98        {
99                std::string tstring = current_node_->first_child()->value_str();
100
101                std::memcpy(s, tstring.data(), tstring.size());
102                s[tstring.size()] = 0;
103                TXML_LOG(boost::wformat(L" << load char*: %1%") % from_utf8(tstring));
104        }
105
106        void load(wchar_t* t)
107        {
108                TXML_LOG(boost::wformat(L" << load wchar_t*: %1%") % from_utf8(current_node_->first_child()->value_str());
109        }
110*/
111        void load(std::string& s) 
112        {               
113                if (xml::node* child = current_node_->first_child())
114                        s = child->value_str();
115                else
116                        s = "";
117
118                TXML_LOG(boost::wformat(L" << load string: %1%") % from_utf8(s));
119        }
120
121        void load(std::wstring& ws) 
122        {
123                if (xml::node* child = current_node_->first_child())
124                        ws = from_utf8(child->value_str());
125                else
126                        ws = L"";
127
128                TXML_LOG(boost::wformat(L" << load wstring: %1%") % ws);
129        }
130
131        void load_override(arc::class_name_type& t, int) 
132        {   
133                std::string tstring = current_node_->first_child()->value_str();
134
135                TXML_LOG(boost::wformat(L" << load class_name_type: %1%") % from_utf8(tstring));
136
137                char * tptr = t;
138                std::memcpy(tptr, tstring.data(), tstring.size());
139                tptr[tstring.size()] = '\0';
140        }
141
142        void init() 
143        {
144                if (current_node_)
145                {
146                        boost_xml_compat_ = (current_node_->value_str() == "boost_serialization");
147                        TXML_LOG(boost::wformat(L" << boost_serialization compatibility %1%") % (boost_xml_compat_ ? "on" : "off"));
148
149                        std::string signature = read_attribute<std::string>("signature");
150                        int version = read_attribute<int>("version");
151
152                        TXML_LOG(boost::wformat(L" << siganture: %1%, version: %2%") % from_utf8(signature) % version);
153                }
154        }
155
156        template<typename T>
157        T read_attribute(const char* attribute_name, const char* fallback_name=0)
158        {
159                T type = T();
160
161                TXML_LOG(boost::wformat(L" << attribute_name: %1%") % from_utf8(attribute_name));
162
163                xml::element* e = current_node_->to_element();
164                if (!e) return type;
165
166                int result = e->query_value_attribute(attribute_name, &type);
167
168                if (result == xml::TIXML_NO_ATTRIBUTE && fallback_name != 0)
169                {
170                        TXML_LOG(boost::wformat(L" << -- fallback_name: %1%") % from_utf8(fallback_name));
171
172                        result = e->query_value_attribute(fallback_name, &type);
173                }
174
175                assert(result == xml::TIXML_SUCCESS);
176                TXML_LOG(boost::wformat(L" << -- value: %2%") % from_utf8(attribute_name) % type);
177               
178                return type;
179        }       
180
181        template<>
182        std::string read_attribute(const char* attribute_name, const char* fallback_name)
183        {
184                std::string type;
185
186                TXML_LOG(boost::wformat(L" << attribute_name: %1%") % from_utf8(attribute_name));
187
188                xml::element* e = current_node_->to_element();
189                if (!e) return type;
190
191                int result = e->query_value_attribute(attribute_name, &type);
192
193                if (result == xml::TIXML_NO_ATTRIBUTE && fallback_name != 0)
194                {
195                        TXML_LOG(boost::wformat(L" << -- fallback_name: %1%") % from_utf8(fallback_name));
196
197                        result = e->query_value_attribute(fallback_name, &type);
198                }
199
200                assert(result == xml::TIXML_SUCCESS);
201
202                TXML_LOG(boost::wformat(L" << -- value: %2%") % from_utf8(attribute_name) % from_utf8(type));
203
204                return type;
205        }       
206
207    bool load_start(const char* name)
208        {
209                if (name)
210                {
211                        TXML_LOG(boost::wformat(L" << load_start: %1%") % from_utf8(name));
212
213                        xml::node* failsafe_current = current_node_;
214
215                        boost::filesystem::path location(name);
216
217                        if (previous_child_node_ &&
218                                        previous_child_branch_ == location.parent_path())
219                        {
220                        //      TXML_LOG(boost::wformat(L" << previous_child: %1%") % previous_child_node_->to_element()->get_text());
221                                failsafe_current = previous_child_node_->next_sibling(location.filename());
222                                previous_child_node_ = 0;
223                               
224                                if (!failsafe_current) 
225                                        failsafe_current = current_node_->first_child(location.filename());;
226                        }
227                        else
228                        {
229                                foreach(std::string elem, location)
230                                {
231                                        TXML_LOG(boost::wformat(L" >> >> %1%") % from_utf8(elem));
232
233                                        if (elem == ".")
234                                        {}
235                                        else if (elem == "..")
236                                        {
237                                                failsafe_current = failsafe_current->parent();
238                                        }
239                                        else
240                                        {
241                                                failsafe_current = failsafe_current->first_child(elem);
242                                               
243                                                if (!failsafe_current) return false;
244                                        }
245                                }
246                        }
247
248                //      xml::node* n = new xml::element(leaf);                 
249
250                        if (!failsafe_current) 
251                                return false;
252                        else
253                        {
254                                current_node_ = failsafe_current;
255
256                                previous_child_branch_ = location.parent_path();
257                        }
258                }
259                return true;
260        }
261   
262    void load_end(const char *name)
263        {
264                if (name)
265                {
266                        TXML_LOG(boost::wformat(L" << load_end: %1%") % from_utf8(name));
267
268                        previous_child_node_ = current_node_;
269                }
270        }
271
272        // Anything not an attribute and not a name-value pair is an
273    // error and should be trapped here.
274    template<class T>
275    void load_override(T & t, BOOST_PFTO int)
276    {
277                BOOST_MPL_ASSERT((boost::serialization::is_wrapper<T>));
278
279        this->detail_common_iarchive::load_override(t, 0);
280        // If your program fails to compile here, its most likely due to
281        // not specifying an nvp wrapper around the variable to
282        // be serialized.
283    }
284
285        // special treatment for name-value pairs.
286    template<class T>
287    void load_override(const ::boost::serialization::nvp<T>& t, int)
288        {
289                node_stack_.push(current_node_);
290
291                if (t.name()) 
292                {
293                        TXML_LOG(boost::wformat(L" << loading: %1%") % t.name());
294                }
295
296                if (current_node_ && load_start(t.name()))
297                {
298                        this->detail_common_iarchive::load_override(t.value(), 0);
299                        load_end(t.name());
300                }
301                else
302                        TXML_LOG(boost::wformat(L" << load_aborted: %1%") % t.name());
303
304                current_node_ = node_stack_.top();
305                node_stack_.pop();
306    }
307
308        // specific overrides for attributes - not name value pairs so we
309    // want to trap them before the above "fall through"
310        void load_override(arc::class_id_optional_type&, int)
311        {}
312
313        void load_override(arc::object_id_type& t, int)
314        { 
315                if (boost_xml_compat_)
316                {
317                        std::string id = read_attribute<std::string>(arc::OBJECT_ID(), arc::OBJECT_REFERENCE());
318
319                        t = boost::lexical_cast<int>(id.substr(1));
320                }
321                else
322                        t = read_attribute<arc::object_id_type>(arc::OBJECT_ID(), arc::OBJECT_REFERENCE());             
323        }
324   
325        void load_override(arc::version_type& t, int)
326        { 
327                t = read_attribute<arc::version_type>(arc::VERSION());
328        }
329   
330        void load_override(arc::class_id_type& t, int)
331        { 
332                t = read_attribute<arc::class_id_type>(arc::CLASS_ID(), arc::CLASS_ID_REFERENCE());
333        }
334   
335        void load_override(arc::tracking_type& t, int)
336        { 
337                t = read_attribute<arc::tracking_type>(arc::TRACKING()); 
338        }
339
340        bool boost_xml_compat_;
341
342        xml::document xml_;
343
344        xml::node* current_node_;
345        xml::node* previous_child_node_;
346        boost::filesystem::path previous_child_branch_;
347
348        std::stack<xml::node*> node_stack_;
349
350        std::istream& is_;
351};
352
353} }
354
355//BOOST_SERIALIZATION_REGISTER_ARCHIVE(xml::txml_iarchive)
Note: See TracBrowser for help on using the repository browser.