Coverage Report

Created: 2025-06-22 06:59

/src/gdal/frmts/gtiff/libgeotiff/geo_new.c
Line
Count
Source (jump to first uncovered line)
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
static void GTIFErrorFunction(GTIF* gt, int level, const char* msg, ...)
29
0
{
30
0
    (void)gt;
31
0
    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
GTIF* GTIFNew(void *tif)
71
72
0
{
73
0
    return GTIFNewEx( tif, GTIFErrorFunction, NULL );
74
0
}
75
76
GTIF* GTIFNewEx(void *tif,
77
                GTErrorCallback error_callback, void* user_data)
78
79
0
{
80
0
    TIFFMethod default_methods;
81
0
    _GTIFSetDefaultTIFF( &default_methods );
82
83
0
    return GTIFNewWithMethodsEx( tif, &default_methods,
84
0
                                 error_callback, user_data );
85
0
}
86
87
GTIF *GTIFNewSimpleTags( void *tif )
88
89
0
{
90
0
    TIFFMethod default_methods;
91
0
    GTIFSetSimpleTagsMethods( &default_methods );
92
93
0
    return GTIFNewWithMethods( tif, &default_methods );
94
0
}
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
GTIF* GTIFNewWithMethods(void *tif, TIFFMethod* methods)
105
0
{
106
0
    return GTIFNewWithMethodsEx(tif, methods, GTIFErrorFunction, NULL);
107
0
}
108
109
GTIF* GTIFNewWithMethodsEx(void *tif, TIFFMethod* methods,
110
                           GTErrorCallback error_callback, void* user_data)
111
0
{
112
0
    TempKeyData tempData;
113
0
    memset( &tempData, 0, sizeof(tempData) );
114
115
0
    GTIF* gt = (GTIF*)_GTIFcalloc( sizeof(GTIF));
116
0
    if (!gt) goto failure;
117
118
0
    gt->gt_error_callback = error_callback;
119
0
    gt->gt_user_data = user_data;
120
121
    /* install TIFF file and I/O methods */
122
0
    gt->gt_tif = (tiff_t *)tif;
123
0
    memcpy( &gt->gt_methods, methods, sizeof(TIFFMethod) );
124
125
    /* since this is an array, GTIF will allocate the memory */
126
0
    pinfo_t *data;
127
0
    if ( tif == NULL
128
0
         || !(gt->gt_methods.get)(tif, GTIFF_GEOKEYDIRECTORY, &gt->gt_nshorts, &data ))
129
0
    {
130
        /* No ProjectionInfo, create a blank one */
131
0
        data=(pinfo_t*)_GTIFcalloc((4+MAX_VALUES)*sizeof(pinfo_t));
132
0
        if (!data) goto failure;
133
0
        KeyHeader *header = (KeyHeader *)data;
134
0
        header->hdr_version = GvCurrentVersion;
135
0
        header->hdr_rev_major = GvCurrentRevision;
136
0
        header->hdr_rev_minor = GvCurrentMinorRev;
137
0
        gt->gt_nshorts=sizeof(KeyHeader)/sizeof(pinfo_t);
138
0
    }
139
0
    else
140
0
    {
141
        /* resize data array so it can be extended if needed */
142
0
        data = (pinfo_t*) _GTIFrealloc(data,(4+MAX_VALUES)*sizeof(pinfo_t));
143
0
    }
144
0
    gt->gt_short = data;
145
0
    KeyHeader *header = (KeyHeader *)data;
146
147
0
    if (header->hdr_version > GvCurrentVersion) goto failure;
148
0
    if (header->hdr_rev_major > GvCurrentRevision)
149
0
    {
150
        /* issue warning */
151
0
    }
152
153
    /* If we got here, then the geokey can be parsed */
154
0
    const int count = header->hdr_num_keys;
155
156
0
    if (count * sizeof(KeyEntry) >= (4 + MAX_VALUES) * sizeof(pinfo_t))
157
0
        goto failure;
158
159
0
    gt->gt_num_keys = count;
160
0
    gt->gt_version  = header->hdr_version;
161
0
    gt->gt_rev_major  = header->hdr_rev_major;
162
0
    gt->gt_rev_minor  = header->hdr_rev_minor;
163
164
0
    const int bufcount = count + MAX_KEYS; /* allow for expansion */
165
166
    /* Get the PARAMS Tags, if any */
167
0
    if (tif == NULL
168
0
        || !(gt->gt_methods.get)(tif, GTIFF_DOUBLEPARAMS,
169
0
                                 &gt->gt_ndoubles, &gt->gt_double ))
170
0
    {
171
0
        gt->gt_double=(double*)_GTIFcalloc(MAX_VALUES*sizeof(double));
172
0
        if (!gt->gt_double) goto failure;
173
0
    }
174
0
    else
175
0
    {
176
0
        if( gt->gt_ndoubles > MAX_VALUES )
177
0
            goto failure;
178
        /* resize data array so it can be extended if needed */
179
0
        gt->gt_double = (double*) _GTIFrealloc(gt->gt_double,
180
0
                                               (MAX_VALUES)*sizeof(double));
181
0
    }
182
183
0
    if ( tif == NULL
184
0
         || !(gt->gt_methods.get)(tif, GTIFF_ASCIIPARAMS,
185
0
                                  &tempData.tk_asciiParamsLength,
186
0
                                  &tempData.tk_asciiParams ))
187
0
    {
188
0
        tempData.tk_asciiParams         = 0;
189
0
        tempData.tk_asciiParamsLength   = 0;
190
0
    }
191
0
    else
192
0
    {
193
        /* last NULL doesn't count; "|" used for delimiter */
194
0
        if( tempData.tk_asciiParamsLength > 0
195
0
            && tempData.tk_asciiParams[tempData.tk_asciiParamsLength-1] == '\0')
196
0
        {
197
0
            --tempData.tk_asciiParamsLength;
198
0
        }
199
0
    }
200
201
    /* allocate space for GeoKey array and its index */
202
0
    gt->gt_keys = (GeoKey *)_GTIFcalloc( sizeof(GeoKey)*bufcount);
203
0
    if (!gt->gt_keys) goto failure;
204
0
    gt->gt_keyindex = (int *)_GTIFcalloc( sizeof(int)*(MAX_KEYINDEX+1));
205
0
    if (!gt->gt_keyindex) goto failure;
206
207
    /*  Loop to get all GeoKeys */
208
0
    KeyEntry *entptr = ((KeyEntry *)data) + 1;
209
0
    GeoKey *keyptr = gt->gt_keys;
210
0
    gt->gt_keymin = MAX_KEYINDEX;
211
0
    gt->gt_keymax = 0;
212
0
    for (int nIndex=1; nIndex<=count; nIndex++,entptr++)
213
0
    {
214
0
        if (!ReadKey(gt, &tempData, entptr, ++keyptr))
215
0
            goto failure;
216
217
        /* Set up the index (start at 1, since 0=unset) */
218
0
        gt->gt_keyindex[entptr->ent_key] = nIndex;
219
0
    }
220
221
0
    if( tempData.tk_asciiParams != NULL )
222
0
        _GTIFFree( tempData.tk_asciiParams );
223
224
0
    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
0
}
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
static int ReadKey(GTIF* gt, TempKeyData* tempData,
246
                   KeyEntry* entptr, GeoKey* keyptr)
247
0
{
248
0
    keyptr->gk_key = entptr->ent_key;
249
0
    keyptr->gk_count = entptr->ent_count;
250
0
    int count = entptr->ent_count;
251
0
    const int offset = entptr->ent_val_offset;
252
0
    if (gt->gt_keymin > keyptr->gk_key)  gt->gt_keymin=keyptr->gk_key;
253
0
    if (gt->gt_keymax < keyptr->gk_key)  gt->gt_keymax=keyptr->gk_key;
254
255
0
    if (entptr->ent_location)
256
0
        keyptr->gk_type = (gt->gt_methods.type)(gt->gt_tif,entptr->ent_location);
257
0
    else
258
0
        keyptr->gk_type = (gt->gt_methods.type)(gt->gt_tif,GTIFF_GEOKEYDIRECTORY);
259
260
0
    switch (entptr->ent_location)
261
0
    {
262
0
        case GTIFF_LOCAL:
263
            /* store value into data value */
264
0
            if (count != 1 )
265
0
            {
266
0
                if( gt->gt_error_callback )
267
0
                {
268
0
                    gt->gt_error_callback(
269
0
                        gt,
270
0
                        LIBGEOTIFF_ERROR,
271
0
                        "Key %s of TIFFTagLocation=0 has count=%d, "
272
0
                        "whereas only 1 is legal.",
273
0
                        GTIFKeyName(keyptr->gk_key), count);
274
0
                }
275
0
                return 0;
276
0
            }
277
0
            memcpy(&keyptr->gk_data, &(entptr->ent_val_offset), sizeof(pinfo_t));
278
0
            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
0
            {
283
0
                if( gt->gt_error_callback )
284
0
                {
285
0
                    gt->gt_error_callback(
286
0
                        gt,
287
0
                        LIBGEOTIFF_ERROR,
288
0
                        "Key %s of type SHORT has offset=%d and count=%d, "
289
0
                        "but the GeoKeyDirectory tag has only %d values.",
290
0
                        GTIFKeyName(keyptr->gk_key),
291
0
                        offset, count, gt->gt_nshorts);
292
0
                }
293
0
                return 0;
294
0
            }
295
0
            break;
296
0
        case GTIFF_DOUBLEPARAMS:
297
0
            keyptr->gk_data = (char *)(gt->gt_double+offset);
298
0
            if (gt->gt_ndoubles < offset+count)
299
0
            {
300
0
                if( gt->gt_error_callback )
301
0
                {
302
0
                    gt->gt_error_callback(
303
0
                        gt,
304
0
                        LIBGEOTIFF_ERROR,
305
0
                        "Key %s of type SHORT has offset=%d and count=%d, "
306
0
                        "but the GeoDoubleParams tag has only %d values.",
307
0
                        GTIFKeyName(keyptr->gk_key),
308
0
                        offset, count, gt->gt_ndoubles);
309
0
                }
310
0
                return 0;
311
0
            }
312
0
            break;
313
0
        case GTIFF_ASCIIPARAMS:
314
0
            if( tempData->tk_asciiParams == NULL )
315
0
            {
316
0
                if( gt->gt_error_callback )
317
0
                {
318
0
                    gt->gt_error_callback(
319
0
                        gt,
320
0
                        LIBGEOTIFF_ERROR,
321
0
                        "Key %s is of type ASCII but GeoAsciiParams is "
322
0
                        "missing or corrupted.",
323
0
                        GTIFKeyName(keyptr->gk_key));
324
0
                }
325
0
                return 0;
326
0
            }
327
0
            if( offset + count == tempData->tk_asciiParamsLength + 1
328
0
                && count > 0 )
329
0
            {
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
0
                count--;
335
0
            }
336
0
            else if (offset < tempData->tk_asciiParamsLength
337
0
                     && offset + count > tempData->tk_asciiParamsLength )
338
0
            {
339
0
                if( gt->gt_error_callback )
340
0
                {
341
0
                    gt->gt_error_callback(
342
0
                        gt,
343
0
                        LIBGEOTIFF_WARNING,
344
0
                        "Key %s of type ASCII has offset=%d and count=%d, but "
345
0
                        "the GeoAsciiParams tag has only %d bytes. "
346
0
                        "Truncating the value of the key.",
347
0
                        GTIFKeyName(keyptr->gk_key), offset, count,
348
0
                        tempData->tk_asciiParamsLength);
349
0
                }
350
0
                count = tempData->tk_asciiParamsLength - offset;
351
0
            }
352
0
            else if (offset + count > tempData->tk_asciiParamsLength)
353
0
            {
354
0
                if( gt->gt_error_callback )
355
0
                {
356
0
                    gt->gt_error_callback(
357
0
                        gt,
358
0
                        LIBGEOTIFF_ERROR,
359
0
                        "Key %s of type ASCII has offset=%d and count=%d, "
360
0
                        "but the GeoAsciiParams tag has only %d values.",
361
0
                        GTIFKeyName(keyptr->gk_key), offset, count,
362
0
                        tempData->tk_asciiParamsLength);
363
0
                }
364
0
                return 0;
365
0
            }
366
367
0
            keyptr->gk_count = MAX(1,count+1);
368
0
            keyptr->gk_data = (char *) _GTIFcalloc (keyptr->gk_count);
369
370
0
            _GTIFmemcpy (keyptr->gk_data,
371
0
                         tempData->tk_asciiParams + offset, count);
372
0
            if( keyptr->gk_data[MAX(0,count-1)] == '|' )
373
0
            {
374
0
                keyptr->gk_data[MAX(0,count-1)] = '\0';
375
0
                keyptr->gk_count = count;
376
0
            }
377
0
            else
378
0
                keyptr->gk_data[MAX(0,count)] = '\0';
379
0
            break;
380
0
        default:
381
0
            if( gt->gt_error_callback )
382
0
            {
383
0
                gt->gt_error_callback(
384
0
                    gt,
385
0
                    LIBGEOTIFF_ERROR,
386
0
                    "Key %d of unknown type.",
387
0
                    keyptr->gk_key);
388
0
            }
389
0
            return 0; /* failure */
390
0
    }
391
0
    keyptr->gk_size = _gtiff_size[keyptr->gk_type];
392
393
0
    return 1; /* success */
394
0
}
395
396
void *GTIFGetUserData(GTIF *gtif)
397
0
{
398
0
    return gtif->gt_user_data;
399
0
}