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