source: trunk/src/global/txml_oarchive.hpp @ 780

Revision 780, 9.3 KB checked in by Eoin, 10 years ago (diff)

Archive supports Boost .40. Some 64bit casts added.

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
11//#include <boost/archive/xml_oarchive.hpp>
12
13#pragma warning (push)
14#pragma warning (disable : 4099)
15#pragma warning (disable : 4267)
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_oprimitive.ipp>
22#       include <boost/archive/impl/xml_oarchive_impl.ipp>
23#       include <boost/archive/impl/basic_xml_oarchive.ipp>
24#pragma warning (pop)
25
26#include "global/string_conv.hpp"
27#include "txml.hpp"
28
29#define foreach BOOST_FOREACH
30
31#ifndef TXML_ARCHIVE_LOGGING
32#       define TXML_LOG(s)
33#else
34#       include "../halEvent.hpp"
35#       define TXML_LOG(msg) \
36        hal::event_log().post(boost::shared_ptr<hal::EventDetail>( \
37                        new hal::EventMsg(msg, hal::event_logger::xml_dev)))
38#endif
39
40namespace 
41{
42
43struct o_stringstream_holder
44{
45        std::stringstream stream_ ;
46};
47
48}
49
50namespace hal { namespace xml
51{
52
53namespace serial = boost::serialization;
54namespace arc = boost::archive;
55
56class txml_oarchive : 
57        private o_stringstream_holder,
58        public arc::basic_text_oprimitive<std::ostream>,
59        public arc::detail::common_oarchive<txml_oarchive>
60{
61        typedef arc::detail::common_oarchive<txml_oarchive> detail_common_oarchive;
62
63public:
64
65    txml_oarchive(std::ostream& os, unsigned int flags = 0) :
66                basic_text_oprimitive<std::ostream>(stream_, 0 != (flags & arc::no_codecvt)),
67                common_oarchive(flags),
68                os_(os),
69                current_node_(0)
70    {
71                xml_.link_end_child(new xml::declaration("1.0", "", "")); 
72               
73                if (!current_node_)
74                {
75                        current_node_ = new xml::element("serial");
76                        xml_.link_end_child(current_node_);
77                }
78
79                if(0 == (flags & arc::no_header))
80                        init();
81        }
82
83    ~txml_oarchive()
84        {
85#ifdef TXML_ARCHIVE_LOGGING
86                xml_.save_file("debug.xml");
87#endif
88                os_ << xml_;
89        }
90
91    template<class T>
92    void save(const T & t)
93        {
94                basic_text_oprimitive<std::ostream>::save(t);
95        }
96           
97        void save(const char *  s)
98        {
99                typedef boost::archive::iterators::xml_escape<
100                        const char * 
101                > xml_escape_translator;
102                std::copy(
103                        xml_escape_translator(BOOST_MAKE_PFTO_WRAPPER(s)),
104                        xml_escape_translator(BOOST_MAKE_PFTO_WRAPPER(s + std::strlen(s))), 
105                        boost::archive::iterators::ostream_iterator<char>(os)
106                );
107        }
108
109    #ifndef BOOST_NO_INTRINSIC_WCHAR_T
110    void save(const wchar_t* ws)
111        {
112                arc::save_iterator(os, ws, ws + std::wcslen(ws));
113        }
114    #endif
115
116    void save(const std::string &s)
117        {
118        //  at least one library doesn't typedef value_type for strings
119        //  so rather than using string directly make a pointer iterator out of it
120                typedef boost::archive::iterators::xml_escape<
121                        const char * 
122                > xml_escape_translator;
123                std::copy(
124                        xml_escape_translator(BOOST_MAKE_PFTO_WRAPPER(s.data())),
125                        xml_escape_translator(BOOST_MAKE_PFTO_WRAPPER(s.data()+ s.size())), 
126                        boost::archive::iterators::ostream_iterator<char>(os)
127                );
128        }
129
130    #ifndef BOOST_NO_STD_WSTRING
131    void save(const std::wstring &ws)
132        {
133        //  at least one library doesn't typedef value_type for strings
134        //  so rather than using string directly make a pointer iterator out of it
135        //    save_iterator(os, ws.data(), ws.data() + std::wcslen(ws.data()));
136        //              arc::save_iterator(os, ws.data(), ws.data() + ws.size());
137                        os << to_utf8(ws);
138        }
139    #endif
140
141    BOOST_ARCHIVE_DECL(BOOST_PP_EMPTY()) 
142
143    void save_binary(const void *address, std::size_t count)
144        {
145        this->end_preamble();
146        this->basic_text_oprimitive<std::ostream>::save_binary(
147            address, 
148            count
149        );
150        //this->indent_next = true;
151    }
152
153    void write_attribute(
154        const char *attribute_name,
155        int t,
156        const char *conjunction = 0)
157        { 
158                assert(attribute_name);
159
160                xml::element* e = dynamic_cast<xml::element*>(current_node_);
161
162                if (true || !conjunction)
163                {
164                        e->set_attribute(attribute_name, t);
165
166                        TXML_LOG(boost::wformat(L" >> write_attribute: %1%, t:%2%") % attribute_name % t);
167                }
168                else
169                {
170                        std::string attr = conjunction;
171                        attr += boost::lexical_cast<std::string>(t);
172                        e->set_attribute(attribute_name, attr);
173                       
174                        TXML_LOG(boost::wformat(L" >> write_attribute: %1%, t:%2%") % attribute_name % from_utf8(attr));
175                }
176        }       
177
178    void write_attribute(const char *attribute_name, const char *key)
179        {
180                assert(attribute_name);
181                assert(key);
182
183                xml::element* e = dynamic_cast<xml::element*>(current_node_);
184                e->set_attribute(attribute_name, key);
185
186                TXML_LOG(boost::wformat(L" >> write_attribute: %1%, key:%2%") % attribute_name % key);
187        }
188
189    void save_start(const char *name)
190        {
191                if (name)
192                {
193                        TXML_LOG(boost::wformat(L" >> save_start: %1%") % name);
194                        node_stack_.push(current_node_);
195
196                        boost::filesystem::path branch(name);
197
198                        std::string leaf = branch.filename();
199                        branch = branch.parent_path();
200
201                        foreach(std::string elem, branch)
202                        {
203                                TXML_LOG(boost::wformat(L" >> >> %1%") % from_utf8(elem));
204
205                                if (elem == ".")
206                                {}
207                                else if (elem == "..")
208                                {
209                                        current_node_ = current_node_->parent();
210                                }
211                                else
212                                {
213                                        xml::node* child_node = current_node_->first_child(elem);
214                                       
215                                        if (!child_node)
216                                        {
217                                                child_node = new xml::element(elem);
218                                                current_node_->link_end_child(child_node);
219                                        }
220                                       
221                                        current_node_ = child_node;
222                                }
223                        }
224
225                        xml::node* n = new xml::element(leaf);
226                        current_node_ = current_node_->link_end_child(n);
227
228                        stream_.str("");
229                }
230        }
231   
232    void save_end(const char *name)
233        {
234                if (name)
235                {
236                        assert(!node_stack_.empty());
237
238                        std::string s = stream_.str();
239
240                        TXML_LOG(boost::wformat(L" >> stringstream: %1%") % from_utf8(s));
241                        xml::text* t = new xml::text(s);
242
243                        current_node_->link_end_child(t);
244
245                        stream_.str("");
246                        stream_ << std::noboolalpha;
247
248                        TXML_LOG(boost::wformat(L" >> save_end: %1%") % name);
249
250                        current_node_ = node_stack_.top();
251                        node_stack_.pop();
252                }               
253        }
254
255        // Anything not an attribute and not a name-value pair is an
256    // error and should be trapped here.
257    template<class T>
258    void save_override(T & t, BOOST_PFTO int)
259    {
260        BOOST_MPL_ASSERT((::boost::serialization::is_wrapper<T>));
261
262        this->detail_common_oarchive::save_override(t, 0);
263        // If your program fails to compile here, its most likely due to
264        // not specifying an nvp wrapper around the variable to
265        // be serialized.
266    }
267
268   // special treatment for name-value pairs.
269
270    template<class T>
271    void save_override( const ::boost::serialization::nvp<T> & t, int)
272    {
273                save_start(t.name());
274                this->detail_common_oarchive::save_override(t.const_value(), 0);
275        save_end(t.name());
276    }
277
278        void init()
279        {
280                // xml header
281#if BOOST_VERSION < 103700
282                write_attribute("signature", arc::ARCHIVE_SIGNATURE());
283                write_attribute("version", arc::ARCHIVE_VERSION());
284#else
285                write_attribute("signature", arc::BOOST_ARCHIVE_SIGNATURE());
286                write_attribute("version", arc::BOOST_ARCHIVE_VERSION());
287#endif
288        }
289
290        // specific overrides for attributes - not name value pairs so we
291    // want to trap them before the above "fall through"
292
293        void save_override(const arc::object_id_type & t, int i)
294        { 
295#if BOOST_VERSION < 103700
296                write_attribute(arc::OBJECT_ID(), t);
297#else
298                write_attribute(arc::BOOST_ARCHIVE_XML_OBJECT_ID(), t);
299#endif
300        }
301
302    void save_override(const arc::object_reference_type & t, int)
303        {
304#if BOOST_VERSION < 103700
305                write_attribute(arc::OBJECT_REFERENCE(), t);
306#else
307                write_attribute(arc::BOOST_ARCHIVE_XML_OBJECT_REFERENCE(), t);
308#endif
309        }
310   
311        void save_override(const arc::version_type & t, int i)
312        { 
313#if BOOST_VERSION < 103700
314                write_attribute(arc::VERSION(), t);
315#else
316                write_attribute(arc::BOOST_ARCHIVE_XML_VERSION(), t);
317#endif
318        }
319   
320        void save_override(const arc::class_id_type & t, int i)
321        { 
322#if BOOST_VERSION < 103700
323                write_attribute(arc::CLASS_ID(), t);
324#else
325                write_attribute(arc::BOOST_ARCHIVE_XML_CLASS_ID(), t);
326#endif
327        }
328   
329        void save_override(const arc::class_id_optional_type & t, int i)
330        { 
331#if BOOST_VERSION < 103700
332                write_attribute(arc::CLASS_ID(), t); 
333#else
334                write_attribute(arc::BOOST_ARCHIVE_XML_CLASS_ID(), t); 
335#endif
336        }
337   
338        void save_override(const arc::class_id_reference_type & t, int i)
339        { 
340#if BOOST_VERSION < 103700
341                write_attribute(arc::CLASS_ID_REFERENCE(), t); 
342#else
343                write_attribute(arc::BOOST_ARCHIVE_XML_CLASS_ID_REFERENCE(), t); 
344#endif
345        }
346   
347        void save_override(const arc::class_name_type & t, int i)
348        { 
349                const char * key = t;
350                if(NULL == key)
351                        return;
352
353#if BOOST_VERSION < 103700
354                write_attribute(arc::CLASS_NAME(), key);
355#else
356                write_attribute(arc::BOOST_ARCHIVE_XML_CLASS_NAME(), key);
357#endif
358        }
359   
360        void save_override(const arc::tracking_type & t, int i)
361        { 
362#if BOOST_VERSION < 103700
363                write_attribute(arc::TRACKING(), t.t); 
364#else
365                write_attribute(arc::BOOST_ARCHIVE_XML_TRACKING(), t.t); 
366#endif
367        }
368
369        xml::document xml_;
370        xml::node* current_node_;
371        std::stack<xml::node*> node_stack_;
372
373        std::ostream& os_;
374};
375
376} }
377
378//BOOST_SERIALIZATION_REGISTER_ARCHIVE(xml::txml_oarchive)
Note: See TracBrowser for help on using the repository browser.