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 27123 : GTIF* GTIFNewEx(void *tif,
77 : GTErrorCallback error_callback, void* user_data)
78 :
79 : {
80 : TIFFMethod default_methods;
81 27123 : _GTIFSetDefaultTIFF( &default_methods );
82 :
83 27123 : 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 27123 : GTIF* GTIFNewWithMethodsEx(void *tif, TIFFMethod* methods,
110 : GTErrorCallback error_callback, void* user_data)
111 : {
112 : TempKeyData tempData;
113 27123 : memset( &tempData, 0, sizeof(tempData) );
114 :
115 27123 : GTIF* gt = (GTIF*)_GTIFcalloc( sizeof(GTIF));
116 27123 : if (!gt) goto failure;
117 :
118 27123 : gt->gt_error_callback = error_callback;
119 27123 : gt->gt_user_data = user_data;
120 :
121 : /* install TIFF file and I/O methods */
122 27123 : gt->gt_tif = (tiff_t *)tif;
123 27123 : memcpy( >->gt_methods, methods, sizeof(TIFFMethod) );
124 :
125 : /* since this is an array, GTIF will allocate the memory */
126 : pinfo_t *data;
127 27123 : if ( tif == NULL
128 27123 : || !(gt->gt_methods.get)(tif, GTIFF_GEOKEYDIRECTORY, >->gt_nshorts, &data ))
129 10430 : {
130 : /* No ProjectionInfo, create a blank one */
131 10430 : data=(pinfo_t*)_GTIFcalloc((4+MAX_VALUES)*sizeof(pinfo_t));
132 10430 : if (!data) goto failure;
133 10430 : KeyHeader *header = (KeyHeader *)data;
134 10430 : header->hdr_version = GvCurrentVersion;
135 10430 : header->hdr_rev_major = GvCurrentRevision;
136 10430 : header->hdr_rev_minor = GvCurrentMinorRev;
137 10430 : gt->gt_nshorts=sizeof(KeyHeader)/sizeof(pinfo_t);
138 : }
139 : else
140 : {
141 : /* resize data array so it can be extended if needed */
142 16693 : data = (pinfo_t*) _GTIFrealloc(data,(4+MAX_VALUES)*sizeof(pinfo_t));
143 : }
144 27123 : gt->gt_short = data;
145 27123 : KeyHeader *header = (KeyHeader *)data;
146 :
147 27123 : if (header->hdr_version > GvCurrentVersion) goto failure;
148 27123 : if (header->hdr_rev_major > GvCurrentRevision)
149 : {
150 : /* issue warning */
151 : }
152 :
153 : /* If we got here, then the geokey can be parsed */
154 27123 : const int count = header->hdr_num_keys;
155 :
156 27123 : if (count * sizeof(KeyEntry) >= (4 + MAX_VALUES) * sizeof(pinfo_t))
157 0 : goto failure;
158 :
159 27123 : gt->gt_num_keys = count;
160 27123 : gt->gt_version = header->hdr_version;
161 27123 : gt->gt_rev_major = header->hdr_rev_major;
162 27123 : gt->gt_rev_minor = header->hdr_rev_minor;
163 :
164 27123 : const int bufcount = count + MAX_KEYS; /* allow for expansion */
165 :
166 : /* Get the PARAMS Tags, if any */
167 27123 : if (tif == NULL
168 27123 : || !(gt->gt_methods.get)(tif, GTIFF_DOUBLEPARAMS,
169 27123 : >->gt_ndoubles, >->gt_double ))
170 : {
171 19048 : gt->gt_double=(double*)_GTIFcalloc(MAX_VALUES*sizeof(double));
172 19048 : if (!gt->gt_double) goto failure;
173 : }
174 : else
175 : {
176 8075 : if( gt->gt_ndoubles > MAX_VALUES )
177 0 : goto failure;
178 : /* resize data array so it can be extended if needed */
179 8075 : gt->gt_double = (double*) _GTIFrealloc(gt->gt_double,
180 : (MAX_VALUES)*sizeof(double));
181 : }
182 :
183 27123 : if ( tif == NULL
184 27123 : || !(gt->gt_methods.get)(tif, GTIFF_ASCIIPARAMS,
185 : &tempData.tk_asciiParamsLength,
186 : &tempData.tk_asciiParams ))
187 : {
188 10832 : tempData.tk_asciiParams = 0;
189 10832 : tempData.tk_asciiParamsLength = 0;
190 : }
191 : else
192 : {
193 : /* last NULL doesn't count; "|" used for delimiter */
194 16291 : if( tempData.tk_asciiParamsLength > 0
195 16291 : && tempData.tk_asciiParams[tempData.tk_asciiParamsLength-1] == '\0')
196 : {
197 16291 : --tempData.tk_asciiParamsLength;
198 : }
199 : }
200 :
201 : /* allocate space for GeoKey array and its index */
202 27123 : gt->gt_keys = (GeoKey *)_GTIFcalloc( sizeof(GeoKey)*bufcount);
203 27123 : if (!gt->gt_keys) goto failure;
204 27123 : gt->gt_keyindex = (int *)_GTIFcalloc( sizeof(int)*(MAX_KEYINDEX+1));
205 27123 : if (!gt->gt_keyindex) goto failure;
206 :
207 : /* Loop to get all GeoKeys */
208 27123 : KeyEntry *entptr = ((KeyEntry *)data) + 1;
209 27123 : GeoKey *keyptr = gt->gt_keys;
210 27123 : gt->gt_keymin = MAX_KEYINDEX;
211 27123 : gt->gt_keymax = 0;
212 134098 : for (int nIndex=1; nIndex<=count; nIndex++,entptr++)
213 : {
214 106975 : if (!ReadKey(gt, &tempData, entptr, ++keyptr))
215 0 : goto failure;
216 :
217 : /* Set up the index (start at 1, since 0=unset) */
218 106975 : gt->gt_keyindex[entptr->ent_key] = nIndex;
219 : }
220 :
221 27123 : if( tempData.tk_asciiParams != NULL )
222 16291 : _GTIFFree( tempData.tk_asciiParams );
223 :
224 27123 : 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 106975 : static int ReadKey(GTIF* gt, TempKeyData* tempData,
246 : KeyEntry* entptr, GeoKey* keyptr)
247 : {
248 106975 : keyptr->gk_key = entptr->ent_key;
249 106975 : keyptr->gk_count = entptr->ent_count;
250 106975 : int count = entptr->ent_count;
251 106975 : const int offset = entptr->ent_val_offset;
252 106975 : if (gt->gt_keymin > keyptr->gk_key) gt->gt_keymin=keyptr->gk_key;
253 106975 : if (gt->gt_keymax < keyptr->gk_key) gt->gt_keymax=keyptr->gk_key;
254 :
255 106975 : if (entptr->ent_location)
256 36608 : keyptr->gk_type = (gt->gt_methods.type)(gt->gt_tif,entptr->ent_location);
257 : else
258 70367 : keyptr->gk_type = (gt->gt_methods.type)(gt->gt_tif,GTIFF_GEOKEYDIRECTORY);
259 :
260 106975 : switch (entptr->ent_location)
261 : {
262 70367 : case GTIFF_LOCAL:
263 : /* store value into data value */
264 70367 : 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 70367 : memcpy(&keyptr->gk_data, &(entptr->ent_val_offset), sizeof(pinfo_t));
278 70367 : 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 17108 : case GTIFF_DOUBLEPARAMS:
297 17108 : keyptr->gk_data = (char *)(gt->gt_double+offset);
298 17108 : 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 17108 : break;
313 19500 : case GTIFF_ASCIIPARAMS:
314 19500 : 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 19500 : 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 19493 : else if (offset < tempData->tk_asciiParamsLength
337 19493 : && 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 19493 : 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 19500 : keyptr->gk_count = MAX(1,count+1);
368 19500 : keyptr->gk_data = (char *) _GTIFcalloc (keyptr->gk_count);
369 :
370 19500 : _GTIFmemcpy (keyptr->gk_data,
371 19500 : tempData->tk_asciiParams + offset, count);
372 19500 : if( keyptr->gk_data[MAX(0,count-1)] == '|' )
373 : {
374 19493 : keyptr->gk_data[MAX(0,count-1)] = '\0';
375 19493 : keyptr->gk_count = count;
376 : }
377 : else
378 7 : keyptr->gk_data[MAX(0,count)] = '\0';
379 19500 : 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 106975 : keyptr->gk_size = _gtiff_size[keyptr->gk_type];
392 :
393 106975 : return 1; /* success */
394 : }
395 :
396 0 : void *GTIFGetUserData(GTIF *gtif)
397 : {
398 0 : return gtif->gt_user_data;
399 : }
|