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