LCOV - code coverage report
Current view: directory - frmts/nitf - nitfimage.c (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 1432 948 66.2 %
Date: 2010-01-09 Functions: 27 26 96.3 %

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

Generated by: LCOV version 1.7