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