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