Coverage Report

Created: 2025-11-15 08:43

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