Line data Source code
1 : /**********************************************************************
2 : *
3 : * geo_new.c -- Public routines for GEOTIFF GeoKey access.
4 : *
5 : * Written By: Niles D. Ritter.
6 : *
7 : * copyright (c) 1995 Niles D. Ritter
8 : *
9 : * Permission granted to use this software, so long as this copyright
10 : * notice accompanies any products derived therefrom.
11 : *
12 : **********************************************************************/
13 :
14 : #include <stdarg.h>
15 : #include <stdio.h>
16 : #include <string.h>
17 :
18 : #include "geotiffio.h" /* public interface */
19 : #include "geo_tiffp.h" /* external TIFF interface */
20 : #include "geo_keyp.h" /* private interface */
21 : #include "geo_simpletags.h"
22 :
23 : /* private local routines */
24 : static int ReadKey(GTIF* gt, TempKeyData* tempData,
25 : KeyEntry* entptr, GeoKey* keyptr);
26 :
27 :
28 0 : static void GTIFErrorFunction(GTIF* gt, int level, const char* msg, ...)
29 : {
30 : (void)gt;
31 : va_list list;
32 :
33 0 : va_start(list, msg);
34 0 : if( level == LIBGEOTIFF_WARNING )
35 0 : fprintf(stderr, "Warning: ");
36 0 : else if( level == LIBGEOTIFF_ERROR )
37 0 : fprintf(stderr, "Error: ");
38 0 : vfprintf(stderr, msg, list);
39 0 : fprintf(stderr, "\n");
40 0 : va_end(list);
41 0 : }
42 :
43 : /**********************************************************************
44 : *
45 : * Public Routines
46 : *
47 : **********************************************************************/
48 :
49 :
50 : /**
51 : * Given an open TIFF file, look for GTIF keys and
52 : * values and return GTIF structure.
53 :
54 : This function creates a GeoTIFF information interpretation handle
55 : (GTIF *) based on a passed in TIFF handle originally from
56 : XTIFFOpen(). Even though the argument
57 : (<b>tif</b>) is shown as type <tt>void *</tt>, it is really normally
58 : of type <tt>TIFF *</tt>.<p>
59 :
60 : The returned GTIF handle can be used to read or write GeoTIFF tags
61 : using the various GTIF functions. The handle should be destroyed using
62 : GTIFFree() before the file is closed with TIFFClose().<p>
63 :
64 : If the file accessed has no GeoTIFF keys, an valid (but empty) GTIF is
65 : still returned. GTIFNew() is used both for existing files being read, and
66 : for new TIFF files that will have GeoTIFF tags written to them.<p>
67 :
68 : */
69 :
70 825 : GTIF* GTIFNew(void *tif)
71 :
72 : {
73 825 : return GTIFNewEx( tif, GTIFErrorFunction, NULL );
74 : }
75 :
76 26511 : GTIF* GTIFNewEx(void *tif,
77 : GTErrorCallback error_callback, void* user_data)
78 :
79 : {
80 : TIFFMethod default_methods;
81 26511 : _GTIFSetDefaultTIFF( &default_methods );
82 :
83 26509 : return GTIFNewWithMethodsEx( tif, &default_methods,
84 : error_callback, user_data );
85 : }
86 :
87 0 : GTIF *GTIFNewSimpleTags( void *tif )
88 :
89 : {
90 : TIFFMethod default_methods;
91 0 : GTIFSetSimpleTagsMethods( &default_methods );
92 :
93 0 : return GTIFNewWithMethods( tif, &default_methods );
94 : }
95 :
96 : /************************************************************************/
97 : /* GTIFNewWithMethods() */
98 : /* */
99 : /* Create a new geotiff, passing in the methods structure to */
100 : /* support not libtiff implementations without replacing the */
101 : /* default methods. */
102 : /************************************************************************/
103 :
104 0 : GTIF* GTIFNewWithMethods(void *tif, TIFFMethod* methods)
105 : {
106 0 : return GTIFNewWithMethodsEx(tif, methods, GTIFErrorFunction, NULL);
107 : }
108 :
109 26509 : GTIF* GTIFNewWithMethodsEx(void *tif, TIFFMethod* methods,
110 : GTErrorCallback error_callback, void* user_data)
111 : {
112 : TempKeyData tempData;
113 26509 : memset( &tempData, 0, sizeof(tempData) );
114 :
115 26509 : GTIF* gt = (GTIF*)_GTIFcalloc( sizeof(GTIF));
116 26509 : if (!gt) goto failure;
117 :
118 26509 : gt->gt_error_callback = error_callback;
119 26509 : gt->gt_user_data = user_data;
120 :
121 : /* install TIFF file and I/O methods */
122 26509 : gt->gt_tif = (tiff_t *)tif;
123 26509 : memcpy( >->gt_methods, methods, sizeof(TIFFMethod) );
124 :
125 : /* since this is an array, GTIF will allocate the memory */
126 : pinfo_t *data;
127 26509 : if ( tif == NULL
128 26510 : || !(gt->gt_methods.get)(tif, GTIFF_GEOKEYDIRECTORY, >->gt_nshorts, &data ))
129 10168 : {
130 : /* No ProjectionInfo, create a blank one */
131 10168 : data=(pinfo_t*)_GTIFcalloc((4+MAX_VALUES)*sizeof(pinfo_t));
132 10168 : if (!data) goto failure;
133 10168 : KeyHeader *header = (KeyHeader *)data;
134 10168 : header->hdr_version = GvCurrentVersion;
135 10168 : header->hdr_rev_major = GvCurrentRevision;
136 10168 : header->hdr_rev_minor = GvCurrentMinorRev;
137 10168 : gt->gt_nshorts=sizeof(KeyHeader)/sizeof(pinfo_t);
138 : }
139 : else
140 : {
141 : /* resize data array so it can be extended if needed */
142 16342 : data = (pinfo_t*) _GTIFrealloc(data,(4+MAX_VALUES)*sizeof(pinfo_t));
143 : }
144 26511 : gt->gt_short = data;
145 26511 : KeyHeader *header = (KeyHeader *)data;
146 :
147 26511 : if (header->hdr_version > GvCurrentVersion) goto failure;
148 26511 : if (header->hdr_rev_major > GvCurrentRevision)
149 : {
150 : /* issue warning */
151 : }
152 :
153 : /* If we got here, then the geokey can be parsed */
154 26511 : const int count = header->hdr_num_keys;
155 :
156 26511 : if (count * sizeof(KeyEntry) >= (4 + MAX_VALUES) * sizeof(pinfo_t))
157 0 : goto failure;
158 :
159 26511 : gt->gt_num_keys = count;
160 26511 : gt->gt_version = header->hdr_version;
161 26511 : gt->gt_rev_major = header->hdr_rev_major;
162 26511 : gt->gt_rev_minor = header->hdr_rev_minor;
163 :
164 26511 : const int bufcount = count + MAX_KEYS; /* allow for expansion */
165 :
166 : /* Get the PARAMS Tags, if any */
167 26511 : if (tif == NULL
168 26511 : || !(gt->gt_methods.get)(tif, GTIFF_DOUBLEPARAMS,
169 26511 : >->gt_ndoubles, >->gt_double ))
170 : {
171 18485 : gt->gt_double=(double*)_GTIFcalloc(MAX_VALUES*sizeof(double));
172 18485 : if (!gt->gt_double) goto failure;
173 : }
174 : else
175 : {
176 8026 : if( gt->gt_ndoubles > MAX_VALUES )
177 0 : goto failure;
178 : /* resize data array so it can be extended if needed */
179 8026 : gt->gt_double = (double*) _GTIFrealloc(gt->gt_double,
180 : (MAX_VALUES)*sizeof(double));
181 : }
182 :
183 26511 : if ( tif == NULL
184 26511 : || !(gt->gt_methods.get)(tif, GTIFF_ASCIIPARAMS,
185 : &tempData.tk_asciiParamsLength,
186 : &tempData.tk_asciiParams ))
187 : {
188 10560 : tempData.tk_asciiParams = 0;
189 10560 : tempData.tk_asciiParamsLength = 0;
190 : }
191 : else
192 : {
193 : /* last NULL doesn't count; "|" used for delimiter */
194 15951 : if( tempData.tk_asciiParamsLength > 0
195 15951 : && tempData.tk_asciiParams[tempData.tk_asciiParamsLength-1] == '\0')
196 : {
197 15951 : --tempData.tk_asciiParamsLength;
198 : }
199 : }
200 :
201 : /* allocate space for GeoKey array and its index */
202 26511 : gt->gt_keys = (GeoKey *)_GTIFcalloc( sizeof(GeoKey)*bufcount);
203 26511 : if (!gt->gt_keys) goto failure;
204 26511 : gt->gt_keyindex = (int *)_GTIFcalloc( sizeof(int)*(MAX_KEYINDEX+1));
205 26511 : if (!gt->gt_keyindex) goto failure;
206 :
207 : /* Loop to get all GeoKeys */
208 26511 : KeyEntry *entptr = ((KeyEntry *)data) + 1;
209 26511 : GeoKey *keyptr = gt->gt_keys;
210 26511 : gt->gt_keymin = MAX_KEYINDEX;
211 26511 : gt->gt_keymax = 0;
212 131240 : for (int nIndex=1; nIndex<=count; nIndex++,entptr++)
213 : {
214 104729 : if (!ReadKey(gt, &tempData, entptr, ++keyptr))
215 0 : goto failure;
216 :
217 : /* Set up the index (start at 1, since 0=unset) */
218 104729 : gt->gt_keyindex[entptr->ent_key] = nIndex;
219 : }
220 :
221 26511 : if( tempData.tk_asciiParams != NULL )
222 15951 : _GTIFFree( tempData.tk_asciiParams );
223 :
224 26511 : return gt;
225 :
226 0 : failure:
227 : /* Notify of error */
228 0 : if( tempData.tk_asciiParams != NULL )
229 0 : _GTIFFree( tempData.tk_asciiParams );
230 0 : GTIFFree (gt);
231 0 : return (GTIF *)0;
232 : }
233 :
234 : /**********************************************************************
235 : *
236 : * Private Routines
237 : *
238 : **********************************************************************/
239 :
240 : /*
241 : * Given KeyEntry, read in the GeoKey value location and set up
242 : * the Key structure, returning 0 if failure.
243 : */
244 :
245 104729 : static int ReadKey(GTIF* gt, TempKeyData* tempData,
246 : KeyEntry* entptr, GeoKey* keyptr)
247 : {
248 104729 : keyptr->gk_key = entptr->ent_key;
249 104729 : keyptr->gk_count = entptr->ent_count;
250 104729 : int count = entptr->ent_count;
251 104729 : const int offset = entptr->ent_val_offset;
252 104729 : if (gt->gt_keymin > keyptr->gk_key) gt->gt_keymin=keyptr->gk_key;
253 104729 : if (gt->gt_keymax < keyptr->gk_key) gt->gt_keymax=keyptr->gk_key;
254 :
255 104729 : if (entptr->ent_location)
256 35955 : keyptr->gk_type = (gt->gt_methods.type)(gt->gt_tif,entptr->ent_location);
257 : else
258 68774 : keyptr->gk_type = (gt->gt_methods.type)(gt->gt_tif,GTIFF_GEOKEYDIRECTORY);
259 :
260 104729 : switch (entptr->ent_location)
261 : {
262 68774 : case GTIFF_LOCAL:
263 : /* store value into data value */
264 68774 : if (count != 1 )
265 : {
266 0 : if( gt->gt_error_callback )
267 : {
268 0 : gt->gt_error_callback(
269 : gt,
270 : LIBGEOTIFF_ERROR,
271 : "Key %s of TIFFTagLocation=0 has count=%d, "
272 : "whereas only 1 is legal.",
273 0 : GTIFKeyName(keyptr->gk_key), count);
274 : }
275 0 : return 0;
276 : }
277 68774 : memcpy(&keyptr->gk_data, &(entptr->ent_val_offset), sizeof(pinfo_t));
278 68774 : break;
279 0 : case GTIFF_GEOKEYDIRECTORY:
280 0 : keyptr->gk_data = (char *)(gt->gt_short+offset);
281 0 : if (gt->gt_nshorts < offset+count)
282 : {
283 0 : if( gt->gt_error_callback )
284 : {
285 0 : gt->gt_error_callback(
286 : gt,
287 : LIBGEOTIFF_ERROR,
288 : "Key %s of type SHORT has offset=%d and count=%d, "
289 : "but the GeoKeyDirectory tag has only %d values.",
290 0 : GTIFKeyName(keyptr->gk_key),
291 : offset, count, gt->gt_nshorts);
292 : }
293 0 : return 0;
294 : }
295 0 : break;
296 16910 : case GTIFF_DOUBLEPARAMS:
297 16910 : keyptr->gk_data = (char *)(gt->gt_double+offset);
298 16910 : if (gt->gt_ndoubles < offset+count)
299 : {
300 0 : if( gt->gt_error_callback )
301 : {
302 0 : gt->gt_error_callback(
303 : gt,
304 : LIBGEOTIFF_ERROR,
305 : "Key %s of type SHORT has offset=%d and count=%d, "
306 : "but the GeoDoubleParams tag has only %d values.",
307 0 : GTIFKeyName(keyptr->gk_key),
308 : offset, count, gt->gt_ndoubles);
309 : }
310 0 : return 0;
311 : }
312 16910 : break;
313 19045 : case GTIFF_ASCIIPARAMS:
314 19045 : if( tempData->tk_asciiParams == NULL )
315 : {
316 0 : if( gt->gt_error_callback )
317 : {
318 0 : gt->gt_error_callback(
319 : gt,
320 : LIBGEOTIFF_ERROR,
321 : "Key %s is of type ASCII but GeoAsciiParams is "
322 : "missing or corrupted.",
323 0 : GTIFKeyName(keyptr->gk_key));
324 : }
325 0 : return 0;
326 : }
327 19045 : if( offset + count == tempData->tk_asciiParamsLength + 1
328 7 : && count > 0 )
329 : {
330 : /* some vendors seem to feel they should not use the
331 : terminating '|' char, but do include a terminating '\0'
332 : which we lose in the low level reading code.
333 : If this is the case, drop the extra character */
334 7 : count--;
335 : }
336 19038 : else if (offset < tempData->tk_asciiParamsLength
337 19038 : && offset + count > tempData->tk_asciiParamsLength )
338 : {
339 0 : if( gt->gt_error_callback )
340 : {
341 0 : gt->gt_error_callback(
342 : gt,
343 : LIBGEOTIFF_WARNING,
344 : "Key %s of type ASCII has offset=%d and count=%d, but "
345 : "the GeoAsciiParams tag has only %d bytes. "
346 : "Truncating the value of the key.",
347 0 : GTIFKeyName(keyptr->gk_key), offset, count,
348 : tempData->tk_asciiParamsLength);
349 : }
350 0 : count = tempData->tk_asciiParamsLength - offset;
351 : }
352 19038 : else if (offset + count > tempData->tk_asciiParamsLength)
353 : {
354 0 : if( gt->gt_error_callback )
355 : {
356 0 : gt->gt_error_callback(
357 : gt,
358 : LIBGEOTIFF_ERROR,
359 : "Key %s of type ASCII has offset=%d and count=%d, "
360 : "but the GeoAsciiParams tag has only %d values.",
361 0 : GTIFKeyName(keyptr->gk_key), offset, count,
362 : tempData->tk_asciiParamsLength);
363 : }
364 0 : return 0;
365 : }
366 :
367 19045 : keyptr->gk_count = MAX(1,count+1);
368 19045 : keyptr->gk_data = (char *) _GTIFcalloc (keyptr->gk_count);
369 :
370 19045 : _GTIFmemcpy (keyptr->gk_data,
371 19045 : tempData->tk_asciiParams + offset, count);
372 19045 : if( keyptr->gk_data[MAX(0,count-1)] == '|' )
373 : {
374 19038 : keyptr->gk_data[MAX(0,count-1)] = '\0';
375 19038 : keyptr->gk_count = count;
376 : }
377 : else
378 7 : keyptr->gk_data[MAX(0,count)] = '\0';
379 19045 : break;
380 0 : default:
381 0 : if( gt->gt_error_callback )
382 : {
383 0 : gt->gt_error_callback(
384 : gt,
385 : LIBGEOTIFF_ERROR,
386 : "Key %d of unknown type.",
387 : keyptr->gk_key);
388 : }
389 0 : return 0; /* failure */
390 : }
391 104729 : keyptr->gk_size = _gtiff_size[keyptr->gk_type];
392 :
393 104729 : return 1; /* success */
394 : }
395 :
396 0 : void *GTIFGetUserData(GTIF *gtif)
397 : {
398 0 : return gtif->gt_user_data;
399 : }
|