PostGIS  3.0.6dev-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  int64_t length, reslen;
64  size_t oldlen = strlen(oldstr);
65  size_t 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 *
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) {
131  fprintf(stderr, "Not enough memory\n");
132  return NULL;
133  }
134  memcpy(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 *
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(int32_t srid)
283 {
284  int i = 0;
285  int len = 0;
286  char *sql = NULL;
287  int spi_result;
288  TupleDesc tupdesc;
289  SPITupleTable *tuptable = NULL;
290  HeapTuple tuple;
291  char *tmp = NULL;
292  char *srs = NULL;
293 
294 /*
295 SELECT
296  CASE
297  WHEN (upper(auth_name) = 'EPSG' OR upper(auth_name) = 'EPSGA') AND length(COALESCE(auth_srid::text, '')) > 0
298  THEN upper(auth_name) || ':' || auth_srid
299  WHEN length(COALESCE(auth_name, '') || COALESCE(auth_srid::text, '')) > 0
300  THEN COALESCE(auth_name, '') || COALESCE(auth_srid::text, '')
301  ELSE ''
302  END,
303  proj4text,
304  srtext
305 FROM spatial_ref_sys
306 WHERE srid = X
307 LIMIT 1
308 */
309 
310  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);
311  sql = (char *) palloc(len);
312  if (NULL == sql) {
313  elog(ERROR, "rtpg_getSR: Could not allocate memory for sql\n");
314  return NULL;
315  }
316 
317  spi_result = SPI_connect();
318  if (spi_result != SPI_OK_CONNECT) {
319  pfree(sql);
320  elog(ERROR, "rtpg_getSR: Could not connect to database using SPI\n");
321  return NULL;
322  }
323 
324  /* execute query */
325  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);
326  POSTGIS_RT_DEBUGF(4, "SRS query: %s", sql);
327  spi_result = SPI_execute(sql, TRUE, 0);
328  SPI_pfree(sql);
329  if (spi_result != SPI_OK_SELECT || SPI_tuptable == NULL || SPI_processed != 1) {
330  if (SPI_tuptable) SPI_freetuptable(tuptable);
331  SPI_finish();
332  elog(ERROR, "rtpg_getSR: Cannot find SRID (%d) in spatial_ref_sys", srid);
333  return NULL;
334  }
335 
336  tupdesc = SPI_tuptable->tupdesc;
337  tuptable = SPI_tuptable;
338  tuple = tuptable->vals[0];
339 
340  /* which column to use? */
341  for (i = 1; i < 4; i++) {
342  tmp = SPI_getvalue(tuple, tupdesc, i);
343 
344  /* value AND GDAL supports this SR */
345  if (
346  SPI_result != SPI_ERROR_NOATTRIBUTE &&
347  SPI_result != SPI_ERROR_NOOUTFUNC &&
348  tmp != NULL &&
349  strlen(tmp) &&
351  ) {
352  POSTGIS_RT_DEBUGF(4, "Value for column %d is %s", i, tmp);
353 
354  len = strlen(tmp) + 1;
355  srs = SPI_palloc(sizeof(char) * len);
356  if (NULL == srs) {
357  pfree(tmp);
358  if (SPI_tuptable) SPI_freetuptable(tuptable);
359  SPI_finish();
360  elog(ERROR, "rtpg_getSR: Could not allocate memory for spatial reference text\n");
361  return NULL;
362  }
363  strncpy(srs, tmp, len);
364  pfree(tmp);
365 
366  break;
367  }
368 
369  if (tmp != NULL)
370  pfree(tmp);
371  continue;
372  }
373 
374  if (SPI_tuptable) SPI_freetuptable(tuptable);
375  SPI_finish();
376 
377  /* unable to get SR info */
378  if (srs == NULL) {
379  if (SPI_tuptable) SPI_freetuptable(tuptable);
380  SPI_finish();
381  elog(ERROR, "rtpg_getSR: Could not find a viable spatial reference for SRID (%d)", srid);
382  return NULL;
383  }
384 
385  return srs;
386 }
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:245
#define str(s)
int count
Definition: genraster.py:57
char * rtpg_removespaces(char *str)
char * rtpg_getSR(int32_t 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