1 /*!
2   \file lib/gis/get_projinfo.c
3 
4   \brief GIS Library - Get projection info
5 
6   (C) 1999-2014 by the GRASS Development Team
7 
8   This program is free software under the GNU General Public License
9   (>=v2). Read the file COPYING that comes with GRASS for details.
10 */
11 
12 #include <string.h>
13 #include <errno.h>
14 #include <unistd.h>
15 #include <stdio.h>
16 #include <grass/gis.h>
17 #include <grass/glocale.h>
18 
19 #define PERMANENT "PERMANENT"
20 
21 /*!
22   \brief Gets units information for location
23 
24   Note: Allocated Key_Value structure should be freed by
25   G_free_key_value().
26 
27   Prints a warning if no units information available.
28 
29   \return pointer to Key_Value structure with key/value pairs
30   \return NULL on failure
31 */
G_get_projunits(void)32 struct Key_Value *G_get_projunits(void)
33 {
34     struct Key_Value *in_units_keys;
35     char path[GPATH_MAX];
36 
37     G_file_name(path, "", UNIT_FILE, PERMANENT);
38     if (access(path, 0) != 0) {
39 	if (G_projection() != PROJECTION_XY) {
40 	    G_warning(_("<%s> file not found for location <%s>"),
41 		      UNIT_FILE, G_location());
42 	}
43 	return NULL;
44     }
45     in_units_keys = G_read_key_value_file(path);
46 
47     return in_units_keys;
48 }
49 
50 /*!
51   \brief Gets projection information for location
52 
53   Note: Allocated Key_Value structure should be freed by
54   G_free_key_value().
55 
56   Prints a warning if no projection information available.
57 
58   \return pointer to Key_Value structure with key/value pairs
59   \return NULL on failure
60 */
G_get_projinfo(void)61 struct Key_Value *G_get_projinfo(void)
62 {
63     struct Key_Value *in_proj_keys, *in_epsg_keys;
64     char path[GPATH_MAX];
65 
66     G_file_name(path, "", PROJECTION_FILE, PERMANENT);
67     if (access(path, 0) != 0) {
68 	if (G_projection() != PROJECTION_XY) {
69 	    G_warning(_("<%s> file not found for location <%s>"),
70 		      PROJECTION_FILE, G_location());
71 	}
72 	return NULL;
73     }
74     in_proj_keys = G_read_key_value_file(path);
75 
76     /* TODO: do not restrict to EPSG as the only authority */
77     if ((in_epsg_keys = G_get_projepsg()) != NULL) {
78 	const char *epsgstr = G_find_key_value("epsg", in_epsg_keys);
79 	char buf[4096];
80 
81 	sprintf(buf, "EPSG:%s", epsgstr);
82 	G_set_key_value("init", buf, in_proj_keys);
83 	G_free_key_value(in_epsg_keys);
84     }
85 
86     return in_proj_keys;
87 }
88 
89 /*!
90   \brief Gets EPSG information for the current location
91 
92   DEPRECATED: Use G_get_projsrid() instead.
93 
94   Note: Allocated Key_Value structure should be freed by
95   G_free_key_value().
96 
97   \return pointer to Key_Value structure with key/value pairs
98   \return NULL when EPSG code is not defined for location
99 */
100 
101 /* superseded by G_get_projsrid(), keep for backwards compatibility */
G_get_projepsg(void)102 struct Key_Value *G_get_projepsg(void)
103 {
104     struct Key_Value *in_epsg_keys;
105     char path[GPATH_MAX];
106 
107     G_file_name(path, "", EPSG_FILE, PERMANENT);
108     if (access(path, 0) != 0) {
109 	if (G_projection() != PROJECTION_XY) {
110             G_debug(1, "<%s> file not found for location <%s>",
111                     EPSG_FILE, G_location());
112 	}
113 	return NULL;
114     }
115     in_epsg_keys = G_read_key_value_file(path);
116 
117     return in_epsg_keys;
118 }
119 
120 /*!
121   \brief Get WKT information for the current location
122 
123   \return pointer to WKT string
124   \return NULL when WKT is not available for the current location
125 */
126 
G_get_projwkt(void)127 char *G_get_projwkt(void)
128 {
129     char *wktstring = NULL;
130     char path[GPATH_MAX];
131     FILE *fp;
132     int n, nalloc;
133     int c;
134 
135     G_file_name(path, "", WKT_FILE, "PERMANENT");
136     if (access(path, 0) != 0) {
137 	if (G_projection() != PROJECTION_XY) {
138 	    G_debug(1, "<%s> file not found for location <%s>",
139 		      WKT_FILE, G_location());
140 	}
141 	return NULL;
142     }
143 
144     fp = fopen(path, "r");
145     if (!fp)
146 	G_fatal_error(_("Unable to open input file <%s>: %s"), path, strerror(errno));
147 
148     wktstring = G_malloc(1024 * sizeof(char));
149     nalloc = 1024;
150 
151     n = 0;
152     while (1) {
153 	c = fgetc(fp);
154 
155 	if (c == EOF) {
156 	    break;
157 	}
158 
159 	if (c == '\r') {	/* DOS or MacOS9 */
160 	    c = fgetc(fp);
161 	    if (c != EOF) {
162 		if (c != '\n') {	/* MacOS9 - we have to return the char to stream */
163 		    ungetc(c, fp);
164 		    c = '\n';
165 		}
166 	    }
167 	    else {	/* MacOS9 - we have to return the char to stream */
168 		ungetc(c, fp);
169 		c = '\n';
170 	    }
171 	}
172 
173 	if (n == nalloc) {
174 	    wktstring = G_realloc(wktstring, nalloc + 1024);
175 	    nalloc += 1024;
176 	}
177 
178 	wktstring[n] = c;
179 
180 	n++;
181     }
182 
183     if (n > 0) {
184 	if (n == nalloc) {
185 	    wktstring = G_realloc(wktstring, nalloc + 1);
186 	    nalloc += 1;
187 	}
188 	wktstring[n] = '\0';
189     }
190     else {
191 	G_free(wktstring);
192 	wktstring = NULL;
193     }
194 
195     if (fclose(fp) != 0)
196 	G_fatal_error(_("Error closing output file <%s>: %s"), path, strerror(errno));
197 
198     if (wktstring && *wktstring)
199 	G_chop(wktstring);
200     if (wktstring && *wktstring == '\0') {
201 	G_free(wktstring);
202 	wktstring = NULL;
203     }
204 
205     return wktstring;
206 }
207 
208 /*!
209   \brief Get srid (spatial reference id) for the current location
210 
211   Typically an srid will be of the form authority NAME:CODE,
212   e.g. EPSG:4326
213 
214   This srid is passed to proj_create() using PROJ or
215   OSRSetFromUserInput() using GDAL. Therefore various other forms of
216   srid are possible, e.g. in OSRSetFromUserInput():
217 
218    1. Well Known Text definition - passed on to importFromWkt().
219    2. "EPSG:n" - number passed on to importFromEPSG().
220    3. "EPSGA:n" - number passed on to importFromEPSGA().
221    4. "AUTO:proj_id,unit_id,lon0,lat0" - WMS auto projections.
222    5. "urn:ogc:def:crs:EPSG::n" - ogc urns
223    6. PROJ.4 definitions - passed on to importFromProj4().
224    7. filename - file read for WKT, XML or PROJ.4 definition.
225    8. well known name accepted by SetWellKnownGeogCS(), such as NAD27, NAD83, WGS84 or WGS72.
226    9. "IGNF:xxxx", "ESRI:xxxx", etc. from definitions from the PROJ database;
227   10. PROJJSON (PROJ >= 6.2)
228 
229   \return pointer to srid string
230   \return NULL when srid is not available for the current location
231 */
232 
G_get_projsrid(void)233 char *G_get_projsrid(void)
234 {
235     char *sridstring = NULL;
236     char path[GPATH_MAX];
237     FILE *fp;
238     int n, nalloc;
239     int c;
240 
241     G_file_name(path, "", SRID_FILE, "PERMANENT");
242     if (access(path, 0) != 0) {
243 	if (G_projection() != PROJECTION_XY) {
244 	    struct Key_Value *projepsg;
245 	    const char *epsg_num;
246 
247 	    G_debug(1, "<%s> file not found for location <%s>",
248 		      SRID_FILE, G_location());
249 
250 	    /* for backwards compatibility, check if PROJ_EPSG exists */
251 	    if ((projepsg = G_get_projepsg()) != NULL) {
252 		epsg_num = G_find_key_value("epsg", projepsg);
253 		if (*epsg_num) {
254 		    G_debug(1, "Using <%s> file instead for location <%s>",
255 			    EPSG_FILE, G_location());
256 		    G_asprintf(&sridstring, "EPSG:%s", epsg_num);
257 		    G_free_key_value(projepsg);
258 
259 		    return sridstring;
260 		}
261 	    }
262 	}
263 	return NULL;
264     }
265 
266     fp = fopen(path, "r");
267     if (!fp)
268 	G_fatal_error(_("Unable to open input file <%s>: %s"), path, strerror(errno));
269 
270     sridstring = G_malloc(1024 * sizeof(char));
271     nalloc = 1024;
272 
273     n = 0;
274     while (1) {
275 	c = fgetc(fp);
276 
277 	if (c == EOF) {
278 	    break;
279 	}
280 
281 	if (c == '\r') {	/* DOS or MacOS9 */
282 	    c = fgetc(fp);
283 	    if (c != EOF) {
284 		if (c != '\n') {	/* MacOS9 - we have to return the char to stream */
285 		    ungetc(c, fp);
286 		    c = '\n';
287 		}
288 	    }
289 	    else {	/* MacOS9 - we have to return the char to stream */
290 		ungetc(c, fp);
291 		c = '\n';
292 	    }
293 	}
294 
295 	if (n == nalloc) {
296 	    sridstring = G_realloc(sridstring, nalloc + 1024);
297 	    nalloc += 1024;
298 	}
299 
300 	sridstring[n] = c;
301 
302 	n++;
303     }
304 
305     if (n > 0) {
306 	if (n == nalloc) {
307 	    sridstring = G_realloc(sridstring, nalloc + 1);
308 	    nalloc += 1;
309 	}
310 	sridstring[n] = '\0';
311     }
312     else {
313 	G_free(sridstring);
314 	sridstring = NULL;
315     }
316 
317     if (fclose(fp) != 0)
318 	G_fatal_error(_("Error closing output file <%s>: %s"), path, strerror(errno));
319 
320     if (sridstring && *sridstring)
321 	G_chop(sridstring);
322     if (sridstring && *sridstring == '\0') {
323 	G_free(sridstring);
324 	sridstring = NULL;
325     }
326 
327     return sridstring;
328 }
329