~ubuntu-branches/ubuntu/saucy/merkaartor/saucy

« back to all changes in this revision

Viewing changes to include/builtin-ggl/ggl/extensions/gis/io/wkb/detail/parser.hpp

Tags: upstream-0.15.3+svn20934
ImportĀ upstreamĀ versionĀ 0.15.3+svn20934

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Generic Geometry Library
 
2
//
 
3
// Copyright Mateusz Loskot <mateusz@loskot.net> 2009
 
4
// Use, modification and distribution is subject to the Boost Software License,
 
5
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
 
6
// http://www.boost.org/LICENSE_1_0.txt)
 
7
 
 
8
#ifndef GGL_IO_WKB_DETAIL_PARSER_HPP
 
9
#define GGL_IO_WKB_DETAIL_PARSER_HPP
 
10
 
 
11
#include <cassert>
 
12
#include <cstddef>
 
13
#include <algorithm>
 
14
#include <iterator>
 
15
#include <limits>
 
16
 
 
17
#include <boost/cstdint.hpp>
 
18
#include <boost/type_traits/is_integral.hpp>
 
19
#include <boost/type_traits/is_same.hpp>
 
20
#include <boost/static_assert.hpp>
 
21
#include <boost/concept/requires.hpp>
 
22
 
 
23
#include <ggl/core/access.hpp>
 
24
#include <ggl/core/coordinate_dimension.hpp>
 
25
#include <ggl/core/coordinate_type.hpp>
 
26
#include <ggl/core/concepts/point_concept.hpp>
 
27
#include <ggl/core/exterior_ring.hpp>
 
28
#include <ggl/core/interior_rings.hpp>
 
29
#include <ggl/extensions/gis/io/wkb/detail/endian.hpp>
 
30
#include <ggl/extensions/gis/io/wkb/detail/ogc.hpp>
 
31
 
 
32
namespace ggl
 
33
{
 
34
 
 
35
#ifndef DOXYGEN_NO_IMPL
 
36
namespace detail { namespace wkb {
 
37
 
 
38
template <typename T>
 
39
struct value_parser
 
40
{
 
41
    typedef T value_type;
 
42
 
 
43
    template <typename Iterator>
 
44
    static bool parse(Iterator& it, Iterator end, T& value, byte_order_type::enum_t order)
 
45
    {
 
46
        // Very basic pre-conditions check on stream of bytes passed in
 
47
        BOOST_STATIC_ASSERT((
 
48
            boost::is_integral<typename std::iterator_traits<Iterator>::value_type>::value
 
49
        ));
 
50
        BOOST_STATIC_ASSERT((sizeof(boost::uint8_t) ==
 
51
            sizeof(typename std::iterator_traits<Iterator>::value_type)
 
52
        ));
 
53
 
 
54
        typedef typename std::iterator_traits<Iterator>::difference_type diff_type;
 
55
        diff_type const required_size = sizeof(T);
 
56
        if (it != end && std::distance(it, end) >= required_size)
 
57
        {
 
58
            typedef endian::endian_value<T> parsed_value_type;
 
59
            parsed_value_type parsed_value;
 
60
 
 
61
            // Decide on direcion of endianness translation, detault to native
 
62
            if (byte_order_type::xdr == order)
 
63
            {
 
64
                parsed_value.template load<endian::big_endian_tag>(it);
 
65
            }
 
66
            else if (byte_order_type::ndr == order)
 
67
            {
 
68
                parsed_value.template load<endian::little_endian_tag>(it);
 
69
            }
 
70
            else
 
71
            {
 
72
                parsed_value.template load<endian::native_endian_tag>(it);
 
73
            }
 
74
 
 
75
            value = parsed_value;
 
76
            std::advance(it, required_size);
 
77
            return true;
 
78
        }
 
79
 
 
80
        return false;
 
81
    }
 
82
};
 
83
 
 
84
struct byte_order_parser
 
85
{
 
86
    template <typename Iterator>
 
87
    static bool parse(Iterator& it, Iterator end, byte_order_type::enum_t& order)
 
88
    {
 
89
        boost::uint8_t value;
 
90
        if (value_parser<boost::uint8_t>::parse(it, end, value, byte_order_type::unknown))
 
91
        {
 
92
            if (byte_order_type::unknown > value)
 
93
            {
 
94
                order = byte_order_type::enum_t(value);
 
95
            }
 
96
            return true;
 
97
        }
 
98
        return false;
 
99
    }
 
100
};
 
101
 
 
102
struct geometry_type_parser
 
103
{
 
104
    template <typename Iterator>
 
105
    static bool parse(Iterator& it, Iterator end, geometry_type::enum_t& type,
 
106
        byte_order_type::enum_t order)
 
107
    {
 
108
        boost::uint32_t value;
 
109
        if (value_parser<boost::uint32_t>::parse(it, end, value, order))
 
110
        {
 
111
            // TODO: Refine the test when multi* geometries are supported
 
112
 
 
113
            boost::uint32_t id = value & 0xff;
 
114
            if (geometry_type::polygon >= id)
 
115
            {
 
116
                type = geometry_type::enum_t(id);
 
117
                return true;
 
118
            }
 
119
        }
 
120
        return false;
 
121
    }
 
122
};
 
123
 
 
124
template <typename P, int I, int N>
 
125
struct parsing_assigner
 
126
{
 
127
    template <typename Iterator>
 
128
    static void run(Iterator& it, Iterator end, P& point, byte_order_type::enum_t order)
 
129
    {
 
130
        typedef typename coordinate_type<P>::type coordinate_type;
 
131
 
 
132
        // coordinate type in WKB is always double
 
133
        double value(0);
 
134
        if (value_parser<double>::parse(it, end, value, order))
 
135
        {
 
136
            // actual coordinate type of point may be different
 
137
            set<I>(point, static_cast<coordinate_type>(value));
 
138
        }
 
139
        else
 
140
        {
 
141
            // TODO: mloskot - Report premature termination at coordinate level
 
142
            //throw failed to read coordinate value
 
143
 
 
144
            // default initialized value as fallback
 
145
            set<I>(point, coordinate_type());
 
146
        }
 
147
        parsing_assigner<P, I+1, N>::run(it, end, point, order);
 
148
    }
 
149
};
 
150
 
 
151
template <typename P, int N>
 
152
struct parsing_assigner<P, N, N>
 
153
{
 
154
    template <typename Iterator>
 
155
    static void run(Iterator& it, Iterator end, P& point, byte_order_type::enum_t order)
 
156
    {
 
157
        // terminate
 
158
    }
 
159
};
 
160
 
 
161
template <typename P>
 
162
struct point_parser
 
163
{
 
164
    template <typename Iterator>
 
165
    static bool parse(Iterator& it, Iterator end, P& point, byte_order_type::enum_t order)
 
166
    {
 
167
        // TODO: mloskot - Add assert on point dimension, 2d only
 
168
 
 
169
        geometry_type::enum_t type;
 
170
        if (geometry_type_parser::parse(it, end, type, order))
 
171
        {
 
172
            if (geometry_type::point == type && it != end)
 
173
            {
 
174
                parsing_assigner<P, 0, dimension<P>::value>::run(it, end, point, order);
 
175
            }
 
176
            return true;
 
177
        }
 
178
        return false;
 
179
    }
 
180
 
 
181
private:
 
182
    BOOST_CONCEPT_ASSERT((concept::Point<P>));
 
183
};
 
184
 
 
185
template <typename C>
 
186
struct point_container_parser
 
187
{
 
188
    template <typename Iterator>
 
189
    static bool parse(Iterator& it, Iterator end, C& container, byte_order_type::enum_t order)
 
190
    {
 
191
        typedef typename point_type<C>::type point_type;
 
192
 
 
193
        boost::uint32_t num_points(0);
 
194
        if (!value_parser<boost::uint32_t>::parse(it, end, num_points, order))
 
195
        {
 
196
            return false;
 
197
        }
 
198
 
 
199
        typedef typename std::iterator_traits<Iterator>::difference_type size_type;
 
200
        assert(num_points <= boost::uint32_t( (std::numeric_limits<size_type>::max)() ) );
 
201
 
 
202
        size_type const container_size = static_cast<size_type>(num_points);
 
203
        size_type const point_size = dimension<point_type>::value * sizeof(double);
 
204
 
 
205
        if (std::distance(it, end) >= (container_size * point_size))
 
206
        {
 
207
            point_type point_buffer;
 
208
            std::back_insert_iterator<C> output(std::back_inserter(container));
 
209
 
 
210
            // Read coordinates into point and append point to line (ring)
 
211
            size_type points_parsed = 0;
 
212
            while (points_parsed < container_size && it != end)
 
213
            {
 
214
                parsing_assigner<point_type, 0, dimension<point_type>::value>::run(it, end, point_buffer, order);
 
215
                output = point_buffer;
 
216
                ++output;
 
217
                ++points_parsed;
 
218
            }
 
219
 
 
220
            if (container_size != points_parsed)
 
221
            {
 
222
                return false;
 
223
            }
 
224
        }
 
225
 
 
226
        return true;
 
227
    }
 
228
};
 
229
 
 
230
template <typename L>
 
231
struct linestring_parser
 
232
{
 
233
    template <typename Iterator>
 
234
    static bool parse(Iterator& it, Iterator end, L& linestring, byte_order_type::enum_t order)
 
235
    {
 
236
        typedef typename point_type<L>::type point_type;
 
237
 
 
238
        geometry_type::enum_t type;
 
239
        if (!geometry_type_parser::parse(it, end, type, order))
 
240
        {
 
241
            return false;
 
242
        }
 
243
 
 
244
        if (geometry_type::linestring != type)
 
245
        {
 
246
            return false;
 
247
        }
 
248
 
 
249
        assert(it != end);
 
250
        return point_container_parser<L>::parse(it, end, linestring, order);
 
251
    }
 
252
};
 
253
 
 
254
template <typename Polygon>
 
255
struct polygon_parser
 
256
{
 
257
    template <typename Iterator>
 
258
    static bool parse(Iterator& it, Iterator end, Polygon& polygon, byte_order_type::enum_t order)
 
259
    {
 
260
        geometry_type::enum_t type;
 
261
        if (!geometry_type_parser::parse(it, end, type, order))
 
262
        {
 
263
            return false;
 
264
        }
 
265
 
 
266
        boost::uint32_t num_rings(0);
 
267
        if (geometry_type::polygon != type ||
 
268
            !value_parser<boost::uint32_t>::parse(it, end, num_rings, order))
 
269
        {
 
270
            return false;
 
271
        }
 
272
 
 
273
        typedef typename ring_type<Polygon>::type ring_type;
 
274
 
 
275
        std::size_t rings_parsed = 0;
 
276
        while (rings_parsed < num_rings && it != end) //while (rings_parsed < num_rings && it != end)
 
277
        {
 
278
            if (0 == rings_parsed)
 
279
            {
 
280
                ring_type& ring0 = exterior_ring(polygon);
 
281
                if (!point_container_parser<ring_type>::parse(it, end, ring0, order))
 
282
                {
 
283
                    return false;
 
284
                }
 
285
            }
 
286
            else
 
287
            {
 
288
                interior_rings(polygon).resize(rings_parsed);
 
289
                ring_type& ringN = interior_rings(polygon).back();
 
290
                if (!point_container_parser<ring_type>::parse(it, end, ringN, order))
 
291
                {
 
292
                    return false;
 
293
                }
 
294
            }
 
295
            ++rings_parsed;
 
296
        }
 
297
 
 
298
        if (num_rings != rings_parsed)
 
299
        {
 
300
            return false;
 
301
        }
 
302
 
 
303
        return true;
 
304
    }
 
305
};
 
306
 
 
307
}}} // namespace ggl::detail::wkb
 
308
#endif // DOXYGEN_NO_IMPL
 
309
 
 
310
#endif // GGL_IO_WKB_DETAIL_PARSER_HPP