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

Generated by: LCOV version 1.14