1 /*
2   Copyright (c) <2007-2012> <Barbara Philippot - Olivier Courtin>
3 
4   Permission is hereby granted, free of charge, to any person obtaining a copy
5   of this software and associated documentation files (the "Software"), to deal
6   in the Software without restriction, including without limitation the rights
7   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8   copies of the Software, and to permit persons to whom the Software is
9   furnished to do so, subject to the following conditions:
10 
11   The above copyright notice and this permission notice shall be included in
12   all copies or substantial portions of the Software.
13 
14   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
20   IN THE SOFTWARE.
21 */
22 
23 
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <assert.h>
27 #include <ctype.h>
28 #include <libpq-fe.h>
29 #include <string.h>
30 
31 #include "ows.h"
32 
33 
34 /*
35  * Initialize proj structure
36  */
ows_srs_init()37 ows_srs *ows_srs_init()
38 {
39   ows_srs *c;
40 
41   c = malloc(sizeof(ows_srs));
42   assert(c);
43 
44   c->srid = -1;
45   c->auth_name = buffer_init();
46   c->auth_srid = 0;
47   c->is_degree = true;
48   c->is_reverse_axis = false;
49   c->is_eastern_axis = false;
50   c->is_long = false;
51 
52   return c;
53 }
54 
55 
ows_srs_copy(ows_srs * d,ows_srs * s)56 ows_srs *ows_srs_copy(ows_srs * d, ows_srs * s)
57 {
58   assert(s);
59   assert(d);
60 
61   d->srid = s->srid;
62   buffer_copy(d->auth_name, s->auth_name);
63   d->auth_srid = s->auth_srid;
64   d->is_degree = s->is_degree;
65   d->is_reverse_axis = s->is_reverse_axis;
66   d->is_eastern_axis = s->is_eastern_axis;
67   d->is_long = s->is_long;
68 
69   return d;
70 }
71 
72 
73 /*
74  * Free proj structure
75  */
ows_srs_free(ows_srs * c)76 void ows_srs_free(ows_srs * c)
77 {
78   assert(c);
79 
80   buffer_free(c->auth_name);
81   free(c);
82   c = NULL;
83 }
84 
85 
86 #ifdef OWS_DEBUG
87 /*
88  * Print ows structure state into a file
89  * (mainly for debug purpose)
90  */
ows_srs_flush(ows_srs * c,FILE * output)91 void ows_srs_flush(ows_srs * c, FILE * output)
92 {
93   assert(c);
94   assert(output);
95 
96   fprintf(output, "[\n");
97   fprintf(output, " srid: %i\n", c->srid);
98   fprintf(output, " auth_name: %s\n", c->auth_name->buf);
99   fprintf(output, " auth_srid: %i\n", c->auth_srid);
100 
101   if (c->is_degree) fprintf(output, " is_degree: true\n]\n");
102   else              fprintf(output, " is_degree: false\n]\n");
103 
104   if (c->is_reverse_axis)
105     fprintf(output, " is_reverse_axis: true\n]\n");
106   else
107     fprintf(output, " is_reverse_axis: false\n]\n");
108 
109   if (c->is_eastern_axis)
110     fprintf(output, " is_eastern_axis: true\n]\n");
111   else
112     fprintf(output, " is_eastern_axis: false\n]\n");
113 
114   if (c->is_long)
115     fprintf(output, " is_long: true\n]\n");
116   else
117     fprintf(output, " is_long: false\n]\n");
118 }
119 #endif
120 
121 
122 /*
123  * Set projection value into srs structure
124  */
ows_srs_set(ows * o,ows_srs * c,const buffer * auth_name,int auth_srid)125 bool ows_srs_set(ows * o, ows_srs * c, const buffer * auth_name, int auth_srid)
126 {
127   PGresult *res;
128   buffer *sql;
129 
130   assert(o);
131   assert(c);
132   assert(o->pg);
133   assert(auth_name);
134 
135   sql = buffer_init();
136   buffer_add_str(sql, "SELECT srid, position('+units=m ' in proj4text)");
137   buffer_add_str(sql, ", (position('AXIS[\"X\",NORTH]]' in srtext) + position('AXIS[\"Easting\",EAST]]' in srtext))");
138   buffer_add_str(sql, " FROM spatial_ref_sys WHERE auth_name='");
139   buffer_copy(sql, auth_name);
140   buffer_add_str(sql, "' AND auth_srid=");
141   buffer_add_int(sql, auth_srid);
142 
143   res = ows_psql_exec(o, sql->buf);
144   buffer_free(sql);
145 
146   /* If query dont return exactly 1 result, it means projection is not handled */
147   if (PQresultStatus(res) != PGRES_TUPLES_OK || PQntuples(res) != 1) {
148     PQclear(res);
149     return false;
150   }
151 
152   buffer_empty(c->auth_name);
153   buffer_copy(c->auth_name, auth_name);
154   c->auth_srid = auth_srid;
155 
156   c->srid = atoi(PQgetvalue(res, 0, 0));
157 
158   /* Such a way to know if units is meter or degree */
159   if (atoi(PQgetvalue(res, 0, 1)) == 0)
160     c->is_degree = true;
161   else
162     c->is_degree = false;
163 
164   /* Is northing-easting SRID ? */
165   if (atoi(PQgetvalue(res, 0, 2)) != 0)
166     c->is_eastern_axis = true;
167 
168   PQclear(res);
169   return true;
170 }
171 
172 
173 /*
174  * Aim is to avoid all pg connection,
175  * not a big deal as we already know values
176  */
ows_srs_set_geobbox(ows * o,ows_srs * s)177 bool ows_srs_set_geobbox(ows * o, ows_srs * s)
178 {
179   assert(o);
180   assert(s);
181 
182   s->srid = 4326;
183   buffer_empty(s->auth_name);
184   buffer_add_str(s->auth_name, "EPSG");
185   s->auth_srid = 4326;
186   s->is_degree = true;
187   s->is_reverse_axis = false;
188   s->is_eastern_axis = false;
189 
190   return true;
191 }
192 
193 
194 /*
195  * Set projection value into srs structure
196  */
ows_srs_set_from_srid(ows * o,ows_srs * s,int srid)197 bool ows_srs_set_from_srid(ows * o, ows_srs * s, int srid)
198 {
199   PGresult *res;
200   buffer *sql;
201 
202   assert(o);
203   assert(s);
204 
205   if (srid == -1 || srid == 0) {
206     s->srid = -1;
207     buffer_empty(s->auth_name);
208     s->auth_srid = 0;
209     s->is_degree = true;
210     s->is_reverse_axis = false;
211     s->is_eastern_axis = false;
212 
213     return true;
214   }
215 
216   sql = buffer_init();
217   buffer_add_str(sql, "SELECT auth_name, auth_srid, ");
218   buffer_add_str(sql, "position('+units=m ' in proj4text), ");
219   buffer_add_str(sql, "(position('AXIS[\"X\",NORTH]]' in srtext) + position('AXIS[\"Easting\",EAST]]' in srtext)) ");
220   buffer_add_str(sql, "FROM spatial_ref_sys WHERE srid = '");
221   buffer_add_int(sql, srid);
222   buffer_add_str(sql, "'");
223 
224   res = ows_psql_exec(o, sql->buf);
225   buffer_free(sql);
226 
227   /* If query dont return exactly 1 result, it mean projection not handled */
228   if (PQresultStatus(res) != PGRES_TUPLES_OK || PQntuples(res) != 1) {
229     PQclear(res);
230     return false;
231   }
232 
233   buffer_add_str(s->auth_name, PQgetvalue(res, 0, 0));
234   s->auth_srid = atoi(PQgetvalue(res, 0, 1));
235   s->srid = srid;
236 
237   /* Such a way to know if units is meter or degree */
238   if (atoi(PQgetvalue(res, 0, 2)) == 0)
239     s->is_degree = true;
240   else
241     s->is_degree = false;
242 
243   /* Is northing-easting SRID ? */
244   if (atoi(PQgetvalue(res, 0, 3)) != 0)
245     s->is_eastern_axis = true;
246 
247   PQclear(res);
248   return true;
249 }
250 
251 
252 /*
253  * Set projection value into srs structure
254  */
ows_srs_set_from_srsname(ows * o,ows_srs * s,const char * srsname)255 bool ows_srs_set_from_srsname(ows * o, ows_srs * s, const char *srsname)
256 {
257   char sep;
258   int srid = -1;
259   const char *p = NULL;
260 
261   assert(o);
262   assert(s);
263   assert(srsname);
264 
265   /* Severals srsName formats are available...
266    *  cf WFS 1.1.0 -> 9.2 (p36)
267    *  cf ISO 19142 -> 7.9.2.4.4 (p34)
268    *  cf RFC 5165 <http://tools.ietf.org/html/rfc5165>
269    *  cf CITE WFS-1.1 (GetFeature-tc17.2)
270    */
271 
272   /* SRS pattern like:    EPSG:4326
273                           urn:EPSG:geographicCRS:4326
274                           urn:ogc:def:crs:EPSG:4326
275                           urn:ogc:def:crs:EPSG::4326
276                           urn:ogc:def:crs:EPSG:6.6:4326
277                           urn:x-ogc:def:crs:EPSG:6.6:4326
278                           http://www.opengis.net/gml/srs/epsg.xml#4326
279                           spatialreferencing.org:900913
280   */
281   s->is_long = true;
282 
283   if    (!strncmp((char *) srsname,        "EPSG:", 5)
284          || !strncmp((char *) srsname, "spatialreferencing.org", 22)) {
285     sep = ':';
286     s->is_reverse_axis = false;
287     s->is_long = false;
288 
289   } else if (!strncmp((char *) srsname, "urn:ogc:def:crs:EPSG:", 21)
290              || !strncmp((char *) srsname, "urn:x-ogc:def:crs:EPSG:", 23)
291              || !strncmp((char *) srsname, "urn:EPSG:geographicCRS:", 23)) {
292     sep = ':';
293     s->is_reverse_axis = true;
294 
295   } else if (!strncmp((char *) srsname, "http://www.opengis.net/gml/srs/epsg.xml#", 40)) {
296     sep = '#';
297     s->is_reverse_axis = false;
298   } else return false; /* FIXME must we really not allow other value ? */
299 
300   /*  Retrieve from last separator to the end of srsName string */
301   for (p = srsname ; *p ; p++);
302   for (--p ; *p != sep ; p--)
303     if (!isdigit(*p)) return false;
304   srid = atoi(++p);
305 
306   return ows_srs_set_from_srid(o, s, srid);
307 }
308 
309 
310 /*
311  * Check if a layer's srs has meter or degree units
312  */
ows_srs_meter_units(ows * o,buffer * layer_name)313 bool ows_srs_meter_units(ows * o, buffer * layer_name)
314 {
315   ows_layer_node * ln;
316 
317   assert(o);
318   assert(layer_name);
319 
320   for (ln = o->layers->first ; ln ; ln = ln->next)
321     if (ln->layer->name && ln->layer->storage && !strcmp(ln->layer->name->buf, layer_name->buf))
322       return !ln->layer->storage->is_degree;
323 
324   assert(0); /* Should not happen */
325   return false;
326 }
327 
328 
329 /*
330  * Retrieve a srs from a layer
331  */
ows_srs_get_srid_from_layer(ows * o,buffer * layer_name)332 int ows_srs_get_srid_from_layer(ows * o, buffer * layer_name)
333 {
334   ows_layer_node * ln;
335 
336   assert(o);
337   assert(layer_name);
338 
339   for (ln = o->layers->first ; ln ; ln = ln->next)
340     if (ln->layer->name && ln->layer->storage && !strcmp(ln->layer->name->buf, layer_name->buf))
341       return ln->layer->storage->srid;
342 
343   return -1;
344 }
345 
346 
347 /*
348  * Retrieve a list of srs from an srid list
349  */
ows_srs_get_from_srid(ows * o,list * l)350 list *ows_srs_get_from_srid(ows * o, list * l)
351 {
352   list_node *ln;
353   buffer *b;
354   list *srs;
355 
356   assert(o);
357   assert(l);
358 
359   srs = list_init();
360 
361   if (l->size == 0) return srs;
362 
363   for (ln = l->first; ln ; ln = ln->next) {
364     b = ows_srs_get_from_a_srid(o, atoi(ln->value->buf));
365     list_add(srs, b);
366   }
367 
368   return srs;
369 }
370 
371 
372 /*
373  * Retrieve a srs from a srid
374  */
ows_srs_get_from_a_srid(ows * o,int srid)375 buffer *ows_srs_get_from_a_srid(ows * o, int srid)
376 {
377   buffer *b;
378   buffer *sql;
379   PGresult *res;
380 
381   assert(o);
382 
383   sql = buffer_init();
384   buffer_add_str(sql, "SELECT auth_name||':'||auth_srid AS srs ");
385   buffer_add_str(sql, "FROM spatial_ref_sys ");
386   buffer_add_str(sql, "WHERE srid=");
387   buffer_add_int(sql, srid);
388 
389   res = ows_psql_exec(o, sql->buf);
390   buffer_free(sql);
391 
392   b = buffer_init();
393 
394   if (PQresultStatus(res) != PGRES_TUPLES_OK || PQntuples(res) != 1) {
395     PQclear(res);
396     return b;
397   }
398 
399   buffer_add_str(b, PQgetvalue(res, 0, 0));
400 
401   PQclear(res);
402 
403   return b;
404 }
405 
406 
407 /*
408  * vim: expandtab sw=4 ts=4
409  */
410