PostGIS  2.2.7dev-r@@SVN_REVISION@@
shpcommon.c
Go to the documentation of this file.
1 /**********************************************************************
2  *
3  * PostGIS - Spatial Types for PostgreSQL
4  * http://postgis.net
5  *
6  * Copyright (C) 2014 Sandro Santilli <strk@keybit.net>
7  * Copyright (C) 2010 Mark Cave-Ayland <mark.cave-ayland@siriusit.co.uk>
8  *
9  * This is free software; you can redistribute and/or modify it under
10  * the terms of the GNU General Public Licence. See the COPYING file.
11  *
12  **********************************************************************/
13 
14 /* This file contains functions that are shared between the loader and dumper */
15 
16 #include <stdio.h>
17 #include <string.h>
18 #include <stdlib.h>
19 
20 #include "shpcommon.h"
21 
22 
28 char *
30 {
31  /*
32  * Escape apostrophes and backslashes:
33  * ' -> \'
34  * \ -> \\
35  *
36  * 1. find # of characters
37  * 2. make new string
38  */
39 
40  char *result;
41  char *ptr, *optr;
42  int toescape = 0;
43  size_t size;
44 
45  ptr = str;
46 
47  /* Count how many characters we need to escape so we know the size of the string we need to return */
48  while (*ptr)
49  {
50  if (*ptr == '\'' || *ptr == '\\')
51  toescape++;
52 
53  ptr++;
54  }
55 
56  /* If we don't have to escape anything, simply return the input pointer */
57  if (toescape == 0)
58  return str;
59 
60  size = ptr - str + toescape + 1;
61  result = calloc(1, size);
62  optr = result;
63  ptr = str;
64 
65  while (*ptr)
66  {
67  if (*ptr == '\'' || *ptr == '\\')
68  *optr++ = '\\';
69 
70  *optr++ = *ptr++;
71  }
72 
73  *optr = '\0';
74 
75  return result;
76 }
77 
78 void
80 {
81  map->size = 0;
82  map->pgfieldnames = NULL;
83  map->dbffieldnames = NULL;
84 }
85 
86 void
88 {
89  int i;
90  if (map->size)
91  {
92  for (i = 0; i < map->size; i++)
93  {
94  if (map->pgfieldnames[i]) free(map->pgfieldnames[i]);
95  if (map->dbffieldnames[i]) free(map->dbffieldnames[i]);
96  }
97  free(map->pgfieldnames);
98  free(map->dbffieldnames);
99  }
100 }
101 
102 const char *
103 colmap_dbf_by_pg(colmap *map, const char *pgname)
104 {
105  int i;
106  for (i=0; i<map->size; ++i)
107  {
108  if (!strcasecmp(map->pgfieldnames[i], pgname))
109  {
110  return map->dbffieldnames[i];
111  }
112  }
113  return NULL;
114 }
115 
116 const char *
117 colmap_pg_by_dbf(colmap *map, const char *dbfname)
118 {
119  int i;
120  for (i=0; i<map->size; ++i)
121  {
122  if (!strcasecmp(map->dbffieldnames[i], dbfname))
123  {
124  return map->pgfieldnames[i];
125  }
126  }
127  return NULL;
128 }
129 
130 int
131 colmap_read(const char *filename, colmap *map, char *errbuf, size_t errbuflen)
132 {
133  FILE *fptr;
134  char linebuffer[1024];
135  char *tmpstr;
136  int curmapsize, fieldnamesize;
137 
138  /* Read column map file and load the colmap_dbffieldnames
139  * and colmap_pgfieldnames arrays */
140  fptr = fopen(filename, "r");
141  if (!fptr)
142  {
143  /* Return an error */
144  snprintf(errbuf, errbuflen, _("ERROR: Unable to open column map file %s"),
145  filename);
146  return 0;
147  }
148 
149  /* First count how many columns we have... */
150  while (fgets(linebuffer, 1024, fptr) != NULL) ++map->size;
151 
152  /* Now we know the final size, allocate the arrays and load the data */
153  fseek(fptr, 0, SEEK_SET);
154  map->pgfieldnames = (char **)malloc(sizeof(char *) * map->size);
155  map->dbffieldnames = (char **)malloc(sizeof(char *) * map->size);
156 
157  /* Read in a line at a time... */
158  curmapsize = 0;
159  while (fgets(linebuffer, 1024, fptr) != NULL)
160  {
161  /* Split into two separate strings: pgfieldname and dbffieldname */
162  /* First locate end of first column (pgfieldname) */
163  fieldnamesize = strcspn(linebuffer, "\t\n ");
164  tmpstr = linebuffer;
165 
166  /* Allocate memory and copy the string ensuring it is terminated */
167  map->pgfieldnames[curmapsize] = malloc(fieldnamesize + 1);
168  strncpy(map->pgfieldnames[curmapsize], tmpstr, fieldnamesize);
169  map->pgfieldnames[curmapsize][fieldnamesize] = '\0';
170 
171  /* Now swallow up any whitespace */
172  tmpstr = linebuffer + fieldnamesize;
173  tmpstr += strspn(tmpstr, "\t\n ");
174 
175  /* Finally locate end of second column (dbffieldname) */
176  fieldnamesize = strcspn(tmpstr, "\t\n ");
177 
178  /* Allocate memory and copy the string ensuring it is terminated */
179  map->dbffieldnames[curmapsize] = malloc(fieldnamesize + 1);
180  strncpy(map->dbffieldnames[curmapsize], tmpstr, fieldnamesize);
181  map->dbffieldnames[curmapsize][fieldnamesize] = '\0';
182 
183  /* Error out if the dbffieldname is > 10 chars */
184  if (strlen(map->dbffieldnames[curmapsize]) > 10)
185  {
186  snprintf(errbuf, errbuflen, _("ERROR: column map file specifies a DBF field name \"%s\" which is longer than 10 characters"), map->dbffieldnames[curmapsize]);
187  return 0;
188  }
189 
190  ++curmapsize;
191  }
192 
193  fclose(fptr);
194 
195  /* Done; return success */
196  return 1;
197 }
198 
199 /*
200 * Code page info will come out of dbfopen as either a bare codepage number
201 * (e.g. 1256) or as "LDID/1234" from the DBF hreader. We want to look up
202 * the equivalent iconv encoding string so we can use iconv to transcode
203 * the data into UTF8
204 */
205 char *
206 codepage2encoding(const char *cpg)
207 {
208  int cpglen;
209  int is_ldid = 0;
210  int num, i;
211 
212  /* Do nothing on nothing. */
213  if ( ! cpg ) return NULL;
214 
215  /* Is this an LDID string? */
216  /* If so, note it and move past the "LDID/" tag */
217  cpglen = strlen(cpg);
218  if ( strstr(cpg, "LDID/") )
219  {
220  if ( cpglen > 5 )
221  {
222  cpg += 5;
223  is_ldid = 1;
224  }
225  else
226  {
227  return NULL;
228  }
229  }
230 
231  /* Read the number */
232  num = atoi(cpg);
233 
234  /* Can we find this number in our lookup table? */
235  for ( i = is_ldid ; i < num_code_pages; i++ )
236  {
237  if ( is_ldid )
238  {
239  if ( code_pages[i].ldid == num )
240  return strdup(code_pages[i].iconv);
241  }
242  else
243  {
244  if ( code_pages[i].cpg == num )
245  return strdup(code_pages[i].iconv);
246  }
247  }
248 
249  /* Didn't find a matching entry */
250  return NULL;
251 
252 }
253 
254 /*
255 * In the case where data is coming out of the database in some wierd encoding
256 * we want to look up the appropriate code page entry to feed to DBFCreateEx
257 */
258 char *
259 encoding2codepage(const char *encoding)
260 {
261  int i;
262  for ( i = 0; i < num_code_pages; i++ )
263  {
264  if ( strcasecmp(encoding, code_pages[i].pg) == 0 )
265  {
266  if ( code_pages[i].ldid == 0xFF )
267  {
268  return strdup("UTF-8");
269  }
270  else
271  {
272  char *codepage = NULL;
273  asprintf(&codepage, "LDID/%d", code_pages[i].ldid);
274  return codepage;
275  }
276  }
277  }
278 
279  /* OK, we give up, pretend it's UTF8 */
280  return strdup("UTF-8");
281 }
void colmap_clean(colmap *map)
Definition: shpcommon.c:87
int size
Definition: shpcommon.h:140
int colmap_read(const char *filename, colmap *map, char *errbuf, size_t errbuflen)
Read the content of filename into a symbol map.
Definition: shpcommon.c:131
static code_page_entry code_pages[]
Definition: shpcommon.h:43
#define _(String)
Definition: shpcommon.h:24
char * codepage2encoding(const char *cpg)
Definition: shpcommon.c:206
void colmap_init(colmap *map)
Definition: shpcommon.c:79
char ** pgfieldnames
Definition: shpcommon.h:134
char * escape_connection_string(char *str)
Escape strings that are to be used as part of a PostgreSQL connection string.
Definition: shpcommon.c:29
static int num_code_pages
Definition: shpcommon.h:38
char * encoding2codepage(const char *encoding)
Definition: shpcommon.c:259
char ** dbffieldnames
Definition: shpcommon.h:137
const char * colmap_pg_by_dbf(colmap *map, const char *dbfname)
Definition: shpcommon.c:117
void free(void *)
void * malloc(YYSIZE_T)
const char * colmap_dbf_by_pg(colmap *map, const char *pgname)
Definition: shpcommon.c:103