LCOV - code coverage report
Current view: top level - frmts/nitf - nitfimage.c (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 1348 1993 67.6 %
Date: 2025-09-10 17:48:50 Functions: 34 40 85.0 %

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

Generated by: LCOV version 1.14