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