1 /*
2 * Copyright 2013 Luciad (http://www.luciad.com)
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #include <stdio.h>
17 #include <string.h>
18 #include "fp.h"
19 #include "spl_geom.h"
20 #include "sqlite.h"
21
22 #define SPB_BIG_ENDIAN 0x00
23 #define SPB_LITTLE_ENDIAN 0x01
24
25 #define CHECK_ENV_COMP(spb, comp, error) \
26 if (spb->envelope.has_env_##comp) { \
27 if ((spb->empty && (!fp_isnan(spb->envelope.min_##comp) || !fp_isnan(spb->envelope.max_##comp))) || spb->envelope.min_##comp > spb->envelope.max_##comp) {\
28 if (error) error_append(error, "SPB envelope min" #comp " > max" #comp ": [min: %g, max: %g]", spb->envelope.min_##comp, spb->envelope.max_##comp);\
29 return SQLITE_IOERR;\
30 }\
31 }
32 #define CHECK_ENV(spb, error) CHECK_ENV_COMP(spb, x, error) CHECK_ENV_COMP(spb, y, error) CHECK_ENV_COMP(spb, z, error) CHECK_ENV_COMP(spb, m, error)
33
spb_read_header(binstream_t * stream,geom_blob_header_t * spb,error_t * error)34 int spb_read_header(binstream_t *stream, geom_blob_header_t *spb, error_t *error) {
35 uint8_t start;
36 if (binstream_read_u8(stream, &start) != SQLITE_OK) {
37 return SQLITE_IOERR;
38 }
39
40 if (start != 0x00) {
41 if (error) {
42 error_append(error, "Incorrect SPB START value [expected: 00, actual:%x]", start);
43 }
44 return SQLITE_IOERR;
45 }
46
47 uint8_t endian;
48 if (binstream_read_u8(stream, &endian)) {
49 return SQLITE_IOERR;
50 }
51
52 if (endian != SPB_BIG_ENDIAN && endian != SPB_LITTLE_ENDIAN) {
53 if (error) {
54 error_append(error, "Incorrect SPB ENDIAN value [expected: 00 or 01, actual:%x]", endian);
55 }
56 return SQLITE_IOERR;
57 }
58
59 binstream_set_endianness(stream, endian == SPB_BIG_ENDIAN ? BIG : LITTLE);
60 if (binstream_read_i32(stream, &spb->srid) != SQLITE_OK) {
61 return SQLITE_IOERR;
62 }
63
64 spb->envelope.has_env_x = 1;
65 spb->envelope.has_env_y = 1;
66 spb->envelope.has_env_z = 0;
67 spb->envelope.has_env_m = 0;
68 if (binstream_read_double(stream, &spb->envelope.min_x)) {
69 return SQLITE_IOERR;
70 }
71 if (binstream_read_double(stream, &spb->envelope.min_y)) {
72 return SQLITE_IOERR;
73 }
74 if (binstream_read_double(stream, &spb->envelope.max_x)) {
75 return SQLITE_IOERR;
76 }
77 if (binstream_read_double(stream, &spb->envelope.max_y)) {
78 return SQLITE_IOERR;
79 }
80
81 spb->empty = fp_isnan(spb->envelope.min_x) && fp_isnan(spb->envelope.max_x) && fp_isnan(spb->envelope.min_y) && fp_isnan(spb->envelope.max_y);
82
83 CHECK_ENV(spb, error)
84
85 return SQLITE_OK;
86 }
87
spb_write_header(binstream_t * stream,geom_blob_header_t * spb,error_t * error)88 int spb_write_header(binstream_t *stream, geom_blob_header_t *spb, error_t *error) {
89 CHECK_ENV(spb, error)
90
91 if (binstream_write_u8(stream, 0x00)) {
92 return SQLITE_IOERR;
93 }
94
95 uint8_t endian = binstream_get_endianness(stream) == LITTLE ? SPB_LITTLE_ENDIAN : SPB_BIG_ENDIAN;
96 if (binstream_write_u8(stream, endian)) {
97 return SQLITE_IOERR;
98 }
99
100 if (binstream_write_i32(stream, spb->srid)) {
101 return SQLITE_IOERR;
102 }
103
104 if (binstream_write_double(stream, spb->envelope.min_x)) {
105 return SQLITE_IOERR;
106 }
107 if (binstream_write_double(stream, spb->envelope.min_y)) {
108 return SQLITE_IOERR;
109 }
110 if (binstream_write_double(stream, spb->envelope.max_x)) {
111 return SQLITE_IOERR;
112 }
113 if (binstream_write_double(stream, spb->envelope.max_y)) {
114 return SQLITE_IOERR;
115 }
116
117 return SQLITE_OK;
118 }
119
spb_begin_geometry(const geom_consumer_t * consumer,const geom_header_t * header,error_t * error)120 static int spb_begin_geometry(const geom_consumer_t *consumer, const geom_header_t *header, error_t *error) {
121 int result = SQLITE_OK;
122
123 spb_writer_t *writer = (spb_writer_t *) consumer;
124 wkb_writer_t *wkb = &writer->wkb_writer;
125
126 if (wkb->offset < 0) {
127 result = binstream_relseek(&wkb->stream, 38);
128 if (result != SQLITE_OK) {
129 goto exit;
130 }
131 }
132
133 geom_consumer_t *wkb_consumer = wkb_writer_geom_consumer(wkb);
134 result = wkb_consumer->begin_geometry(wkb_consumer, header, error);
135 exit:
136 return result;
137 }
138
spb_coordinates(const geom_consumer_t * consumer,const geom_header_t * header,size_t point_count,const double * coords,int skip_coords,error_t * error)139 static int spb_coordinates(const geom_consumer_t *consumer, const geom_header_t *header, size_t point_count, const double *coords, int skip_coords, error_t *error) {
140 int result = SQLITE_OK;
141
142 if (point_count <= 0) {
143 goto exit;
144 }
145
146 spb_writer_t *writer = (spb_writer_t *) consumer;
147 wkb_writer_t *wkb = &writer->wkb_writer;
148 geom_consumer_t *wkb_consumer = wkb_writer_geom_consumer(wkb);
149 result = wkb_consumer->coordinates(wkb_consumer, header, point_count, coords, skip_coords, error);
150 if (result != SQLITE_OK) {
151 goto exit;
152 }
153
154 if (header->geom_type == GEOM_POINT) {
155 int allnan = 1;
156 for (uint32_t i = 0; i < header->coord_size; i++) {
157 allnan &= fp_isnan(coords[i]);
158 }
159 if (allnan) {
160 goto exit;
161 }
162 }
163
164 geom_blob_header_t *spb = &writer->header;
165 spb->empty = 0;
166 geom_envelope_t *envelope = &spb->envelope;
167 geom_envelope_fill(envelope, header, point_count, coords);
168
169 exit:
170 return result;
171 }
172
spb_end_geometry(const geom_consumer_t * consumer,const geom_header_t * header,error_t * error)173 static int spb_end_geometry(const geom_consumer_t *consumer, const geom_header_t *header, error_t *error) {
174 spb_writer_t *writer = (spb_writer_t *) consumer;
175 wkb_writer_t *wkb = &writer->wkb_writer;
176
177 geom_consumer_t *wkb_consumer = wkb_writer_geom_consumer(wkb);
178 return wkb_consumer->end_geometry(wkb_consumer, header, error);
179 }
180
spb_end(const geom_consumer_t * consumer,error_t * error)181 static int spb_end(const geom_consumer_t *consumer, error_t *error) {
182 int result = SQLITE_OK;
183
184 spb_writer_t *writer = (spb_writer_t *) consumer;
185 wkb_writer_t *wkb = &writer->wkb_writer;
186 binstream_t *stream = &wkb->stream;
187
188 size_t pos = binstream_position(stream);
189 result = binstream_seek(stream, 0);
190 if (result != SQLITE_OK) {
191 goto exit;
192 }
193
194 geom_envelope_t *envelope = &writer->header.envelope;
195 if (geom_envelope_finalize(envelope) == EMPTY_GEOM) {
196 writer->header.empty = 1;
197 }
198
199 result = spb_write_header(stream, &writer->header, NULL);
200 if (result != SQLITE_OK) {
201 goto exit;
202 }
203
204 result = binstream_seek(stream, pos);
205 if (result != SQLITE_OK) {
206 goto exit;
207 }
208
209 geom_consumer_t *wkb_consumer = wkb_writer_geom_consumer(wkb);
210 result = wkb_consumer->end(wkb_consumer, error);
211
212 exit:
213 return result;
214 }
215
spb_writer_init(geom_blob_writer_t * writer,int32_t srid)216 int spb_writer_init(geom_blob_writer_t *writer, int32_t srid) {
217 geom_consumer_init(&writer->geom_consumer, NULL, spb_end, spb_begin_geometry, spb_end_geometry, spb_coordinates);
218 geom_envelope_init(&writer->header.envelope);
219 writer->header.envelope.has_env_x = 1;
220 writer->header.envelope.has_env_y = 1;
221 writer->header.srid = srid;
222 writer->header.empty = 1;
223 return wkb_writer_init(&writer->wkb_writer, WKB_SPATIALITE);
224 }
225
spb_writer_destroy(geom_blob_writer_t * writer,int free_data)226 void spb_writer_destroy(geom_blob_writer_t *writer, int free_data) {
227 wkb_writer_destroy(&writer->wkb_writer, free_data);
228 }
229