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