PostGIS  2.5.7dev-r@@SVN_REVISION@@
rtpg_internal.c
Go to the documentation of this file.
1 /*
2  *
3  * WKTRaster - Raster Types for PostGIS
4  * http://trac.osgeo.org/postgis/wiki/WKTRaster
5  *
6  * Copyright (C) 2011-2013 Regents of the University of California
7  * <bkpark@ucdavis.edu>
8  * Copyright (C) 2010-2011 Jorge Arevalo <jorge.arevalo@deimos-space.com>
9  * Copyright (C) 2010-2011 David Zwarg <dzwarg@azavea.com>
10  * Copyright (C) 2009-2011 Pierre Racine <pierre.racine@sbf.ulaval.ca>
11  * Copyright (C) 2009-2011 Mateusz Loskot <mateusz@loskot.net>
12  * Copyright (C) 2008-2009 Sandro Santilli <strk@kbt.io>
13  *
14  * This program is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU General Public License
16  * as published by the Free Software Foundation; either version 2
17  * of the License, or (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, write to the Free Software Foundation,
26  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
27  *
28  */
29 
30 #include <ctype.h> /* for isspace */
31 #include <postgres.h> /* for palloc */
32 #include <executor/spi.h>
33 
34 #include "rtpg_internal.h"
35 
36 /* string replacement function taken from
37  * http://ubuntuforums.org/showthread.php?s=aa6f015109fd7e4c7e30d2fd8b717497&t=141670&page=3
38  */
39 /* ---------------------------------------------------------------------------
40  Name : replace - Search & replace a substring by another one.
41  Creation : Thierry Husson, Sept 2010
42  Parameters :
43  str : Big string where we search
44  oldstr : Substring we are looking for
45  newstr : Substring we want to replace with
46  count : Optional pointer to int (input / output value). NULL to ignore.
47  Input: Maximum replacements to be done. NULL or < 1 to do all.
48  Output: Number of replacements done or -1 if not enough memory.
49  Returns : Pointer to the new string or NULL if error.
50  Notes :
51  - Case sensitive - Otherwise, replace functions "strstr" by "strcasestr"
52  - Always allocates memory for the result.
53 --------------------------------------------------------------------------- */
54 char*
56  const char *str,
57  const char *oldstr, const char *newstr,
58  int *count
59 ) {
60  const char *tmp = str;
61  char *result;
62  int found = 0;
63  int length, reslen;
64  int oldlen = strlen(oldstr);
65  int newlen = strlen(newstr);
66  int limit = (count != NULL && *count > 0) ? *count : -1;
67 
68  tmp = str;
69  while ((tmp = strstr(tmp, oldstr)) != NULL && found != limit)
70  found++, tmp += oldlen;
71 
72  length = strlen(str) + found * (newlen - oldlen);
73  if ((result = (char *) palloc(length + 1)) == NULL) {
74  fprintf(stderr, "Not enough memory\n");
75  found = -1;
76  }
77  else {
78  tmp = str;
79  limit = found; /* Countdown */
80  reslen = 0; /* length of current result */
81 
82  /* Replace each old string found with new string */
83  while ((limit-- > 0) && (tmp = strstr(tmp, oldstr)) != NULL) {
84  length = (tmp - str); /* Number of chars to keep intouched */
85  strncpy(result + reslen, str, length); /* Original part keeped */
86  strcpy(result + (reslen += length), newstr); /* Insert new string */
87 
88  reslen += newlen;
89  tmp += oldlen;
90  str = tmp;
91  }
92  strcpy(result + reslen, str); /* Copies last part and ending null char */
93  }
94 
95  if (count != NULL) *count = found;
96  return result;
97 }
98 
99 char *
100 rtpg_strtoupper(char * str) {
101  int j;
102 
103  for (j = strlen(str) - 1; j >= 0; j--)
104  str[j] = toupper(str[j]);
105 
106  return str;
107 }
108 
109 char*
110 rtpg_chartrim(const char *input, char *remove) {
111  char *rtn = NULL;
112  char *ptr = NULL;
113  uint32_t offset = 0;
114 
115  if (!input)
116  return NULL;
117  else if (!*input)
118  return (char *) input;
119 
120  /* trim left */
121  while (strchr(remove, *input) != NULL)
122  input++;
123 
124  /* trim right */
125  ptr = ((char *) input) + strlen(input);
126  while (strchr(remove, *--ptr) != NULL)
127  offset++;
128 
129  rtn = palloc(sizeof(char) * (strlen(input) - offset + 1));
130  if (rtn == NULL) {
131  fprintf(stderr, "Not enough memory\n");
132  return NULL;
133  }
134  strncpy(rtn, input, strlen(input) - offset);
135  rtn[strlen(input) - offset] = '\0';
136 
137  return rtn;
138 }
139 
140 /* split a string based on a delimiter */
141 char**
142 rtpg_strsplit(const char *str, const char *delimiter, uint32_t *n) {
143  char *tmp = NULL;
144  char **rtn = NULL;
145  char *token = NULL;
146 
147  *n = 0;
148  if (!str)
149  return NULL;
150 
151  /* copy str to tmp as strtok will mangle the string */
152  tmp = palloc(sizeof(char) * (strlen(str) + 1));
153  if (NULL == tmp) {
154  fprintf(stderr, "Not enough memory\n");
155  return NULL;
156  }
157  strcpy(tmp, str);
158 
159  if (!strlen(tmp) || !delimiter || !strlen(delimiter)) {
160  *n = 1;
161  rtn = (char **) palloc(*n * sizeof(char *));
162  if (NULL == rtn) {
163  fprintf(stderr, "Not enough memory\n");
164  return NULL;
165  }
166  rtn[0] = (char *) palloc(sizeof(char) * (strlen(tmp) + 1));
167  if (NULL == rtn[0]) {
168  fprintf(stderr, "Not enough memory\n");
169  return NULL;
170  }
171  strcpy(rtn[0], tmp);
172  pfree(tmp);
173  return rtn;
174  }
175 
176  token = strtok(tmp, delimiter);
177  while (token != NULL) {
178  if (*n < 1) {
179  rtn = (char **) palloc(sizeof(char *));
180  }
181  else {
182  rtn = (char **) repalloc(rtn, (*n + 1) * sizeof(char *));
183  }
184  if (NULL == rtn) {
185  fprintf(stderr, "Not enough memory\n");
186  return NULL;
187  }
188 
189  rtn[*n] = NULL;
190  rtn[*n] = (char *) palloc(sizeof(char) * (strlen(token) + 1));
191  if (NULL == rtn[*n]) {
192  fprintf(stderr, "Not enough memory\n");
193  return NULL;
194  }
195 
196  strcpy(rtn[*n], token);
197  *n = *n + 1;
198 
199  token = strtok(NULL, delimiter);
200  }
201 
202  pfree(tmp);
203  return rtn;
204 }
205 
206 char *
207 rtpg_removespaces(char *str) {
208  char *rtn;
209  char *tmp;
210 
211  rtn = rtpg_strreplace(str, " ", "", NULL);
212 
213  tmp = rtpg_strreplace(rtn, "\n", "", NULL);
214  pfree(rtn);
215  rtn = rtpg_strreplace(tmp, "\t", "", NULL);
216  pfree(tmp);
217  tmp = rtpg_strreplace(rtn, "\f", "", NULL);
218  pfree(rtn);
219  rtn = rtpg_strreplace(tmp, "\r", "", NULL);
220  pfree(tmp);
221 
222  return rtn;
223 }
224 
225 char*
226 rtpg_trim(const char *input) {
227  char *rtn;
228  char *ptr;
229  uint32_t offset = 0;
230  int inputlen = 0;
231 
232  if (!input)
233  return NULL;
234  else if (!*input)
235  return (char *) input;
236 
237  /* trim left */
238  while (isspace(*input) && *input != '\0')
239  input++;
240 
241  /* trim right */
242  inputlen = strlen(input);
243  if (inputlen) {
244  ptr = ((char *) input) + inputlen;
245  while (isspace(*--ptr))
246  offset++;
247  }
248 
249  rtn = palloc(sizeof(char) * (inputlen - offset + 1));
250  if (rtn == NULL) {
251  fprintf(stderr, "Not enough memory\n");
252  return NULL;
253  }
254  strncpy(rtn, input, inputlen - offset);
255  rtn[inputlen - offset] = '\0';
256 
257  return rtn;
258 }
259 
260 /*
261  * reverse string search function from
262  * http://stackoverflow.com/a/1634398
263  */
264 char *
265 rtpg_strrstr(const char *s1, const char *s2) {
266  int s1len = strlen(s1);
267  int s2len = strlen(s2);
268  char *s;
269 
270  if (s2len > s1len)
271  return NULL;
272 
273  s = (char *) (s1 + s1len - s2len);
274  for (; s >= s1; --s)
275  if (strncmp(s, s2, s2len) == 0)
276  return s;
277 
278  return NULL;
279 }
280 
281 char*
282 rtpg_getSR(int srid) {
283  int i = 0;
284  int len = 0;
285  char *sql = NULL;
286  int spi_result;
287  TupleDesc tupdesc;
288  SPITupleTable *tuptable = NULL;
289  HeapTuple tuple;
290  char *tmp = NULL;
291  char *srs = NULL;
292 
293 /*
294 SELECT
295  CASE
296  WHEN (upper(auth_name) = 'EPSG' OR upper(auth_name) = 'EPSGA') AND length(COALESCE(auth_srid::text, '')) > 0
297  THEN upper(auth_name) || ':' || auth_srid
298  WHEN length(COALESCE(auth_name, '') || COALESCE(auth_srid::text, '')) > 0
299  THEN COALESCE(auth_name, '') || COALESCE(auth_srid::text, '')
300  ELSE ''
301  END,
302  proj4text,
303  srtext
304 FROM spatial_ref_sys
305 WHERE srid = X
306 LIMIT 1
307 */
308 
309  len = sizeof(char) * (strlen("SELECT CASE WHEN (upper(auth_name) = 'EPSG' OR upper(auth_name) = 'EPSGA') AND length(COALESCE(auth_srid::text, '')) > 0 THEN upper(auth_name) || ':' || auth_srid WHEN length(COALESCE(auth_name, '') || COALESCE(auth_srid::text, '')) > 0 THEN COALESCE(auth_name, '') || COALESCE(auth_srid::text, '') ELSE '' END, proj4text, srtext FROM spatial_ref_sys WHERE srid = LIMIT 1") + MAX_INT_CHARLEN + 1);
310  sql = (char *) palloc(len);
311  if (NULL == sql) {
312  elog(ERROR, "rtpg_getSR: Could not allocate memory for sql\n");
313  return NULL;
314  }
315 
316  spi_result = SPI_connect();
317  if (spi_result != SPI_OK_CONNECT) {
318  pfree(sql);
319  elog(ERROR, "rtpg_getSR: Could not connect to database using SPI\n");
320  return NULL;
321  }
322 
323  /* execute query */
324  snprintf(sql, len, "SELECT CASE WHEN (upper(auth_name) = 'EPSG' OR upper(auth_name) = 'EPSGA') AND length(COALESCE(auth_srid::text, '')) > 0 THEN upper(auth_name) || ':' || auth_srid WHEN length(COALESCE(auth_name, '') || COALESCE(auth_srid::text, '')) > 0 THEN COALESCE(auth_name, '') || COALESCE(auth_srid::text, '') ELSE '' END, proj4text, srtext FROM spatial_ref_sys WHERE srid = %d LIMIT 1", srid);
325  POSTGIS_RT_DEBUGF(4, "SRS query: %s", sql);
326  spi_result = SPI_execute(sql, TRUE, 0);
327  SPI_pfree(sql);
328  if (spi_result != SPI_OK_SELECT || SPI_tuptable == NULL || SPI_processed != 1) {
329  if (SPI_tuptable) SPI_freetuptable(tuptable);
330  SPI_finish();
331  elog(ERROR, "rtpg_getSR: Cannot find SRID (%d) in spatial_ref_sys", srid);
332  return NULL;
333  }
334 
335  tupdesc = SPI_tuptable->tupdesc;
336  tuptable = SPI_tuptable;
337  tuple = tuptable->vals[0];
338 
339  /* which column to use? */
340  for (i = 1; i < 4; i++) {
341  tmp = SPI_getvalue(tuple, tupdesc, i);
342 
343  /* value AND GDAL supports this SR */
344  if (
345  SPI_result != SPI_ERROR_NOATTRIBUTE &&
346  SPI_result != SPI_ERROR_NOOUTFUNC &&
347  tmp != NULL &&
348  strlen(tmp) &&
350  ) {
351  POSTGIS_RT_DEBUGF(4, "Value for column %d is %s", i, tmp);
352 
353  len = strlen(tmp) + 1;
354  srs = SPI_palloc(sizeof(char) * len);
355  if (NULL == srs) {
356  pfree(tmp);
357  if (SPI_tuptable) SPI_freetuptable(tuptable);
358  SPI_finish();
359  elog(ERROR, "rtpg_getSR: Could not allocate memory for spatial reference text\n");
360  return NULL;
361  }
362  strncpy(srs, tmp, len);
363  pfree(tmp);
364 
365  break;
366  }
367 
368  if (tmp != NULL)
369  pfree(tmp);
370  continue;
371  }
372 
373  if (SPI_tuptable) SPI_freetuptable(tuptable);
374  SPI_finish();
375 
376  /* unable to get SR info */
377  if (srs == NULL) {
378  if (SPI_tuptable) SPI_freetuptable(tuptable);
379  SPI_finish();
380  elog(ERROR, "rtpg_getSR: Could not find a viable spatial reference for SRID (%d)", srid);
381  return NULL;
382  }
383 
384  return srs;
385 }
char * s
Definition: cu_in_wkt.c:23
#define TRUE
Definition: dbfopen.c:169
int rt_util_gdal_supported_sr(const char *srs)
Definition: rt_util.c:243
int count
Definition: genraster.py:56
char * rtpg_removespaces(char *str)
char * rtpg_getSR(int srid)
char * rtpg_strtoupper(char *str)
char * rtpg_chartrim(const char *input, char *remove)
char * rtpg_strrstr(const char *s1, const char *s2)
char * rtpg_trim(const char *input)
char ** rtpg_strsplit(const char *str, const char *delimiter, uint32_t *n)
char * rtpg_strreplace(const char *str, const char *oldstr, const char *newstr, int *count)
Definition: rtpg_internal.c:55
#define POSTGIS_RT_DEBUGF(level, msg,...)
Definition: rtpostgis.h:65
#define MAX_INT_CHARLEN
Definition: rtpostgis.h:76
unsigned int uint32_t
Definition: uthash.h:78