LTP GCOV extension - code coverage report
Current view: directory - frmts/nitf - nitfimage.c
Test: gdal_filtered.info
Date: 2010-07-12 Instrumented lines: 1374
Code covered: 79.0 % Executed lines: 1085

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

Generated by: LTP GCOV extension version 1.5