LCOV - code coverage report
Current view: top level - frmts/nitf - nitfimage.c (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 1454 2031 71.6 %
Date: 2026-07-08 22:10:34 Functions: 35 40 87.5 %

          Line data    Source code
       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             : #include <inttypes.h>
      23             : 
      24             : #ifndef CPL_IGNORE_RET_VAL_INT_defined
      25             : #define CPL_IGNORE_RET_VAL_INT_defined
      26             : 
      27        1356 : CPL_INLINE static void CPL_IGNORE_RET_VAL_INT(CPL_UNUSED int unused)
      28             : {
      29        1356 : }
      30             : #endif
      31             : 
      32             : static int NITFReadIMRFCA(NITFImage *psImage, NITFRPC00BInfo *psRPC);
      33             : static char *NITFTrimWhite(char *);
      34             : #ifdef CPL_LSB
      35             : static void NITFSwapWords(NITFImage *psImage, void *pData, int nWordCount);
      36             : #endif
      37             : 
      38             : static void NITFLoadLocationTable(NITFImage *psImage);
      39             : static void NITFLoadColormapSubSection(NITFImage *psImage);
      40             : static void NITFLoadSubframeMaskTable(NITFImage *psImage,
      41             :                                       bool *pbBlockStartRead);
      42             : static int NITFLoadVQTables(NITFImage *psImage, int bTryGuessingOffset);
      43             : static int NITFReadGEOLOB(NITFImage *psImage);
      44             : static void NITFLoadAttributeSection(NITFImage *psImage);
      45             : static void NITFPossibleIGEOLOReorientation(NITFImage *psImage);
      46             : 
      47             : void NITFGetGCP(const char *pachCoord, double *pdfXYs, int iCoord);
      48             : int NITFReadBLOCKA_GCPs(NITFImage *psImage);
      49             : 
      50             : #define GOTO_header_too_small()                                                \
      51             :     do                                                                         \
      52             :     {                                                                          \
      53             :         nFaultyLine = __LINE__;                                                \
      54             :         goto header_too_small;                                                 \
      55             :     } while (0)
      56             : 
      57             : #define DIGIT_ZERO '0'
      58             : 
      59             : /************************************************************************/
      60             : /*                          NITFImageAccess()                           */
      61             : /************************************************************************/
      62             : 
      63        9195 : NITFImage *NITFImageAccess(NITFFile *psFile, int iSegment)
      64             : 
      65             : {
      66             :     NITFImage *psImage;
      67             :     char *pachHeader;
      68             :     NITFSegmentInfo *psSegInfo;
      69             :     char szTemp[128];
      70             :     int nOffset, iBand, i;
      71             :     int nNICOM;
      72             :     const char *pszIID1;
      73        9195 :     int nFaultyLine = -1;
      74             : 
      75             :     /* -------------------------------------------------------------------- */
      76             :     /*      Verify segment, and return existing image accessor if there     */
      77             :     /*      is one.                                                         */
      78             :     /* -------------------------------------------------------------------- */
      79        9195 :     if (iSegment < 0 || iSegment >= psFile->nSegmentCount)
      80           0 :         return NULL;
      81             : 
      82        9195 :     psSegInfo = psFile->pasSegmentInfo + iSegment;
      83             : 
      84        9195 :     if (!EQUAL(psSegInfo->szSegmentType, "IM"))
      85           0 :         return NULL;
      86             : 
      87        9195 :     if (psSegInfo->hAccess != NULL)
      88         440 :         return (NITFImage *)psSegInfo->hAccess;
      89             : 
      90             :     /* -------------------------------------------------------------------- */
      91             :     /*      Read the image subheader.                                       */
      92             :     /* -------------------------------------------------------------------- */
      93        8755 :     if (psSegInfo->nSegmentHeaderSize < 370 + 1)
      94             :     {
      95           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Image header too small");
      96           0 :         return NULL;
      97             :     }
      98             : 
      99        8755 :     pachHeader = (char *)VSI_MALLOC_VERBOSE(psSegInfo->nSegmentHeaderSize);
     100        8755 :     if (pachHeader == NULL)
     101             :     {
     102           0 :         return NULL;
     103             :     }
     104             : 
     105        8755 :     if (VSIFSeekL(psFile->fp, psSegInfo->nSegmentHeaderStart, SEEK_SET) != 0 ||
     106        8755 :         VSIFReadL(pachHeader, 1, psSegInfo->nSegmentHeaderSize, psFile->fp) !=
     107        8755 :             psSegInfo->nSegmentHeaderSize)
     108             :     {
     109           0 :         CPLError(CE_Failure, CPLE_FileIO,
     110             :                  "Failed to read %u byte image subheader from " CPL_FRMT_GUIB
     111             :                  ".",
     112             :                  psSegInfo->nSegmentHeaderSize, psSegInfo->nSegmentHeaderStart);
     113           0 :         CPLFree(pachHeader);
     114           0 :         return NULL;
     115             :     }
     116             : 
     117             :     /* -------------------------------------------------------------------- */
     118             :     /*      Initialize image object.                                        */
     119             :     /* -------------------------------------------------------------------- */
     120        8755 :     psImage = (NITFImage *)CPLCalloc(sizeof(NITFImage), 1);
     121             : 
     122        8755 :     psImage->psFile = psFile;
     123        8755 :     psImage->iSegment = iSegment;
     124        8755 :     psImage->pachHeader = pachHeader;
     125        8755 :     psImage->nIXSOFL = -1;
     126             : 
     127        8755 :     psSegInfo->hAccess = psImage;
     128             : 
     129             : /* -------------------------------------------------------------------- */
     130             : /*      Collect a variety of information as metadata.                   */
     131             : /* -------------------------------------------------------------------- */
     132             : #define GetMD(target, hdr, start, length, name)                                \
     133             :     NITFExtractMetadata(&(target->papszMetadata), hdr, start, length,          \
     134             :                         "NITF_" #name);
     135             : 
     136        8755 :     if (EQUAL(psFile->szVersion, "NITF02.10") ||
     137         191 :         EQUAL(psFile->szVersion, "NSIF01.00"))
     138             :     {
     139        8590 :         GetMD(psImage, pachHeader, 2, 10, IID1);
     140        8590 :         GetMD(psImage, pachHeader, 12, 14, IDATIM);
     141        8590 :         GetMD(psImage, pachHeader, 26, 17, TGTID);
     142        8590 :         GetMD(psImage, pachHeader, 43, 80, IID2);
     143        8590 :         GetMD(psImage, pachHeader, 123, 1, ISCLAS);
     144        8590 :         GetMD(psImage, pachHeader, 124, 2, ISCLSY);
     145        8590 :         GetMD(psImage, pachHeader, 126, 11, ISCODE);
     146        8590 :         GetMD(psImage, pachHeader, 137, 2, ISCTLH);
     147        8590 :         GetMD(psImage, pachHeader, 139, 20, ISREL);
     148        8590 :         GetMD(psImage, pachHeader, 159, 2, ISDCTP);
     149        8590 :         GetMD(psImage, pachHeader, 161, 8, ISDCDT);
     150        8590 :         GetMD(psImage, pachHeader, 169, 4, ISDCXM);
     151        8590 :         GetMD(psImage, pachHeader, 173, 1, ISDG);
     152        8590 :         GetMD(psImage, pachHeader, 174, 8, ISDGDT);
     153        8590 :         GetMD(psImage, pachHeader, 182, 43, ISCLTX);
     154        8590 :         GetMD(psImage, pachHeader, 225, 1, ISCATP);
     155        8590 :         GetMD(psImage, pachHeader, 226, 40, ISCAUT);
     156        8590 :         GetMD(psImage, pachHeader, 266, 1, ISCRSN);
     157        8590 :         GetMD(psImage, pachHeader, 267, 8, ISSRDT);
     158        8590 :         GetMD(psImage, pachHeader, 275, 15, ISCTLN);
     159             :         /* skip ENCRYPT - 1 character */
     160        8590 :         GetMD(psImage, pachHeader, 291, 42, ISORCE);
     161             :         /* skip NROWS (8), and NCOLS (8) */
     162        8590 :         GetMD(psImage, pachHeader, 349, 3, PVTYPE);
     163        8590 :         GetMD(psImage, pachHeader, 352, 8, IREP);
     164        8590 :         GetMD(psImage, pachHeader, 360, 8, ICAT);
     165        8590 :         GetMD(psImage, pachHeader, 368, 2, ABPP);
     166        8590 :         GetMD(psImage, pachHeader, 370, 1, PJUST);
     167             :     }
     168         165 :     else if (EQUAL(psFile->szVersion, "NITF02.00"))
     169             :     {
     170         165 :         nOffset = 0;
     171         165 :         GetMD(psImage, pachHeader, 2, 10, IID1);
     172         165 :         GetMD(psImage, pachHeader, 12, 14, IDATIM);
     173         165 :         GetMD(psImage, pachHeader, 26, 17, TGTID);
     174         165 :         GetMD(psImage, pachHeader, 43, 80, ITITLE);
     175         165 :         GetMD(psImage, pachHeader, 123, 1, ISCLAS);
     176         165 :         GetMD(psImage, pachHeader, 124, 40, ISCODE);
     177         165 :         GetMD(psImage, pachHeader, 164, 40, ISCTLH);
     178         165 :         GetMD(psImage, pachHeader, 204, 40, ISREL);
     179         165 :         GetMD(psImage, pachHeader, 244, 20, ISCAUT);
     180         165 :         GetMD(psImage, pachHeader, 264, 20, ISCTLN);
     181         165 :         GetMD(psImage, pachHeader, 284, 6, ISDWNG);
     182             : 
     183         165 :         if (STARTS_WITH_CI(pachHeader + 284, "999998"))
     184             :         {
     185           4 :             if (psSegInfo->nSegmentHeaderSize < 370 + 40 + 1)
     186           0 :                 GOTO_header_too_small();
     187           4 :             GetMD(psImage, pachHeader, 290, 40, ISDEVT);
     188           4 :             nOffset += 40;
     189             :         }
     190             : 
     191             :         /* skip ENCRYPT - 1 character */
     192         165 :         GetMD(psImage, pachHeader, 291 + nOffset, 42, ISORCE);
     193             :         /* skip NROWS (8), and NCOLS (8) */
     194         165 :         GetMD(psImage, pachHeader, 349 + nOffset, 3, PVTYPE);
     195         165 :         GetMD(psImage, pachHeader, 352 + nOffset, 8, IREP);
     196         165 :         GetMD(psImage, pachHeader, 360 + nOffset, 8, ICAT);
     197         165 :         GetMD(psImage, pachHeader, 368 + nOffset, 2, ABPP);
     198         165 :         GetMD(psImage, pachHeader, 370 + nOffset, 1, PJUST);
     199             :     }
     200             : 
     201             :     /* -------------------------------------------------------------------- */
     202             :     /*      Does this header have the ISDEVT field?                         */
     203             :     /* -------------------------------------------------------------------- */
     204        8755 :     nOffset = 333;
     205             : 
     206        8755 :     if (STARTS_WITH_CI(psFile->szVersion, "NITF01.") ||
     207        8755 :         STARTS_WITH_CI(pachHeader + 284, "999998"))
     208           4 :         nOffset += 40;
     209             : 
     210             :     /* -------------------------------------------------------------------- */
     211             :     /*      Read lots of header fields.                                     */
     212             :     /* -------------------------------------------------------------------- */
     213        8755 :     if (!STARTS_WITH_CI(psFile->szVersion, "NITF01."))
     214             :     {
     215        8755 :         if ((int)psSegInfo->nSegmentHeaderSize < nOffset + 35 + 2)
     216           0 :             GOTO_header_too_small();
     217             : 
     218        8755 :         psImage->nRows = atoi(NITFGetField(szTemp, pachHeader, nOffset, 8));
     219        8755 :         psImage->nCols = atoi(NITFGetField(szTemp, pachHeader, nOffset + 8, 8));
     220             : 
     221        8755 :         NITFTrimWhite(
     222        8755 :             NITFGetField(psImage->szPVType, pachHeader, nOffset + 16, 3));
     223        8755 :         NITFTrimWhite(
     224        8755 :             NITFGetField(psImage->szIREP, pachHeader, nOffset + 19, 8));
     225        8755 :         NITFTrimWhite(
     226        8755 :             NITFGetField(psImage->szICAT, pachHeader, nOffset + 27, 8));
     227        8755 :         psImage->nABPP =
     228        8755 :             atoi(NITFGetField(szTemp, pachHeader, nOffset + 35, 2));
     229             :     }
     230             : 
     231        8755 :     nOffset += 38;
     232             : 
     233             :     /* -------------------------------------------------------------------- */
     234             :     /*      Do we have IGEOLO information?  In NITF 2.0 (and 1.x) 'N' means */
     235             :     /*      no information, while in 2.1 this is indicated as ' ', and 'N'  */
     236             :     /*      means UTM (north).  So for 2.0 products we change 'N' to ' '    */
     237             :     /*      to conform to 2.1 conventions.                                  */
     238             :     /* -------------------------------------------------------------------- */
     239        8755 :     if ((int)psSegInfo->nSegmentHeaderSize < nOffset + 1)
     240           0 :         GOTO_header_too_small();
     241             : 
     242        8755 :     GetMD(psImage, pachHeader, nOffset, 1, ICORDS);
     243             : 
     244        8755 :     psImage->chICORDS = pachHeader[nOffset++];
     245        8755 :     psImage->bHaveIGEOLO = FALSE;
     246             : 
     247        8755 :     if ((STARTS_WITH_CI(psFile->szVersion, "NITF02.0") ||
     248        8590 :          STARTS_WITH_CI(psFile->szVersion, "NITF01.")) &&
     249         165 :         psImage->chICORDS == 'N')
     250           8 :         psImage->chICORDS = ' ';
     251             : 
     252             :     /* -------------------------------------------------------------------- */
     253             :     /*      Read the image bounds.                                          */
     254             :     /* -------------------------------------------------------------------- */
     255        8755 :     if (psImage->chICORDS != ' ')
     256             :     {
     257             :         int iCoord;
     258             : 
     259         386 :         psImage->bHaveIGEOLO = TRUE;
     260         386 :         if ((int)psSegInfo->nSegmentHeaderSize < nOffset + 4 * 15)
     261           0 :             GOTO_header_too_small();
     262             : 
     263         386 :         GetMD(psImage, pachHeader, nOffset, 60, IGEOLO);
     264             : 
     265         386 :         psImage->bIsBoxCenterOfPixel = TRUE;
     266        1930 :         for (iCoord = 0; iCoord < 4; iCoord++)
     267             :         {
     268        1544 :             const char *pszCoordPair = pachHeader + nOffset + iCoord * 15;
     269        1544 :             double *pdfXY = &(psImage->dfULX) + iCoord * 2;
     270             : 
     271        1544 :             if (psImage->chICORDS == 'N' || psImage->chICORDS == 'S')
     272             :             {
     273         236 :                 psImage->nZone = atoi(NITFGetField(szTemp, pszCoordPair, 0, 2));
     274             : 
     275         236 :                 pdfXY[0] = CPLAtof(NITFGetField(szTemp, pszCoordPair, 2, 6));
     276         236 :                 pdfXY[1] = CPLAtof(NITFGetField(szTemp, pszCoordPair, 8, 7));
     277             :             }
     278        1308 :             else if (psImage->chICORDS == 'G' || psImage->chICORDS == 'C')
     279             :             {
     280             :                 // It is critical to do the fetching of the D, M, S components
     281             :                 // in 3 separate statements, otherwise if NITFGetField() is
     282             :                 // defined in this compilation unit, the MSVC optimizer will
     283             :                 // generate bad code, due to szTemp being overwritten before
     284             :                 // being evaluated by CPLAtof() !
     285        1272 :                 pdfXY[1] = CPLAtof(NITFGetField(szTemp, pszCoordPair, 0, 2));
     286        1272 :                 pdfXY[1] +=
     287        1272 :                     CPLAtof(NITFGetField(szTemp, pszCoordPair, 2, 2)) / 60.0;
     288        1272 :                 pdfXY[1] +=
     289        1272 :                     CPLAtof(NITFGetField(szTemp, pszCoordPair, 4, 2)) / 3600.0;
     290        1272 :                 if (pszCoordPair[6] == 's' || pszCoordPair[6] == 'S')
     291         208 :                     pdfXY[1] *= -1;
     292             : 
     293             :                 // It is critical to do the fetching of the D, M, S components
     294             :                 // in 3 separate statements, otherwise if NITFGetField() is
     295             :                 // defined in this compilation unit, the MSVC optimizer will
     296             :                 // generate bad code, due to szTemp being overwritten before
     297             :                 // being evaluated by CPLAtof() !
     298        1272 :                 pdfXY[0] = CPLAtof(NITFGetField(szTemp, pszCoordPair, 7, 3));
     299        1272 :                 pdfXY[0] +=
     300        1272 :                     CPLAtof(NITFGetField(szTemp, pszCoordPair, 10, 2)) / 60.0;
     301        1272 :                 pdfXY[0] +=
     302        1272 :                     CPLAtof(NITFGetField(szTemp, pszCoordPair, 12, 2)) / 3600.0;
     303             : 
     304        1272 :                 if (pszCoordPair[14] == 'w' || pszCoordPair[14] == 'W')
     305         386 :                     pdfXY[0] *= -1;
     306             :             }
     307          36 :             else if (psImage->chICORDS == 'D')
     308             :             { /* 'D' is Decimal Degrees */
     309          32 :                 pdfXY[1] = CPLAtof(NITFGetField(szTemp, pszCoordPair, 0, 7));
     310          32 :                 pdfXY[0] = CPLAtof(NITFGetField(szTemp, pszCoordPair, 7, 8));
     311             :             }
     312           4 :             else if (psImage->chICORDS == 'U')
     313             :             {
     314             :                 /* int err; */
     315             :                 long nZone;
     316             :                 char chHemisphere;
     317           4 :                 NITFGetField(szTemp, pszCoordPair, 0, 15);
     318             : 
     319           4 :                 CPLDebug("NITF", "IGEOLO = %15.15s", pszCoordPair);
     320           4 :                 /* err = */ Convert_MGRS_To_UTM(szTemp, &nZone, &chHemisphere,
     321             :                                                 pdfXY + 0, pdfXY + 1);
     322             : 
     323           4 :                 if (chHemisphere == 'S')
     324           0 :                     nZone = -1 * nZone;
     325             : 
     326           4 :                 if (psImage->nZone != 0 && psImage->nZone != -100)
     327             :                 {
     328           3 :                     if (nZone != psImage->nZone)
     329             :                     {
     330           0 :                         CPLError(
     331             :                             CE_Warning, CPLE_AppDefined,
     332             :                             "Some IGEOLO points are in different UTM\n"
     333             :                             "zones, but this configuration isn't currently\n"
     334             :                             "supported by GDAL, ignoring IGEOLO.");
     335           0 :                         psImage->nZone = -100;
     336             :                     }
     337             :                 }
     338           1 :                 else if (psImage->nZone == 0)
     339             :                 {
     340           1 :                     psImage->nZone = (int)nZone;
     341             :                 }
     342             :             }
     343             :         }
     344             : 
     345         386 :         if (psImage->nZone == -100)
     346           0 :             psImage->nZone = 0;
     347             : 
     348         386 :         nOffset += 60;
     349             :     }
     350             : #undef GetMD
     351             : 
     352             :     /* -------------------------------------------------------------------- */
     353             :     /*      Should we reorient the IGEOLO points in an attempt to handle    */
     354             :     /*      files where they were written in the wrong order?               */
     355             :     /* -------------------------------------------------------------------- */
     356        8755 :     if (psImage->bHaveIGEOLO)
     357         386 :         NITFPossibleIGEOLOReorientation(psImage);
     358             : 
     359             :     /* -------------------------------------------------------------------- */
     360             :     /*      Read the image comments.                                        */
     361             :     /* -------------------------------------------------------------------- */
     362             :     {
     363        8755 :         if ((int)psSegInfo->nSegmentHeaderSize < nOffset + 1)
     364           0 :             GOTO_header_too_small();
     365             : 
     366        8755 :         nNICOM = atoi(NITFGetField(szTemp, pachHeader, nOffset++, 1));
     367        8755 :         if ((int)psSegInfo->nSegmentHeaderSize < nOffset + 80 * nNICOM)
     368           0 :             GOTO_header_too_small();
     369             : 
     370        8755 :         char *pszICOM = (char *)CPLMalloc(nNICOM * 80 + 1);
     371        8755 :         psImage->pszComments =
     372        8755 :             CPLRecode(NITFGetField(pszICOM, pachHeader, nOffset, 80 * nNICOM),
     373             :                       CPL_ENC_ISO8859_1, CPL_ENC_UTF8);
     374        8755 :         CPLFree(pszICOM);
     375        8755 :         nOffset += nNICOM * 80;
     376             :     }
     377             : 
     378             :     /* -------------------------------------------------------------------- */
     379             :     /*      Read more stuff.                                                */
     380             :     /* -------------------------------------------------------------------- */
     381        8755 :     if ((int)psSegInfo->nSegmentHeaderSize < nOffset + 2)
     382           0 :         GOTO_header_too_small();
     383             : 
     384        8755 :     NITFGetField(psImage->szIC, pachHeader, nOffset, 2);
     385        8755 :     nOffset += 2;
     386             : 
     387        8755 :     if (psImage->szIC[0] != 'N')
     388             :     {
     389         222 :         if ((int)psSegInfo->nSegmentHeaderSize < nOffset + 4)
     390           0 :             GOTO_header_too_small();
     391             : 
     392         222 :         NITFGetField(psImage->szCOMRAT, pachHeader, nOffset, 4);
     393         222 :         nOffset += 4;
     394             :     }
     395             : 
     396             :     /* NBANDS */
     397        8755 :     if ((int)psSegInfo->nSegmentHeaderSize < nOffset + 1)
     398           0 :         GOTO_header_too_small();
     399        8755 :     psImage->nBands = atoi(NITFGetField(szTemp, pachHeader, nOffset, 1));
     400        8755 :     nOffset++;
     401             : 
     402             :     /* XBANDS */
     403        8755 :     if (psImage->nBands == 0)
     404             :     {
     405           2 :         if ((int)psSegInfo->nSegmentHeaderSize < nOffset + 5)
     406           0 :             GOTO_header_too_small();
     407           2 :         psImage->nBands = atoi(NITFGetField(szTemp, pachHeader, nOffset, 5));
     408           2 :         nOffset += 5;
     409             :     }
     410             : 
     411        8755 :     if (psImage->nBands <= 0)
     412             :     {
     413           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Invalid band number");
     414           0 :         NITFImageDeaccess(psImage);
     415           0 :         return NULL;
     416             :     }
     417             : 
     418             :     /* -------------------------------------------------------------------- */
     419             :     /*      Read per-band information.                                      */
     420             :     /* -------------------------------------------------------------------- */
     421        8755 :     psImage->pasBandInfo = (NITFBandInfo *)VSI_CALLOC_VERBOSE(
     422             :         sizeof(NITFBandInfo), psImage->nBands);
     423        8755 :     if (psImage->pasBandInfo == NULL)
     424             :     {
     425           0 :         NITFImageDeaccess(psImage);
     426           0 :         return NULL;
     427             :     }
     428             : 
     429      157801 :     for (iBand = 0; iBand < psImage->nBands; iBand++)
     430             :     {
     431      149046 :         NITFBandInfo *psBandInfo = psImage->pasBandInfo + iBand;
     432             :         int nLUTS;
     433             : 
     434      149046 :         if ((int)psSegInfo->nSegmentHeaderSize < nOffset + 2 + 6 + 4 + 1 + 5)
     435           0 :             GOTO_header_too_small();
     436             : 
     437      149046 :         NITFTrimWhite(
     438      149046 :             NITFGetField(psBandInfo->szIREPBAND, pachHeader, nOffset, 2));
     439      149046 :         nOffset += 2;
     440             : 
     441      149046 :         NITFTrimWhite(
     442      149046 :             NITFGetField(psBandInfo->szISUBCAT, pachHeader, nOffset, 6));
     443      149046 :         nOffset += 6;
     444             : 
     445      149046 :         nOffset += 4; /* Skip IFCn and IMFLTn */
     446             : 
     447      149046 :         nLUTS = atoi(NITFGetField(szTemp, pachHeader, nOffset, 1));
     448      149046 :         nOffset += 1;
     449             : 
     450      149046 :         if (nLUTS == 0)
     451      148883 :             continue;
     452             : 
     453         163 :         psBandInfo->nSignificantLUTEntries =
     454         163 :             atoi(NITFGetField(szTemp, pachHeader, nOffset, 5));
     455         163 :         nOffset += 5;
     456             : 
     457         163 :         if (psBandInfo->nSignificantLUTEntries < 0 ||
     458         163 :             psBandInfo->nSignificantLUTEntries > 256)
     459             :         {
     460           0 :             CPLError(CE_Warning, CPLE_AppDefined,
     461             :                      "LUT for band %d is corrupted : "
     462             :                      "nSignificantLUTEntries=%d. Truncating to 256",
     463             :                      iBand + 1, psBandInfo->nSignificantLUTEntries);
     464           0 :             psBandInfo->nSignificantLUTEntries = 256;
     465             :         }
     466             : 
     467         163 :         psBandInfo->nLUTLocation =
     468         163 :             nOffset + (int)psSegInfo->nSegmentHeaderStart;
     469             : 
     470         163 :         psBandInfo->pabyLUT = (unsigned char *)CPLCalloc(768, 1);
     471             : 
     472         163 :         if ((int)psSegInfo->nSegmentHeaderSize <
     473         163 :             nOffset + nLUTS * psBandInfo->nSignificantLUTEntries)
     474           0 :             GOTO_header_too_small();
     475             : 
     476         163 :         memcpy(psBandInfo->pabyLUT, pachHeader + nOffset,
     477         163 :                psBandInfo->nSignificantLUTEntries);
     478         163 :         nOffset += psBandInfo->nSignificantLUTEntries;
     479             : 
     480         163 :         if (nLUTS == 3)
     481             :         {
     482         163 :             memcpy(psBandInfo->pabyLUT + 256, pachHeader + nOffset,
     483         163 :                    psBandInfo->nSignificantLUTEntries);
     484         163 :             nOffset += psBandInfo->nSignificantLUTEntries;
     485             : 
     486         163 :             memcpy(psBandInfo->pabyLUT + 512, pachHeader + nOffset,
     487         163 :                    psBandInfo->nSignificantLUTEntries);
     488         163 :             nOffset += psBandInfo->nSignificantLUTEntries;
     489             :         }
     490           0 :         else if ((nLUTS == 2) && (STARTS_WITH_CI(psImage->szIREP, "MONO")) &&
     491           0 :                  ((STARTS_WITH_CI(psBandInfo->szIREPBAND, "M")) ||
     492           0 :                   (STARTS_WITH_CI(psBandInfo->szIREPBAND, "LU"))))
     493           0 :         {
     494             :             int iLUTEntry;
     495           0 :             double scale = 255.0 / 65535.0;
     496           0 :             unsigned char *pMSB = NULL;
     497           0 :             unsigned char *pLSB = NULL;
     498           0 :             unsigned char *p3rdLUT = NULL;
     499           0 :             unsigned char scaledVal = 0;
     500           0 :             unsigned short *pLUTVal = NULL;
     501             : 
     502             :             /* In this case, we have two LUTs. The first and second LUTs should
     503             :              * map respectively to the most */
     504             :             /* significant byte and the least significant byte of the 16 bit
     505             :              * values. */
     506             : 
     507           0 :             memcpy(psBandInfo->pabyLUT + 256, pachHeader + nOffset,
     508           0 :                    psBandInfo->nSignificantLUTEntries);
     509           0 :             nOffset += psBandInfo->nSignificantLUTEntries;
     510             : 
     511           0 :             pMSB = psBandInfo->pabyLUT;
     512           0 :             pLSB = psBandInfo->pabyLUT + 256;
     513           0 :             p3rdLUT = psBandInfo->pabyLUT + 512;
     514             :             /* E. Rouault: Why 255 and not 256 ? */
     515           0 :             pLUTVal = (unsigned short *)CPLMalloc(sizeof(short) * 255);
     516             : 
     517           0 :             for (iLUTEntry = 0; iLUTEntry < 255; ++iLUTEntry)
     518             :             {
     519             :                 /* E. Rouault: I don't understand why the following logic is
     520             :                  * endianness dependent. */
     521           0 :                 pLUTVal[iLUTEntry] = ((pMSB[iLUTEntry] << 8) | pLSB[iLUTEntry]);
     522             : #ifdef CPL_LSB
     523           0 :                 pLUTVal[iLUTEntry] =
     524           0 :                     ((pLUTVal[iLUTEntry] >> 8) | (pLUTVal[iLUTEntry] << 8));
     525             : #endif
     526             :             }
     527             : 
     528           0 :             for (iLUTEntry = 0; iLUTEntry < 255; ++iLUTEntry)
     529             :             {
     530           0 :                 scaledVal =
     531           0 :                     (unsigned char)ceil((double)(pLUTVal[iLUTEntry] * scale));
     532             : 
     533           0 :                 pMSB[iLUTEntry] = scaledVal;
     534           0 :                 pLSB[iLUTEntry] = scaledVal;
     535           0 :                 p3rdLUT[iLUTEntry] = scaledVal;
     536             :             }
     537             : 
     538           0 :             CPLFree(pLUTVal);
     539             :         }
     540             :         else
     541             :         {
     542             :             /* morph greyscale lut into RGB LUT. */
     543           0 :             memcpy(psBandInfo->pabyLUT + 256, psBandInfo->pabyLUT, 256);
     544           0 :             memcpy(psBandInfo->pabyLUT + 512, psBandInfo->pabyLUT, 256);
     545             :         }
     546             :     }
     547             : 
     548             :     /* -------------------------------------------------------------------- */
     549             :     /*      Some files (i.e. NSIF datasets) have truncated image              */
     550             :     /*      headers.  This has been observed with JPEG compressed           */
     551             :     /*      files.  In this case guess reasonable values for these          */
     552             :     /*      fields.                                                         */
     553             :     /* -------------------------------------------------------------------- */
     554        8755 :     if (nOffset + 40 > (int)psSegInfo->nSegmentHeaderSize)
     555             :     {
     556           0 :         psImage->chIMODE = 'B';
     557           0 :         psImage->nBlocksPerRow = 1;
     558           0 :         psImage->nBlocksPerColumn = 1;
     559           0 :         psImage->nBlockWidth = psImage->nCols;
     560           0 :         psImage->nBlockHeight = psImage->nRows;
     561           0 :         psImage->nBitsPerSample = psImage->nABPP;
     562           0 :         psImage->nIDLVL = 0;
     563           0 :         psImage->nIALVL = 0;
     564           0 :         psImage->nILOCRow = 0;
     565           0 :         psImage->nILOCColumn = 0;
     566           0 :         psImage->szIMAG[0] = '\0';
     567             : 
     568           0 :         nOffset += 40;
     569             :     }
     570             : 
     571             :     /* -------------------------------------------------------------------- */
     572             :     /*      Read more header fields.                                        */
     573             :     /* -------------------------------------------------------------------- */
     574             :     else
     575             :     {
     576        8755 :         psImage->chIMODE = pachHeader[nOffset + 1];
     577             : 
     578        8755 :         psImage->nBlocksPerRow =
     579        8755 :             atoi(NITFGetField(szTemp, pachHeader, nOffset + 2, 4));
     580        8755 :         psImage->nBlocksPerColumn =
     581        8755 :             atoi(NITFGetField(szTemp, pachHeader, nOffset + 6, 4));
     582        8755 :         psImage->nBlockWidth =
     583        8755 :             atoi(NITFGetField(szTemp, pachHeader, nOffset + 10, 4));
     584        8755 :         psImage->nBlockHeight =
     585        8755 :             atoi(NITFGetField(szTemp, pachHeader, nOffset + 14, 4));
     586             : 
     587             :         /* See MIL-STD-2500-C, paragraph 5.4.2.2-d (#3263) */
     588        8755 :         if (psImage->nBlocksPerRow == 1 && psImage->nBlockWidth == 0)
     589             :         {
     590           4 :             psImage->nBlockWidth = psImage->nCols;
     591             :         }
     592             : 
     593        8755 :         if (psImage->nBlocksPerColumn == 1 && psImage->nBlockHeight == 0)
     594             :         {
     595           6 :             psImage->nBlockHeight = psImage->nRows;
     596             :         }
     597             : 
     598        8755 :         psImage->nBitsPerSample =
     599        8755 :             atoi(NITFGetField(szTemp, pachHeader, nOffset + 18, 2));
     600             : 
     601        8755 :         if (psImage->nABPP == 0)
     602           0 :             psImage->nABPP = psImage->nBitsPerSample;
     603             : 
     604        8755 :         nOffset += 20;
     605             : 
     606             :         /* capture image inset information */
     607             : 
     608        8755 :         psImage->nIDLVL =
     609        8755 :             atoi(NITFGetField(szTemp, pachHeader, nOffset + 0, 3));
     610        8755 :         psImage->nIALVL =
     611        8755 :             atoi(NITFGetField(szTemp, pachHeader, nOffset + 3, 3));
     612        8755 :         psImage->nILOCRow =
     613        8755 :             atoi(NITFGetField(szTemp, pachHeader, nOffset + 6, 5));
     614        8755 :         psImage->nILOCColumn =
     615        8755 :             atoi(NITFGetField(szTemp, pachHeader, nOffset + 11, 5));
     616             : 
     617        8755 :         memcpy(psImage->szIMAG, pachHeader + nOffset + 16, 4);
     618        8755 :         psImage->szIMAG[4] = '\0';
     619             : 
     620        8755 :         nOffset += 3;  /* IDLVL */
     621        8755 :         nOffset += 3;  /* IALVL */
     622        8755 :         nOffset += 10; /* ILOC */
     623        8755 :         nOffset += 4;  /* IMAG */
     624             :     }
     625             : 
     626        8755 :     if (psImage->nBitsPerSample <= 0 || psImage->nBlocksPerRow <= 0 ||
     627        8755 :         psImage->nBlocksPerColumn <= 0 || psImage->nBlockWidth <= 0 ||
     628        8755 :         psImage->nBlockHeight <= 0 ||
     629        8755 :         psImage->nBlocksPerRow > INT_MAX / psImage->nBlockWidth ||
     630        8755 :         psImage->nBlocksPerColumn > INT_MAX / psImage->nBlockHeight ||
     631        8755 :         psImage->nCols > psImage->nBlocksPerRow * psImage->nBlockWidth ||
     632        8755 :         psImage->nRows > psImage->nBlocksPerColumn * psImage->nBlockHeight ||
     633        8755 :         psImage->nBlocksPerRow > INT_MAX / psImage->nBlocksPerColumn ||
     634        8755 :         psImage->nBlocksPerRow * psImage->nBlocksPerColumn >
     635        8755 :             INT_MAX / psImage->nBands)
     636             :     {
     637           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     638             :                  "Invalid values for block dimension/number");
     639           0 :         NITFImageDeaccess(psImage);
     640           0 :         return NULL;
     641             :     }
     642             : 
     643        8755 :     if (psImage->nBlocksPerRow * psImage->nBlocksPerColumn * psImage->nBands >
     644             :         1000 * 1000)
     645             :     {
     646             :         // Sanity check to avoid allocating too much memory
     647           0 :         VSIFSeekL(psFile->fp, 0, SEEK_END);
     648             :         // This is really a very safe bound. A smarter check would taken
     649             :         // into account the block size as well and/or the size of an entry
     650             :         // in the offset table.
     651           0 :         if (VSIFTellL(psFile->fp) <
     652           0 :             (vsi_l_offset)(psImage->nBlocksPerRow) * psImage->nBlocksPerColumn)
     653             :         {
     654           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     655             :                      "File is too small compared to the number of blocks");
     656           0 :             NITFImageDeaccess(psImage);
     657           0 :             return NULL;
     658             :         }
     659             :     }
     660             : 
     661             :     /* -------------------------------------------------------------------- */
     662             :     /*      Override nCols and nRows for NITF 1.1 (not sure why!)           */
     663             :     /* -------------------------------------------------------------------- */
     664        8755 :     if (STARTS_WITH_CI(psFile->szVersion, "NITF01."))
     665             :     {
     666           0 :         psImage->nCols = psImage->nBlocksPerRow * psImage->nBlockWidth;
     667           0 :         psImage->nRows = psImage->nBlocksPerColumn * psImage->nBlockHeight;
     668             :     }
     669             : 
     670             :     /* -------------------------------------------------------------------- */
     671             :     /*      Read TREs if we have them.                                      */
     672             :     /* -------------------------------------------------------------------- */
     673        8755 :     else if (nOffset + 10 <= (int)psSegInfo->nSegmentHeaderSize)
     674             :     {
     675        8755 :         int nUserTREBytes, nExtendedTREBytes, nFirstTagUsedLength = 0;
     676             : 
     677             :         /* --------------------------------------------------------------------
     678             :          */
     679             :         /*      Are there user TRE bytes to skip? */
     680             :         /* --------------------------------------------------------------------
     681             :          */
     682        8755 :         nUserTREBytes = atoi(NITFGetField(szTemp, pachHeader, nOffset, 5));
     683        8755 :         nOffset += 5;
     684             : 
     685        8755 :         if (nUserTREBytes > 3 + 11) /* Must have at least one tag */
     686             :         {
     687         158 :             if ((int)psSegInfo->nSegmentHeaderSize < nOffset + nUserTREBytes)
     688           0 :                 GOTO_header_too_small();
     689             : 
     690         158 :             psImage->nTREBytes = nUserTREBytes - 3;
     691         158 :             psImage->pachTRE = (char *)CPLMalloc(psImage->nTREBytes);
     692         158 :             memcpy(psImage->pachTRE, pachHeader + nOffset + 3,
     693         158 :                    psImage->nTREBytes);
     694             : 
     695         158 :             nOffset += nUserTREBytes;
     696             : 
     697             :             /* pachTRE is a raw copy of the header and is not NUL-terminated,
     698             :                so sscanf() would read past its end. Parse the 5-byte tag
     699             :                length field from a NUL-terminated copy. nTREBytes is > 11
     700             :                here (nUserTREBytes > 14), so bytes 6..10 are present. */
     701             :             {
     702             :                 char szFirstTagLength[6];
     703         158 :                 memcpy(szFirstTagLength, psImage->pachTRE + 6, 5);
     704         158 :                 szFirstTagLength[5] = '\0';
     705         158 :                 sscanf(szFirstTagLength, "%*5d%n", &nFirstTagUsedLength);
     706             :             }
     707         158 :             if (nFirstTagUsedLength != 5)
     708             :             {
     709           2 :                 CPLError(CE_Warning, CPLE_AppDefined,
     710             :                          "Cannot read User TRE. First tag's length is invalid");
     711           2 :                 CPLFree(psImage->pachTRE);
     712           2 :                 psImage->nTREBytes = 0;
     713           2 :                 psImage->pachTRE = NULL;
     714             :             }
     715             :         }
     716             :         else
     717             :         {
     718        8597 :             psImage->nTREBytes = 0;
     719        8597 :             psImage->pachTRE = NULL;
     720             : 
     721        8597 :             if (nUserTREBytes > 0)
     722           0 :                 nOffset += nUserTREBytes;
     723             :         }
     724             : 
     725             :         /* --------------------------------------------------------------------
     726             :          */
     727             :         /*      Are there managed TRE bytes to recognise? */
     728             :         /* --------------------------------------------------------------------
     729             :          */
     730        8755 :         if ((int)psSegInfo->nSegmentHeaderSize < nOffset + 5)
     731           0 :             GOTO_header_too_small();
     732        8755 :         nExtendedTREBytes = atoi(NITFGetField(szTemp, pachHeader, nOffset, 5));
     733        8755 :         nOffset += 5;
     734             : 
     735        8755 :         if (nExtendedTREBytes >= 3)
     736             :         {
     737         180 :             if ((int)psSegInfo->nSegmentHeaderSize <
     738         180 :                 nOffset + nExtendedTREBytes)
     739           0 :                 GOTO_header_too_small();
     740             : 
     741         180 :             psImage->nIXSOFLOffsetInSubfileHeader = nOffset;
     742             :             char szIXSOFL[4];
     743         180 :             memcpy(szIXSOFL, pachHeader + nOffset, 3);
     744         180 :             szIXSOFL[3] = 0;
     745         180 :             psImage->nIXSOFL = atoi(szIXSOFL);
     746         180 :             if (psImage->nIXSOFL != 0)
     747           2 :                 psImage->papszMetadata = CSLSetNameValue(
     748             :                     psImage->papszMetadata, "NITF_IXSOFL", szIXSOFL);
     749             : 
     750         180 :             if (nExtendedTREBytes > 3)
     751             :             {
     752         348 :                 psImage->pachTRE = (char *)CPLRealloc(
     753         174 :                     psImage->pachTRE,
     754         174 :                     psImage->nTREBytes + nExtendedTREBytes - 3);
     755         174 :                 memcpy(psImage->pachTRE + psImage->nTREBytes,
     756         174 :                        pachHeader + nOffset + 3, nExtendedTREBytes - 3);
     757             : 
     758         174 :                 psImage->nTREBytes += (nExtendedTREBytes - 3);
     759             :             }
     760             :             /*nOffset += nExtendedTREBytes;*/
     761             :         }
     762             :     }
     763             : 
     764             :     /* -------------------------------------------------------------------- */
     765             :     /*      Is there a location table to load?                              */
     766             :     /* -------------------------------------------------------------------- */
     767        8755 :     NITFLoadLocationTable(psImage);
     768             : 
     769             :     /* Fix bug #1744 */
     770        8755 :     if (psImage->nBands == 1)
     771        8608 :         NITFLoadColormapSubSection(psImage);
     772             : 
     773             :     /* -------------------------------------------------------------------- */
     774             :     /*      Setup some image access values.  Some of these may not apply    */
     775             :     /*      for compressed images, or band interleaved by block images.     */
     776             :     /* -------------------------------------------------------------------- */
     777        8755 :     if (psImage->nBitsPerSample <= 8)
     778        8666 :         psImage->nWordSize = 1;
     779          89 :     else if (psImage->nBitsPerSample <= 16)
     780          45 :         psImage->nWordSize = 2;
     781          44 :     else if (psImage->nBitsPerSample <= 32)
     782          31 :         psImage->nWordSize = 4;
     783             :     else
     784          13 :         psImage->nWordSize = psImage->nBitsPerSample / 8;
     785        8755 :     if (psImage->chIMODE == 'S')
     786             :     {
     787           0 :         psImage->nPixelOffset = psImage->nWordSize;
     788           0 :         psImage->nLineOffset =
     789           0 :             ((GIntBig)psImage->nBlockWidth * psImage->nBitsPerSample) / 8;
     790           0 :         psImage->nBlockOffset = psImage->nLineOffset * psImage->nBlockHeight;
     791           0 :         psImage->nBandOffset = psImage->nBlockOffset * psImage->nBlocksPerRow *
     792           0 :                                psImage->nBlocksPerColumn;
     793             :     }
     794        8755 :     else if (psImage->chIMODE == 'P')
     795             :     {
     796          19 :         psImage->nPixelOffset = (GIntBig)psImage->nWordSize * psImage->nBands;
     797          19 :         psImage->nLineOffset = ((GIntBig)psImage->nBlockWidth *
     798          19 :                                 psImage->nBitsPerSample * psImage->nBands) /
     799             :                                8;
     800          19 :         psImage->nBandOffset = psImage->nWordSize;
     801          19 :         psImage->nBlockOffset = psImage->nLineOffset * psImage->nBlockHeight;
     802             :     }
     803        8736 :     else if (psImage->chIMODE == 'R')
     804             :     {
     805           0 :         psImage->nPixelOffset = psImage->nWordSize;
     806           0 :         psImage->nBandOffset =
     807           0 :             ((GIntBig)psImage->nBlockWidth * psImage->nBitsPerSample) / 8;
     808           0 :         psImage->nLineOffset = psImage->nBandOffset * psImage->nBands;
     809           0 :         psImage->nBlockOffset = psImage->nLineOffset * psImage->nBlockHeight;
     810             :     }
     811             :     else /* if( psImage->chIMODE == 'B' ) */
     812             :     {
     813        8736 :         psImage->nPixelOffset = psImage->nWordSize;
     814        8736 :         psImage->nLineOffset =
     815        8736 :             ((GIntBig)psImage->nBlockWidth * psImage->nBitsPerSample) / 8;
     816        8736 :         psImage->nBandOffset = psImage->nBlockHeight * psImage->nLineOffset;
     817        8736 :         psImage->nBlockOffset = psImage->nBandOffset * psImage->nBands;
     818             :     }
     819             : 
     820             :     /* -------------------------------------------------------------------- */
     821             :     /*      Setup block map.                                                */
     822             :     /* -------------------------------------------------------------------- */
     823             : 
     824             :     /* Int overflow already checked above */
     825        8755 :     psImage->panBlockStart = (GUIntBig *)VSI_CALLOC_VERBOSE(
     826             :         (size_t)psImage->nBlocksPerRow * psImage->nBlocksPerColumn *
     827             :             psImage->nBands,
     828             :         sizeof(GUIntBig));
     829        8755 :     if (psImage->panBlockStart == NULL)
     830             :     {
     831           0 :         NITFImageDeaccess(psImage);
     832           0 :         return NULL;
     833             :     }
     834             : 
     835             :     /* -------------------------------------------------------------------- */
     836             :     /*  Load subframe mask table if present (typically, for CADRG/CIB       */
     837             :     /*  images with IC=C4/M4)                                               */
     838             :     /* -------------------------------------------------------------------- */
     839        8755 :     bool bBlockStartRead = false;
     840        8755 :     NITFLoadSubframeMaskTable(psImage, &bBlockStartRead);
     841             : 
     842             :     /* -------------------------------------------------------------------- */
     843             :     /*      Offsets to VQ compressed tiles are based on a fixed block       */
     844             :     /*      size, and are offset from the spatial data location kept in     */
     845             :     /*      the location table ... which is generally not the beginning     */
     846             :     /*      of the image data segment.                                      */
     847             :     /* -------------------------------------------------------------------- */
     848        8755 :     if (EQUAL(psImage->szIC, "C4"))
     849             :     {
     850         154 :         if (!bBlockStartRead)
     851             :         {
     852         120 :             GUIntBig nLocBase = psSegInfo->nSegmentStart;
     853             : 
     854        1560 :             for (i = 0; i < psImage->nLocCount; i++)
     855             :             {
     856        1440 :                 if (psImage->pasLocations[i].nLocId ==
     857             :                     LID_SpatialDataSubsection)
     858         120 :                     nLocBase = psImage->pasLocations[i].nLocOffset;
     859             :             }
     860             : 
     861         120 :             if (nLocBase == psSegInfo->nSegmentStart)
     862           0 :                 CPLError(CE_Warning, CPLE_AppDefined,
     863             :                          "Failed to find spatial data location, guessing.");
     864             : 
     865        4440 :             for (i = 0; i < psImage->nBlocksPerRow * psImage->nBlocksPerColumn;
     866        4320 :                  i++)
     867        4320 :                 psImage->panBlockStart[i] = nLocBase + (GUIntBig)(6144) * i;
     868             :         }
     869             :     }
     870             : 
     871             :     /* -------------------------------------------------------------------- */
     872             :     /*      If there is no block map, just compute directly assuming the    */
     873             :     /*      blocks start at the beginning of the image segment, and are     */
     874             :     /*      packed tightly with the IMODE organization.                     */
     875             :     /* -------------------------------------------------------------------- */
     876        8601 :     else if (psImage->szIC[0] != 'M' && psImage->szIC[1] != 'M')
     877        8594 :     {
     878             :         int iBlockX, iBlockY;
     879             : 
     880       17310 :         for (iBlockY = 0; iBlockY < psImage->nBlocksPerColumn; iBlockY++)
     881             :         {
     882       19023 :             for (iBlockX = 0; iBlockX < psImage->nBlocksPerRow; iBlockX++)
     883             :             {
     884      164125 :                 for (iBand = 0; iBand < psImage->nBands; iBand++)
     885             :                 {
     886             :                     int iBlock;
     887             : 
     888      153818 :                     iBlock = iBlockX + iBlockY * psImage->nBlocksPerRow +
     889      153818 :                              iBand * psImage->nBlocksPerRow *
     890      153818 :                                  psImage->nBlocksPerColumn;
     891             : 
     892      153818 :                     psImage->panBlockStart[iBlock] =
     893      153818 :                         psSegInfo->nSegmentStart +
     894      153818 :                         ((iBlockX + iBlockY * psImage->nBlocksPerRow) *
     895      153818 :                          psImage->nBlockOffset) +
     896      153818 :                         (iBand * psImage->nBandOffset);
     897             :                 }
     898             :             }
     899             :         }
     900             :     }
     901             : 
     902             :     /* -------------------------------------------------------------------- */
     903             :     /*      Otherwise we need to read the block map from the beginning      */
     904             :     /*      of the image segment.                                           */
     905             :     /* -------------------------------------------------------------------- */
     906             :     else
     907             :     {
     908             :         GUInt32 nIMDATOFF;
     909             :         GUInt16 nBMRLNTH, nTMRLNTH, nTPXCDLNTH;
     910             :         int nBlockCount;
     911           7 :         int bOK = TRUE;
     912             : 
     913           7 :         nBlockCount = psImage->nBlocksPerRow * psImage->nBlocksPerColumn *
     914           7 :                       psImage->nBands;
     915             : 
     916           7 :         CPLAssert(psImage->szIC[0] == 'M' || psImage->szIC[1] == 'M');
     917             : 
     918           7 :         bOK &= VSIFSeekL(psFile->fp, psSegInfo->nSegmentStart, SEEK_SET) == 0;
     919           7 :         bOK &= VSIFReadL(&nIMDATOFF, 1, 4, psFile->fp) == 4;
     920           7 :         bOK &= VSIFReadL(&nBMRLNTH, 1, 2, psFile->fp) == 2;
     921           7 :         bOK &= VSIFReadL(&nTMRLNTH, 1, 2, psFile->fp) == 2;
     922           7 :         bOK &= VSIFReadL(&nTPXCDLNTH, 1, 2, psFile->fp) == 2;
     923             : 
     924           7 :         CPL_MSBPTR32(&nIMDATOFF);
     925           7 :         CPL_MSBPTR16(&nBMRLNTH);
     926           7 :         CPL_MSBPTR16(&nTMRLNTH);
     927           7 :         CPL_MSBPTR16(&nTPXCDLNTH);
     928             : 
     929           7 :         if (nTPXCDLNTH == 8)
     930             :         {
     931             :             GByte byNodata;
     932             : 
     933           0 :             psImage->bNoDataSet = TRUE;
     934           0 :             bOK &= VSIFReadL(&byNodata, 1, 1, psFile->fp) == 1;
     935           0 :             psImage->nNoDataValue = byNodata;
     936             :         }
     937             :         else
     938           7 :             bOK &= VSIFSeekL(psFile->fp, (nTPXCDLNTH + 7) / 8, SEEK_CUR) == 0;
     939             : 
     940           7 :         if (nBMRLNTH == 4 && psImage->chIMODE == 'P')
     941           2 :         {
     942           2 :             int nStoredBlocks =
     943           2 :                 psImage->nBlocksPerRow * psImage->nBlocksPerColumn;
     944             : 
     945          10 :             for (i = 0; bOK && i < nStoredBlocks; i++)
     946             :             {
     947             :                 GUInt32 l_nOffset;
     948           8 :                 bOK &= VSIFReadL(&l_nOffset, 4, 1, psFile->fp) == 1;
     949           8 :                 CPL_MSBPTR32(&l_nOffset);
     950           8 :                 psImage->panBlockStart[i] = l_nOffset;
     951           8 :                 if (psImage->panBlockStart[i] != UINT_MAX)
     952             :                 {
     953           8 :                     psImage->panBlockStart[i] +=
     954           8 :                         psSegInfo->nSegmentStart + nIMDATOFF;
     955             : 
     956          24 :                     for (iBand = 1; iBand < psImage->nBands; iBand++)
     957             :                     {
     958          16 :                         psImage->panBlockStart[i + iBand * nStoredBlocks] =
     959          16 :                             psImage->panBlockStart[i] +
     960          16 :                             iBand * psImage->nBandOffset;
     961             :                     }
     962             :                 }
     963             :                 else
     964             :                 {
     965           0 :                     for (iBand = 1; iBand < psImage->nBands; iBand++)
     966           0 :                         psImage->panBlockStart[i + iBand * nStoredBlocks] =
     967             :                             UINT_MAX;
     968             :                 }
     969             :             }
     970             :         }
     971           5 :         else if (nBMRLNTH == 4)
     972             :         {
     973           0 :             if (!bBlockStartRead)
     974             :             {
     975           0 :                 for (i = 0; bOK && i < nBlockCount; i++)
     976             :                 {
     977             :                     GUInt32 l_nOffset;
     978           0 :                     bOK &= VSIFReadL(&l_nOffset, 4, 1, psFile->fp) == 1;
     979           0 :                     CPL_MSBPTR32(&l_nOffset);
     980           0 :                     psImage->panBlockStart[i] = l_nOffset;
     981           0 :                     if (psImage->panBlockStart[i] != UINT_MAX)
     982             :                     {
     983           0 :                         psImage->panBlockStart[i] +=
     984           0 :                             psSegInfo->nSegmentStart + nIMDATOFF;
     985             :                     }
     986             :                 }
     987             :             }
     988             :         }
     989             :         else
     990             :         {
     991           5 :             if (EQUAL(psImage->szIC, "M4"))
     992             :             {
     993           1 :                 if (!bBlockStartRead)
     994             :                 {
     995          37 :                     for (i = 0; i < nBlockCount; i++)
     996          36 :                         psImage->panBlockStart[i] = (GUIntBig)6144 * i +
     997          36 :                                                     psSegInfo->nSegmentStart +
     998             :                                                     nIMDATOFF;
     999             :                 }
    1000             :             }
    1001           4 :             else if (EQUAL(psImage->szIC, "NM"))
    1002             :             {
    1003             :                 int iBlockX, iBlockY;
    1004             : 
    1005           8 :                 for (iBlockY = 0; iBlockY < psImage->nBlocksPerColumn;
    1006           4 :                      iBlockY++)
    1007             :                 {
    1008           8 :                     for (iBlockX = 0; iBlockX < psImage->nBlocksPerRow;
    1009           4 :                          iBlockX++)
    1010             :                     {
    1011           8 :                         for (iBand = 0; iBand < psImage->nBands; iBand++)
    1012             :                         {
    1013             :                             int iBlock;
    1014             : 
    1015           4 :                             iBlock = iBlockX +
    1016           4 :                                      iBlockY * psImage->nBlocksPerRow +
    1017           4 :                                      iBand * psImage->nBlocksPerRow *
    1018           4 :                                          psImage->nBlocksPerColumn;
    1019             : 
    1020           4 :                             psImage->panBlockStart[iBlock] =
    1021           4 :                                 psSegInfo->nSegmentStart + nIMDATOFF +
    1022           4 :                                 ((iBlockX + iBlockY * psImage->nBlocksPerRow) *
    1023           4 :                                  psImage->nBlockOffset) +
    1024           4 :                                 (iBand * psImage->nBandOffset);
    1025             :                         }
    1026             :                     }
    1027             :                 }
    1028             :             }
    1029             :             else
    1030             :             {
    1031           0 :                 CPLError(
    1032             :                     CE_Warning, CPLE_AppDefined,
    1033             :                     "Unsupported IC value '%s', image access will likely fail.",
    1034           0 :                     psImage->szIC);
    1035             :             }
    1036             :         }
    1037           7 :         if (!bOK)
    1038             :         {
    1039           0 :             CPLError(CE_Failure, CPLE_FileIO, "I/O error");
    1040           0 :             NITFImageDeaccess(psImage);
    1041           0 :             return NULL;
    1042             :         }
    1043             :     }
    1044             : 
    1045             :     /* -------------------------------------------------------------------- */
    1046             :     /*      Bug #1751: Add a transparent color if there are none. Absent    */
    1047             :     /*      subblocks will be then transparent.                             */
    1048             :     /* -------------------------------------------------------------------- */
    1049        8755 :     if (!psImage->bNoDataSet && psImage->nBands == 1 &&
    1050        8504 :         psImage->nBitsPerSample == 8)
    1051             :     {
    1052        8384 :         NITFBandInfo *psBandInfo = psImage->pasBandInfo;
    1053        8384 :         if (psBandInfo->nSignificantLUTEntries < 256 - 1 &&
    1054        8384 :             psBandInfo->pabyLUT != NULL)
    1055             :         {
    1056          55 :             if (psBandInfo->nSignificantLUTEntries == 217 &&
    1057           0 :                 psBandInfo->pabyLUT[216] == 0 &&
    1058           0 :                 psBandInfo->pabyLUT[256 + 216] == 0 &&
    1059           0 :                 psBandInfo->pabyLUT[512 + 216] == 0)
    1060             :             {
    1061           0 :                 psImage->bNoDataSet = TRUE;
    1062           0 :                 psImage->nNoDataValue = psBandInfo->nSignificantLUTEntries - 1;
    1063             :             }
    1064             :             else
    1065             :             {
    1066          55 :                 bool bHasMissingBlock = false;
    1067         705 :                 for (int iBlock = 0; !bHasMissingBlock &&
    1068         671 :                                      iBlock < psImage->nBlocksPerRow *
    1069         671 :                                                   psImage->nBlocksPerColumn;
    1070         650 :                      ++iBlock)
    1071             :                 {
    1072         650 :                     bHasMissingBlock =
    1073         650 :                         (psImage->panBlockStart[iBlock] == UINT_MAX);
    1074             :                 }
    1075          55 :                 if (bHasMissingBlock)
    1076             :                 {
    1077             :                     psBandInfo
    1078          34 :                         ->pabyLUT[0 + psBandInfo->nSignificantLUTEntries] = 0;
    1079             :                     psBandInfo
    1080          34 :                         ->pabyLUT[256 + psBandInfo->nSignificantLUTEntries] = 0;
    1081             :                     psBandInfo
    1082          34 :                         ->pabyLUT[512 + psBandInfo->nSignificantLUTEntries] = 0;
    1083          34 :                     psImage->bNoDataSet = TRUE;
    1084          34 :                     psImage->nNoDataValue = psBandInfo->nSignificantLUTEntries;
    1085             :                 }
    1086             :             }
    1087             :         }
    1088             :     }
    1089             : 
    1090             :     /* -------------------------------------------------------------------- */
    1091             :     /*  We override the coordinates found in IGEOLO in case a BLOCKA is     */
    1092             :     /*  present. According to the BLOCKA specification, it repeats earth    */
    1093             :     /*  coordinates image corner locations described by IGEOLO in the NITF  */
    1094             :     /*  image subheader, but provide higher precision.                      */
    1095             :     /* -------------------------------------------------------------------- */
    1096             : 
    1097        8755 :     NITFReadBLOCKA_GCPs(psImage);
    1098             : 
    1099             :     /* -------------------------------------------------------------------- */
    1100             :     /*      We override the coordinates found in IGEOLO in case a GEOLOB is */
    1101             :     /*      present.  It provides higher precision lat/long values.         */
    1102             :     /* -------------------------------------------------------------------- */
    1103        8755 :     NITFReadGEOLOB(psImage);
    1104             : 
    1105             :     /* -------------------------------------------------------------------- */
    1106             :     /*      If we have an RPF CoverageSectionSubheader, read the more       */
    1107             :     /*      precise bounds from it.                                         */
    1108             :     /* -------------------------------------------------------------------- */
    1109        8755 :     for (i = 0; i < psImage->nLocCount; i++)
    1110             :     {
    1111         155 :         if (psImage->pasLocations[i].nLocId == LID_CoverageSectionSubheader)
    1112             :         {
    1113             :             double adfTarget[8];
    1114             : 
    1115         155 :             if (VSIFSeekL(psFile->fp, psImage->pasLocations[i].nLocOffset,
    1116         155 :                           SEEK_SET) != 0 ||
    1117         155 :                 VSIFReadL(adfTarget, 8, 8, psFile->fp) != 8)
    1118             :             {
    1119           0 :                 CPLError(CE_Failure, CPLE_FileIO, "I/O error");
    1120           0 :                 NITFImageDeaccess(psImage);
    1121           0 :                 return NULL;
    1122             :             }
    1123             : 
    1124        1395 :             for (i = 0; i < 8; i++)
    1125        1240 :                 CPL_MSBPTR64((adfTarget + i));
    1126             : 
    1127         155 :             psImage->dfULX = adfTarget[1];
    1128         155 :             psImage->dfULY = adfTarget[0];
    1129         155 :             psImage->dfLLX = adfTarget[3];
    1130         155 :             psImage->dfLLY = adfTarget[2];
    1131         155 :             psImage->dfURX = adfTarget[5];
    1132         155 :             psImage->dfURY = adfTarget[4];
    1133         155 :             psImage->dfLRX = adfTarget[7];
    1134         155 :             psImage->dfLRY = adfTarget[6];
    1135             : 
    1136         155 :             psImage->bIsBoxCenterOfPixel = FALSE;  // edge of pixel
    1137             : 
    1138         155 :             CPLDebug("NITF", "Got spatial info from CoverageSection");
    1139         155 :             break;
    1140             :         }
    1141             :     }
    1142             : 
    1143             :     /* Bug #1750, #2135 and #3383 */
    1144             :     /* Fix CADRG products like cjnc/cjncz01/000k1023.jn1 (and similar) from NIMA
    1145             :      * GNCJNCN CDROM: */
    1146             :     /* this product is crossing meridian 180deg and the upper and lower right
    1147             :      * longitudes are negative  */
    1148             :     /* while the upper and lower left longitudes are positive which causes
    1149             :      * problems in OpenEV, etc... */
    1150             :     /* So we are adjusting the upper and lower right longitudes by setting them
    1151             :      * above +180 */
    1152             :     /* Make this test only CADRG specific are there are other NITF profiles
    1153             :      * where non north-up imagery */
    1154             :     /* is valid */
    1155        8755 :     pszIID1 = CSLFetchNameValue(psImage->papszMetadata, "NITF_IID1");
    1156        8755 :     if ((psImage->chICORDS == 'G' || psImage->chICORDS == 'D') &&
    1157         328 :         pszIID1 != NULL && EQUAL(pszIID1, "CADRG") &&
    1158         155 :         (psImage->dfULX > psImage->dfURX && psImage->dfLLX > psImage->dfLRX &&
    1159           5 :          psImage->dfULY > psImage->dfLLY && psImage->dfURY > psImage->dfLRY))
    1160             :     {
    1161           0 :         psImage->dfURX += 360;
    1162           0 :         psImage->dfLRX += 360;
    1163             :     }
    1164             : 
    1165             :     /* -------------------------------------------------------------------- */
    1166             :     /*      Load RPF attribute metadata if we have it.                      */
    1167             :     /* -------------------------------------------------------------------- */
    1168        8755 :     NITFLoadAttributeSection(psImage);
    1169             : 
    1170             :     /* -------------------------------------------------------------------- */
    1171             :     /*      Are the VQ tables to load up?                                   */
    1172             :     /* -------------------------------------------------------------------- */
    1173        8755 :     NITFLoadVQTables(psImage, TRUE);
    1174             : 
    1175        8755 :     return psImage;
    1176             : 
    1177           0 : header_too_small:
    1178             : 
    1179           0 :     CPLError(CE_Failure, CPLE_AppDefined,
    1180             :              "Image header too small (called from line %d)", nFaultyLine);
    1181           0 :     NITFImageDeaccess(psImage);
    1182           0 :     return NULL;
    1183             : }
    1184             : 
    1185             : /************************************************************************/
    1186             : /*                         NITFImageDeaccess()                          */
    1187             : /************************************************************************/
    1188             : 
    1189        8755 : void NITFImageDeaccess(NITFImage *psImage)
    1190             : 
    1191             : {
    1192             :     int iBand;
    1193             : 
    1194        8755 :     CPLAssert(psImage->psFile->pasSegmentInfo[psImage->iSegment].hAccess ==
    1195             :               psImage);
    1196             : 
    1197        8755 :     psImage->psFile->pasSegmentInfo[psImage->iSegment].hAccess = NULL;
    1198             : 
    1199        8755 :     if (psImage->pasBandInfo)
    1200             :     {
    1201      157801 :         for (iBand = 0; iBand < psImage->nBands; iBand++)
    1202      149046 :             CPLFree(psImage->pasBandInfo[iBand].pabyLUT);
    1203             :     }
    1204        8755 :     CPLFree(psImage->pasBandInfo);
    1205        8755 :     CPLFree(psImage->panBlockStart);
    1206        8755 :     CPLFree(psImage->pszComments);
    1207        8755 :     CPLFree(psImage->pachHeader);
    1208        8755 :     CPLFree(psImage->pachTRE);
    1209        8755 :     CSLDestroy(psImage->papszMetadata);
    1210             : 
    1211        8755 :     CPLFree(psImage->pasLocations);
    1212       43775 :     for (iBand = 0; iBand < 4; iBand++)
    1213       35020 :         CPLFree(psImage->apanVQLUT[iBand]);
    1214             : 
    1215        8755 :     CPLFree(psImage);
    1216        8755 : }
    1217             : 
    1218             : /************************************************************************/
    1219             : /*                        NITFUncompressVQTile()                        */
    1220             : /*                                                                      */
    1221             : /*      This code was derived from OSSIM which in turn derived it       */
    1222             : /*      from OpenMap ... open source means sharing!                     */
    1223             : /************************************************************************/
    1224             : 
    1225         756 : static void NITFUncompressVQTile(const NITFImage *psImage,
    1226             :                                  const GByte *pabyVQBuf, GByte *pabyResult)
    1227             : 
    1228             : {
    1229         756 :     int i, j, t, iSrcByte = 0;
    1230             : 
    1231       49140 :     for (i = 0; i < 256; i += 4)
    1232             :     {
    1233     1596670 :         for (j = 0; j < 256; j += 8)
    1234             :         {
    1235     1548290 :             GUInt16 firstByte = pabyVQBuf[iSrcByte++];
    1236     1548290 :             GUInt16 secondByte = pabyVQBuf[iSrcByte++];
    1237     1548290 :             GUInt16 thirdByte = pabyVQBuf[iSrcByte++];
    1238             : 
    1239             :             /*
    1240             :              * because dealing with half-bytes is hard, we
    1241             :              * uncompress two 4x4 tiles at the same time. (a
    1242             :              * 4x4 tile compressed is 12 bits )
    1243             :              * this little code was grabbed from openmap software.
    1244             :              */
    1245             : 
    1246             :             /* Get first 12-bit value as index into VQ table */
    1247             : 
    1248     1548290 :             GUInt16 val1 = (firstByte << 4) | (secondByte >> 4);
    1249             : 
    1250             :             /* Get second 12-bit value as index into VQ table*/
    1251             : 
    1252     1548290 :             GUInt16 val2 = ((secondByte & 0x000F) << 8) | thirdByte;
    1253             : 
    1254     7741440 :             for (t = 0; t < 4; ++t)
    1255             :             {
    1256     6193150 :                 GByte *pabyTarget = pabyResult + (i + t) * 256 + j;
    1257             : 
    1258     6193150 :                 memcpy(pabyTarget, psImage->apanVQLUT[t] + val1, 4);
    1259     6193150 :                 memcpy(pabyTarget + 4, psImage->apanVQLUT[t] + val2, 4);
    1260             :             }
    1261             :         } /* for j */
    1262             :     } /* for i */
    1263         756 : }
    1264             : 
    1265             : /************************************************************************/
    1266             : /*                         NITFReadImageBlock()                         */
    1267             : /************************************************************************/
    1268             : 
    1269        3445 : int NITFReadImageBlock(NITFImage *psImage, int nBlockX, int nBlockY, int nBand,
    1270             :                        void *pData)
    1271             : 
    1272             : {
    1273             :     int nWrkBufSize;
    1274        3445 :     int iBaseBlock = nBlockX + nBlockY * psImage->nBlocksPerRow;
    1275        3445 :     int iFullBlock = iBaseBlock + (nBand - 1) * psImage->nBlocksPerRow *
    1276        3445 :                                       psImage->nBlocksPerColumn;
    1277             : 
    1278             :     /* -------------------------------------------------------------------- */
    1279             :     /*      Special exit conditions.                                        */
    1280             :     /* -------------------------------------------------------------------- */
    1281        3445 :     if (nBand == 0)
    1282           0 :         return BLKREAD_FAIL;
    1283             : 
    1284        3445 :     if (psImage->panBlockStart[iFullBlock] == UINT_MAX)
    1285         576 :         return BLKREAD_NULL;
    1286             : 
    1287             :     /* -------------------------------------------------------------------- */
    1288             :     /*      Special case for 1 bit data.  NITFRasterBand::IReadBlock()      */
    1289             :     /*      already knows how to promote to byte.                           */
    1290             :     /* -------------------------------------------------------------------- */
    1291        2869 :     if ((EQUAL(psImage->szIC, "NC") || EQUAL(psImage->szIC, "NM")) &&
    1292        2112 :         psImage->nBitsPerSample == 1)
    1293             :     {
    1294          10 :         if (nBlockX != 0 || nBlockY != 0)
    1295             :         {
    1296           0 :             CPLError(CE_Failure, CPLE_AppDefined,
    1297             :                      "assert nBlockX == 0 && nBlockY == 0 failed\n");
    1298           0 :             return BLKREAD_FAIL;
    1299             :         }
    1300          10 :         if (VSIFSeekL(psImage->psFile->fp,
    1301          10 :                       psImage->panBlockStart[0] +
    1302          10 :                           ((vsi_l_offset)psImage->nBlockWidth *
    1303          10 :                                psImage->nBlockHeight +
    1304          10 :                            7) /
    1305          10 :                               8 * (nBand - 1),
    1306          10 :                       SEEK_SET) == 0 &&
    1307          10 :             VSIFReadL(pData,
    1308          10 :                       (psImage->nBlockWidth * psImage->nBlockHeight + 7) / 8, 1,
    1309          10 :                       psImage->psFile->fp) == 1)
    1310             :         {
    1311          10 :             return BLKREAD_OK;
    1312             :         }
    1313           0 :         CPLError(CE_Failure, CPLE_FileIO, "I/O error");
    1314           0 :         return BLKREAD_FAIL;
    1315             :     }
    1316             : 
    1317             :     /* -------------------------------------------------------------------- */
    1318             :     /*      Figure out how big the working buffer will need to be.          */
    1319             :     /* -------------------------------------------------------------------- */
    1320        2859 :     if (psImage->nBitsPerSample != psImage->nWordSize * 8)
    1321          43 :         nWrkBufSize =
    1322          43 :             (int)psImage->nLineOffset * (psImage->nBlockHeight - 1) +
    1323          43 :             (psImage->nBitsPerSample * (psImage->nBlockWidth) + 7) / 8;
    1324             :     else
    1325        2816 :         nWrkBufSize = (int)psImage->nLineOffset * (psImage->nBlockHeight - 1) +
    1326        2816 :                       (int)psImage->nPixelOffset * (psImage->nBlockWidth - 1) +
    1327        2816 :                       psImage->nWordSize;
    1328             : 
    1329        2859 :     if (nWrkBufSize == 0)
    1330           0 :         nWrkBufSize = (psImage->nBlockWidth * psImage->nBlockHeight *
    1331           0 :                            psImage->nBitsPerSample +
    1332             :                        7) /
    1333             :                       8;
    1334             : 
    1335             :     /* -------------------------------------------------------------------- */
    1336             :     /*      Can we do a direct read into our buffer?                        */
    1337             :     /* -------------------------------------------------------------------- */
    1338        2859 :     if ((size_t)psImage->nWordSize == psImage->nPixelOffset &&
    1339        2859 :         (size_t)((psImage->nBitsPerSample * psImage->nBlockWidth + 7) / 8) ==
    1340        2859 :             psImage->nLineOffset &&
    1341        2827 :         psImage->szIC[0] != 'C' && psImage->szIC[0] != 'M' &&
    1342        2070 :         psImage->chIMODE != 'P')
    1343             :     {
    1344        2070 :         if (VSIFSeekL(psImage->psFile->fp, psImage->panBlockStart[iFullBlock],
    1345        2070 :                       SEEK_SET) != 0 ||
    1346        2070 :             (int)VSIFReadL(pData, 1, nWrkBufSize, psImage->psFile->fp) !=
    1347             :                 nWrkBufSize)
    1348             :         {
    1349           0 :             CPLError(CE_Failure, CPLE_FileIO,
    1350             :                      "Unable to read %d byte block from " CPL_FRMT_GUIB ".",
    1351           0 :                      nWrkBufSize, psImage->panBlockStart[iFullBlock]);
    1352           0 :             return BLKREAD_FAIL;
    1353             :         }
    1354             :         else
    1355             :         {
    1356             : #ifdef CPL_LSB
    1357        2070 :             NITFSwapWords(psImage, pData,
    1358        2070 :                           psImage->nBlockWidth * psImage->nBlockHeight);
    1359             : #endif
    1360             : 
    1361        2070 :             return BLKREAD_OK;
    1362             :         }
    1363             :     }
    1364             : 
    1365         789 :     if (psImage->szIC[0] == 'N')
    1366             :     {
    1367             :         /* read all the data needed to get our requested band-block */
    1368          32 :         if (psImage->nBitsPerSample != psImage->nWordSize * 8)
    1369             :         {
    1370          32 :             if (psImage->chIMODE == 'S' ||
    1371          32 :                 (psImage->chIMODE == 'B' && psImage->nBands == 1))
    1372             :             {
    1373          32 :                 nWrkBufSize = ((psImage->nBlockWidth * psImage->nBlockHeight *
    1374          32 :                                 psImage->nBitsPerSample) +
    1375             :                                7) /
    1376             :                               8;
    1377          32 :                 if (VSIFSeekL(psImage->psFile->fp,
    1378          32 :                               psImage->panBlockStart[iFullBlock],
    1379          32 :                               SEEK_SET) != 0 ||
    1380          32 :                     (int)VSIFReadL(pData, 1, nWrkBufSize,
    1381          32 :                                    psImage->psFile->fp) != nWrkBufSize)
    1382             :                 {
    1383           0 :                     CPLError(CE_Failure, CPLE_FileIO,
    1384             :                              "Unable to read %d byte block from %d.",
    1385             :                              (int)nWrkBufSize,
    1386           0 :                              (int)psImage->panBlockStart[iFullBlock]);
    1387           0 :                     return BLKREAD_FAIL;
    1388             :                 }
    1389             : 
    1390          32 :                 return BLKREAD_OK;
    1391             :             }
    1392             :             else
    1393             :             {
    1394           0 :                 CPLError(CE_Failure, CPLE_NotSupported,
    1395             :                          "ABPP=%d and IMODE=%c not supported",
    1396           0 :                          psImage->nBitsPerSample, psImage->chIMODE);
    1397           0 :                 return BLKREAD_FAIL;
    1398             :             }
    1399             :         }
    1400             :     }
    1401             : 
    1402             :     /* -------------------------------------------------------------------- */
    1403             :     /*      Read the requested information into a temporary buffer and      */
    1404             :     /*      pull out what we want.                                          */
    1405             :     /* -------------------------------------------------------------------- */
    1406         757 :     if (psImage->szIC[0] == 'N')
    1407             :     {
    1408           0 :         GByte *pabyWrkBuf = (GByte *)VSI_MALLOC_VERBOSE(nWrkBufSize);
    1409             :         int iPixel, iLine;
    1410             : 
    1411           0 :         if (pabyWrkBuf == NULL)
    1412             :         {
    1413           0 :             return BLKREAD_FAIL;
    1414             :         }
    1415             : 
    1416             :         /* read all the data needed to get our requested band-block */
    1417           0 :         if (VSIFSeekL(psImage->psFile->fp, psImage->panBlockStart[iFullBlock],
    1418           0 :                       SEEK_SET) != 0 ||
    1419           0 :             (int)VSIFReadL(pabyWrkBuf, 1, nWrkBufSize, psImage->psFile->fp) !=
    1420             :                 nWrkBufSize)
    1421             :         {
    1422           0 :             CPLError(CE_Failure, CPLE_FileIO,
    1423             :                      "Unable to read %d byte block from " CPL_FRMT_GUIB ".",
    1424           0 :                      nWrkBufSize, psImage->panBlockStart[iFullBlock]);
    1425           0 :             CPLFree(pabyWrkBuf);
    1426           0 :             return BLKREAD_FAIL;
    1427             :         }
    1428             : 
    1429           0 :         for (iLine = 0; iLine < psImage->nBlockHeight; iLine++)
    1430             :         {
    1431             :             GByte *pabySrc, *pabyDst;
    1432             : 
    1433           0 :             pabySrc = pabyWrkBuf + iLine * psImage->nLineOffset;
    1434           0 :             pabyDst = ((GByte *)pData) +
    1435           0 :                       iLine * (psImage->nWordSize * psImage->nBlockWidth);
    1436             : 
    1437           0 :             for (iPixel = 0; iPixel < psImage->nBlockWidth; iPixel++)
    1438             :             {
    1439           0 :                 memcpy(pabyDst + iPixel * psImage->nWordSize,
    1440           0 :                        pabySrc + iPixel * psImage->nPixelOffset,
    1441           0 :                        psImage->nWordSize);
    1442             :             }
    1443             :         }
    1444             : 
    1445             : #ifdef CPL_LSB
    1446           0 :         NITFSwapWords(psImage, pData,
    1447           0 :                       psImage->nBlockWidth * psImage->nBlockHeight);
    1448             : #endif
    1449             : 
    1450           0 :         CPLFree(pabyWrkBuf);
    1451             : 
    1452           0 :         return BLKREAD_OK;
    1453             :     }
    1454             : 
    1455             :     /* -------------------------------------------------------------------- */
    1456             :     /*      Handle VQ compression.  The VQ compression basically keeps a    */
    1457             :     /*      64x64 array of 12bit code words.  Each code word expands to     */
    1458             :     /*      a predefined 4x4 8 bit per pixel pattern.                       */
    1459             :     /* -------------------------------------------------------------------- */
    1460         757 :     else if (EQUAL(psImage->szIC, "C4") || EQUAL(psImage->szIC, "M4"))
    1461             :     {
    1462             :         GByte abyVQCoded[6144];
    1463             : 
    1464         756 :         if (psImage->apanVQLUT[0] == NULL)
    1465             :         {
    1466           0 :             CPLError(CE_Failure, CPLE_NotSupported,
    1467             :                      "File lacks VQ LUTs, unable to decode imagery.");
    1468           0 :             return BLKREAD_FAIL;
    1469             :         }
    1470         756 :         if (psImage->nBlockWidth != 256 || psImage->nBlockHeight != 256)
    1471             :         {
    1472           0 :             CPLError(CE_Failure, CPLE_NotSupported,
    1473             :                      "Invalid block dimension for VQ compressed data.");
    1474           0 :             return BLKREAD_FAIL;
    1475             :         }
    1476             : 
    1477             :         /* Read the codewords */
    1478         756 :         if (VSIFSeekL(psImage->psFile->fp, psImage->panBlockStart[iFullBlock],
    1479         756 :                       SEEK_SET) != 0 ||
    1480         756 :             VSIFReadL(abyVQCoded, 1, sizeof(abyVQCoded), psImage->psFile->fp) !=
    1481             :                 sizeof(abyVQCoded))
    1482             :         {
    1483           0 :             CPLError(CE_Failure, CPLE_FileIO,
    1484             :                      "Unable to read %d byte block from " CPL_FRMT_GUIB ".",
    1485             :                      (int)sizeof(abyVQCoded),
    1486           0 :                      psImage->panBlockStart[iFullBlock]);
    1487           0 :             return BLKREAD_FAIL;
    1488             :         }
    1489             : 
    1490         756 :         NITFUncompressVQTile(psImage, abyVQCoded, pData);
    1491             : 
    1492         756 :         return BLKREAD_OK;
    1493             :     }
    1494             : 
    1495             :     /* -------------------------------------------------------------------- */
    1496             :     /*      Handle ARIDPCM compression.                                     */
    1497             :     /* -------------------------------------------------------------------- */
    1498           1 :     else if (EQUAL(psImage->szIC, "C2") || EQUAL(psImage->szIC, "M2"))
    1499             :     {
    1500             :         GIntBig nSignedRawBytes;
    1501             :         size_t nRawBytes;
    1502             :         NITFSegmentInfo *psSegInfo;
    1503             :         int success;
    1504             :         GByte *pabyRawData;
    1505             : 
    1506           0 :         if (psImage->nBitsPerSample != 8)
    1507             :         {
    1508           0 :             CPLError(
    1509             :                 CE_Failure, CPLE_AppDefined,
    1510             :                 "Unsupported bits per sample value (%d) for C2/M2 compression",
    1511             :                 psImage->nBitsPerSample);
    1512           0 :             return BLKREAD_FAIL;
    1513             :         }
    1514             : 
    1515           0 :         if (iFullBlock < psImage->nBlocksPerRow * psImage->nBlocksPerColumn *
    1516           0 :                                  psImage->nBands -
    1517             :                              1)
    1518             :         {
    1519           0 :             nSignedRawBytes = (GIntBig)psImage->panBlockStart[iFullBlock + 1] -
    1520           0 :                               (GIntBig)psImage->panBlockStart[iFullBlock];
    1521             :         }
    1522             :         else
    1523             :         {
    1524           0 :             psSegInfo = psImage->psFile->pasSegmentInfo + psImage->iSegment;
    1525           0 :             nSignedRawBytes = (GIntBig)psSegInfo->nSegmentStart +
    1526           0 :                               (GIntBig)psSegInfo->nSegmentSize -
    1527           0 :                               (GIntBig)psImage->panBlockStart[iFullBlock];
    1528             :         }
    1529           0 :         if (nSignedRawBytes <= 0 || nSignedRawBytes > INT_MAX)
    1530             :         {
    1531           0 :             CPLError(CE_Failure, CPLE_AppDefined,
    1532             :                      "Invalid block size : " CPL_FRMT_GIB, nSignedRawBytes);
    1533           0 :             return BLKREAD_FAIL;
    1534             :         }
    1535             : 
    1536           0 :         nRawBytes = (size_t)nSignedRawBytes;
    1537           0 :         pabyRawData = (GByte *)VSI_MALLOC_VERBOSE(nRawBytes);
    1538           0 :         if (pabyRawData == NULL)
    1539             :         {
    1540           0 :             return BLKREAD_FAIL;
    1541             :         }
    1542             : 
    1543             :         /* Read the codewords */
    1544           0 :         if (VSIFSeekL(psImage->psFile->fp, psImage->panBlockStart[iFullBlock],
    1545           0 :                       SEEK_SET) != 0 ||
    1546           0 :             VSIFReadL(pabyRawData, 1, nRawBytes, psImage->psFile->fp) !=
    1547             :                 nRawBytes)
    1548             :         {
    1549           0 :             CPLError(CE_Failure, CPLE_FileIO,
    1550             :                      "Unable to read %d byte block from " CPL_FRMT_GUIB ".",
    1551           0 :                      (int)nRawBytes, psImage->panBlockStart[iFullBlock]);
    1552           0 :             CPLFree(pabyRawData);
    1553           0 :             return BLKREAD_FAIL;
    1554             :         }
    1555             : 
    1556             :         success =
    1557           0 :             NITFUncompressARIDPCM(psImage, pabyRawData, (int)nRawBytes, pData);
    1558             : 
    1559           0 :         CPLFree(pabyRawData);
    1560             : 
    1561           0 :         if (success)
    1562           0 :             return BLKREAD_OK;
    1563             :         else
    1564           0 :             return BLKREAD_FAIL;
    1565             :     }
    1566             : 
    1567             :     /* -------------------------------------------------------------------- */
    1568             :     /*      Handle BILEVEL (C1) compression.                                */
    1569             :     /* -------------------------------------------------------------------- */
    1570           1 :     else if (EQUAL(psImage->szIC, "C1") || EQUAL(psImage->szIC, "M1"))
    1571             :     {
    1572             : #ifdef HAVE_TIFF
    1573             :         GIntBig nSignedRawBytes;
    1574             :         size_t nRawBytes;
    1575             :         NITFSegmentInfo *psSegInfo;
    1576             :         int success;
    1577             :         GByte *pabyRawData;
    1578             : 
    1579           1 :         if (psImage->nBitsPerSample != 1)
    1580             :         {
    1581           0 :             CPLError(CE_Failure, CPLE_AppDefined,
    1582             :                      "Invalid bits per sample value (%d) for C1/M1 compression",
    1583             :                      psImage->nBitsPerSample);
    1584           0 :             return BLKREAD_FAIL;
    1585             :         }
    1586             : 
    1587           1 :         if (iFullBlock < psImage->nBlocksPerRow * psImage->nBlocksPerColumn *
    1588           1 :                                  psImage->nBands -
    1589             :                              1)
    1590             :         {
    1591           0 :             nSignedRawBytes = (GIntBig)psImage->panBlockStart[iFullBlock + 1] -
    1592           0 :                               (GIntBig)psImage->panBlockStart[iFullBlock];
    1593             :         }
    1594             :         else
    1595             :         {
    1596           1 :             psSegInfo = psImage->psFile->pasSegmentInfo + psImage->iSegment;
    1597           1 :             nSignedRawBytes = (GIntBig)psSegInfo->nSegmentStart +
    1598           1 :                               (GIntBig)psSegInfo->nSegmentSize -
    1599           1 :                               (GIntBig)psImage->panBlockStart[iFullBlock];
    1600             :         }
    1601           1 :         if (nSignedRawBytes <= 0 || nSignedRawBytes > INT_MAX)
    1602             :         {
    1603           0 :             CPLError(CE_Failure, CPLE_AppDefined,
    1604             :                      "Invalid block size : " CPL_FRMT_GIB, nSignedRawBytes);
    1605           0 :             return BLKREAD_FAIL;
    1606             :         }
    1607             : 
    1608           1 :         nRawBytes = (size_t)nSignedRawBytes;
    1609           1 :         pabyRawData = (GByte *)VSI_MALLOC_VERBOSE(nRawBytes);
    1610           1 :         if (pabyRawData == NULL)
    1611             :         {
    1612           0 :             return BLKREAD_FAIL;
    1613             :         }
    1614             : 
    1615             :         /* Read the codewords */
    1616           1 :         if (VSIFSeekL(psImage->psFile->fp, psImage->panBlockStart[iFullBlock],
    1617           1 :                       SEEK_SET) != 0 ||
    1618           1 :             VSIFReadL(pabyRawData, 1, nRawBytes, psImage->psFile->fp) !=
    1619             :                 nRawBytes)
    1620             :         {
    1621           0 :             CPLError(CE_Failure, CPLE_FileIO,
    1622             :                      "Unable to read %d byte block from " CPL_FRMT_GUIB ".",
    1623           0 :                      (int)nRawBytes, psImage->panBlockStart[iFullBlock]);
    1624           0 :             CPLFree(pabyRawData);
    1625           0 :             return BLKREAD_FAIL;
    1626             :         }
    1627             : 
    1628             :         success =
    1629           1 :             NITFUncompressBILEVEL(psImage, pabyRawData, (int)nRawBytes, pData);
    1630             : 
    1631           1 :         CPLFree(pabyRawData);
    1632             : 
    1633           1 :         if (success)
    1634           1 :             return BLKREAD_OK;
    1635             :         else
    1636           0 :             return BLKREAD_FAIL;
    1637             : #else
    1638             :         CPLError(CE_Failure, CPLE_NotSupported,
    1639             :                  "BILEVEL compression not supported because of lack of "
    1640             :                  "TIFF support");
    1641             :         return BLKREAD_FAIL;
    1642             : #endif
    1643             :     }
    1644             : 
    1645             :     /* -------------------------------------------------------------------- */
    1646             :     /*      Report unsupported compression scheme(s).                       */
    1647             :     /* -------------------------------------------------------------------- */
    1648           0 :     else if (atoi(psImage->szIC + 1) > 0)
    1649             :     {
    1650           0 :         CPLError(CE_Failure, CPLE_NotSupported,
    1651             :                  "Unsupported imagery compression format %s in NITF library.",
    1652           0 :                  psImage->szIC);
    1653           0 :         return BLKREAD_FAIL;
    1654             :     }
    1655             : 
    1656           0 :     return BLKREAD_FAIL;
    1657             : }
    1658             : 
    1659             : /************************************************************************/
    1660             : /*                        NITFWriteImageBlock()                         */
    1661             : /************************************************************************/
    1662             : 
    1663         644 : int NITFWriteImageBlock(NITFImage *psImage, int nBlockX, int nBlockY, int nBand,
    1664             :                         void *pData)
    1665             : 
    1666             : {
    1667             :     GUIntBig nWrkBufSize;
    1668         644 :     int iBaseBlock = nBlockX + nBlockY * psImage->nBlocksPerRow;
    1669         644 :     int iFullBlock = iBaseBlock + (nBand - 1) * psImage->nBlocksPerRow *
    1670         644 :                                       psImage->nBlocksPerColumn;
    1671             : 
    1672         644 :     if (nBand == 0)
    1673           0 :         return BLKREAD_FAIL;
    1674             : 
    1675         644 :     nWrkBufSize = psImage->nLineOffset * (psImage->nBlockHeight - 1) +
    1676         644 :                   psImage->nPixelOffset * (psImage->nBlockWidth - 1) +
    1677         644 :                   psImage->nWordSize;
    1678             : 
    1679         644 :     if (nWrkBufSize == 0)
    1680           0 :         nWrkBufSize = ((GUIntBig)psImage->nBlockWidth * psImage->nBlockHeight *
    1681           0 :                            psImage->nBitsPerSample +
    1682             :                        7) /
    1683             :                       8;
    1684             : 
    1685             :     /* -------------------------------------------------------------------- */
    1686             :     /*      Can we do a direct read into our buffer?                        */
    1687             :     /* -------------------------------------------------------------------- */
    1688         644 :     if ((size_t)psImage->nWordSize == psImage->nPixelOffset &&
    1689         644 :         (size_t)(psImage->nWordSize * psImage->nBlockWidth) ==
    1690         644 :             psImage->nLineOffset &&
    1691         644 :         psImage->szIC[0] != 'C' && psImage->szIC[0] != 'M')
    1692             :     {
    1693             : #ifdef CPL_LSB
    1694         644 :         NITFSwapWords(psImage, pData,
    1695         644 :                       psImage->nBlockWidth * psImage->nBlockHeight);
    1696             : #endif
    1697             : 
    1698         644 :         if (VSIFSeekL(psImage->psFile->fp, psImage->panBlockStart[iFullBlock],
    1699         644 :                       SEEK_SET) != 0 ||
    1700         644 :             (GUIntBig)VSIFWriteL(pData, 1, (size_t)nWrkBufSize,
    1701         644 :                                  psImage->psFile->fp) != nWrkBufSize)
    1702             :         {
    1703           0 :             CPLError(CE_Failure, CPLE_FileIO,
    1704             :                      "Unable to write " CPL_FRMT_GUIB
    1705             :                      " byte block from " CPL_FRMT_GUIB ".",
    1706           0 :                      nWrkBufSize, psImage->panBlockStart[iFullBlock]);
    1707           0 :             return BLKREAD_FAIL;
    1708             :         }
    1709             :         else
    1710             :         {
    1711             : #ifdef CPL_LSB
    1712             :             /* restore byte order to original */
    1713         644 :             NITFSwapWords(psImage, pData,
    1714         644 :                           psImage->nBlockWidth * psImage->nBlockHeight);
    1715             : #endif
    1716             : 
    1717         644 :             return BLKREAD_OK;
    1718             :         }
    1719             :     }
    1720             : 
    1721             :     /* -------------------------------------------------------------------- */
    1722             :     /*      Other forms not supported at this time.                         */
    1723             :     /* -------------------------------------------------------------------- */
    1724           0 :     CPLError(CE_Failure, CPLE_NotSupported,
    1725             :              "Mapped, interleaved and compressed NITF forms not supported\n"
    1726             :              "for writing at this time.");
    1727             : 
    1728           0 :     return BLKREAD_FAIL;
    1729             : }
    1730             : 
    1731             : /************************************************************************/
    1732             : /*                         NITFReadImageLine()                          */
    1733             : /************************************************************************/
    1734             : 
    1735       16551 : int NITFReadImageLine(NITFImage *psImage, int nLine, int nBand, void *pData)
    1736             : 
    1737             : {
    1738             :     GUIntBig nLineOffsetInFile;
    1739             :     size_t nLineSize;
    1740             :     unsigned char *pabyLineBuf;
    1741             : 
    1742       16551 :     if (nBand == 0)
    1743           0 :         return BLKREAD_FAIL;
    1744             : 
    1745       16551 :     if (psImage->nBlocksPerRow != 1 || psImage->nBlocksPerColumn != 1)
    1746             :     {
    1747           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    1748             :                  "Scanline access not supported on tiled NITF files.");
    1749           0 :         return BLKREAD_FAIL;
    1750             :     }
    1751             : 
    1752       16551 :     if (psImage->nBlockWidth < psImage->nCols)
    1753             :     {
    1754           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    1755             :                  "For scanline access, block width cannot be lesser than the "
    1756             :                  "number of columns.");
    1757           0 :         return BLKREAD_FAIL;
    1758             :     }
    1759             : 
    1760       16551 :     if (!EQUAL(psImage->szIC, "NC"))
    1761             :     {
    1762           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    1763             :                  "Scanline access not supported on compressed NITF files.");
    1764           0 :         return BLKREAD_FAIL;
    1765             :     }
    1766             : 
    1767             :     /* -------------------------------------------------------------------- */
    1768             :     /*      Workout location and size of data in file.                      */
    1769             :     /* -------------------------------------------------------------------- */
    1770       16551 :     nLineOffsetInFile = psImage->panBlockStart[0] +
    1771       16551 :                         psImage->nLineOffset * nLine +
    1772       16551 :                         psImage->nBandOffset * (nBand - 1);
    1773             : 
    1774       16551 :     nLineSize = (size_t)psImage->nPixelOffset * (psImage->nBlockWidth - 1) +
    1775       16551 :                 psImage->nWordSize;
    1776             : 
    1777       16551 :     if (nLineSize == 0 || psImage->nWordSize * 8 != psImage->nBitsPerSample)
    1778           7 :         nLineSize = (psImage->nBlockWidth * psImage->nBitsPerSample + 7) / 8;
    1779             : 
    1780       16551 :     if (VSIFSeekL(psImage->psFile->fp, nLineOffsetInFile, SEEK_SET) != 0)
    1781           0 :         return BLKREAD_FAIL;
    1782             : 
    1783             :     /* -------------------------------------------------------------------- */
    1784             :     /*      Can we do a direct read into our buffer.                        */
    1785             :     /* -------------------------------------------------------------------- */
    1786       16551 :     if ((psImage->nBitsPerSample % 8) != 0 ||
    1787       16544 :         ((size_t)psImage->nWordSize == psImage->nPixelOffset &&
    1788       16469 :          (size_t)(psImage->nWordSize * psImage->nBlockWidth) ==
    1789       16469 :              psImage->nLineOffset))
    1790             :     {
    1791       16476 :         if (VSIFReadL(pData, 1, nLineSize, psImage->psFile->fp) != nLineSize)
    1792             :         {
    1793           0 :             CPLError(CE_Failure, CPLE_FileIO,
    1794             :                      "Unable to read %d bytes for line %d.", (int)nLineSize,
    1795             :                      nLine);
    1796           0 :             return BLKREAD_FAIL;
    1797             :         }
    1798             : 
    1799             : #ifdef CPL_LSB
    1800       16476 :         NITFSwapWords(psImage, pData, psImage->nBlockWidth);
    1801             : #endif
    1802             : 
    1803       16476 :         return BLKREAD_OK;
    1804             :     }
    1805             : 
    1806             :     /* -------------------------------------------------------------------- */
    1807             :     /*      Allocate a buffer for all the interleaved data, and read        */
    1808             :     /*      it.                                                             */
    1809             :     /* -------------------------------------------------------------------- */
    1810          75 :     pabyLineBuf = (unsigned char *)VSI_MALLOC_VERBOSE(nLineSize);
    1811          75 :     if (pabyLineBuf == NULL)
    1812             :     {
    1813           0 :         return BLKREAD_FAIL;
    1814             :     }
    1815             : 
    1816          75 :     if (VSIFReadL(pabyLineBuf, 1, nLineSize, psImage->psFile->fp) != nLineSize)
    1817             :     {
    1818           0 :         CPLError(CE_Failure, CPLE_FileIO,
    1819             :                  "Unable to read %d bytes for line %d.", (int)nLineSize, nLine);
    1820           0 :         CPLFree(pabyLineBuf);
    1821           0 :         return BLKREAD_FAIL;
    1822             :     }
    1823             : 
    1824             :     /* -------------------------------------------------------------------- */
    1825             :     /*      Copy the desired data out of the interleaved buffer.            */
    1826             :     /* -------------------------------------------------------------------- */
    1827             :     {
    1828             :         GByte *pabySrc, *pabyDst;
    1829             :         int iPixel;
    1830             : 
    1831          75 :         pabySrc = pabyLineBuf;
    1832          75 :         pabyDst = ((GByte *)pData);
    1833             : 
    1834       19275 :         for (iPixel = 0; iPixel < psImage->nBlockWidth; iPixel++)
    1835             :         {
    1836       19200 :             memcpy(pabyDst + iPixel * psImage->nWordSize,
    1837       19200 :                    pabySrc + iPixel * psImage->nPixelOffset,
    1838       19200 :                    psImage->nWordSize);
    1839             :         }
    1840             : 
    1841             : #ifdef CPL_LSB
    1842          75 :         NITFSwapWords(psImage, pabyDst, psImage->nBlockWidth);
    1843             : #endif
    1844             :     }
    1845             : 
    1846          75 :     CPLFree(pabyLineBuf);
    1847             : 
    1848          75 :     return BLKREAD_OK;
    1849             : }
    1850             : 
    1851             : /************************************************************************/
    1852             : /*                         NITFWriteImageLine()                         */
    1853             : /************************************************************************/
    1854             : 
    1855       16881 : int NITFWriteImageLine(NITFImage *psImage, int nLine, int nBand, void *pData)
    1856             : 
    1857             : {
    1858             :     GUIntBig nLineOffsetInFile;
    1859             :     size_t nLineSize;
    1860             :     unsigned char *pabyLineBuf;
    1861             : 
    1862       16881 :     if (nBand == 0)
    1863           0 :         return BLKREAD_FAIL;
    1864             : 
    1865       16881 :     if (psImage->nBlocksPerRow != 1 || psImage->nBlocksPerColumn != 1)
    1866             :     {
    1867           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    1868             :                  "Scanline access not supported on tiled NITF files.");
    1869           0 :         return BLKREAD_FAIL;
    1870             :     }
    1871             : 
    1872       16881 :     if (psImage->nBlockWidth < psImage->nCols)
    1873             :     {
    1874           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    1875             :                  "For scanline access, block width cannot be lesser than the "
    1876             :                  "number of columns.");
    1877           0 :         return BLKREAD_FAIL;
    1878             :     }
    1879             : 
    1880       16881 :     if (!EQUAL(psImage->szIC, "NC"))
    1881             :     {
    1882           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    1883             :                  "Scanline access not supported on compressed NITF files.");
    1884           0 :         return BLKREAD_FAIL;
    1885             :     }
    1886             : 
    1887             :     /* -------------------------------------------------------------------- */
    1888             :     /*      Workout location and size of data in file.                      */
    1889             :     /* -------------------------------------------------------------------- */
    1890       16881 :     nLineOffsetInFile = psImage->panBlockStart[0] +
    1891       16881 :                         psImage->nLineOffset * nLine +
    1892       16881 :                         psImage->nBandOffset * (nBand - 1);
    1893             : 
    1894       16881 :     nLineSize = (size_t)psImage->nPixelOffset * (psImage->nBlockWidth - 1) +
    1895       16881 :                 psImage->nWordSize;
    1896             : 
    1897       16881 :     if (VSIFSeekL(psImage->psFile->fp, nLineOffsetInFile, SEEK_SET) != 0)
    1898             :     {
    1899           0 :         CPLError(CE_Failure, CPLE_FileIO, "I/O error");
    1900           0 :         return BLKREAD_FAIL;
    1901             :     }
    1902             : 
    1903             :     /* -------------------------------------------------------------------- */
    1904             :     /*      Can we do a direct write into our buffer.                       */
    1905             :     /* -------------------------------------------------------------------- */
    1906       16881 :     if ((size_t)psImage->nWordSize == psImage->nPixelOffset &&
    1907       16806 :         (size_t)(psImage->nWordSize * psImage->nBlockWidth) ==
    1908       16806 :             psImage->nLineOffset)
    1909             :     {
    1910             : #ifdef CPL_LSB
    1911       16806 :         NITFSwapWords(psImage, pData, psImage->nBlockWidth);
    1912             : #endif
    1913             : 
    1914       16806 :         if (VSIFWriteL(pData, 1, nLineSize, psImage->psFile->fp) != nLineSize)
    1915             :         {
    1916           0 :             CPLError(CE_Failure, CPLE_FileIO, "I/O error");
    1917           0 :             return BLKREAD_FAIL;
    1918             :         }
    1919             : 
    1920             : #ifdef CPL_LSB
    1921       16806 :         NITFSwapWords(psImage, pData, psImage->nBlockWidth);
    1922             : #endif
    1923             : 
    1924       16806 :         return BLKREAD_OK;
    1925             :     }
    1926             : 
    1927             :     /* -------------------------------------------------------------------- */
    1928             :     /*      Allocate a buffer for all the interleaved data, and read        */
    1929             :     /*      it.                                                             */
    1930             :     /* -------------------------------------------------------------------- */
    1931          75 :     pabyLineBuf = (unsigned char *)VSI_MALLOC_VERBOSE(nLineSize);
    1932          75 :     if (pabyLineBuf == NULL)
    1933             :     {
    1934           0 :         return BLKREAD_FAIL;
    1935             :     }
    1936             : 
    1937          75 :     if (VSIFReadL(pabyLineBuf, 1, nLineSize, psImage->psFile->fp) != nLineSize)
    1938             :     {
    1939           0 :         memset(pabyLineBuf, 0, nLineSize);
    1940             :     }
    1941             : 
    1942             :     /* -------------------------------------------------------------------- */
    1943             :     /*      Copy the desired data into the interleaved buffer.              */
    1944             :     /* -------------------------------------------------------------------- */
    1945             :     {
    1946             :         GByte *pabySrc, *pabyDst;
    1947             :         int iPixel;
    1948             : 
    1949          75 :         pabyDst = pabyLineBuf;
    1950          75 :         pabySrc = ((GByte *)pData);
    1951             : 
    1952             : #ifdef CPL_LSB
    1953          75 :         NITFSwapWords(psImage, pData, psImage->nBlockWidth);
    1954             : #endif
    1955             : 
    1956       19275 :         for (iPixel = 0; iPixel < psImage->nBlockWidth; iPixel++)
    1957             :         {
    1958       19200 :             memcpy(pabyDst + iPixel * psImage->nPixelOffset,
    1959       19200 :                    pabySrc + iPixel * psImage->nWordSize, psImage->nWordSize);
    1960             :         }
    1961             : 
    1962             : #ifdef CPL_LSB
    1963          75 :         NITFSwapWords(psImage, pData, psImage->nBlockWidth);
    1964             : #endif
    1965             :     }
    1966             : 
    1967             :     /* -------------------------------------------------------------------- */
    1968             :     /*      Write the results back out.                                     */
    1969             :     /* -------------------------------------------------------------------- */
    1970         150 :     if (VSIFSeekL(psImage->psFile->fp, nLineOffsetInFile, SEEK_SET) != 0 ||
    1971          75 :         VSIFWriteL(pabyLineBuf, 1, nLineSize, psImage->psFile->fp) != nLineSize)
    1972             :     {
    1973           0 :         CPLFree(pabyLineBuf);
    1974           0 :         CPLError(CE_Failure, CPLE_FileIO, "I/O error");
    1975           0 :         return BLKREAD_FAIL;
    1976             :     }
    1977          75 :     CPLFree(pabyLineBuf);
    1978             : 
    1979          75 :     return BLKREAD_OK;
    1980             : }
    1981             : 
    1982             : /************************************************************************/
    1983             : /*                          NITFEncodeDMSLoc()                          */
    1984             : /************************************************************************/
    1985             : 
    1986         808 : static void NITFEncodeDMSLoc(char *pszTarget, size_t nTargetLen, double dfValue,
    1987             :                              const char *pszAxis)
    1988             : 
    1989             : {
    1990             :     char chHemisphere;
    1991             :     int nDegrees, nMinutes, nSeconds;
    1992             : 
    1993         808 :     if (EQUAL(pszAxis, "Lat"))
    1994             :     {
    1995         404 :         if (dfValue < 0.0)
    1996          70 :             chHemisphere = 'S';
    1997             :         else
    1998         334 :             chHemisphere = 'N';
    1999             :     }
    2000             :     else
    2001             :     {
    2002         404 :         if (dfValue < 0.0)
    2003         204 :             chHemisphere = 'W';
    2004             :         else
    2005         200 :             chHemisphere = 'E';
    2006             :     }
    2007             : 
    2008         808 :     dfValue = fabs(dfValue);
    2009             : 
    2010         808 :     nDegrees = (int)dfValue;
    2011         808 :     dfValue = (dfValue - nDegrees) * 60.0;
    2012             : 
    2013         808 :     nMinutes = (int)dfValue;
    2014         808 :     dfValue = (dfValue - nMinutes) * 60.0;
    2015             : 
    2016             :     /* -------------------------------------------------------------------- */
    2017             :     /*      Do careful rounding on seconds so that 59.9->60 is properly     */
    2018             :     /*      rolled into minutes and degrees.                                */
    2019             :     /* -------------------------------------------------------------------- */
    2020         808 :     nSeconds = (int)(dfValue + 0.5);
    2021         808 :     if (nSeconds == 60)
    2022             :     {
    2023         161 :         nSeconds = 0;
    2024         161 :         nMinutes += 1;
    2025         161 :         if (nMinutes == 60)
    2026             :         {
    2027           7 :             nMinutes = 0;
    2028           7 :             nDegrees += 1;
    2029             :         }
    2030             :     }
    2031             : 
    2032         808 :     if (EQUAL(pszAxis, "Lat"))
    2033         404 :         snprintf(pszTarget, nTargetLen, "%02d%02d%02d%c", nDegrees, nMinutes,
    2034             :                  nSeconds, chHemisphere);
    2035             :     else
    2036         404 :         snprintf(pszTarget, nTargetLen, "%03d%02d%02d%c", nDegrees, nMinutes,
    2037             :                  nSeconds, chHemisphere);
    2038         808 : }
    2039             : 
    2040             : /************************************************************************/
    2041             : /*                          NITFWriteIGEOLO()                           */
    2042             : /************************************************************************/
    2043             : 
    2044             : /* Check that easting can be represented as a 6 character string */
    2045             : #define CHECK_IGEOLO_UTM_X(name, x)                                            \
    2046             :     if ((int)floor((x) + 0.5) <= -100000 || (int)floor((x) + 0.5) >= 1000000)  \
    2047             :     {                                                                          \
    2048             :         CPLError(CE_Failure, CPLE_AppDefined,                                  \
    2049             :                  "Attempt to write UTM easting %s=%d which is outside of "     \
    2050             :                  "valid range.",                                               \
    2051             :                  name, (int)floor((x) + 0.5));                                 \
    2052             :         return FALSE;                                                          \
    2053             :     }
    2054             : 
    2055             : /* Check that northing can be represented as a 7 character string */
    2056             : #define CHECK_IGEOLO_UTM_Y(name, y)                                            \
    2057             :     if ((int)floor((y) + 0.5) <= -1000000 ||                                   \
    2058             :         (int)floor((y) + 0.5) >= 10000000)                                     \
    2059             :     {                                                                          \
    2060             :         CPLError(CE_Failure, CPLE_AppDefined,                                  \
    2061             :                  "Attempt to write UTM northing %s=%d which is outside of "    \
    2062             :                  "valid range.",                                               \
    2063             :                  name, (int)floor((y) + 0.5));                                 \
    2064             :         return FALSE;                                                          \
    2065             :     }
    2066             : 
    2067         144 : int NITFWriteIGEOLO(NITFImage *psImage, char chICORDS, int nZone, double dfULX,
    2068             :                     double dfULY, double dfURX, double dfURY, double dfLRX,
    2069             :                     double dfLRY, double dfLLX, double dfLLY)
    2070             : 
    2071             : {
    2072             :     char szIGEOLO[61];
    2073             : 
    2074             :     /* -------------------------------------------------------------------- */
    2075             :     /*      Do some checking.                                               */
    2076             :     /* -------------------------------------------------------------------- */
    2077         144 :     if (psImage->chICORDS == ' ')
    2078             :     {
    2079          19 :         CPLError(CE_Failure, CPLE_NotSupported,
    2080             :                  "Apparently no space reserved for IGEOLO info in NITF file.\n"
    2081             :                  "NITFWriteIGEOGLO() fails.");
    2082          19 :         return FALSE;
    2083             :     }
    2084             : 
    2085         125 :     if (EQUAL(psImage->psFile->szVersion, "NITF02.00"))
    2086             :     {
    2087          33 :         if (chICORDS == 'U')
    2088             :         {
    2089             :             // Could be done, but we don't need UTM for CADRG support
    2090           0 :             CPLError(CE_Failure, CPLE_NotSupported,
    2091             :                      "Writing UTM MGRS coordinates for NITF02.00 is not "
    2092             :                      "supported in this implementation.");
    2093           0 :             return FALSE;
    2094             :         }
    2095          33 :         else if (chICORDS != 'G' && chICORDS != 'D')
    2096             :         {
    2097           0 :             CPLError(CE_Failure, CPLE_NotSupported,
    2098             :                      "Invalid ICOORDS value (%c) for NITFWriteIGEOLO().",
    2099             :                      chICORDS);
    2100           0 :             return FALSE;
    2101             :         }
    2102             :     }
    2103             :     else
    2104             :     {
    2105          92 :         if (chICORDS != 'G' && chICORDS != 'N' && chICORDS != 'S' &&
    2106             :             chICORDS != 'D')
    2107             :         {
    2108           0 :             CPLError(CE_Failure, CPLE_NotSupported,
    2109             :                      "Invalid ICOORDS value (%c) for NITFWriteIGEOLO().",
    2110             :                      chICORDS);
    2111           0 :             return FALSE;
    2112             :         }
    2113             :     }
    2114             : 
    2115         125 :     if (chICORDS == 'G' || chICORDS == 'D')
    2116             :     {
    2117         104 :         if (fabs(dfULX) <= 180 && fabs(dfLLX) <= 180 && dfURX > 180 &&
    2118             :             dfLRX > 180)
    2119             :         {
    2120           0 :             dfURX -= 360;
    2121           0 :             dfLRX -= 360;
    2122             :         }
    2123         104 :         else if (dfULX < -180 && dfLLX < -180 && fabs(dfURX) <= 180 &&
    2124           0 :                  fabs(dfLRX) <= 180)
    2125             :         {
    2126           0 :             dfULX += 360;
    2127           0 :             dfLLX += 360;
    2128             :         }
    2129             : 
    2130         104 :         if (fabs(dfULX) > 180 || fabs(dfURX) > 180 || fabs(dfLRX) > 180 ||
    2131         104 :             fabs(dfLLX) > 180 || fabs(dfULY) > 90 || fabs(dfURY) > 90 ||
    2132         104 :             fabs(dfLRY) > 90 || fabs(dfLLY) > 90)
    2133             :         {
    2134           0 :             CPLError(
    2135             :                 CE_Failure, CPLE_AppDefined,
    2136             :                 "Attempt to write geographic bound outside of legal range.");
    2137           0 :             return FALSE;
    2138             :         }
    2139             :     }
    2140             : 
    2141             :     /* -------------------------------------------------------------------- */
    2142             :     /*      Format geographic coordinates in DMS                            */
    2143             :     /* -------------------------------------------------------------------- */
    2144         125 :     if (chICORDS == 'G')
    2145             :     {
    2146         101 :         NITFEncodeDMSLoc(szIGEOLO + 0, sizeof(szIGEOLO) - 0, dfULY, "Lat");
    2147         101 :         NITFEncodeDMSLoc(szIGEOLO + 7, sizeof(szIGEOLO) - 7, dfULX, "Long");
    2148         101 :         NITFEncodeDMSLoc(szIGEOLO + 15, sizeof(szIGEOLO) - 15, dfURY, "Lat");
    2149         101 :         NITFEncodeDMSLoc(szIGEOLO + 22, sizeof(szIGEOLO) - 22, dfURX, "Long");
    2150         101 :         NITFEncodeDMSLoc(szIGEOLO + 30, sizeof(szIGEOLO) - 30, dfLRY, "Lat");
    2151         101 :         NITFEncodeDMSLoc(szIGEOLO + 37, sizeof(szIGEOLO) - 37, dfLRX, "Long");
    2152         101 :         NITFEncodeDMSLoc(szIGEOLO + 45, sizeof(szIGEOLO) - 45, dfLLY, "Lat");
    2153         101 :         NITFEncodeDMSLoc(szIGEOLO + 52, sizeof(szIGEOLO) - 52, dfLLX, "Long");
    2154             :     }
    2155             :     /* -------------------------------------------------------------------- */
    2156             :     /*      Format geographic coordinates in decimal degrees                */
    2157             :     /* -------------------------------------------------------------------- */
    2158          24 :     else if (chICORDS == 'D')
    2159             :     {
    2160           3 :         CPLsnprintf(szIGEOLO + 0, sizeof(szIGEOLO), "%+#07.3f%+#08.3f", dfULY,
    2161             :                     dfULX);
    2162           3 :         CPLsnprintf(szIGEOLO + 15, sizeof(szIGEOLO) - 15, "%+#07.3f%+#08.3f",
    2163             :                     dfURY, dfURX);
    2164           3 :         CPLsnprintf(szIGEOLO + 30, sizeof(szIGEOLO) - 30, "%+#07.3f%+#08.3f",
    2165             :                     dfLRY, dfLRX);
    2166           3 :         CPLsnprintf(szIGEOLO + 45, sizeof(szIGEOLO) - 45, "%+#07.3f%+#08.3f",
    2167             :                     dfLLY, dfLLX);
    2168             :     }
    2169             : 
    2170             :     /* -------------------------------------------------------------------- */
    2171             :     /*      Format UTM coordinates.                                         */
    2172             :     /* -------------------------------------------------------------------- */
    2173          21 :     else if (chICORDS == 'N' || chICORDS == 'S')
    2174             :     {
    2175          21 :         CHECK_IGEOLO_UTM_X("dfULX", dfULX);
    2176          21 :         CHECK_IGEOLO_UTM_Y("dfULY", dfULY);
    2177          21 :         CHECK_IGEOLO_UTM_X("dfURX", dfURX);
    2178          21 :         CHECK_IGEOLO_UTM_Y("dfURY", dfURY);
    2179          21 :         CHECK_IGEOLO_UTM_X("dfLRX", dfLRX);
    2180          21 :         CHECK_IGEOLO_UTM_Y("dfLRY", dfLRY);
    2181          21 :         CHECK_IGEOLO_UTM_X("dfLLX", dfLLX);
    2182          21 :         CHECK_IGEOLO_UTM_Y("dfLLY", dfLLY);
    2183          21 :         CPLsnprintf(szIGEOLO + 0, sizeof(szIGEOLO), "%02d%06d%07d", nZone,
    2184          21 :                     (int)floor(dfULX + 0.5), (int)floor(dfULY + 0.5));
    2185          21 :         CPLsnprintf(szIGEOLO + 15, sizeof(szIGEOLO) - 15, "%02d%06d%07d", nZone,
    2186          21 :                     (int)floor(dfURX + 0.5), (int)floor(dfURY + 0.5));
    2187          21 :         CPLsnprintf(szIGEOLO + 30, sizeof(szIGEOLO) - 30, "%02d%06d%07d", nZone,
    2188          21 :                     (int)floor(dfLRX + 0.5), (int)floor(dfLRY + 0.5));
    2189          21 :         CPLsnprintf(szIGEOLO + 45, sizeof(szIGEOLO) - 45, "%02d%06d%07d", nZone,
    2190          21 :                     (int)floor(dfLLX + 0.5), (int)floor(dfLLY + 0.5));
    2191             :     }
    2192             : 
    2193             :     /* -------------------------------------------------------------------- */
    2194             :     /*      Write IGEOLO data to disk.                                      */
    2195             :     /* -------------------------------------------------------------------- */
    2196         125 :     int nOffset = 372;
    2197         125 :     if (EQUAL(psImage->psFile->szVersion, "NITF02.00"))
    2198             :     {
    2199             :         // Read ISDWNG field;
    2200          33 :         char szISDWNG[6 + 1] = {0};
    2201          33 :         if (VSIFSeekL(psImage->psFile->fp,
    2202          33 :                       psImage->psFile->pasSegmentInfo[psImage->iSegment]
    2203          33 :                               .nSegmentHeaderStart +
    2204             :                           284,
    2205          33 :                       SEEK_SET) != 0 ||
    2206          33 :             VSIFReadL(szISDWNG, 1, 6, psImage->psFile->fp) != 6)
    2207             :         {
    2208           0 :             CPLError(CE_Failure, CPLE_AppDefined,
    2209             :                      "I/O Error writing IGEOLO segment.\n%s",
    2210           0 :                      VSIStrerror(errno));
    2211           0 :             return FALSE;
    2212             :         }
    2213          33 :         if (EQUAL(szISDWNG, "999998"))
    2214           1 :             nOffset += 40;
    2215             :     }
    2216         125 :     if (VSIFSeekL(psImage->psFile->fp,
    2217         125 :                   psImage->psFile->pasSegmentInfo[psImage->iSegment]
    2218         125 :                           .nSegmentHeaderStart +
    2219             :                       nOffset,
    2220         125 :                   SEEK_SET) == 0 &&
    2221         125 :         VSIFWriteL(szIGEOLO, 1, 60, psImage->psFile->fp) == 60)
    2222             :     {
    2223         125 :         return TRUE;
    2224             :     }
    2225             :     else
    2226             :     {
    2227           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    2228           0 :                  "I/O Error writing IGEOLO segment.\n%s", VSIStrerror(errno));
    2229           0 :         return FALSE;
    2230             :     }
    2231             : }
    2232             : 
    2233             : /************************************************************************/
    2234             : /*                            NITFWriteLUT()                            */
    2235             : /************************************************************************/
    2236             : 
    2237          34 : int NITFWriteLUT(NITFImage *psImage, int nBand, int nColors,
    2238             :                  unsigned char *pabyLUT)
    2239             : 
    2240             : {
    2241             :     NITFBandInfo *psBandInfo;
    2242          34 :     int bSuccess = TRUE;
    2243             : 
    2244          34 :     if (nBand < 1 || nBand > psImage->nBands)
    2245           0 :         return FALSE;
    2246             : 
    2247          34 :     psBandInfo = psImage->pasBandInfo + (nBand - 1);
    2248             : 
    2249          34 :     if (nColors > psBandInfo->nSignificantLUTEntries)
    2250             :     {
    2251           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    2252             :                  "Unable to write all %d LUT entries, only able to write %d.",
    2253             :                  nColors, psBandInfo->nSignificantLUTEntries);
    2254           0 :         nColors = psBandInfo->nSignificantLUTEntries;
    2255           0 :         bSuccess = FALSE;
    2256             :     }
    2257             : 
    2258          34 :     bSuccess &=
    2259          34 :         VSIFSeekL(psImage->psFile->fp, psBandInfo->nLUTLocation, SEEK_SET) == 0;
    2260          34 :     bSuccess &=
    2261          34 :         (int)VSIFWriteL(pabyLUT, 1, nColors, psImage->psFile->fp) == nColors;
    2262          34 :     bSuccess &=
    2263          34 :         VSIFSeekL(psImage->psFile->fp,
    2264          34 :                   psBandInfo->nLUTLocation + psBandInfo->nSignificantLUTEntries,
    2265          34 :                   SEEK_SET) == 0;
    2266          68 :     bSuccess &= (int)VSIFWriteL(pabyLUT + 256, 1, nColors,
    2267          34 :                                 psImage->psFile->fp) == nColors;
    2268          68 :     bSuccess &= VSIFSeekL(psImage->psFile->fp,
    2269          34 :                           psBandInfo->nLUTLocation +
    2270          34 :                               2 * psBandInfo->nSignificantLUTEntries,
    2271          34 :                           SEEK_SET) == 0;
    2272          68 :     bSuccess &= (int)VSIFWriteL(pabyLUT + 512, 1, nColors,
    2273          34 :                                 psImage->psFile->fp) == nColors;
    2274             : 
    2275          34 :     return bSuccess;
    2276             : }
    2277             : 
    2278             : /************************************************************************/
    2279             : /*                           NITFTrimWhite()                            */
    2280             : /*                                                                      */
    2281             : /*      Trim any white space off the white of the passed string in      */
    2282             : /*      place.                                                          */
    2283             : /************************************************************************/
    2284             : 
    2285      324357 : char *NITFTrimWhite(char *pszTarget)
    2286             : 
    2287             : {
    2288             :     int i;
    2289             : 
    2290      324357 :     i = (int)strlen(pszTarget) - 1;
    2291     1445920 :     while (i >= 0 && pszTarget[i] == ' ')
    2292     1121570 :         pszTarget[i--] = '\0';
    2293             : 
    2294      324357 :     return pszTarget;
    2295             : }
    2296             : 
    2297             : /************************************************************************/
    2298             : /*                           NITFSwapWords()                            */
    2299             : /************************************************************************/
    2300             : 
    2301             : #ifdef CPL_LSB
    2302             : 
    2303       53654 : static void NITFSwapWordsInternal(void *pData, int nWordSize, int nWordCount,
    2304             :                                   int nWordSkip)
    2305             : 
    2306             : {
    2307             :     int i;
    2308       53654 :     GByte *pabyData = (GByte *)pData;
    2309             : 
    2310       53654 :     switch (nWordSize)
    2311             :     {
    2312       52753 :         case 1:
    2313       52753 :             break;
    2314             : 
    2315         401 :         case 2:
    2316      126337 :             for (i = 0; i < nWordCount; i++)
    2317             :             {
    2318             :                 GByte byTemp;
    2319             : 
    2320      125936 :                 byTemp = pabyData[0];
    2321      125936 :                 pabyData[0] = pabyData[1];
    2322      125936 :                 pabyData[1] = byTemp;
    2323             : 
    2324      125936 :                 pabyData += nWordSkip;
    2325             :             }
    2326         401 :             break;
    2327             : 
    2328         420 :         case 4:
    2329       11420 :             for (i = 0; i < nWordCount; i++)
    2330             :             {
    2331             :                 GByte byTemp;
    2332             : 
    2333       11000 :                 byTemp = pabyData[0];
    2334       11000 :                 pabyData[0] = pabyData[3];
    2335       11000 :                 pabyData[3] = byTemp;
    2336             : 
    2337       11000 :                 byTemp = pabyData[1];
    2338       11000 :                 pabyData[1] = pabyData[2];
    2339       11000 :                 pabyData[2] = byTemp;
    2340             : 
    2341       11000 :                 pabyData += nWordSkip;
    2342             :             }
    2343         420 :             break;
    2344             : 
    2345          80 :         case 8:
    2346        1480 :             for (i = 0; i < nWordCount; i++)
    2347             :             {
    2348             :                 GByte byTemp;
    2349             : 
    2350        1400 :                 byTemp = pabyData[0];
    2351        1400 :                 pabyData[0] = pabyData[7];
    2352        1400 :                 pabyData[7] = byTemp;
    2353             : 
    2354        1400 :                 byTemp = pabyData[1];
    2355        1400 :                 pabyData[1] = pabyData[6];
    2356        1400 :                 pabyData[6] = byTemp;
    2357             : 
    2358        1400 :                 byTemp = pabyData[2];
    2359        1400 :                 pabyData[2] = pabyData[5];
    2360        1400 :                 pabyData[5] = byTemp;
    2361             : 
    2362        1400 :                 byTemp = pabyData[3];
    2363        1400 :                 pabyData[3] = pabyData[4];
    2364        1400 :                 pabyData[4] = byTemp;
    2365             : 
    2366        1400 :                 pabyData += nWordSkip;
    2367             :             }
    2368          80 :             break;
    2369             : 
    2370           0 :         default:
    2371           0 :             break;
    2372             :     }
    2373       53654 : }
    2374             : 
    2375             : /* Swap real or complex types */
    2376       53671 : static void NITFSwapWords(NITFImage *psImage, void *pData, int nWordCount)
    2377             : 
    2378             : {
    2379       53671 :     if (psImage->nWordSize * 8 != psImage->nBitsPerSample)
    2380             :     {
    2381             :         // FIXME ?
    2382          17 :         return;
    2383             :     }
    2384             : 
    2385       53654 :     if (EQUAL(psImage->szPVType, "C"))
    2386             :     {
    2387             :         /* According to
    2388             :          * http://jitc.fhu.disa.mil/nitf/tag_reg/imagesubheader/pvtype.html */
    2389             :         /* "C values shall be represented with the Real and Imaginary parts,
    2390             :          * each represented */
    2391             :         /* in IEEE 32 or 64-bit floating point representation (IEEE 754) and
    2392             :          * appearing in */
    2393             :         /* adjacent four or eight-byte blocks, first Real, then Imaginary" */
    2394          20 :         NITFSwapWordsInternal(pData, psImage->nWordSize / 2, 2 * nWordCount,
    2395          20 :                               psImage->nWordSize / 2);
    2396             :     }
    2397             :     else
    2398             :     {
    2399       53634 :         NITFSwapWordsInternal(pData, psImage->nWordSize, nWordCount,
    2400             :                               psImage->nWordSize);
    2401             :     }
    2402             : }
    2403             : 
    2404             : #endif /* def CPL_LSB */
    2405             : 
    2406             : /************************************************************************/
    2407             : /*                           NITFReadCSEXRA()                           */
    2408             : /*                                                                      */
    2409             : /*      Read a CSEXRA TRE and return contents as metadata strings.      */
    2410             : /************************************************************************/
    2411             : 
    2412           0 : char **NITFReadCSEXRA(NITFImage *psImage)
    2413             : 
    2414             : {
    2415           0 :     return NITFGenericMetadataRead(NULL, NULL, psImage, "CSEXRA");
    2416             : }
    2417             : 
    2418             : /************************************************************************/
    2419             : /*                           NITFReadPIAIMC()                           */
    2420             : /*                                                                      */
    2421             : /*      Read a PIAIMC TRE and return contents as metadata strings.      */
    2422             : /************************************************************************/
    2423             : 
    2424           0 : char **NITFReadPIAIMC(NITFImage *psImage)
    2425             : 
    2426             : {
    2427           0 :     return NITFGenericMetadataRead(NULL, NULL, psImage, "PIAIMC");
    2428             : }
    2429             : 
    2430             : /************************************************************************/
    2431             : /*                    NITFFormatRPC00BCoefficient()                     */
    2432             : /*                                                                      */
    2433             : /*      Format coefficients like +X.XXXXXXE+X (12 bytes)                */
    2434             : /************************************************************************/
    2435        1202 : static int NITFFormatRPC00BCoefficient(char *pszBuffer, double dfVal,
    2436             :                                        int *pbPrecisionLoss)
    2437             : {
    2438             :     // We need 12 bytes + 2=3-1 bytes for MSVC potentially outputting exponents
    2439             :     // with 3 digits + 1 terminating byte
    2440             :     char szTemp[12 + 2 + 1];
    2441             : #if defined(DEBUG) || defined(_WIN32)
    2442             :     int nLen;
    2443             : #endif
    2444             : 
    2445        1202 :     if (fabs(dfVal) > 9.999999e9)
    2446             :     {
    2447           1 :         CPLError(CE_Failure, CPLE_AppDefined, "Coefficient out of range: %g",
    2448             :                  dfVal);
    2449           1 :         return FALSE;
    2450             :     }
    2451             : 
    2452        1201 :     CPLsnprintf(szTemp, sizeof(szTemp), "%+.6E", dfVal);
    2453             : #if defined(DEBUG) || defined(_WIN32)
    2454        1201 :     nLen = (int)strlen(szTemp);
    2455        1201 :     CPL_IGNORE_RET_VAL_INT(nLen);
    2456             : #endif
    2457        1201 :     CPLAssert(szTemp[9] == 'E');
    2458             : #ifdef _WIN32
    2459             :     if (nLen == 14)  // Old MSVC versions: 3 digits for the exponent
    2460             :     {
    2461             :         if (szTemp[11] != DIGIT_ZERO || szTemp[12] != DIGIT_ZERO)
    2462             :         {
    2463             :             CPLError(CE_Warning, CPLE_AppDefined, "%g rounded to 0", dfVal);
    2464             :             snprintf(pszBuffer, 12 + 1, "%s", "+0.000000E+0");
    2465             :             if (pbPrecisionLoss)
    2466             :                 *pbPrecisionLoss = TRUE;
    2467             :             return TRUE;
    2468             :         }
    2469             :         szTemp[11] = szTemp[13];
    2470             :     }
    2471             :     else  // behavior of the standard: 2 digits for the exponent
    2472             : #endif
    2473             :     {
    2474        1201 :         CPLAssert(nLen == 13);
    2475        1201 :         if (szTemp[11] != DIGIT_ZERO)
    2476             :         {
    2477           2 :             CPLError(CE_Warning, CPLE_AppDefined, "%g rounded to 0", dfVal);
    2478           2 :             snprintf(pszBuffer, 12 + 1, "%s", "+0.000000E+0");
    2479           2 :             if (pbPrecisionLoss)
    2480           2 :                 *pbPrecisionLoss = TRUE;
    2481           2 :             return TRUE;
    2482             :         }
    2483        1199 :         szTemp[11] = szTemp[12];
    2484             :     }
    2485        1199 :     szTemp[12] = '\0';
    2486        1199 :     memcpy(pszBuffer, szTemp, strlen(szTemp) + 1);
    2487        1199 :     return TRUE;
    2488             : }
    2489             : 
    2490             : /************************************************************************/
    2491             : /*                   NITFFormatRPC00BFromMetadata()                     */
    2492             : /*                                                                      */
    2493             : /*      Format the content of a RPC00B TRE from RPC metadata            */
    2494             : /************************************************************************/
    2495             : 
    2496          26 : char *NITFFormatRPC00BFromMetadata(CSLConstList papszRPC, int *pbPrecisionLoss)
    2497             : {
    2498             :     GDALRPCInfoV2 sRPC;
    2499             :     char *pszRPC00B;
    2500             :     double dfErrBIAS;
    2501             :     double dfErrRAND;
    2502             :     int nOffset;
    2503             :     int nLength;
    2504             :     int nRounded;
    2505             :     int i;
    2506             :     char szTemp[24];
    2507             : 
    2508          26 :     if (pbPrecisionLoss)
    2509          26 :         *pbPrecisionLoss = FALSE;
    2510             : 
    2511          26 :     if (!GDALExtractRPCInfoV2(papszRPC, &sRPC))
    2512           0 :         return NULL;
    2513             : 
    2514          26 :     pszRPC00B = (char *)CPLMalloc(1041 + 1);
    2515          26 :     pszRPC00B[0] = '1'; /* success flag */
    2516          26 :     nOffset = 1;
    2517             : 
    2518          26 :     dfErrBIAS = sRPC.dfERR_BIAS;
    2519          26 :     if (dfErrBIAS == -1.0)  // value by default to indicate unknown
    2520             :     {
    2521           1 :         dfErrBIAS = 0.0;
    2522             :     }
    2523          25 :     else if (dfErrBIAS < 0)
    2524             :     {
    2525           0 :         CPLError(CE_Warning, CPLE_AppDefined,
    2526             :                  "Correcting ERR_BIAS from %f to 0", dfErrBIAS);
    2527             :     }
    2528          25 :     else if (dfErrBIAS > 9999.99)
    2529             :     {
    2530           0 :         CPLError(CE_Warning, CPLE_AppDefined,
    2531             :                  "ERR_BIAS out of range. Clamping to 9999.99");
    2532           0 :         dfErrBIAS = 9999.99;
    2533             :     }
    2534          26 :     nLength = 7;
    2535          26 :     CPLsnprintf(pszRPC00B + nOffset, nLength + 1, "%07.2f", dfErrBIAS);
    2536          26 :     nOffset += nLength;
    2537             : 
    2538          26 :     dfErrRAND = sRPC.dfERR_RAND;
    2539          26 :     if (dfErrRAND == -1.0)  // value by default to indicate unknown
    2540             :     {
    2541           1 :         dfErrRAND = 0.0;
    2542             :     }
    2543          25 :     else if (dfErrRAND < 0)
    2544             :     {
    2545           0 :         CPLError(CE_Warning, CPLE_AppDefined,
    2546             :                  "Correcting ERR_RAND from %f to 0", dfErrRAND);
    2547           0 :         if (pbPrecisionLoss)
    2548           0 :             *pbPrecisionLoss = TRUE;
    2549             :     }
    2550          25 :     else if (dfErrRAND > 9999.99)
    2551             :     {
    2552           0 :         CPLError(CE_Warning, CPLE_AppDefined,
    2553             :                  "ERR_RAND out of range. Clamping to 9999.99");
    2554           0 :         dfErrRAND = 9999.99;
    2555           0 :         if (pbPrecisionLoss)
    2556           0 :             *pbPrecisionLoss = TRUE;
    2557             :     }
    2558          26 :     nLength = 7;
    2559          26 :     CPLsnprintf(pszRPC00B + nOffset, nLength + 1, "%07.2f", dfErrRAND);
    2560          26 :     nOffset += nLength;
    2561             : 
    2562          26 :     nLength = 6;
    2563          26 :     if (sRPC.dfLINE_OFF < 0 || sRPC.dfLINE_OFF >= 1e6)
    2564             :     {
    2565           1 :         CPLError(CE_Failure, CPLE_AppDefined, "LINE_OFF out of range.");
    2566           1 :         CPLFree(pszRPC00B);
    2567           1 :         return NULL;
    2568             :     }
    2569          25 :     nRounded = (int)floor(sRPC.dfLINE_OFF + 0.5);
    2570          25 :     if (fabs(nRounded - sRPC.dfLINE_OFF) > 1e-2)
    2571             :     {
    2572           1 :         CPLError(CE_Warning, CPLE_AppDefined,
    2573             :                  "LINE_OFF was rounded from %f to %d", sRPC.dfLINE_OFF,
    2574             :                  nRounded);
    2575           1 :         if (pbPrecisionLoss)
    2576           1 :             *pbPrecisionLoss = TRUE;
    2577             :     }
    2578          25 :     CPLsnprintf(pszRPC00B + nOffset, nLength + 1, "%06d", nRounded);
    2579          25 :     nOffset += nLength;
    2580             : 
    2581          25 :     nLength = 5;
    2582          25 :     if (sRPC.dfSAMP_OFF < 0 || sRPC.dfSAMP_OFF >= 1e5)
    2583             :     {
    2584           1 :         CPLError(CE_Failure, CPLE_AppDefined, "SAMP_OFF out of range.");
    2585           1 :         CPLFree(pszRPC00B);
    2586           1 :         return NULL;
    2587             :     }
    2588          24 :     nRounded = (int)floor(sRPC.dfSAMP_OFF + 0.5);
    2589          24 :     if (fabs(nRounded - sRPC.dfSAMP_OFF) > 1e-2)
    2590             :     {
    2591           1 :         CPLError(CE_Warning, CPLE_AppDefined,
    2592             :                  "SAMP_OFF was rounded from %f to %d", sRPC.dfSAMP_OFF,
    2593             :                  nRounded);
    2594           1 :         if (pbPrecisionLoss)
    2595           1 :             *pbPrecisionLoss = TRUE;
    2596             :     }
    2597          24 :     CPLsnprintf(pszRPC00B + nOffset, nLength + 1, "%05d", nRounded);
    2598          24 :     nOffset += nLength;
    2599             : 
    2600          24 :     nLength = 8;
    2601          24 :     if (fabs(sRPC.dfLAT_OFF) > 90)
    2602             :     {
    2603           1 :         CPLError(CE_Failure, CPLE_AppDefined, "LAT_OFF out of range.");
    2604           1 :         CPLFree(pszRPC00B);
    2605           1 :         return NULL;
    2606             :     }
    2607          23 :     CPLsnprintf(pszRPC00B + nOffset, nLength + 1, "%+08.4f", sRPC.dfLAT_OFF);
    2608          23 :     if (fabs(sRPC.dfLAT_OFF -
    2609          23 :              CPLAtof(NITFGetField(szTemp, pszRPC00B, nOffset, nLength))) > 1e-8)
    2610             :     {
    2611           1 :         CPLError(CE_Warning, CPLE_AppDefined,
    2612             :                  "LAT_OFF was rounded from %f to %s", sRPC.dfLAT_OFF, szTemp);
    2613           1 :         if (pbPrecisionLoss)
    2614           1 :             *pbPrecisionLoss = TRUE;
    2615             :     }
    2616          23 :     nOffset += nLength;
    2617             : 
    2618          23 :     nLength = 9;
    2619          23 :     if (fabs(sRPC.dfLONG_OFF) > 180)
    2620             :     {
    2621           1 :         CPLError(CE_Failure, CPLE_AppDefined, "LONG_OFF out of range.");
    2622           1 :         CPLFree(pszRPC00B);
    2623           1 :         return NULL;
    2624             :     }
    2625          22 :     CPLsnprintf(pszRPC00B + nOffset, nLength + 1, "%+09.4f", sRPC.dfLONG_OFF);
    2626          22 :     if (fabs(sRPC.dfLONG_OFF -
    2627          22 :              CPLAtof(NITFGetField(szTemp, pszRPC00B, nOffset, nLength))) > 1e-8)
    2628             :     {
    2629           1 :         CPLError(CE_Warning, CPLE_AppDefined,
    2630             :                  "LONG_OFF was rounded from %f to %s", sRPC.dfLONG_OFF, szTemp);
    2631           1 :         if (pbPrecisionLoss)
    2632           1 :             *pbPrecisionLoss = TRUE;
    2633             :     }
    2634          22 :     nOffset += nLength;
    2635             : 
    2636          22 :     nLength = 5;
    2637          22 :     if (fabs(sRPC.dfHEIGHT_OFF) > 9999)
    2638             :     {
    2639           1 :         CPLError(CE_Failure, CPLE_AppDefined, "HEIGHT_OFF out of range.");
    2640           1 :         CPLFree(pszRPC00B);
    2641           1 :         return NULL;
    2642             :     }
    2643          21 :     nRounded = (int)floor(sRPC.dfHEIGHT_OFF + 0.5);
    2644          21 :     if (fabs(nRounded - sRPC.dfHEIGHT_OFF) > 1e-2)
    2645             :     {
    2646           1 :         CPLError(CE_Warning, CPLE_AppDefined,
    2647             :                  "HEIGHT_OFF was rounded from %f to %d", sRPC.dfHEIGHT_OFF,
    2648             :                  nRounded);
    2649           1 :         if (pbPrecisionLoss)
    2650           1 :             *pbPrecisionLoss = TRUE;
    2651             :     }
    2652          21 :     CPLsnprintf(pszRPC00B + nOffset, nLength + 1, "%+05d", nRounded);
    2653          21 :     nOffset += nLength;
    2654             : 
    2655          21 :     nLength = 6;
    2656          21 :     if (sRPC.dfLINE_SCALE < 1 || sRPC.dfLINE_SCALE >= 999999)
    2657             :     {
    2658           1 :         CPLError(CE_Failure, CPLE_AppDefined, "LINE_SCALE out of range.");
    2659           1 :         CPLFree(pszRPC00B);
    2660           1 :         return NULL;
    2661             :     }
    2662          20 :     nRounded = (int)floor(sRPC.dfLINE_SCALE + 0.5);
    2663          20 :     if (fabs(nRounded - sRPC.dfLINE_SCALE) > 1e-2)
    2664             :     {
    2665           1 :         CPLError(CE_Warning, CPLE_AppDefined,
    2666             :                  "LINE_SCALE was rounded from %f to %d", sRPC.dfLINE_SCALE,
    2667             :                  nRounded);
    2668           1 :         if (pbPrecisionLoss)
    2669           1 :             *pbPrecisionLoss = TRUE;
    2670             :     }
    2671          20 :     CPLsnprintf(pszRPC00B + nOffset, nLength + 1, "%06d", nRounded);
    2672          20 :     nOffset += nLength;
    2673             : 
    2674          20 :     nLength = 5;
    2675          20 :     if (sRPC.dfSAMP_SCALE < 1 || sRPC.dfSAMP_SCALE >= 99999)
    2676             :     {
    2677           1 :         CPLError(CE_Failure, CPLE_AppDefined, "SAMP_SCALE out of range.");
    2678           1 :         CPLFree(pszRPC00B);
    2679           1 :         return NULL;
    2680             :     }
    2681          19 :     nRounded = (int)floor(sRPC.dfSAMP_SCALE + 0.5);
    2682          19 :     if (fabs(nRounded - sRPC.dfSAMP_SCALE) > 1e-2)
    2683             :     {
    2684           1 :         CPLError(CE_Warning, CPLE_AppDefined,
    2685             :                  "SAMP_SCALE was rounded from %f to %d", sRPC.dfSAMP_SCALE,
    2686             :                  nRounded);
    2687           1 :         if (pbPrecisionLoss)
    2688           1 :             *pbPrecisionLoss = TRUE;
    2689             :     }
    2690          19 :     CPLsnprintf(pszRPC00B + nOffset, nLength + 1, "%05d", nRounded);
    2691          19 :     nOffset += nLength;
    2692             : 
    2693          19 :     nLength = 8;
    2694          19 :     if (fabs(sRPC.dfLAT_SCALE) > 90)
    2695             :     {
    2696           1 :         CPLError(CE_Failure, CPLE_AppDefined, "LAT_SCALE out of range.");
    2697           1 :         CPLFree(pszRPC00B);
    2698           1 :         return NULL;
    2699             :     }
    2700          18 :     CPLsnprintf(pszRPC00B + nOffset, nLength + 1, "%+08.4f", sRPC.dfLAT_SCALE);
    2701          18 :     if (fabs(sRPC.dfLAT_SCALE -
    2702          18 :              CPLAtof(NITFGetField(szTemp, pszRPC00B, nOffset, nLength))) > 1e-8)
    2703             :     {
    2704           1 :         CPLError(CE_Warning, CPLE_AppDefined,
    2705             :                  "LAT_SCALE was rounded from %f to %s", sRPC.dfLAT_SCALE,
    2706             :                  szTemp);
    2707           1 :         if (pbPrecisionLoss)
    2708           1 :             *pbPrecisionLoss = TRUE;
    2709             :     }
    2710          18 :     nOffset += nLength;
    2711             : 
    2712          18 :     nLength = 9;
    2713          18 :     if (fabs(sRPC.dfLONG_SCALE) > 180)
    2714             :     {
    2715           1 :         CPLError(CE_Failure, CPLE_AppDefined, "LONG_SCALE out of range.");
    2716           1 :         CPLFree(pszRPC00B);
    2717           1 :         return NULL;
    2718             :     }
    2719          17 :     CPLsnprintf(pszRPC00B + nOffset, nLength + 1, "%+09.4f", sRPC.dfLONG_SCALE);
    2720          17 :     if (fabs(sRPC.dfLONG_SCALE -
    2721          17 :              CPLAtof(NITFGetField(szTemp, pszRPC00B, nOffset, nLength))) > 1e-8)
    2722             :     {
    2723           1 :         CPLError(CE_Warning, CPLE_AppDefined,
    2724             :                  "LONG_SCALE was rounded from %f to %s", sRPC.dfLONG_SCALE,
    2725             :                  szTemp);
    2726           1 :         if (pbPrecisionLoss)
    2727           1 :             *pbPrecisionLoss = TRUE;
    2728             :     }
    2729          17 :     nOffset += nLength;
    2730             : 
    2731          17 :     nLength = 5;
    2732          17 :     if (fabs(sRPC.dfHEIGHT_SCALE) > 9999)
    2733             :     {
    2734           1 :         CPLError(CE_Failure, CPLE_AppDefined, "HEIGHT_SCALE out of range.");
    2735           1 :         CPLFree(pszRPC00B);
    2736           1 :         return NULL;
    2737             :     }
    2738          16 :     nRounded = (int)floor(sRPC.dfHEIGHT_SCALE + 0.5);
    2739          16 :     if (fabs(nRounded - sRPC.dfHEIGHT_SCALE) > 1e-2)
    2740             :     {
    2741           1 :         CPLError(CE_Warning, CPLE_AppDefined,
    2742             :                  "HEIGHT_SCALE was rounded from %f to %d", sRPC.dfHEIGHT_SCALE,
    2743             :                  nRounded);
    2744           1 :         if (pbPrecisionLoss)
    2745           1 :             *pbPrecisionLoss = TRUE;
    2746             :     }
    2747          16 :     CPLsnprintf(pszRPC00B + nOffset, nLength + 1, "%+05d", nRounded);
    2748          16 :     nOffset += nLength;
    2749             : 
    2750             :     /* -------------------------------------------------------------------- */
    2751             :     /*      Write coefficients.                                             */
    2752             :     /* -------------------------------------------------------------------- */
    2753         317 :     for (i = 0; i < 20; i++)
    2754             :     {
    2755         302 :         if (!NITFFormatRPC00BCoefficient(pszRPC00B + nOffset,
    2756             :                                          sRPC.adfLINE_NUM_COEFF[i],
    2757             :                                          pbPrecisionLoss))
    2758             :         {
    2759           1 :             CPLFree(pszRPC00B);
    2760           1 :             return NULL;
    2761             :         }
    2762         301 :         nOffset += 12;
    2763             :     }
    2764         315 :     for (i = 0; i < 20; i++)
    2765             :     {
    2766         300 :         if (!NITFFormatRPC00BCoefficient(pszRPC00B + nOffset,
    2767             :                                          sRPC.adfLINE_DEN_COEFF[i],
    2768             :                                          pbPrecisionLoss))
    2769             :         {
    2770           0 :             CPLFree(pszRPC00B);
    2771           0 :             return NULL;
    2772             :         }
    2773         300 :         nOffset += 12;
    2774             :     }
    2775         315 :     for (i = 0; i < 20; i++)
    2776             :     {
    2777         300 :         if (!NITFFormatRPC00BCoefficient(pszRPC00B + nOffset,
    2778             :                                          sRPC.adfSAMP_NUM_COEFF[i],
    2779             :                                          pbPrecisionLoss))
    2780             :         {
    2781           0 :             CPLFree(pszRPC00B);
    2782           0 :             return NULL;
    2783             :         }
    2784         300 :         nOffset += 12;
    2785             :     }
    2786         315 :     for (i = 0; i < 20; i++)
    2787             :     {
    2788         300 :         if (!NITFFormatRPC00BCoefficient(pszRPC00B + nOffset,
    2789             :                                          sRPC.adfSAMP_DEN_COEFF[i],
    2790             :                                          pbPrecisionLoss))
    2791             :         {
    2792           0 :             CPLFree(pszRPC00B);
    2793           0 :             return NULL;
    2794             :         }
    2795         300 :         nOffset += 12;
    2796             :     }
    2797             : 
    2798          15 :     CPLAssert(nOffset == 1041);
    2799          15 :     pszRPC00B[nOffset] = '\0';
    2800          15 :     CPLAssert(strlen(pszRPC00B) == 1041);
    2801          15 :     CPLAssert(strchr(pszRPC00B, ' ') == NULL);
    2802             : 
    2803          15 :     return pszRPC00B;
    2804             : }
    2805             : 
    2806             : /************************************************************************/
    2807             : /*                           NITFReadRPC00B()                           */
    2808             : /*                                                                      */
    2809             : /*      Read an RPC00A or RPC00B structure if the TRE is available.     */
    2810             : /*      RPC00A is remapped into RPC00B organization.                    */
    2811             : /************************************************************************/
    2812             : 
    2813         752 : int NITFReadRPC00B(NITFImage *psImage, NITFRPC00BInfo *psRPC)
    2814             : 
    2815             : {
    2816             :     const char *pachTRE;
    2817         752 :     int bIsRPC00A = FALSE;
    2818             :     int nTRESize;
    2819             : 
    2820         752 :     psRPC->SUCCESS = 0;
    2821             : 
    2822             :     /* -------------------------------------------------------------------- */
    2823             :     /*      Do we have the TRE?                                             */
    2824             :     /* -------------------------------------------------------------------- */
    2825             :     pachTRE =
    2826         752 :         NITFFindTRE(psImage->pachTRE, psImage->nTREBytes, "RPC00B", &nTRESize);
    2827             : 
    2828         752 :     if (pachTRE == NULL)
    2829             :     {
    2830         700 :         pachTRE = NITFFindTRE(psImage->pachTRE, psImage->nTREBytes, "RPC00A",
    2831             :                               &nTRESize);
    2832         700 :         if (pachTRE)
    2833           0 :             bIsRPC00A = TRUE;
    2834             :     }
    2835             : 
    2836         752 :     if (pachTRE == NULL)
    2837             :     {
    2838             :         /* No RPC00 tag. Check to see if we have the IMASDA and IMRFCA
    2839             :            tags (DPPDB data) before returning. */
    2840         700 :         return NITFReadIMRFCA(psImage, psRPC);
    2841             :     }
    2842             : 
    2843          52 :     if (nTRESize < 801 + 19 * 12 + 12)
    2844             :     {
    2845           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    2846             :                  "Cannot read RPC00A/RPC00B TRE. Not enough bytes");
    2847           0 :         return FALSE;
    2848             :     }
    2849             : 
    2850          52 :     return NITFDeserializeRPC00B((const GByte *)pachTRE, psRPC, bIsRPC00A);
    2851             : }
    2852             : 
    2853             : /************************************************************************/
    2854             : /*                       NITFDeserializeRPC00B()                        */
    2855             : /************************************************************************/
    2856             : 
    2857          52 : int NITFDeserializeRPC00B(const GByte *pabyTRE, NITFRPC00BInfo *psRPC,
    2858             :                           int bIsRPC00A)
    2859             : {
    2860          52 :     const char *pachTRE = (const char *)pabyTRE;
    2861             :     char szTemp[100];
    2862             :     int i;
    2863             :     static const int anRPC00AMap[] = /* See ticket #2040 */
    2864             :         {0, 1, 2, 3, 4, 5, 6, 10, 7, 8, 9, 11, 14, 17, 12, 15, 18, 13, 16, 19};
    2865             : 
    2866             :     /* -------------------------------------------------------------------- */
    2867             :     /*      Parse out field values.                                         */
    2868             :     /* -------------------------------------------------------------------- */
    2869          52 :     psRPC->SUCCESS = atoi(NITFGetField(szTemp, pachTRE, 0, 1));
    2870             : 
    2871          52 :     if (!psRPC->SUCCESS)
    2872             :     {
    2873           0 :         CPLError(CE_Warning, CPLE_AppDefined, "RPC Extension not Populated!");
    2874             :     }
    2875             : 
    2876          52 :     psRPC->ERR_BIAS = CPLAtof(NITFGetField(szTemp, pachTRE, 1, 7));
    2877          52 :     psRPC->ERR_RAND = CPLAtof(NITFGetField(szTemp, pachTRE, 8, 7));
    2878             : 
    2879          52 :     psRPC->LINE_OFF = CPLAtof(NITFGetField(szTemp, pachTRE, 15, 6));
    2880          52 :     psRPC->SAMP_OFF = CPLAtof(NITFGetField(szTemp, pachTRE, 21, 5));
    2881          52 :     psRPC->LAT_OFF = CPLAtof(NITFGetField(szTemp, pachTRE, 26, 8));
    2882          52 :     psRPC->LONG_OFF = CPLAtof(NITFGetField(szTemp, pachTRE, 34, 9));
    2883          52 :     psRPC->HEIGHT_OFF = CPLAtof(NITFGetField(szTemp, pachTRE, 43, 5));
    2884             : 
    2885          52 :     psRPC->LINE_SCALE = CPLAtof(NITFGetField(szTemp, pachTRE, 48, 6));
    2886          52 :     psRPC->SAMP_SCALE = CPLAtof(NITFGetField(szTemp, pachTRE, 54, 5));
    2887          52 :     psRPC->LAT_SCALE = CPLAtof(NITFGetField(szTemp, pachTRE, 59, 8));
    2888          52 :     psRPC->LONG_SCALE = CPLAtof(NITFGetField(szTemp, pachTRE, 67, 9));
    2889          52 :     psRPC->HEIGHT_SCALE = CPLAtof(NITFGetField(szTemp, pachTRE, 76, 5));
    2890             : 
    2891             :     /* -------------------------------------------------------------------- */
    2892             :     /*      Parse out coefficients.                                         */
    2893             :     /* -------------------------------------------------------------------- */
    2894        1092 :     for (i = 0; i < 20; i++)
    2895             :     {
    2896        1040 :         int iSrcCoef = i;
    2897             : 
    2898        1040 :         if (bIsRPC00A)
    2899           0 :             iSrcCoef = anRPC00AMap[i];
    2900             : 
    2901        1040 :         psRPC->LINE_NUM_COEFF[i] =
    2902        1040 :             CPLAtof(NITFGetField(szTemp, pachTRE, 81 + iSrcCoef * 12, 12));
    2903        1040 :         psRPC->LINE_DEN_COEFF[i] =
    2904        1040 :             CPLAtof(NITFGetField(szTemp, pachTRE, 321 + iSrcCoef * 12, 12));
    2905        1040 :         psRPC->SAMP_NUM_COEFF[i] =
    2906        1040 :             CPLAtof(NITFGetField(szTemp, pachTRE, 561 + iSrcCoef * 12, 12));
    2907        1040 :         psRPC->SAMP_DEN_COEFF[i] =
    2908        1040 :             CPLAtof(NITFGetField(szTemp, pachTRE, 801 + iSrcCoef * 12, 12));
    2909             :     }
    2910             : 
    2911          52 :     return TRUE;
    2912             : }
    2913             : 
    2914             : /************************************************************************/
    2915             : /*                           NITFReadICHIPB()                           */
    2916             : /*                                                                      */
    2917             : /*      Read an ICHIPB structure if the TRE is available.               */
    2918             : /************************************************************************/
    2919             : 
    2920         752 : int NITFReadICHIPB(NITFImage *psImage, NITFICHIPBInfo *psICHIP)
    2921             : 
    2922             : {
    2923             :     const char *pachTRE;
    2924             :     char szTemp[32];
    2925             :     int nTRESize;
    2926             : 
    2927             :     /* -------------------------------------------------------------------- */
    2928             :     /*      Do we have the TRE?                                             */
    2929             :     /* -------------------------------------------------------------------- */
    2930             :     pachTRE =
    2931         752 :         NITFFindTRE(psImage->pachTRE, psImage->nTREBytes, "ICHIPB", &nTRESize);
    2932             : 
    2933         752 :     if (pachTRE == NULL)
    2934             :     {
    2935         750 :         pachTRE = NITFFindTRE(psImage->pachTRE, psImage->nTREBytes, "ICHIPA",
    2936             :                               &nTRESize);
    2937             :     }
    2938             : 
    2939         752 :     if (pachTRE == NULL)
    2940             :     {
    2941         750 :         return FALSE;
    2942             :     }
    2943             : 
    2944           2 :     if (nTRESize < 2)
    2945             :     {
    2946           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    2947             :                  "Cannot read ICHIPA/ICHIPB TRE. Not enough bytes");
    2948           0 :         return FALSE;
    2949             :     }
    2950             :     /* -------------------------------------------------------------------- */
    2951             :     /*      Parse out field values.                                         */
    2952             :     /* -------------------------------------------------------------------- */
    2953           2 :     psICHIP->XFRM_FLAG = atoi(NITFGetField(szTemp, pachTRE, 0, 2));
    2954             : 
    2955           2 :     if (psICHIP->XFRM_FLAG == 0)
    2956             :     {
    2957           2 :         if (nTRESize < 216 + 8)
    2958             :         {
    2959           0 :             CPLError(CE_Failure, CPLE_AppDefined,
    2960             :                      "Cannot read ICHIPA/ICHIPB TRE. Not enough bytes");
    2961           0 :             return FALSE;
    2962             :         }
    2963             : 
    2964           2 :         psICHIP->SCALE_FACTOR = CPLAtof(NITFGetField(szTemp, pachTRE, 2, 10));
    2965           2 :         psICHIP->ANAMORPH_CORR = atoi(NITFGetField(szTemp, pachTRE, 12, 2));
    2966           2 :         psICHIP->SCANBLK_NUM = atoi(NITFGetField(szTemp, pachTRE, 14, 2));
    2967             : 
    2968           2 :         psICHIP->OP_ROW_11 = CPLAtof(NITFGetField(szTemp, pachTRE, 16, 12));
    2969           2 :         psICHIP->OP_COL_11 = CPLAtof(NITFGetField(szTemp, pachTRE, 28, 12));
    2970             : 
    2971           2 :         psICHIP->OP_ROW_12 = CPLAtof(NITFGetField(szTemp, pachTRE, 40, 12));
    2972           2 :         psICHIP->OP_COL_12 = CPLAtof(NITFGetField(szTemp, pachTRE, 52, 12));
    2973             : 
    2974           2 :         psICHIP->OP_ROW_21 = CPLAtof(NITFGetField(szTemp, pachTRE, 64, 12));
    2975           2 :         psICHIP->OP_COL_21 = CPLAtof(NITFGetField(szTemp, pachTRE, 76, 12));
    2976             : 
    2977           2 :         psICHIP->OP_ROW_22 = CPLAtof(NITFGetField(szTemp, pachTRE, 88, 12));
    2978           2 :         psICHIP->OP_COL_22 = CPLAtof(NITFGetField(szTemp, pachTRE, 100, 12));
    2979             : 
    2980           2 :         psICHIP->FI_ROW_11 = CPLAtof(NITFGetField(szTemp, pachTRE, 112, 12));
    2981           2 :         psICHIP->FI_COL_11 = CPLAtof(NITFGetField(szTemp, pachTRE, 124, 12));
    2982             : 
    2983           2 :         psICHIP->FI_ROW_12 = CPLAtof(NITFGetField(szTemp, pachTRE, 136, 12));
    2984           2 :         psICHIP->FI_COL_12 = CPLAtof(NITFGetField(szTemp, pachTRE, 148, 12));
    2985             : 
    2986           2 :         psICHIP->FI_ROW_21 = CPLAtof(NITFGetField(szTemp, pachTRE, 160, 12));
    2987           2 :         psICHIP->FI_COL_21 = CPLAtof(NITFGetField(szTemp, pachTRE, 172, 12));
    2988             : 
    2989           2 :         psICHIP->FI_ROW_22 = CPLAtof(NITFGetField(szTemp, pachTRE, 184, 12));
    2990           2 :         psICHIP->FI_COL_22 = CPLAtof(NITFGetField(szTemp, pachTRE, 196, 12));
    2991             : 
    2992           2 :         psICHIP->FI_ROW = atoi(NITFGetField(szTemp, pachTRE, 208, 8));
    2993           2 :         psICHIP->FI_COL = atoi(NITFGetField(szTemp, pachTRE, 216, 8));
    2994             :     }
    2995             :     else
    2996             :     {
    2997           0 :         CPLError(CE_Warning, CPLE_AppDefined, "Chip is already de-warped?");
    2998             :     }
    2999             : 
    3000           2 :     return TRUE;
    3001             : }
    3002             : 
    3003             : /************************************************************************/
    3004             : /*                           NITFReadUSE00A()                           */
    3005             : /*                                                                      */
    3006             : /*      Read a USE00A TRE and return contents as metadata strings.      */
    3007             : /************************************************************************/
    3008             : 
    3009           0 : char **NITFReadUSE00A(NITFImage *psImage)
    3010             : 
    3011             : {
    3012           0 :     return NITFGenericMetadataRead(NULL, NULL, psImage, "USE00A");
    3013             : }
    3014             : 
    3015             : /************************************************************************/
    3016             : /*                           NITFReadBLOCKA()                           */
    3017             : /*                                                                      */
    3018             : /*      Read a BLOCKA SDE and return contents as metadata strings.      */
    3019             : /************************************************************************/
    3020             : 
    3021         752 : char **NITFReadBLOCKA(NITFImage *psImage)
    3022             : 
    3023             : {
    3024             :     const char *pachTRE;
    3025             :     int nTRESize;
    3026         752 :     char **papszMD = NULL;
    3027         752 :     int nBlockaCount = 0;
    3028             :     char szTemp[128];
    3029             : 
    3030             :     while (TRUE)
    3031             :     {
    3032             :         /* --------------------------------------------------------------------
    3033             :          */
    3034             :         /*      Do we have the TRE? */
    3035             :         /* --------------------------------------------------------------------
    3036             :          */
    3037         775 :         pachTRE = NITFFindTREByIndex(psImage->pachTRE, psImage->nTREBytes,
    3038             :                                      "BLOCKA", nBlockaCount, &nTRESize);
    3039             : 
    3040         775 :         if (pachTRE == NULL)
    3041         749 :             break;
    3042             : 
    3043          26 :         if (nTRESize != 123)
    3044             :         {
    3045           3 :             CPLError(CE_Warning, CPLE_AppDefined,
    3046             :                      "BLOCKA TRE wrong size, ignoring.");
    3047           3 :             break;
    3048             :         }
    3049             : 
    3050          23 :         nBlockaCount++;
    3051             : 
    3052             :         /* --------------------------------------------------------------------
    3053             :          */
    3054             :         /*      Parse out field values. */
    3055             :         /* --------------------------------------------------------------------
    3056             :          */
    3057          23 :         snprintf(szTemp, sizeof(szTemp), "NITF_BLOCKA_BLOCK_INSTANCE_%02d",
    3058             :                  nBlockaCount);
    3059          23 :         NITFExtractMetadata(&papszMD, pachTRE, 0, 2, szTemp);
    3060          23 :         snprintf(szTemp, sizeof(szTemp), "NITF_BLOCKA_N_GRAY_%02d",
    3061             :                  nBlockaCount);
    3062          23 :         NITFExtractMetadata(&papszMD, pachTRE, 2, 5, szTemp);
    3063          23 :         snprintf(szTemp, sizeof(szTemp), "NITF_BLOCKA_L_LINES_%02d",
    3064             :                  nBlockaCount);
    3065          23 :         NITFExtractMetadata(&papszMD, pachTRE, 7, 5, szTemp);
    3066          23 :         snprintf(szTemp, sizeof(szTemp), "NITF_BLOCKA_LAYOVER_ANGLE_%02d",
    3067             :                  nBlockaCount);
    3068          23 :         NITFExtractMetadata(&papszMD, pachTRE, 12, 3, szTemp);
    3069          23 :         snprintf(szTemp, sizeof(szTemp), "NITF_BLOCKA_SHADOW_ANGLE_%02d",
    3070             :                  nBlockaCount);
    3071          23 :         NITFExtractMetadata(&papszMD, pachTRE, 15, 3, szTemp);
    3072             :         /* reserved: 16 */
    3073          23 :         snprintf(szTemp, sizeof(szTemp), "NITF_BLOCKA_FRLC_LOC_%02d",
    3074             :                  nBlockaCount);
    3075          23 :         NITFExtractMetadata(&papszMD, pachTRE, 34, 21, szTemp);
    3076          23 :         snprintf(szTemp, sizeof(szTemp), "NITF_BLOCKA_LRLC_LOC_%02d",
    3077             :                  nBlockaCount);
    3078          23 :         NITFExtractMetadata(&papszMD, pachTRE, 55, 21, szTemp);
    3079          23 :         snprintf(szTemp, sizeof(szTemp), "NITF_BLOCKA_LRFC_LOC_%02d",
    3080             :                  nBlockaCount);
    3081          23 :         NITFExtractMetadata(&papszMD, pachTRE, 76, 21, szTemp);
    3082          23 :         snprintf(szTemp, sizeof(szTemp), "NITF_BLOCKA_FRFC_LOC_%02d",
    3083             :                  nBlockaCount);
    3084          23 :         NITFExtractMetadata(&papszMD, pachTRE, 97, 21, szTemp);
    3085             :         /* reserved: 5 -> 97 + 21 + 5 = 123 -> OK */
    3086             :     }
    3087             : 
    3088         752 :     if (nBlockaCount > 0)
    3089             :     {
    3090          23 :         snprintf(szTemp, sizeof(szTemp), "%02d", nBlockaCount);
    3091          23 :         papszMD = CSLSetNameValue(papszMD, "NITF_BLOCKA_BLOCK_COUNT", szTemp);
    3092             :     }
    3093             : 
    3094         752 :     return papszMD;
    3095             : }
    3096             : 
    3097             : /************************************************************************/
    3098             : /*                           NITFGetGCP()                               */
    3099             : /*                                                                      */
    3100             : /* Reads a geographical coordinate (lat, long) from the provided        */
    3101             : /* buffer.                                                              */
    3102             : /************************************************************************/
    3103             : 
    3104           8 : void NITFGetGCP(const char *pachCoord, double *pdfXYs, int iCoord)
    3105             : {
    3106             :     char szTemp[128];
    3107             : 
    3108             :     // offset to selected coordinate.
    3109           8 :     pdfXYs += 2 * iCoord;
    3110             : 
    3111           8 :     if (pachCoord[0] == 'N' || pachCoord[0] == 'n' || pachCoord[0] == 'S' ||
    3112           8 :         pachCoord[0] == 's')
    3113             :     {
    3114             :         /* ------------------------------------------------------------ */
    3115             :         /*                             0....+....1....+....2            */
    3116             :         /* Coordinates are in the form Xddmmss.ssYdddmmss.ss:           */
    3117             :         /* The format Xddmmss.cc represents degrees (00 to 89), minutes */
    3118             :         /* (00 to 59), seconds (00 to 59), and hundredths of seconds    */
    3119             :         /* (00 to 99) of latitude, with X = N for north or S for south, */
    3120             :         /* and Ydddmmss.cc represents degrees (000 to 179), minutes     */
    3121             :         /* (00 to 59), seconds (00 to 59), and hundredths of seconds    */
    3122             :         /* (00 to 99) of longitude, with Y = E for east or W for west.  */
    3123             :         /* ------------------------------------------------------------ */
    3124             : 
    3125             :         // It is critical to do the fetching of the D, M, S components
    3126             :         // in 3 separate statements, otherwise if NITFGetField() is
    3127             :         // defined in this compilation unit, the MSVC optimizer will
    3128             :         // generate bad code, due to szTemp being overwritten before
    3129             :         // being evaluated by CPLAtof() !
    3130           0 :         pdfXYs[1] = CPLAtof(NITFGetField(szTemp, pachCoord, 1, 2));
    3131           0 :         pdfXYs[1] += CPLAtof(NITFGetField(szTemp, pachCoord, 3, 2)) / 60.0;
    3132           0 :         pdfXYs[1] += CPLAtof(NITFGetField(szTemp, pachCoord, 5, 5)) / 3600.0;
    3133             : 
    3134           0 :         if (pachCoord[0] == 's' || pachCoord[0] == 'S')
    3135           0 :             pdfXYs[1] *= -1;
    3136             : 
    3137             :         // It is critical to do the fetching of the D, M, S components
    3138             :         // in 3 separate statements, otherwise if NITFGetField() is
    3139             :         // defined in this compilation unit, the MSVC optimizer will
    3140             :         // generate bad code, due to szTemp being overwritten before
    3141             :         // being evaluated by CPLAtof() !
    3142           0 :         pdfXYs[0] = CPLAtof(NITFGetField(szTemp, pachCoord, 11, 3));
    3143           0 :         pdfXYs[0] += CPLAtof(NITFGetField(szTemp, pachCoord, 14, 2)) / 60.0;
    3144           0 :         pdfXYs[0] += CPLAtof(NITFGetField(szTemp, pachCoord, 16, 5)) / 3600.0;
    3145             : 
    3146           0 :         if (pachCoord[10] == 'w' || pachCoord[10] == 'W')
    3147           0 :             pdfXYs[0] *= -1;
    3148             :     }
    3149             :     else
    3150             :     {
    3151             :         /* ------------------------------------------------------------ */
    3152             :         /*                             0....+....1....+....2            */
    3153             :         /* Coordinates are in the form ±dd.dddddd±ddd.dddddd:           */
    3154             :         /* The format ±dd.dddddd indicates degrees of latitude (north   */
    3155             :         /* is positive), and ±ddd.dddddd represents degrees of          */
    3156             :         /* longitude (east is positive).                                */
    3157             :         /* ------------------------------------------------------------ */
    3158             : 
    3159           8 :         pdfXYs[1] = CPLAtof(NITFGetField(szTemp, pachCoord, 0, 10));
    3160           8 :         pdfXYs[0] = CPLAtof(NITFGetField(szTemp, pachCoord, 10, 11));
    3161             :     }
    3162           8 : }
    3163             : 
    3164             : /************************************************************************/
    3165             : /*                           NITFReadBLOCKA_GCPs()                      */
    3166             : /*                                                                      */
    3167             : /* The BLOCKA repeat earth coordinates image corner locations described */
    3168             : /* by IGEOLO in the NITF image subheader, but provide higher precision. */
    3169             : /************************************************************************/
    3170             : 
    3171        8755 : int NITFReadBLOCKA_GCPs(NITFImage *psImage)
    3172             : {
    3173             :     const char *pachTRE;
    3174             :     int nTRESize;
    3175             :     int nBlockaLines;
    3176             :     char szTemp[128];
    3177             : 
    3178             :     /* -------------------------------------------------------------------- */
    3179             :     /*      Do we have the TRE?                                             */
    3180             :     /* -------------------------------------------------------------------- */
    3181             :     pachTRE =
    3182        8755 :         NITFFindTRE(psImage->pachTRE, psImage->nTREBytes, "BLOCKA", &nTRESize);
    3183             : 
    3184        8755 :     if (pachTRE == NULL)
    3185        8729 :         return FALSE;
    3186             : 
    3187          26 :     if (nTRESize != 123)
    3188             :     {
    3189           3 :         return FALSE;
    3190             :     }
    3191             : 
    3192             :     /* -------------------------------------------------------------------- */
    3193             :     /*      Parse out field values.                                         */
    3194             :     /* -------------------------------------------------------------------- */
    3195             : 
    3196             :     /* ---------------------------------------------------------------- */
    3197             :     /* Make sure the BLOCKA geo coordinates are set. Spaces indicate    */
    3198             :     /* the value of a coordinate is unavailable or inapplicable.        */
    3199             :     /* ---------------------------------------------------------------- */
    3200          23 :     if (pachTRE[34] == ' ' || pachTRE[55] == ' ' || pachTRE[76] == ' ' ||
    3201          23 :         pachTRE[97] == ' ')
    3202             :     {
    3203           0 :         return FALSE;
    3204             :     }
    3205             : 
    3206             :     /* ---------------------------------------------------------------- */
    3207             :     /* Extract the L_LINES field of BLOCKA and see if this instance     */
    3208             :     /* covers the whole image. This is the case if L_LINES is equal to  */
    3209             :     /* the no of rows of this image.                                    */
    3210             :     /* We use the BLOCKA only in that case!                             */
    3211             :     /* ---------------------------------------------------------------- */
    3212          23 :     nBlockaLines = atoi(NITFGetField(szTemp, pachTRE, 7, 5));
    3213          23 :     if (psImage->nRows != nBlockaLines)
    3214             :     {
    3215          21 :         return FALSE;
    3216             :     }
    3217             : 
    3218             :     /* ---------------------------------------------------------------- */
    3219             :     /* Note that the order of these coordinates is different from       */
    3220             :     /* IGEOLO/NITFImage.                                                */
    3221             :     /*                   IGEOLO            BLOCKA                       */
    3222             :     /*                   0, 0              0, MaxCol                    */
    3223             :     /*                   0, MaxCol         MaxRow, MaxCol               */
    3224             :     /*                   MaxRow, MaxCol    MaxRow, 0                    */
    3225             :     /*                   MaxRow, 0         0, 0                         */
    3226             :     /* ---------------------------------------------------------------- */
    3227             :     {
    3228           2 :         double *pdfXYs = &(psImage->dfULX);
    3229             : 
    3230           2 :         NITFGetGCP(pachTRE + 34, pdfXYs, 1);
    3231           2 :         NITFGetGCP(pachTRE + 55, pdfXYs, 2);
    3232           2 :         NITFGetGCP(pachTRE + 76, pdfXYs, 3);
    3233           2 :         NITFGetGCP(pachTRE + 97, pdfXYs, 0);
    3234             : 
    3235           2 :         psImage->bIsBoxCenterOfPixel = TRUE;
    3236             :     }
    3237             : 
    3238             :     /* ---------------------------------------------------------------- */
    3239             :     /* Regardless of the former value of ICORDS, the values are now in  */
    3240             :     /* decimal degrees.                                                 */
    3241             :     /* ---------------------------------------------------------------- */
    3242             : 
    3243           2 :     psImage->chICORDS = 'D';
    3244             : 
    3245           2 :     return TRUE;
    3246             : }
    3247             : 
    3248             : /************************************************************************/
    3249             : /*                        NITFReadGEOLOB()                              */
    3250             : /*                                                                      */
    3251             : /*      The GEOLOB contains high precision lat/long geotransform        */
    3252             : /*      values.                                                         */
    3253             : /************************************************************************/
    3254             : 
    3255        8755 : static int NITFReadGEOLOB(NITFImage *psImage)
    3256             : {
    3257             :     const char *pachTRE;
    3258             :     int nTRESize;
    3259             :     char szTemp[128];
    3260             : 
    3261             :     /* -------------------------------------------------------------------- */
    3262             :     /*      Do we have the TRE?                                             */
    3263             :     /* -------------------------------------------------------------------- */
    3264             :     pachTRE =
    3265        8755 :         NITFFindTRE(psImage->pachTRE, psImage->nTREBytes, "GEOLOB", &nTRESize);
    3266             : 
    3267        8755 :     if (pachTRE == NULL)
    3268        8737 :         return FALSE;
    3269             : 
    3270          18 :     if (!CPLTestBoolean(CPLGetConfigOption("NITF_USEGEOLOB", "YES")))
    3271             :     {
    3272           0 :         CPLDebug("NITF", "GEOLOB available, but ignored by request.");
    3273           0 :         return FALSE;
    3274             :     }
    3275             : 
    3276          18 :     if (nTRESize != 48)
    3277             :     {
    3278           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    3279             :                  "Cannot read GEOLOB TRE. Wrong size.");
    3280           0 :         return FALSE;
    3281             :     }
    3282             : 
    3283             :     /* -------------------------------------------------------------------- */
    3284             :     /*      Parse out field values.                                         */
    3285             :     /* -------------------------------------------------------------------- */
    3286             :     {
    3287          18 :         double dfARV = atoi(NITFGetField(szTemp, pachTRE, 0, 9));
    3288          18 :         double dfBRV = atoi(NITFGetField(szTemp, pachTRE, 9, 9));
    3289             : 
    3290          18 :         double dfLSO = CPLAtof(NITFGetField(szTemp, pachTRE, 18, 15));
    3291          18 :         double dfPSO = CPLAtof(NITFGetField(szTemp, pachTRE, 33, 15));
    3292             : 
    3293          18 :         double dfPixelWidth = 360.0 / dfARV;
    3294          18 :         double dfPixelHeight = 360.0 / dfBRV;
    3295             : 
    3296          18 :         psImage->dfULX = dfLSO;
    3297          18 :         psImage->dfURX = psImage->dfULX + psImage->nCols * dfPixelWidth;
    3298          18 :         psImage->dfLLX = psImage->dfULX;
    3299          18 :         psImage->dfLRX = psImage->dfURX;
    3300             : 
    3301          18 :         psImage->dfULY = dfPSO;
    3302          18 :         psImage->dfURY = psImage->dfULY;
    3303          18 :         psImage->dfLLY = psImage->dfULY - psImage->nRows * dfPixelHeight;
    3304          18 :         psImage->dfLRY = psImage->dfLLY;
    3305             : 
    3306          18 :         psImage->bIsBoxCenterOfPixel = FALSE;  // GEOLOB is edge of pixel.
    3307          18 :         psImage->chICORDS = 'G';
    3308             : 
    3309          18 :         CPLDebug("NITF", "IGEOLO bounds overridden by GEOLOB TRE.");
    3310             :     }
    3311             : 
    3312          18 :     return TRUE;
    3313             : }
    3314             : 
    3315             : /************************************************************************/
    3316             : /*                      NITFLoadAttributeSection()                      */
    3317             : /*                                                                      */
    3318             : /*      Load metadata items from selected attributes in the RPF         */
    3319             : /*      attributes subsection.  The items are defined in                */
    3320             : /*      MIL-STD-2411-1 section 5.3.2.                                   */
    3321             : /************************************************************************/
    3322             : 
    3323             : // MIL-STD-2411-1 section 5.3.2.
    3324             : typedef enum
    3325             : {
    3326             :     RPFAttr_ASCII,
    3327             :     RPFAttr_UINT,
    3328             :     RPFAttr_REAL,
    3329             :     RPFAttr_VARIABLE
    3330             : } RPFAttributeType;
    3331             : 
    3332             : typedef struct
    3333             : {
    3334             :     int nAttrID;
    3335             :     const char *pszGDALMetadataItem;
    3336             :     int nParamID;
    3337             :     RPFAttributeType eType;
    3338             :     int nLength; /* bytes */
    3339             : } RPFAttribute;
    3340             : 
    3341             : static const RPFAttribute asRPFAttributes[] = {
    3342             :     {1, "CurrencyDate", 1, RPFAttr_ASCII, 8},
    3343             :     {2, "ProductionDate", 1, RPFAttr_ASCII, 8},
    3344             :     {3, "SignificantDate", 1, RPFAttr_ASCII, 8},
    3345             :     {4, "DataSeriesDesignation", 1, RPFAttr_ASCII, 10},
    3346             :     {4, "MapSeriesDesignation", 2, RPFAttr_ASCII, 8},
    3347             :     {4, "OldHorizontalDatumCode", 3, RPFAttr_ASCII, 4},
    3348             :     {4, "EditionIdentifier", 4, RPFAttr_ASCII, 7},
    3349             :     {5, "ProjectionCode", 1, RPFAttr_ASCII, 2},
    3350             :     {5, "ParameterA", 2, RPFAttr_REAL, 4},
    3351             :     {5, "ParameterB", 3, RPFAttr_REAL, 4},
    3352             :     {5, "ParameterC", 4, RPFAttr_REAL, 4},
    3353             :     {5, "ParameterD", 5, RPFAttr_REAL, 4},
    3354             :     {6, "VerticalDatumCode", 1, RPFAttr_ASCII, 4},
    3355             :     {7, "HorizontalDatumCode", 1, RPFAttr_ASCII, 4},  // not in CADRG
    3356             :     {8, "VerticalAbsoluteAccuracy", 1, RPFAttr_UINT, 4},
    3357             :     {8, "VerticalAbsoluteAccuracyUnits", 2, RPFAttr_UINT, 2},
    3358             :     {9, "HorizontalAbsoluteAccuracy", 1, RPFAttr_UINT, 4},
    3359             :     {9, "HorizontalAbsoluteAccuracyUnits", 2, RPFAttr_UINT, 2},
    3360             :     {10, "VerticalRelativeAccuracy", 1, RPFAttr_UINT, 4},
    3361             :     {10, "VerticalRelativeAccuracyUnits", 2, RPFAttr_UINT, 2},
    3362             :     {11, "HorizontalRelativeAccuracy", 1, RPFAttr_UINT, 4},
    3363             :     {11, "HorizontalRelativeAccuracyUnits", 2, RPFAttr_UINT, 2},
    3364             :     {12, "EllipsoidCode", 1, RPFAttr_ASCII, 3},
    3365             :     {13, "SoundingDatum", 1, RPFAttr_ASCII, 4},
    3366             :     {14, "NavigationSystemsCode", 1, RPFAttr_UINT, 2},
    3367             :     {15, "GridCode", 1, RPFAttr_ASCII, 2},
    3368             :     {16, "EasterlyAnnualMagneticChange", 1, RPFAttr_REAL, 4},
    3369             :     {16, "EasterlyAnnualMagneticChangeUnits", 2, RPFAttr_UINT, 2},
    3370             :     {17, "WesterlyAnnualMagneticChange", 1, RPFAttr_REAL, 4},
    3371             :     {17, "WesterlyAnnualMagneticChangeUnits", 2, RPFAttr_UINT, 2},
    3372             :     {18, "GridNorthMagneticAngle", 1, RPFAttr_REAL, 4},
    3373             :     {18, "GridNorthMagneticAngleUnits", 2, RPFAttr_UINT, 2},
    3374             :     {19, "GridConvergenceAngle", 1, RPFAttr_REAL, 4},
    3375             :     {19, "GridConvergenceAngleUnits", 2, RPFAttr_UINT, 2},
    3376             :     {20, "MaximumElevation", 1, RPFAttr_REAL, 8},
    3377             :     {20, "MaximumElevationUnits", 2, RPFAttr_UINT, 2},
    3378             :     {20, "MaximumElevationLatitude", 3, RPFAttr_REAL, 8},
    3379             :     {20, "MaximumElevationLongitude", 4, RPFAttr_REAL, 8},
    3380             :     {21, "LegendFileName", 1, RPFAttr_ASCII, 12},
    3381             :     {22, "DataSource", 1, RPFAttr_ASCII, 12},
    3382             :     {22, "GSD", 2, RPFAttr_UINT, 4},
    3383             :     {23, "DataLevel", 1, RPFAttr_UINT, 2},
    3384             :     // Following from MIL-PRF-89038_AMENDMENT-2.pdf
    3385             :     {24, "NumberOfUpdates", 1, RPFAttr_UINT, 2},
    3386             :     {24, "UpdateNumber", 2, RPFAttr_UINT, 2},
    3387             :     {24, "UpdateDate", 3, RPFAttr_ASCII, 8},
    3388             :     {24, "NumberOfSubframesImpacted", 4, RPFAttr_UINT, 2},
    3389             :     {24, "ListOfSubframes", 5, RPFAttr_VARIABLE, 0 /* variable */},
    3390             :     {24, "NumberOfCharactersInDescription", 6, RPFAttr_UINT, 2},
    3391             :     {24, "ChangeDescription", 7, RPFAttr_ASCII, 0},  // given by previous attr
    3392             :     {25, "ContourInterval", 1, RPFAttr_UINT, 2},
    3393             :     {25, "ContourIntervalUnits", 2, RPFAttr_UINT, 2},
    3394             : };
    3395             : 
    3396        8755 : static void NITFLoadAttributeSection(NITFImage *psImage)
    3397             : 
    3398             : {
    3399        8755 :     GUInt32 nASHOffset = 0, /* nASHSize=0, */ nASSOffset = 0, nASSSize = 0,
    3400        8755 :             nNextOffset = 0;
    3401             :     GInt16 nAttrCount;
    3402             :     GByte *pabyAttributeSubsection;
    3403             : 
    3404       10536 :     for (int i = 0; i < psImage->nLocCount; i++)
    3405             :     {
    3406        1781 :         if (psImage->pasLocations[i].nLocId == LID_AttributeSectionSubheader)
    3407             :         {
    3408         120 :             nASHOffset = psImage->pasLocations[i].nLocOffset;
    3409             :             /* nASHSize = psImage->pasLocations[i].nLocSize; */
    3410             :         }
    3411        1661 :         else if (psImage->pasLocations[i].nLocId == LID_AttributeSubsection)
    3412             :         {
    3413         120 :             nASSOffset = psImage->pasLocations[i].nLocOffset;
    3414         120 :             nASSSize = psImage->pasLocations[i].nLocSize;
    3415             :         }
    3416             :     }
    3417             : 
    3418        8755 :     if (nASSOffset == 0 || nASHOffset == 0)
    3419        8635 :         return;
    3420             : 
    3421             :     /* -------------------------------------------------------------------- */
    3422             :     /*      How many attribute records do we have?                          */
    3423             :     /* -------------------------------------------------------------------- */
    3424         240 :     if (VSIFSeekL(psImage->psFile->fp, nASHOffset, SEEK_SET) != 0 ||
    3425         120 :         VSIFReadL(&nAttrCount, 2, 1, psImage->psFile->fp) != 1)
    3426           0 :         return;
    3427             : 
    3428         120 :     CPL_MSBPTR16(&nAttrCount);
    3429             : 
    3430             :     /* -------------------------------------------------------------------- */
    3431             :     /*      nASSSize Hack                                                   */
    3432             :     /* -------------------------------------------------------------------- */
    3433             :     /* OK, now, as often with RPF/CADRG, here is the necessary dirty hack */
    3434             :     /* -- Begin of lengthy explanation -- */
    3435             :     /* A lot of CADRG files have a nASSSize value that reports a size */
    3436             :     /* smaller than the genuine size of the attribute subsection in the */
    3437             :     /* file, so if we trust the nASSSize value, we'll reject existing */
    3438             :     /* attributes. This is for example the case for */
    3439             :     /* http://download.osgeo.org/gdal/data/nitf/0000M033.GN3 */
    3440             :     /* where nASSSize is reported to be 302 bytes for 52 attributes (which */
    3441             :     /* is odd since 52 * 8 < 302), but a binary inspection of the attribute */
    3442             :     /* subsection shows that the actual size is 608 bytes, which is also
    3443             :      * confirmed*/
    3444             :     /* by the fact that the next subsection (quite often
    3445             :      * LID_ExplicitArealCoverageTable but not always) */
    3446             :     /* begins right after. So if this next subsection is found and that the */
    3447             :     /* difference in offset is larger than the original nASSSize, use it. */
    3448             :     /* I have observed that nowhere in the NITF driver we make use of the
    3449             :      * .nLocSize field */
    3450             :     /* -- End of lengthy explanation -- */
    3451             : 
    3452        1560 :     for (int i = 0; i < psImage->nLocCount; i++)
    3453             :     {
    3454        1440 :         if (psImage->pasLocations[i].nLocOffset > nASSOffset)
    3455             :         {
    3456           0 :             if (nNextOffset == 0 ||
    3457           0 :                 nNextOffset > psImage->pasLocations[i].nLocOffset)
    3458           0 :                 nNextOffset = psImage->pasLocations[i].nLocOffset;
    3459             :         }
    3460             :     }
    3461             : 
    3462         120 :     if (nNextOffset > 0 && nNextOffset - nASSOffset > nASSSize)
    3463           0 :         nASSSize = nNextOffset - nASSOffset;
    3464             : 
    3465             :     /* -------------------------------------------------------------------- */
    3466             :     /*      Be sure that the attribute subsection is large enough to        */
    3467             :     /*      hold the offset table (otherwise NITFFetchAttribute could       */
    3468             :     /*      read out of the buffer)                                         */
    3469             :     /* -------------------------------------------------------------------- */
    3470         120 :     if (nASSSize < (size_t)(8 * nAttrCount))
    3471             :     {
    3472           0 :         CPLError(CE_Warning, CPLE_AppDefined,
    3473             :                  "Attribute subsection not large enough (%d bytes) to contain "
    3474             :                  "%d attributes.",
    3475             :                  nASSSize, nAttrCount);
    3476           0 :         return;
    3477             :     }
    3478             : 
    3479             :     /* -------------------------------------------------------------------- */
    3480             :     /*      Load the attribute table.                                       */
    3481             :     /* -------------------------------------------------------------------- */
    3482         120 :     pabyAttributeSubsection = (GByte *)VSIMalloc(nASSSize);
    3483         120 :     if (pabyAttributeSubsection == NULL)
    3484             :     {
    3485           0 :         CPLError(
    3486             :             CE_Warning, CPLE_AppDefined,
    3487             :             "Out of memory failure reading %d bytes of attribute subsection.",
    3488             :             nASSSize);
    3489           0 :         return;
    3490             :     }
    3491             : 
    3492         120 :     if (VSIFSeekL(psImage->psFile->fp, nASSOffset, SEEK_SET) != 0 ||
    3493         120 :         VSIFReadL(pabyAttributeSubsection, 1, nASSSize, psImage->psFile->fp) !=
    3494             :             nASSSize)
    3495             :     {
    3496           0 :         CPLError(CE_Warning, CPLE_FileIO,
    3497             :                  "I/O error when reading attribute subsection.");
    3498           0 :         CPLFree(pabyAttributeSubsection);
    3499           0 :         return;
    3500             :     }
    3501             : 
    3502             :     /* -------------------------------------------------------------------- */
    3503             :     /*      Scan the attribute offset table                                 */
    3504             :     /* -------------------------------------------------------------------- */
    3505             :     GByte abyBuffer[12];  // max size is for LegendFileName
    3506         120 :     const int nRPFAttributeDictSize =
    3507             :         (int)(sizeof(asRPFAttributes) / sizeof(asRPFAttributes[0]));
    3508         120 :     const bool bShowAllAttributes =
    3509         120 :         CPLTestBoolean(CPLGetConfigOption("RPF_SHOW_ALL_ATTRIBUTES", "NO"));
    3510         612 :     for (int i = 0; i < nAttrCount; i++)
    3511             :     {
    3512         492 :         const GByte *pabyOffsetRec = pabyAttributeSubsection + i * 8;
    3513        7584 :         for (int iRPFAttrDict = 0; iRPFAttrDict < nRPFAttributeDictSize;
    3514        7092 :              iRPFAttrDict++)
    3515             :         {
    3516        7452 :             const RPFAttribute *psAttr = &(asRPFAttributes[iRPFAttrDict]);
    3517        7452 :             const int nAttrID = pabyOffsetRec[0] * 256 + pabyOffsetRec[1];
    3518        7452 :             const int nParamID = pabyOffsetRec[2];
    3519        7452 :             if (nAttrID == psAttr->nAttrID && nParamID == psAttr->nParamID &&
    3520             :                 // By default only shows the first three attributes.
    3521         132 :                 (nAttrID <= 3 || bShowAllAttributes))
    3522             :             {
    3523             :                 // const int nArealCoverageSeqNumber = pabyOffsetRec[3];
    3524             : 
    3525         360 :                 GUInt32 nAttrOffset = 0;
    3526         360 :                 memcpy(&nAttrOffset, pabyOffsetRec + 4, 4);
    3527         360 :                 CPL_MSBPTR32(&nAttrOffset);
    3528             : 
    3529         360 :                 const char *pszName = psAttr->pszGDALMetadataItem;
    3530         360 :                 const int nLength = psAttr->nLength;
    3531         360 :                 if (nLength != 0 && (GUInt32)nLength <= nASSSize &&
    3532         360 :                     nAttrOffset <= nASSSize - nLength)
    3533             :                 {
    3534         360 :                     memcpy(abyBuffer, pabyAttributeSubsection + nAttrOffset,
    3535             :                            nLength);
    3536         360 :                     if (psAttr->eType == RPFAttr_ASCII)
    3537             :                     {
    3538         360 :                         NITFExtractMetadata(&(psImage->papszMetadata),
    3539             :                                             (char *)abyBuffer, 0, nLength,
    3540             :                                             CPLSPrintf("NITF_RPF_%s", pszName));
    3541             :                     }
    3542           0 :                     else if (psAttr->eType == RPFAttr_UINT)
    3543             :                     {
    3544           0 :                         if (nLength == 2)
    3545             :                         {
    3546           0 :                             const uint16_t nVal =
    3547           0 :                                 abyBuffer[0] * 256 + abyBuffer[1];
    3548           0 :                             psImage->papszMetadata = CSLSetNameValue(
    3549             :                                 psImage->papszMetadata,
    3550             :                                 CPLSPrintf("NITF_RPF_%s", pszName),
    3551             :                                 CPLSPrintf("%d", nVal));
    3552             :                         }
    3553             :                         else
    3554             :                         {
    3555           0 :                             CPLAssert(nLength == 4);
    3556             :                             uint32_t nVal;
    3557           0 :                             memcpy(&nVal, abyBuffer, sizeof(nVal));
    3558           0 :                             CPL_MSBPTR32(&nVal);
    3559           0 :                             psImage->papszMetadata = CSLSetNameValue(
    3560             :                                 psImage->papszMetadata,
    3561             :                                 CPLSPrintf("NITF_RPF_%s", pszName),
    3562             :                                 CPLSPrintf("%u", nVal));
    3563             :                         }
    3564             :                     }
    3565             :                     else
    3566             :                     {
    3567           0 :                         CPLAssert(psAttr->eType == RPFAttr_REAL);
    3568           0 :                         if (nLength == 4)
    3569             :                         {
    3570             :                             float fVal;
    3571           0 :                             memcpy(&fVal, abyBuffer, sizeof(fVal));
    3572           0 :                             CPL_MSBPTR32(&fVal);
    3573           0 :                             psImage->papszMetadata = CSLSetNameValue(
    3574             :                                 psImage->papszMetadata,
    3575             :                                 CPLSPrintf("NITF_RPF_%s", pszName),
    3576             :                                 CPLSPrintf("%.8g", fVal));
    3577             :                         }
    3578             :                         else
    3579             :                         {
    3580           0 :                             CPLAssert(nLength == 8);
    3581             :                             double dfVal;
    3582           0 :                             memcpy(&dfVal, abyBuffer, sizeof(dfVal));
    3583           0 :                             CPL_MSBPTR64(&dfVal);
    3584           0 :                             psImage->papszMetadata = CSLSetNameValue(
    3585             :                                 psImage->papszMetadata,
    3586             :                                 CPLSPrintf("NITF_RPF_%s", pszName),
    3587             :                                 CPLSPrintf("%.17g", dfVal));
    3588             :                         }
    3589             :                     }
    3590             :                 }
    3591         360 :                 break;
    3592             :             }
    3593             :         }
    3594             :     }
    3595             : 
    3596         120 :     CPLFree(pabyAttributeSubsection);
    3597             : }
    3598             : 
    3599             : /************************************************************************/
    3600             : /*                     NITFLoadColormapSubSection()                     */
    3601             : /************************************************************************/
    3602             : 
    3603             : /* This function is directly inspired by function parse_clut coming from
    3604             :    ogdi/driver/rpf/utils.c and placed under the following copyright */
    3605             : 
    3606             : /*
    3607             :  ******************************************************************************
    3608             :  * Copyright (C) 1995 Logiciels et Applications Scientifiques (L.A.S.) Inc
    3609             :  * Permission to use, copy, modify and distribute this software and
    3610             :  * its documentation for any purpose and without fee is hereby granted,
    3611             :  * provided that the above copyright notice appear in all copies, that
    3612             :  * both the copyright notice and this permission notice appear in
    3613             :  * supporting documentation, and that the name of L.A.S. Inc not be used
    3614             :  * in advertising or publicity pertaining to distribution of the software
    3615             :  * without specific, written prior permission. L.A.S. Inc. makes no
    3616             :  * representations about the suitability of this software for any purpose.
    3617             :  * It is provided "as is" without express or implied warranty.
    3618             :  ******************************************************************************
    3619             :  */
    3620             : 
    3621        8608 : static void NITFLoadColormapSubSection(NITFImage *psImage)
    3622             : {
    3623        8608 :     int nLocBaseColorGrayscaleSection = 0;
    3624        8608 :     int nLocBaseColormapSubSection = 0;
    3625             :     /* int colorGrayscaleSectionSize = 0; */
    3626             :     /* int colormapSubSectionSize = 0; */
    3627        8608 :     NITFFile *psFile = psImage->psFile;
    3628             :     unsigned int i, j;
    3629             :     unsigned char nOffsetRecs;
    3630             :     NITFColormapRecord *colormapRecords;
    3631             :     unsigned int colormapOffsetTableOffset;
    3632             :     unsigned short offsetRecLen;
    3633        8608 :     int bOK = TRUE;
    3634             : 
    3635        8608 :     NITFBandInfo *psBandInfo = psImage->pasBandInfo;
    3636             : 
    3637       10389 :     for (i = 0; (int)i < psImage->nLocCount; i++)
    3638             :     {
    3639        1781 :         if (psImage->pasLocations[i].nLocId ==
    3640             :             LID_ColorGrayscaleSectionSubheader)
    3641             :         {
    3642         154 :             nLocBaseColorGrayscaleSection = psImage->pasLocations[i].nLocOffset;
    3643             :             /* colorGrayscaleSectionSize = psImage->pasLocations[i].nLocSize; */
    3644             :         }
    3645        1627 :         else if (psImage->pasLocations[i].nLocId == LID_ColormapSubsection)
    3646             :         {
    3647         154 :             nLocBaseColormapSubSection = psImage->pasLocations[i].nLocOffset;
    3648             :             /* colormapSubSectionSize = psImage->pasLocations[i].nLocSize; */
    3649             :         }
    3650             :     }
    3651        8608 :     if (nLocBaseColorGrayscaleSection == 0)
    3652             :     {
    3653        8454 :         return;
    3654             :     }
    3655         154 :     if (nLocBaseColormapSubSection == 0)
    3656             :     {
    3657           0 :         return;
    3658             :     }
    3659             : 
    3660         308 :     if (VSIFSeekL(psFile->fp, nLocBaseColorGrayscaleSection, SEEK_SET) != 0 ||
    3661         154 :         VSIFReadL(&nOffsetRecs, 1, 1, psFile->fp) != 1)
    3662             :     {
    3663           0 :         CPLError(CE_Failure, CPLE_FileIO, "Failed to seek to %d.",
    3664             :                  nLocBaseColorGrayscaleSection);
    3665           0 :         return;
    3666             :     }
    3667             : 
    3668         154 :     if (VSIFSeekL(psFile->fp, nLocBaseColormapSubSection, SEEK_SET) != 0)
    3669             :     {
    3670           0 :         CPLError(CE_Failure, CPLE_FileIO, "Failed to seek to %d.",
    3671             :                  nLocBaseColormapSubSection);
    3672           0 :         return;
    3673             :     }
    3674             : 
    3675         154 :     colormapRecords = (NITFColormapRecord *)CPLMalloc(
    3676             :         nOffsetRecs * sizeof(NITFColormapRecord));
    3677             : 
    3678             :     /* colormap offset table offset length */
    3679         154 :     bOK &= VSIFReadL(&colormapOffsetTableOffset,
    3680         154 :                      sizeof(colormapOffsetTableOffset), 1, psFile->fp) == 1;
    3681         154 :     CPL_MSBPTR32(&colormapOffsetTableOffset);
    3682             : 
    3683             :     /* offset record length */
    3684         154 :     bOK &= VSIFReadL(&offsetRecLen, sizeof(offsetRecLen), 1, psFile->fp) == 1;
    3685         154 :     CPL_MSBPTR16(&offsetRecLen);
    3686             : 
    3687         616 :     for (i = 0; bOK && i < nOffsetRecs; i++)
    3688             :     {
    3689         462 :         bOK &=
    3690         462 :             VSIFReadL(&colormapRecords[i].tableId,
    3691         462 :                       sizeof(colormapRecords[i].tableId), 1, psFile->fp) == 1;
    3692         462 :         CPL_MSBPTR16(&colormapRecords[i].tableId);
    3693             : 
    3694         462 :         bOK &=
    3695         462 :             VSIFReadL(&colormapRecords[i].nRecords,
    3696         462 :                       sizeof(colormapRecords[i].nRecords), 1, psFile->fp) == 1;
    3697         462 :         CPL_MSBPTR32(&colormapRecords[i].nRecords);
    3698             : 
    3699         462 :         bOK &= VSIFReadL(&colormapRecords[i].elementLength,
    3700             :                          sizeof(colormapRecords[i].elementLength), 1,
    3701         462 :                          psFile->fp) == 1;
    3702             : 
    3703         462 :         bOK &= VSIFReadL(&colormapRecords[i].histogramRecordLength,
    3704             :                          sizeof(colormapRecords[i].histogramRecordLength), 1,
    3705         462 :                          psFile->fp) == 1;
    3706         462 :         CPL_MSBPTR16(&colormapRecords[i].histogramRecordLength);
    3707             : 
    3708         462 :         bOK &= VSIFReadL(&colormapRecords[i].colorTableOffset,
    3709             :                          sizeof(colormapRecords[i].colorTableOffset), 1,
    3710         462 :                          psFile->fp) == 1;
    3711         462 :         CPL_MSBPTR32(&colormapRecords[i].colorTableOffset);
    3712             : 
    3713         462 :         bOK &= VSIFReadL(&colormapRecords[i].histogramTableOffset,
    3714             :                          sizeof(colormapRecords[i].histogramTableOffset), 1,
    3715         462 :                          psFile->fp) == 1;
    3716         462 :         CPL_MSBPTR32(&colormapRecords[i].histogramTableOffset);
    3717             :     }
    3718             : 
    3719         616 :     for (i = 0; bOK && i < nOffsetRecs; i++)
    3720             :     {
    3721         462 :         vsi_l_offset nOffset = (vsi_l_offset)nLocBaseColormapSubSection +
    3722         462 :                                colormapRecords[i].colorTableOffset;
    3723         462 :         if (VSIFSeekL(psFile->fp, nOffset, SEEK_SET) != 0)
    3724             :         {
    3725           0 :             CPLError(CE_Failure, CPLE_FileIO,
    3726             :                      "Failed to seek to " CPL_FRMT_GUIB ".", nOffset);
    3727           0 :             CPLFree(colormapRecords);
    3728           0 :             return;
    3729             :         }
    3730             : 
    3731             :         /* This test is very CADRG specific. See MIL-C-89038, paragraph 3.12.5.a
    3732             :          */
    3733         462 :         if (i == 0 && colormapRecords[i].tableId == 2 &&
    3734         154 :             colormapRecords[i].elementLength == 4 &&
    3735         154 :             colormapRecords[i].nRecords == 216) /* read, use colortable */
    3736             :         {
    3737         154 :             GByte *rgbm = (GByte *)CPLMalloc(colormapRecords[i].nRecords * 4);
    3738         154 :             if (VSIFReadL(rgbm, 1, colormapRecords[i].nRecords * 4,
    3739         154 :                           psFile->fp) != colormapRecords[i].nRecords * 4)
    3740             :             {
    3741           0 :                 CPLError(CE_Failure, CPLE_FileIO,
    3742             :                          "Failed to read %d byte rgbm.",
    3743           0 :                          colormapRecords[i].nRecords * 4);
    3744           0 :                 CPLFree(rgbm);
    3745           0 :                 CPLFree(colormapRecords);
    3746           0 :                 return;
    3747             :             }
    3748       33418 :             for (j = 0; j < colormapRecords[i].nRecords; j++)
    3749             :             {
    3750       33264 :                 psBandInfo->pabyLUT[j] = rgbm[4 * j];
    3751       33264 :                 psBandInfo->pabyLUT[j + 256] = rgbm[4 * j + 1];
    3752       33264 :                 psBandInfo->pabyLUT[j + 512] = rgbm[4 * j + 2];
    3753             :             }
    3754         154 :             CPLFree(rgbm);
    3755             :         }
    3756             :     }
    3757             : 
    3758         154 :     CPLFree(colormapRecords);
    3759             : }
    3760             : 
    3761             : /************************************************************************/
    3762             : /*                     NITFLoadSubframeMaskTable()                      */
    3763             : /************************************************************************/
    3764             : 
    3765             : /* Fixes bug #913 */
    3766        8755 : static void NITFLoadSubframeMaskTable(NITFImage *psImage,
    3767             :                                       bool *pbBlockStartRead)
    3768             : {
    3769             :     int i;
    3770        8755 :     NITFFile *psFile = psImage->psFile;
    3771        8755 :     NITFSegmentInfo *psSegInfo = psFile->pasSegmentInfo + psImage->iSegment;
    3772        8755 :     vsi_l_offset nLocBaseSpatialDataSubsection = psSegInfo->nSegmentStart;
    3773        8755 :     GUInt32 nLocBaseMaskSubsection = 0;
    3774        8755 :     vsi_l_offset nLocImageDescriptionSubheader = 0;
    3775             :     GUInt16 subframeSequenceRecordLength, transparencySequenceRecordLength,
    3776             :         transparencyOutputPixelCodeLength;
    3777        8755 :     bool bOK = true;
    3778             : 
    3779       10536 :     for (i = 0; i < psImage->nLocCount; i++)
    3780             :     {
    3781        1781 :         if (psImage->pasLocations[i].nLocId == LID_SpatialDataSubsection)
    3782             :         {
    3783         154 :             nLocBaseSpatialDataSubsection = psImage->pasLocations[i].nLocOffset;
    3784             :         }
    3785        1627 :         else if (psImage->pasLocations[i].nLocId == LID_MaskSubsection)
    3786             :         {
    3787         154 :             nLocBaseMaskSubsection = psImage->pasLocations[i].nLocOffset;
    3788             :         }
    3789        1473 :         else if (psImage->pasLocations[i].nLocId ==
    3790             :                  LID_ImageDescriptionSubheader)
    3791             :         {
    3792         154 :             nLocImageDescriptionSubheader = psImage->pasLocations[i].nLocOffset;
    3793             :         }
    3794             :     }
    3795        8755 :     if (nLocBaseMaskSubsection == 0)
    3796             :     {
    3797             :         // fprintf(stderr, "nLocBase(LID_MaskSubsection) == 0\n");
    3798        8721 :         return;
    3799             :     }
    3800             : 
    3801             :     // Reasonable default if ImageDescriptionSubheader is missing assuming
    3802             :     // the offset follow immediately the header of MaskSubsection which they
    3803             :     // generally do except for product cjga/cjgaz01/0105f033.ja1, which has
    3804             :     // however an explicit correct value for SUBFRAME_MASK_TABLE_OFFSET
    3805         154 :     GUInt32 nSUBFRAME_MASK_TABLE_OFFSET = 6;
    3806         154 :     if (nLocImageDescriptionSubheader > 0)
    3807             :     {
    3808         154 :         if (VSIFSeekL(psFile->fp, nLocImageDescriptionSubheader + 20,
    3809             :                       SEEK_SET) != 0)
    3810             :         {
    3811           0 :             CPLError(CE_Failure, CPLE_FileIO, "Failed to seek to %" PRIu64,
    3812             :                      ((uint64_t)nLocImageDescriptionSubheader) + 20);
    3813           0 :             return;
    3814             :         }
    3815             : 
    3816         154 :         bOK &=
    3817         154 :             VSIFReadL(&nSUBFRAME_MASK_TABLE_OFFSET,
    3818         154 :                       sizeof(nSUBFRAME_MASK_TABLE_OFFSET), 1, psFile->fp) == 1;
    3819         154 :         CPL_MSBPTR32(&nSUBFRAME_MASK_TABLE_OFFSET);
    3820             :     }
    3821             : 
    3822             :     // fprintf(stderr, "nLocBaseMaskSubsection = %d\n", nLocBaseMaskSubsection);
    3823         154 :     if (VSIFSeekL(psFile->fp, nLocBaseMaskSubsection, SEEK_SET) != 0)
    3824             :     {
    3825           0 :         CPLError(CE_Failure, CPLE_FileIO, "Failed to seek to %u",
    3826             :                  nLocBaseMaskSubsection);
    3827           0 :         return;
    3828             :     }
    3829             : 
    3830         154 :     bOK &= VSIFReadL(&subframeSequenceRecordLength,
    3831         154 :                      sizeof(subframeSequenceRecordLength), 1, psFile->fp) == 1;
    3832         154 :     CPL_MSBPTR16(&subframeSequenceRecordLength);
    3833             : 
    3834         154 :     bOK &=
    3835         154 :         VSIFReadL(&transparencySequenceRecordLength,
    3836         154 :                   sizeof(transparencySequenceRecordLength), 1, psFile->fp) == 1;
    3837         154 :     CPL_MSBPTR16(&transparencySequenceRecordLength);
    3838             : 
    3839             :     /* in bits */
    3840         154 :     bOK &= VSIFReadL(&transparencyOutputPixelCodeLength,
    3841             :                      sizeof(transparencyOutputPixelCodeLength), 1,
    3842         154 :                      psFile->fp) == 1;
    3843         154 :     CPL_MSBPTR16(&transparencyOutputPixelCodeLength);
    3844             : 
    3845             :     // fprintf(stderr, "transparencyOutputPixelCodeLength=%d\n",
    3846             :     // transparencyOutputPixelCodeLength);
    3847             : 
    3848         154 :     if (transparencyOutputPixelCodeLength == 8)
    3849             :     {
    3850             :         GByte byNodata;
    3851             : 
    3852         104 :         if (bOK && VSIFReadL(&byNodata, 1, 1, psFile->fp) == 1)
    3853             :         {
    3854         104 :             psImage->bNoDataSet = TRUE;
    3855         104 :             psImage->nNoDataValue = byNodata;
    3856             :         }
    3857             :     }
    3858             :     else
    3859             :     {
    3860          50 :         bOK &=
    3861          50 :             VSIFSeekL(psFile->fp, (transparencyOutputPixelCodeLength + 7) / 8,
    3862          50 :                       SEEK_CUR) == 0;
    3863             :     }
    3864             : 
    3865             :     /* Fix for rpf/cjnc/cjncz01/0001f023.jn1 */
    3866         154 :     if (!bOK || subframeSequenceRecordLength != 4 ||
    3867          34 :         nSUBFRAME_MASK_TABLE_OFFSET == UINT_MAX)
    3868             :     {
    3869             :         // fprintf(stderr, "subframeSequenceRecordLength=%d\n",
    3870             :         // subframeSequenceRecordLength);
    3871         120 :         return;
    3872             :     }
    3873          34 :     if (nSUBFRAME_MASK_TABLE_OFFSET < 6)
    3874             :     {
    3875           0 :         CPLError(CE_Warning, CPLE_AppDefined,
    3876             :                  "Invalid value for SUBFRAME_MASK_TABLE_OFFSET: %u. Ignoring "
    3877             :                  "block start table",
    3878             :                  nSUBFRAME_MASK_TABLE_OFFSET);
    3879           0 :         return;
    3880             :     }
    3881             : 
    3882          68 :     bOK &= (VSIFSeekL(psFile->fp,
    3883          34 :                       nLocBaseMaskSubsection + nSUBFRAME_MASK_TABLE_OFFSET,
    3884          34 :                       SEEK_SET) == 0);
    3885             : 
    3886        1258 :     for (i = 0; bOK && i < psImage->nBlocksPerRow * psImage->nBlocksPerColumn;
    3887        1224 :          i++)
    3888             :     {
    3889             :         unsigned int offset;
    3890        1224 :         bOK = VSIFReadL(&offset, sizeof(offset), 1, psFile->fp) == 1;
    3891        1224 :         CPL_MSBPTR32(&offset);
    3892             :         // fprintf(stderr, "%u : %d\n", i, offset);
    3893        1224 :         if (!bOK || offset == UINT_MAX)
    3894        1224 :             psImage->panBlockStart[i] = UINT_MAX;
    3895             :         else
    3896           0 :             psImage->panBlockStart[i] = nLocBaseSpatialDataSubsection + offset;
    3897             :     }
    3898             : 
    3899          34 :     *pbBlockStartRead = bOK;
    3900             : }
    3901             : 
    3902        2351 : static GUInt16 NITFReadMSBGUInt16(VSILFILE *fp, int *pbSuccess)
    3903             : {
    3904             :     GUInt16 nVal;
    3905        2351 :     if (VSIFReadL(&nVal, 1, sizeof(nVal), fp) != sizeof(nVal))
    3906             :     {
    3907           0 :         *pbSuccess = FALSE;
    3908           0 :         return 0;
    3909             :     }
    3910        2351 :     CPL_MSBPTR16(&nVal);
    3911        2351 :     return nVal;
    3912             : }
    3913             : 
    3914        4022 : static GUInt32 NITFReadMSBGUInt32(VSILFILE *fp, int *pbSuccess)
    3915             : {
    3916             :     GUInt32 nVal;
    3917        4022 :     if (VSIFReadL(&nVal, 1, sizeof(nVal), fp) != sizeof(nVal))
    3918             :     {
    3919           0 :         *pbSuccess = FALSE;
    3920           0 :         return 0;
    3921             :     }
    3922        4022 :     CPL_MSBPTR32(&nVal);
    3923        4022 :     return nVal;
    3924             : }
    3925             : 
    3926             : /************************************************************************/
    3927             : /*                      NITFReadRPFLocationTable()                      */
    3928             : /************************************************************************/
    3929             : 
    3930         170 : NITFLocation *NITFReadRPFLocationTable(VSILFILE *fp, int *pnLocCount)
    3931             : {
    3932             :     /* GUInt16 nLocSectionLength; */
    3933             :     GUInt32 nLocSectionOffset;
    3934             :     GUInt16 iLoc;
    3935             :     GUInt16 nLocCount;
    3936             :     GUInt16 nLocRecordLength;
    3937             :     /* GUInt32 nLocComponentAggregateLength; */
    3938         170 :     NITFLocation *pasLocations = NULL;
    3939             :     int bSuccess;
    3940             :     GUIntBig nCurOffset;
    3941             : 
    3942         170 :     if (fp == NULL || pnLocCount == NULL)
    3943           0 :         return NULL;
    3944             : 
    3945         170 :     *pnLocCount = 0;
    3946             : 
    3947         170 :     nCurOffset = VSIFTellL(fp);
    3948             : 
    3949         170 :     bSuccess = TRUE;
    3950         170 :     /* nLocSectionLength = */ NITFReadMSBGUInt16(fp, &bSuccess);
    3951         170 :     nLocSectionOffset = NITFReadMSBGUInt32(fp, &bSuccess);
    3952         170 :     if (nLocSectionOffset != 14)
    3953             :     {
    3954           0 :         CPLDebug("NITF", "Unusual location section offset : %d",
    3955             :                  nLocSectionOffset);
    3956             :     }
    3957             : 
    3958         170 :     nLocCount = NITFReadMSBGUInt16(fp, &bSuccess);
    3959             : 
    3960         170 :     if (!bSuccess || nLocCount == 0)
    3961             :     {
    3962           0 :         return NULL;
    3963             :     }
    3964             : 
    3965         170 :     nLocRecordLength = NITFReadMSBGUInt16(fp, &bSuccess);
    3966         170 :     if (nLocRecordLength != 10)
    3967             :     {
    3968           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    3969             :                  "Did not get expected record length : %d", nLocRecordLength);
    3970           0 :         return NULL;
    3971             :     }
    3972             : 
    3973         170 :     /* nLocComponentAggregateLength = */ NITFReadMSBGUInt32(fp, &bSuccess);
    3974             : 
    3975         170 :     bSuccess = VSIFSeekL(fp, nCurOffset + nLocSectionOffset, SEEK_SET) == 0;
    3976             : 
    3977             :     pasLocations =
    3978         170 :         (NITFLocation *)VSI_CALLOC_VERBOSE(sizeof(NITFLocation), nLocCount);
    3979         170 :     if (pasLocations == NULL)
    3980             :     {
    3981           0 :         return NULL;
    3982             :     }
    3983             : 
    3984             :     /* -------------------------------------------------------------------- */
    3985             :     /*      Process the locations.                                          */
    3986             :     /* -------------------------------------------------------------------- */
    3987        2011 :     for (iLoc = 0; bSuccess && iLoc < nLocCount; iLoc++)
    3988             :     {
    3989        1841 :         pasLocations[iLoc].nLocId = NITFReadMSBGUInt16(fp, &bSuccess);
    3990        1841 :         pasLocations[iLoc].nLocSize = NITFReadMSBGUInt32(fp, &bSuccess);
    3991        1841 :         pasLocations[iLoc].nLocOffset = NITFReadMSBGUInt32(fp, &bSuccess);
    3992        1841 :         CPLDebugOnly("NITF", "Location[%d]: id=%d, size=%u, offset=%u", iLoc,
    3993             :                      pasLocations[iLoc].nLocId, pasLocations[iLoc].nLocSize,
    3994             :                      pasLocations[iLoc].nLocOffset);
    3995             :     }
    3996             : 
    3997         170 :     if (!bSuccess)
    3998             :     {
    3999           0 :         CPLFree(pasLocations);
    4000           0 :         return NULL;
    4001             :     }
    4002             : 
    4003         170 :     *pnLocCount = nLocCount;
    4004         170 :     return pasLocations;
    4005             : }
    4006             : 
    4007             : /************************************************************************/
    4008             : /*                       NITFLoadLocationTable()                        */
    4009             : /************************************************************************/
    4010             : 
    4011        8755 : static void NITFLoadLocationTable(NITFImage *psImage)
    4012             : 
    4013             : {
    4014             :     /* -------------------------------------------------------------------- */
    4015             :     /*      Get the location table out of the RPFIMG TRE on the image.      */
    4016             :     /* -------------------------------------------------------------------- */
    4017             :     const char *pszTRE;
    4018        8755 :     GUInt32 nHeaderOffset = 0;
    4019             :     int i;
    4020             :     int nTRESize;
    4021             :     char szTempFileName[256];
    4022             :     VSILFILE *fpTemp;
    4023             : 
    4024             :     pszTRE =
    4025        8755 :         NITFFindTRE(psImage->pachTRE, psImage->nTREBytes, "RPFIMG", &nTRESize);
    4026        8755 :     if (pszTRE == NULL)
    4027        8600 :         return;
    4028             : 
    4029         155 :     snprintf(szTempFileName, sizeof(szTempFileName), "%s",
    4030             :              VSIMemGenerateHiddenFilename("nitf_tre"));
    4031             :     fpTemp =
    4032         155 :         VSIFileFromMemBuffer(szTempFileName, (GByte *)pszTRE, nTRESize, FALSE);
    4033         155 :     psImage->pasLocations =
    4034         155 :         NITFReadRPFLocationTable(fpTemp, &psImage->nLocCount);
    4035         155 :     CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fpTemp));
    4036         155 :     VSIUnlink(szTempFileName);
    4037             : 
    4038         155 :     if (psImage->nLocCount == 0)
    4039           0 :         return;
    4040             : 
    4041             :     /* -------------------------------------------------------------------- */
    4042             :     /*      It seems that sometimes (at least for bug #1313 and #1714)      */
    4043             :     /*      the RPF headers are improperly placed.  We check by looking     */
    4044             :     /*      to see if the RPFHDR is where it should be.  If not, we         */
    4045             :     /*      disregard the location table.                                   */
    4046             :     /*                                                                      */
    4047             :     /*      The NITF21_CGM_ANNO_Uncompressed_unmasked.ntf sample data       */
    4048             :     /*      file (see gdal data downloads) is an example of this.           */
    4049             :     /* -------------------------------------------------------------------- */
    4050        1936 :     for (i = 0; i < psImage->nLocCount; i++)
    4051             :     {
    4052        1781 :         if (psImage->pasLocations[i].nLocId == LID_HeaderComponent)
    4053             :         {
    4054           0 :             nHeaderOffset = psImage->pasLocations[i].nLocOffset;
    4055           0 :             break;
    4056             :         }
    4057             :     }
    4058             : 
    4059         155 :     if (nHeaderOffset > 11)
    4060             :     {
    4061             :         char achHeaderChunk[1000];
    4062             : 
    4063           0 :         if (VSIFSeekL(psImage->psFile->fp, nHeaderOffset - 11, SEEK_SET) != 0 ||
    4064           0 :             VSIFReadL(achHeaderChunk, sizeof(achHeaderChunk), 1,
    4065           0 :                       psImage->psFile->fp) != 1)
    4066             :         {
    4067           0 :             CPLFree(psImage->pasLocations);
    4068           0 :             psImage->pasLocations = NULL;
    4069           0 :             psImage->nLocCount = 0;
    4070           0 :             return;
    4071             :         }
    4072             : 
    4073             :         /* You can define NITF_DISABLE_RPF_LOCATION_TABLE_SANITY_TESTS to TRUE
    4074             :          */
    4075             :         /* to blindly trust the RPF location table even if it doesn't look */
    4076             :         /* sane. Necessary for dataset attached to
    4077             :          * http://trac.osgeo.org/gdal/ticket/3930 */
    4078           0 :         if (!STARTS_WITH_CI(achHeaderChunk, "RPFHDR") &&
    4079           0 :             !CPLTestBoolean(CPLGetConfigOption(
    4080             :                 "NITF_DISABLE_RPF_LOCATION_TABLE_SANITY_TESTS", "FALSE")))
    4081             :         {
    4082             :             /* Image of http://trac.osgeo.org/gdal/ticket/3848 has incorrect */
    4083             :             /* RPFHDR offset, but all other locations are correct... */
    4084             :             /* So if we find LID_CoverageSectionSubheader and
    4085             :              * LID_CompressionLookupSubsection */
    4086             :             /* we check whether their content is valid. */
    4087           0 :             int bFoundValidLocation = FALSE;
    4088           0 :             for (i = 0; i < psImage->nLocCount; i++)
    4089             :             {
    4090           0 :                 if (psImage->pasLocations[i].nLocId ==
    4091           0 :                         LID_CoverageSectionSubheader &&
    4092           0 :                     (psImage->chICORDS == 'G' || psImage->chICORDS == 'D'))
    4093           0 :                 {
    4094             :                     /* Does that look like valid latitude/longitude values ? */
    4095             :                     /* We test that they are close enough from the values of the
    4096             :                      * IGEOLO record */
    4097             :                     double adfTarget[8];
    4098             : 
    4099           0 :                     if (VSIFSeekL(psImage->psFile->fp,
    4100           0 :                                   psImage->pasLocations[i].nLocOffset,
    4101           0 :                                   SEEK_SET) != 0 ||
    4102           0 :                         VSIFReadL(adfTarget, 8, 8, psImage->psFile->fp) != 8)
    4103             :                     {
    4104           0 :                         CPLFree(psImage->pasLocations);
    4105           0 :                         psImage->pasLocations = NULL;
    4106           0 :                         psImage->nLocCount = 0;
    4107           0 :                         return;
    4108             :                     }
    4109           0 :                     for (i = 0; i < 8; i++)
    4110           0 :                         CPL_MSBPTR64((adfTarget + i));
    4111             : 
    4112           0 :                     if (fabs(psImage->dfULX - adfTarget[1]) < 0.1 &&
    4113           0 :                         fabs(psImage->dfULY - adfTarget[0]) < 0.1 &&
    4114           0 :                         fabs(psImage->dfLLX - adfTarget[3]) < 0.1 &&
    4115           0 :                         fabs(psImage->dfLLY - adfTarget[2]) < 0.1 &&
    4116           0 :                         fabs(psImage->dfURX - adfTarget[5]) < 0.1 &&
    4117           0 :                         fabs(psImage->dfURY - adfTarget[4]) < 0.1 &&
    4118           0 :                         fabs(psImage->dfLRX - adfTarget[7]) < 0.1 &&
    4119           0 :                         fabs(psImage->dfLRY - adfTarget[6]) < 0.1)
    4120             :                     {
    4121           0 :                         bFoundValidLocation = TRUE;
    4122             :                     }
    4123             :                     else
    4124             :                     {
    4125           0 :                         CPLDebug("NITF", "The CoverageSectionSubheader content "
    4126             :                                          "isn't consistent");
    4127           0 :                         bFoundValidLocation = FALSE;
    4128           0 :                         break;
    4129             :                     }
    4130             :                 }
    4131           0 :                 else if (psImage->pasLocations[i].nLocId ==
    4132             :                          LID_CompressionLookupSubsection)
    4133             :                 {
    4134           0 :                     if (NITFLoadVQTables(psImage, FALSE))
    4135             :                     {
    4136           0 :                         bFoundValidLocation = TRUE;
    4137             :                     }
    4138             :                     else
    4139             :                     {
    4140           0 :                         CPLDebug("NITF",
    4141             :                                  "The VQ tables content aren't consistent");
    4142           0 :                         bFoundValidLocation = FALSE;
    4143           0 :                         break;
    4144             :                     }
    4145             :                 }
    4146             :             }
    4147           0 :             if (bFoundValidLocation)
    4148             :             {
    4149           0 :                 CPLDebug("NITF", "RPFHDR is not correctly placed, but other "
    4150             :                                  "locations seem correct. Going on...");
    4151             :             }
    4152             :             else
    4153             :             {
    4154           0 :                 CPLError(CE_Warning, CPLE_AppDefined,
    4155             :                          "Ignoring NITF RPF Location table since it seems to "
    4156             :                          "be corrupt.");
    4157           0 :                 CPLFree(psImage->pasLocations);
    4158           0 :                 psImage->pasLocations = NULL;
    4159           0 :                 psImage->nLocCount = 0;
    4160             :             }
    4161             :         }
    4162             :     }
    4163             : }
    4164             : 
    4165             : /************************************************************************/
    4166             : /*                          NITFLoadVQTables()                          */
    4167             : /************************************************************************/
    4168             : 
    4169        8755 : static int NITFLoadVQTables(NITFImage *psImage, int bTryGuessingOffset)
    4170             : 
    4171             : {
    4172             :     int i;
    4173        8755 :     GUInt32 nVQOffset = 0 /*, nVQSize=0 */;
    4174             :     GByte abyTestChunk[1000];
    4175        8755 :     const GByte abySignature[6] = {0x00, 0x00, 0x00, 0x06, 0x00, 0x0E};
    4176             : 
    4177             :     /* -------------------------------------------------------------------- */
    4178             :     /*      Do we already have the VQ tables?                               */
    4179             :     /* -------------------------------------------------------------------- */
    4180        8755 :     if (psImage->apanVQLUT[0] != NULL)
    4181           0 :         return TRUE;
    4182             : 
    4183             :     /* -------------------------------------------------------------------- */
    4184             :     /*      Do we have the location information?                            */
    4185             :     /* -------------------------------------------------------------------- */
    4186       10536 :     for (i = 0; i < psImage->nLocCount; i++)
    4187             :     {
    4188        1781 :         if (psImage->pasLocations[i].nLocId == LID_CompressionLookupSubsection)
    4189             :         {
    4190         154 :             nVQOffset = psImage->pasLocations[i].nLocOffset;
    4191             :             /* nVQSize = psImage->pasLocations[i].nLocSize; */
    4192             :         }
    4193             :     }
    4194             : 
    4195        8755 :     if (nVQOffset == 0)
    4196        8601 :         return FALSE;
    4197             : 
    4198             :     /* -------------------------------------------------------------------- */
    4199             :     /*      Does it look like we have the tables properly identified?       */
    4200             :     /* -------------------------------------------------------------------- */
    4201         308 :     if (VSIFSeekL(psImage->psFile->fp, nVQOffset, SEEK_SET) != 0 ||
    4202         154 :         VSIFReadL(abyTestChunk, sizeof(abyTestChunk), 1, psImage->psFile->fp) !=
    4203             :             1)
    4204             :     {
    4205           0 :         return FALSE;
    4206             :     }
    4207             : 
    4208         154 :     if (memcmp(abyTestChunk, abySignature, sizeof(abySignature)) != 0)
    4209             :     {
    4210           0 :         int bFoundSignature = FALSE;
    4211           0 :         if (!bTryGuessingOffset)
    4212           0 :             return FALSE;
    4213             : 
    4214           0 :         for (i = 0; (size_t)i < sizeof(abyTestChunk) - sizeof(abySignature);
    4215           0 :              i++)
    4216             :         {
    4217           0 :             if (memcmp(abyTestChunk + i, abySignature, sizeof(abySignature)) ==
    4218             :                 0)
    4219             :             {
    4220           0 :                 bFoundSignature = TRUE;
    4221           0 :                 nVQOffset += i;
    4222           0 :                 CPLDebug("NITF",
    4223             :                          "VQ CompressionLookupSubsection offsets off by %d "
    4224             :                          "bytes, adjusting accordingly.",
    4225             :                          i);
    4226           0 :                 break;
    4227             :             }
    4228             :         }
    4229           0 :         if (!bFoundSignature)
    4230           0 :             return FALSE;
    4231             :     }
    4232             : 
    4233             :     /* -------------------------------------------------------------------- */
    4234             :     /*      Load the tables.                                                */
    4235             :     /* -------------------------------------------------------------------- */
    4236         770 :     for (i = 0; i < 4; i++)
    4237             :     {
    4238             :         GUInt32 nVQVector;
    4239             :         int bOK;
    4240             : 
    4241         616 :         psImage->apanVQLUT[i] = (GUInt32 *)CPLCalloc(4096, sizeof(GUInt32));
    4242             : 
    4243         616 :         bOK = VSIFSeekL(psImage->psFile->fp, nVQOffset + 6 + i * 14 + 10,
    4244         616 :                         SEEK_SET) == 0;
    4245         616 :         bOK &= VSIFReadL(&nVQVector, 1, 4, psImage->psFile->fp) == 4;
    4246         616 :         nVQVector = CPL_MSBWORD32(nVQVector);
    4247             : 
    4248        1232 :         bOK &= VSIFSeekL(psImage->psFile->fp,
    4249         616 :                          (vsi_l_offset)(nVQOffset) + nVQVector, SEEK_SET) == 0;
    4250         616 :         bOK &= VSIFReadL(psImage->apanVQLUT[i], 4, 4096, psImage->psFile->fp) ==
    4251             :                4096;
    4252         616 :         if (!bOK)
    4253             :         {
    4254           0 :             for (i = 0; i < 4; i++)
    4255             :             {
    4256           0 :                 CPLFree(psImage->apanVQLUT[i]);
    4257           0 :                 psImage->apanVQLUT[i] = NULL;
    4258             :             }
    4259           0 :             return FALSE;
    4260             :         }
    4261             :     }
    4262             : 
    4263         154 :     return TRUE;
    4264             : }
    4265             : 
    4266             : /************************************************************************/
    4267             : /*                           NITFReadSTDIDC()                           */
    4268             : /*                                                                      */
    4269             : /*      Read a STDIDC TRE and return contents as metadata strings.      */
    4270             : /************************************************************************/
    4271             : 
    4272           0 : char **NITFReadSTDIDC(NITFImage *psImage)
    4273             : 
    4274             : {
    4275           0 :     return NITFGenericMetadataRead(NULL, NULL, psImage, "STDIDC");
    4276             : }
    4277             : 
    4278             : /************************************************************************/
    4279             : /*                         NITFRPCGeoToImage()                          */
    4280             : /************************************************************************/
    4281             : 
    4282           0 : int NITFRPCGeoToImage(NITFRPC00BInfo *psRPC, double dfLong, double dfLat,
    4283             :                       double dfHeight, double *pdfPixel, double *pdfLine)
    4284             : 
    4285             : {
    4286             :     double dfLineNumerator, dfLineDenominator, dfPixelNumerator,
    4287             :         dfPixelDenominator;
    4288             :     double dfPolyTerm[20];
    4289           0 :     double *pdfPolyTerm = dfPolyTerm;
    4290             :     int i;
    4291             : 
    4292             :     /* -------------------------------------------------------------------- */
    4293             :     /*      Normalize Lat/Long position.                                    */
    4294             :     /* -------------------------------------------------------------------- */
    4295           0 :     dfLong = (dfLong - psRPC->LONG_OFF) / psRPC->LONG_SCALE;
    4296           0 :     dfLat = (dfLat - psRPC->LAT_OFF) / psRPC->LAT_SCALE;
    4297           0 :     dfHeight = (dfHeight - psRPC->HEIGHT_OFF) / psRPC->HEIGHT_SCALE;
    4298             : 
    4299             :     /* -------------------------------------------------------------------- */
    4300             :     /*      Compute the 20 terms.                                           */
    4301             :     /* -------------------------------------------------------------------- */
    4302             : 
    4303           0 :     pdfPolyTerm[0] = 1.0; /* workaround cppcheck false positive */
    4304           0 :     dfPolyTerm[1] = dfLong;
    4305           0 :     dfPolyTerm[2] = dfLat;
    4306           0 :     dfPolyTerm[3] = dfHeight;
    4307           0 :     dfPolyTerm[4] = dfLong * dfLat;
    4308           0 :     dfPolyTerm[5] = dfLong * dfHeight;
    4309           0 :     dfPolyTerm[6] = dfLat * dfHeight;
    4310           0 :     dfPolyTerm[7] = dfLong * dfLong;
    4311           0 :     dfPolyTerm[8] = dfLat * dfLat;
    4312           0 :     dfPolyTerm[9] = dfHeight * dfHeight;
    4313             : 
    4314           0 :     dfPolyTerm[10] = dfLong * dfLat * dfHeight;
    4315           0 :     dfPolyTerm[11] = dfLong * dfLong * dfLong;
    4316           0 :     dfPolyTerm[12] = dfLong * dfLat * dfLat;
    4317           0 :     dfPolyTerm[13] = dfLong * dfHeight * dfHeight;
    4318           0 :     dfPolyTerm[14] = dfLong * dfLong * dfLat;
    4319           0 :     dfPolyTerm[15] = dfLat * dfLat * dfLat;
    4320           0 :     dfPolyTerm[16] = dfLat * dfHeight * dfHeight;
    4321           0 :     dfPolyTerm[17] = dfLong * dfLong * dfHeight;
    4322           0 :     dfPolyTerm[18] = dfLat * dfLat * dfHeight;
    4323           0 :     dfPolyTerm[19] = dfHeight * dfHeight * dfHeight;
    4324             : 
    4325             :     /* -------------------------------------------------------------------- */
    4326             :     /*      Compute numerator and denominator sums.                         */
    4327             :     /* -------------------------------------------------------------------- */
    4328           0 :     dfPixelNumerator = 0.0;
    4329           0 :     dfPixelDenominator = 0.0;
    4330           0 :     dfLineNumerator = 0.0;
    4331           0 :     dfLineDenominator = 0.0;
    4332             : 
    4333           0 :     for (i = 0; i < 20; i++)
    4334             :     {
    4335           0 :         dfPixelNumerator += psRPC->SAMP_NUM_COEFF[i] * dfPolyTerm[i];
    4336           0 :         dfPixelDenominator += psRPC->SAMP_DEN_COEFF[i] * dfPolyTerm[i];
    4337           0 :         dfLineNumerator += psRPC->LINE_NUM_COEFF[i] * dfPolyTerm[i];
    4338           0 :         dfLineDenominator += psRPC->LINE_DEN_COEFF[i] * dfPolyTerm[i];
    4339             :     }
    4340             : 
    4341             :     /* -------------------------------------------------------------------- */
    4342             :     /*      Compute normalized pixel and line values.                       */
    4343             :     /* -------------------------------------------------------------------- */
    4344           0 :     *pdfPixel = dfPixelNumerator / dfPixelDenominator;
    4345           0 :     *pdfLine = dfLineNumerator / dfLineDenominator;
    4346             : 
    4347             :     /* -------------------------------------------------------------------- */
    4348             :     /*      Denormalize.                                                    */
    4349             :     /* -------------------------------------------------------------------- */
    4350           0 :     *pdfPixel = *pdfPixel * psRPC->SAMP_SCALE + psRPC->SAMP_OFF;
    4351           0 :     *pdfLine = *pdfLine * psRPC->LINE_SCALE + psRPC->LINE_OFF;
    4352             : 
    4353           0 :     return TRUE;
    4354             : }
    4355             : 
    4356             : /************************************************************************/
    4357             : /*                         NITFIHFieldOffset()                          */
    4358             : /*                                                                      */
    4359             : /*      Find the file offset for the beginning of a particular field    */
    4360             : /*      in this image header.  Only implemented for selected fields.    */
    4361             : /************************************************************************/
    4362             : 
    4363          33 : GUIntBig NITFIHFieldOffset(NITFImage *psImage, const char *pszFieldName)
    4364             : 
    4365             : {
    4366             :     char szTemp[128];
    4367             :     int nNICOM;
    4368             :     GUIntBig nWrkOffset;
    4369          33 :     GUIntBig nIMOffset =
    4370          33 :         psImage->psFile->pasSegmentInfo[psImage->iSegment].nSegmentHeaderStart;
    4371             : 
    4372             :     // We only support files we created.
    4373          33 :     if (!STARTS_WITH_CI(psImage->psFile->szVersion, "NITF02.1"))
    4374             :     {
    4375           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    4376             :                  "NITFIHFieldOffset() only works with NITF 2.1 images");
    4377           0 :         return 0;
    4378             :     }
    4379             : 
    4380          33 :     if (EQUAL(pszFieldName, "IM"))
    4381           0 :         return nIMOffset;
    4382             : 
    4383          33 :     if (EQUAL(pszFieldName, "PJUST"))
    4384           0 :         return nIMOffset + 370;
    4385             : 
    4386          33 :     if (EQUAL(pszFieldName, "ICORDS"))
    4387           0 :         return nIMOffset + 371;
    4388             : 
    4389          33 :     if (EQUAL(pszFieldName, "IGEOLO"))
    4390             :     {
    4391           0 :         if (!psImage->bHaveIGEOLO)
    4392           0 :             return 0;
    4393             :         else
    4394           0 :             return nIMOffset + 372;
    4395             :     }
    4396             : 
    4397             :     /* -------------------------------------------------------------------- */
    4398             :     /*      Keep working offset from here on in since everything else is    */
    4399             :     /*      variable.                                                       */
    4400             :     /* -------------------------------------------------------------------- */
    4401          33 :     nWrkOffset = 372 + nIMOffset;
    4402             : 
    4403          33 :     if (psImage->bHaveIGEOLO)
    4404          30 :         nWrkOffset += 60;
    4405             : 
    4406             :     /* -------------------------------------------------------------------- */
    4407             :     /*      Comments.                                                       */
    4408             :     /* -------------------------------------------------------------------- */
    4409          66 :     nNICOM = atoi(NITFGetField(szTemp, psImage->pachHeader,
    4410          33 :                                (int)(nWrkOffset - nIMOffset), 1));
    4411             : 
    4412          33 :     if (EQUAL(pszFieldName, "NICOM"))
    4413           0 :         return nWrkOffset;
    4414             : 
    4415          33 :     nWrkOffset++;
    4416             : 
    4417          33 :     if (EQUAL(pszFieldName, "ICOM"))
    4418           0 :         return nWrkOffset;
    4419             : 
    4420          33 :     nWrkOffset += 80 * nNICOM;
    4421             : 
    4422             :     /* -------------------------------------------------------------------- */
    4423             :     /*      IC                                                              */
    4424             :     /* -------------------------------------------------------------------- */
    4425          33 :     if (EQUAL(pszFieldName, "IC"))
    4426           0 :         return nWrkOffset;
    4427             : 
    4428          33 :     nWrkOffset += 2;
    4429             : 
    4430             :     /* -------------------------------------------------------------------- */
    4431             :     /*      COMRAT                                                          */
    4432             :     /* -------------------------------------------------------------------- */
    4433             : 
    4434          33 :     if (psImage->szIC[0] != 'N')
    4435             :     {
    4436           3 :         if (EQUAL(pszFieldName, "COMRAT"))
    4437           0 :             return nWrkOffset;
    4438           3 :         nWrkOffset += 4;
    4439             :     }
    4440             : 
    4441             :     /* -------------------------------------------------------------------- */
    4442             :     /*      NBANDS                                                          */
    4443             :     /* -------------------------------------------------------------------- */
    4444          33 :     if (EQUAL(pszFieldName, "NBANDS"))
    4445           0 :         return nWrkOffset;
    4446             : 
    4447          33 :     nWrkOffset += 1;
    4448             : 
    4449             :     /* -------------------------------------------------------------------- */
    4450             :     /*      XBANDS                                                          */
    4451             :     /* -------------------------------------------------------------------- */
    4452          33 :     if (EQUAL(pszFieldName, "XBANDS"))
    4453           0 :         return nWrkOffset;
    4454             : 
    4455          33 :     if (psImage->nBands > 9)
    4456           0 :         nWrkOffset += 5;
    4457             : 
    4458             :     /* -------------------------------------------------------------------- */
    4459             :     /*      IREPBAND                                                        */
    4460             :     /* -------------------------------------------------------------------- */
    4461          33 :     if (EQUAL(pszFieldName, "IREPBAND"))
    4462          33 :         return nWrkOffset;
    4463             : 
    4464             :     //    nWrkOffset += 2 * psImage->nBands;
    4465             : 
    4466           0 :     return 0;
    4467             : }
    4468             : 
    4469             : /************************************************************************/
    4470             : /*                        NITFDoLinesIntersect()                        */
    4471             : /************************************************************************/
    4472             : 
    4473         386 : static int NITFDoLinesIntersect(double dfL1X1, double dfL1Y1, double dfL1X2,
    4474             :                                 double dfL1Y2, double dfL2X1, double dfL2Y1,
    4475             :                                 double dfL2X2, double dfL2Y2)
    4476             : 
    4477             : {
    4478             :     double dfL1M, dfL1B, dfL2M, dfL2B;
    4479             : 
    4480         386 :     if (dfL1X1 == dfL1X2)
    4481             :     {
    4482         353 :         dfL1M = 1e10;
    4483         353 :         dfL1B = 0.0;
    4484             :     }
    4485             :     else
    4486             :     {
    4487          33 :         dfL1M = (dfL1Y2 - dfL1Y1) / (dfL1X2 - dfL1X1);
    4488          33 :         dfL1B = dfL1Y2 - dfL1M * dfL1X2;
    4489             :     }
    4490             : 
    4491         386 :     if (dfL2X1 == dfL2X2)
    4492             :     {
    4493         353 :         dfL2M = 1e10;
    4494         353 :         dfL2B = 0.0;
    4495             :     }
    4496             :     else
    4497             :     {
    4498          33 :         dfL2M = (dfL2Y2 - dfL2Y1) / (dfL2X2 - dfL2X1);
    4499          33 :         dfL2B = dfL2Y2 - dfL2M * dfL2X2;
    4500             :     }
    4501             : 
    4502         386 :     if (dfL2M == dfL1M)
    4503             :     {
    4504             :         // parallel .. no meaningful intersection.
    4505         358 :         return FALSE;
    4506             :     }
    4507             :     else
    4508             :     {
    4509             :         double dfX /*, dfY*/;
    4510             : 
    4511          28 :         dfX = (dfL2B - dfL1B) / (dfL1M - dfL2M);
    4512             :         /* dfY = dfL2M * dfX + dfL2B; */
    4513             : 
    4514             :         /*
    4515             :         ** Is this intersection on the line between
    4516             :         ** our corner points or "out somewhere" else?
    4517             :         */
    4518          28 :         return ((dfX >= dfL1X1 && dfX <= dfL1X2) ||
    4519          56 :                 (dfX >= dfL1X2 && dfX <= dfL1X1)) &&
    4520           0 :                ((dfX >= dfL2X1 && dfX <= dfL2X2) ||
    4521           0 :                 (dfX >= dfL2X2 && dfX <= dfL2X1));
    4522             :     }
    4523             : }
    4524             : 
    4525             : /************************************************************************/
    4526             : /*                  NITFPossibleIGEOLOReorientation()                   */
    4527             : /************************************************************************/
    4528             : 
    4529         386 : static void NITFPossibleIGEOLOReorientation(NITFImage *psImage)
    4530             : 
    4531             : {
    4532             : /* -------------------------------------------------------------------- */
    4533             : /*      Check whether the vector from top left to bottom left           */
    4534             : /*      intersects the line from top right to bottom right.  If this    */
    4535             : /*      is true, then we believe the corner coordinate order was        */
    4536             : /*      written improperly.                                             */
    4537             : /* -------------------------------------------------------------------- */
    4538             : #if 1
    4539         386 :     if (!NITFDoLinesIntersect(psImage->dfULX, psImage->dfULY, psImage->dfLLX,
    4540             :                               psImage->dfLLY, psImage->dfURX, psImage->dfURY,
    4541             :                               psImage->dfLRX, psImage->dfLRY))
    4542         386 :         return;
    4543             :     else
    4544           0 :         CPLDebug("NITF", "It appears the IGEOLO corner coordinates were "
    4545             :                          "written improperly!");
    4546             : #endif
    4547             : 
    4548             :     /* -------------------------------------------------------------------- */
    4549             :     /*      Divide the lat/long extents of this image into four             */
    4550             :     /*      quadrants and assign the corners based on which point falls     */
    4551             :     /*      into which quadrant.  This is intended to correct images        */
    4552             :     /*      with the corner points written improperly.  Unfortunately it    */
    4553             :     /*      also breaks images which are mirrored, or rotated more than     */
    4554             :     /*      90 degrees from simple north up.                                */
    4555             :     /* -------------------------------------------------------------------- */
    4556             :     {
    4557             : 
    4558           0 :         double dfXMax = CPL_MAX(CPL_MAX(psImage->dfULX, psImage->dfURX),
    4559             :                                 CPL_MAX(psImage->dfLRX, psImage->dfLLX));
    4560           0 :         double dfXMin = CPL_MIN(CPL_MIN(psImage->dfULX, psImage->dfURX),
    4561             :                                 CPL_MIN(psImage->dfLRX, psImage->dfLLX));
    4562           0 :         double dfYMax = CPL_MAX(CPL_MAX(psImage->dfULY, psImage->dfURY),
    4563             :                                 CPL_MAX(psImage->dfLRY, psImage->dfLLY));
    4564           0 :         double dfYMin = CPL_MIN(CPL_MIN(psImage->dfULY, psImage->dfURY),
    4565             :                                 CPL_MIN(psImage->dfLRY, psImage->dfLLY));
    4566           0 :         double dfXPivot = (dfXMax + dfXMin) * 0.5;
    4567           0 :         double dfYPivot = (dfYMax + dfYMin) * 0.5;
    4568             : 
    4569           0 :         double dfNewULX = 0., dfNewULY = 0., dfNewURX = 0., dfNewURY = 0.,
    4570           0 :                dfNewLLX = 0., dfNewLLY = 0., dfNewLRX = 0., dfNewLRY = 0.;
    4571           0 :         int bGotUL = FALSE, bGotUR = FALSE, bGotLL = FALSE, bGotLR = FALSE;
    4572           0 :         int iCoord, bChange = FALSE;
    4573             : 
    4574           0 :         for (iCoord = 0; iCoord < 4; iCoord++)
    4575             :         {
    4576           0 :             double *pdfXY = &(psImage->dfULX) + iCoord * 2;
    4577             : 
    4578           0 :             if (pdfXY[0] < dfXPivot && pdfXY[1] < dfYPivot)
    4579             :             {
    4580           0 :                 bGotLL = TRUE;
    4581           0 :                 dfNewLLX = pdfXY[0];
    4582           0 :                 dfNewLLY = pdfXY[1];
    4583           0 :                 bChange |= iCoord != 3;
    4584             :             }
    4585           0 :             else if (pdfXY[0] > dfXPivot && pdfXY[1] < dfYPivot)
    4586             :             {
    4587           0 :                 bGotLR = TRUE;
    4588           0 :                 dfNewLRX = pdfXY[0];
    4589           0 :                 dfNewLRY = pdfXY[1];
    4590           0 :                 bChange |= iCoord != 2;
    4591             :             }
    4592           0 :             else if (pdfXY[0] > dfXPivot && pdfXY[1] > dfYPivot)
    4593             :             {
    4594           0 :                 bGotUR = TRUE;
    4595           0 :                 dfNewURX = pdfXY[0];
    4596           0 :                 dfNewURY = pdfXY[1];
    4597           0 :                 bChange |= iCoord != 1;
    4598             :             }
    4599             :             else
    4600             :             {
    4601           0 :                 bGotUL = TRUE;
    4602           0 :                 dfNewULX = pdfXY[0];
    4603           0 :                 dfNewULY = pdfXY[1];
    4604           0 :                 bChange |= iCoord != 0;
    4605             :             }
    4606             :         }
    4607             : 
    4608           0 :         if (!bGotUL || !bGotUR || !bGotLL || !bGotLR)
    4609             :         {
    4610           0 :             CPLDebug("NITF", "Unable to reorient corner points sensibly in "
    4611             :                              "NITFPossibleIGEOLOReorganization(), discarding "
    4612             :                              "IGEOLO locations.");
    4613           0 :             psImage->bHaveIGEOLO = FALSE;
    4614           0 :             return;
    4615             :         }
    4616             : 
    4617           0 :         if (!bChange)
    4618           0 :             return;
    4619             : 
    4620           0 :         psImage->dfULX = dfNewULX;
    4621           0 :         psImage->dfULY = dfNewULY;
    4622           0 :         psImage->dfURX = dfNewURX;
    4623           0 :         psImage->dfURY = dfNewURY;
    4624           0 :         psImage->dfLRX = dfNewLRX;
    4625           0 :         psImage->dfLRY = dfNewLRY;
    4626           0 :         psImage->dfLLX = dfNewLLX;
    4627           0 :         psImage->dfLLY = dfNewLLY;
    4628             : 
    4629           0 :         CPLDebug("NITF", "IGEOLO corners have been reoriented by "
    4630             :                          "NITFPossibleIGEOLOReorientation().");
    4631             :     }
    4632             : }
    4633             : 
    4634             : /************************************************************************/
    4635             : /*                           NITFReadIMRFCA()                           */
    4636             : /*                                                                      */
    4637             : /*      Read DPPDB IMRFCA TRE (and the associated IMASDA TRE) if it is  */
    4638             : /*      available. IMRFCA RPC coefficients are remapped into RPC00B     */
    4639             : /*      organization.                                                   */
    4640             : /*      See table 68 for IMASDA and table 69 for IMRFCA in              */
    4641             : /*      http://earth-info.nga.mil/publications/specs/printed/89034/89034DPPDB.pdf
    4642             :  */
    4643             : /************************************************************************/
    4644         700 : int NITFReadIMRFCA(NITFImage *psImage, NITFRPC00BInfo *psRPC)
    4645             : {
    4646             :     char szTemp[100];
    4647         700 :     const char *pachTreIMASDA = NULL;
    4648         700 :     const char *pachTreIMRFCA = NULL;
    4649         700 :     double dfTolerance = 1.0e-10;
    4650         700 :     int count = 0;
    4651         700 :     int nTreIMASDASize = 0;
    4652         700 :     int nTreIMRFCASize = 0;
    4653             : 
    4654         700 :     if ((psImage == NULL) || (psRPC == NULL))
    4655           0 :         return FALSE;
    4656             : 
    4657             :     /* Check to see if we have the IMASDA and IMRFCA tag (DPPDB data). */
    4658             : 
    4659         700 :     pachTreIMASDA = NITFFindTRE(psImage->pachTRE, psImage->nTREBytes, "IMASDA",
    4660             :                                 &nTreIMASDASize);
    4661         700 :     pachTreIMRFCA = NITFFindTRE(psImage->pachTRE, psImage->nTREBytes, "IMRFCA",
    4662             :                                 &nTreIMRFCASize);
    4663             : 
    4664         700 :     if ((pachTreIMASDA == NULL) || (pachTreIMRFCA == NULL))
    4665         694 :         return FALSE;
    4666             : 
    4667           6 :     if (nTreIMASDASize < 242 || nTreIMRFCASize < 1760)
    4668             :     {
    4669           4 :         CPLError(CE_Failure, CPLE_AppDefined,
    4670             :                  "Cannot read DPPDB IMASDA/IMRFCA TREs; not enough bytes.");
    4671             : 
    4672           4 :         return FALSE;
    4673             :     }
    4674             : 
    4675             :     /* Parse out the field values. */
    4676             : 
    4677             :     /* Set the errors to 0.0 for now. */
    4678             : 
    4679           2 :     psRPC->ERR_BIAS = 0.0;
    4680           2 :     psRPC->ERR_RAND = 0.0;
    4681             : 
    4682           2 :     psRPC->LONG_OFF = CPLAtof(NITFGetField(szTemp, pachTreIMASDA, 0, 22));
    4683           2 :     psRPC->LAT_OFF = CPLAtof(NITFGetField(szTemp, pachTreIMASDA, 22, 22));
    4684           2 :     psRPC->HEIGHT_OFF = CPLAtof(NITFGetField(szTemp, pachTreIMASDA, 44, 22));
    4685           2 :     psRPC->LONG_SCALE = CPLAtof(NITFGetField(szTemp, pachTreIMASDA, 66, 22));
    4686           2 :     psRPC->LAT_SCALE = CPLAtof(NITFGetField(szTemp, pachTreIMASDA, 88, 22));
    4687           2 :     psRPC->HEIGHT_SCALE = CPLAtof(NITFGetField(szTemp, pachTreIMASDA, 110, 22));
    4688           2 :     psRPC->SAMP_OFF = CPLAtof(NITFGetField(szTemp, pachTreIMASDA, 132, 22));
    4689           2 :     psRPC->LINE_OFF = CPLAtof(NITFGetField(szTemp, pachTreIMASDA, 154, 22));
    4690           2 :     psRPC->SAMP_SCALE = CPLAtof(NITFGetField(szTemp, pachTreIMASDA, 176, 22));
    4691           2 :     psRPC->LINE_SCALE = CPLAtof(NITFGetField(szTemp, pachTreIMASDA, 198, 22));
    4692             : 
    4693           2 :     if (psRPC->HEIGHT_SCALE == 0.0)
    4694           2 :         psRPC->HEIGHT_SCALE = dfTolerance;
    4695           2 :     if (psRPC->LAT_SCALE == 0.0)
    4696           2 :         psRPC->LAT_SCALE = dfTolerance;
    4697           2 :     if (psRPC->LINE_SCALE == 0.0)
    4698           2 :         psRPC->LINE_SCALE = dfTolerance;
    4699           2 :     if (psRPC->LONG_SCALE == 0.0)
    4700           2 :         psRPC->LONG_SCALE = dfTolerance;
    4701           2 :     if (psRPC->SAMP_SCALE == 0.0)
    4702           2 :         psRPC->SAMP_SCALE = dfTolerance;
    4703             : 
    4704           2 :     psRPC->HEIGHT_SCALE = 1.0 / psRPC->HEIGHT_SCALE;
    4705           2 :     psRPC->LAT_SCALE = 1.0 / psRPC->LAT_SCALE;
    4706           2 :     psRPC->LINE_SCALE = 1.0 / psRPC->LINE_SCALE;
    4707           2 :     psRPC->LONG_SCALE = 1.0 / psRPC->LONG_SCALE;
    4708           2 :     psRPC->SAMP_SCALE = 1.0 / psRPC->SAMP_SCALE;
    4709             : 
    4710             :     /* Parse out the RPC coefficients. */
    4711             : 
    4712          42 :     for (count = 0; count < 20; ++count)
    4713             :     {
    4714          40 :         psRPC->SAMP_NUM_COEFF[count] =
    4715          40 :             CPLAtof(NITFGetField(szTemp, pachTreIMRFCA, count * 22, 22));
    4716          40 :         psRPC->SAMP_DEN_COEFF[count] =
    4717          40 :             CPLAtof(NITFGetField(szTemp, pachTreIMRFCA, 440 + count * 22, 22));
    4718             : 
    4719          40 :         psRPC->LINE_NUM_COEFF[count] =
    4720          40 :             CPLAtof(NITFGetField(szTemp, pachTreIMRFCA, 880 + count * 22, 22));
    4721          40 :         psRPC->LINE_DEN_COEFF[count] =
    4722          40 :             CPLAtof(NITFGetField(szTemp, pachTreIMRFCA, 1320 + count * 22, 22));
    4723             :     }
    4724             : 
    4725           2 :     psRPC->SUCCESS = 1;
    4726             : 
    4727           2 :     return TRUE;
    4728             : }

Generated by: LCOV version 1.14