1 /******************************************************************************
2  * Project:  PROJ.4
3  * Purpose:  Initialize projection object from string definition.  Includes
4  *           pj_init(), pj_init_plus() and pj_free() function.
5  * Author:   Gerald Evenden, Frank Warmerdam <warmerdam@pobox.com>
6  *
7  ******************************************************************************
8  * Copyright (c) 1995, Gerald Evenden
9  * Copyright (c) 2002, Frank Warmerdam <warmerdam@pobox.com>
10  *
11  * Permission is hereby granted, free of charge, to any person obtaining a
12  * copy of this software and associated documentation files (the "Software"),
13  * to deal in the Software without restriction, including without limitation
14  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15  * and/or sell copies of the Software, and to permit persons to whom the
16  * Software is furnished to do so, subject to the following conditions:
17  *
18  * The above copyright notice and this permission notice shall be included
19  * in all copies or substantial portions of the Software.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27  * DEALINGS IN THE SOFTWARE.
28  *****************************************************************************/
29 
30 #define PJ_LIB__
31 #include <projects.h>
32 #include <stdio.h>
33 #include <string.h>
34 #include <errno.h>
35 #include <ctype.h>
36 
37 typedef struct {
38     projCtx ctx;
39     PAFile fid;
40     char buffer[8193];
41     int buffer_filled;
42     int at_eof;
43 } pj_read_state;
44 
45 /************************************************************************/
46 /*                            fill_buffer()                             */
47 /************************************************************************/
48 
fill_buffer(pj_read_state * state,const char * last_char)49 static const char *fill_buffer(pj_read_state *state, const char *last_char)
50 {
51     size_t bytes_read;
52     size_t char_remaining, char_requested;
53 
54 /* -------------------------------------------------------------------- */
55 /*      Don't bother trying to read more if we are at eof, or if the    */
56 /*      buffer is still over half full.                                 */
57 /* -------------------------------------------------------------------- */
58     if (last_char == NULL)
59         last_char = state->buffer;
60 
61     if (state->at_eof)
62         return last_char;
63 
64     char_remaining = state->buffer_filled - (last_char - state->buffer);
65     if (char_remaining >= sizeof(state->buffer) / 2)
66         return last_char;
67 
68 /* -------------------------------------------------------------------- */
69 /*      Move the existing data to the start of the buffer.              */
70 /* -------------------------------------------------------------------- */
71     memmove(state->buffer, last_char, char_remaining);
72     state->buffer_filled = char_remaining;
73     last_char = state->buffer;
74 
75 /* -------------------------------------------------------------------- */
76 /*      Refill.                                                         */
77 /* -------------------------------------------------------------------- */
78     char_requested = sizeof(state->buffer) - state->buffer_filled - 1;
79     bytes_read = pj_ctx_fread( state->ctx, state->buffer + state->buffer_filled,
80                                1, char_requested, state->fid );
81     if (bytes_read < char_requested)
82     {
83         state->at_eof = 1;
84         state->buffer[state->buffer_filled + bytes_read] = '\0';
85     }
86 
87     state->buffer_filled += bytes_read;
88     return last_char;
89 }
90 
91 /************************************************************************/
92 /*                              get_opt()                               */
93 /************************************************************************/
94 static paralist *
get_opt(projCtx ctx,paralist ** start,PAFile fid,char * name,paralist * next,int * found_def)95 get_opt(projCtx ctx, paralist **start, PAFile fid, char *name, paralist *next,
96         int *found_def) {
97     pj_read_state *state = (pj_read_state*) calloc(1,sizeof(pj_read_state));
98     char sword[302];
99     int len;
100     int in_target = 0;
101     const char *next_char = NULL;
102 
103     state->fid = fid;
104     state->ctx = ctx;
105     next_char = fill_buffer(state, NULL);
106     if(found_def)
107         *found_def = 0;
108 
109     len = strlen(name);
110     *sword = 't';
111 
112     /* loop till we find our target keyword */
113     while (*next_char)
114     {
115         next_char = fill_buffer(state, next_char);
116 
117         /* Skip white space. */
118         while( isspace(*next_char) )
119             next_char++;
120 
121         next_char = fill_buffer(state, next_char);
122 
123         /* for comments, skip past end of line. */
124         if( *next_char == '#' )
125         {
126             while( *next_char && *next_char != '\n' )
127                 next_char++;
128 
129             next_char = fill_buffer(state, next_char);
130             if (*next_char == '\n')
131                 next_char++;
132             if (*next_char == '\r')
133                 next_char++;
134 
135         }
136 
137         /* Is this our target? */
138         else if( *next_char == '<' )
139         {
140             /* terminate processing target on the next block definition */
141             if (in_target)
142                 break;
143 
144             next_char++;
145             if (strncmp(name, next_char, len) == 0
146                 && next_char[len] == '>')
147             {
148                 /* skip past target word */
149                 next_char += len + 1;
150                 in_target = 1;
151                 if(found_def)
152                     *found_def = 1;
153             }
154             else
155             {
156                 /* skip past end of line */
157                 while( *next_char && *next_char != '\n' )
158                     next_char++;
159             }
160         }
161         else if (in_target)
162         {
163             const char *start_of_word = next_char;
164             int word_len = 0;
165 
166             if (*start_of_word == '+')
167             {
168                 start_of_word++;
169                 next_char++;
170             }
171 
172             /* capture parameter */
173             while( *next_char && !isspace(*next_char) )
174             {
175                 next_char++;
176                 word_len++;
177             }
178 
179             strncpy(sword+1, start_of_word, word_len);
180             sword[word_len+1] = '\0';
181 
182             /* do not override existing parameter value of same name */
183             if (!pj_param(ctx, *start, sword).i) {
184                 /* don't default ellipse if datum, ellps or any earth model
185                    information is set. */
186                 if( strncmp(sword+1,"ellps=",6) != 0
187                     || (!pj_param(ctx, *start, "tdatum").i
188                         && !pj_param(ctx, *start, "tellps").i
189                         && !pj_param(ctx, *start, "ta").i
190                         && !pj_param(ctx, *start, "tb").i
191                         && !pj_param(ctx, *start, "trf").i
192                         && !pj_param(ctx, *start, "tf").i) )
193                 {
194                     next = next->next = pj_mkparam(sword+1);
195                 }
196             }
197 
198         }
199         else
200         {
201             /* skip past word */
202             while( *next_char && !isspace(*next_char) )
203                 next_char++;
204 
205         }
206     }
207 
208     if (errno == 25)
209         errno = 0;
210 
211     free(state);
212 
213     return next;
214 }
215 
216 /************************************************************************/
217 /*                            get_defaults()                            */
218 /************************************************************************/
219 static paralist *
get_defaults(projCtx ctx,paralist ** start,paralist * next,char * name)220 get_defaults(projCtx ctx, paralist **start, paralist *next, char *name) {
221     PAFile fid;
222 
223     if ( (fid = pj_open_lib(ctx,"proj_def.dat", "rt")) != NULL) {
224         next = get_opt(ctx, start, fid, "general", next, NULL);
225         pj_ctx_fseek(ctx, fid, 0, SEEK_SET);
226         next = get_opt(ctx, start, fid, name, next, NULL);
227         pj_ctx_fclose(ctx, fid);
228     }
229     if (errno)
230         errno = 0; /* don't care if can't open file */
231     ctx->last_errno = 0;
232 
233     return next;
234 }
235 
236 /************************************************************************/
237 /*                              get_init()                              */
238 /************************************************************************/
239 static paralist *
get_init(projCtx ctx,paralist ** start,paralist * next,char * name,int * found_def)240 get_init(projCtx ctx, paralist **start, paralist *next, char *name,
241          int *found_def) {
242     char fname[MAX_PATH_FILENAME+ID_TAG_MAX+3], *opt;
243     PAFile fid;
244     paralist *init_items = NULL;
245     const paralist *orig_next = next;
246 
247     (void)strncpy(fname, name, MAX_PATH_FILENAME + ID_TAG_MAX + 1);
248 
249     /*
250     ** Search for file/key pair in cache
251     */
252 
253     init_items = pj_search_initcache( name );
254     if( init_items != NULL )
255     {
256         next->next = init_items;
257         while( next->next != NULL )
258             next = next->next;
259         *found_def = 1;
260         return next;
261     }
262 
263     /*
264     ** Otherwise we try to open the file and search for it.
265     */
266     if ((opt = strrchr(fname, ':')) != NULL)
267         *opt++ = '\0';
268     else { pj_ctx_set_errno(ctx,-3); return NULL; }
269 
270     if ( (fid = pj_open_lib(ctx,fname, "rt")) != NULL)
271         next = get_opt(ctx, start, fid, opt, next, found_def);
272     else
273         return NULL;
274     pj_ctx_fclose(ctx, fid);
275     if (errno == 25)
276         errno = 0; /* unknown problem with some sys errno<-25 */
277 
278     /*
279     ** If we seem to have gotten a result, insert it into the
280     ** init file cache.
281     */
282     if( next != NULL && next != orig_next )
283         pj_insert_initcache( name, orig_next->next );
284 
285     return next;
286 }
287 
288 /************************************************************************/
289 /*                            pj_init_plus()                            */
290 /*                                                                      */
291 /*      Same as pj_init() except it takes one argument string with      */
292 /*      individual arguments preceeded by '+', such as "+proj=utm       */
293 /*      +zone=11 +ellps=WGS84".                                         */
294 /************************************************************************/
295 
296 PJ *
pj_init_plus(const char * definition)297 pj_init_plus( const char *definition )
298 
299 {
300     return pj_init_plus_ctx( pj_get_default_ctx(), definition );
301 }
302 
303 PJ *
pj_init_plus_ctx(projCtx ctx,const char * definition)304 pj_init_plus_ctx( projCtx ctx, const char *definition )
305 {
306 #define MAX_ARG 200
307     char	*argv[MAX_ARG];
308     char	*defn_copy;
309     int		argc = 0, i, blank_count = 0;
310     PJ	    *result = NULL;
311 
312     /* make a copy that we can manipulate */
313     defn_copy = (char *) pj_malloc( strlen(definition)+1 );
314     strcpy( defn_copy, definition );
315 
316     /* split into arguments based on '+' and trim white space */
317 
318     for( i = 0; defn_copy[i] != '\0'; i++ )
319     {
320         switch( defn_copy[i] )
321         {
322           case '+':
323             if( i == 0 || defn_copy[i-1] == '\0' || blank_count > 0 )
324             {
325                 /* trim trailing spaces from the previous param */
326                 if( blank_count > 0 )
327                 {
328                     defn_copy[i - blank_count] = '\0';
329                     blank_count = 0;
330                 }
331 
332                 if( argc+1 == MAX_ARG )
333                 {
334                     pj_ctx_set_errno( ctx, -44 );
335                     goto bum_call;
336                 }
337 
338                 argv[argc++] = defn_copy + i + 1;
339             }
340             break;
341 
342           case ' ':
343           case '\t':
344           case '\n':
345             /* trim leading spaces from the current param */
346             if( i == 0 || defn_copy[i-1] == '\0' || argc == 0 || argv[argc-1] == defn_copy + i )
347                 defn_copy[i] = '\0';
348             else
349                 blank_count++;
350             break;
351 
352           default:
353             /* reset blank_count */
354             blank_count = 0;
355         }
356     }
357     /* trim trailing spaces from the last param */
358     defn_copy[i - blank_count] = '\0';
359 
360     /* perform actual initialization */
361     result = pj_init_ctx( ctx, argc, argv );
362 
363 bum_call:
364     pj_dalloc( defn_copy );
365 
366     return result;
367 }
368 
369 /************************************************************************/
370 /*                              pj_init()                               */
371 /*                                                                      */
372 /*      Main entry point for initialing a PJ projections                */
373 /*      definition.  Note that the projection specific function is      */
374 /*      called to do the initial allocation so it can be created        */
375 /*      large enough to hold projection specific parameters.            */
376 /************************************************************************/
377 
378 PJ *
pj_init(int argc,char ** argv)379 pj_init(int argc, char **argv) {
380     return pj_init_ctx( pj_get_default_ctx(), argc, argv );
381 }
382 
383 PJ *
pj_init_ctx(projCtx ctx,int argc,char ** argv)384 pj_init_ctx(projCtx ctx, int argc, char **argv) {
385     char *s, *name;
386     paralist *start = NULL;
387     PJ *(*proj)(PJ *);
388     paralist *curr;
389     int i;
390     PJ *PIN = 0;
391 
392     ctx->last_errno = 0;
393     start = NULL;
394 
395     /* put arguments into internal linked list */
396     if (argc <= 0) { pj_ctx_set_errno( ctx, -1 ); goto bum_call; }
397     start = curr = pj_mkparam(argv[0]);
398     for (i = 1; i < argc; ++i) {
399         curr->next = pj_mkparam(argv[i]);
400         curr = curr->next;
401     }
402     if (ctx->last_errno) goto bum_call;
403 
404     /* check if +init present */
405     if (pj_param(ctx, start, "tinit").i) {
406         int found_def = 0;
407 
408         if (!(curr = get_init(ctx,&start, curr,
409                               pj_param(ctx, start, "sinit").s,
410                               &found_def)))
411             goto bum_call;
412         if (!found_def) { pj_ctx_set_errno( ctx, -2); goto bum_call; }
413     }
414 
415     /* find projection selection */
416     if (!(name = pj_param(ctx, start, "sproj").s))
417     { pj_ctx_set_errno( ctx, -4 ); goto bum_call; }
418     for (i = 0; (s = pj_list[i].id) && strcmp(name, s) ; ++i) ;
419     if (!s) { pj_ctx_set_errno( ctx, -5 ); goto bum_call; }
420 
421     /* set defaults, unless inhibited */
422     if (!pj_param(ctx, start, "bno_defs").i)
423         curr = get_defaults(ctx,&start, curr, name);
424     proj = (PJ *(*)(PJ *)) pj_list[i].proj;
425 
426     /* allocate projection structure */
427     if (!(PIN = (*proj)(0))) goto bum_call;
428     PIN->ctx = ctx;
429     PIN->params = start;
430     PIN->is_latlong = 0;
431     PIN->is_geocent = 0;
432     PIN->is_long_wrap_set = 0;
433     PIN->long_wrap_center = 0.0;
434     strcpy( PIN->axis, "enu" );
435 
436     PIN->gridlist = NULL;
437     PIN->gridlist_count = 0;
438 
439     PIN->vgridlist_geoid = NULL;
440     PIN->vgridlist_geoid_count = 0;
441 
442     /* set datum parameters */
443     if (pj_datum_set(ctx, start, PIN)) goto bum_call;
444 
445     /* set ellipsoid/sphere parameters */
446     if (pj_ell_set(ctx, start, &PIN->a, &PIN->es)) goto bum_call;
447 
448     PIN->a_orig = PIN->a;
449     PIN->es_orig = PIN->es;
450 
451     PIN->e = sqrt(PIN->es);
452     PIN->ra = 1. / PIN->a;
453     PIN->one_es = 1. - PIN->es;
454     if (PIN->one_es == 0.) { pj_ctx_set_errno( ctx, -6 ); goto bum_call; }
455     PIN->rone_es = 1./PIN->one_es;
456 
457     /* Now that we have ellipse information check for WGS84 datum */
458     if( PIN->datum_type == PJD_3PARAM
459         && PIN->datum_params[0] == 0.0
460         && PIN->datum_params[1] == 0.0
461         && PIN->datum_params[2] == 0.0
462         && PIN->a == 6378137.0
463         && ABS(PIN->es - 0.006694379990) < 0.000000000050 )/*WGS84/GRS80*/
464     {
465         PIN->datum_type = PJD_WGS84;
466     }
467 
468     /* set PIN->geoc coordinate system */
469     PIN->geoc = (PIN->es && pj_param(ctx, start, "bgeoc").i);
470 
471     /* over-ranging flag */
472     PIN->over = pj_param(ctx, start, "bover").i;
473 
474     /* vertical datum geoid grids */
475     PIN->has_geoid_vgrids = pj_param(ctx, start, "tgeoidgrids").i;
476     if( PIN->has_geoid_vgrids ) /* we need to mark it as used. */
477         pj_param(ctx, start, "sgeoidgrids");
478 
479     /* longitude center for wrapping */
480     PIN->is_long_wrap_set = pj_param(ctx, start, "tlon_wrap").i;
481     if (PIN->is_long_wrap_set)
482         PIN->long_wrap_center = pj_param(ctx, start, "rlon_wrap").f;
483 
484     /* axis orientation */
485     if( (pj_param(ctx, start,"saxis").s) != NULL )
486     {
487         static const char *axis_legal = "ewnsud";
488         const char *axis_arg = pj_param(ctx, start,"saxis").s;
489         if( strlen(axis_arg) != 3 )
490         {
491             pj_ctx_set_errno( ctx, PJD_ERR_AXIS );
492             goto bum_call;
493         }
494 
495         if( strchr( axis_legal, axis_arg[0] ) == NULL
496             || strchr( axis_legal, axis_arg[1] ) == NULL
497             || strchr( axis_legal, axis_arg[2] ) == NULL)
498         {
499             pj_ctx_set_errno( ctx, PJD_ERR_AXIS );
500             goto bum_call;
501         }
502 
503         /* it would be nice to validate we don't have on axis repeated */
504         strcpy( PIN->axis, axis_arg );
505     }
506 
507     PIN->is_long_wrap_set = pj_param(ctx, start, "tlon_wrap").i;
508     if (PIN->is_long_wrap_set)
509         PIN->long_wrap_center = pj_param(ctx, start, "rlon_wrap").f;
510 
511     /* central meridian */
512     PIN->lam0=pj_param(ctx, start, "rlon_0").f;
513 
514     /* central latitude */
515     PIN->phi0 = pj_param(ctx, start, "rlat_0").f;
516 
517     /* false easting and northing */
518     PIN->x0 = pj_param(ctx, start, "dx_0").f;
519     PIN->y0 = pj_param(ctx, start, "dy_0").f;
520 
521     /* general scaling factor */
522     if (pj_param(ctx, start, "tk_0").i)
523         PIN->k0 = pj_param(ctx, start, "dk_0").f;
524     else if (pj_param(ctx, start, "tk").i)
525         PIN->k0 = pj_param(ctx, start, "dk").f;
526     else
527         PIN->k0 = 1.;
528     if (PIN->k0 <= 0.) {
529         pj_ctx_set_errno( ctx, -31 );
530         goto bum_call;
531     }
532 
533     /* set units */
534     s = 0;
535     if ((name = pj_param(ctx, start, "sunits").s) != NULL) {
536         for (i = 0; (s = pj_units[i].id) && strcmp(name, s) ; ++i) ;
537         if (!s) { pj_ctx_set_errno( ctx, -7 ); goto bum_call; }
538         s = pj_units[i].to_meter;
539     }
540     if (s || (s = pj_param(ctx, start, "sto_meter").s)) {
541         PIN->to_meter = pj_strtod(s, &s);
542         if (*s == '/') /* ratio number */
543             PIN->to_meter /= pj_strtod(++s, 0);
544         PIN->fr_meter = 1. / PIN->to_meter;
545     } else
546         PIN->to_meter = PIN->fr_meter = 1.;
547 
548     /* set vertical units */
549     s = 0;
550     if ((name = pj_param(ctx, start, "svunits").s) != NULL) {
551         for (i = 0; (s = pj_units[i].id) && strcmp(name, s) ; ++i) ;
552         if (!s) { pj_ctx_set_errno( ctx, -7 ); goto bum_call; }
553         s = pj_units[i].to_meter;
554     }
555     if (s || (s = pj_param(ctx, start, "svto_meter").s)) {
556         PIN->vto_meter = pj_strtod(s, &s);
557         if (*s == '/') /* ratio number */
558             PIN->vto_meter /= pj_strtod(++s, 0);
559         PIN->vfr_meter = 1. / PIN->vto_meter;
560     } else {
561         PIN->vto_meter = PIN->to_meter;
562         PIN->vfr_meter = PIN->fr_meter;
563     }
564 
565     /* prime meridian */
566     s = 0;
567     if ((name = pj_param(ctx, start, "spm").s) != NULL) {
568         const char *value = NULL;
569         char *next_str = NULL;
570 
571         for (i = 0; pj_prime_meridians[i].id != NULL; ++i )
572         {
573             if( strcmp(name,pj_prime_meridians[i].id) == 0 )
574             {
575                 value = pj_prime_meridians[i].defn;
576                 break;
577             }
578         }
579 
580         if( value == NULL
581             && (dmstor_ctx(ctx,name,&next_str) != 0.0  || *name == '0')
582             && *next_str == '\0' )
583             value = name;
584 
585         if (!value) { pj_ctx_set_errno( ctx, -46 ); goto bum_call; }
586         PIN->from_greenwich = dmstor_ctx(ctx,value,NULL);
587     }
588     else
589         PIN->from_greenwich = 0.0;
590 
591     /* projection specific initialization */
592     if (!(PIN = (*proj)(PIN)) || ctx->last_errno) {
593       bum_call: /* cleanup error return */
594         if (PIN)
595             pj_free(PIN);
596         else
597             for ( ; start; start = curr) {
598                 curr = start->next;
599                 pj_dalloc(start);
600             }
601         PIN = 0;
602     }
603 
604     return PIN;
605 }
606 
607 /************************************************************************/
608 /*                              pj_free()                               */
609 /*                                                                      */
610 /*      This is the application callable entry point for destroying     */
611 /*      a projection definition.  It does work generic to all           */
612 /*      projection types, and then calls the projection specific        */
613 /*      free function (P->pfree()) to do local work.  This maps to      */
614 /*      the FREEUP code in the individual projection source files.      */
615 /************************************************************************/
616 
617 void
pj_free(PJ * P)618 pj_free(PJ *P) {
619     if (P) {
620         paralist *t, *n;
621 
622         /* free parameter list elements */
623         for (t = P->params; t; t = n) {
624             n = t->next;
625             pj_dalloc(t);
626         }
627 
628         /* free array of grid pointers if we have one */
629         if( P->gridlist != NULL )
630             pj_dalloc( P->gridlist );
631 
632         if( P->vgridlist_geoid != NULL )
633             pj_dalloc( P->vgridlist_geoid );
634 
635         if( P->catalog != NULL )
636             pj_dalloc( P->catalog );
637 
638         /* free projection parameters */
639         P->pfree(P);
640     }
641 }
642 
643 
644 
645 
646 
647 
648 
649 
650 /************************************************************************/
651 /*                              pj_prepare()                            */
652 /*                                                                      */
653 /*      Helper function for the PJ_xxxx functions providing the         */
654 /*      projection specific setup for each projection type.             */
655 /*                                                                      */
656 /*      Currently not used, but placed here as part of the  material    */
657 /*      Demonstrating the idea for a future PJ_xxx architecture         */
658 /*      (cf. pj_minimal.c)                                              */
659 /*                                                                      */
660 /************************************************************************/
pj_prepare(PJ * P,const char * description,void (* freeup)(struct PJconsts *),size_t sizeof_struct_opaque)661 void pj_prepare (PJ *P, const char *description, void (*freeup)(struct PJconsts *), size_t sizeof_struct_opaque) {
662     P->descr = description;
663     P->pfree = freeup;
664     P->opaque  = pj_calloc (1, sizeof_struct_opaque);
665 }
666