@@ -43,49 +43,66 @@ enum wkb_byte_order_type_t : uint8_t
4343#endif
4444};
4545
46+ template <typename T>
47+ static void str_push (std::string *str, T data)
48+ {
49+ assert (str);
50+ str->append (reinterpret_cast <char const *const >(&data), sizeof (T));
51+ }
52+
4653/* *
47- * Writer for EWKB data suitable for postgres .
54+ * Add a EWKB header to the string .
4855 *
49- * Code has been largely derived from osmium::geom::WKBFactoryImpl.
56+ * \pre \code str != nullptr \endcode
5057 */
51- class writer_t
58+ inline std::size_t write_header (std::string *str, geometry_type type,
59+ uint32_t srid)
5260{
61+ assert (str);
5362
54- std::string m_data;
55- int m_srid;
63+ str_push (str, Endian);
64+ str_push (str, type | wkb_srid);
65+ str_push (str, srid);
5666
57- size_t m_geometry_size_offset = 0 ;
58- size_t m_multigeometry_size_offset = 0 ;
59- size_t m_ring_size_offset = 0 ;
67+ return str->size ();
68+ }
6069
61- size_t header (std::string &str, geometry_type type, bool add_length) const
62- {
63- str_push (str, Endian);
64- str_push (str, type | wkb_srid);
65- str_push (str, m_srid);
70+ /* *
71+ * Add a EWKB header to the string and add a dummy placeholder length of 0.
72+ * This can later be replaced by the real length.
73+ *
74+ * \pre \code str != nullptr \endcode
75+ */
76+ inline std::size_t write_header_with_length (std::string *str,
77+ geometry_type type, uint32_t srid)
78+ {
79+ auto const offset = write_header (str, type, srid);
80+ str_push (str, static_cast <uint32_t >(0 ));
81+ return offset;
82+ }
6683
67- std::size_t const offset = str.size ();
68- if (add_length) {
69- str_push (str, static_cast <uint32_t >(0 ));
70- }
71- return offset;
72- }
84+ // / Create EWKB Point geometry.
85+ inline std::string create_point (double x, double y, uint32_t srid = 4326 )
86+ {
87+ std::string data;
88+ data.reserve (25 ); // Point geometries are always 25 bytes
7389
74- void set_size (size_t const offset, size_t const size)
75- {
76- uint32_t s = static_cast <uint32_t >(size);
77- std::copy_n (reinterpret_cast <char *>(&s), sizeof (uint32_t ),
78- &m_data[offset]);
79- }
90+ write_header (&data, wkb_point, srid);
91+ str_push (&data, x);
92+ str_push (&data, y);
8093
81- template <typename T>
82- inline static void str_push (std::string &str, T data)
83- {
84- str.append (reinterpret_cast <char const *>(&data), sizeof (T));
85- }
94+ return data;
95+ }
8696
97+ /* *
98+ * Writer for EWKB data suitable for postgres.
99+ *
100+ * Code has been largely derived from osmium::geom::WKBFactoryImpl.
101+ */
102+ class writer_t
103+ {
87104public:
88- explicit writer_t (int srid) : m_srid(srid) {}
105+ explicit writer_t (uint32_t srid) : m_srid(srid) {}
89106
90107 void add_sub_geometry (std::string const &part)
91108 {
@@ -96,31 +113,27 @@ class writer_t
96113 void add_location (osmium::geom::Coordinates const &xy)
97114 {
98115 assert (!m_data.empty ());
99- str_push (m_data, xy.x );
100- str_push (m_data, xy.y );
116+ str_push (& m_data, xy.x );
117+ str_push (& m_data, xy.y );
101118 }
102119
103120 /* Point */
104121
105122 std::string make_point (osmium::geom::Coordinates const &xy) const
106123 {
107- std::string data;
108- header (data, wkb_point, false );
109- str_push (data, xy.x );
110- str_push (data, xy.y );
111-
112- return data;
124+ return create_point (xy.x , xy.y , m_srid);
113125 }
114126
115127 /* LineString */
116128
117129 void linestring_start ()
118130 {
119131 assert (m_data.empty ());
120- m_geometry_size_offset = header (m_data, wkb_line, true );
132+ m_geometry_size_offset =
133+ write_header_with_length (&m_data, wkb_line, m_srid);
121134 }
122135
123- std::string linestring_finish (size_t num_points)
136+ std::string linestring_finish (std:: size_t num_points)
124137 {
125138 set_size (m_geometry_size_offset, num_points);
126139 std::string data;
@@ -136,10 +149,11 @@ class writer_t
136149 void multilinestring_start ()
137150 {
138151 assert (m_data.empty ());
139- m_multigeometry_size_offset = header (m_data, wkb_multi_line, true );
152+ m_multigeometry_size_offset =
153+ write_header_with_length (&m_data, wkb_multi_line, m_srid);
140154 }
141155
142- std::string multilinestring_finish (size_t num_lines)
156+ std::string multilinestring_finish (std:: size_t num_lines)
143157 {
144158 set_size (m_multigeometry_size_offset, num_lines);
145159 std::string data;
@@ -155,21 +169,22 @@ class writer_t
155169 void polygon_start ()
156170 {
157171 assert (m_data.empty ());
158- m_geometry_size_offset = header (m_data, wkb_polygon, true );
172+ m_geometry_size_offset =
173+ write_header_with_length (&m_data, wkb_polygon, m_srid);
159174 }
160175
161176 void polygon_ring_start ()
162177 {
163178 m_ring_size_offset = m_data.size ();
164- str_push (m_data, static_cast <uint32_t >(0 ));
179+ str_push (& m_data, static_cast <uint32_t >(0 ));
165180 }
166181
167- void polygon_ring_finish (size_t num_points)
182+ void polygon_ring_finish (std:: size_t num_points)
168183 {
169184 set_size (m_ring_size_offset, num_points);
170185 }
171186
172- std::string polygon_finish (size_t num_rings)
187+ std::string polygon_finish (std:: size_t num_rings)
173188 {
174189 set_size (m_geometry_size_offset, num_rings);
175190 std::string data;
@@ -185,10 +200,11 @@ class writer_t
185200 void multipolygon_start ()
186201 {
187202 assert (m_data.empty ());
188- m_multigeometry_size_offset = header (m_data, wkb_multi_polygon, true );
203+ m_multigeometry_size_offset =
204+ write_header_with_length (&m_data, wkb_multi_polygon, m_srid);
189205 }
190206
191- std::string multipolygon_finish (size_t num_polygons)
207+ std::string multipolygon_finish (std:: size_t num_polygons)
192208 {
193209 set_size (m_multigeometry_size_offset, num_polygons);
194210 std::string data;
@@ -198,7 +214,24 @@ class writer_t
198214
199215 return data;
200216 }
201- };
217+
218+ private:
219+ void set_size (std::size_t offset, std::size_t size)
220+ {
221+ assert (m_data.size () >= offset + sizeof (uint32_t ));
222+ auto const s = static_cast <uint32_t >(size);
223+ std::memcpy (&m_data[offset], reinterpret_cast <char const *>(&s),
224+ sizeof (uint32_t ));
225+ }
226+
227+ std::string m_data;
228+
229+ std::size_t m_geometry_size_offset = 0 ;
230+ std::size_t m_multigeometry_size_offset = 0 ;
231+ std::size_t m_ring_size_offset = 0 ;
232+
233+ uint32_t m_srid;
234+ }; // class writer_t
202235
203236/* *
204237 * Class that allows to iterate over the elements of a ewkb geometry.
@@ -245,20 +278,20 @@ class parser_t
245278 return out;
246279 }
247280
248- explicit parser_t (char const *wkb) : m_wkb(wkb), m_pos(0 ) {}
249- explicit parser_t (std::string const &wkb) : m_wkb(wkb.c_str()), m_pos(0 ) {}
281+ explicit parser_t (std::string const &wkb) noexcept : m_wkb(&wkb) {}
250282
251- size_t save_pos () const { return m_pos; }
252- void rewind (size_t pos) { m_pos = pos; }
283+ std::size_t save_pos () const noexcept { return m_pos; }
253284
254- int read_header ()
285+ void rewind (std::size_t pos) noexcept { m_pos = pos; }
286+
287+ uint32_t read_header ()
255288 {
256- m_pos += sizeof (uint8_t ); // skip endianess
289+ m_pos += sizeof (uint8_t ); // skip endianess marker
257290
258291 auto const type = read_data<uint32_t >();
259292
260293 if (type & wkb_srid) {
261- m_pos += sizeof (int ); // skip srid
294+ m_pos += sizeof (uint32_t ); // skip SRID
262295 }
263296
264297 return type & 0xffU ;
@@ -274,7 +307,12 @@ class parser_t
274307 return osmium::geom::Coordinates{x, y};
275308 }
276309
277- void skip_points (size_t num) { m_pos += sizeof (double ) * 2 * num; }
310+ void skip_points (std::size_t num)
311+ {
312+ auto const length = sizeof (double ) * 2 * num;
313+ check_available (length);
314+ m_pos += length;
315+ }
278316
279317 template <typename PROJ>
280318 double get_area (PROJ *proj = nullptr )
@@ -355,18 +393,27 @@ class parser_t
355393 return std::abs (total) * 0.5 ;
356394 }
357395
396+ void check_available (std::size_t length)
397+ {
398+ if (m_pos + length > m_wkb->size ()) {
399+ throw std::runtime_error{" Invalid EWKB geometry found" };
400+ }
401+ }
402+
358403 template <typename T>
359404 T read_data ()
360405 {
406+ check_available (sizeof (T));
407+
361408 T data;
362- memcpy (&data, m_wkb + m_pos, sizeof (T));
409+ std:: memcpy (&data, m_wkb-> data () + m_pos, sizeof (T));
363410 m_pos += sizeof (T);
364411
365412 return data;
366413 }
367414
368- char const *m_wkb;
369- size_t m_pos;
415+ std::string const *m_wkb;
416+ std:: size_t m_pos = 0 ;
370417};
371418
372419} // namespace ewkb
0 commit comments