LCOV - code coverage report
Current view: top level - frmts/nitf - nitfimage.c (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 1348 1974 68.3 %
Date: 2024-11-21 22:18:42 Functions: 34 41 82.9 %

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

Generated by: LCOV version 1.14