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