• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

OSGeo / gdal / 14023130831

23 Mar 2025 09:23PM UTC coverage: 70.463% (+0.01%) from 70.452%
14023130831

Pull #12013

github

web-flow
Merge ba7475e98 into 8eb234d4d
Pull Request #12013: Add gdal raster select/astype/scale/unscale

210 of 214 new or added lines in 12 files covered. (98.13%)

69 existing lines in 34 files now uncovered.

554668 of 787176 relevant lines covered (70.46%)

222369.68 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

68.29
/frmts/nitf/nitfimage.c
1
/******************************************************************************
2
 *
3
 * Project:  NITF Read/Write Library
4
 * Purpose:  Module responsible for implementation of most NITFImage
5
 *           implementation.
6
 * Author:   Frank Warmerdam, warmerdam@pobox.com
7
 *
8
 **********************************************************************
9
 * Copyright (c) 2002, Frank Warmerdam
10
 * Copyright (c) 2007-2013, Even Rouault <even dot rouault at spatialys.com>
11
 *
12
 * SPDX-License-Identifier: MIT
13
 ****************************************************************************/
14

15
#include "gdal.h"
16
#include "nitflib.h"
17
#include "mgrs.h"
18
#include "cpl_vsi.h"
19
#include "cpl_conv.h"
20
#include "cpl_string.h"
21

22
#ifndef CPL_IGNORE_RET_VAL_INT_defined
23
#define CPL_IGNORE_RET_VAL_INT_defined
24

25
CPL_INLINE static void CPL_IGNORE_RET_VAL_INT(CPL_UNUSED int unused)
1,225✔
26
{
27
}
1,225✔
28
#endif
29

30
static int NITFReadIMRFCA(NITFImage *psImage, NITFRPC00BInfo *psRPC);
31
static char *NITFTrimWhite(char *);
32
#ifdef CPL_LSB
33
static void NITFSwapWords(NITFImage *psImage, void *pData, int nWordCount);
34
#endif
35

36
static void NITFLoadLocationTable(NITFImage *psImage);
37
static void NITFLoadColormapSubSection(NITFImage *psImage);
38
static void NITFLoadSubframeMaskTable(NITFImage *psImage);
39
static int NITFLoadVQTables(NITFImage *psImage, int bTryGuessingOffset);
40
static int NITFReadGEOLOB(NITFImage *psImage);
41
static void NITFLoadAttributeSection(NITFImage *psImage);
42
static void NITFPossibleIGEOLOReorientation(NITFImage *psImage);
43

44
void NITFGetGCP(const char *pachCoord, double *pdfXYs, int iCoord);
45
int NITFReadBLOCKA_GCPs(NITFImage *psImage);
46

47
#define GOTO_header_too_small()                                                \
48
    do                                                                         \
49
    {                                                                          \
50
        nFaultyLine = __LINE__;                                                \
51
        goto header_too_small;                                                 \
52
    } while (0)
53

54
#define DIGIT_ZERO '0'
55

56
/************************************************************************/
57
/*                          NITFImageAccess()                           */
58
/************************************************************************/
59

60
NITFImage *NITFImageAccess(NITFFile *psFile, int iSegment)
10,250✔
61

62
{
63
    NITFImage *psImage;
64
    char *pachHeader;
65
    NITFSegmentInfo *psSegInfo;
66
    char szTemp[128];
67
    int nOffset, iBand, i;
68
    int nNICOM;
69
    const char *pszIID1;
70
    int nFaultyLine = -1;
10,250✔
71
    int bGotWrongOffset = FALSE;
10,250✔
72

73
    /* -------------------------------------------------------------------- */
74
    /*      Verify segment, and return existing image accessor if there     */
75
    /*      is one.                                                         */
76
    /* -------------------------------------------------------------------- */
77
    if (iSegment < 0 || iSegment >= psFile->nSegmentCount)
10,250✔
78
        return NULL;
×
79

80
    psSegInfo = psFile->pasSegmentInfo + iSegment;
10,250✔
81

82
    if (!EQUAL(psSegInfo->szSegmentType, "IM"))
10,250✔
83
        return NULL;
×
84

85
    if (psSegInfo->hAccess != NULL)
10,250✔
86
        return (NITFImage *)psSegInfo->hAccess;
496✔
87

88
    /* -------------------------------------------------------------------- */
89
    /*      Read the image subheader.                                       */
90
    /* -------------------------------------------------------------------- */
91
    if (psSegInfo->nSegmentHeaderSize < 370 + 1)
9,754✔
92
    {
93
        CPLError(CE_Failure, CPLE_AppDefined, "Image header too small");
×
94
        return NULL;
×
95
    }
96

97
    pachHeader = (char *)VSI_MALLOC_VERBOSE(psSegInfo->nSegmentHeaderSize);
9,754✔
98
    if (pachHeader == NULL)
9,754✔
99
    {
100
        return NULL;
×
101
    }
102

103
    if (VSIFSeekL(psFile->fp, psSegInfo->nSegmentHeaderStart, SEEK_SET) != 0 ||
9,754✔
104
        VSIFReadL(pachHeader, 1, psSegInfo->nSegmentHeaderSize, psFile->fp) !=
9,754✔
105
            psSegInfo->nSegmentHeaderSize)
9,754✔
106
    {
107
        CPLError(CE_Failure, CPLE_FileIO,
×
108
                 "Failed to read %u byte image subheader from " CPL_FRMT_GUIB
109
                 ".",
110
                 psSegInfo->nSegmentHeaderSize, psSegInfo->nSegmentHeaderStart);
111
        CPLFree(pachHeader);
×
112
        return NULL;
×
113
    }
114

115
    /* -------------------------------------------------------------------- */
116
    /*      Initialize image object.                                        */
117
    /* -------------------------------------------------------------------- */
118
    psImage = (NITFImage *)CPLCalloc(sizeof(NITFImage), 1);
9,754✔
119

120
    psImage->psFile = psFile;
9,754✔
121
    psImage->iSegment = iSegment;
9,754✔
122
    psImage->pachHeader = pachHeader;
9,754✔
123
    psImage->nIXSOFL = -1;
9,754✔
124

125
    psSegInfo->hAccess = psImage;
9,754✔
126

127
/* -------------------------------------------------------------------- */
128
/*      Collect a variety of information as metadata.                   */
129
/* -------------------------------------------------------------------- */
130
#define GetMD(target, hdr, start, length, name)                                \
131
    NITFExtractMetadata(&(target->papszMetadata), hdr, start, length,          \
132
                        "NITF_" #name);
133

134
    if (EQUAL(psFile->szVersion, "NITF02.10") ||
9,754✔
135
        EQUAL(psFile->szVersion, "NSIF01.00"))
53✔
136
    {
137
        GetMD(psImage, pachHeader, 2, 10, IID1);
9,726✔
138
        GetMD(psImage, pachHeader, 12, 14, IDATIM);
9,726✔
139
        GetMD(psImage, pachHeader, 26, 17, TGTID);
9,726✔
140
        GetMD(psImage, pachHeader, 43, 80, IID2);
9,726✔
141
        GetMD(psImage, pachHeader, 123, 1, ISCLAS);
9,726✔
142
        GetMD(psImage, pachHeader, 124, 2, ISCLSY);
9,726✔
143
        GetMD(psImage, pachHeader, 126, 11, ISCODE);
9,726✔
144
        GetMD(psImage, pachHeader, 137, 2, ISCTLH);
9,726✔
145
        GetMD(psImage, pachHeader, 139, 20, ISREL);
9,726✔
146
        GetMD(psImage, pachHeader, 159, 2, ISDCTP);
9,726✔
147
        GetMD(psImage, pachHeader, 161, 8, ISDCDT);
9,726✔
148
        GetMD(psImage, pachHeader, 169, 4, ISDCXM);
9,726✔
149
        GetMD(psImage, pachHeader, 173, 1, ISDG);
9,726✔
150
        GetMD(psImage, pachHeader, 174, 8, ISDGDT);
9,726✔
151
        GetMD(psImage, pachHeader, 182, 43, ISCLTX);
9,726✔
152
        GetMD(psImage, pachHeader, 225, 1, ISCATP);
9,726✔
153
        GetMD(psImage, pachHeader, 226, 40, ISCAUT);
9,726✔
154
        GetMD(psImage, pachHeader, 266, 1, ISCRSN);
9,726✔
155
        GetMD(psImage, pachHeader, 267, 8, ISSRDT);
9,726✔
156
        GetMD(psImage, pachHeader, 275, 15, ISCTLN);
9,726✔
157
        /* skip ENCRYPT - 1 character */
158
        GetMD(psImage, pachHeader, 291, 42, ISORCE);
9,726✔
159
        /* skip NROWS (8), and NCOLS (8) */
160
        GetMD(psImage, pachHeader, 349, 3, PVTYPE);
9,726✔
161
        GetMD(psImage, pachHeader, 352, 8, IREP);
9,726✔
162
        GetMD(psImage, pachHeader, 360, 8, ICAT);
9,726✔
163
        GetMD(psImage, pachHeader, 368, 2, ABPP);
9,726✔
164
        GetMD(psImage, pachHeader, 370, 1, PJUST);
9,726✔
165
    }
166
    else if (EQUAL(psFile->szVersion, "NITF02.00"))
28✔
167
    {
168
        nOffset = 0;
28✔
169
        GetMD(psImage, pachHeader, 2, 10, IID1);
28✔
170
        GetMD(psImage, pachHeader, 12, 14, IDATIM);
28✔
171
        GetMD(psImage, pachHeader, 26, 17, TGTID);
28✔
172
        GetMD(psImage, pachHeader, 43, 80, ITITLE);
28✔
173
        GetMD(psImage, pachHeader, 123, 1, ISCLAS);
28✔
174
        GetMD(psImage, pachHeader, 124, 40, ISCODE);
28✔
175
        GetMD(psImage, pachHeader, 164, 40, ISCTLH);
28✔
176
        GetMD(psImage, pachHeader, 204, 40, ISREL);
28✔
177
        GetMD(psImage, pachHeader, 244, 20, ISCAUT);
28✔
178
        GetMD(psImage, pachHeader, 264, 20, ISCTLN);
28✔
179
        GetMD(psImage, pachHeader, 284, 6, ISDWNG);
28✔
180

181
        if (STARTS_WITH_CI(pachHeader + 284, "999998"))
28✔
182
        {
183
            if (psSegInfo->nSegmentHeaderSize < 370 + 40 + 1)
2✔
184
                GOTO_header_too_small();
×
185
            GetMD(psImage, pachHeader, 290, 40, ISDEVT);
2✔
186
            nOffset += 40;
2✔
187
        }
188

189
        /* skip ENCRYPT - 1 character */
190
        GetMD(psImage, pachHeader, 291 + nOffset, 42, ISORCE);
28✔
191
        /* skip NROWS (8), and NCOLS (8) */
192
        GetMD(psImage, pachHeader, 349 + nOffset, 3, PVTYPE);
28✔
193
        GetMD(psImage, pachHeader, 352 + nOffset, 8, IREP);
28✔
194
        GetMD(psImage, pachHeader, 360 + nOffset, 8, ICAT);
28✔
195
        GetMD(psImage, pachHeader, 368 + nOffset, 2, ABPP);
28✔
196
        GetMD(psImage, pachHeader, 370 + nOffset, 1, PJUST);
28✔
197
    }
198

199
    /* -------------------------------------------------------------------- */
200
    /*      Does this header have the FSDEVT field?                         */
201
    /* -------------------------------------------------------------------- */
202
    nOffset = 333;
9,754✔
203

204
    if (STARTS_WITH_CI(psFile->szVersion, "NITF01.") ||
9,754✔
205
        STARTS_WITH_CI(pachHeader + 284, "999998"))
9,754✔
206
        nOffset += 40;
2✔
207

208
    /* -------------------------------------------------------------------- */
209
    /*      Read lots of header fields.                                     */
210
    /* -------------------------------------------------------------------- */
211
    if (!STARTS_WITH_CI(psFile->szVersion, "NITF01."))
9,754✔
212
    {
213
        if ((int)psSegInfo->nSegmentHeaderSize < nOffset + 35 + 2)
9,754✔
214
            GOTO_header_too_small();
×
215

216
        psImage->nRows = atoi(NITFGetField(szTemp, pachHeader, nOffset, 8));
9,754✔
217
        psImage->nCols = atoi(NITFGetField(szTemp, pachHeader, nOffset + 8, 8));
9,754✔
218

219
        NITFTrimWhite(
9,754✔
220
            NITFGetField(psImage->szPVType, pachHeader, nOffset + 16, 3));
9,754✔
221
        NITFTrimWhite(
9,754✔
222
            NITFGetField(psImage->szIREP, pachHeader, nOffset + 19, 8));
9,754✔
223
        NITFTrimWhite(
9,754✔
224
            NITFGetField(psImage->szICAT, pachHeader, nOffset + 27, 8));
9,754✔
225
        psImage->nABPP =
9,754✔
226
            atoi(NITFGetField(szTemp, pachHeader, nOffset + 35, 2));
9,754✔
227
    }
228

229
    nOffset += 38;
9,754✔
230

231
    /* -------------------------------------------------------------------- */
232
    /*      Do we have IGEOLO information?  In NITF 2.0 (and 1.x) 'N' means */
233
    /*      no information, while in 2.1 this is indicated as ' ', and 'N'  */
234
    /*      means UTM (north).  So for 2.0 products we change 'N' to ' '    */
235
    /*      to conform to 2.1 conventions.                                  */
236
    /* -------------------------------------------------------------------- */
237
    if ((int)psSegInfo->nSegmentHeaderSize < nOffset + 1)
9,754✔
238
        GOTO_header_too_small();
×
239

240
    GetMD(psImage, pachHeader, nOffset, 1, ICORDS);
9,754✔
241

242
    psImage->chICORDS = pachHeader[nOffset++];
9,754✔
243
    psImage->bHaveIGEOLO = FALSE;
9,754✔
244

245
    if ((STARTS_WITH_CI(psFile->szVersion, "NITF02.0") ||
9,754✔
246
         STARTS_WITH_CI(psFile->szVersion, "NITF01.")) &&
9,726✔
247
        psImage->chICORDS == 'N')
28✔
248
        psImage->chICORDS = ' ';
4✔
249

250
    /* -------------------------------------------------------------------- */
251
    /*      Read the image bounds.                                          */
252
    /* -------------------------------------------------------------------- */
253
    if (psImage->chICORDS != ' ')
9,754✔
254
    {
255
        int iCoord;
256

257
        psImage->bHaveIGEOLO = TRUE;
266✔
258
        if ((int)psSegInfo->nSegmentHeaderSize < nOffset + 4 * 15)
266✔
259
            GOTO_header_too_small();
×
260

261
        GetMD(psImage, pachHeader, nOffset, 60, IGEOLO);
266✔
262

263
        psImage->bIsBoxCenterOfPixel = TRUE;
266✔
264
        for (iCoord = 0; iCoord < 4; iCoord++)
1,330✔
265
        {
266
            const char *pszCoordPair = pachHeader + nOffset + iCoord * 15;
1,064✔
267
            double *pdfXY = &(psImage->dfULX) + iCoord * 2;
1,064✔
268

269
            if (psImage->chICORDS == 'N' || psImage->chICORDS == 'S')
1,064✔
270
            {
271
                psImage->nZone = atoi(NITFGetField(szTemp, pszCoordPair, 0, 2));
248✔
272

273
                pdfXY[0] = CPLAtof(NITFGetField(szTemp, pszCoordPair, 2, 6));
248✔
274
                pdfXY[1] = CPLAtof(NITFGetField(szTemp, pszCoordPair, 8, 7));
248✔
275
            }
276
            else if (psImage->chICORDS == 'G' || psImage->chICORDS == 'C')
816✔
277
            {
278
                // It is critical to do the fetching of the D, M, S components
279
                // in 3 separate statements, otherwise if NITFGetField() is
280
                // defined in this compilation unit, the MSVC optimizer will
281
                // generate bad code, due to szTemp being overwritten before
282
                // being evaluated by CPLAtof() !
283
                pdfXY[1] = CPLAtof(NITFGetField(szTemp, pszCoordPair, 0, 2));
776✔
284
                pdfXY[1] +=
776✔
285
                    CPLAtof(NITFGetField(szTemp, pszCoordPair, 2, 2)) / 60.0;
776✔
286
                pdfXY[1] +=
776✔
287
                    CPLAtof(NITFGetField(szTemp, pszCoordPair, 4, 2)) / 3600.0;
776✔
288
                if (pszCoordPair[6] == 's' || pszCoordPair[6] == 'S')
776✔
289
                    pdfXY[1] *= -1;
188✔
290

291
                // It is critical to do the fetching of the D, M, S components
292
                // in 3 separate statements, otherwise if NITFGetField() is
293
                // defined in this compilation unit, the MSVC optimizer will
294
                // generate bad code, due to szTemp being overwritten before
295
                // being evaluated by CPLAtof() !
296
                pdfXY[0] = CPLAtof(NITFGetField(szTemp, pszCoordPair, 7, 3));
776✔
297
                pdfXY[0] +=
776✔
298
                    CPLAtof(NITFGetField(szTemp, pszCoordPair, 10, 2)) / 60.0;
776✔
299
                pdfXY[0] +=
776✔
300
                    CPLAtof(NITFGetField(szTemp, pszCoordPair, 12, 2)) / 3600.0;
776✔
301

302
                if (pszCoordPair[14] == 'w' || pszCoordPair[14] == 'W')
776✔
303
                    pdfXY[0] *= -1;
236✔
304
            }
305
            else if (psImage->chICORDS == 'D')
40✔
306
            { /* 'D' is Decimal Degrees */
307
                pdfXY[1] = CPLAtof(NITFGetField(szTemp, pszCoordPair, 0, 7));
32✔
308
                pdfXY[0] = CPLAtof(NITFGetField(szTemp, pszCoordPair, 7, 8));
32✔
309
            }
310
            else if (psImage->chICORDS == 'U')
8✔
311
            {
312
                /* int err; */
313
                long nZone;
314
                char chHemisphere;
315
                NITFGetField(szTemp, pszCoordPair, 0, 15);
8✔
316

317
                CPLDebug("NITF", "IGEOLO = %15.15s", pszCoordPair);
8✔
318
                /* err = */ Convert_MGRS_To_UTM(szTemp, &nZone, &chHemisphere,
8✔
319
                                                pdfXY + 0, pdfXY + 1);
320

321
                if (chHemisphere == 'S')
8✔
322
                    nZone = -1 * nZone;
×
323

324
                if (psImage->nZone != 0 && psImage->nZone != -100)
8✔
325
                {
326
                    if (nZone != psImage->nZone)
6✔
327
                    {
328
                        CPLError(
×
329
                            CE_Warning, CPLE_AppDefined,
330
                            "Some IGEOLO points are in different UTM\n"
331
                            "zones, but this configuration isn't currently\n"
332
                            "supported by GDAL, ignoring IGEOLO.");
333
                        psImage->nZone = -100;
×
334
                    }
335
                }
336
                else if (psImage->nZone == 0)
2✔
337
                {
338
                    psImage->nZone = (int)nZone;
2✔
339
                }
340
            }
341
        }
342

343
        if (psImage->nZone == -100)
266✔
344
            psImage->nZone = 0;
×
345

346
        nOffset += 60;
266✔
347
    }
348
#undef GetMD
349

350
    /* -------------------------------------------------------------------- */
351
    /*      Should we reorient the IGEOLO points in an attempt to handle    */
352
    /*      files where they were written in the wrong order?               */
353
    /* -------------------------------------------------------------------- */
354
    if (psImage->bHaveIGEOLO)
9,754✔
355
        NITFPossibleIGEOLOReorientation(psImage);
266✔
356

357
    /* -------------------------------------------------------------------- */
358
    /*      Read the image comments.                                        */
359
    /* -------------------------------------------------------------------- */
360
    {
361
        if ((int)psSegInfo->nSegmentHeaderSize < nOffset + 1)
9,754✔
362
            GOTO_header_too_small();
×
363

364
        nNICOM = atoi(NITFGetField(szTemp, pachHeader, nOffset++, 1));
9,754✔
365
        if ((int)psSegInfo->nSegmentHeaderSize < nOffset + 80 * nNICOM)
9,754✔
366
            GOTO_header_too_small();
×
367

368
        char *pszICOM = (char *)CPLMalloc(nNICOM * 80 + 1);
9,754✔
369
        psImage->pszComments =
9,754✔
370
            CPLRecode(NITFGetField(pszICOM, pachHeader, nOffset, 80 * nNICOM),
9,754✔
371
                      CPL_ENC_ISO8859_1, CPL_ENC_UTF8);
372
        CPLFree(pszICOM);
9,754✔
373
        nOffset += nNICOM * 80;
9,754✔
374
    }
375

376
    /* -------------------------------------------------------------------- */
377
    /*      Read more stuff.                                                */
378
    /* -------------------------------------------------------------------- */
379
    if ((int)psSegInfo->nSegmentHeaderSize < nOffset + 2)
9,754✔
380
        GOTO_header_too_small();
×
381

382
    NITFGetField(psImage->szIC, pachHeader, nOffset, 2);
9,754✔
383
    nOffset += 2;
9,754✔
384

385
    if (psImage->szIC[0] != 'N')
9,754✔
386
    {
387
        if ((int)psSegInfo->nSegmentHeaderSize < nOffset + 4)
102✔
388
            GOTO_header_too_small();
×
389

390
        NITFGetField(psImage->szCOMRAT, pachHeader, nOffset, 4);
102✔
391
        nOffset += 4;
102✔
392
    }
393

394
    /* NBANDS */
395
    if ((int)psSegInfo->nSegmentHeaderSize < nOffset + 1)
9,754✔
396
        GOTO_header_too_small();
×
397
    psImage->nBands = atoi(NITFGetField(szTemp, pachHeader, nOffset, 1));
9,754✔
398
    nOffset++;
9,754✔
399

400
    /* XBANDS */
401
    if (psImage->nBands == 0)
9,754✔
402
    {
403
        if ((int)psSegInfo->nSegmentHeaderSize < nOffset + 5)
3✔
404
            GOTO_header_too_small();
×
405
        psImage->nBands = atoi(NITFGetField(szTemp, pachHeader, nOffset, 5));
3✔
406
        nOffset += 5;
3✔
407
    }
408

409
    if (psImage->nBands <= 0)
9,754✔
410
    {
411
        CPLError(CE_Failure, CPLE_AppDefined, "Invalid band number");
×
412
        NITFImageDeaccess(psImage);
×
413
        return NULL;
×
414
    }
415

416
    /* -------------------------------------------------------------------- */
417
    /*      Read per-band information.                                      */
418
    /* -------------------------------------------------------------------- */
419
    psImage->pasBandInfo = (NITFBandInfo *)VSI_CALLOC_VERBOSE(
9,754✔
420
        sizeof(NITFBandInfo), psImage->nBands);
421
    if (psImage->pasBandInfo == NULL)
9,754✔
422
    {
423
        NITFImageDeaccess(psImage);
×
424
        return NULL;
×
425
    }
426

427
    for (iBand = 0; iBand < psImage->nBands; iBand++)
229,813✔
428
    {
429
        NITFBandInfo *psBandInfo = psImage->pasBandInfo + iBand;
220,059✔
430
        int nLUTS;
431

432
        if ((int)psSegInfo->nSegmentHeaderSize < nOffset + 2 + 6 + 4 + 1 + 5)
220,059✔
433
            GOTO_header_too_small();
×
434

435
        NITFTrimWhite(
220,059✔
436
            NITFGetField(psBandInfo->szIREPBAND, pachHeader, nOffset, 2));
220,059✔
437
        nOffset += 2;
220,059✔
438

439
        NITFTrimWhite(
220,059✔
440
            NITFGetField(psBandInfo->szISUBCAT, pachHeader, nOffset, 6));
220,059✔
441
        nOffset += 6;
220,059✔
442

443
        nOffset += 4; /* Skip IFCn and IMFLTn */
220,059✔
444

445
        nLUTS = atoi(NITFGetField(szTemp, pachHeader, nOffset, 1));
220,059✔
446
        nOffset += 1;
220,059✔
447

448
        if (nLUTS == 0)
220,059✔
449
            continue;
220,025✔
450

451
        psBandInfo->nSignificantLUTEntries =
34✔
452
            atoi(NITFGetField(szTemp, pachHeader, nOffset, 5));
34✔
453
        nOffset += 5;
34✔
454

455
        if (psBandInfo->nSignificantLUTEntries < 0 ||
34✔
456
            psBandInfo->nSignificantLUTEntries > 256)
34✔
457
        {
458
            CPLError(CE_Warning, CPLE_AppDefined,
×
459
                     "LUT for band %d is corrupted : "
460
                     "nSignificantLUTEntries=%d. Truncating to 256",
461
                     iBand + 1, psBandInfo->nSignificantLUTEntries);
462
            psBandInfo->nSignificantLUTEntries = 256;
×
463
        }
464

465
        psBandInfo->nLUTLocation =
34✔
466
            nOffset + (int)psSegInfo->nSegmentHeaderStart;
34✔
467

468
        psBandInfo->pabyLUT = (unsigned char *)CPLCalloc(768, 1);
34✔
469

470
        if ((int)psSegInfo->nSegmentHeaderSize <
34✔
471
            nOffset + nLUTS * psBandInfo->nSignificantLUTEntries)
34✔
472
            GOTO_header_too_small();
×
473

474
        memcpy(psBandInfo->pabyLUT, pachHeader + nOffset,
34✔
475
               psBandInfo->nSignificantLUTEntries);
34✔
476
        nOffset += psBandInfo->nSignificantLUTEntries;
34✔
477

478
        if (nLUTS == 3)
34✔
479
        {
480
            memcpy(psBandInfo->pabyLUT + 256, pachHeader + nOffset,
34✔
481
                   psBandInfo->nSignificantLUTEntries);
34✔
482
            nOffset += psBandInfo->nSignificantLUTEntries;
34✔
483

484
            memcpy(psBandInfo->pabyLUT + 512, pachHeader + nOffset,
34✔
485
                   psBandInfo->nSignificantLUTEntries);
34✔
486
            nOffset += psBandInfo->nSignificantLUTEntries;
34✔
487
        }
488
        else if ((nLUTS == 2) && (STARTS_WITH_CI(psImage->szIREP, "MONO")) &&
×
489
                 ((STARTS_WITH_CI(psBandInfo->szIREPBAND, "M")) ||
×
490
                  (STARTS_WITH_CI(psBandInfo->szIREPBAND, "LU"))))
×
491
        {
×
492
            int iLUTEntry;
493
            double scale = 255.0 / 65535.0;
×
494
            unsigned char *pMSB = NULL;
×
495
            unsigned char *pLSB = NULL;
×
496
            unsigned char *p3rdLUT = NULL;
×
497
            unsigned char scaledVal = 0;
×
498
            unsigned short *pLUTVal = NULL;
×
499

500
            /* In this case, we have two LUTs. The first and second LUTs should
501
             * map respectively to the most */
502
            /* significant byte and the least significant byte of the 16 bit
503
             * values. */
504

505
            memcpy(psBandInfo->pabyLUT + 256, pachHeader + nOffset,
×
506
                   psBandInfo->nSignificantLUTEntries);
×
507
            nOffset += psBandInfo->nSignificantLUTEntries;
×
508

509
            pMSB = psBandInfo->pabyLUT;
×
510
            pLSB = psBandInfo->pabyLUT + 256;
×
511
            p3rdLUT = psBandInfo->pabyLUT + 512;
×
512
            /* E. Rouault: Why 255 and not 256 ? */
513
            pLUTVal = (unsigned short *)CPLMalloc(sizeof(short) * 255);
×
514

515
            for (iLUTEntry = 0; iLUTEntry < 255; ++iLUTEntry)
×
516
            {
517
                /* E. Rouault: I don't understand why the following logic is
518
                 * endianness dependent. */
519
                pLUTVal[iLUTEntry] = ((pMSB[iLUTEntry] << 8) | pLSB[iLUTEntry]);
×
520
#ifdef CPL_LSB
521
                pLUTVal[iLUTEntry] =
×
522
                    ((pLUTVal[iLUTEntry] >> 8) | (pLUTVal[iLUTEntry] << 8));
×
523
#endif
524
            }
525

526
            for (iLUTEntry = 0; iLUTEntry < 255; ++iLUTEntry)
×
527
            {
528
                scaledVal =
×
529
                    (unsigned char)ceil((double)(pLUTVal[iLUTEntry] * scale));
×
530

531
                pMSB[iLUTEntry] = scaledVal;
×
532
                pLSB[iLUTEntry] = scaledVal;
×
533
                p3rdLUT[iLUTEntry] = scaledVal;
×
534
            }
535

536
            CPLFree(pLUTVal);
×
537
        }
538
        else
539
        {
540
            /* morph greyscale lut into RGB LUT. */
541
            memcpy(psBandInfo->pabyLUT + 256, psBandInfo->pabyLUT, 256);
×
542
            memcpy(psBandInfo->pabyLUT + 512, psBandInfo->pabyLUT, 256);
×
543
        }
544
    }
545

546
    /* -------------------------------------------------------------------- */
547
    /*      Some files (i.e. NSIF datasets) have truncated image              */
548
    /*      headers.  This has been observed with JPEG compressed           */
549
    /*      files.  In this case guess reasonable values for these          */
550
    /*      fields.                                                         */
551
    /* -------------------------------------------------------------------- */
552
    if (nOffset + 40 > (int)psSegInfo->nSegmentHeaderSize)
9,754✔
553
    {
554
        psImage->chIMODE = 'B';
×
555
        psImage->nBlocksPerRow = 1;
×
556
        psImage->nBlocksPerColumn = 1;
×
557
        psImage->nBlockWidth = psImage->nCols;
×
558
        psImage->nBlockHeight = psImage->nRows;
×
559
        psImage->nBitsPerSample = psImage->nABPP;
×
560
        psImage->nIDLVL = 0;
×
561
        psImage->nIALVL = 0;
×
562
        psImage->nILOCRow = 0;
×
563
        psImage->nILOCColumn = 0;
×
564
        psImage->szIMAG[0] = '\0';
×
565

566
        nOffset += 40;
×
567
    }
568

569
    /* -------------------------------------------------------------------- */
570
    /*      Read more header fields.                                        */
571
    /* -------------------------------------------------------------------- */
572
    else
573
    {
574
        psImage->chIMODE = pachHeader[nOffset + 1];
9,754✔
575

576
        psImage->nBlocksPerRow =
9,754✔
577
            atoi(NITFGetField(szTemp, pachHeader, nOffset + 2, 4));
9,754✔
578
        psImage->nBlocksPerColumn =
9,754✔
579
            atoi(NITFGetField(szTemp, pachHeader, nOffset + 6, 4));
9,754✔
580
        psImage->nBlockWidth =
9,754✔
581
            atoi(NITFGetField(szTemp, pachHeader, nOffset + 10, 4));
9,754✔
582
        psImage->nBlockHeight =
9,754✔
583
            atoi(NITFGetField(szTemp, pachHeader, nOffset + 14, 4));
9,754✔
584

585
        /* See MIL-STD-2500-C, paragraph 5.4.2.2-d (#3263) */
586
        if (psImage->nBlocksPerRow == 1 && psImage->nBlockWidth == 0)
9,754✔
587
        {
588
            psImage->nBlockWidth = psImage->nCols;
5✔
589
        }
590

591
        if (psImage->nBlocksPerColumn == 1 && psImage->nBlockHeight == 0)
9,754✔
592
        {
593
            psImage->nBlockHeight = psImage->nRows;
7✔
594
        }
595

596
        psImage->nBitsPerSample =
9,754✔
597
            atoi(NITFGetField(szTemp, pachHeader, nOffset + 18, 2));
9,754✔
598

599
        if (psImage->nABPP == 0)
9,754✔
600
            psImage->nABPP = psImage->nBitsPerSample;
×
601

602
        nOffset += 20;
9,754✔
603

604
        /* capture image inset information */
605

606
        psImage->nIDLVL =
9,754✔
607
            atoi(NITFGetField(szTemp, pachHeader, nOffset + 0, 3));
9,754✔
608
        psImage->nIALVL =
9,754✔
609
            atoi(NITFGetField(szTemp, pachHeader, nOffset + 3, 3));
9,754✔
610
        psImage->nILOCRow =
9,754✔
611
            atoi(NITFGetField(szTemp, pachHeader, nOffset + 6, 5));
9,754✔
612
        psImage->nILOCColumn =
9,754✔
613
            atoi(NITFGetField(szTemp, pachHeader, nOffset + 11, 5));
9,754✔
614

615
        memcpy(psImage->szIMAG, pachHeader + nOffset + 16, 4);
9,754✔
616
        psImage->szIMAG[4] = '\0';
9,754✔
617

618
        nOffset += 3;  /* IDLVL */
9,754✔
619
        nOffset += 3;  /* IALVL */
9,754✔
620
        nOffset += 10; /* ILOC */
9,754✔
621
        nOffset += 4;  /* IMAG */
9,754✔
622
    }
623

624
    if (psImage->nBitsPerSample <= 0 || psImage->nBlocksPerRow <= 0 ||
9,754✔
625
        psImage->nBlocksPerColumn <= 0 || psImage->nBlockWidth <= 0 ||
9,754✔
626
        psImage->nBlockHeight <= 0 ||
9,754✔
627
        psImage->nBlocksPerRow > INT_MAX / psImage->nBlockWidth ||
9,754✔
628
        psImage->nBlocksPerColumn > INT_MAX / psImage->nBlockHeight ||
9,754✔
629
        psImage->nCols > psImage->nBlocksPerRow * psImage->nBlockWidth ||
9,754✔
630
        psImage->nRows > psImage->nBlocksPerColumn * psImage->nBlockHeight ||
9,754✔
631
        psImage->nBlocksPerRow > INT_MAX / psImage->nBlocksPerColumn ||
9,754✔
632
        psImage->nBlocksPerRow * psImage->nBlocksPerColumn >
9,754✔
633
            INT_MAX / psImage->nBands)
9,754✔
634
    {
635
        CPLError(CE_Failure, CPLE_AppDefined,
×
636
                 "Invalid values for block dimension/number");
637
        NITFImageDeaccess(psImage);
×
638
        return NULL;
×
639
    }
640

641
    if (psImage->nBlocksPerRow * psImage->nBlocksPerColumn * psImage->nBands >
9,754✔
642
        1000 * 1000)
643
    {
644
        // Sanity check to avoid allocating too much memory
645
        VSIFSeekL(psFile->fp, 0, SEEK_END);
×
646
        // This is really a very safe bound. A smarter check would taken
647
        // into account the block size as well and/or the size of an entry
648
        // in the offset table.
649
        if (VSIFTellL(psFile->fp) <
×
650
            (vsi_l_offset)(psImage->nBlocksPerRow) * psImage->nBlocksPerColumn)
×
651
        {
652
            CPLError(CE_Failure, CPLE_AppDefined,
×
653
                     "File is too small compared to the number of blocks");
654
            NITFImageDeaccess(psImage);
×
655
            return NULL;
×
656
        }
657
    }
658

659
    /* -------------------------------------------------------------------- */
660
    /*      Override nCols and nRows for NITF 1.1 (not sure why!)           */
661
    /* -------------------------------------------------------------------- */
662
    if (STARTS_WITH_CI(psFile->szVersion, "NITF01."))
9,754✔
663
    {
664
        psImage->nCols = psImage->nBlocksPerRow * psImage->nBlockWidth;
×
665
        psImage->nRows = psImage->nBlocksPerColumn * psImage->nBlockHeight;
×
666
    }
667

668
    /* -------------------------------------------------------------------- */
669
    /*      Read TREs if we have them.                                      */
670
    /* -------------------------------------------------------------------- */
671
    else if (nOffset + 10 <= (int)psSegInfo->nSegmentHeaderSize)
9,754✔
672
    {
673
        int nUserTREBytes, nExtendedTREBytes, nFirstTagUsedLength = 0;
9,754✔
674

675
        /* --------------------------------------------------------------------
676
         */
677
        /*      Are there user TRE bytes to skip? */
678
        /* --------------------------------------------------------------------
679
         */
680
        nUserTREBytes = atoi(NITFGetField(szTemp, pachHeader, nOffset, 5));
9,754✔
681
        nOffset += 5;
9,754✔
682

683
        if (nUserTREBytes > 3 + 11) /* Must have at least one tag */
9,754✔
684
        {
685
            if ((int)psSegInfo->nSegmentHeaderSize < nOffset + nUserTREBytes)
26✔
686
                GOTO_header_too_small();
×
687

688
            psImage->nTREBytes = nUserTREBytes - 3;
26✔
689
            psImage->pachTRE = (char *)CPLMalloc(psImage->nTREBytes);
26✔
690
            memcpy(psImage->pachTRE, pachHeader + nOffset + 3,
26✔
691
                   psImage->nTREBytes);
26✔
692

693
            nOffset += nUserTREBytes;
26✔
694

695
            sscanf(psImage->pachTRE + 6, "%*5d%n", &nFirstTagUsedLength);
26✔
696
            if (nFirstTagUsedLength != 5)
26✔
697
            {
698
                CPLError(CE_Warning, CPLE_AppDefined,
1✔
699
                         "Cannot read User TRE. First tag's length is invalid");
700
                CPLFree(psImage->pachTRE);
1✔
701
                psImage->nTREBytes = 0;
1✔
702
                psImage->pachTRE = NULL;
1✔
703
            }
704
        }
705
        else
706
        {
707
            psImage->nTREBytes = 0;
9,728✔
708
            psImage->pachTRE = NULL;
9,728✔
709

710
            if (nUserTREBytes > 0)
9,728✔
711
                nOffset += nUserTREBytes;
×
712
        }
713

714
        /* --------------------------------------------------------------------
715
         */
716
        /*      Are there managed TRE bytes to recognise? */
717
        /* --------------------------------------------------------------------
718
         */
719
        if ((int)psSegInfo->nSegmentHeaderSize < nOffset + 5)
9,754✔
720
            GOTO_header_too_small();
×
721
        nExtendedTREBytes = atoi(NITFGetField(szTemp, pachHeader, nOffset, 5));
9,754✔
722
        nOffset += 5;
9,754✔
723

724
        if (nExtendedTREBytes >= 3)
9,754✔
725
        {
726
            if ((int)psSegInfo->nSegmentHeaderSize <
201✔
727
                nOffset + nExtendedTREBytes)
201✔
728
                GOTO_header_too_small();
×
729

730
            psImage->nIXSOFLOffsetInSubfileHeader = nOffset;
201✔
731
            char szIXSOFL[4];
732
            memcpy(szIXSOFL, pachHeader + nOffset, 3);
201✔
733
            szIXSOFL[3] = 0;
201✔
734
            psImage->nIXSOFL = atoi(szIXSOFL);
201✔
735
            if (psImage->nIXSOFL != 0)
201✔
736
                psImage->papszMetadata = CSLSetNameValue(
3✔
737
                    psImage->papszMetadata, "NITF_IXSOFL", szIXSOFL);
738

739
            if (nExtendedTREBytes > 3)
201✔
740
            {
741
                psImage->pachTRE = (char *)CPLRealloc(
388✔
742
                    psImage->pachTRE,
194✔
743
                    psImage->nTREBytes + nExtendedTREBytes - 3);
194✔
744
                memcpy(psImage->pachTRE + psImage->nTREBytes,
194✔
745
                       pachHeader + nOffset + 3, nExtendedTREBytes - 3);
194✔
746

747
                psImage->nTREBytes += (nExtendedTREBytes - 3);
194✔
748
            }
749
            /*nOffset += nExtendedTREBytes;*/
750
        }
751
    }
752

753
    /* -------------------------------------------------------------------- */
754
    /*      Is there a location table to load?                              */
755
    /* -------------------------------------------------------------------- */
756
    NITFLoadLocationTable(psImage);
9,754✔
757

758
    /* Fix bug #1744 */
759
    if (psImage->nBands == 1)
9,754✔
760
        NITFLoadColormapSubSection(psImage);
9,598✔
761

762
    /* -------------------------------------------------------------------- */
763
    /*      Setup some image access values.  Some of these may not apply    */
764
    /*      for compressed images, or band interleaved by block images.     */
765
    /* -------------------------------------------------------------------- */
766
    if (psImage->nBitsPerSample <= 8)
9,754✔
767
        psImage->nWordSize = 1;
9,654✔
768
    else if (psImage->nBitsPerSample <= 16)
100✔
769
        psImage->nWordSize = 2;
56✔
770
    else if (psImage->nBitsPerSample <= 32)
44✔
771
        psImage->nWordSize = 4;
31✔
772
    else
773
        psImage->nWordSize = psImage->nBitsPerSample / 8;
13✔
774
    if (psImage->chIMODE == 'S')
9,754✔
775
    {
776
        psImage->nPixelOffset = psImage->nWordSize;
×
777
        psImage->nLineOffset =
×
778
            ((GIntBig)psImage->nBlockWidth * psImage->nBitsPerSample) / 8;
×
779
        psImage->nBlockOffset = psImage->nLineOffset * psImage->nBlockHeight;
×
780
        psImage->nBandOffset = psImage->nBlockOffset * psImage->nBlocksPerRow *
×
781
                               psImage->nBlocksPerColumn;
×
782
    }
783
    else if (psImage->chIMODE == 'P')
9,754✔
784
    {
785
        psImage->nPixelOffset = (GIntBig)psImage->nWordSize * psImage->nBands;
25✔
786
        psImage->nLineOffset = ((GIntBig)psImage->nBlockWidth *
25✔
787
                                psImage->nBitsPerSample * psImage->nBands) /
25✔
788
                               8;
789
        psImage->nBandOffset = psImage->nWordSize;
25✔
790
        psImage->nBlockOffset = psImage->nLineOffset * psImage->nBlockHeight;
25✔
791
    }
792
    else if (psImage->chIMODE == 'R')
9,729✔
793
    {
794
        psImage->nPixelOffset = psImage->nWordSize;
×
795
        psImage->nBandOffset =
×
796
            ((GIntBig)psImage->nBlockWidth * psImage->nBitsPerSample) / 8;
×
797
        psImage->nLineOffset = psImage->nBandOffset * psImage->nBands;
×
798
        psImage->nBlockOffset = psImage->nLineOffset * psImage->nBlockHeight;
×
799
    }
800
    else /* if( psImage->chIMODE == 'B' ) */
801
    {
802
        psImage->nPixelOffset = psImage->nWordSize;
9,729✔
803
        psImage->nLineOffset =
9,729✔
804
            ((GIntBig)psImage->nBlockWidth * psImage->nBitsPerSample) / 8;
9,729✔
805
        psImage->nBandOffset = psImage->nBlockHeight * psImage->nLineOffset;
9,729✔
806
        psImage->nBlockOffset = psImage->nBandOffset * psImage->nBands;
9,729✔
807
    }
808

809
    /* -------------------------------------------------------------------- */
810
    /*      Setup block map.                                                */
811
    /* -------------------------------------------------------------------- */
812

813
    /* Int overflow already checked above */
814
    psImage->panBlockStart = (GUIntBig *)VSI_CALLOC_VERBOSE(
9,754✔
815
        (size_t)psImage->nBlocksPerRow * psImage->nBlocksPerColumn *
816
            psImage->nBands,
817
        sizeof(GUIntBig));
818
    if (psImage->panBlockStart == NULL)
9,754✔
819
    {
820
        NITFImageDeaccess(psImage);
×
821
        return NULL;
×
822
    }
823

824
    /* -------------------------------------------------------------------- */
825
    /*      Offsets to VQ compressed tiles are based on a fixed block       */
826
    /*      size, and are offset from the spatial data location kept in     */
827
    /*      the location table ... which is generally not the beginning     */
828
    /*      of the image data segment.                                      */
829
    /* -------------------------------------------------------------------- */
830
    if (EQUAL(psImage->szIC, "C4"))
9,754✔
831
    {
832
        GUIntBig nLocBase = psSegInfo->nSegmentStart;
23✔
833

834
        for (i = 0; i < psImage->nLocCount; i++)
253✔
835
        {
836
            if (psImage->pasLocations[i].nLocId == LID_SpatialDataSubsection)
230✔
837
                nLocBase = psImage->pasLocations[i].nLocOffset;
23✔
838
        }
839

840
        if (nLocBase == psSegInfo->nSegmentStart)
23✔
841
            CPLError(CE_Warning, CPLE_AppDefined,
×
842
                     "Failed to find spatial data location, guessing.");
843

844
        for (i = 0; i < psImage->nBlocksPerRow * psImage->nBlocksPerColumn; i++)
851✔
845
            psImage->panBlockStart[i] = nLocBase + (GUIntBig)(6144) * i;
828✔
846
    }
847

848
    /* -------------------------------------------------------------------- */
849
    /*      If there is no block map, just compute directly assuming the    */
850
    /*      blocks start at the beginning of the image segment, and are     */
851
    /*      packed tightly with the IMODE organization.                     */
852
    /* -------------------------------------------------------------------- */
853
    else if (psImage->szIC[0] != 'M' && psImage->szIC[1] != 'M')
9,731✔
854
    {
9,723✔
855
        int iBlockX, iBlockY;
856

857
        for (iBlockY = 0; iBlockY < psImage->nBlocksPerColumn; iBlockY++)
19,577✔
858
        {
859
            for (iBlockX = 0; iBlockX < psImage->nBlocksPerRow; iBlockX++)
21,454✔
860
            {
861
                for (iBand = 0; iBand < psImage->nBands; iBand++)
237,051✔
862
                {
863
                    int iBlock;
864

865
                    iBlock = iBlockX + iBlockY * psImage->nBlocksPerRow +
225,451✔
866
                             iBand * psImage->nBlocksPerRow *
225,451✔
867
                                 psImage->nBlocksPerColumn;
225,451✔
868

869
                    psImage->panBlockStart[iBlock] =
225,451✔
870
                        psSegInfo->nSegmentStart +
225,451✔
871
                        ((iBlockX + iBlockY * psImage->nBlocksPerRow) *
225,451✔
872
                         psImage->nBlockOffset) +
225,451✔
873
                        (iBand * psImage->nBandOffset);
225,451✔
874
                }
875
            }
876
        }
877
    }
878

879
    /* -------------------------------------------------------------------- */
880
    /*      Otherwise we need to read the block map from the beginning      */
881
    /*      of the image segment.                                           */
882
    /* -------------------------------------------------------------------- */
883
    else
884
    {
885
        GUInt32 nIMDATOFF;
886
        GUInt16 nBMRLNTH, nTMRLNTH, nTPXCDLNTH;
887
        int nBlockCount;
888
        int bOK = TRUE;
8✔
889

890
        nBlockCount = psImage->nBlocksPerRow * psImage->nBlocksPerColumn *
8✔
891
                      psImage->nBands;
8✔
892

893
        CPLAssert(psImage->szIC[0] == 'M' || psImage->szIC[1] == 'M');
8✔
894

895
        bOK &= VSIFSeekL(psFile->fp, psSegInfo->nSegmentStart, SEEK_SET) == 0;
8✔
896
        bOK &= VSIFReadL(&nIMDATOFF, 1, 4, psFile->fp) == 4;
8✔
897
        bOK &= VSIFReadL(&nBMRLNTH, 1, 2, psFile->fp) == 2;
8✔
898
        bOK &= VSIFReadL(&nTMRLNTH, 1, 2, psFile->fp) == 2;
8✔
899
        bOK &= VSIFReadL(&nTPXCDLNTH, 1, 2, psFile->fp) == 2;
8✔
900

901
        CPL_MSBPTR32(&nIMDATOFF);
8✔
902
        CPL_MSBPTR16(&nBMRLNTH);
8✔
903
        CPL_MSBPTR16(&nTMRLNTH);
8✔
904
        CPL_MSBPTR16(&nTPXCDLNTH);
8✔
905

906
        if (nTPXCDLNTH == 8)
8✔
907
        {
908
            GByte byNodata;
909

910
            psImage->bNoDataSet = TRUE;
×
911
            bOK &= VSIFReadL(&byNodata, 1, 1, psFile->fp) == 1;
×
912
            psImage->nNoDataValue = byNodata;
×
913
        }
914
        else
915
            bOK &= VSIFSeekL(psFile->fp, (nTPXCDLNTH + 7) / 8, SEEK_CUR) == 0;
8✔
916

917
        if (nBMRLNTH == 4 && psImage->chIMODE == 'P')
8✔
918
        {
3✔
919
            int nStoredBlocks =
3✔
920
                psImage->nBlocksPerRow * psImage->nBlocksPerColumn;
3✔
921

922
            for (i = 0; bOK && i < nStoredBlocks; i++)
15✔
923
            {
924
                GUInt32 l_nOffset;
925
                bOK &= VSIFReadL(&l_nOffset, 4, 1, psFile->fp) == 1;
12✔
926
                CPL_MSBPTR32(&l_nOffset);
12✔
927
                psImage->panBlockStart[i] = l_nOffset;
12✔
928
                if (psImage->panBlockStart[i] != UINT_MAX)
12✔
929
                {
930
                    psImage->panBlockStart[i] +=
12✔
931
                        psSegInfo->nSegmentStart + nIMDATOFF;
12✔
932

933
                    for (iBand = 1; iBand < psImage->nBands; iBand++)
36✔
934
                    {
935
                        psImage->panBlockStart[i + iBand * nStoredBlocks] =
24✔
936
                            psImage->panBlockStart[i] +
24✔
937
                            iBand * psImage->nBandOffset;
24✔
938
                    }
939
                }
940
                else
941
                {
942
                    for (iBand = 1; iBand < psImage->nBands; iBand++)
×
943
                        psImage->panBlockStart[i + iBand * nStoredBlocks] =
×
944
                            UINT_MAX;
945
                }
946
            }
947
        }
948
        else if (nBMRLNTH == 4)
5✔
949
        {
950
            int isM4 = EQUAL(psImage->szIC, "M4");
×
951
            for (i = 0; bOK && i < nBlockCount; i++)
×
952
            {
953
                GUInt32 l_nOffset;
954
                bOK &= VSIFReadL(&l_nOffset, 4, 1, psFile->fp) == 1;
×
955
                CPL_MSBPTR32(&l_nOffset);
×
956
                psImage->panBlockStart[i] = l_nOffset;
×
957
                if (psImage->panBlockStart[i] != UINT_MAX)
×
958
                {
959
                    if (isM4 && (psImage->panBlockStart[i] % 6144) != 0)
×
960
                    {
961
                        break;
×
962
                    }
963
                    psImage->panBlockStart[i] +=
×
964
                        psSegInfo->nSegmentStart + nIMDATOFF;
×
965
                }
966
            }
967
            /* This is a fix for a problem with rpf/cjga/cjgaz01/0105f033.ja1
968
             * and */
969
            /* rpf/cjga/cjgaz03/0034t0b3.ja3 CADRG products (bug 1754). */
970
            /* These products have the strange particularity that their block
971
             * start table begins */
972
            /* one byte after its theoretical beginning, for an unknown reason
973
             */
974
            /* We detect this situation when the block start offset is not a
975
             * multiple of 6144 */
976
            /* Hopefully there's something in the NITF/CADRG standard that can
977
             * account for it,  */
978
            /* but I've not found it */
979
            if (isM4 && i != nBlockCount)
×
980
            {
981
                bGotWrongOffset = TRUE;
×
982
                CPLError(CE_Warning, CPLE_AppDefined,
×
983
                         "Block start for block %d is wrong. Retrying with one "
984
                         "extra byte shift...",
985
                         i);
986
                bOK &= VSIFSeekL(psFile->fp,
×
987
                                 psSegInfo->nSegmentStart + 4 + /* nIMDATOFF */
×
988
                                     2 +                        /* nBMRLNTH */
989
                                     2 +                        /* nTMRLNTH */
990
                                     2 +                        /* nTPXCDLNTH */
×
991
                                     (nTPXCDLNTH + 7) / 8 +
×
992
                                     1, /* MAGIC here ! One byte shift... */
993
                                 SEEK_SET) == 0;
×
994

995
                for (i = 0; bOK && i < nBlockCount; i++)
×
996
                {
997
                    GUInt32 l_nOffset;
998
                    bOK &= VSIFReadL(&l_nOffset, 4, 1, psFile->fp) == 1;
×
999
                    CPL_MSBPTR32(&l_nOffset);
×
1000
                    psImage->panBlockStart[i] = l_nOffset;
×
1001
                    if (psImage->panBlockStart[i] != UINT_MAX)
×
1002
                    {
1003
                        if ((psImage->panBlockStart[i] % 6144) != 0)
×
1004
                        {
1005
                            CPLError(CE_Warning, CPLE_AppDefined,
×
1006
                                     "Block start for block %d is still wrong. "
1007
                                     "Display will be wrong.",
1008
                                     i);
1009
                            break;
×
1010
                        }
1011
                        psImage->panBlockStart[i] +=
×
1012
                            psSegInfo->nSegmentStart + nIMDATOFF;
×
1013
                    }
1014
                }
1015
            }
1016
        }
1017
        else
1018
        {
1019
            if (EQUAL(psImage->szIC, "M4"))
5✔
1020
            {
1021
                for (i = 0; i < nBlockCount; i++)
37✔
1022
                    psImage->panBlockStart[i] = (GUIntBig)6144 * i +
36✔
1023
                                                psSegInfo->nSegmentStart +
36✔
1024
                                                nIMDATOFF;
1025
            }
1026
            else if (EQUAL(psImage->szIC, "NM"))
4✔
1027
            {
1028
                int iBlockX, iBlockY;
1029

1030
                for (iBlockY = 0; iBlockY < psImage->nBlocksPerColumn;
8✔
1031
                     iBlockY++)
4✔
1032
                {
1033
                    for (iBlockX = 0; iBlockX < psImage->nBlocksPerRow;
8✔
1034
                         iBlockX++)
4✔
1035
                    {
1036
                        for (iBand = 0; iBand < psImage->nBands; iBand++)
8✔
1037
                        {
1038
                            int iBlock;
1039

1040
                            iBlock = iBlockX +
4✔
1041
                                     iBlockY * psImage->nBlocksPerRow +
4✔
1042
                                     iBand * psImage->nBlocksPerRow *
4✔
1043
                                         psImage->nBlocksPerColumn;
4✔
1044

1045
                            psImage->panBlockStart[iBlock] =
4✔
1046
                                psSegInfo->nSegmentStart + nIMDATOFF +
4✔
1047
                                ((iBlockX + iBlockY * psImage->nBlocksPerRow) *
4✔
1048
                                 psImage->nBlockOffset) +
4✔
1049
                                (iBand * psImage->nBandOffset);
4✔
1050
                        }
1051
                    }
1052
                }
1053
            }
1054
            else
1055
            {
1056
                CPLError(
×
1057
                    CE_Warning, CPLE_AppDefined,
1058
                    "Unsupported IC value '%s', image access will likely fail.",
1059
                    psImage->szIC);
×
1060
            }
1061
        }
1062
        if (!bOK)
8✔
1063
        {
1064
            CPLError(CE_Failure, CPLE_FileIO, "I/O error");
×
1065
            NITFImageDeaccess(psImage);
×
1066
            return NULL;
×
1067
        }
1068
    }
1069

1070
    /* -------------------------------------------------------------------- */
1071
    /*  Load subframe mask table if present (typically, for CADRG/CIB       */
1072
    /*  images with IC=C4/M4)                                               */
1073
    /* -------------------------------------------------------------------- */
1074
    if (!bGotWrongOffset)
9,754✔
1075
        NITFLoadSubframeMaskTable(psImage);
9,754✔
1076

1077
    /* -------------------------------------------------------------------- */
1078
    /*      Bug #1751: Add a transparent color if there are none. Absent    */
1079
    /*      subblocks will be then transparent.                             */
1080
    /* -------------------------------------------------------------------- */
1081
    if (!psImage->bNoDataSet && psImage->nBands == 1 &&
9,754✔
1082
        psImage->nBitsPerSample == 8)
9,598✔
1083
    {
1084
        NITFBandInfo *psBandInfo = psImage->pasBandInfo;
9,405✔
1085
        if (psBandInfo->nSignificantLUTEntries < 256 - 1 &&
9,405✔
1086
            psBandInfo->pabyLUT != NULL)
9,405✔
1087
        {
1088
            if (psBandInfo->nSignificantLUTEntries == 217 &&
30✔
1089
                psBandInfo->pabyLUT[216] == 0 &&
×
1090
                psBandInfo->pabyLUT[256 + 216] == 0 &&
×
1091
                psBandInfo->pabyLUT[512 + 216] == 0)
×
1092
            {
1093
                psImage->bNoDataSet = TRUE;
×
1094
                psImage->nNoDataValue = psBandInfo->nSignificantLUTEntries - 1;
×
1095
            }
1096
            else
1097
            {
1098
                psBandInfo->pabyLUT[0 + psBandInfo->nSignificantLUTEntries] = 0;
30✔
1099
                psBandInfo->pabyLUT[256 + psBandInfo->nSignificantLUTEntries] =
30✔
1100
                    0;
1101
                psBandInfo->pabyLUT[512 + psBandInfo->nSignificantLUTEntries] =
30✔
1102
                    0;
1103
                psImage->bNoDataSet = TRUE;
30✔
1104
                psImage->nNoDataValue = psBandInfo->nSignificantLUTEntries;
30✔
1105
            }
1106
        }
1107
    }
1108

1109
    /* -------------------------------------------------------------------- */
1110
    /*  We override the coordinates found in IGEOLO in case a BLOCKA is     */
1111
    /*  present. According to the BLOCKA specification, it repeats earth    */
1112
    /*  coordinates image corner locations described by IGEOLO in the NITF  */
1113
    /*  image subheader, but provide higher precision.                      */
1114
    /* -------------------------------------------------------------------- */
1115

1116
    NITFReadBLOCKA_GCPs(psImage);
9,754✔
1117

1118
    /* -------------------------------------------------------------------- */
1119
    /*      We override the coordinates found in IGEOLO in case a GEOLOB is */
1120
    /*      present.  It provides higher precision lat/long values.         */
1121
    /* -------------------------------------------------------------------- */
1122
    NITFReadGEOLOB(psImage);
9,754✔
1123

1124
    /* -------------------------------------------------------------------- */
1125
    /*      If we have an RPF CoverageSectionSubheader, read the more       */
1126
    /*      precise bounds from it.                                         */
1127
    /* -------------------------------------------------------------------- */
1128
    for (i = 0; i < psImage->nLocCount; i++)
9,754✔
1129
    {
1130
        if (psImage->pasLocations[i].nLocId == LID_CoverageSectionSubheader)
24✔
1131
        {
1132
            double adfTarget[8];
1133

1134
            if (VSIFSeekL(psFile->fp, psImage->pasLocations[i].nLocOffset,
24✔
1135
                          SEEK_SET) != 0 ||
24✔
1136
                VSIFReadL(adfTarget, 8, 8, psFile->fp) != 8)
24✔
1137
            {
1138
                CPLError(CE_Failure, CPLE_FileIO, "I/O error");
×
1139
                NITFImageDeaccess(psImage);
×
1140
                return NULL;
×
1141
            }
1142

1143
            for (i = 0; i < 8; i++)
216✔
1144
                CPL_MSBPTR64((adfTarget + i));
192✔
1145

1146
            psImage->dfULX = adfTarget[1];
24✔
1147
            psImage->dfULY = adfTarget[0];
24✔
1148
            psImage->dfLLX = adfTarget[3];
24✔
1149
            psImage->dfLLY = adfTarget[2];
24✔
1150
            psImage->dfURX = adfTarget[5];
24✔
1151
            psImage->dfURY = adfTarget[4];
24✔
1152
            psImage->dfLRX = adfTarget[7];
24✔
1153
            psImage->dfLRY = adfTarget[6];
24✔
1154

1155
            psImage->bIsBoxCenterOfPixel = FALSE;  // edge of pixel
24✔
1156

1157
            CPLDebug("NITF", "Got spatial info from CoverageSection");
24✔
1158
            break;
24✔
1159
        }
1160
    }
1161

1162
    /* Bug #1750, #2135 and #3383 */
1163
    /* Fix CADRG products like cjnc/cjncz01/000k1023.jn1 (and similar) from NIMA
1164
     * GNCJNCN CDROM: */
1165
    /* this product is crossing meridian 180deg and the upper and lower right
1166
     * longitudes are negative  */
1167
    /* while the upper and lower left longitudes are positive which causes
1168
     * problems in OpenEV, etc... */
1169
    /* So we are adjusting the upper and lower right longitudes by setting them
1170
     * above +180 */
1171
    /* Make this test only CADRG specific are there are other NITF profiles
1172
     * where non north-up imagery */
1173
    /* is valid */
1174
    pszIID1 = CSLFetchNameValue(psImage->papszMetadata, "NITF_IID1");
9,754✔
1175
    if ((psImage->chICORDS == 'G' || psImage->chICORDS == 'D') &&
9,754✔
1176
        pszIID1 != NULL && EQUAL(pszIID1, "CADRG") &&
205✔
1177
        (psImage->dfULX > psImage->dfURX && psImage->dfLLX > psImage->dfLRX &&
24✔
1178
         psImage->dfULY > psImage->dfLLY && psImage->dfURY > psImage->dfLRY))
1✔
1179
    {
1180
        psImage->dfURX += 360;
×
1181
        psImage->dfLRX += 360;
×
1182
    }
1183

1184
    /* -------------------------------------------------------------------- */
1185
    /*      Load RPF attribute metadata if we have it.                      */
1186
    /* -------------------------------------------------------------------- */
1187
    NITFLoadAttributeSection(psImage);
9,754✔
1188

1189
    /* -------------------------------------------------------------------- */
1190
    /*      Are the VQ tables to load up?                                   */
1191
    /* -------------------------------------------------------------------- */
1192
    NITFLoadVQTables(psImage, TRUE);
9,754✔
1193

1194
    return psImage;
9,754✔
1195

1196
header_too_small:
×
1197

1198
    CPLError(CE_Failure, CPLE_AppDefined,
×
1199
             "Image header too small (called from line %d)", nFaultyLine);
1200
    NITFImageDeaccess(psImage);
×
1201
    return NULL;
×
1202
}
1203

1204
/************************************************************************/
1205
/*                         NITFImageDeaccess()                          */
1206
/************************************************************************/
1207

1208
void NITFImageDeaccess(NITFImage *psImage)
9,754✔
1209

1210
{
1211
    int iBand;
1212

1213
    CPLAssert(psImage->psFile->pasSegmentInfo[psImage->iSegment].hAccess ==
9,754✔
1214
              psImage);
1215

1216
    psImage->psFile->pasSegmentInfo[psImage->iSegment].hAccess = NULL;
9,754✔
1217

1218
    if (psImage->pasBandInfo)
9,754✔
1219
    {
1220
        for (iBand = 0; iBand < psImage->nBands; iBand++)
229,813✔
1221
            CPLFree(psImage->pasBandInfo[iBand].pabyLUT);
220,059✔
1222
    }
1223
    CPLFree(psImage->pasBandInfo);
9,754✔
1224
    CPLFree(psImage->panBlockStart);
9,754✔
1225
    CPLFree(psImage->pszComments);
9,754✔
1226
    CPLFree(psImage->pachHeader);
9,754✔
1227
    CPLFree(psImage->pachTRE);
9,754✔
1228
    CSLDestroy(psImage->papszMetadata);
9,754✔
1229

1230
    CPLFree(psImage->pasLocations);
9,754✔
1231
    for (iBand = 0; iBand < 4; iBand++)
48,770✔
1232
        CPLFree(psImage->apanVQLUT[iBand]);
39,016✔
1233

1234
    CPLFree(psImage);
9,754✔
1235
}
9,754✔
1236

1237
/************************************************************************/
1238
/*                        NITFUncompressVQTile()                        */
1239
/*                                                                      */
1240
/*      This code was derived from OSSIM which in turn derived it       */
1241
/*      from OpenMap ... open source means sharing!                     */
1242
/************************************************************************/
1243

1244
static void NITFUncompressVQTile(NITFImage *psImage, GByte *pabyVQBuf,
×
1245
                                 GByte *pabyResult)
1246

1247
{
1248
    int i, j, t, iSrcByte = 0;
×
1249

1250
    for (i = 0; i < 256; i += 4)
×
1251
    {
1252
        for (j = 0; j < 256; j += 8)
×
1253
        {
1254
            GUInt16 firstByte = pabyVQBuf[iSrcByte++];
×
1255
            GUInt16 secondByte = pabyVQBuf[iSrcByte++];
×
1256
            GUInt16 thirdByte = pabyVQBuf[iSrcByte++];
×
1257

1258
            /*
1259
             * because dealing with half-bytes is hard, we
1260
             * uncompress two 4x4 tiles at the same time. (a
1261
             * 4x4 tile compressed is 12 bits )
1262
             * this little code was grabbed from openmap software.
1263
             */
1264

1265
            /* Get first 12-bit value as index into VQ table */
1266

1267
            GUInt16 val1 = (firstByte << 4) | (secondByte >> 4);
×
1268

1269
            /* Get second 12-bit value as index into VQ table*/
1270

1271
            GUInt16 val2 = ((secondByte & 0x000F) << 8) | thirdByte;
×
1272

1273
            for (t = 0; t < 4; ++t)
×
1274
            {
1275
                GByte *pabyTarget = pabyResult + (i + t) * 256 + j;
×
1276

1277
                memcpy(pabyTarget, psImage->apanVQLUT[t] + val1, 4);
×
1278
                memcpy(pabyTarget + 4, psImage->apanVQLUT[t] + val2, 4);
×
1279
            }
1280
        } /* for j */
1281
    }     /* for i */
1282
}
×
1283

1284
/************************************************************************/
1285
/*                         NITFReadImageBlock()                         */
1286
/************************************************************************/
1287

1288
int NITFReadImageBlock(NITFImage *psImage, int nBlockX, int nBlockY, int nBand,
2,552✔
1289
                       void *pData)
1290

1291
{
1292
    int nWrkBufSize;
1293
    int iBaseBlock = nBlockX + nBlockY * psImage->nBlocksPerRow;
2,552✔
1294
    int iFullBlock = iBaseBlock + (nBand - 1) * psImage->nBlocksPerRow *
2,552✔
1295
                                      psImage->nBlocksPerColumn;
2,552✔
1296

1297
    /* -------------------------------------------------------------------- */
1298
    /*      Special exit conditions.                                        */
1299
    /* -------------------------------------------------------------------- */
1300
    if (nBand == 0)
2,552✔
1301
        return BLKREAD_FAIL;
×
1302

1303
    if (psImage->panBlockStart[iFullBlock] == UINT_MAX)
2,552✔
1304
        return BLKREAD_NULL;
432✔
1305

1306
    /* -------------------------------------------------------------------- */
1307
    /*      Special case for 1 bit data.  NITFRasterBand::IReadBlock()      */
1308
    /*      already knows how to promote to byte.                           */
1309
    /* -------------------------------------------------------------------- */
1310
    if ((EQUAL(psImage->szIC, "NC") || EQUAL(psImage->szIC, "NM")) &&
2,120✔
1311
        psImage->nBitsPerSample == 1)
2,119✔
1312
    {
1313
        if (nBlockX != 0 || nBlockY != 0)
11✔
1314
        {
1315
            CPLError(CE_Failure, CPLE_AppDefined,
×
1316
                     "assert nBlockX == 0 && nBlockY == 0 failed\n");
1317
            return BLKREAD_FAIL;
×
1318
        }
1319
        if (VSIFSeekL(psImage->psFile->fp,
11✔
1320
                      psImage->panBlockStart[0] +
11✔
1321
                          ((vsi_l_offset)psImage->nBlockWidth *
11✔
1322
                               psImage->nBlockHeight +
11✔
1323
                           7) /
11✔
1324
                              8 * (nBand - 1),
11✔
1325
                      SEEK_SET) == 0 &&
11✔
1326
            VSIFReadL(pData,
11✔
1327
                      (psImage->nBlockWidth * psImage->nBlockHeight + 7) / 8, 1,
11✔
1328
                      psImage->psFile->fp) == 1)
11✔
1329
        {
1330
            return BLKREAD_OK;
11✔
1331
        }
1332
        CPLError(CE_Failure, CPLE_FileIO, "I/O error");
×
1333
        return BLKREAD_FAIL;
×
1334
    }
1335

1336
    /* -------------------------------------------------------------------- */
1337
    /*      Figure out how big the working buffer will need to be.          */
1338
    /* -------------------------------------------------------------------- */
1339
    if (psImage->nBitsPerSample != psImage->nWordSize * 8)
2,109✔
1340
        nWrkBufSize =
49✔
1341
            (int)psImage->nLineOffset * (psImage->nBlockHeight - 1) +
49✔
1342
            (psImage->nBitsPerSample * (psImage->nBlockWidth) + 7) / 8;
49✔
1343
    else
1344
        nWrkBufSize = (int)psImage->nLineOffset * (psImage->nBlockHeight - 1) +
2,060✔
1345
                      (int)psImage->nPixelOffset * (psImage->nBlockWidth - 1) +
2,060✔
1346
                      psImage->nWordSize;
2,060✔
1347

1348
    if (nWrkBufSize == 0)
2,109✔
1349
        nWrkBufSize = (psImage->nBlockWidth * psImage->nBlockHeight *
×
1350
                           psImage->nBitsPerSample +
×
1351
                       7) /
1352
                      8;
1353

1354
    /* -------------------------------------------------------------------- */
1355
    /*      Can we do a direct read into our buffer?                        */
1356
    /* -------------------------------------------------------------------- */
1357
    if ((size_t)psImage->nWordSize == psImage->nPixelOffset &&
2,109✔
1358
        (size_t)((psImage->nBitsPerSample * psImage->nBlockWidth + 7) / 8) ==
2,109✔
1359
            psImage->nLineOffset &&
2,109✔
1360
        psImage->szIC[0] != 'C' && psImage->szIC[0] != 'M' &&
2,072✔
1361
        psImage->chIMODE != 'P')
2,071✔
1362
    {
1363
        if (VSIFSeekL(psImage->psFile->fp, psImage->panBlockStart[iFullBlock],
2,071✔
1364
                      SEEK_SET) != 0 ||
2,071✔
1365
            (int)VSIFReadL(pData, 1, nWrkBufSize, psImage->psFile->fp) !=
2,071✔
1366
                nWrkBufSize)
1367
        {
1368
            CPLError(CE_Failure, CPLE_FileIO,
×
1369
                     "Unable to read %d byte block from " CPL_FRMT_GUIB ".",
1370
                     nWrkBufSize, psImage->panBlockStart[iFullBlock]);
×
1371
            return BLKREAD_FAIL;
×
1372
        }
1373
        else
1374
        {
1375
#ifdef CPL_LSB
1376
            NITFSwapWords(psImage, pData,
2,071✔
1377
                          psImage->nBlockWidth * psImage->nBlockHeight);
2,071✔
1378
#endif
1379

1380
            return BLKREAD_OK;
2,071✔
1381
        }
1382
    }
1383

1384
    if (psImage->szIC[0] == 'N')
38✔
1385
    {
1386
        /* read all the data needed to get our requested band-block */
1387
        if (psImage->nBitsPerSample != psImage->nWordSize * 8)
37✔
1388
        {
1389
            if (psImage->chIMODE == 'S' ||
37✔
1390
                (psImage->chIMODE == 'B' && psImage->nBands == 1))
37✔
1391
            {
1392
                nWrkBufSize = ((psImage->nBlockWidth * psImage->nBlockHeight *
37✔
1393
                                psImage->nBitsPerSample) +
37✔
1394
                               7) /
1395
                              8;
1396
                if (VSIFSeekL(psImage->psFile->fp,
37✔
1397
                              psImage->panBlockStart[iFullBlock],
37✔
1398
                              SEEK_SET) != 0 ||
37✔
1399
                    (int)VSIFReadL(pData, 1, nWrkBufSize,
37✔
1400
                                   psImage->psFile->fp) != nWrkBufSize)
37✔
1401
                {
1402
                    CPLError(CE_Failure, CPLE_FileIO,
×
1403
                             "Unable to read %d byte block from %d.",
1404
                             (int)nWrkBufSize,
1405
                             (int)psImage->panBlockStart[iFullBlock]);
×
1406
                    return BLKREAD_FAIL;
×
1407
                }
1408

1409
                return BLKREAD_OK;
37✔
1410
            }
1411
            else
1412
            {
1413
                CPLError(CE_Failure, CPLE_NotSupported,
×
1414
                         "ABPP=%d and IMODE=%c not supported",
1415
                         psImage->nBitsPerSample, psImage->chIMODE);
×
1416
                return BLKREAD_FAIL;
×
1417
            }
1418
        }
1419
    }
1420

1421
    /* -------------------------------------------------------------------- */
1422
    /*      Read the requested information into a temporary buffer and      */
1423
    /*      pull out what we want.                                          */
1424
    /* -------------------------------------------------------------------- */
1425
    if (psImage->szIC[0] == 'N')
1✔
1426
    {
1427
        GByte *pabyWrkBuf = (GByte *)VSI_MALLOC_VERBOSE(nWrkBufSize);
×
1428
        int iPixel, iLine;
1429

1430
        if (pabyWrkBuf == NULL)
×
1431
        {
1432
            return BLKREAD_FAIL;
×
1433
        }
1434

1435
        /* read all the data needed to get our requested band-block */
1436
        if (VSIFSeekL(psImage->psFile->fp, psImage->panBlockStart[iFullBlock],
×
1437
                      SEEK_SET) != 0 ||
×
1438
            (int)VSIFReadL(pabyWrkBuf, 1, nWrkBufSize, psImage->psFile->fp) !=
×
1439
                nWrkBufSize)
1440
        {
1441
            CPLError(CE_Failure, CPLE_FileIO,
×
1442
                     "Unable to read %d byte block from " CPL_FRMT_GUIB ".",
1443
                     nWrkBufSize, psImage->panBlockStart[iFullBlock]);
×
1444
            CPLFree(pabyWrkBuf);
×
1445
            return BLKREAD_FAIL;
×
1446
        }
1447

1448
        for (iLine = 0; iLine < psImage->nBlockHeight; iLine++)
×
1449
        {
1450
            GByte *pabySrc, *pabyDst;
1451

1452
            pabySrc = pabyWrkBuf + iLine * psImage->nLineOffset;
×
1453
            pabyDst = ((GByte *)pData) +
×
1454
                      iLine * (psImage->nWordSize * psImage->nBlockWidth);
×
1455

1456
            for (iPixel = 0; iPixel < psImage->nBlockWidth; iPixel++)
×
1457
            {
1458
                memcpy(pabyDst + iPixel * psImage->nWordSize,
×
1459
                       pabySrc + iPixel * psImage->nPixelOffset,
×
1460
                       psImage->nWordSize);
×
1461
            }
1462
        }
1463

1464
#ifdef CPL_LSB
1465
        NITFSwapWords(psImage, pData,
×
1466
                      psImage->nBlockWidth * psImage->nBlockHeight);
×
1467
#endif
1468

1469
        CPLFree(pabyWrkBuf);
×
1470

1471
        return BLKREAD_OK;
×
1472
    }
1473

1474
    /* -------------------------------------------------------------------- */
1475
    /*      Handle VQ compression.  The VQ compression basically keeps a    */
1476
    /*      64x64 array of 12bit code words.  Each code word expands to     */
1477
    /*      a predefined 4x4 8 bit per pixel pattern.                       */
1478
    /* -------------------------------------------------------------------- */
1479
    else if (EQUAL(psImage->szIC, "C4") || EQUAL(psImage->szIC, "M4"))
1✔
1480
    {
1481
        GByte abyVQCoded[6144];
1482

1483
        if (psImage->apanVQLUT[0] == NULL)
×
1484
        {
1485
            CPLError(CE_Failure, CPLE_NotSupported,
×
1486
                     "File lacks VQ LUTs, unable to decode imagery.");
1487
            return BLKREAD_FAIL;
×
1488
        }
1489
        if (psImage->nBlockWidth != 256 || psImage->nBlockHeight != 256)
×
1490
        {
1491
            CPLError(CE_Failure, CPLE_NotSupported,
×
1492
                     "Invalid block dimension for VQ compressed data.");
1493
            return BLKREAD_FAIL;
×
1494
        }
1495

1496
        /* Read the codewords */
1497
        if (VSIFSeekL(psImage->psFile->fp, psImage->panBlockStart[iFullBlock],
×
1498
                      SEEK_SET) != 0 ||
×
1499
            VSIFReadL(abyVQCoded, 1, sizeof(abyVQCoded), psImage->psFile->fp) !=
×
1500
                sizeof(abyVQCoded))
1501
        {
1502
            CPLError(CE_Failure, CPLE_FileIO,
×
1503
                     "Unable to read %d byte block from " CPL_FRMT_GUIB ".",
1504
                     (int)sizeof(abyVQCoded),
1505
                     psImage->panBlockStart[iFullBlock]);
×
1506
            return BLKREAD_FAIL;
×
1507
        }
1508

1509
        NITFUncompressVQTile(psImage, abyVQCoded, pData);
×
1510

1511
        return BLKREAD_OK;
×
1512
    }
1513

1514
    /* -------------------------------------------------------------------- */
1515
    /*      Handle ARIDPCM compression.                                     */
1516
    /* -------------------------------------------------------------------- */
1517
    else if (EQUAL(psImage->szIC, "C2") || EQUAL(psImage->szIC, "M2"))
1✔
1518
    {
1519
        GIntBig nSignedRawBytes;
1520
        size_t nRawBytes;
1521
        NITFSegmentInfo *psSegInfo;
1522
        int success;
1523
        GByte *pabyRawData;
1524

1525
        if (psImage->nBitsPerSample != 8)
×
1526
        {
1527
            CPLError(
×
1528
                CE_Failure, CPLE_AppDefined,
1529
                "Unsupported bits per sample value (%d) for C2/M2 compression",
1530
                psImage->nBitsPerSample);
1531
            return BLKREAD_FAIL;
×
1532
        }
1533

1534
        if (iFullBlock < psImage->nBlocksPerRow * psImage->nBlocksPerColumn *
×
1535
                                 psImage->nBands -
×
1536
                             1)
1537
        {
1538
            nSignedRawBytes = (GIntBig)psImage->panBlockStart[iFullBlock + 1] -
×
1539
                              (GIntBig)psImage->panBlockStart[iFullBlock];
×
1540
        }
1541
        else
1542
        {
1543
            psSegInfo = psImage->psFile->pasSegmentInfo + psImage->iSegment;
×
1544
            nSignedRawBytes = (GIntBig)psSegInfo->nSegmentStart +
×
1545
                              (GIntBig)psSegInfo->nSegmentSize -
×
1546
                              (GIntBig)psImage->panBlockStart[iFullBlock];
×
1547
        }
1548
        if (nSignedRawBytes <= 0 || nSignedRawBytes > INT_MAX)
×
1549
        {
1550
            CPLError(CE_Failure, CPLE_AppDefined,
×
1551
                     "Invalid block size : " CPL_FRMT_GIB, nSignedRawBytes);
1552
            return BLKREAD_FAIL;
×
1553
        }
1554

1555
        nRawBytes = (size_t)nSignedRawBytes;
×
1556
        pabyRawData = (GByte *)VSI_MALLOC_VERBOSE(nRawBytes);
×
1557
        if (pabyRawData == NULL)
×
1558
        {
1559
            return BLKREAD_FAIL;
×
1560
        }
1561

1562
        /* Read the codewords */
1563
        if (VSIFSeekL(psImage->psFile->fp, psImage->panBlockStart[iFullBlock],
×
1564
                      SEEK_SET) != 0 ||
×
1565
            VSIFReadL(pabyRawData, 1, nRawBytes, psImage->psFile->fp) !=
×
1566
                nRawBytes)
1567
        {
1568
            CPLError(CE_Failure, CPLE_FileIO,
×
1569
                     "Unable to read %d byte block from " CPL_FRMT_GUIB ".",
1570
                     (int)nRawBytes, psImage->panBlockStart[iFullBlock]);
×
1571
            CPLFree(pabyRawData);
×
1572
            return BLKREAD_FAIL;
×
1573
        }
1574

1575
        success =
1576
            NITFUncompressARIDPCM(psImage, pabyRawData, (int)nRawBytes, pData);
×
1577

1578
        CPLFree(pabyRawData);
×
1579

1580
        if (success)
×
1581
            return BLKREAD_OK;
×
1582
        else
1583
            return BLKREAD_FAIL;
×
1584
    }
1585

1586
    /* -------------------------------------------------------------------- */
1587
    /*      Handle BILEVEL (C1) compression.                                */
1588
    /* -------------------------------------------------------------------- */
1589
    else if (EQUAL(psImage->szIC, "C1") || EQUAL(psImage->szIC, "M1"))
1✔
1590
    {
1591
#ifdef HAVE_TIFF
1592
        GIntBig nSignedRawBytes;
1593
        size_t nRawBytes;
1594
        NITFSegmentInfo *psSegInfo;
1595
        int success;
1596
        GByte *pabyRawData;
1597

1598
        if (psImage->nBitsPerSample != 1)
1✔
1599
        {
1600
            CPLError(CE_Failure, CPLE_AppDefined,
×
1601
                     "Invalid bits per sample value (%d) for C1/M1 compression",
1602
                     psImage->nBitsPerSample);
1603
            return BLKREAD_FAIL;
×
1604
        }
1605

1606
        if (iFullBlock < psImage->nBlocksPerRow * psImage->nBlocksPerColumn *
1✔
1607
                                 psImage->nBands -
1✔
1608
                             1)
1609
        {
1610
            nSignedRawBytes = (GIntBig)psImage->panBlockStart[iFullBlock + 1] -
×
1611
                              (GIntBig)psImage->panBlockStart[iFullBlock];
×
1612
        }
1613
        else
1614
        {
1615
            psSegInfo = psImage->psFile->pasSegmentInfo + psImage->iSegment;
1✔
1616
            nSignedRawBytes = (GIntBig)psSegInfo->nSegmentStart +
1✔
1617
                              (GIntBig)psSegInfo->nSegmentSize -
1✔
1618
                              (GIntBig)psImage->panBlockStart[iFullBlock];
1✔
1619
        }
1620
        if (nSignedRawBytes <= 0 || nSignedRawBytes > INT_MAX)
1✔
1621
        {
1622
            CPLError(CE_Failure, CPLE_AppDefined,
×
1623
                     "Invalid block size : " CPL_FRMT_GIB, nSignedRawBytes);
1624
            return BLKREAD_FAIL;
×
1625
        }
1626

1627
        nRawBytes = (size_t)nSignedRawBytes;
1✔
1628
        pabyRawData = (GByte *)VSI_MALLOC_VERBOSE(nRawBytes);
1✔
1629
        if (pabyRawData == NULL)
1✔
1630
        {
1631
            return BLKREAD_FAIL;
×
1632
        }
1633

1634
        /* Read the codewords */
1635
        if (VSIFSeekL(psImage->psFile->fp, psImage->panBlockStart[iFullBlock],
1✔
1636
                      SEEK_SET) != 0 ||
1✔
1637
            VSIFReadL(pabyRawData, 1, nRawBytes, psImage->psFile->fp) !=
1✔
1638
                nRawBytes)
1639
        {
1640
            CPLError(CE_Failure, CPLE_FileIO,
×
1641
                     "Unable to read %d byte block from " CPL_FRMT_GUIB ".",
1642
                     (int)nRawBytes, psImage->panBlockStart[iFullBlock]);
×
1643
            CPLFree(pabyRawData);
×
1644
            return BLKREAD_FAIL;
×
1645
        }
1646

1647
        success =
1648
            NITFUncompressBILEVEL(psImage, pabyRawData, (int)nRawBytes, pData);
1✔
1649

1650
        CPLFree(pabyRawData);
1✔
1651

1652
        if (success)
1✔
1653
            return BLKREAD_OK;
1✔
1654
        else
1655
            return BLKREAD_FAIL;
×
1656
#else
1657
        CPLError(CE_Failure, CPLE_NotSupported,
1658
                 "BILEVEL compression not supported because of lack of "
1659
                 "TIFF support");
1660
        return BLKREAD_FAIL;
1661
#endif
1662
    }
1663

1664
    /* -------------------------------------------------------------------- */
1665
    /*      Report unsupported compression scheme(s).                       */
1666
    /* -------------------------------------------------------------------- */
1667
    else if (atoi(psImage->szIC + 1) > 0)
×
1668
    {
1669
        CPLError(CE_Failure, CPLE_NotSupported,
×
1670
                 "Unsupported imagery compression format %s in NITF library.",
1671
                 psImage->szIC);
×
1672
        return BLKREAD_FAIL;
×
1673
    }
1674

1675
    return BLKREAD_FAIL;
×
1676
}
1677

1678
/************************************************************************/
1679
/*                        NITFWriteImageBlock()                         */
1680
/************************************************************************/
1681

1682
int NITFWriteImageBlock(NITFImage *psImage, int nBlockX, int nBlockY, int nBand,
644✔
1683
                        void *pData)
1684

1685
{
1686
    GUIntBig nWrkBufSize;
1687
    int iBaseBlock = nBlockX + nBlockY * psImage->nBlocksPerRow;
644✔
1688
    int iFullBlock = iBaseBlock + (nBand - 1) * psImage->nBlocksPerRow *
644✔
1689
                                      psImage->nBlocksPerColumn;
644✔
1690

1691
    if (nBand == 0)
644✔
1692
        return BLKREAD_FAIL;
×
1693

1694
    nWrkBufSize = psImage->nLineOffset * (psImage->nBlockHeight - 1) +
644✔
1695
                  psImage->nPixelOffset * (psImage->nBlockWidth - 1) +
644✔
1696
                  psImage->nWordSize;
644✔
1697

1698
    if (nWrkBufSize == 0)
644✔
1699
        nWrkBufSize = ((GUIntBig)psImage->nBlockWidth * psImage->nBlockHeight *
×
1700
                           psImage->nBitsPerSample +
×
1701
                       7) /
1702
                      8;
1703

1704
    /* -------------------------------------------------------------------- */
1705
    /*      Can we do a direct read into our buffer?                        */
1706
    /* -------------------------------------------------------------------- */
1707
    if ((size_t)psImage->nWordSize == psImage->nPixelOffset &&
644✔
1708
        (size_t)(psImage->nWordSize * psImage->nBlockWidth) ==
644✔
1709
            psImage->nLineOffset &&
644✔
1710
        psImage->szIC[0] != 'C' && psImage->szIC[0] != 'M')
644✔
1711
    {
1712
#ifdef CPL_LSB
1713
        NITFSwapWords(psImage, pData,
644✔
1714
                      psImage->nBlockWidth * psImage->nBlockHeight);
644✔
1715
#endif
1716

1717
        if (VSIFSeekL(psImage->psFile->fp, psImage->panBlockStart[iFullBlock],
644✔
1718
                      SEEK_SET) != 0 ||
644✔
1719
            (GUIntBig)VSIFWriteL(pData, 1, (size_t)nWrkBufSize,
644✔
1720
                                 psImage->psFile->fp) != nWrkBufSize)
644✔
1721
        {
1722
            CPLError(CE_Failure, CPLE_FileIO,
×
1723
                     "Unable to write " CPL_FRMT_GUIB
1724
                     " byte block from " CPL_FRMT_GUIB ".",
1725
                     nWrkBufSize, psImage->panBlockStart[iFullBlock]);
×
1726
            return BLKREAD_FAIL;
×
1727
        }
1728
        else
1729
        {
1730
#ifdef CPL_LSB
1731
            /* restore byte order to original */
1732
            NITFSwapWords(psImage, pData,
644✔
1733
                          psImage->nBlockWidth * psImage->nBlockHeight);
644✔
1734
#endif
1735

1736
            return BLKREAD_OK;
644✔
1737
        }
1738
    }
1739

1740
    /* -------------------------------------------------------------------- */
1741
    /*      Other forms not supported at this time.                         */
1742
    /* -------------------------------------------------------------------- */
1743
    CPLError(CE_Failure, CPLE_NotSupported,
×
1744
             "Mapped, interleaved and compressed NITF forms not supported\n"
1745
             "for writing at this time.");
1746

1747
    return BLKREAD_FAIL;
×
1748
}
1749

1750
/************************************************************************/
1751
/*                         NITFReadImageLine()                          */
1752
/************************************************************************/
1753

1754
int NITFReadImageLine(NITFImage *psImage, int nLine, int nBand, void *pData)
15,951✔
1755

1756
{
1757
    GUIntBig nLineOffsetInFile;
1758
    size_t nLineSize;
1759
    unsigned char *pabyLineBuf;
1760

1761
    if (nBand == 0)
15,951✔
1762
        return BLKREAD_FAIL;
×
1763

1764
    if (psImage->nBlocksPerRow != 1 || psImage->nBlocksPerColumn != 1)
15,951✔
1765
    {
1766
        CPLError(CE_Failure, CPLE_AppDefined,
×
1767
                 "Scanline access not supported on tiled NITF files.");
1768
        return BLKREAD_FAIL;
×
1769
    }
1770

1771
    if (psImage->nBlockWidth < psImage->nCols)
15,951✔
1772
    {
1773
        CPLError(CE_Failure, CPLE_AppDefined,
×
1774
                 "For scanline access, block width cannot be lesser than the "
1775
                 "number of columns.");
1776
        return BLKREAD_FAIL;
×
1777
    }
1778

1779
    if (!EQUAL(psImage->szIC, "NC"))
15,951✔
1780
    {
1781
        CPLError(CE_Failure, CPLE_AppDefined,
×
1782
                 "Scanline access not supported on compressed NITF files.");
1783
        return BLKREAD_FAIL;
×
1784
    }
1785

1786
    /* -------------------------------------------------------------------- */
1787
    /*      Workout location and size of data in file.                      */
1788
    /* -------------------------------------------------------------------- */
1789
    nLineOffsetInFile = psImage->panBlockStart[0] +
15,951✔
1790
                        psImage->nLineOffset * nLine +
15,951✔
1791
                        psImage->nBandOffset * (nBand - 1);
15,951✔
1792

1793
    nLineSize = (size_t)psImage->nPixelOffset * (psImage->nBlockWidth - 1) +
15,951✔
1794
                psImage->nWordSize;
15,951✔
1795

1796
    if (nLineSize == 0 || psImage->nWordSize * 8 != psImage->nBitsPerSample)
15,951✔
1797
        nLineSize = (psImage->nBlockWidth * psImage->nBitsPerSample + 7) / 8;
8✔
1798

1799
    if (VSIFSeekL(psImage->psFile->fp, nLineOffsetInFile, SEEK_SET) != 0)
15,951✔
1800
        return BLKREAD_FAIL;
×
1801

1802
    /* -------------------------------------------------------------------- */
1803
    /*      Can we do a direct read into our buffer.                        */
1804
    /* -------------------------------------------------------------------- */
1805
    if ((psImage->nBitsPerSample % 8) != 0 ||
15,951✔
1806
        ((size_t)psImage->nWordSize == psImage->nPixelOffset &&
15,943✔
1807
         (size_t)(psImage->nWordSize * psImage->nBlockWidth) ==
15,868✔
1808
             psImage->nLineOffset))
15,868✔
1809
    {
1810
        if (VSIFReadL(pData, 1, nLineSize, psImage->psFile->fp) != nLineSize)
15,876✔
1811
        {
1812
            CPLError(CE_Failure, CPLE_FileIO,
×
1813
                     "Unable to read %d bytes for line %d.", (int)nLineSize,
1814
                     nLine);
1815
            return BLKREAD_FAIL;
×
1816
        }
1817

1818
#ifdef CPL_LSB
1819
        NITFSwapWords(psImage, pData, psImage->nBlockWidth);
15,876✔
1820
#endif
1821

1822
        return BLKREAD_OK;
15,876✔
1823
    }
1824

1825
    /* -------------------------------------------------------------------- */
1826
    /*      Allocate a buffer for all the interleaved data, and read        */
1827
    /*      it.                                                             */
1828
    /* -------------------------------------------------------------------- */
1829
    pabyLineBuf = (unsigned char *)VSI_MALLOC_VERBOSE(nLineSize);
75✔
1830
    if (pabyLineBuf == NULL)
75✔
1831
    {
1832
        return BLKREAD_FAIL;
×
1833
    }
1834

1835
    if (VSIFReadL(pabyLineBuf, 1, nLineSize, psImage->psFile->fp) != nLineSize)
75✔
1836
    {
1837
        CPLError(CE_Failure, CPLE_FileIO,
×
1838
                 "Unable to read %d bytes for line %d.", (int)nLineSize, nLine);
1839
        CPLFree(pabyLineBuf);
×
1840
        return BLKREAD_FAIL;
×
1841
    }
1842

1843
    /* -------------------------------------------------------------------- */
1844
    /*      Copy the desired data out of the interleaved buffer.            */
1845
    /* -------------------------------------------------------------------- */
1846
    {
1847
        GByte *pabySrc, *pabyDst;
1848
        int iPixel;
1849

1850
        pabySrc = pabyLineBuf;
75✔
1851
        pabyDst = ((GByte *)pData);
75✔
1852

1853
        for (iPixel = 0; iPixel < psImage->nBlockWidth; iPixel++)
19,275✔
1854
        {
1855
            memcpy(pabyDst + iPixel * psImage->nWordSize,
19,200✔
1856
                   pabySrc + iPixel * psImage->nPixelOffset,
19,200✔
1857
                   psImage->nWordSize);
19,200✔
1858
        }
1859

1860
#ifdef CPL_LSB
1861
        NITFSwapWords(psImage, pabyDst, psImage->nBlockWidth);
75✔
1862
#endif
1863
    }
1864

1865
    CPLFree(pabyLineBuf);
75✔
1866

1867
    return BLKREAD_OK;
75✔
1868
}
1869

1870
/************************************************************************/
1871
/*                         NITFWriteImageLine()                         */
1872
/************************************************************************/
1873

1874
int NITFWriteImageLine(NITFImage *psImage, int nLine, int nBand, void *pData)
16,260✔
1875

1876
{
1877
    GUIntBig nLineOffsetInFile;
1878
    size_t nLineSize;
1879
    unsigned char *pabyLineBuf;
1880

1881
    if (nBand == 0)
16,260✔
1882
        return BLKREAD_FAIL;
×
1883

1884
    if (psImage->nBlocksPerRow != 1 || psImage->nBlocksPerColumn != 1)
16,260✔
1885
    {
1886
        CPLError(CE_Failure, CPLE_AppDefined,
×
1887
                 "Scanline access not supported on tiled NITF files.");
1888
        return BLKREAD_FAIL;
×
1889
    }
1890

1891
    if (psImage->nBlockWidth < psImage->nCols)
16,260✔
1892
    {
1893
        CPLError(CE_Failure, CPLE_AppDefined,
×
1894
                 "For scanline access, block width cannot be lesser than the "
1895
                 "number of columns.");
1896
        return BLKREAD_FAIL;
×
1897
    }
1898

1899
    if (!EQUAL(psImage->szIC, "NC"))
16,260✔
1900
    {
1901
        CPLError(CE_Failure, CPLE_AppDefined,
×
1902
                 "Scanline access not supported on compressed NITF files.");
1903
        return BLKREAD_FAIL;
×
1904
    }
1905

1906
    /* -------------------------------------------------------------------- */
1907
    /*      Workout location and size of data in file.                      */
1908
    /* -------------------------------------------------------------------- */
1909
    nLineOffsetInFile = psImage->panBlockStart[0] +
16,260✔
1910
                        psImage->nLineOffset * nLine +
16,260✔
1911
                        psImage->nBandOffset * (nBand - 1);
16,260✔
1912

1913
    nLineSize = (size_t)psImage->nPixelOffset * (psImage->nBlockWidth - 1) +
16,260✔
1914
                psImage->nWordSize;
16,260✔
1915

1916
    if (VSIFSeekL(psImage->psFile->fp, nLineOffsetInFile, SEEK_SET) != 0)
16,260✔
1917
    {
1918
        CPLError(CE_Failure, CPLE_FileIO, "I/O error");
×
1919
        return BLKREAD_FAIL;
×
1920
    }
1921

1922
    /* -------------------------------------------------------------------- */
1923
    /*      Can we do a direct write into our buffer.                       */
1924
    /* -------------------------------------------------------------------- */
1925
    if ((size_t)psImage->nWordSize == psImage->nPixelOffset &&
16,260✔
1926
        (size_t)(psImage->nWordSize * psImage->nBlockWidth) ==
16,185✔
1927
            psImage->nLineOffset)
16,185✔
1928
    {
1929
#ifdef CPL_LSB
1930
        NITFSwapWords(psImage, pData, psImage->nBlockWidth);
16,185✔
1931
#endif
1932

1933
        if (VSIFWriteL(pData, 1, nLineSize, psImage->psFile->fp) != nLineSize)
16,185✔
1934
        {
1935
            CPLError(CE_Failure, CPLE_FileIO, "I/O error");
×
1936
            return BLKREAD_FAIL;
×
1937
        }
1938

1939
#ifdef CPL_LSB
1940
        NITFSwapWords(psImage, pData, psImage->nBlockWidth);
16,185✔
1941
#endif
1942

1943
        return BLKREAD_OK;
16,185✔
1944
    }
1945

1946
    /* -------------------------------------------------------------------- */
1947
    /*      Allocate a buffer for all the interleaved data, and read        */
1948
    /*      it.                                                             */
1949
    /* -------------------------------------------------------------------- */
1950
    pabyLineBuf = (unsigned char *)VSI_MALLOC_VERBOSE(nLineSize);
75✔
1951
    if (pabyLineBuf == NULL)
75✔
1952
    {
1953
        return BLKREAD_FAIL;
×
1954
    }
1955

1956
    if (VSIFReadL(pabyLineBuf, 1, nLineSize, psImage->psFile->fp) != nLineSize)
75✔
1957
    {
1958
        memset(pabyLineBuf, 0, nLineSize);
×
1959
    }
1960

1961
    /* -------------------------------------------------------------------- */
1962
    /*      Copy the desired data into the interleaved buffer.              */
1963
    /* -------------------------------------------------------------------- */
1964
    {
1965
        GByte *pabySrc, *pabyDst;
1966
        int iPixel;
1967

1968
        pabyDst = pabyLineBuf;
75✔
1969
        pabySrc = ((GByte *)pData);
75✔
1970

1971
#ifdef CPL_LSB
1972
        NITFSwapWords(psImage, pData, psImage->nBlockWidth);
75✔
1973
#endif
1974

1975
        for (iPixel = 0; iPixel < psImage->nBlockWidth; iPixel++)
19,275✔
1976
        {
1977
            memcpy(pabyDst + iPixel * psImage->nPixelOffset,
19,200✔
1978
                   pabySrc + iPixel * psImage->nWordSize, psImage->nWordSize);
19,200✔
1979
        }
1980

1981
#ifdef CPL_LSB
1982
        NITFSwapWords(psImage, pData, psImage->nBlockWidth);
75✔
1983
#endif
1984
    }
1985

1986
    /* -------------------------------------------------------------------- */
1987
    /*      Write the results back out.                                     */
1988
    /* -------------------------------------------------------------------- */
1989
    if (VSIFSeekL(psImage->psFile->fp, nLineOffsetInFile, SEEK_SET) != 0 ||
150✔
1990
        VSIFWriteL(pabyLineBuf, 1, nLineSize, psImage->psFile->fp) != nLineSize)
75✔
1991
    {
1992
        CPLFree(pabyLineBuf);
×
1993
        CPLError(CE_Failure, CPLE_FileIO, "I/O error");
×
1994
        return BLKREAD_FAIL;
×
1995
    }
1996
    CPLFree(pabyLineBuf);
75✔
1997

1998
    return BLKREAD_OK;
75✔
1999
}
2000

2001
/************************************************************************/
2002
/*                          NITFEncodeDMSLoc()                          */
2003
/************************************************************************/
2004

2005
static void NITFEncodeDMSLoc(char *pszTarget, size_t nTargetLen, double dfValue,
544✔
2006
                             const char *pszAxis)
2007

2008
{
2009
    char chHemisphere;
2010
    int nDegrees, nMinutes, nSeconds;
2011

2012
    if (EQUAL(pszAxis, "Lat"))
544✔
2013
    {
2014
        if (dfValue < 0.0)
272✔
2015
            chHemisphere = 'S';
50✔
2016
        else
2017
            chHemisphere = 'N';
222✔
2018
    }
2019
    else
2020
    {
2021
        if (dfValue < 0.0)
272✔
2022
            chHemisphere = 'W';
120✔
2023
        else
2024
            chHemisphere = 'E';
152✔
2025
    }
2026

2027
    dfValue = fabs(dfValue);
544✔
2028

2029
    nDegrees = (int)dfValue;
544✔
2030
    dfValue = (dfValue - nDegrees) * 60.0;
544✔
2031

2032
    nMinutes = (int)dfValue;
544✔
2033
    dfValue = (dfValue - nMinutes) * 60.0;
544✔
2034

2035
    /* -------------------------------------------------------------------- */
2036
    /*      Do careful rounding on seconds so that 59.9->60 is properly     */
2037
    /*      rolled into minutes and degrees.                                */
2038
    /* -------------------------------------------------------------------- */
2039
    nSeconds = (int)(dfValue + 0.5);
544✔
2040
    if (nSeconds == 60)
544✔
2041
    {
2042
        nSeconds = 0;
154✔
2043
        nMinutes += 1;
154✔
2044
        if (nMinutes == 60)
154✔
2045
        {
2046
            nMinutes = 0;
4✔
2047
            nDegrees += 1;
4✔
2048
        }
2049
    }
2050

2051
    if (EQUAL(pszAxis, "Lat"))
544✔
2052
        snprintf(pszTarget, nTargetLen, "%02d%02d%02d%c", nDegrees, nMinutes,
272✔
2053
                 nSeconds, chHemisphere);
2054
    else
2055
        snprintf(pszTarget, nTargetLen, "%03d%02d%02d%c", nDegrees, nMinutes,
272✔
2056
                 nSeconds, chHemisphere);
2057
}
544✔
2058

2059
/************************************************************************/
2060
/*                          NITFWriteIGEOLO()                           */
2061
/************************************************************************/
2062

2063
/* Check that easting can be represented as a 6 character string */
2064
#define CHECK_IGEOLO_UTM_X(name, x)                                            \
2065
    if ((int)floor((x) + 0.5) <= -100000 || (int)floor((x) + 0.5) >= 1000000)  \
2066
    {                                                                          \
2067
        CPLError(CE_Failure, CPLE_AppDefined,                                  \
2068
                 "Attempt to write UTM easting %s=%d which is outside of "     \
2069
                 "valid range.",                                               \
2070
                 name, (int)floor((x) + 0.5));                                 \
2071
        return FALSE;                                                          \
2072
    }
2073

2074
/* Check that northing can be represented as a 7 character string */
2075
#define CHECK_IGEOLO_UTM_Y(name, y)                                            \
2076
    if ((int)floor((y) + 0.5) <= -1000000 ||                                   \
2077
        (int)floor((y) + 0.5) >= 10000000)                                     \
2078
    {                                                                          \
2079
        CPLError(CE_Failure, CPLE_AppDefined,                                  \
2080
                 "Attempt to write UTM northing %s=%d which is outside of "    \
2081
                 "valid range.",                                               \
2082
                 name, (int)floor((y) + 0.5));                                 \
2083
        return FALSE;                                                          \
2084
    }
2085

2086
int NITFWriteIGEOLO(NITFImage *psImage, char chICORDS, int nZone, double dfULX,
110✔
2087
                    double dfULY, double dfURX, double dfURY, double dfLRX,
2088
                    double dfLRY, double dfLLX, double dfLLY)
2089

2090
{
2091
    char szIGEOLO[61];
2092

2093
    /* -------------------------------------------------------------------- */
2094
    /*      Do some checking.                                               */
2095
    /* -------------------------------------------------------------------- */
2096
    if (psImage->chICORDS == ' ')
110✔
2097
    {
2098
        CPLError(CE_Failure, CPLE_NotSupported,
19✔
2099
                 "Apparently no space reserved for IGEOLO info in NITF file.\n"
2100
                 "NITFWriteIGEOGLO() fails.");
2101
        return FALSE;
19✔
2102
    }
2103

2104
    if (chICORDS != 'G' && chICORDS != 'N' && chICORDS != 'S' &&
91✔
2105
        chICORDS != 'D')
2106
    {
2107
        CPLError(CE_Failure, CPLE_NotSupported,
×
2108
                 "Invalid ICOORDS value (%c) for NITFWriteIGEOLO().", chICORDS);
2109
        return FALSE;
×
2110
    }
2111

2112
    /* -------------------------------------------------------------------- */
2113
    /*      Format geographic coordinates in DMS                            */
2114
    /* -------------------------------------------------------------------- */
2115
    if (chICORDS == 'G')
91✔
2116
    {
2117
        if (fabs(dfULX) > 180 || fabs(dfURX) > 180 || fabs(dfLRX) > 180 ||
68✔
2118
            fabs(dfLLX) > 180 || fabs(dfULY) > 90 || fabs(dfURY) > 90 ||
68✔
2119
            fabs(dfLRY) > 90 || fabs(dfLLY) > 90)
68✔
2120
        {
2121
            CPLError(
×
2122
                CE_Failure, CPLE_AppDefined,
2123
                "Attempt to write geographic bound outside of legal range.");
2124
            return FALSE;
×
2125
        }
2126

2127
        NITFEncodeDMSLoc(szIGEOLO + 0, sizeof(szIGEOLO) - 0, dfULY, "Lat");
68✔
2128
        NITFEncodeDMSLoc(szIGEOLO + 7, sizeof(szIGEOLO) - 7, dfULX, "Long");
68✔
2129
        NITFEncodeDMSLoc(szIGEOLO + 15, sizeof(szIGEOLO) - 15, dfURY, "Lat");
68✔
2130
        NITFEncodeDMSLoc(szIGEOLO + 22, sizeof(szIGEOLO) - 22, dfURX, "Long");
68✔
2131
        NITFEncodeDMSLoc(szIGEOLO + 30, sizeof(szIGEOLO) - 30, dfLRY, "Lat");
68✔
2132
        NITFEncodeDMSLoc(szIGEOLO + 37, sizeof(szIGEOLO) - 37, dfLRX, "Long");
68✔
2133
        NITFEncodeDMSLoc(szIGEOLO + 45, sizeof(szIGEOLO) - 45, dfLLY, "Lat");
68✔
2134
        NITFEncodeDMSLoc(szIGEOLO + 52, sizeof(szIGEOLO) - 52, dfLLX, "Long");
68✔
2135
    }
2136
    /* -------------------------------------------------------------------- */
2137
    /*      Format geographic coordinates in decimal degrees                */
2138
    /* -------------------------------------------------------------------- */
2139
    else if (chICORDS == 'D')
23✔
2140
    {
2141
        if (fabs(dfULX) > 180 || fabs(dfURX) > 180 || fabs(dfLRX) > 180 ||
3✔
2142
            fabs(dfLLX) > 180 || fabs(dfULY) > 90 || fabs(dfURY) > 90 ||
3✔
2143
            fabs(dfLRY) > 90 || fabs(dfLLY) > 90)
3✔
2144
        {
2145
            CPLError(
×
2146
                CE_Failure, CPLE_AppDefined,
2147
                "Attempt to write geographic bound outside of legal range.");
2148
            return FALSE;
×
2149
        }
2150

2151
        CPLsnprintf(szIGEOLO + 0, sizeof(szIGEOLO), "%+#07.3f%+#08.3f", dfULY,
3✔
2152
                    dfULX);
2153
        CPLsnprintf(szIGEOLO + 15, sizeof(szIGEOLO) - 15, "%+#07.3f%+#08.3f",
3✔
2154
                    dfURY, dfURX);
2155
        CPLsnprintf(szIGEOLO + 30, sizeof(szIGEOLO) - 30, "%+#07.3f%+#08.3f",
3✔
2156
                    dfLRY, dfLRX);
2157
        CPLsnprintf(szIGEOLO + 45, sizeof(szIGEOLO) - 45, "%+#07.3f%+#08.3f",
3✔
2158
                    dfLLY, dfLLX);
2159
    }
2160

2161
    /* -------------------------------------------------------------------- */
2162
    /*      Format UTM coordinates.                                         */
2163
    /* -------------------------------------------------------------------- */
2164
    else if (chICORDS == 'N' || chICORDS == 'S')
20✔
2165
    {
2166
        CHECK_IGEOLO_UTM_X("dfULX", dfULX);
20✔
2167
        CHECK_IGEOLO_UTM_Y("dfULY", dfULY);
20✔
2168
        CHECK_IGEOLO_UTM_X("dfURX", dfURX);
20✔
2169
        CHECK_IGEOLO_UTM_Y("dfURY", dfURY);
20✔
2170
        CHECK_IGEOLO_UTM_X("dfLRX", dfLRX);
20✔
2171
        CHECK_IGEOLO_UTM_Y("dfLRY", dfLRY);
20✔
2172
        CHECK_IGEOLO_UTM_X("dfLLX", dfLLX);
20✔
2173
        CHECK_IGEOLO_UTM_Y("dfLLY", dfLLY);
20✔
2174
        CPLsnprintf(szIGEOLO + 0, sizeof(szIGEOLO), "%02d%06d%07d", nZone,
20✔
2175
                    (int)floor(dfULX + 0.5), (int)floor(dfULY + 0.5));
20✔
2176
        CPLsnprintf(szIGEOLO + 15, sizeof(szIGEOLO) - 15, "%02d%06d%07d", nZone,
20✔
2177
                    (int)floor(dfURX + 0.5), (int)floor(dfURY + 0.5));
20✔
2178
        CPLsnprintf(szIGEOLO + 30, sizeof(szIGEOLO) - 30, "%02d%06d%07d", nZone,
20✔
2179
                    (int)floor(dfLRX + 0.5), (int)floor(dfLRY + 0.5));
20✔
2180
        CPLsnprintf(szIGEOLO + 45, sizeof(szIGEOLO) - 45, "%02d%06d%07d", nZone,
20✔
2181
                    (int)floor(dfLLX + 0.5), (int)floor(dfLLY + 0.5));
20✔
2182
    }
2183

2184
    /* -------------------------------------------------------------------- */
2185
    /*      Write IGEOLO data to disk.                                      */
2186
    /* -------------------------------------------------------------------- */
2187
    if (VSIFSeekL(psImage->psFile->fp,
91✔
2188
                  psImage->psFile->pasSegmentInfo[psImage->iSegment]
91✔
2189
                          .nSegmentHeaderStart +
91✔
2190
                      372,
2191
                  SEEK_SET) == 0 &&
91✔
2192
        VSIFWriteL(szIGEOLO, 1, 60, psImage->psFile->fp) == 60)
91✔
2193
    {
2194
        return TRUE;
91✔
2195
    }
2196
    else
2197
    {
2198
        CPLError(CE_Failure, CPLE_AppDefined,
×
2199
                 "I/O Error writing IGEOLO segment.\n%s", VSIStrerror(errno));
×
2200
        return FALSE;
×
2201
    }
2202
}
2203

2204
/************************************************************************/
2205
/*                            NITFWriteLUT()                            */
2206
/************************************************************************/
2207

2208
int NITFWriteLUT(NITFImage *psImage, int nBand, int nColors,
2✔
2209
                 unsigned char *pabyLUT)
2210

2211
{
2212
    NITFBandInfo *psBandInfo;
2213
    int bSuccess = TRUE;
2✔
2214

2215
    if (nBand < 1 || nBand > psImage->nBands)
2✔
2216
        return FALSE;
×
2217

2218
    psBandInfo = psImage->pasBandInfo + (nBand - 1);
2✔
2219

2220
    if (nColors > psBandInfo->nSignificantLUTEntries)
2✔
2221
    {
2222
        CPLError(CE_Failure, CPLE_AppDefined,
×
2223
                 "Unable to write all %d LUT entries, only able to write %d.",
2224
                 nColors, psBandInfo->nSignificantLUTEntries);
2225
        nColors = psBandInfo->nSignificantLUTEntries;
×
2226
        bSuccess = FALSE;
×
2227
    }
2228

2229
    bSuccess &=
2✔
2230
        VSIFSeekL(psImage->psFile->fp, psBandInfo->nLUTLocation, SEEK_SET) == 0;
2✔
2231
    bSuccess &=
2✔
2232
        (int)VSIFWriteL(pabyLUT, 1, nColors, psImage->psFile->fp) == nColors;
2✔
2233
    bSuccess &=
2✔
2234
        VSIFSeekL(psImage->psFile->fp,
2✔
2235
                  psBandInfo->nLUTLocation + psBandInfo->nSignificantLUTEntries,
2✔
2236
                  SEEK_SET) == 0;
2✔
2237
    bSuccess &= (int)VSIFWriteL(pabyLUT + 256, 1, nColors,
4✔
2238
                                psImage->psFile->fp) == nColors;
2✔
2239
    bSuccess &= VSIFSeekL(psImage->psFile->fp,
4✔
2240
                          psBandInfo->nLUTLocation +
2✔
2241
                              2 * psBandInfo->nSignificantLUTEntries,
2✔
2242
                          SEEK_SET) == 0;
2✔
2243
    bSuccess &= (int)VSIFWriteL(pabyLUT + 512, 1, nColors,
4✔
2244
                                psImage->psFile->fp) == nColors;
2✔
2245

2246
    return bSuccess;
2✔
2247
}
2248

2249
/************************************************************************/
2250
/*                           NITFTrimWhite()                            */
2251
/*                                                                      */
2252
/*      Trim any white space off the white of the passed string in      */
2253
/*      place.                                                          */
2254
/************************************************************************/
2255

2256
char *NITFTrimWhite(char *pszTarget)
469,380✔
2257

2258
{
2259
    int i;
2260

2261
    i = (int)strlen(pszTarget) - 1;
469,380✔
2262
    while (i >= 0 && pszTarget[i] == ' ')
2,097,490✔
2263
        pszTarget[i--] = '\0';
1,628,110✔
2264

2265
    return pszTarget;
469,380✔
2266
}
2267

2268
/************************************************************************/
2269
/*                           NITFSwapWords()                            */
2270
/************************************************************************/
2271

2272
#ifdef CPL_LSB
2273

2274
static void NITFSwapWordsInternal(void *pData, int nWordSize, int nWordCount,
51,807✔
2275
                                  int nWordSkip)
2276

2277
{
2278
    int i;
2279
    GByte *pabyData = (GByte *)pData;
51,807✔
2280

2281
    switch (nWordSize)
51,807✔
2282
    {
2283
        case 1:
50,907✔
2284
            break;
50,907✔
2285

2286
        case 2:
401✔
2287
            for (i = 0; i < nWordCount; i++)
126,337✔
2288
            {
2289
                GByte byTemp;
2290

2291
                byTemp = pabyData[0];
125,936✔
2292
                pabyData[0] = pabyData[1];
125,936✔
2293
                pabyData[1] = byTemp;
125,936✔
2294

2295
                pabyData += nWordSkip;
125,936✔
2296
            }
2297
            break;
401✔
2298

2299
        case 4:
420✔
2300
            for (i = 0; i < nWordCount; i++)
11,420✔
2301
            {
2302
                GByte byTemp;
2303

2304
                byTemp = pabyData[0];
11,000✔
2305
                pabyData[0] = pabyData[3];
11,000✔
2306
                pabyData[3] = byTemp;
11,000✔
2307

2308
                byTemp = pabyData[1];
11,000✔
2309
                pabyData[1] = pabyData[2];
11,000✔
2310
                pabyData[2] = byTemp;
11,000✔
2311

2312
                pabyData += nWordSkip;
11,000✔
2313
            }
2314
            break;
420✔
2315

2316
        case 8:
80✔
2317
            for (i = 0; i < nWordCount; i++)
1,480✔
2318
            {
2319
                GByte byTemp;
2320

2321
                byTemp = pabyData[0];
1,400✔
2322
                pabyData[0] = pabyData[7];
1,400✔
2323
                pabyData[7] = byTemp;
1,400✔
2324

2325
                byTemp = pabyData[1];
1,400✔
2326
                pabyData[1] = pabyData[6];
1,400✔
2327
                pabyData[6] = byTemp;
1,400✔
2328

2329
                byTemp = pabyData[2];
1,400✔
2330
                pabyData[2] = pabyData[5];
1,400✔
2331
                pabyData[5] = byTemp;
1,400✔
2332

2333
                byTemp = pabyData[3];
1,400✔
2334
                pabyData[3] = pabyData[4];
1,400✔
2335
                pabyData[4] = byTemp;
1,400✔
2336

2337
                pabyData += nWordSkip;
1,400✔
2338
            }
2339
            break;
80✔
2340

UNCOV
2341
        default:
×
UNCOV
2342
            break;
×
2343
    }
2344
}
51,807✔
2345

2346
/* Swap real or complex types */
2347
static void NITFSwapWords(NITFImage *psImage, void *pData, int nWordCount)
51,827✔
2348

2349
{
2350
    if (psImage->nWordSize * 8 != psImage->nBitsPerSample)
51,827✔
2351
    {
2352
        // FIXME ?
2353
        return;
19✔
2354
    }
2355

2356
    if (EQUAL(psImage->szPVType, "C"))
51,808✔
2357
    {
2358
        /* According to
2359
         * http://jitc.fhu.disa.mil/nitf/tag_reg/imagesubheader/pvtype.html */
2360
        /* "C values shall be represented with the Real and Imaginary parts,
2361
         * each represented */
2362
        /* in IEEE 32 or 64-bit floating point representation (IEEE 754) and
2363
         * appearing in */
2364
        /* adjacent four or eight-byte blocks, first Real, then Imaginary" */
2365
        NITFSwapWordsInternal(pData, psImage->nWordSize / 2, 2 * nWordCount,
20✔
2366
                              psImage->nWordSize / 2);
20✔
2367
    }
2368
    else
2369
    {
2370
        NITFSwapWordsInternal(pData, psImage->nWordSize, nWordCount,
51,788✔
2371
                              psImage->nWordSize);
2372
    }
2373
}
2374

2375
#endif /* def CPL_LSB */
2376

2377
/************************************************************************/
2378
/*                           NITFReadCSEXRA()                           */
2379
/*                                                                      */
2380
/*      Read a CSEXRA TRE and return contents as metadata strings.      */
2381
/************************************************************************/
2382

2383
char **NITFReadCSEXRA(NITFImage *psImage)
×
2384

2385
{
2386
    return NITFGenericMetadataRead(NULL, NULL, psImage, "CSEXRA");
×
2387
}
2388

2389
/************************************************************************/
2390
/*                           NITFReadPIAIMC()                           */
2391
/*                                                                      */
2392
/*      Read a PIAIMC TRE and return contents as metadata strings.      */
2393
/************************************************************************/
2394

2395
char **NITFReadPIAIMC(NITFImage *psImage)
×
2396

2397
{
2398
    return NITFGenericMetadataRead(NULL, NULL, psImage, "PIAIMC");
×
2399
}
2400

2401
/************************************************************************/
2402
/*                    NITFFormatRPC00BCoefficient()                     */
2403
/*                                                                      */
2404
/*      Format coefficients like +X.XXXXXXE+X (12 bytes)                */
2405
/************************************************************************/
2406
static int NITFFormatRPC00BCoefficient(char *pszBuffer, double dfVal,
1,202✔
2407
                                       int *pbPrecisionLoss)
2408
{
2409
    // We need 12 bytes + 2=3-1 bytes for MSVC potentially outputting exponents
2410
    // with 3 digits + 1 terminating byte
2411
    char szTemp[12 + 2 + 1];
2412
#if defined(DEBUG) || defined(_WIN32)
2413
    int nLen;
2414
#endif
2415

2416
    if (fabs(dfVal) > 9.999999e9)
1,202✔
2417
    {
2418
        CPLError(CE_Failure, CPLE_AppDefined, "Coefficient out of range: %g",
1✔
2419
                 dfVal);
2420
        return FALSE;
1✔
2421
    }
2422

2423
    CPLsnprintf(szTemp, sizeof(szTemp), "%+.6E", dfVal);
1,201✔
2424
#if defined(DEBUG) || defined(_WIN32)
2425
    nLen = (int)strlen(szTemp);
1,201✔
2426
    CPL_IGNORE_RET_VAL_INT(nLen);
1,201✔
2427
#endif
2428
    CPLAssert(szTemp[9] == 'E');
1,201✔
2429
#ifdef _WIN32
2430
    if (nLen == 14)  // Old MSVC versions: 3 digits for the exponent
2431
    {
2432
        if (szTemp[11] != DIGIT_ZERO || szTemp[12] != DIGIT_ZERO)
2433
        {
2434
            CPLError(CE_Warning, CPLE_AppDefined, "%g rounded to 0", dfVal);
2435
            snprintf(pszBuffer, 12 + 1, "%s", "+0.000000E+0");
2436
            if (pbPrecisionLoss)
2437
                *pbPrecisionLoss = TRUE;
2438
            return TRUE;
2439
        }
2440
        szTemp[11] = szTemp[13];
2441
    }
2442
    else  // behavior of the standard: 2 digits for the exponent
2443
#endif
2444
    {
2445
        CPLAssert(nLen == 13);
1,201✔
2446
        if (szTemp[11] != DIGIT_ZERO)
1,201✔
2447
        {
2448
            CPLError(CE_Warning, CPLE_AppDefined, "%g rounded to 0", dfVal);
2✔
2449
            snprintf(pszBuffer, 12 + 1, "%s", "+0.000000E+0");
2✔
2450
            if (pbPrecisionLoss)
2✔
2451
                *pbPrecisionLoss = TRUE;
2✔
2452
            return TRUE;
2✔
2453
        }
2454
        szTemp[11] = szTemp[12];
1,199✔
2455
    }
2456
    szTemp[12] = '\0';
1,199✔
2457
    memcpy(pszBuffer, szTemp, strlen(szTemp) + 1);
1,199✔
2458
    return TRUE;
1,199✔
2459
}
2460

2461
/************************************************************************/
2462
/*                   NITFFormatRPC00BFromMetadata()                     */
2463
/*                                                                      */
2464
/*      Format the content of a RPC00B TRE from RPC metadata            */
2465
/************************************************************************/
2466

2467
char *NITFFormatRPC00BFromMetadata(char **papszRPC, int *pbPrecisionLoss)
26✔
2468
{
2469
    GDALRPCInfoV2 sRPC;
2470
    char *pszRPC00B;
2471
    double dfErrBIAS;
2472
    double dfErrRAND;
2473
    int nOffset;
2474
    int nLength;
2475
    int nRounded;
2476
    int i;
2477
    char szTemp[24];
2478

2479
    if (pbPrecisionLoss)
26✔
2480
        *pbPrecisionLoss = FALSE;
26✔
2481

2482
    if (!GDALExtractRPCInfoV2(papszRPC, &sRPC))
26✔
2483
        return NULL;
×
2484

2485
    pszRPC00B = (char *)CPLMalloc(1041 + 1);
26✔
2486
    pszRPC00B[0] = '1'; /* success flag */
26✔
2487
    nOffset = 1;
26✔
2488

2489
    dfErrBIAS = sRPC.dfERR_BIAS;
26✔
2490
    if (dfErrBIAS == -1.0)  // value by default to indicate unknown
26✔
2491
    {
2492
        dfErrBIAS = 0.0;
1✔
2493
    }
2494
    else if (dfErrBIAS < 0)
25✔
2495
    {
2496
        CPLError(CE_Warning, CPLE_AppDefined,
×
2497
                 "Correcting ERR_BIAS from %f to 0", dfErrBIAS);
2498
    }
2499
    else if (dfErrBIAS > 9999.99)
25✔
2500
    {
2501
        CPLError(CE_Warning, CPLE_AppDefined,
×
2502
                 "ERR_BIAS out of range. Clamping to 9999.99");
2503
        dfErrBIAS = 9999.99;
×
2504
    }
2505
    nLength = 7;
26✔
2506
    CPLsnprintf(pszRPC00B + nOffset, nLength + 1, "%07.2f", dfErrBIAS);
26✔
2507
    nOffset += nLength;
26✔
2508

2509
    dfErrRAND = sRPC.dfERR_RAND;
26✔
2510
    if (dfErrRAND == -1.0)  // value by default to indicate unknown
26✔
2511
    {
2512
        dfErrRAND = 0.0;
1✔
2513
    }
2514
    else if (dfErrRAND < 0)
25✔
2515
    {
2516
        CPLError(CE_Warning, CPLE_AppDefined,
×
2517
                 "Correcting ERR_RAND from %f to 0", dfErrRAND);
2518
        if (pbPrecisionLoss)
×
2519
            *pbPrecisionLoss = TRUE;
×
2520
    }
2521
    else if (dfErrRAND > 9999.99)
25✔
2522
    {
2523
        CPLError(CE_Warning, CPLE_AppDefined,
×
2524
                 "ERR_RAND out of range. Clamping to 9999.99");
2525
        dfErrRAND = 9999.99;
×
2526
        if (pbPrecisionLoss)
×
2527
            *pbPrecisionLoss = TRUE;
×
2528
    }
2529
    nLength = 7;
26✔
2530
    CPLsnprintf(pszRPC00B + nOffset, nLength + 1, "%07.2f", dfErrRAND);
26✔
2531
    nOffset += nLength;
26✔
2532

2533
    nLength = 6;
26✔
2534
    if (sRPC.dfLINE_OFF < 0 || sRPC.dfLINE_OFF >= 1e6)
26✔
2535
    {
2536
        CPLError(CE_Failure, CPLE_AppDefined, "LINE_OFF out of range.");
1✔
2537
        CPLFree(pszRPC00B);
1✔
2538
        return NULL;
1✔
2539
    }
2540
    nRounded = (int)floor(sRPC.dfLINE_OFF + 0.5);
25✔
2541
    if (fabs(nRounded - sRPC.dfLINE_OFF) > 1e-2)
25✔
2542
    {
2543
        CPLError(CE_Warning, CPLE_AppDefined,
1✔
2544
                 "LINE_OFF was rounded from %f to %d", sRPC.dfLINE_OFF,
2545
                 nRounded);
2546
        if (pbPrecisionLoss)
1✔
2547
            *pbPrecisionLoss = TRUE;
1✔
2548
    }
2549
    CPLsnprintf(pszRPC00B + nOffset, nLength + 1, "%06d", nRounded);
25✔
2550
    nOffset += nLength;
25✔
2551

2552
    nLength = 5;
25✔
2553
    if (sRPC.dfSAMP_OFF < 0 || sRPC.dfSAMP_OFF >= 1e5)
25✔
2554
    {
2555
        CPLError(CE_Failure, CPLE_AppDefined, "SAMP_OFF out of range.");
1✔
2556
        CPLFree(pszRPC00B);
1✔
2557
        return NULL;
1✔
2558
    }
2559
    nRounded = (int)floor(sRPC.dfSAMP_OFF + 0.5);
24✔
2560
    if (fabs(nRounded - sRPC.dfSAMP_OFF) > 1e-2)
24✔
2561
    {
2562
        CPLError(CE_Warning, CPLE_AppDefined,
1✔
2563
                 "SAMP_OFF was rounded from %f to %d", sRPC.dfSAMP_OFF,
2564
                 nRounded);
2565
        if (pbPrecisionLoss)
1✔
2566
            *pbPrecisionLoss = TRUE;
1✔
2567
    }
2568
    CPLsnprintf(pszRPC00B + nOffset, nLength + 1, "%05d", nRounded);
24✔
2569
    nOffset += nLength;
24✔
2570

2571
    nLength = 8;
24✔
2572
    if (fabs(sRPC.dfLAT_OFF) > 90)
24✔
2573
    {
2574
        CPLError(CE_Failure, CPLE_AppDefined, "LAT_OFF out of range.");
1✔
2575
        CPLFree(pszRPC00B);
1✔
2576
        return NULL;
1✔
2577
    }
2578
    CPLsnprintf(pszRPC00B + nOffset, nLength + 1, "%+08.4f", sRPC.dfLAT_OFF);
23✔
2579
    if (fabs(sRPC.dfLAT_OFF -
23✔
2580
             CPLAtof(NITFGetField(szTemp, pszRPC00B, nOffset, nLength))) > 1e-8)
23✔
2581
    {
2582
        CPLError(CE_Warning, CPLE_AppDefined,
1✔
2583
                 "LAT_OFF was rounded from %f to %s", sRPC.dfLAT_OFF, szTemp);
2584
        if (pbPrecisionLoss)
1✔
2585
            *pbPrecisionLoss = TRUE;
1✔
2586
    }
2587
    nOffset += nLength;
23✔
2588

2589
    nLength = 9;
23✔
2590
    if (fabs(sRPC.dfLONG_OFF) > 180)
23✔
2591
    {
2592
        CPLError(CE_Failure, CPLE_AppDefined, "LONG_OFF out of range.");
1✔
2593
        CPLFree(pszRPC00B);
1✔
2594
        return NULL;
1✔
2595
    }
2596
    CPLsnprintf(pszRPC00B + nOffset, nLength + 1, "%+09.4f", sRPC.dfLONG_OFF);
22✔
2597
    if (fabs(sRPC.dfLONG_OFF -
22✔
2598
             CPLAtof(NITFGetField(szTemp, pszRPC00B, nOffset, nLength))) > 1e-8)
22✔
2599
    {
2600
        CPLError(CE_Warning, CPLE_AppDefined,
1✔
2601
                 "LONG_OFF was rounded from %f to %s", sRPC.dfLONG_OFF, szTemp);
2602
        if (pbPrecisionLoss)
1✔
2603
            *pbPrecisionLoss = TRUE;
1✔
2604
    }
2605
    nOffset += nLength;
22✔
2606

2607
    nLength = 5;
22✔
2608
    if (fabs(sRPC.dfHEIGHT_OFF) > 9999)
22✔
2609
    {
2610
        CPLError(CE_Failure, CPLE_AppDefined, "HEIGHT_OFF out of range.");
1✔
2611
        CPLFree(pszRPC00B);
1✔
2612
        return NULL;
1✔
2613
    }
2614
    nRounded = (int)floor(sRPC.dfHEIGHT_OFF + 0.5);
21✔
2615
    if (fabs(nRounded - sRPC.dfHEIGHT_OFF) > 1e-2)
21✔
2616
    {
2617
        CPLError(CE_Warning, CPLE_AppDefined,
1✔
2618
                 "HEIGHT_OFF was rounded from %f to %d", sRPC.dfHEIGHT_OFF,
2619
                 nRounded);
2620
        if (pbPrecisionLoss)
1✔
2621
            *pbPrecisionLoss = TRUE;
1✔
2622
    }
2623
    CPLsnprintf(pszRPC00B + nOffset, nLength + 1, "%+05d", nRounded);
21✔
2624
    nOffset += nLength;
21✔
2625

2626
    nLength = 6;
21✔
2627
    if (sRPC.dfLINE_SCALE < 1 || sRPC.dfLINE_SCALE >= 999999)
21✔
2628
    {
2629
        CPLError(CE_Failure, CPLE_AppDefined, "LINE_SCALE out of range.");
1✔
2630
        CPLFree(pszRPC00B);
1✔
2631
        return NULL;
1✔
2632
    }
2633
    nRounded = (int)floor(sRPC.dfLINE_SCALE + 0.5);
20✔
2634
    if (fabs(nRounded - sRPC.dfLINE_SCALE) > 1e-2)
20✔
2635
    {
2636
        CPLError(CE_Warning, CPLE_AppDefined,
1✔
2637
                 "LINE_SCALE was rounded from %f to %d", sRPC.dfLINE_SCALE,
2638
                 nRounded);
2639
        if (pbPrecisionLoss)
1✔
2640
            *pbPrecisionLoss = TRUE;
1✔
2641
    }
2642
    CPLsnprintf(pszRPC00B + nOffset, nLength + 1, "%06d", nRounded);
20✔
2643
    nOffset += nLength;
20✔
2644

2645
    nLength = 5;
20✔
2646
    if (sRPC.dfSAMP_SCALE < 1 || sRPC.dfSAMP_SCALE >= 99999)
20✔
2647
    {
2648
        CPLError(CE_Failure, CPLE_AppDefined, "SAMP_SCALE out of range.");
1✔
2649
        CPLFree(pszRPC00B);
1✔
2650
        return NULL;
1✔
2651
    }
2652
    nRounded = (int)floor(sRPC.dfSAMP_SCALE + 0.5);
19✔
2653
    if (fabs(nRounded - sRPC.dfSAMP_SCALE) > 1e-2)
19✔
2654
    {
2655
        CPLError(CE_Warning, CPLE_AppDefined,
1✔
2656
                 "SAMP_SCALE was rounded from %f to %d", sRPC.dfSAMP_SCALE,
2657
                 nRounded);
2658
        if (pbPrecisionLoss)
1✔
2659
            *pbPrecisionLoss = TRUE;
1✔
2660
    }
2661
    CPLsnprintf(pszRPC00B + nOffset, nLength + 1, "%05d", nRounded);
19✔
2662
    nOffset += nLength;
19✔
2663

2664
    nLength = 8;
19✔
2665
    if (fabs(sRPC.dfLAT_SCALE) > 90)
19✔
2666
    {
2667
        CPLError(CE_Failure, CPLE_AppDefined, "LAT_SCALE out of range.");
1✔
2668
        CPLFree(pszRPC00B);
1✔
2669
        return NULL;
1✔
2670
    }
2671
    CPLsnprintf(pszRPC00B + nOffset, nLength + 1, "%+08.4f", sRPC.dfLAT_SCALE);
18✔
2672
    if (fabs(sRPC.dfLAT_SCALE -
18✔
2673
             CPLAtof(NITFGetField(szTemp, pszRPC00B, nOffset, nLength))) > 1e-8)
18✔
2674
    {
2675
        CPLError(CE_Warning, CPLE_AppDefined,
1✔
2676
                 "LAT_SCALE was rounded from %f to %s", sRPC.dfLAT_SCALE,
2677
                 szTemp);
2678
        if (pbPrecisionLoss)
1✔
2679
            *pbPrecisionLoss = TRUE;
1✔
2680
    }
2681
    nOffset += nLength;
18✔
2682

2683
    nLength = 9;
18✔
2684
    if (fabs(sRPC.dfLONG_SCALE) > 180)
18✔
2685
    {
2686
        CPLError(CE_Failure, CPLE_AppDefined, "LONG_SCALE out of range.");
1✔
2687
        CPLFree(pszRPC00B);
1✔
2688
        return NULL;
1✔
2689
    }
2690
    CPLsnprintf(pszRPC00B + nOffset, nLength + 1, "%+09.4f", sRPC.dfLONG_SCALE);
17✔
2691
    if (fabs(sRPC.dfLONG_SCALE -
17✔
2692
             CPLAtof(NITFGetField(szTemp, pszRPC00B, nOffset, nLength))) > 1e-8)
17✔
2693
    {
2694
        CPLError(CE_Warning, CPLE_AppDefined,
1✔
2695
                 "LONG_SCALE was rounded from %f to %s", sRPC.dfLONG_SCALE,
2696
                 szTemp);
2697
        if (pbPrecisionLoss)
1✔
2698
            *pbPrecisionLoss = TRUE;
1✔
2699
    }
2700
    nOffset += nLength;
17✔
2701

2702
    nLength = 5;
17✔
2703
    if (fabs(sRPC.dfHEIGHT_SCALE) > 9999)
17✔
2704
    {
2705
        CPLError(CE_Failure, CPLE_AppDefined, "HEIGHT_SCALE out of range.");
1✔
2706
        CPLFree(pszRPC00B);
1✔
2707
        return NULL;
1✔
2708
    }
2709
    nRounded = (int)floor(sRPC.dfHEIGHT_SCALE + 0.5);
16✔
2710
    if (fabs(nRounded - sRPC.dfHEIGHT_SCALE) > 1e-2)
16✔
2711
    {
2712
        CPLError(CE_Warning, CPLE_AppDefined,
1✔
2713
                 "HEIGHT_SCALE was rounded from %f to %d", sRPC.dfHEIGHT_SCALE,
2714
                 nRounded);
2715
        if (pbPrecisionLoss)
1✔
2716
            *pbPrecisionLoss = TRUE;
1✔
2717
    }
2718
    CPLsnprintf(pszRPC00B + nOffset, nLength + 1, "%+05d", nRounded);
16✔
2719
    nOffset += nLength;
16✔
2720

2721
    /* -------------------------------------------------------------------- */
2722
    /*      Write coefficients.                                             */
2723
    /* -------------------------------------------------------------------- */
2724
    for (i = 0; i < 20; i++)
317✔
2725
    {
2726
        if (!NITFFormatRPC00BCoefficient(pszRPC00B + nOffset,
302✔
2727
                                         sRPC.adfLINE_NUM_COEFF[i],
2728
                                         pbPrecisionLoss))
2729
        {
2730
            CPLFree(pszRPC00B);
1✔
2731
            return NULL;
1✔
2732
        }
2733
        nOffset += 12;
301✔
2734
    }
2735
    for (i = 0; i < 20; i++)
315✔
2736
    {
2737
        if (!NITFFormatRPC00BCoefficient(pszRPC00B + nOffset,
300✔
2738
                                         sRPC.adfLINE_DEN_COEFF[i],
2739
                                         pbPrecisionLoss))
2740
        {
2741
            CPLFree(pszRPC00B);
×
2742
            return NULL;
×
2743
        }
2744
        nOffset += 12;
300✔
2745
    }
2746
    for (i = 0; i < 20; i++)
315✔
2747
    {
2748
        if (!NITFFormatRPC00BCoefficient(pszRPC00B + nOffset,
300✔
2749
                                         sRPC.adfSAMP_NUM_COEFF[i],
2750
                                         pbPrecisionLoss))
2751
        {
2752
            CPLFree(pszRPC00B);
×
2753
            return NULL;
×
2754
        }
2755
        nOffset += 12;
300✔
2756
    }
2757
    for (i = 0; i < 20; i++)
315✔
2758
    {
2759
        if (!NITFFormatRPC00BCoefficient(pszRPC00B + nOffset,
300✔
2760
                                         sRPC.adfSAMP_DEN_COEFF[i],
2761
                                         pbPrecisionLoss))
2762
        {
2763
            CPLFree(pszRPC00B);
×
2764
            return NULL;
×
2765
        }
2766
        nOffset += 12;
300✔
2767
    }
2768

2769
    CPLAssert(nOffset == 1041);
15✔
2770
    pszRPC00B[nOffset] = '\0';
15✔
2771
    CPLAssert(strlen(pszRPC00B) == 1041);
15✔
2772
    CPLAssert(strchr(pszRPC00B, ' ') == NULL);
15✔
2773

2774
    return pszRPC00B;
15✔
2775
}
2776

2777
/************************************************************************/
2778
/*                           NITFReadRPC00B()                           */
2779
/*                                                                      */
2780
/*      Read an RPC00A or RPC00B structure if the TRE is available.     */
2781
/*      RPC00A is remapped into RPC00B organization.                    */
2782
/************************************************************************/
2783

2784
int NITFReadRPC00B(NITFImage *psImage, NITFRPC00BInfo *psRPC)
747✔
2785

2786
{
2787
    const char *pachTRE;
2788
    int bIsRPC00A = FALSE;
747✔
2789
    int nTRESize;
2790

2791
    psRPC->SUCCESS = 0;
747✔
2792

2793
    /* -------------------------------------------------------------------- */
2794
    /*      Do we have the TRE?                                             */
2795
    /* -------------------------------------------------------------------- */
2796
    pachTRE =
2797
        NITFFindTRE(psImage->pachTRE, psImage->nTREBytes, "RPC00B", &nTRESize);
747✔
2798

2799
    if (pachTRE == NULL)
747✔
2800
    {
2801
        pachTRE = NITFFindTRE(psImage->pachTRE, psImage->nTREBytes, "RPC00A",
694✔
2802
                              &nTRESize);
2803
        if (pachTRE)
694✔
2804
            bIsRPC00A = TRUE;
×
2805
    }
2806

2807
    if (pachTRE == NULL)
747✔
2808
    {
2809
        /* No RPC00 tag. Check to see if we have the IMASDA and IMRFCA
2810
           tags (DPPDB data) before returning. */
2811
        return NITFReadIMRFCA(psImage, psRPC);
694✔
2812
    }
2813

2814
    if (nTRESize < 801 + 19 * 12 + 12)
53✔
2815
    {
2816
        CPLError(CE_Failure, CPLE_AppDefined,
×
2817
                 "Cannot read RPC00A/RPC00B TRE. Not enough bytes");
2818
        return FALSE;
×
2819
    }
2820

2821
    return NITFDeserializeRPC00B((const GByte *)pachTRE, psRPC, bIsRPC00A);
53✔
2822
}
2823

2824
/************************************************************************/
2825
/*                          NITFDeserializeRPC00B()                     */
2826
/************************************************************************/
2827

2828
int NITFDeserializeRPC00B(const GByte *pabyTRE, NITFRPC00BInfo *psRPC,
53✔
2829
                          int bIsRPC00A)
2830
{
2831
    const char *pachTRE = (const char *)pabyTRE;
53✔
2832
    char szTemp[100];
2833
    int i;
2834
    static const int anRPC00AMap[] = /* See ticket #2040 */
2835
        {0, 1, 2, 3, 4, 5, 6, 10, 7, 8, 9, 11, 14, 17, 12, 15, 18, 13, 16, 19};
2836

2837
    /* -------------------------------------------------------------------- */
2838
    /*      Parse out field values.                                         */
2839
    /* -------------------------------------------------------------------- */
2840
    psRPC->SUCCESS = atoi(NITFGetField(szTemp, pachTRE, 0, 1));
53✔
2841

2842
    if (!psRPC->SUCCESS)
53✔
2843
    {
2844
        CPLError(CE_Warning, CPLE_AppDefined, "RPC Extension not Populated!");
×
2845
    }
2846

2847
    psRPC->ERR_BIAS = CPLAtof(NITFGetField(szTemp, pachTRE, 1, 7));
53✔
2848
    psRPC->ERR_RAND = CPLAtof(NITFGetField(szTemp, pachTRE, 8, 7));
53✔
2849

2850
    psRPC->LINE_OFF = CPLAtof(NITFGetField(szTemp, pachTRE, 15, 6));
53✔
2851
    psRPC->SAMP_OFF = CPLAtof(NITFGetField(szTemp, pachTRE, 21, 5));
53✔
2852
    psRPC->LAT_OFF = CPLAtof(NITFGetField(szTemp, pachTRE, 26, 8));
53✔
2853
    psRPC->LONG_OFF = CPLAtof(NITFGetField(szTemp, pachTRE, 34, 9));
53✔
2854
    psRPC->HEIGHT_OFF = CPLAtof(NITFGetField(szTemp, pachTRE, 43, 5));
53✔
2855

2856
    psRPC->LINE_SCALE = CPLAtof(NITFGetField(szTemp, pachTRE, 48, 6));
53✔
2857
    psRPC->SAMP_SCALE = CPLAtof(NITFGetField(szTemp, pachTRE, 54, 5));
53✔
2858
    psRPC->LAT_SCALE = CPLAtof(NITFGetField(szTemp, pachTRE, 59, 8));
53✔
2859
    psRPC->LONG_SCALE = CPLAtof(NITFGetField(szTemp, pachTRE, 67, 9));
53✔
2860
    psRPC->HEIGHT_SCALE = CPLAtof(NITFGetField(szTemp, pachTRE, 76, 5));
53✔
2861

2862
    /* -------------------------------------------------------------------- */
2863
    /*      Parse out coefficients.                                         */
2864
    /* -------------------------------------------------------------------- */
2865
    for (i = 0; i < 20; i++)
1,113✔
2866
    {
2867
        int iSrcCoef = i;
1,060✔
2868

2869
        if (bIsRPC00A)
1,060✔
2870
            iSrcCoef = anRPC00AMap[i];
×
2871

2872
        psRPC->LINE_NUM_COEFF[i] =
1,060✔
2873
            CPLAtof(NITFGetField(szTemp, pachTRE, 81 + iSrcCoef * 12, 12));
1,060✔
2874
        psRPC->LINE_DEN_COEFF[i] =
1,060✔
2875
            CPLAtof(NITFGetField(szTemp, pachTRE, 321 + iSrcCoef * 12, 12));
1,060✔
2876
        psRPC->SAMP_NUM_COEFF[i] =
1,060✔
2877
            CPLAtof(NITFGetField(szTemp, pachTRE, 561 + iSrcCoef * 12, 12));
1,060✔
2878
        psRPC->SAMP_DEN_COEFF[i] =
1,060✔
2879
            CPLAtof(NITFGetField(szTemp, pachTRE, 801 + iSrcCoef * 12, 12));
1,060✔
2880
    }
2881

2882
    return TRUE;
53✔
2883
}
2884

2885
/************************************************************************/
2886
/*                           NITFReadICHIPB()                           */
2887
/*                                                                      */
2888
/*      Read an ICHIPB structure if the TRE is available.               */
2889
/************************************************************************/
2890

2891
int NITFReadICHIPB(NITFImage *psImage, NITFICHIPBInfo *psICHIP)
747✔
2892

2893
{
2894
    const char *pachTRE;
2895
    char szTemp[32];
2896
    int nTRESize;
2897

2898
    /* -------------------------------------------------------------------- */
2899
    /*      Do we have the TRE?                                             */
2900
    /* -------------------------------------------------------------------- */
2901
    pachTRE =
2902
        NITFFindTRE(psImage->pachTRE, psImage->nTREBytes, "ICHIPB", &nTRESize);
747✔
2903

2904
    if (pachTRE == NULL)
747✔
2905
    {
2906
        pachTRE = NITFFindTRE(psImage->pachTRE, psImage->nTREBytes, "ICHIPA",
744✔
2907
                              &nTRESize);
2908
    }
2909

2910
    if (pachTRE == NULL)
747✔
2911
    {
2912
        return FALSE;
744✔
2913
    }
2914

2915
    if (nTRESize < 2)
3✔
2916
    {
2917
        CPLError(CE_Failure, CPLE_AppDefined,
×
2918
                 "Cannot read ICHIPA/ICHIPB TRE. Not enough bytes");
2919
        return FALSE;
×
2920
    }
2921
    /* -------------------------------------------------------------------- */
2922
    /*      Parse out field values.                                         */
2923
    /* -------------------------------------------------------------------- */
2924
    psICHIP->XFRM_FLAG = atoi(NITFGetField(szTemp, pachTRE, 0, 2));
3✔
2925

2926
    if (psICHIP->XFRM_FLAG == 0)
3✔
2927
    {
2928
        if (nTRESize < 216 + 8)
3✔
2929
        {
2930
            CPLError(CE_Failure, CPLE_AppDefined,
×
2931
                     "Cannot read ICHIPA/ICHIPB TRE. Not enough bytes");
2932
            return FALSE;
×
2933
        }
2934

2935
        psICHIP->SCALE_FACTOR = CPLAtof(NITFGetField(szTemp, pachTRE, 2, 10));
3✔
2936
        psICHIP->ANAMORPH_CORR = atoi(NITFGetField(szTemp, pachTRE, 12, 2));
3✔
2937
        psICHIP->SCANBLK_NUM = atoi(NITFGetField(szTemp, pachTRE, 14, 2));
3✔
2938

2939
        psICHIP->OP_ROW_11 = CPLAtof(NITFGetField(szTemp, pachTRE, 16, 12));
3✔
2940
        psICHIP->OP_COL_11 = CPLAtof(NITFGetField(szTemp, pachTRE, 28, 12));
3✔
2941

2942
        psICHIP->OP_ROW_12 = CPLAtof(NITFGetField(szTemp, pachTRE, 40, 12));
3✔
2943
        psICHIP->OP_COL_12 = CPLAtof(NITFGetField(szTemp, pachTRE, 52, 12));
3✔
2944

2945
        psICHIP->OP_ROW_21 = CPLAtof(NITFGetField(szTemp, pachTRE, 64, 12));
3✔
2946
        psICHIP->OP_COL_21 = CPLAtof(NITFGetField(szTemp, pachTRE, 76, 12));
3✔
2947

2948
        psICHIP->OP_ROW_22 = CPLAtof(NITFGetField(szTemp, pachTRE, 88, 12));
3✔
2949
        psICHIP->OP_COL_22 = CPLAtof(NITFGetField(szTemp, pachTRE, 100, 12));
3✔
2950

2951
        psICHIP->FI_ROW_11 = CPLAtof(NITFGetField(szTemp, pachTRE, 112, 12));
3✔
2952
        psICHIP->FI_COL_11 = CPLAtof(NITFGetField(szTemp, pachTRE, 124, 12));
3✔
2953

2954
        psICHIP->FI_ROW_12 = CPLAtof(NITFGetField(szTemp, pachTRE, 136, 12));
3✔
2955
        psICHIP->FI_COL_12 = CPLAtof(NITFGetField(szTemp, pachTRE, 148, 12));
3✔
2956

2957
        psICHIP->FI_ROW_21 = CPLAtof(NITFGetField(szTemp, pachTRE, 160, 12));
3✔
2958
        psICHIP->FI_COL_21 = CPLAtof(NITFGetField(szTemp, pachTRE, 172, 12));
3✔
2959

2960
        psICHIP->FI_ROW_22 = CPLAtof(NITFGetField(szTemp, pachTRE, 184, 12));
3✔
2961
        psICHIP->FI_COL_22 = CPLAtof(NITFGetField(szTemp, pachTRE, 196, 12));
3✔
2962

2963
        psICHIP->FI_ROW = atoi(NITFGetField(szTemp, pachTRE, 208, 8));
3✔
2964
        psICHIP->FI_COL = atoi(NITFGetField(szTemp, pachTRE, 216, 8));
3✔
2965
    }
2966
    else
2967
    {
2968
        fprintf(stdout, "Chip is already de-warped?\n");
×
2969
    }
2970

2971
    return TRUE;
3✔
2972
}
2973

2974
/************************************************************************/
2975
/*                           NITFReadUSE00A()                           */
2976
/*                                                                      */
2977
/*      Read a USE00A TRE and return contents as metadata strings.      */
2978
/************************************************************************/
2979

2980
char **NITFReadUSE00A(NITFImage *psImage)
×
2981

2982
{
2983
    return NITFGenericMetadataRead(NULL, NULL, psImage, "USE00A");
×
2984
}
2985

2986
/************************************************************************/
2987
/*                           NITFReadBLOCKA()                           */
2988
/*                                                                      */
2989
/*      Read a BLOCKA SDE and return contents as metadata strings.      */
2990
/************************************************************************/
2991

2992
char **NITFReadBLOCKA(NITFImage *psImage)
747✔
2993

2994
{
2995
    const char *pachTRE;
2996
    int nTRESize;
2997
    char **papszMD = NULL;
747✔
2998
    int nBlockaCount = 0;
747✔
2999
    char szTemp[128];
3000

3001
    while (TRUE)
3002
    {
3003
        /* --------------------------------------------------------------------
3004
         */
3005
        /*      Do we have the TRE? */
3006
        /* --------------------------------------------------------------------
3007
         */
3008
        pachTRE = NITFFindTREByIndex(psImage->pachTRE, psImage->nTREBytes,
769✔
3009
                                     "BLOCKA", nBlockaCount, &nTRESize);
3010

3011
        if (pachTRE == NULL)
769✔
3012
            break;
744✔
3013

3014
        if (nTRESize != 123)
25✔
3015
        {
3016
            CPLError(CE_Warning, CPLE_AppDefined,
3✔
3017
                     "BLOCKA TRE wrong size, ignoring.");
3018
            break;
3✔
3019
        }
3020

3021
        nBlockaCount++;
22✔
3022

3023
        /* --------------------------------------------------------------------
3024
         */
3025
        /*      Parse out field values. */
3026
        /* --------------------------------------------------------------------
3027
         */
3028
        snprintf(szTemp, sizeof(szTemp), "NITF_BLOCKA_BLOCK_INSTANCE_%02d",
22✔
3029
                 nBlockaCount);
3030
        NITFExtractMetadata(&papszMD, pachTRE, 0, 2, szTemp);
22✔
3031
        snprintf(szTemp, sizeof(szTemp), "NITF_BLOCKA_N_GRAY_%02d",
22✔
3032
                 nBlockaCount);
3033
        NITFExtractMetadata(&papszMD, pachTRE, 2, 5, szTemp);
22✔
3034
        snprintf(szTemp, sizeof(szTemp), "NITF_BLOCKA_L_LINES_%02d",
22✔
3035
                 nBlockaCount);
3036
        NITFExtractMetadata(&papszMD, pachTRE, 7, 5, szTemp);
22✔
3037
        snprintf(szTemp, sizeof(szTemp), "NITF_BLOCKA_LAYOVER_ANGLE_%02d",
22✔
3038
                 nBlockaCount);
3039
        NITFExtractMetadata(&papszMD, pachTRE, 12, 3, szTemp);
22✔
3040
        snprintf(szTemp, sizeof(szTemp), "NITF_BLOCKA_SHADOW_ANGLE_%02d",
22✔
3041
                 nBlockaCount);
3042
        NITFExtractMetadata(&papszMD, pachTRE, 15, 3, szTemp);
22✔
3043
        /* reserved: 16 */
3044
        snprintf(szTemp, sizeof(szTemp), "NITF_BLOCKA_FRLC_LOC_%02d",
22✔
3045
                 nBlockaCount);
3046
        NITFExtractMetadata(&papszMD, pachTRE, 34, 21, szTemp);
22✔
3047
        snprintf(szTemp, sizeof(szTemp), "NITF_BLOCKA_LRLC_LOC_%02d",
22✔
3048
                 nBlockaCount);
3049
        NITFExtractMetadata(&papszMD, pachTRE, 55, 21, szTemp);
22✔
3050
        snprintf(szTemp, sizeof(szTemp), "NITF_BLOCKA_LRFC_LOC_%02d",
22✔
3051
                 nBlockaCount);
3052
        NITFExtractMetadata(&papszMD, pachTRE, 76, 21, szTemp);
22✔
3053
        snprintf(szTemp, sizeof(szTemp), "NITF_BLOCKA_FRFC_LOC_%02d",
22✔
3054
                 nBlockaCount);
3055
        NITFExtractMetadata(&papszMD, pachTRE, 97, 21, szTemp);
22✔
3056
        /* reserved: 5 -> 97 + 21 + 5 = 123 -> OK */
3057
    }
3058

3059
    if (nBlockaCount > 0)
747✔
3060
    {
3061
        snprintf(szTemp, sizeof(szTemp), "%02d", nBlockaCount);
22✔
3062
        papszMD = CSLSetNameValue(papszMD, "NITF_BLOCKA_BLOCK_COUNT", szTemp);
22✔
3063
    }
3064

3065
    return papszMD;
747✔
3066
}
3067

3068
/************************************************************************/
3069
/*                           NITFGetGCP()                               */
3070
/*                                                                      */
3071
/* Reads a geographical coordinate (lat, long) from the provided        */
3072
/* buffer.                                                              */
3073
/************************************************************************/
3074

3075
void NITFGetGCP(const char *pachCoord, double *pdfXYs, int iCoord)
8✔
3076
{
3077
    char szTemp[128];
3078

3079
    // offset to selected coordinate.
3080
    pdfXYs += 2 * iCoord;
8✔
3081

3082
    if (pachCoord[0] == 'N' || pachCoord[0] == 'n' || pachCoord[0] == 'S' ||
8✔
3083
        pachCoord[0] == 's')
8✔
3084
    {
3085
        /* ------------------------------------------------------------ */
3086
        /*                             0....+....1....+....2            */
3087
        /* Coordinates are in the form Xddmmss.ssYdddmmss.ss:           */
3088
        /* The format Xddmmss.cc represents degrees (00 to 89), minutes */
3089
        /* (00 to 59), seconds (00 to 59), and hundredths of seconds    */
3090
        /* (00 to 99) of latitude, with X = N for north or S for south, */
3091
        /* and Ydddmmss.cc represents degrees (000 to 179), minutes     */
3092
        /* (00 to 59), seconds (00 to 59), and hundredths of seconds    */
3093
        /* (00 to 99) of longitude, with Y = E for east or W for west.  */
3094
        /* ------------------------------------------------------------ */
3095

3096
        // It is critical to do the fetching of the D, M, S components
3097
        // in 3 separate statements, otherwise if NITFGetField() is
3098
        // defined in this compilation unit, the MSVC optimizer will
3099
        // generate bad code, due to szTemp being overwritten before
3100
        // being evaluated by CPLAtof() !
3101
        pdfXYs[1] = CPLAtof(NITFGetField(szTemp, pachCoord, 1, 2));
×
3102
        pdfXYs[1] += CPLAtof(NITFGetField(szTemp, pachCoord, 3, 2)) / 60.0;
×
3103
        pdfXYs[1] += CPLAtof(NITFGetField(szTemp, pachCoord, 5, 5)) / 3600.0;
×
3104

3105
        if (pachCoord[0] == 's' || pachCoord[0] == 'S')
×
3106
            pdfXYs[1] *= -1;
×
3107

3108
        // It is critical to do the fetching of the D, M, S components
3109
        // in 3 separate statements, otherwise if NITFGetField() is
3110
        // defined in this compilation unit, the MSVC optimizer will
3111
        // generate bad code, due to szTemp being overwritten before
3112
        // being evaluated by CPLAtof() !
3113
        pdfXYs[0] = CPLAtof(NITFGetField(szTemp, pachCoord, 11, 3));
×
3114
        pdfXYs[0] += CPLAtof(NITFGetField(szTemp, pachCoord, 14, 2)) / 60.0;
×
3115
        pdfXYs[0] += CPLAtof(NITFGetField(szTemp, pachCoord, 16, 5)) / 3600.0;
×
3116

3117
        if (pachCoord[10] == 'w' || pachCoord[10] == 'W')
×
3118
            pdfXYs[0] *= -1;
×
3119
    }
3120
    else
3121
    {
3122
        /* ------------------------------------------------------------ */
3123
        /*                             0....+....1....+....2            */
3124
        /* Coordinates are in the form ±dd.dddddd±ddd.dddddd:           */
3125
        /* The format ±dd.dddddd indicates degrees of latitude (north   */
3126
        /* is positive), and ±ddd.dddddd represents degrees of          */
3127
        /* longitude (east is positive).                                */
3128
        /* ------------------------------------------------------------ */
3129

3130
        pdfXYs[1] = CPLAtof(NITFGetField(szTemp, pachCoord, 0, 10));
8✔
3131
        pdfXYs[0] = CPLAtof(NITFGetField(szTemp, pachCoord, 10, 11));
8✔
3132
    }
3133
}
8✔
3134

3135
/************************************************************************/
3136
/*                           NITFReadBLOCKA_GCPs()                      */
3137
/*                                                                      */
3138
/* The BLOCKA repeat earth coordinates image corner locations described */
3139
/* by IGEOLO in the NITF image subheader, but provide higher precision. */
3140
/************************************************************************/
3141

3142
int NITFReadBLOCKA_GCPs(NITFImage *psImage)
9,754✔
3143
{
3144
    const char *pachTRE;
3145
    int nTRESize;
3146
    int nBlockaLines;
3147
    char szTemp[128];
3148

3149
    /* -------------------------------------------------------------------- */
3150
    /*      Do we have the TRE?                                             */
3151
    /* -------------------------------------------------------------------- */
3152
    pachTRE =
3153
        NITFFindTRE(psImage->pachTRE, psImage->nTREBytes, "BLOCKA", &nTRESize);
9,754✔
3154

3155
    if (pachTRE == NULL)
9,754✔
3156
        return FALSE;
9,729✔
3157

3158
    if (nTRESize != 123)
25✔
3159
    {
3160
        return FALSE;
3✔
3161
    }
3162

3163
    /* -------------------------------------------------------------------- */
3164
    /*      Parse out field values.                                         */
3165
    /* -------------------------------------------------------------------- */
3166

3167
    /* ---------------------------------------------------------------- */
3168
    /* Make sure the BLOCKA geo coordinates are set. Spaces indicate    */
3169
    /* the value of a coordinate is unavailable or inapplicable.        */
3170
    /* ---------------------------------------------------------------- */
3171
    if (pachTRE[34] == ' ' || pachTRE[55] == ' ' || pachTRE[76] == ' ' ||
22✔
3172
        pachTRE[97] == ' ')
22✔
3173
    {
3174
        return FALSE;
×
3175
    }
3176

3177
    /* ---------------------------------------------------------------- */
3178
    /* Extract the L_LINES field of BLOCKA and see if this instance     */
3179
    /* covers the whole image. This is the case if L_LINES is equal to  */
3180
    /* the no of rows of this image.                                    */
3181
    /* We use the BLOCKA only in that case!                             */
3182
    /* ---------------------------------------------------------------- */
3183
    nBlockaLines = atoi(NITFGetField(szTemp, pachTRE, 7, 5));
22✔
3184
    if (psImage->nRows != nBlockaLines)
22✔
3185
    {
3186
        return FALSE;
20✔
3187
    }
3188

3189
    /* ---------------------------------------------------------------- */
3190
    /* Note that the order of these coordinates is different from       */
3191
    /* IGEOLO/NITFImage.                                                */
3192
    /*                   IGEOLO            BLOCKA                       */
3193
    /*                   0, 0              0, MaxCol                    */
3194
    /*                   0, MaxCol         MaxRow, MaxCol               */
3195
    /*                   MaxRow, MaxCol    MaxRow, 0                    */
3196
    /*                   MaxRow, 0         0, 0                         */
3197
    /* ---------------------------------------------------------------- */
3198
    {
3199
        double *pdfXYs = &(psImage->dfULX);
2✔
3200

3201
        NITFGetGCP(pachTRE + 34, pdfXYs, 1);
2✔
3202
        NITFGetGCP(pachTRE + 55, pdfXYs, 2);
2✔
3203
        NITFGetGCP(pachTRE + 76, pdfXYs, 3);
2✔
3204
        NITFGetGCP(pachTRE + 97, pdfXYs, 0);
2✔
3205

3206
        psImage->bIsBoxCenterOfPixel = TRUE;
2✔
3207
    }
3208

3209
    /* ---------------------------------------------------------------- */
3210
    /* Regardless of the former value of ICORDS, the values are now in  */
3211
    /* decimal degrees.                                                 */
3212
    /* ---------------------------------------------------------------- */
3213

3214
    psImage->chICORDS = 'D';
2✔
3215

3216
    return TRUE;
2✔
3217
}
3218

3219
/************************************************************************/
3220
/*                        NITFReadGEOLOB()                              */
3221
/*                                                                      */
3222
/*      The GEOLOB contains high precision lat/long geotransform        */
3223
/*      values.                                                         */
3224
/************************************************************************/
3225

3226
static int NITFReadGEOLOB(NITFImage *psImage)
9,754✔
3227
{
3228
    const char *pachTRE;
3229
    int nTRESize;
3230
    char szTemp[128];
3231

3232
    /* -------------------------------------------------------------------- */
3233
    /*      Do we have the TRE?                                             */
3234
    /* -------------------------------------------------------------------- */
3235
    pachTRE =
3236
        NITFFindTRE(psImage->pachTRE, psImage->nTREBytes, "GEOLOB", &nTRESize);
9,754✔
3237

3238
    if (pachTRE == NULL)
9,754✔
3239
        return FALSE;
9,733✔
3240

3241
    if (!CPLTestBoolean(CPLGetConfigOption("NITF_USEGEOLOB", "YES")))
21✔
3242
    {
3243
        CPLDebug("NITF", "GEOLOB available, but ignored by request.");
×
3244
        return FALSE;
×
3245
    }
3246

3247
    if (nTRESize != 48)
21✔
3248
    {
3249
        CPLError(CE_Failure, CPLE_AppDefined,
×
3250
                 "Cannot read GEOLOB TRE. Wrong size.");
3251
        return FALSE;
×
3252
    }
3253

3254
    /* -------------------------------------------------------------------- */
3255
    /*      Parse out field values.                                         */
3256
    /* -------------------------------------------------------------------- */
3257
    {
3258
        double dfARV = atoi(NITFGetField(szTemp, pachTRE, 0, 9));
21✔
3259
        double dfBRV = atoi(NITFGetField(szTemp, pachTRE, 9, 9));
21✔
3260

3261
        double dfLSO = CPLAtof(NITFGetField(szTemp, pachTRE, 18, 15));
21✔
3262
        double dfPSO = CPLAtof(NITFGetField(szTemp, pachTRE, 33, 15));
21✔
3263

3264
        double dfPixelWidth = 360.0 / dfARV;
21✔
3265
        double dfPixelHeight = 360.0 / dfBRV;
21✔
3266

3267
        psImage->dfULX = dfLSO;
21✔
3268
        psImage->dfURX = psImage->dfULX + psImage->nCols * dfPixelWidth;
21✔
3269
        psImage->dfLLX = psImage->dfULX;
21✔
3270
        psImage->dfLRX = psImage->dfURX;
21✔
3271

3272
        psImage->dfULY = dfPSO;
21✔
3273
        psImage->dfURY = psImage->dfULY;
21✔
3274
        psImage->dfLLY = psImage->dfULY - psImage->nRows * dfPixelHeight;
21✔
3275
        psImage->dfLRY = psImage->dfLLY;
21✔
3276

3277
        psImage->bIsBoxCenterOfPixel = FALSE;  // GEOLOB is edge of pixel.
21✔
3278
        psImage->chICORDS = 'G';
21✔
3279

3280
        CPLDebug("NITF", "IGEOLO bounds overridden by GEOLOB TRE.");
21✔
3281
    }
3282

3283
    return TRUE;
21✔
3284
}
3285

3286
/************************************************************************/
3287
/*                         NITFFetchAttribute()                         */
3288
/*                                                                      */
3289
/*      Load one attribute given the attribute id, and the parameter    */
3290
/*      id and the number of bytes to fetch.                            */
3291
/************************************************************************/
3292

3293
static int NITFFetchAttribute(GByte *pabyAttributeSubsection, GUInt32 nASSSize,
×
3294
                              int nAttrCount, int nAttrID, int nParamID,
3295
                              GUInt32 nBytesToFetch, GByte *pabyBuffer)
3296

3297
{
3298
    int i;
3299
    GUInt32 nAttrOffset = 0;
×
3300

3301
    /* -------------------------------------------------------------------- */
3302
    /*      Scan the attribute offset table                                 */
3303
    /* -------------------------------------------------------------------- */
3304
    for (i = 0; i < nAttrCount; i++)
×
3305
    {
3306
        GByte *pabyOffsetRec = i * 8 + pabyAttributeSubsection;
×
3307

3308
        if ((pabyOffsetRec[0] * 256 + pabyOffsetRec[1]) == nAttrID &&
×
3309
            pabyOffsetRec[2] == nParamID)
×
3310
        {
3311
            memcpy(&nAttrOffset, pabyOffsetRec + 4, 4);
×
3312
            CPL_MSBPTR32(&nAttrOffset);
×
3313
            break;
×
3314
        }
3315
    }
3316

3317
    /* -------------------------------------------------------------------- */
3318
    /*      Extract the attribute value.                                    */
3319
    /* -------------------------------------------------------------------- */
3320
    if (nAttrOffset == 0)
×
3321
        return FALSE;
×
3322

3323
    if (nAttrOffset + nBytesToFetch > nASSSize)
×
3324
        return FALSE;
×
3325

3326
    memcpy(pabyBuffer, pabyAttributeSubsection + nAttrOffset, nBytesToFetch);
×
3327
    return TRUE;
×
3328
}
3329

3330
/************************************************************************/
3331
/*                      NITFLoadAttributeSection()                      */
3332
/*                                                                      */
3333
/*      Load metadata items from selected attributes in the RPF         */
3334
/*      attributes subsection.  The items are defined in                */
3335
/*      MIL-STD-2411-1 section 5.3.2.                                   */
3336
/************************************************************************/
3337

3338
static void NITFLoadAttributeSection(NITFImage *psImage)
9,754✔
3339

3340
{
3341
    int i;
3342
    GUInt32 nASHOffset = 0, /* nASHSize=0, */ nASSOffset = 0, nASSSize = 0,
9,754✔
3343
            nNextOffset = 0;
9,754✔
3344
    GInt16 nAttrCount;
3345
    GByte *pabyAttributeSubsection;
3346
    GByte abyBuffer[128];
3347

3348
    for (i = 0; i < psImage->nLocCount; i++)
9,985✔
3349
    {
3350
        if (psImage->pasLocations[i].nLocId == LID_AttributeSectionSubheader)
231✔
3351
        {
3352
            nASHOffset = psImage->pasLocations[i].nLocOffset;
×
3353
            /* nASHSize = psImage->pasLocations[i].nLocSize; */
3354
        }
3355
        else if (psImage->pasLocations[i].nLocId == LID_AttributeSubsection)
231✔
3356
        {
3357
            nASSOffset = psImage->pasLocations[i].nLocOffset;
×
3358
            nASSSize = psImage->pasLocations[i].nLocSize;
×
3359
        }
3360
    }
3361

3362
    if (nASSOffset == 0 || nASHOffset == 0)
9,754✔
3363
        return;
9,754✔
3364

3365
    /* -------------------------------------------------------------------- */
3366
    /*      How many attribute records do we have?                          */
3367
    /* -------------------------------------------------------------------- */
3368
    if (VSIFSeekL(psImage->psFile->fp, nASHOffset, SEEK_SET) != 0 ||
×
3369
        VSIFReadL(&nAttrCount, 2, 1, psImage->psFile->fp) != 1)
×
3370
        return;
×
3371

3372
    CPL_MSBPTR16(&nAttrCount);
×
3373

3374
    /* -------------------------------------------------------------------- */
3375
    /*      nASSSize Hack                                                   */
3376
    /* -------------------------------------------------------------------- */
3377
    /* OK, now, as often with RPF/CADRG, here is the necessary dirty hack */
3378
    /* -- Begin of lengthy explanation -- */
3379
    /* A lot of CADRG files have a nASSSize value that reports a size */
3380
    /* smaller than the genuine size of the attribute subsection in the */
3381
    /* file, so if we trust the nASSSize value, we'll reject existing */
3382
    /* attributes. This is for example the case for */
3383
    /* http://download.osgeo.org/gdal/data/nitf/0000M033.GN3 */
3384
    /* where nASSSize is reported to be 302 bytes for 52 attributes (which */
3385
    /* is odd since 52 * 8 < 302), but a binary inspection of the attribute */
3386
    /* subsection shows that the actual size is 608 bytes, which is also
3387
     * confirmed*/
3388
    /* by the fact that the next subsection (quite often
3389
     * LID_ExplicitArealCoverageTable but not always) */
3390
    /* begins right after. So if this next subsection is found and that the */
3391
    /* difference in offset is larger than the original nASSSize, use it. */
3392
    /* I have observed that nowhere in the NITF driver we make use of the
3393
     * .nLocSize field */
3394
    /* -- End of lengthy explanation -- */
3395

3396
    for (i = 0; i < psImage->nLocCount; i++)
×
3397
    {
3398
        if (psImage->pasLocations[i].nLocOffset > nASSOffset)
×
3399
        {
3400
            if (nNextOffset == 0 ||
×
3401
                nNextOffset > psImage->pasLocations[i].nLocOffset)
×
3402
                nNextOffset = psImage->pasLocations[i].nLocOffset;
×
3403
        }
3404
    }
3405

3406
    if (nNextOffset > 0 && nNextOffset - nASSOffset > nASSSize)
×
3407
        nASSSize = nNextOffset - nASSOffset;
×
3408

3409
    /* -------------------------------------------------------------------- */
3410
    /*      Be sure that the attribute subsection is large enough to        */
3411
    /*      hold the offset table (otherwise NITFFetchAttribute could       */
3412
    /*      read out of the buffer)                                         */
3413
    /* -------------------------------------------------------------------- */
3414
    if (nASSSize < (size_t)(8 * nAttrCount))
×
3415
    {
3416
        CPLError(CE_Warning, CPLE_AppDefined,
×
3417
                 "Attribute subsection not large enough (%d bytes) to contain "
3418
                 "%d attributes.",
3419
                 nASSSize, nAttrCount);
3420
        return;
×
3421
    }
3422

3423
    /* -------------------------------------------------------------------- */
3424
    /*      Load the attribute table.                                       */
3425
    /* -------------------------------------------------------------------- */
3426
    pabyAttributeSubsection = (GByte *)VSIMalloc(nASSSize);
×
3427
    if (pabyAttributeSubsection == NULL)
×
3428
    {
3429
        CPLError(
×
3430
            CE_Warning, CPLE_AppDefined,
3431
            "Out of memory failure reading %d bytes of attribute subsection.",
3432
            nASSSize);
3433
        return;
×
3434
    }
3435

3436
    if (VSIFSeekL(psImage->psFile->fp, nASSOffset, SEEK_SET) != 0 ||
×
3437
        VSIFReadL(pabyAttributeSubsection, 1, nASSSize, psImage->psFile->fp) !=
×
3438
            nASSSize)
3439
    {
3440
        CPLError(CE_Warning, CPLE_FileIO,
×
3441
                 "I/O error when reading attribute subsection.");
3442
        CPLFree(pabyAttributeSubsection);
×
3443
        return;
×
3444
    }
3445

3446
    /* -------------------------------------------------------------------- */
3447
    /*      Scan for some particular attributes we would like.              */
3448
    /* -------------------------------------------------------------------- */
3449
    if (NITFFetchAttribute(pabyAttributeSubsection, nASSSize, nAttrCount, 1, 1,
×
3450
                           8, abyBuffer))
3451
        NITFExtractMetadata(&(psImage->papszMetadata), (char *)abyBuffer, 0, 8,
×
3452
                            "NITF_RPF_CurrencyDate");
3453
    if (NITFFetchAttribute(pabyAttributeSubsection, nASSSize, nAttrCount, 2, 1,
×
3454
                           8, abyBuffer))
3455
        NITFExtractMetadata(&(psImage->papszMetadata), (char *)abyBuffer, 0, 8,
×
3456
                            "NITF_RPF_ProductionDate");
3457
    if (NITFFetchAttribute(pabyAttributeSubsection, nASSSize, nAttrCount, 3, 1,
×
3458
                           8, abyBuffer))
3459
        NITFExtractMetadata(&(psImage->papszMetadata), (char *)abyBuffer, 0, 8,
×
3460
                            "NITF_RPF_SignificantDate");
3461

3462
    CPLFree(pabyAttributeSubsection);
×
3463
}
3464

3465
/************************************************************************/
3466
/*                       NITFLoadColormapSubSection()                   */
3467
/************************************************************************/
3468

3469
/* This function is directly inspired by function parse_clut coming from
3470
   ogdi/driver/rpf/utils.c and placed under the following copyright */
3471

3472
/*
3473
 ******************************************************************************
3474
 * Copyright (C) 1995 Logiciels et Applications Scientifiques (L.A.S.) Inc
3475
 * Permission to use, copy, modify and distribute this software and
3476
 * its documentation for any purpose and without fee is hereby granted,
3477
 * provided that the above copyright notice appear in all copies, that
3478
 * both the copyright notice and this permission notice appear in
3479
 * supporting documentation, and that the name of L.A.S. Inc not be used
3480
 * in advertising or publicity pertaining to distribution of the software
3481
 * without specific, written prior permission. L.A.S. Inc. makes no
3482
 * representations about the suitability of this software for any purpose.
3483
 * It is provided "as is" without express or implied warranty.
3484
 ******************************************************************************
3485
 */
3486

3487
static void NITFLoadColormapSubSection(NITFImage *psImage)
9,598✔
3488
{
3489
    int nLocBaseColorGrayscaleSection = 0;
9,598✔
3490
    int nLocBaseColormapSubSection = 0;
9,598✔
3491
    /* int colorGrayscaleSectionSize = 0; */
3492
    /* int colormapSubSectionSize = 0; */
3493
    NITFFile *psFile = psImage->psFile;
9,598✔
3494
    unsigned int i, j;
3495
    unsigned char nOffsetRecs;
3496
    NITFColormapRecord *colormapRecords;
3497
    unsigned int colormapOffsetTableOffset;
3498
    unsigned short offsetRecLen;
3499
    int bOK = TRUE;
9,598✔
3500

3501
    NITFBandInfo *psBandInfo = psImage->pasBandInfo;
9,598✔
3502

3503
    for (i = 0; (int)i < psImage->nLocCount; i++)
9,829✔
3504
    {
3505
        if (psImage->pasLocations[i].nLocId ==
231✔
3506
            LID_ColorGrayscaleSectionSubheader)
3507
        {
3508
            nLocBaseColorGrayscaleSection = psImage->pasLocations[i].nLocOffset;
23✔
3509
            /* colorGrayscaleSectionSize = psImage->pasLocations[i].nLocSize; */
3510
        }
3511
        else if (psImage->pasLocations[i].nLocId == LID_ColormapSubsection)
208✔
3512
        {
3513
            nLocBaseColormapSubSection = psImage->pasLocations[i].nLocOffset;
23✔
3514
            /* colormapSubSectionSize = psImage->pasLocations[i].nLocSize; */
3515
        }
3516
    }
3517
    if (nLocBaseColorGrayscaleSection == 0)
9,598✔
3518
    {
3519
        return;
9,575✔
3520
    }
3521
    if (nLocBaseColormapSubSection == 0)
23✔
3522
    {
3523
        return;
×
3524
    }
3525

3526
    if (VSIFSeekL(psFile->fp, nLocBaseColorGrayscaleSection, SEEK_SET) != 0 ||
46✔
3527
        VSIFReadL(&nOffsetRecs, 1, 1, psFile->fp) != 1)
23✔
3528
    {
3529
        CPLError(CE_Failure, CPLE_FileIO, "Failed to seek to %d.",
×
3530
                 nLocBaseColorGrayscaleSection);
3531
        return;
×
3532
    }
3533

3534
    if (VSIFSeekL(psFile->fp, nLocBaseColormapSubSection, SEEK_SET) != 0)
23✔
3535
    {
3536
        CPLError(CE_Failure, CPLE_FileIO, "Failed to seek to %d.",
×
3537
                 nLocBaseColormapSubSection);
3538
        return;
×
3539
    }
3540

3541
    colormapRecords = (NITFColormapRecord *)CPLMalloc(
23✔
3542
        nOffsetRecs * sizeof(NITFColormapRecord));
3543

3544
    /* colormap offset table offset length */
3545
    bOK &= VSIFReadL(&colormapOffsetTableOffset,
23✔
3546
                     sizeof(colormapOffsetTableOffset), 1, psFile->fp) == 1;
23✔
3547
    CPL_MSBPTR32(&colormapOffsetTableOffset);
23✔
3548

3549
    /* offset record length */
3550
    bOK &= VSIFReadL(&offsetRecLen, sizeof(offsetRecLen), 1, psFile->fp) == 1;
23✔
3551
    CPL_MSBPTR16(&offsetRecLen);
23✔
3552

3553
    for (i = 0; bOK && i < nOffsetRecs; i++)
92✔
3554
    {
3555
        bOK &=
69✔
3556
            VSIFReadL(&colormapRecords[i].tableId,
69✔
3557
                      sizeof(colormapRecords[i].tableId), 1, psFile->fp) == 1;
69✔
3558
        CPL_MSBPTR16(&colormapRecords[i].tableId);
69✔
3559

3560
        bOK &=
69✔
3561
            VSIFReadL(&colormapRecords[i].nRecords,
69✔
3562
                      sizeof(colormapRecords[i].nRecords), 1, psFile->fp) == 1;
69✔
3563
        CPL_MSBPTR32(&colormapRecords[i].nRecords);
69✔
3564

3565
        bOK &= VSIFReadL(&colormapRecords[i].elementLength,
69✔
3566
                         sizeof(colormapRecords[i].elementLength), 1,
3567
                         psFile->fp) == 1;
69✔
3568

3569
        bOK &= VSIFReadL(&colormapRecords[i].histogramRecordLength,
69✔
3570
                         sizeof(colormapRecords[i].histogramRecordLength), 1,
3571
                         psFile->fp) == 1;
69✔
3572
        CPL_MSBPTR16(&colormapRecords[i].histogramRecordLength);
69✔
3573

3574
        bOK &= VSIFReadL(&colormapRecords[i].colorTableOffset,
69✔
3575
                         sizeof(colormapRecords[i].colorTableOffset), 1,
3576
                         psFile->fp) == 1;
69✔
3577
        CPL_MSBPTR32(&colormapRecords[i].colorTableOffset);
69✔
3578

3579
        bOK &= VSIFReadL(&colormapRecords[i].histogramTableOffset,
69✔
3580
                         sizeof(colormapRecords[i].histogramTableOffset), 1,
3581
                         psFile->fp) == 1;
69✔
3582
        CPL_MSBPTR32(&colormapRecords[i].histogramTableOffset);
69✔
3583
    }
3584

3585
    for (i = 0; bOK && i < nOffsetRecs; i++)
92✔
3586
    {
3587
        vsi_l_offset nOffset = (vsi_l_offset)nLocBaseColormapSubSection +
69✔
3588
                               colormapRecords[i].colorTableOffset;
69✔
3589
        if (VSIFSeekL(psFile->fp, nOffset, SEEK_SET) != 0)
69✔
3590
        {
3591
            CPLError(CE_Failure, CPLE_FileIO,
×
3592
                     "Failed to seek to " CPL_FRMT_GUIB ".", nOffset);
3593
            CPLFree(colormapRecords);
×
3594
            return;
×
3595
        }
3596

3597
        /* This test is very CADRG specific. See MIL-C-89038, paragraph 3.12.5.a
3598
         */
3599
        if (i == 0 && colormapRecords[i].tableId == 2 &&
69✔
3600
            colormapRecords[i].elementLength == 4 &&
23✔
3601
            colormapRecords[i].nRecords == 216) /* read, use colortable */
23✔
3602
        {
3603
            GByte *rgbm = (GByte *)CPLMalloc(colormapRecords[i].nRecords * 4);
23✔
3604
            if (VSIFReadL(rgbm, 1, colormapRecords[i].nRecords * 4,
23✔
3605
                          psFile->fp) != colormapRecords[i].nRecords * 4)
23✔
3606
            {
3607
                CPLError(CE_Failure, CPLE_FileIO,
×
3608
                         "Failed to read %d byte rgbm.",
3609
                         colormapRecords[i].nRecords * 4);
×
3610
                CPLFree(rgbm);
×
3611
                CPLFree(colormapRecords);
×
3612
                return;
×
3613
            }
3614
            for (j = 0; j < colormapRecords[i].nRecords; j++)
4,991✔
3615
            {
3616
                psBandInfo->pabyLUT[j] = rgbm[4 * j];
4,968✔
3617
                psBandInfo->pabyLUT[j + 256] = rgbm[4 * j + 1];
4,968✔
3618
                psBandInfo->pabyLUT[j + 512] = rgbm[4 * j + 2];
4,968✔
3619
            }
3620
            CPLFree(rgbm);
23✔
3621
        }
3622
    }
3623

3624
    CPLFree(colormapRecords);
23✔
3625
}
3626

3627
/************************************************************************/
3628
/*                       NITFLoadSubframeMaskTable()                        */
3629
/************************************************************************/
3630

3631
/* Fixes bug #913 */
3632
static void NITFLoadSubframeMaskTable(NITFImage *psImage)
9,754✔
3633
{
3634
    int i;
3635
    NITFFile *psFile = psImage->psFile;
9,754✔
3636
    NITFSegmentInfo *psSegInfo = psFile->pasSegmentInfo + psImage->iSegment;
9,754✔
3637
    GUIntBig nLocBaseSpatialDataSubsection = psSegInfo->nSegmentStart;
9,754✔
3638
    GUInt32 nLocBaseMaskSubsection = 0;
9,754✔
3639
    GUInt16 subframeSequenceRecordLength, transparencySequenceRecordLength,
3640
        transparencyOutputPixelCodeLength;
3641
    int bOK = TRUE;
9,754✔
3642

3643
    for (i = 0; i < psImage->nLocCount; i++)
9,985✔
3644
    {
3645
        if (psImage->pasLocations[i].nLocId == LID_SpatialDataSubsection)
231✔
3646
        {
3647
            nLocBaseSpatialDataSubsection = psImage->pasLocations[i].nLocOffset;
23✔
3648
        }
3649
        else if (psImage->pasLocations[i].nLocId == LID_MaskSubsection)
208✔
3650
        {
3651
            nLocBaseMaskSubsection = psImage->pasLocations[i].nLocOffset;
23✔
3652
        }
3653
    }
3654
    if (nLocBaseMaskSubsection == 0)
9,754✔
3655
    {
3656
        // fprintf(stderr, "nLocBase(LID_MaskSubsection) == 0\n");
3657
        return;
9,731✔
3658
    }
3659

3660
    // fprintf(stderr, "nLocBaseMaskSubsection = %d\n", nLocBaseMaskSubsection);
3661
    if (VSIFSeekL(psFile->fp, nLocBaseMaskSubsection, SEEK_SET) != 0)
23✔
3662
    {
3663
        CPLError(CE_Failure, CPLE_FileIO, "Failed to seek to %d.",
×
3664
                 nLocBaseMaskSubsection);
3665
        return;
×
3666
    }
3667

3668
    bOK &= VSIFReadL(&subframeSequenceRecordLength,
23✔
3669
                     sizeof(subframeSequenceRecordLength), 1, psFile->fp) == 1;
23✔
3670
    CPL_MSBPTR16(&subframeSequenceRecordLength);
23✔
3671

3672
    bOK &=
23✔
3673
        VSIFReadL(&transparencySequenceRecordLength,
23✔
3674
                  sizeof(transparencySequenceRecordLength), 1, psFile->fp) == 1;
23✔
3675
    CPL_MSBPTR16(&transparencySequenceRecordLength);
23✔
3676

3677
    /* in bits */
3678
    bOK &= VSIFReadL(&transparencyOutputPixelCodeLength,
23✔
3679
                     sizeof(transparencyOutputPixelCodeLength), 1,
3680
                     psFile->fp) == 1;
23✔
3681
    CPL_MSBPTR16(&transparencyOutputPixelCodeLength);
23✔
3682

3683
    // fprintf(stderr, "transparencyOutputPixelCodeLength=%d\n",
3684
    // transparencyOutputPixelCodeLength);
3685

3686
    if (transparencyOutputPixelCodeLength == 8)
23✔
3687
    {
3688
        GByte byNodata;
3689

3690
        if (bOK && VSIFReadL(&byNodata, 1, 1, psFile->fp) == 1)
×
3691
        {
3692
            psImage->bNoDataSet = TRUE;
×
3693
            psImage->nNoDataValue = byNodata;
×
3694
        }
3695
    }
3696
    else
3697
    {
3698
        bOK &=
23✔
3699
            VSIFSeekL(psFile->fp, (transparencyOutputPixelCodeLength + 7) / 8,
23✔
3700
                      SEEK_CUR) == 0;
23✔
3701
    }
3702

3703
    /* Fix for rpf/cjnc/cjncz01/0001f023.jn1 */
3704
    if (!bOK || subframeSequenceRecordLength != 4)
23✔
3705
    {
3706
        // fprintf(stderr, "subframeSequenceRecordLength=%d\n",
3707
        // subframeSequenceRecordLength);
3708
        return;
×
3709
    }
3710

3711
    for (i = 0; i < psImage->nBlocksPerRow * psImage->nBlocksPerColumn; i++)
851✔
3712
    {
3713
        unsigned int offset;
3714
        bOK &= VSIFReadL(&offset, sizeof(offset), 1, psFile->fp) == 1;
828✔
3715
        CPL_MSBPTR32(&offset);
828✔
3716
        // fprintf(stderr, "%d : %d\n", i, offset);
3717
        if (!bOK || offset == UINT_MAX)
828✔
3718
            psImage->panBlockStart[i] = UINT_MAX;
828✔
3719
        else
3720
            psImage->panBlockStart[i] = nLocBaseSpatialDataSubsection + offset;
×
3721
    }
3722
}
3723

3724
static GUInt16 NITFReadMSBGUInt16(VSILFILE *fp, int *pbSuccess)
373✔
3725
{
3726
    GUInt16 nVal;
3727
    if (VSIFReadL(&nVal, 1, sizeof(nVal), fp) != sizeof(nVal))
373✔
3728
    {
3729
        *pbSuccess = FALSE;
×
3730
        return 0;
×
3731
    }
3732
    CPL_MSBPTR16(&nVal);
373✔
3733
    return nVal;
373✔
3734
}
3735

3736
static GUInt32 NITFReadMSBGUInt32(VSILFILE *fp, int *pbSuccess)
610✔
3737
{
3738
    GUInt32 nVal;
3739
    if (VSIFReadL(&nVal, 1, sizeof(nVal), fp) != sizeof(nVal))
610✔
3740
    {
3741
        *pbSuccess = FALSE;
×
3742
        return 0;
×
3743
    }
3744
    CPL_MSBPTR32(&nVal);
610✔
3745
    return nVal;
610✔
3746
}
3747

3748
/************************************************************************/
3749
/*                     NITFReadRPFLocationTable()                       */
3750
/************************************************************************/
3751

3752
NITFLocation *NITFReadRPFLocationTable(VSILFILE *fp, int *pnLocCount)
34✔
3753
{
3754
    /* GUInt16 nLocSectionLength; */
3755
    GUInt32 nLocSectionOffset;
3756
    GUInt16 iLoc;
3757
    GUInt16 nLocCount;
3758
    GUInt16 nLocRecordLength;
3759
    /* GUInt32 nLocComponentAggregateLength; */
3760
    NITFLocation *pasLocations = NULL;
34✔
3761
    int bSuccess;
3762
    GUIntBig nCurOffset;
3763

3764
    if (fp == NULL || pnLocCount == NULL)
34✔
3765
        return NULL;
×
3766

3767
    *pnLocCount = 0;
34✔
3768

3769
    nCurOffset = VSIFTellL(fp);
34✔
3770

3771
    bSuccess = TRUE;
34✔
3772
    /* nLocSectionLength = */ NITFReadMSBGUInt16(fp, &bSuccess);
34✔
3773
    nLocSectionOffset = NITFReadMSBGUInt32(fp, &bSuccess);
34✔
3774
    if (nLocSectionOffset != 14)
34✔
3775
    {
3776
        CPLDebug("NITF", "Unusual location section offset : %d",
×
3777
                 nLocSectionOffset);
3778
    }
3779

3780
    nLocCount = NITFReadMSBGUInt16(fp, &bSuccess);
34✔
3781

3782
    if (!bSuccess || nLocCount == 0)
34✔
3783
    {
3784
        return NULL;
×
3785
    }
3786

3787
    nLocRecordLength = NITFReadMSBGUInt16(fp, &bSuccess);
34✔
3788
    if (nLocRecordLength != 10)
34✔
3789
    {
3790
        CPLError(CE_Failure, CPLE_AppDefined,
×
3791
                 "Did not get expected record length : %d", nLocRecordLength);
3792
        return NULL;
×
3793
    }
3794

3795
    /* nLocComponentAggregateLength = */ NITFReadMSBGUInt32(fp, &bSuccess);
34✔
3796

3797
    bSuccess = VSIFSeekL(fp, nCurOffset + nLocSectionOffset, SEEK_SET) == 0;
34✔
3798

3799
    pasLocations =
3800
        (NITFLocation *)VSI_CALLOC_VERBOSE(sizeof(NITFLocation), nLocCount);
34✔
3801
    if (pasLocations == NULL)
34✔
3802
    {
3803
        return NULL;
×
3804
    }
3805

3806
    /* -------------------------------------------------------------------- */
3807
    /*      Process the locations.                                          */
3808
    /* -------------------------------------------------------------------- */
3809
    for (iLoc = 0; bSuccess && iLoc < nLocCount; iLoc++)
305✔
3810
    {
3811
        pasLocations[iLoc].nLocId = NITFReadMSBGUInt16(fp, &bSuccess);
271✔
3812
        pasLocations[iLoc].nLocSize = NITFReadMSBGUInt32(fp, &bSuccess);
271✔
3813
        pasLocations[iLoc].nLocOffset = NITFReadMSBGUInt32(fp, &bSuccess);
271✔
3814
    }
3815

3816
    if (!bSuccess)
34✔
3817
    {
3818
        CPLFree(pasLocations);
×
3819
        return NULL;
×
3820
    }
3821

3822
    *pnLocCount = nLocCount;
34✔
3823
    return pasLocations;
34✔
3824
}
3825

3826
/************************************************************************/
3827
/*                       NITFLoadLocationTable()                        */
3828
/************************************************************************/
3829

3830
static void NITFLoadLocationTable(NITFImage *psImage)
9,754✔
3831

3832
{
3833
    /* -------------------------------------------------------------------- */
3834
    /*      Get the location table out of the RPFIMG TRE on the image.      */
3835
    /* -------------------------------------------------------------------- */
3836
    const char *pszTRE;
3837
    GUInt32 nHeaderOffset = 0;
9,754✔
3838
    int i;
3839
    int nTRESize;
3840
    char szTempFileName[256];
3841
    VSILFILE *fpTemp;
3842

3843
    pszTRE =
3844
        NITFFindTRE(psImage->pachTRE, psImage->nTREBytes, "RPFIMG", &nTRESize);
9,754✔
3845
    if (pszTRE == NULL)
9,753✔
3846
        return;
9,729✔
3847

3848
    snprintf(szTempFileName, sizeof(szTempFileName), "%s",
24✔
3849
             VSIMemGenerateHiddenFilename("nitf_tre"));
3850
    fpTemp =
3851
        VSIFileFromMemBuffer(szTempFileName, (GByte *)pszTRE, nTRESize, FALSE);
24✔
3852
    psImage->pasLocations =
24✔
3853
        NITFReadRPFLocationTable(fpTemp, &psImage->nLocCount);
24✔
3854
    CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fpTemp));
24✔
3855
    VSIUnlink(szTempFileName);
24✔
3856

3857
    if (psImage->nLocCount == 0)
24✔
3858
        return;
×
3859

3860
    /* -------------------------------------------------------------------- */
3861
    /*      It seems that sometimes (at least for bug #1313 and #1714)      */
3862
    /*      the RPF headers are improperly placed.  We check by looking     */
3863
    /*      to see if the RPFHDR is where it should be.  If not, we         */
3864
    /*      disregard the location table.                                   */
3865
    /*                                                                      */
3866
    /*      The NITF21_CGM_ANNO_Uncompressed_unmasked.ntf sample data       */
3867
    /*      file (see gdal data downloads) is an example of this.           */
3868
    /* -------------------------------------------------------------------- */
3869
    for (i = 0; i < psImage->nLocCount; i++)
255✔
3870
    {
3871
        if (psImage->pasLocations[i].nLocId == LID_HeaderComponent)
231✔
3872
        {
3873
            nHeaderOffset = psImage->pasLocations[i].nLocOffset;
×
3874
            break;
×
3875
        }
3876
    }
3877

3878
    if (nHeaderOffset > 11)
24✔
3879
    {
3880
        char achHeaderChunk[1000];
3881

3882
        if (VSIFSeekL(psImage->psFile->fp, nHeaderOffset - 11, SEEK_SET) != 0 ||
×
3883
            VSIFReadL(achHeaderChunk, sizeof(achHeaderChunk), 1,
×
3884
                      psImage->psFile->fp) != 1)
×
3885
        {
3886
            CPLFree(psImage->pasLocations);
×
3887
            psImage->pasLocations = NULL;
×
3888
            psImage->nLocCount = 0;
×
3889
            return;
×
3890
        }
3891

3892
        /* You can define NITF_DISABLE_RPF_LOCATION_TABLE_SANITY_TESTS to TRUE
3893
         */
3894
        /* to blindly trust the RPF location table even if it doesn't look */
3895
        /* sane. Necessary for dataset attached to
3896
         * http://trac.osgeo.org/gdal/ticket/3930 */
3897
        if (!STARTS_WITH_CI(achHeaderChunk, "RPFHDR") &&
×
3898
            !CPLTestBoolean(CPLGetConfigOption(
×
3899
                "NITF_DISABLE_RPF_LOCATION_TABLE_SANITY_TESTS", "FALSE")))
3900
        {
3901
            /* Image of http://trac.osgeo.org/gdal/ticket/3848 has incorrect */
3902
            /* RPFHDR offset, but all other locations are correct... */
3903
            /* So if we find LID_CoverageSectionSubheader and
3904
             * LID_CompressionLookupSubsection */
3905
            /* we check whether their content is valid. */
3906
            int bFoundValidLocation = FALSE;
×
3907
            for (i = 0; i < psImage->nLocCount; i++)
×
3908
            {
3909
                if (psImage->pasLocations[i].nLocId ==
×
3910
                        LID_CoverageSectionSubheader &&
×
3911
                    (psImage->chICORDS == 'G' || psImage->chICORDS == 'D'))
×
3912
                {
×
3913
                    /* Does that look like valid latitude/longitude values ? */
3914
                    /* We test that they are close enough from the values of the
3915
                     * IGEOLO record */
3916
                    double adfTarget[8];
3917

3918
                    if (VSIFSeekL(psImage->psFile->fp,
×
3919
                                  psImage->pasLocations[i].nLocOffset,
×
3920
                                  SEEK_SET) != 0 ||
×
3921
                        VSIFReadL(adfTarget, 8, 8, psImage->psFile->fp) != 8)
×
3922
                    {
3923
                        CPLFree(psImage->pasLocations);
×
3924
                        psImage->pasLocations = NULL;
×
3925
                        psImage->nLocCount = 0;
×
3926
                        return;
×
3927
                    }
3928
                    for (i = 0; i < 8; i++)
×
3929
                        CPL_MSBPTR64((adfTarget + i));
×
3930

3931
                    if (fabs(psImage->dfULX - adfTarget[1]) < 0.1 &&
×
3932
                        fabs(psImage->dfULY - adfTarget[0]) < 0.1 &&
×
3933
                        fabs(psImage->dfLLX - adfTarget[3]) < 0.1 &&
×
3934
                        fabs(psImage->dfLLY - adfTarget[2]) < 0.1 &&
×
3935
                        fabs(psImage->dfURX - adfTarget[5]) < 0.1 &&
×
3936
                        fabs(psImage->dfURY - adfTarget[4]) < 0.1 &&
×
3937
                        fabs(psImage->dfLRX - adfTarget[7]) < 0.1 &&
×
3938
                        fabs(psImage->dfLRY - adfTarget[6]) < 0.1)
×
3939
                    {
3940
                        bFoundValidLocation = TRUE;
×
3941
                    }
3942
                    else
3943
                    {
3944
                        CPLDebug("NITF", "The CoverageSectionSubheader content "
×
3945
                                         "isn't consistent");
3946
                        bFoundValidLocation = FALSE;
×
3947
                        break;
×
3948
                    }
3949
                }
3950
                else if (psImage->pasLocations[i].nLocId ==
×
3951
                         LID_CompressionLookupSubsection)
3952
                {
3953
                    if (NITFLoadVQTables(psImage, FALSE))
×
3954
                    {
3955
                        bFoundValidLocation = TRUE;
×
3956
                    }
3957
                    else
3958
                    {
3959
                        CPLDebug("NITF",
×
3960
                                 "The VQ tables content aren't consistent");
3961
                        bFoundValidLocation = FALSE;
×
3962
                        break;
×
3963
                    }
3964
                }
3965
            }
3966
            if (bFoundValidLocation)
×
3967
            {
3968
                CPLDebug("NITF", "RPFHDR is not correctly placed, but other "
×
3969
                                 "locations seem correct. Going on...");
3970
            }
3971
            else
3972
            {
3973
                CPLError(CE_Warning, CPLE_AppDefined,
×
3974
                         "Ignoring NITF RPF Location table since it seems to "
3975
                         "be corrupt.");
3976
                CPLFree(psImage->pasLocations);
×
3977
                psImage->pasLocations = NULL;
×
3978
                psImage->nLocCount = 0;
×
3979
            }
3980
        }
3981
    }
3982
}
3983

3984
/************************************************************************/
3985
/*                          NITFLoadVQTables()                          */
3986
/************************************************************************/
3987

3988
static int NITFLoadVQTables(NITFImage *psImage, int bTryGuessingOffset)
9,754✔
3989

3990
{
3991
    int i;
3992
    GUInt32 nVQOffset = 0 /*, nVQSize=0 */;
9,754✔
3993
    GByte abyTestChunk[1000];
3994
    const GByte abySignature[6] = {0x00, 0x00, 0x00, 0x06, 0x00, 0x0E};
9,754✔
3995

3996
    /* -------------------------------------------------------------------- */
3997
    /*      Do we already have the VQ tables?                               */
3998
    /* -------------------------------------------------------------------- */
3999
    if (psImage->apanVQLUT[0] != NULL)
9,754✔
4000
        return TRUE;
×
4001

4002
    /* -------------------------------------------------------------------- */
4003
    /*      Do we have the location information?                            */
4004
    /* -------------------------------------------------------------------- */
4005
    for (i = 0; i < psImage->nLocCount; i++)
9,985✔
4006
    {
4007
        if (psImage->pasLocations[i].nLocId == LID_CompressionLookupSubsection)
231✔
4008
        {
4009
            nVQOffset = psImage->pasLocations[i].nLocOffset;
23✔
4010
            /* nVQSize = psImage->pasLocations[i].nLocSize; */
4011
        }
4012
    }
4013

4014
    if (nVQOffset == 0)
9,754✔
4015
        return FALSE;
9,731✔
4016

4017
    /* -------------------------------------------------------------------- */
4018
    /*      Does it look like we have the tables properly identified?       */
4019
    /* -------------------------------------------------------------------- */
4020
    if (VSIFSeekL(psImage->psFile->fp, nVQOffset, SEEK_SET) != 0 ||
46✔
4021
        VSIFReadL(abyTestChunk, sizeof(abyTestChunk), 1, psImage->psFile->fp) !=
23✔
4022
            1)
4023
    {
4024
        return FALSE;
×
4025
    }
4026

4027
    if (memcmp(abyTestChunk, abySignature, sizeof(abySignature)) != 0)
23✔
4028
    {
4029
        int bFoundSignature = FALSE;
×
4030
        if (!bTryGuessingOffset)
×
4031
            return FALSE;
×
4032

4033
        for (i = 0; (size_t)i < sizeof(abyTestChunk) - sizeof(abySignature);
×
4034
             i++)
×
4035
        {
4036
            if (memcmp(abyTestChunk + i, abySignature, sizeof(abySignature)) ==
×
4037
                0)
4038
            {
4039
                bFoundSignature = TRUE;
×
4040
                nVQOffset += i;
×
4041
                CPLDebug("NITF",
×
4042
                         "VQ CompressionLookupSubsection offsets off by %d "
4043
                         "bytes, adjusting accordingly.",
4044
                         i);
4045
                break;
×
4046
            }
4047
        }
4048
        if (!bFoundSignature)
×
4049
            return FALSE;
×
4050
    }
4051

4052
    /* -------------------------------------------------------------------- */
4053
    /*      Load the tables.                                                */
4054
    /* -------------------------------------------------------------------- */
4055
    for (i = 0; i < 4; i++)
115✔
4056
    {
4057
        GUInt32 nVQVector;
4058
        int bOK;
4059

4060
        psImage->apanVQLUT[i] = (GUInt32 *)CPLCalloc(4096, sizeof(GUInt32));
92✔
4061

4062
        bOK = VSIFSeekL(psImage->psFile->fp, nVQOffset + 6 + i * 14 + 10,
92✔
4063
                        SEEK_SET) == 0;
92✔
4064
        bOK &= VSIFReadL(&nVQVector, 1, 4, psImage->psFile->fp) == 4;
92✔
4065
        nVQVector = CPL_MSBWORD32(nVQVector);
92✔
4066

4067
        bOK &= VSIFSeekL(psImage->psFile->fp,
184✔
4068
                         (vsi_l_offset)(nVQOffset) + nVQVector, SEEK_SET) == 0;
92✔
4069
        bOK &= VSIFReadL(psImage->apanVQLUT[i], 4, 4096, psImage->psFile->fp) ==
92✔
4070
               4096;
4071
        if (!bOK)
92✔
4072
        {
4073
            for (i = 0; i < 4; i++)
×
4074
            {
4075
                CPLFree(psImage->apanVQLUT[i]);
×
4076
                psImage->apanVQLUT[i] = NULL;
×
4077
            }
4078
            return FALSE;
×
4079
        }
4080
    }
4081

4082
    return TRUE;
23✔
4083
}
4084

4085
/************************************************************************/
4086
/*                           NITFReadSTDIDC()                           */
4087
/*                                                                      */
4088
/*      Read a STDIDC TRE and return contents as metadata strings.      */
4089
/************************************************************************/
4090

4091
char **NITFReadSTDIDC(NITFImage *psImage)
×
4092

4093
{
4094
    return NITFGenericMetadataRead(NULL, NULL, psImage, "STDIDC");
×
4095
}
4096

4097
/************************************************************************/
4098
/*                         NITFRPCGeoToImage()                          */
4099
/************************************************************************/
4100

4101
int NITFRPCGeoToImage(NITFRPC00BInfo *psRPC, double dfLong, double dfLat,
×
4102
                      double dfHeight, double *pdfPixel, double *pdfLine)
4103

4104
{
4105
    double dfLineNumerator, dfLineDenominator, dfPixelNumerator,
4106
        dfPixelDenominator;
4107
    double dfPolyTerm[20];
4108
    double *pdfPolyTerm = dfPolyTerm;
×
4109
    int i;
4110

4111
    /* -------------------------------------------------------------------- */
4112
    /*      Normalize Lat/Long position.                                    */
4113
    /* -------------------------------------------------------------------- */
4114
    dfLong = (dfLong - psRPC->LONG_OFF) / psRPC->LONG_SCALE;
×
4115
    dfLat = (dfLat - psRPC->LAT_OFF) / psRPC->LAT_SCALE;
×
4116
    dfHeight = (dfHeight - psRPC->HEIGHT_OFF) / psRPC->HEIGHT_SCALE;
×
4117

4118
    /* -------------------------------------------------------------------- */
4119
    /*      Compute the 20 terms.                                           */
4120
    /* -------------------------------------------------------------------- */
4121

4122
    pdfPolyTerm[0] = 1.0; /* workaround cppcheck false positive */
×
4123
    dfPolyTerm[1] = dfLong;
×
4124
    dfPolyTerm[2] = dfLat;
×
4125
    dfPolyTerm[3] = dfHeight;
×
4126
    dfPolyTerm[4] = dfLong * dfLat;
×
4127
    dfPolyTerm[5] = dfLong * dfHeight;
×
4128
    dfPolyTerm[6] = dfLat * dfHeight;
×
4129
    dfPolyTerm[7] = dfLong * dfLong;
×
4130
    dfPolyTerm[8] = dfLat * dfLat;
×
4131
    dfPolyTerm[9] = dfHeight * dfHeight;
×
4132

4133
    dfPolyTerm[10] = dfLong * dfLat * dfHeight;
×
4134
    dfPolyTerm[11] = dfLong * dfLong * dfLong;
×
4135
    dfPolyTerm[12] = dfLong * dfLat * dfLat;
×
4136
    dfPolyTerm[13] = dfLong * dfHeight * dfHeight;
×
4137
    dfPolyTerm[14] = dfLong * dfLong * dfLat;
×
4138
    dfPolyTerm[15] = dfLat * dfLat * dfLat;
×
4139
    dfPolyTerm[16] = dfLat * dfHeight * dfHeight;
×
4140
    dfPolyTerm[17] = dfLong * dfLong * dfHeight;
×
4141
    dfPolyTerm[18] = dfLat * dfLat * dfHeight;
×
4142
    dfPolyTerm[19] = dfHeight * dfHeight * dfHeight;
×
4143

4144
    /* -------------------------------------------------------------------- */
4145
    /*      Compute numerator and denominator sums.                         */
4146
    /* -------------------------------------------------------------------- */
4147
    dfPixelNumerator = 0.0;
×
4148
    dfPixelDenominator = 0.0;
×
4149
    dfLineNumerator = 0.0;
×
4150
    dfLineDenominator = 0.0;
×
4151

4152
    for (i = 0; i < 20; i++)
×
4153
    {
4154
        dfPixelNumerator += psRPC->SAMP_NUM_COEFF[i] * dfPolyTerm[i];
×
4155
        dfPixelDenominator += psRPC->SAMP_DEN_COEFF[i] * dfPolyTerm[i];
×
4156
        dfLineNumerator += psRPC->LINE_NUM_COEFF[i] * dfPolyTerm[i];
×
4157
        dfLineDenominator += psRPC->LINE_DEN_COEFF[i] * dfPolyTerm[i];
×
4158
    }
4159

4160
    /* -------------------------------------------------------------------- */
4161
    /*      Compute normalized pixel and line values.                       */
4162
    /* -------------------------------------------------------------------- */
4163
    *pdfPixel = dfPixelNumerator / dfPixelDenominator;
×
4164
    *pdfLine = dfLineNumerator / dfLineDenominator;
×
4165

4166
    /* -------------------------------------------------------------------- */
4167
    /*      Denormalize.                                                    */
4168
    /* -------------------------------------------------------------------- */
4169
    *pdfPixel = *pdfPixel * psRPC->SAMP_SCALE + psRPC->SAMP_OFF;
×
4170
    *pdfLine = *pdfLine * psRPC->LINE_SCALE + psRPC->LINE_OFF;
×
4171

4172
    return TRUE;
×
4173
}
4174

4175
/************************************************************************/
4176
/*                         NITFIHFieldOffset()                          */
4177
/*                                                                      */
4178
/*      Find the file offset for the beginning of a particular field    */
4179
/*      in this image header.  Only implemented for selected fields.    */
4180
/************************************************************************/
4181

4182
GUIntBig NITFIHFieldOffset(NITFImage *psImage, const char *pszFieldName)
33✔
4183

4184
{
4185
    char szTemp[128];
4186
    int nNICOM;
4187
    GUIntBig nWrkOffset;
4188
    GUIntBig nIMOffset =
33✔
4189
        psImage->psFile->pasSegmentInfo[psImage->iSegment].nSegmentHeaderStart;
33✔
4190

4191
    // We only support files we created.
4192
    if (!STARTS_WITH_CI(psImage->psFile->szVersion, "NITF02.1"))
33✔
4193
    {
4194
        CPLError(CE_Failure, CPLE_AppDefined,
×
4195
                 "NITFIHFieldOffset() only works with NITF 2.1 images");
4196
        return 0;
×
4197
    }
4198

4199
    if (EQUAL(pszFieldName, "IM"))
33✔
4200
        return nIMOffset;
×
4201

4202
    if (EQUAL(pszFieldName, "PJUST"))
33✔
4203
        return nIMOffset + 370;
×
4204

4205
    if (EQUAL(pszFieldName, "ICORDS"))
33✔
4206
        return nIMOffset + 371;
×
4207

4208
    if (EQUAL(pszFieldName, "IGEOLO"))
33✔
4209
    {
4210
        if (!psImage->bHaveIGEOLO)
×
4211
            return 0;
×
4212
        else
4213
            return nIMOffset + 372;
×
4214
    }
4215

4216
    /* -------------------------------------------------------------------- */
4217
    /*      Keep working offset from here on in since everything else is    */
4218
    /*      variable.                                                       */
4219
    /* -------------------------------------------------------------------- */
4220
    nWrkOffset = 372 + nIMOffset;
33✔
4221

4222
    if (psImage->bHaveIGEOLO)
33✔
4223
        nWrkOffset += 60;
30✔
4224

4225
    /* -------------------------------------------------------------------- */
4226
    /*      Comments.                                                       */
4227
    /* -------------------------------------------------------------------- */
4228
    nNICOM = atoi(NITFGetField(szTemp, psImage->pachHeader,
66✔
4229
                               (int)(nWrkOffset - nIMOffset), 1));
33✔
4230

4231
    if (EQUAL(pszFieldName, "NICOM"))
33✔
4232
        return nWrkOffset;
×
4233

4234
    nWrkOffset++;
33✔
4235

4236
    if (EQUAL(pszFieldName, "ICOM"))
33✔
4237
        return nWrkOffset;
×
4238

4239
    nWrkOffset += 80 * nNICOM;
33✔
4240

4241
    /* -------------------------------------------------------------------- */
4242
    /*      IC                                                              */
4243
    /* -------------------------------------------------------------------- */
4244
    if (EQUAL(pszFieldName, "IC"))
33✔
4245
        return nWrkOffset;
×
4246

4247
    nWrkOffset += 2;
33✔
4248

4249
    /* -------------------------------------------------------------------- */
4250
    /*      COMRAT                                                          */
4251
    /* -------------------------------------------------------------------- */
4252

4253
    if (psImage->szIC[0] != 'N')
33✔
4254
    {
4255
        if (EQUAL(pszFieldName, "COMRAT"))
3✔
4256
            return nWrkOffset;
×
4257
        nWrkOffset += 4;
3✔
4258
    }
4259

4260
    /* -------------------------------------------------------------------- */
4261
    /*      NBANDS                                                          */
4262
    /* -------------------------------------------------------------------- */
4263
    if (EQUAL(pszFieldName, "NBANDS"))
33✔
4264
        return nWrkOffset;
×
4265

4266
    nWrkOffset += 1;
33✔
4267

4268
    /* -------------------------------------------------------------------- */
4269
    /*      XBANDS                                                          */
4270
    /* -------------------------------------------------------------------- */
4271
    if (EQUAL(pszFieldName, "XBANDS"))
33✔
4272
        return nWrkOffset;
×
4273

4274
    if (psImage->nBands > 9)
33✔
4275
        nWrkOffset += 5;
×
4276

4277
    /* -------------------------------------------------------------------- */
4278
    /*      IREPBAND                                                        */
4279
    /* -------------------------------------------------------------------- */
4280
    if (EQUAL(pszFieldName, "IREPBAND"))
33✔
4281
        return nWrkOffset;
33✔
4282

4283
    //    nWrkOffset += 2 * psImage->nBands;
4284

4285
    return 0;
×
4286
}
4287

4288
/************************************************************************/
4289
/*                        NITFDoLinesIntersect()                        */
4290
/************************************************************************/
4291

4292
static int NITFDoLinesIntersect(double dfL1X1, double dfL1Y1, double dfL1X2,
266✔
4293
                                double dfL1Y2, double dfL2X1, double dfL2Y1,
4294
                                double dfL2X2, double dfL2Y2)
4295

4296
{
4297
    double dfL1M, dfL1B, dfL2M, dfL2B;
4298

4299
    if (dfL1X1 == dfL1X2)
266✔
4300
    {
4301
        dfL1M = 1e10;
247✔
4302
        dfL1B = 0.0;
247✔
4303
    }
4304
    else
4305
    {
4306
        dfL1M = (dfL1Y2 - dfL1Y1) / (dfL1X2 - dfL1X1);
19✔
4307
        dfL1B = dfL1Y2 - dfL1M * dfL1X2;
19✔
4308
    }
4309

4310
    if (dfL2X1 == dfL2X2)
266✔
4311
    {
4312
        dfL2M = 1e10;
247✔
4313
        dfL2B = 0.0;
247✔
4314
    }
4315
    else
4316
    {
4317
        dfL2M = (dfL2Y2 - dfL2Y1) / (dfL2X2 - dfL2X1);
19✔
4318
        dfL2B = dfL2Y2 - dfL2M * dfL2X2;
19✔
4319
    }
4320

4321
    if (dfL2M == dfL1M)
266✔
4322
    {
4323
        // parallel .. no meaningful intersection.
4324
        return FALSE;
247✔
4325
    }
4326
    else
4327
    {
4328
        double dfX /*, dfY*/;
4329

4330
        dfX = (dfL2B - dfL1B) / (dfL1M - dfL2M);
19✔
4331
        /* dfY = dfL2M * dfX + dfL2B; */
4332

4333
        /*
4334
        ** Is this intersection on the line between
4335
        ** our corner points or "out somewhere" else?
4336
        */
4337
        return ((dfX >= dfL1X1 && dfX <= dfL1X2) ||
19✔
4338
                (dfX >= dfL1X2 && dfX <= dfL1X1)) &&
38✔
4339
               ((dfX >= dfL2X1 && dfX <= dfL2X2) ||
×
4340
                (dfX >= dfL2X2 && dfX <= dfL2X1));
×
4341
    }
4342
}
4343

4344
/************************************************************************/
4345
/*                  NITFPossibleIGEOLOReorientation()                   */
4346
/************************************************************************/
4347

4348
static void NITFPossibleIGEOLOReorientation(NITFImage *psImage)
266✔
4349

4350
{
4351
/* -------------------------------------------------------------------- */
4352
/*      Check whether the vector from top left to bottom left           */
4353
/*      intersects the line from top right to bottom right.  If this    */
4354
/*      is true, then we believe the corner coordinate order was        */
4355
/*      written improperly.                                             */
4356
/* -------------------------------------------------------------------- */
4357
#if 1
4358
    if (!NITFDoLinesIntersect(psImage->dfULX, psImage->dfULY, psImage->dfLLX,
266✔
4359
                              psImage->dfLLY, psImage->dfURX, psImage->dfURY,
4360
                              psImage->dfLRX, psImage->dfLRY))
4361
        return;
266✔
4362
    else
4363
        CPLDebug("NITF", "It appears the IGEOLO corner coordinates were "
×
4364
                         "written improperly!");
4365
#endif
4366

4367
    /* -------------------------------------------------------------------- */
4368
    /*      Divide the lat/long extents of this image into four             */
4369
    /*      quadrants and assign the corners based on which point falls     */
4370
    /*      into which quadrant.  This is intended to correct images        */
4371
    /*      with the corner points written improperly.  Unfortunately it    */
4372
    /*      also breaks images which are mirrored, or rotated more than     */
4373
    /*      90 degrees from simple north up.                                */
4374
    /* -------------------------------------------------------------------- */
4375
    {
4376

4377
        double dfXMax = MAX(MAX(psImage->dfULX, psImage->dfURX),
×
4378
                            MAX(psImage->dfLRX, psImage->dfLLX));
4379
        double dfXMin = MIN(MIN(psImage->dfULX, psImage->dfURX),
×
4380
                            MIN(psImage->dfLRX, psImage->dfLLX));
4381
        double dfYMax = MAX(MAX(psImage->dfULY, psImage->dfURY),
×
4382
                            MAX(psImage->dfLRY, psImage->dfLLY));
4383
        double dfYMin = MIN(MIN(psImage->dfULY, psImage->dfURY),
×
4384
                            MIN(psImage->dfLRY, psImage->dfLLY));
4385
        double dfXPivot = (dfXMax + dfXMin) * 0.5;
×
4386
        double dfYPivot = (dfYMax + dfYMin) * 0.5;
×
4387

4388
        double dfNewULX = 0., dfNewULY = 0., dfNewURX = 0., dfNewURY = 0.,
×
4389
               dfNewLLX = 0., dfNewLLY = 0., dfNewLRX = 0., dfNewLRY = 0.;
×
4390
        int bGotUL = FALSE, bGotUR = FALSE, bGotLL = FALSE, bGotLR = FALSE;
×
4391
        int iCoord, bChange = FALSE;
×
4392

4393
        for (iCoord = 0; iCoord < 4; iCoord++)
×
4394
        {
4395
            double *pdfXY = &(psImage->dfULX) + iCoord * 2;
×
4396

4397
            if (pdfXY[0] < dfXPivot && pdfXY[1] < dfYPivot)
×
4398
            {
4399
                bGotLL = TRUE;
×
4400
                dfNewLLX = pdfXY[0];
×
4401
                dfNewLLY = pdfXY[1];
×
4402
                bChange |= iCoord != 3;
×
4403
            }
4404
            else if (pdfXY[0] > dfXPivot && pdfXY[1] < dfYPivot)
×
4405
            {
4406
                bGotLR = TRUE;
×
4407
                dfNewLRX = pdfXY[0];
×
4408
                dfNewLRY = pdfXY[1];
×
4409
                bChange |= iCoord != 2;
×
4410
            }
4411
            else if (pdfXY[0] > dfXPivot && pdfXY[1] > dfYPivot)
×
4412
            {
4413
                bGotUR = TRUE;
×
4414
                dfNewURX = pdfXY[0];
×
4415
                dfNewURY = pdfXY[1];
×
4416
                bChange |= iCoord != 1;
×
4417
            }
4418
            else
4419
            {
4420
                bGotUL = TRUE;
×
4421
                dfNewULX = pdfXY[0];
×
4422
                dfNewULY = pdfXY[1];
×
4423
                bChange |= iCoord != 0;
×
4424
            }
4425
        }
4426

4427
        if (!bGotUL || !bGotUR || !bGotLL || !bGotLR)
×
4428
        {
4429
            CPLDebug("NITF", "Unable to reorient corner points sensibly in "
×
4430
                             "NITFPossibleIGEOLOReorganization(), discarding "
4431
                             "IGEOLO locations.");
4432
            psImage->bHaveIGEOLO = FALSE;
×
4433
            return;
×
4434
        }
4435

4436
        if (!bChange)
×
4437
            return;
×
4438

4439
        psImage->dfULX = dfNewULX;
×
4440
        psImage->dfULY = dfNewULY;
×
4441
        psImage->dfURX = dfNewURX;
×
4442
        psImage->dfURY = dfNewURY;
×
4443
        psImage->dfLRX = dfNewLRX;
×
4444
        psImage->dfLRY = dfNewLRY;
×
4445
        psImage->dfLLX = dfNewLLX;
×
4446
        psImage->dfLLY = dfNewLLY;
×
4447

4448
        CPLDebug("NITF", "IGEOLO corners have been reoriented by "
×
4449
                         "NITFPossibleIGEOLOReorientation().");
4450
    }
4451
}
4452

4453
/************************************************************************/
4454
/*                           NITFReadIMRFCA()                           */
4455
/*                                                                      */
4456
/*      Read DPPDB IMRFCA TRE (and the associated IMASDA TRE) if it is  */
4457
/*      available. IMRFCA RPC coefficients are remapped into RPC00B     */
4458
/*      organization.                                                   */
4459
/*      See table 68 for IMASDA and table 69 for IMRFCA in              */
4460
/*      http://earth-info.nga.mil/publications/specs/printed/89034/89034DPPDB.pdf
4461
 */
4462
/************************************************************************/
4463
int NITFReadIMRFCA(NITFImage *psImage, NITFRPC00BInfo *psRPC)
694✔
4464
{
4465
    char szTemp[100];
4466
    const char *pachTreIMASDA = NULL;
694✔
4467
    const char *pachTreIMRFCA = NULL;
694✔
4468
    double dfTolerance = 1.0e-10;
694✔
4469
    int count = 0;
694✔
4470
    int nTreIMASDASize = 0;
694✔
4471
    int nTreIMRFCASize = 0;
694✔
4472

4473
    if ((psImage == NULL) || (psRPC == NULL))
694✔
4474
        return FALSE;
×
4475

4476
    /* Check to see if we have the IMASDA and IMRFCA tag (DPPDB data). */
4477

4478
    pachTreIMASDA = NITFFindTRE(psImage->pachTRE, psImage->nTREBytes, "IMASDA",
694✔
4479
                                &nTreIMASDASize);
4480
    pachTreIMRFCA = NITFFindTRE(psImage->pachTRE, psImage->nTREBytes, "IMRFCA",
694✔
4481
                                &nTreIMRFCASize);
4482

4483
    if ((pachTreIMASDA == NULL) || (pachTreIMRFCA == NULL))
694✔
4484
        return FALSE;
688✔
4485

4486
    if (nTreIMASDASize < 242 || nTreIMRFCASize < 1760)
6✔
4487
    {
4488
        CPLError(CE_Failure, CPLE_AppDefined,
4✔
4489
                 "Cannot read DPPDB IMASDA/IMRFCA TREs; not enough bytes.");
4490

4491
        return FALSE;
4✔
4492
    }
4493

4494
    /* Parse out the field values. */
4495

4496
    /* Set the errors to 0.0 for now. */
4497

4498
    psRPC->ERR_BIAS = 0.0;
2✔
4499
    psRPC->ERR_RAND = 0.0;
2✔
4500

4501
    psRPC->LONG_OFF = CPLAtof(NITFGetField(szTemp, pachTreIMASDA, 0, 22));
2✔
4502
    psRPC->LAT_OFF = CPLAtof(NITFGetField(szTemp, pachTreIMASDA, 22, 22));
2✔
4503
    psRPC->HEIGHT_OFF = CPLAtof(NITFGetField(szTemp, pachTreIMASDA, 44, 22));
2✔
4504
    psRPC->LONG_SCALE = CPLAtof(NITFGetField(szTemp, pachTreIMASDA, 66, 22));
2✔
4505
    psRPC->LAT_SCALE = CPLAtof(NITFGetField(szTemp, pachTreIMASDA, 88, 22));
2✔
4506
    psRPC->HEIGHT_SCALE = CPLAtof(NITFGetField(szTemp, pachTreIMASDA, 110, 22));
2✔
4507
    psRPC->SAMP_OFF = CPLAtof(NITFGetField(szTemp, pachTreIMASDA, 132, 22));
2✔
4508
    psRPC->LINE_OFF = CPLAtof(NITFGetField(szTemp, pachTreIMASDA, 154, 22));
2✔
4509
    psRPC->SAMP_SCALE = CPLAtof(NITFGetField(szTemp, pachTreIMASDA, 176, 22));
2✔
4510
    psRPC->LINE_SCALE = CPLAtof(NITFGetField(szTemp, pachTreIMASDA, 198, 22));
2✔
4511

4512
    if (psRPC->HEIGHT_SCALE == 0.0)
2✔
4513
        psRPC->HEIGHT_SCALE = dfTolerance;
2✔
4514
    if (psRPC->LAT_SCALE == 0.0)
2✔
4515
        psRPC->LAT_SCALE = dfTolerance;
2✔
4516
    if (psRPC->LINE_SCALE == 0.0)
2✔
4517
        psRPC->LINE_SCALE = dfTolerance;
2✔
4518
    if (psRPC->LONG_SCALE == 0.0)
2✔
4519
        psRPC->LONG_SCALE = dfTolerance;
2✔
4520
    if (psRPC->SAMP_SCALE == 0.0)
2✔
4521
        psRPC->SAMP_SCALE = dfTolerance;
2✔
4522

4523
    psRPC->HEIGHT_SCALE = 1.0 / psRPC->HEIGHT_SCALE;
2✔
4524
    psRPC->LAT_SCALE = 1.0 / psRPC->LAT_SCALE;
2✔
4525
    psRPC->LINE_SCALE = 1.0 / psRPC->LINE_SCALE;
2✔
4526
    psRPC->LONG_SCALE = 1.0 / psRPC->LONG_SCALE;
2✔
4527
    psRPC->SAMP_SCALE = 1.0 / psRPC->SAMP_SCALE;
2✔
4528

4529
    /* Parse out the RPC coefficients. */
4530

4531
    for (count = 0; count < 20; ++count)
42✔
4532
    {
4533
        psRPC->SAMP_NUM_COEFF[count] =
40✔
4534
            CPLAtof(NITFGetField(szTemp, pachTreIMRFCA, count * 22, 22));
40✔
4535
        psRPC->SAMP_DEN_COEFF[count] =
40✔
4536
            CPLAtof(NITFGetField(szTemp, pachTreIMRFCA, 440 + count * 22, 22));
40✔
4537

4538
        psRPC->LINE_NUM_COEFF[count] =
40✔
4539
            CPLAtof(NITFGetField(szTemp, pachTreIMRFCA, 880 + count * 22, 22));
40✔
4540
        psRPC->LINE_DEN_COEFF[count] =
40✔
4541
            CPLAtof(NITFGetField(szTemp, pachTreIMRFCA, 1320 + count * 22, 22));
40✔
4542
    }
4543

4544
    psRPC->SUCCESS = 1;
2✔
4545

4546
    return TRUE;
2✔
4547
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc