Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: NITF Read/Write Library
4 : * Purpose: Module responsible for implementation of most NITFImage
5 : * implementation.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : **********************************************************************
9 : * Copyright (c) 2002, Frank Warmerdam
10 : * Copyright (c) 2007-2013, Even Rouault <even dot rouault at spatialys.com>
11 : *
12 : * SPDX-License-Identifier: MIT
13 : ****************************************************************************/
14 :
15 : #include "gdal.h"
16 : #include "nitflib.h"
17 : #include "mgrs.h"
18 : #include "cpl_vsi.h"
19 : #include "cpl_conv.h"
20 : #include "cpl_string.h"
21 :
22 : #include <inttypes.h>
23 :
24 : #ifndef CPL_IGNORE_RET_VAL_INT_defined
25 : #define CPL_IGNORE_RET_VAL_INT_defined
26 :
27 1356 : CPL_INLINE static void CPL_IGNORE_RET_VAL_INT(CPL_UNUSED int unused)
28 : {
29 1356 : }
30 : #endif
31 :
32 : static int NITFReadIMRFCA(NITFImage *psImage, NITFRPC00BInfo *psRPC);
33 : static char *NITFTrimWhite(char *);
34 : #ifdef CPL_LSB
35 : static void NITFSwapWords(NITFImage *psImage, void *pData, int nWordCount);
36 : #endif
37 :
38 : static void NITFLoadLocationTable(NITFImage *psImage);
39 : static void NITFLoadColormapSubSection(NITFImage *psImage);
40 : static void NITFLoadSubframeMaskTable(NITFImage *psImage,
41 : bool *pbBlockStartRead);
42 : static int NITFLoadVQTables(NITFImage *psImage, int bTryGuessingOffset);
43 : static int NITFReadGEOLOB(NITFImage *psImage);
44 : static void NITFLoadAttributeSection(NITFImage *psImage);
45 : static void NITFPossibleIGEOLOReorientation(NITFImage *psImage);
46 :
47 : void NITFGetGCP(const char *pachCoord, double *pdfXYs, int iCoord);
48 : int NITFReadBLOCKA_GCPs(NITFImage *psImage);
49 :
50 : #define GOTO_header_too_small() \
51 : do \
52 : { \
53 : nFaultyLine = __LINE__; \
54 : goto header_too_small; \
55 : } while (0)
56 :
57 : #define DIGIT_ZERO '0'
58 :
59 : /************************************************************************/
60 : /* NITFImageAccess() */
61 : /************************************************************************/
62 :
63 9195 : NITFImage *NITFImageAccess(NITFFile *psFile, int iSegment)
64 :
65 : {
66 : NITFImage *psImage;
67 : char *pachHeader;
68 : NITFSegmentInfo *psSegInfo;
69 : char szTemp[128];
70 : int nOffset, iBand, i;
71 : int nNICOM;
72 : const char *pszIID1;
73 9195 : int nFaultyLine = -1;
74 :
75 : /* -------------------------------------------------------------------- */
76 : /* Verify segment, and return existing image accessor if there */
77 : /* is one. */
78 : /* -------------------------------------------------------------------- */
79 9195 : if (iSegment < 0 || iSegment >= psFile->nSegmentCount)
80 0 : return NULL;
81 :
82 9195 : psSegInfo = psFile->pasSegmentInfo + iSegment;
83 :
84 9195 : if (!EQUAL(psSegInfo->szSegmentType, "IM"))
85 0 : return NULL;
86 :
87 9195 : if (psSegInfo->hAccess != NULL)
88 440 : return (NITFImage *)psSegInfo->hAccess;
89 :
90 : /* -------------------------------------------------------------------- */
91 : /* Read the image subheader. */
92 : /* -------------------------------------------------------------------- */
93 8755 : if (psSegInfo->nSegmentHeaderSize < 370 + 1)
94 : {
95 0 : CPLError(CE_Failure, CPLE_AppDefined, "Image header too small");
96 0 : return NULL;
97 : }
98 :
99 8755 : pachHeader = (char *)VSI_MALLOC_VERBOSE(psSegInfo->nSegmentHeaderSize);
100 8755 : if (pachHeader == NULL)
101 : {
102 0 : return NULL;
103 : }
104 :
105 8755 : if (VSIFSeekL(psFile->fp, psSegInfo->nSegmentHeaderStart, SEEK_SET) != 0 ||
106 8755 : VSIFReadL(pachHeader, 1, psSegInfo->nSegmentHeaderSize, psFile->fp) !=
107 8755 : psSegInfo->nSegmentHeaderSize)
108 : {
109 0 : CPLError(CE_Failure, CPLE_FileIO,
110 : "Failed to read %u byte image subheader from " CPL_FRMT_GUIB
111 : ".",
112 : psSegInfo->nSegmentHeaderSize, psSegInfo->nSegmentHeaderStart);
113 0 : CPLFree(pachHeader);
114 0 : return NULL;
115 : }
116 :
117 : /* -------------------------------------------------------------------- */
118 : /* Initialize image object. */
119 : /* -------------------------------------------------------------------- */
120 8755 : psImage = (NITFImage *)CPLCalloc(sizeof(NITFImage), 1);
121 :
122 8755 : psImage->psFile = psFile;
123 8755 : psImage->iSegment = iSegment;
124 8755 : psImage->pachHeader = pachHeader;
125 8755 : psImage->nIXSOFL = -1;
126 :
127 8755 : psSegInfo->hAccess = psImage;
128 :
129 : /* -------------------------------------------------------------------- */
130 : /* Collect a variety of information as metadata. */
131 : /* -------------------------------------------------------------------- */
132 : #define GetMD(target, hdr, start, length, name) \
133 : NITFExtractMetadata(&(target->papszMetadata), hdr, start, length, \
134 : "NITF_" #name);
135 :
136 8755 : if (EQUAL(psFile->szVersion, "NITF02.10") ||
137 191 : EQUAL(psFile->szVersion, "NSIF01.00"))
138 : {
139 8590 : GetMD(psImage, pachHeader, 2, 10, IID1);
140 8590 : GetMD(psImage, pachHeader, 12, 14, IDATIM);
141 8590 : GetMD(psImage, pachHeader, 26, 17, TGTID);
142 8590 : GetMD(psImage, pachHeader, 43, 80, IID2);
143 8590 : GetMD(psImage, pachHeader, 123, 1, ISCLAS);
144 8590 : GetMD(psImage, pachHeader, 124, 2, ISCLSY);
145 8590 : GetMD(psImage, pachHeader, 126, 11, ISCODE);
146 8590 : GetMD(psImage, pachHeader, 137, 2, ISCTLH);
147 8590 : GetMD(psImage, pachHeader, 139, 20, ISREL);
148 8590 : GetMD(psImage, pachHeader, 159, 2, ISDCTP);
149 8590 : GetMD(psImage, pachHeader, 161, 8, ISDCDT);
150 8590 : GetMD(psImage, pachHeader, 169, 4, ISDCXM);
151 8590 : GetMD(psImage, pachHeader, 173, 1, ISDG);
152 8590 : GetMD(psImage, pachHeader, 174, 8, ISDGDT);
153 8590 : GetMD(psImage, pachHeader, 182, 43, ISCLTX);
154 8590 : GetMD(psImage, pachHeader, 225, 1, ISCATP);
155 8590 : GetMD(psImage, pachHeader, 226, 40, ISCAUT);
156 8590 : GetMD(psImage, pachHeader, 266, 1, ISCRSN);
157 8590 : GetMD(psImage, pachHeader, 267, 8, ISSRDT);
158 8590 : GetMD(psImage, pachHeader, 275, 15, ISCTLN);
159 : /* skip ENCRYPT - 1 character */
160 8590 : GetMD(psImage, pachHeader, 291, 42, ISORCE);
161 : /* skip NROWS (8), and NCOLS (8) */
162 8590 : GetMD(psImage, pachHeader, 349, 3, PVTYPE);
163 8590 : GetMD(psImage, pachHeader, 352, 8, IREP);
164 8590 : GetMD(psImage, pachHeader, 360, 8, ICAT);
165 8590 : GetMD(psImage, pachHeader, 368, 2, ABPP);
166 8590 : GetMD(psImage, pachHeader, 370, 1, PJUST);
167 : }
168 165 : else if (EQUAL(psFile->szVersion, "NITF02.00"))
169 : {
170 165 : nOffset = 0;
171 165 : GetMD(psImage, pachHeader, 2, 10, IID1);
172 165 : GetMD(psImage, pachHeader, 12, 14, IDATIM);
173 165 : GetMD(psImage, pachHeader, 26, 17, TGTID);
174 165 : GetMD(psImage, pachHeader, 43, 80, ITITLE);
175 165 : GetMD(psImage, pachHeader, 123, 1, ISCLAS);
176 165 : GetMD(psImage, pachHeader, 124, 40, ISCODE);
177 165 : GetMD(psImage, pachHeader, 164, 40, ISCTLH);
178 165 : GetMD(psImage, pachHeader, 204, 40, ISREL);
179 165 : GetMD(psImage, pachHeader, 244, 20, ISCAUT);
180 165 : GetMD(psImage, pachHeader, 264, 20, ISCTLN);
181 165 : GetMD(psImage, pachHeader, 284, 6, ISDWNG);
182 :
183 165 : if (STARTS_WITH_CI(pachHeader + 284, "999998"))
184 : {
185 4 : if (psSegInfo->nSegmentHeaderSize < 370 + 40 + 1)
186 0 : GOTO_header_too_small();
187 4 : GetMD(psImage, pachHeader, 290, 40, ISDEVT);
188 4 : nOffset += 40;
189 : }
190 :
191 : /* skip ENCRYPT - 1 character */
192 165 : GetMD(psImage, pachHeader, 291 + nOffset, 42, ISORCE);
193 : /* skip NROWS (8), and NCOLS (8) */
194 165 : GetMD(psImage, pachHeader, 349 + nOffset, 3, PVTYPE);
195 165 : GetMD(psImage, pachHeader, 352 + nOffset, 8, IREP);
196 165 : GetMD(psImage, pachHeader, 360 + nOffset, 8, ICAT);
197 165 : GetMD(psImage, pachHeader, 368 + nOffset, 2, ABPP);
198 165 : GetMD(psImage, pachHeader, 370 + nOffset, 1, PJUST);
199 : }
200 :
201 : /* -------------------------------------------------------------------- */
202 : /* Does this header have the ISDEVT field? */
203 : /* -------------------------------------------------------------------- */
204 8755 : nOffset = 333;
205 :
206 8755 : if (STARTS_WITH_CI(psFile->szVersion, "NITF01.") ||
207 8755 : STARTS_WITH_CI(pachHeader + 284, "999998"))
208 4 : nOffset += 40;
209 :
210 : /* -------------------------------------------------------------------- */
211 : /* Read lots of header fields. */
212 : /* -------------------------------------------------------------------- */
213 8755 : if (!STARTS_WITH_CI(psFile->szVersion, "NITF01."))
214 : {
215 8755 : if ((int)psSegInfo->nSegmentHeaderSize < nOffset + 35 + 2)
216 0 : GOTO_header_too_small();
217 :
218 8755 : psImage->nRows = atoi(NITFGetField(szTemp, pachHeader, nOffset, 8));
219 8755 : psImage->nCols = atoi(NITFGetField(szTemp, pachHeader, nOffset + 8, 8));
220 :
221 8755 : NITFTrimWhite(
222 8755 : NITFGetField(psImage->szPVType, pachHeader, nOffset + 16, 3));
223 8755 : NITFTrimWhite(
224 8755 : NITFGetField(psImage->szIREP, pachHeader, nOffset + 19, 8));
225 8755 : NITFTrimWhite(
226 8755 : NITFGetField(psImage->szICAT, pachHeader, nOffset + 27, 8));
227 8755 : psImage->nABPP =
228 8755 : atoi(NITFGetField(szTemp, pachHeader, nOffset + 35, 2));
229 : }
230 :
231 8755 : nOffset += 38;
232 :
233 : /* -------------------------------------------------------------------- */
234 : /* Do we have IGEOLO information? In NITF 2.0 (and 1.x) 'N' means */
235 : /* no information, while in 2.1 this is indicated as ' ', and 'N' */
236 : /* means UTM (north). So for 2.0 products we change 'N' to ' ' */
237 : /* to conform to 2.1 conventions. */
238 : /* -------------------------------------------------------------------- */
239 8755 : if ((int)psSegInfo->nSegmentHeaderSize < nOffset + 1)
240 0 : GOTO_header_too_small();
241 :
242 8755 : GetMD(psImage, pachHeader, nOffset, 1, ICORDS);
243 :
244 8755 : psImage->chICORDS = pachHeader[nOffset++];
245 8755 : psImage->bHaveIGEOLO = FALSE;
246 :
247 8755 : if ((STARTS_WITH_CI(psFile->szVersion, "NITF02.0") ||
248 8590 : STARTS_WITH_CI(psFile->szVersion, "NITF01.")) &&
249 165 : psImage->chICORDS == 'N')
250 8 : psImage->chICORDS = ' ';
251 :
252 : /* -------------------------------------------------------------------- */
253 : /* Read the image bounds. */
254 : /* -------------------------------------------------------------------- */
255 8755 : if (psImage->chICORDS != ' ')
256 : {
257 : int iCoord;
258 :
259 386 : psImage->bHaveIGEOLO = TRUE;
260 386 : if ((int)psSegInfo->nSegmentHeaderSize < nOffset + 4 * 15)
261 0 : GOTO_header_too_small();
262 :
263 386 : GetMD(psImage, pachHeader, nOffset, 60, IGEOLO);
264 :
265 386 : psImage->bIsBoxCenterOfPixel = TRUE;
266 1930 : for (iCoord = 0; iCoord < 4; iCoord++)
267 : {
268 1544 : const char *pszCoordPair = pachHeader + nOffset + iCoord * 15;
269 1544 : double *pdfXY = &(psImage->dfULX) + iCoord * 2;
270 :
271 1544 : if (psImage->chICORDS == 'N' || psImage->chICORDS == 'S')
272 : {
273 236 : psImage->nZone = atoi(NITFGetField(szTemp, pszCoordPair, 0, 2));
274 :
275 236 : pdfXY[0] = CPLAtof(NITFGetField(szTemp, pszCoordPair, 2, 6));
276 236 : pdfXY[1] = CPLAtof(NITFGetField(szTemp, pszCoordPair, 8, 7));
277 : }
278 1308 : else if (psImage->chICORDS == 'G' || psImage->chICORDS == 'C')
279 : {
280 : // It is critical to do the fetching of the D, M, S components
281 : // in 3 separate statements, otherwise if NITFGetField() is
282 : // defined in this compilation unit, the MSVC optimizer will
283 : // generate bad code, due to szTemp being overwritten before
284 : // being evaluated by CPLAtof() !
285 1272 : pdfXY[1] = CPLAtof(NITFGetField(szTemp, pszCoordPair, 0, 2));
286 1272 : pdfXY[1] +=
287 1272 : CPLAtof(NITFGetField(szTemp, pszCoordPair, 2, 2)) / 60.0;
288 1272 : pdfXY[1] +=
289 1272 : CPLAtof(NITFGetField(szTemp, pszCoordPair, 4, 2)) / 3600.0;
290 1272 : if (pszCoordPair[6] == 's' || pszCoordPair[6] == 'S')
291 208 : pdfXY[1] *= -1;
292 :
293 : // It is critical to do the fetching of the D, M, S components
294 : // in 3 separate statements, otherwise if NITFGetField() is
295 : // defined in this compilation unit, the MSVC optimizer will
296 : // generate bad code, due to szTemp being overwritten before
297 : // being evaluated by CPLAtof() !
298 1272 : pdfXY[0] = CPLAtof(NITFGetField(szTemp, pszCoordPair, 7, 3));
299 1272 : pdfXY[0] +=
300 1272 : CPLAtof(NITFGetField(szTemp, pszCoordPair, 10, 2)) / 60.0;
301 1272 : pdfXY[0] +=
302 1272 : CPLAtof(NITFGetField(szTemp, pszCoordPair, 12, 2)) / 3600.0;
303 :
304 1272 : if (pszCoordPair[14] == 'w' || pszCoordPair[14] == 'W')
305 386 : pdfXY[0] *= -1;
306 : }
307 36 : else if (psImage->chICORDS == 'D')
308 : { /* 'D' is Decimal Degrees */
309 32 : pdfXY[1] = CPLAtof(NITFGetField(szTemp, pszCoordPair, 0, 7));
310 32 : pdfXY[0] = CPLAtof(NITFGetField(szTemp, pszCoordPair, 7, 8));
311 : }
312 4 : else if (psImage->chICORDS == 'U')
313 : {
314 : /* int err; */
315 : long nZone;
316 : char chHemisphere;
317 4 : NITFGetField(szTemp, pszCoordPair, 0, 15);
318 :
319 4 : CPLDebug("NITF", "IGEOLO = %15.15s", pszCoordPair);
320 4 : /* err = */ Convert_MGRS_To_UTM(szTemp, &nZone, &chHemisphere,
321 : pdfXY + 0, pdfXY + 1);
322 :
323 4 : if (chHemisphere == 'S')
324 0 : nZone = -1 * nZone;
325 :
326 4 : if (psImage->nZone != 0 && psImage->nZone != -100)
327 : {
328 3 : if (nZone != psImage->nZone)
329 : {
330 0 : CPLError(
331 : CE_Warning, CPLE_AppDefined,
332 : "Some IGEOLO points are in different UTM\n"
333 : "zones, but this configuration isn't currently\n"
334 : "supported by GDAL, ignoring IGEOLO.");
335 0 : psImage->nZone = -100;
336 : }
337 : }
338 1 : else if (psImage->nZone == 0)
339 : {
340 1 : psImage->nZone = (int)nZone;
341 : }
342 : }
343 : }
344 :
345 386 : if (psImage->nZone == -100)
346 0 : psImage->nZone = 0;
347 :
348 386 : nOffset += 60;
349 : }
350 : #undef GetMD
351 :
352 : /* -------------------------------------------------------------------- */
353 : /* Should we reorient the IGEOLO points in an attempt to handle */
354 : /* files where they were written in the wrong order? */
355 : /* -------------------------------------------------------------------- */
356 8755 : if (psImage->bHaveIGEOLO)
357 386 : NITFPossibleIGEOLOReorientation(psImage);
358 :
359 : /* -------------------------------------------------------------------- */
360 : /* Read the image comments. */
361 : /* -------------------------------------------------------------------- */
362 : {
363 8755 : if ((int)psSegInfo->nSegmentHeaderSize < nOffset + 1)
364 0 : GOTO_header_too_small();
365 :
366 8755 : nNICOM = atoi(NITFGetField(szTemp, pachHeader, nOffset++, 1));
367 8755 : if ((int)psSegInfo->nSegmentHeaderSize < nOffset + 80 * nNICOM)
368 0 : GOTO_header_too_small();
369 :
370 8755 : char *pszICOM = (char *)CPLMalloc(nNICOM * 80 + 1);
371 8755 : psImage->pszComments =
372 8755 : CPLRecode(NITFGetField(pszICOM, pachHeader, nOffset, 80 * nNICOM),
373 : CPL_ENC_ISO8859_1, CPL_ENC_UTF8);
374 8755 : CPLFree(pszICOM);
375 8755 : nOffset += nNICOM * 80;
376 : }
377 :
378 : /* -------------------------------------------------------------------- */
379 : /* Read more stuff. */
380 : /* -------------------------------------------------------------------- */
381 8755 : if ((int)psSegInfo->nSegmentHeaderSize < nOffset + 2)
382 0 : GOTO_header_too_small();
383 :
384 8755 : NITFGetField(psImage->szIC, pachHeader, nOffset, 2);
385 8755 : nOffset += 2;
386 :
387 8755 : if (psImage->szIC[0] != 'N')
388 : {
389 222 : if ((int)psSegInfo->nSegmentHeaderSize < nOffset + 4)
390 0 : GOTO_header_too_small();
391 :
392 222 : NITFGetField(psImage->szCOMRAT, pachHeader, nOffset, 4);
393 222 : nOffset += 4;
394 : }
395 :
396 : /* NBANDS */
397 8755 : if ((int)psSegInfo->nSegmentHeaderSize < nOffset + 1)
398 0 : GOTO_header_too_small();
399 8755 : psImage->nBands = atoi(NITFGetField(szTemp, pachHeader, nOffset, 1));
400 8755 : nOffset++;
401 :
402 : /* XBANDS */
403 8755 : if (psImage->nBands == 0)
404 : {
405 2 : if ((int)psSegInfo->nSegmentHeaderSize < nOffset + 5)
406 0 : GOTO_header_too_small();
407 2 : psImage->nBands = atoi(NITFGetField(szTemp, pachHeader, nOffset, 5));
408 2 : nOffset += 5;
409 : }
410 :
411 8755 : if (psImage->nBands <= 0)
412 : {
413 0 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid band number");
414 0 : NITFImageDeaccess(psImage);
415 0 : return NULL;
416 : }
417 :
418 : /* -------------------------------------------------------------------- */
419 : /* Read per-band information. */
420 : /* -------------------------------------------------------------------- */
421 8755 : psImage->pasBandInfo = (NITFBandInfo *)VSI_CALLOC_VERBOSE(
422 : sizeof(NITFBandInfo), psImage->nBands);
423 8755 : if (psImage->pasBandInfo == NULL)
424 : {
425 0 : NITFImageDeaccess(psImage);
426 0 : return NULL;
427 : }
428 :
429 157801 : for (iBand = 0; iBand < psImage->nBands; iBand++)
430 : {
431 149046 : NITFBandInfo *psBandInfo = psImage->pasBandInfo + iBand;
432 : int nLUTS;
433 :
434 149046 : if ((int)psSegInfo->nSegmentHeaderSize < nOffset + 2 + 6 + 4 + 1 + 5)
435 0 : GOTO_header_too_small();
436 :
437 149046 : NITFTrimWhite(
438 149046 : NITFGetField(psBandInfo->szIREPBAND, pachHeader, nOffset, 2));
439 149046 : nOffset += 2;
440 :
441 149046 : NITFTrimWhite(
442 149046 : NITFGetField(psBandInfo->szISUBCAT, pachHeader, nOffset, 6));
443 149046 : nOffset += 6;
444 :
445 149046 : nOffset += 4; /* Skip IFCn and IMFLTn */
446 :
447 149046 : nLUTS = atoi(NITFGetField(szTemp, pachHeader, nOffset, 1));
448 149046 : nOffset += 1;
449 :
450 149046 : if (nLUTS == 0)
451 148883 : continue;
452 :
453 163 : psBandInfo->nSignificantLUTEntries =
454 163 : atoi(NITFGetField(szTemp, pachHeader, nOffset, 5));
455 163 : nOffset += 5;
456 :
457 163 : if (psBandInfo->nSignificantLUTEntries < 0 ||
458 163 : psBandInfo->nSignificantLUTEntries > 256)
459 : {
460 0 : CPLError(CE_Warning, CPLE_AppDefined,
461 : "LUT for band %d is corrupted : "
462 : "nSignificantLUTEntries=%d. Truncating to 256",
463 : iBand + 1, psBandInfo->nSignificantLUTEntries);
464 0 : psBandInfo->nSignificantLUTEntries = 256;
465 : }
466 :
467 163 : psBandInfo->nLUTLocation =
468 163 : nOffset + (int)psSegInfo->nSegmentHeaderStart;
469 :
470 163 : psBandInfo->pabyLUT = (unsigned char *)CPLCalloc(768, 1);
471 :
472 163 : if ((int)psSegInfo->nSegmentHeaderSize <
473 163 : nOffset + nLUTS * psBandInfo->nSignificantLUTEntries)
474 0 : GOTO_header_too_small();
475 :
476 163 : memcpy(psBandInfo->pabyLUT, pachHeader + nOffset,
477 163 : psBandInfo->nSignificantLUTEntries);
478 163 : nOffset += psBandInfo->nSignificantLUTEntries;
479 :
480 163 : if (nLUTS == 3)
481 : {
482 163 : memcpy(psBandInfo->pabyLUT + 256, pachHeader + nOffset,
483 163 : psBandInfo->nSignificantLUTEntries);
484 163 : nOffset += psBandInfo->nSignificantLUTEntries;
485 :
486 163 : memcpy(psBandInfo->pabyLUT + 512, pachHeader + nOffset,
487 163 : psBandInfo->nSignificantLUTEntries);
488 163 : nOffset += psBandInfo->nSignificantLUTEntries;
489 : }
490 0 : else if ((nLUTS == 2) && (STARTS_WITH_CI(psImage->szIREP, "MONO")) &&
491 0 : ((STARTS_WITH_CI(psBandInfo->szIREPBAND, "M")) ||
492 0 : (STARTS_WITH_CI(psBandInfo->szIREPBAND, "LU"))))
493 0 : {
494 : int iLUTEntry;
495 0 : double scale = 255.0 / 65535.0;
496 0 : unsigned char *pMSB = NULL;
497 0 : unsigned char *pLSB = NULL;
498 0 : unsigned char *p3rdLUT = NULL;
499 0 : unsigned char scaledVal = 0;
500 0 : unsigned short *pLUTVal = NULL;
501 :
502 : /* In this case, we have two LUTs. The first and second LUTs should
503 : * map respectively to the most */
504 : /* significant byte and the least significant byte of the 16 bit
505 : * values. */
506 :
507 0 : memcpy(psBandInfo->pabyLUT + 256, pachHeader + nOffset,
508 0 : psBandInfo->nSignificantLUTEntries);
509 0 : nOffset += psBandInfo->nSignificantLUTEntries;
510 :
511 0 : pMSB = psBandInfo->pabyLUT;
512 0 : pLSB = psBandInfo->pabyLUT + 256;
513 0 : p3rdLUT = psBandInfo->pabyLUT + 512;
514 : /* E. Rouault: Why 255 and not 256 ? */
515 0 : pLUTVal = (unsigned short *)CPLMalloc(sizeof(short) * 255);
516 :
517 0 : for (iLUTEntry = 0; iLUTEntry < 255; ++iLUTEntry)
518 : {
519 : /* E. Rouault: I don't understand why the following logic is
520 : * endianness dependent. */
521 0 : pLUTVal[iLUTEntry] = ((pMSB[iLUTEntry] << 8) | pLSB[iLUTEntry]);
522 : #ifdef CPL_LSB
523 0 : pLUTVal[iLUTEntry] =
524 0 : ((pLUTVal[iLUTEntry] >> 8) | (pLUTVal[iLUTEntry] << 8));
525 : #endif
526 : }
527 :
528 0 : for (iLUTEntry = 0; iLUTEntry < 255; ++iLUTEntry)
529 : {
530 0 : scaledVal =
531 0 : (unsigned char)ceil((double)(pLUTVal[iLUTEntry] * scale));
532 :
533 0 : pMSB[iLUTEntry] = scaledVal;
534 0 : pLSB[iLUTEntry] = scaledVal;
535 0 : p3rdLUT[iLUTEntry] = scaledVal;
536 : }
537 :
538 0 : CPLFree(pLUTVal);
539 : }
540 : else
541 : {
542 : /* morph greyscale lut into RGB LUT. */
543 0 : memcpy(psBandInfo->pabyLUT + 256, psBandInfo->pabyLUT, 256);
544 0 : memcpy(psBandInfo->pabyLUT + 512, psBandInfo->pabyLUT, 256);
545 : }
546 : }
547 :
548 : /* -------------------------------------------------------------------- */
549 : /* Some files (i.e. NSIF datasets) have truncated image */
550 : /* headers. This has been observed with JPEG compressed */
551 : /* files. In this case guess reasonable values for these */
552 : /* fields. */
553 : /* -------------------------------------------------------------------- */
554 8755 : if (nOffset + 40 > (int)psSegInfo->nSegmentHeaderSize)
555 : {
556 0 : psImage->chIMODE = 'B';
557 0 : psImage->nBlocksPerRow = 1;
558 0 : psImage->nBlocksPerColumn = 1;
559 0 : psImage->nBlockWidth = psImage->nCols;
560 0 : psImage->nBlockHeight = psImage->nRows;
561 0 : psImage->nBitsPerSample = psImage->nABPP;
562 0 : psImage->nIDLVL = 0;
563 0 : psImage->nIALVL = 0;
564 0 : psImage->nILOCRow = 0;
565 0 : psImage->nILOCColumn = 0;
566 0 : psImage->szIMAG[0] = '\0';
567 :
568 0 : nOffset += 40;
569 : }
570 :
571 : /* -------------------------------------------------------------------- */
572 : /* Read more header fields. */
573 : /* -------------------------------------------------------------------- */
574 : else
575 : {
576 8755 : psImage->chIMODE = pachHeader[nOffset + 1];
577 :
578 8755 : psImage->nBlocksPerRow =
579 8755 : atoi(NITFGetField(szTemp, pachHeader, nOffset + 2, 4));
580 8755 : psImage->nBlocksPerColumn =
581 8755 : atoi(NITFGetField(szTemp, pachHeader, nOffset + 6, 4));
582 8755 : psImage->nBlockWidth =
583 8755 : atoi(NITFGetField(szTemp, pachHeader, nOffset + 10, 4));
584 8755 : psImage->nBlockHeight =
585 8755 : atoi(NITFGetField(szTemp, pachHeader, nOffset + 14, 4));
586 :
587 : /* See MIL-STD-2500-C, paragraph 5.4.2.2-d (#3263) */
588 8755 : if (psImage->nBlocksPerRow == 1 && psImage->nBlockWidth == 0)
589 : {
590 4 : psImage->nBlockWidth = psImage->nCols;
591 : }
592 :
593 8755 : if (psImage->nBlocksPerColumn == 1 && psImage->nBlockHeight == 0)
594 : {
595 6 : psImage->nBlockHeight = psImage->nRows;
596 : }
597 :
598 8755 : psImage->nBitsPerSample =
599 8755 : atoi(NITFGetField(szTemp, pachHeader, nOffset + 18, 2));
600 :
601 8755 : if (psImage->nABPP == 0)
602 0 : psImage->nABPP = psImage->nBitsPerSample;
603 :
604 8755 : nOffset += 20;
605 :
606 : /* capture image inset information */
607 :
608 8755 : psImage->nIDLVL =
609 8755 : atoi(NITFGetField(szTemp, pachHeader, nOffset + 0, 3));
610 8755 : psImage->nIALVL =
611 8755 : atoi(NITFGetField(szTemp, pachHeader, nOffset + 3, 3));
612 8755 : psImage->nILOCRow =
613 8755 : atoi(NITFGetField(szTemp, pachHeader, nOffset + 6, 5));
614 8755 : psImage->nILOCColumn =
615 8755 : atoi(NITFGetField(szTemp, pachHeader, nOffset + 11, 5));
616 :
617 8755 : memcpy(psImage->szIMAG, pachHeader + nOffset + 16, 4);
618 8755 : psImage->szIMAG[4] = '\0';
619 :
620 8755 : nOffset += 3; /* IDLVL */
621 8755 : nOffset += 3; /* IALVL */
622 8755 : nOffset += 10; /* ILOC */
623 8755 : nOffset += 4; /* IMAG */
624 : }
625 :
626 8755 : if (psImage->nBitsPerSample <= 0 || psImage->nBlocksPerRow <= 0 ||
627 8755 : psImage->nBlocksPerColumn <= 0 || psImage->nBlockWidth <= 0 ||
628 8755 : psImage->nBlockHeight <= 0 ||
629 8755 : psImage->nBlocksPerRow > INT_MAX / psImage->nBlockWidth ||
630 8755 : psImage->nBlocksPerColumn > INT_MAX / psImage->nBlockHeight ||
631 8755 : psImage->nCols > psImage->nBlocksPerRow * psImage->nBlockWidth ||
632 8755 : psImage->nRows > psImage->nBlocksPerColumn * psImage->nBlockHeight ||
633 8755 : psImage->nBlocksPerRow > INT_MAX / psImage->nBlocksPerColumn ||
634 8755 : psImage->nBlocksPerRow * psImage->nBlocksPerColumn >
635 8755 : INT_MAX / psImage->nBands)
636 : {
637 0 : CPLError(CE_Failure, CPLE_AppDefined,
638 : "Invalid values for block dimension/number");
639 0 : NITFImageDeaccess(psImage);
640 0 : return NULL;
641 : }
642 :
643 8755 : if (psImage->nBlocksPerRow * psImage->nBlocksPerColumn * psImage->nBands >
644 : 1000 * 1000)
645 : {
646 : // Sanity check to avoid allocating too much memory
647 0 : VSIFSeekL(psFile->fp, 0, SEEK_END);
648 : // This is really a very safe bound. A smarter check would taken
649 : // into account the block size as well and/or the size of an entry
650 : // in the offset table.
651 0 : if (VSIFTellL(psFile->fp) <
652 0 : (vsi_l_offset)(psImage->nBlocksPerRow) * psImage->nBlocksPerColumn)
653 : {
654 0 : CPLError(CE_Failure, CPLE_AppDefined,
655 : "File is too small compared to the number of blocks");
656 0 : NITFImageDeaccess(psImage);
657 0 : return NULL;
658 : }
659 : }
660 :
661 : /* -------------------------------------------------------------------- */
662 : /* Override nCols and nRows for NITF 1.1 (not sure why!) */
663 : /* -------------------------------------------------------------------- */
664 8755 : if (STARTS_WITH_CI(psFile->szVersion, "NITF01."))
665 : {
666 0 : psImage->nCols = psImage->nBlocksPerRow * psImage->nBlockWidth;
667 0 : psImage->nRows = psImage->nBlocksPerColumn * psImage->nBlockHeight;
668 : }
669 :
670 : /* -------------------------------------------------------------------- */
671 : /* Read TREs if we have them. */
672 : /* -------------------------------------------------------------------- */
673 8755 : else if (nOffset + 10 <= (int)psSegInfo->nSegmentHeaderSize)
674 : {
675 8755 : int nUserTREBytes, nExtendedTREBytes, nFirstTagUsedLength = 0;
676 :
677 : /* --------------------------------------------------------------------
678 : */
679 : /* Are there user TRE bytes to skip? */
680 : /* --------------------------------------------------------------------
681 : */
682 8755 : nUserTREBytes = atoi(NITFGetField(szTemp, pachHeader, nOffset, 5));
683 8755 : nOffset += 5;
684 :
685 8755 : if (nUserTREBytes > 3 + 11) /* Must have at least one tag */
686 : {
687 158 : if ((int)psSegInfo->nSegmentHeaderSize < nOffset + nUserTREBytes)
688 0 : GOTO_header_too_small();
689 :
690 158 : psImage->nTREBytes = nUserTREBytes - 3;
691 158 : psImage->pachTRE = (char *)CPLMalloc(psImage->nTREBytes);
692 158 : memcpy(psImage->pachTRE, pachHeader + nOffset + 3,
693 158 : psImage->nTREBytes);
694 :
695 158 : nOffset += nUserTREBytes;
696 :
697 : /* pachTRE is a raw copy of the header and is not NUL-terminated,
698 : so sscanf() would read past its end. Parse the 5-byte tag
699 : length field from a NUL-terminated copy. nTREBytes is > 11
700 : here (nUserTREBytes > 14), so bytes 6..10 are present. */
701 : {
702 : char szFirstTagLength[6];
703 158 : memcpy(szFirstTagLength, psImage->pachTRE + 6, 5);
704 158 : szFirstTagLength[5] = '\0';
705 158 : sscanf(szFirstTagLength, "%*5d%n", &nFirstTagUsedLength);
706 : }
707 158 : if (nFirstTagUsedLength != 5)
708 : {
709 2 : CPLError(CE_Warning, CPLE_AppDefined,
710 : "Cannot read User TRE. First tag's length is invalid");
711 2 : CPLFree(psImage->pachTRE);
712 2 : psImage->nTREBytes = 0;
713 2 : psImage->pachTRE = NULL;
714 : }
715 : }
716 : else
717 : {
718 8597 : psImage->nTREBytes = 0;
719 8597 : psImage->pachTRE = NULL;
720 :
721 8597 : if (nUserTREBytes > 0)
722 0 : nOffset += nUserTREBytes;
723 : }
724 :
725 : /* --------------------------------------------------------------------
726 : */
727 : /* Are there managed TRE bytes to recognise? */
728 : /* --------------------------------------------------------------------
729 : */
730 8755 : if ((int)psSegInfo->nSegmentHeaderSize < nOffset + 5)
731 0 : GOTO_header_too_small();
732 8755 : nExtendedTREBytes = atoi(NITFGetField(szTemp, pachHeader, nOffset, 5));
733 8755 : nOffset += 5;
734 :
735 8755 : if (nExtendedTREBytes >= 3)
736 : {
737 180 : if ((int)psSegInfo->nSegmentHeaderSize <
738 180 : nOffset + nExtendedTREBytes)
739 0 : GOTO_header_too_small();
740 :
741 180 : psImage->nIXSOFLOffsetInSubfileHeader = nOffset;
742 : char szIXSOFL[4];
743 180 : memcpy(szIXSOFL, pachHeader + nOffset, 3);
744 180 : szIXSOFL[3] = 0;
745 180 : psImage->nIXSOFL = atoi(szIXSOFL);
746 180 : if (psImage->nIXSOFL != 0)
747 2 : psImage->papszMetadata = CSLSetNameValue(
748 : psImage->papszMetadata, "NITF_IXSOFL", szIXSOFL);
749 :
750 180 : if (nExtendedTREBytes > 3)
751 : {
752 348 : psImage->pachTRE = (char *)CPLRealloc(
753 174 : psImage->pachTRE,
754 174 : psImage->nTREBytes + nExtendedTREBytes - 3);
755 174 : memcpy(psImage->pachTRE + psImage->nTREBytes,
756 174 : pachHeader + nOffset + 3, nExtendedTREBytes - 3);
757 :
758 174 : psImage->nTREBytes += (nExtendedTREBytes - 3);
759 : }
760 : /*nOffset += nExtendedTREBytes;*/
761 : }
762 : }
763 :
764 : /* -------------------------------------------------------------------- */
765 : /* Is there a location table to load? */
766 : /* -------------------------------------------------------------------- */
767 8755 : NITFLoadLocationTable(psImage);
768 :
769 : /* Fix bug #1744 */
770 8755 : if (psImage->nBands == 1)
771 8608 : NITFLoadColormapSubSection(psImage);
772 :
773 : /* -------------------------------------------------------------------- */
774 : /* Setup some image access values. Some of these may not apply */
775 : /* for compressed images, or band interleaved by block images. */
776 : /* -------------------------------------------------------------------- */
777 8755 : if (psImage->nBitsPerSample <= 8)
778 8666 : psImage->nWordSize = 1;
779 89 : else if (psImage->nBitsPerSample <= 16)
780 45 : psImage->nWordSize = 2;
781 44 : else if (psImage->nBitsPerSample <= 32)
782 31 : psImage->nWordSize = 4;
783 : else
784 13 : psImage->nWordSize = psImage->nBitsPerSample / 8;
785 8755 : if (psImage->chIMODE == 'S')
786 : {
787 0 : psImage->nPixelOffset = psImage->nWordSize;
788 0 : psImage->nLineOffset =
789 0 : ((GIntBig)psImage->nBlockWidth * psImage->nBitsPerSample) / 8;
790 0 : psImage->nBlockOffset = psImage->nLineOffset * psImage->nBlockHeight;
791 0 : psImage->nBandOffset = psImage->nBlockOffset * psImage->nBlocksPerRow *
792 0 : psImage->nBlocksPerColumn;
793 : }
794 8755 : else if (psImage->chIMODE == 'P')
795 : {
796 19 : psImage->nPixelOffset = (GIntBig)psImage->nWordSize * psImage->nBands;
797 19 : psImage->nLineOffset = ((GIntBig)psImage->nBlockWidth *
798 19 : psImage->nBitsPerSample * psImage->nBands) /
799 : 8;
800 19 : psImage->nBandOffset = psImage->nWordSize;
801 19 : psImage->nBlockOffset = psImage->nLineOffset * psImage->nBlockHeight;
802 : }
803 8736 : else if (psImage->chIMODE == 'R')
804 : {
805 0 : psImage->nPixelOffset = psImage->nWordSize;
806 0 : psImage->nBandOffset =
807 0 : ((GIntBig)psImage->nBlockWidth * psImage->nBitsPerSample) / 8;
808 0 : psImage->nLineOffset = psImage->nBandOffset * psImage->nBands;
809 0 : psImage->nBlockOffset = psImage->nLineOffset * psImage->nBlockHeight;
810 : }
811 : else /* if( psImage->chIMODE == 'B' ) */
812 : {
813 8736 : psImage->nPixelOffset = psImage->nWordSize;
814 8736 : psImage->nLineOffset =
815 8736 : ((GIntBig)psImage->nBlockWidth * psImage->nBitsPerSample) / 8;
816 8736 : psImage->nBandOffset = psImage->nBlockHeight * psImage->nLineOffset;
817 8736 : psImage->nBlockOffset = psImage->nBandOffset * psImage->nBands;
818 : }
819 :
820 : /* -------------------------------------------------------------------- */
821 : /* Setup block map. */
822 : /* -------------------------------------------------------------------- */
823 :
824 : /* Int overflow already checked above */
825 8755 : psImage->panBlockStart = (GUIntBig *)VSI_CALLOC_VERBOSE(
826 : (size_t)psImage->nBlocksPerRow * psImage->nBlocksPerColumn *
827 : psImage->nBands,
828 : sizeof(GUIntBig));
829 8755 : if (psImage->panBlockStart == NULL)
830 : {
831 0 : NITFImageDeaccess(psImage);
832 0 : return NULL;
833 : }
834 :
835 : /* -------------------------------------------------------------------- */
836 : /* Load subframe mask table if present (typically, for CADRG/CIB */
837 : /* images with IC=C4/M4) */
838 : /* -------------------------------------------------------------------- */
839 8755 : bool bBlockStartRead = false;
840 8755 : NITFLoadSubframeMaskTable(psImage, &bBlockStartRead);
841 :
842 : /* -------------------------------------------------------------------- */
843 : /* Offsets to VQ compressed tiles are based on a fixed block */
844 : /* size, and are offset from the spatial data location kept in */
845 : /* the location table ... which is generally not the beginning */
846 : /* of the image data segment. */
847 : /* -------------------------------------------------------------------- */
848 8755 : if (EQUAL(psImage->szIC, "C4"))
849 : {
850 154 : if (!bBlockStartRead)
851 : {
852 120 : GUIntBig nLocBase = psSegInfo->nSegmentStart;
853 :
854 1560 : for (i = 0; i < psImage->nLocCount; i++)
855 : {
856 1440 : if (psImage->pasLocations[i].nLocId ==
857 : LID_SpatialDataSubsection)
858 120 : nLocBase = psImage->pasLocations[i].nLocOffset;
859 : }
860 :
861 120 : if (nLocBase == psSegInfo->nSegmentStart)
862 0 : CPLError(CE_Warning, CPLE_AppDefined,
863 : "Failed to find spatial data location, guessing.");
864 :
865 4440 : for (i = 0; i < psImage->nBlocksPerRow * psImage->nBlocksPerColumn;
866 4320 : i++)
867 4320 : psImage->panBlockStart[i] = nLocBase + (GUIntBig)(6144) * i;
868 : }
869 : }
870 :
871 : /* -------------------------------------------------------------------- */
872 : /* If there is no block map, just compute directly assuming the */
873 : /* blocks start at the beginning of the image segment, and are */
874 : /* packed tightly with the IMODE organization. */
875 : /* -------------------------------------------------------------------- */
876 8601 : else if (psImage->szIC[0] != 'M' && psImage->szIC[1] != 'M')
877 8594 : {
878 : int iBlockX, iBlockY;
879 :
880 17310 : for (iBlockY = 0; iBlockY < psImage->nBlocksPerColumn; iBlockY++)
881 : {
882 19023 : for (iBlockX = 0; iBlockX < psImage->nBlocksPerRow; iBlockX++)
883 : {
884 164125 : for (iBand = 0; iBand < psImage->nBands; iBand++)
885 : {
886 : int iBlock;
887 :
888 153818 : iBlock = iBlockX + iBlockY * psImage->nBlocksPerRow +
889 153818 : iBand * psImage->nBlocksPerRow *
890 153818 : psImage->nBlocksPerColumn;
891 :
892 153818 : psImage->panBlockStart[iBlock] =
893 153818 : psSegInfo->nSegmentStart +
894 153818 : ((iBlockX + iBlockY * psImage->nBlocksPerRow) *
895 153818 : psImage->nBlockOffset) +
896 153818 : (iBand * psImage->nBandOffset);
897 : }
898 : }
899 : }
900 : }
901 :
902 : /* -------------------------------------------------------------------- */
903 : /* Otherwise we need to read the block map from the beginning */
904 : /* of the image segment. */
905 : /* -------------------------------------------------------------------- */
906 : else
907 : {
908 : GUInt32 nIMDATOFF;
909 : GUInt16 nBMRLNTH, nTMRLNTH, nTPXCDLNTH;
910 : int nBlockCount;
911 7 : int bOK = TRUE;
912 :
913 7 : nBlockCount = psImage->nBlocksPerRow * psImage->nBlocksPerColumn *
914 7 : psImage->nBands;
915 :
916 7 : CPLAssert(psImage->szIC[0] == 'M' || psImage->szIC[1] == 'M');
917 :
918 7 : bOK &= VSIFSeekL(psFile->fp, psSegInfo->nSegmentStart, SEEK_SET) == 0;
919 7 : bOK &= VSIFReadL(&nIMDATOFF, 1, 4, psFile->fp) == 4;
920 7 : bOK &= VSIFReadL(&nBMRLNTH, 1, 2, psFile->fp) == 2;
921 7 : bOK &= VSIFReadL(&nTMRLNTH, 1, 2, psFile->fp) == 2;
922 7 : bOK &= VSIFReadL(&nTPXCDLNTH, 1, 2, psFile->fp) == 2;
923 :
924 7 : CPL_MSBPTR32(&nIMDATOFF);
925 7 : CPL_MSBPTR16(&nBMRLNTH);
926 7 : CPL_MSBPTR16(&nTMRLNTH);
927 7 : CPL_MSBPTR16(&nTPXCDLNTH);
928 :
929 7 : if (nTPXCDLNTH == 8)
930 : {
931 : GByte byNodata;
932 :
933 0 : psImage->bNoDataSet = TRUE;
934 0 : bOK &= VSIFReadL(&byNodata, 1, 1, psFile->fp) == 1;
935 0 : psImage->nNoDataValue = byNodata;
936 : }
937 : else
938 7 : bOK &= VSIFSeekL(psFile->fp, (nTPXCDLNTH + 7) / 8, SEEK_CUR) == 0;
939 :
940 7 : if (nBMRLNTH == 4 && psImage->chIMODE == 'P')
941 2 : {
942 2 : int nStoredBlocks =
943 2 : psImage->nBlocksPerRow * psImage->nBlocksPerColumn;
944 :
945 10 : for (i = 0; bOK && i < nStoredBlocks; i++)
946 : {
947 : GUInt32 l_nOffset;
948 8 : bOK &= VSIFReadL(&l_nOffset, 4, 1, psFile->fp) == 1;
949 8 : CPL_MSBPTR32(&l_nOffset);
950 8 : psImage->panBlockStart[i] = l_nOffset;
951 8 : if (psImage->panBlockStart[i] != UINT_MAX)
952 : {
953 8 : psImage->panBlockStart[i] +=
954 8 : psSegInfo->nSegmentStart + nIMDATOFF;
955 :
956 24 : for (iBand = 1; iBand < psImage->nBands; iBand++)
957 : {
958 16 : psImage->panBlockStart[i + iBand * nStoredBlocks] =
959 16 : psImage->panBlockStart[i] +
960 16 : iBand * psImage->nBandOffset;
961 : }
962 : }
963 : else
964 : {
965 0 : for (iBand = 1; iBand < psImage->nBands; iBand++)
966 0 : psImage->panBlockStart[i + iBand * nStoredBlocks] =
967 : UINT_MAX;
968 : }
969 : }
970 : }
971 5 : else if (nBMRLNTH == 4)
972 : {
973 0 : if (!bBlockStartRead)
974 : {
975 0 : for (i = 0; bOK && i < nBlockCount; i++)
976 : {
977 : GUInt32 l_nOffset;
978 0 : bOK &= VSIFReadL(&l_nOffset, 4, 1, psFile->fp) == 1;
979 0 : CPL_MSBPTR32(&l_nOffset);
980 0 : psImage->panBlockStart[i] = l_nOffset;
981 0 : if (psImage->panBlockStart[i] != UINT_MAX)
982 : {
983 0 : psImage->panBlockStart[i] +=
984 0 : psSegInfo->nSegmentStart + nIMDATOFF;
985 : }
986 : }
987 : }
988 : }
989 : else
990 : {
991 5 : if (EQUAL(psImage->szIC, "M4"))
992 : {
993 1 : if (!bBlockStartRead)
994 : {
995 37 : for (i = 0; i < nBlockCount; i++)
996 36 : psImage->panBlockStart[i] = (GUIntBig)6144 * i +
997 36 : psSegInfo->nSegmentStart +
998 : nIMDATOFF;
999 : }
1000 : }
1001 4 : else if (EQUAL(psImage->szIC, "NM"))
1002 : {
1003 : int iBlockX, iBlockY;
1004 :
1005 8 : for (iBlockY = 0; iBlockY < psImage->nBlocksPerColumn;
1006 4 : iBlockY++)
1007 : {
1008 8 : for (iBlockX = 0; iBlockX < psImage->nBlocksPerRow;
1009 4 : iBlockX++)
1010 : {
1011 8 : for (iBand = 0; iBand < psImage->nBands; iBand++)
1012 : {
1013 : int iBlock;
1014 :
1015 4 : iBlock = iBlockX +
1016 4 : iBlockY * psImage->nBlocksPerRow +
1017 4 : iBand * psImage->nBlocksPerRow *
1018 4 : psImage->nBlocksPerColumn;
1019 :
1020 4 : psImage->panBlockStart[iBlock] =
1021 4 : psSegInfo->nSegmentStart + nIMDATOFF +
1022 4 : ((iBlockX + iBlockY * psImage->nBlocksPerRow) *
1023 4 : psImage->nBlockOffset) +
1024 4 : (iBand * psImage->nBandOffset);
1025 : }
1026 : }
1027 : }
1028 : }
1029 : else
1030 : {
1031 0 : CPLError(
1032 : CE_Warning, CPLE_AppDefined,
1033 : "Unsupported IC value '%s', image access will likely fail.",
1034 0 : psImage->szIC);
1035 : }
1036 : }
1037 7 : if (!bOK)
1038 : {
1039 0 : CPLError(CE_Failure, CPLE_FileIO, "I/O error");
1040 0 : NITFImageDeaccess(psImage);
1041 0 : return NULL;
1042 : }
1043 : }
1044 :
1045 : /* -------------------------------------------------------------------- */
1046 : /* Bug #1751: Add a transparent color if there are none. Absent */
1047 : /* subblocks will be then transparent. */
1048 : /* -------------------------------------------------------------------- */
1049 8755 : if (!psImage->bNoDataSet && psImage->nBands == 1 &&
1050 8504 : psImage->nBitsPerSample == 8)
1051 : {
1052 8384 : NITFBandInfo *psBandInfo = psImage->pasBandInfo;
1053 8384 : if (psBandInfo->nSignificantLUTEntries < 256 - 1 &&
1054 8384 : psBandInfo->pabyLUT != NULL)
1055 : {
1056 55 : if (psBandInfo->nSignificantLUTEntries == 217 &&
1057 0 : psBandInfo->pabyLUT[216] == 0 &&
1058 0 : psBandInfo->pabyLUT[256 + 216] == 0 &&
1059 0 : psBandInfo->pabyLUT[512 + 216] == 0)
1060 : {
1061 0 : psImage->bNoDataSet = TRUE;
1062 0 : psImage->nNoDataValue = psBandInfo->nSignificantLUTEntries - 1;
1063 : }
1064 : else
1065 : {
1066 55 : bool bHasMissingBlock = false;
1067 705 : for (int iBlock = 0; !bHasMissingBlock &&
1068 671 : iBlock < psImage->nBlocksPerRow *
1069 671 : psImage->nBlocksPerColumn;
1070 650 : ++iBlock)
1071 : {
1072 650 : bHasMissingBlock =
1073 650 : (psImage->panBlockStart[iBlock] == UINT_MAX);
1074 : }
1075 55 : if (bHasMissingBlock)
1076 : {
1077 : psBandInfo
1078 34 : ->pabyLUT[0 + psBandInfo->nSignificantLUTEntries] = 0;
1079 : psBandInfo
1080 34 : ->pabyLUT[256 + psBandInfo->nSignificantLUTEntries] = 0;
1081 : psBandInfo
1082 34 : ->pabyLUT[512 + psBandInfo->nSignificantLUTEntries] = 0;
1083 34 : psImage->bNoDataSet = TRUE;
1084 34 : psImage->nNoDataValue = psBandInfo->nSignificantLUTEntries;
1085 : }
1086 : }
1087 : }
1088 : }
1089 :
1090 : /* -------------------------------------------------------------------- */
1091 : /* We override the coordinates found in IGEOLO in case a BLOCKA is */
1092 : /* present. According to the BLOCKA specification, it repeats earth */
1093 : /* coordinates image corner locations described by IGEOLO in the NITF */
1094 : /* image subheader, but provide higher precision. */
1095 : /* -------------------------------------------------------------------- */
1096 :
1097 8755 : NITFReadBLOCKA_GCPs(psImage);
1098 :
1099 : /* -------------------------------------------------------------------- */
1100 : /* We override the coordinates found in IGEOLO in case a GEOLOB is */
1101 : /* present. It provides higher precision lat/long values. */
1102 : /* -------------------------------------------------------------------- */
1103 8755 : NITFReadGEOLOB(psImage);
1104 :
1105 : /* -------------------------------------------------------------------- */
1106 : /* If we have an RPF CoverageSectionSubheader, read the more */
1107 : /* precise bounds from it. */
1108 : /* -------------------------------------------------------------------- */
1109 8755 : for (i = 0; i < psImage->nLocCount; i++)
1110 : {
1111 155 : if (psImage->pasLocations[i].nLocId == LID_CoverageSectionSubheader)
1112 : {
1113 : double adfTarget[8];
1114 :
1115 155 : if (VSIFSeekL(psFile->fp, psImage->pasLocations[i].nLocOffset,
1116 155 : SEEK_SET) != 0 ||
1117 155 : VSIFReadL(adfTarget, 8, 8, psFile->fp) != 8)
1118 : {
1119 0 : CPLError(CE_Failure, CPLE_FileIO, "I/O error");
1120 0 : NITFImageDeaccess(psImage);
1121 0 : return NULL;
1122 : }
1123 :
1124 1395 : for (i = 0; i < 8; i++)
1125 1240 : CPL_MSBPTR64((adfTarget + i));
1126 :
1127 155 : psImage->dfULX = adfTarget[1];
1128 155 : psImage->dfULY = adfTarget[0];
1129 155 : psImage->dfLLX = adfTarget[3];
1130 155 : psImage->dfLLY = adfTarget[2];
1131 155 : psImage->dfURX = adfTarget[5];
1132 155 : psImage->dfURY = adfTarget[4];
1133 155 : psImage->dfLRX = adfTarget[7];
1134 155 : psImage->dfLRY = adfTarget[6];
1135 :
1136 155 : psImage->bIsBoxCenterOfPixel = FALSE; // edge of pixel
1137 :
1138 155 : CPLDebug("NITF", "Got spatial info from CoverageSection");
1139 155 : break;
1140 : }
1141 : }
1142 :
1143 : /* Bug #1750, #2135 and #3383 */
1144 : /* Fix CADRG products like cjnc/cjncz01/000k1023.jn1 (and similar) from NIMA
1145 : * GNCJNCN CDROM: */
1146 : /* this product is crossing meridian 180deg and the upper and lower right
1147 : * longitudes are negative */
1148 : /* while the upper and lower left longitudes are positive which causes
1149 : * problems in OpenEV, etc... */
1150 : /* So we are adjusting the upper and lower right longitudes by setting them
1151 : * above +180 */
1152 : /* Make this test only CADRG specific are there are other NITF profiles
1153 : * where non north-up imagery */
1154 : /* is valid */
1155 8755 : pszIID1 = CSLFetchNameValue(psImage->papszMetadata, "NITF_IID1");
1156 8755 : if ((psImage->chICORDS == 'G' || psImage->chICORDS == 'D') &&
1157 328 : pszIID1 != NULL && EQUAL(pszIID1, "CADRG") &&
1158 155 : (psImage->dfULX > psImage->dfURX && psImage->dfLLX > psImage->dfLRX &&
1159 5 : psImage->dfULY > psImage->dfLLY && psImage->dfURY > psImage->dfLRY))
1160 : {
1161 0 : psImage->dfURX += 360;
1162 0 : psImage->dfLRX += 360;
1163 : }
1164 :
1165 : /* -------------------------------------------------------------------- */
1166 : /* Load RPF attribute metadata if we have it. */
1167 : /* -------------------------------------------------------------------- */
1168 8755 : NITFLoadAttributeSection(psImage);
1169 :
1170 : /* -------------------------------------------------------------------- */
1171 : /* Are the VQ tables to load up? */
1172 : /* -------------------------------------------------------------------- */
1173 8755 : NITFLoadVQTables(psImage, TRUE);
1174 :
1175 8755 : return psImage;
1176 :
1177 0 : header_too_small:
1178 :
1179 0 : CPLError(CE_Failure, CPLE_AppDefined,
1180 : "Image header too small (called from line %d)", nFaultyLine);
1181 0 : NITFImageDeaccess(psImage);
1182 0 : return NULL;
1183 : }
1184 :
1185 : /************************************************************************/
1186 : /* NITFImageDeaccess() */
1187 : /************************************************************************/
1188 :
1189 8755 : void NITFImageDeaccess(NITFImage *psImage)
1190 :
1191 : {
1192 : int iBand;
1193 :
1194 8755 : CPLAssert(psImage->psFile->pasSegmentInfo[psImage->iSegment].hAccess ==
1195 : psImage);
1196 :
1197 8755 : psImage->psFile->pasSegmentInfo[psImage->iSegment].hAccess = NULL;
1198 :
1199 8755 : if (psImage->pasBandInfo)
1200 : {
1201 157801 : for (iBand = 0; iBand < psImage->nBands; iBand++)
1202 149046 : CPLFree(psImage->pasBandInfo[iBand].pabyLUT);
1203 : }
1204 8755 : CPLFree(psImage->pasBandInfo);
1205 8755 : CPLFree(psImage->panBlockStart);
1206 8755 : CPLFree(psImage->pszComments);
1207 8755 : CPLFree(psImage->pachHeader);
1208 8755 : CPLFree(psImage->pachTRE);
1209 8755 : CSLDestroy(psImage->papszMetadata);
1210 :
1211 8755 : CPLFree(psImage->pasLocations);
1212 43775 : for (iBand = 0; iBand < 4; iBand++)
1213 35020 : CPLFree(psImage->apanVQLUT[iBand]);
1214 :
1215 8755 : CPLFree(psImage);
1216 8755 : }
1217 :
1218 : /************************************************************************/
1219 : /* NITFUncompressVQTile() */
1220 : /* */
1221 : /* This code was derived from OSSIM which in turn derived it */
1222 : /* from OpenMap ... open source means sharing! */
1223 : /************************************************************************/
1224 :
1225 756 : static void NITFUncompressVQTile(const NITFImage *psImage,
1226 : const GByte *pabyVQBuf, GByte *pabyResult)
1227 :
1228 : {
1229 756 : int i, j, t, iSrcByte = 0;
1230 :
1231 49140 : for (i = 0; i < 256; i += 4)
1232 : {
1233 1596670 : for (j = 0; j < 256; j += 8)
1234 : {
1235 1548290 : GUInt16 firstByte = pabyVQBuf[iSrcByte++];
1236 1548290 : GUInt16 secondByte = pabyVQBuf[iSrcByte++];
1237 1548290 : GUInt16 thirdByte = pabyVQBuf[iSrcByte++];
1238 :
1239 : /*
1240 : * because dealing with half-bytes is hard, we
1241 : * uncompress two 4x4 tiles at the same time. (a
1242 : * 4x4 tile compressed is 12 bits )
1243 : * this little code was grabbed from openmap software.
1244 : */
1245 :
1246 : /* Get first 12-bit value as index into VQ table */
1247 :
1248 1548290 : GUInt16 val1 = (firstByte << 4) | (secondByte >> 4);
1249 :
1250 : /* Get second 12-bit value as index into VQ table*/
1251 :
1252 1548290 : GUInt16 val2 = ((secondByte & 0x000F) << 8) | thirdByte;
1253 :
1254 7741440 : for (t = 0; t < 4; ++t)
1255 : {
1256 6193150 : GByte *pabyTarget = pabyResult + (i + t) * 256 + j;
1257 :
1258 6193150 : memcpy(pabyTarget, psImage->apanVQLUT[t] + val1, 4);
1259 6193150 : memcpy(pabyTarget + 4, psImage->apanVQLUT[t] + val2, 4);
1260 : }
1261 : } /* for j */
1262 : } /* for i */
1263 756 : }
1264 :
1265 : /************************************************************************/
1266 : /* NITFReadImageBlock() */
1267 : /************************************************************************/
1268 :
1269 3445 : int NITFReadImageBlock(NITFImage *psImage, int nBlockX, int nBlockY, int nBand,
1270 : void *pData)
1271 :
1272 : {
1273 : int nWrkBufSize;
1274 3445 : int iBaseBlock = nBlockX + nBlockY * psImage->nBlocksPerRow;
1275 3445 : int iFullBlock = iBaseBlock + (nBand - 1) * psImage->nBlocksPerRow *
1276 3445 : psImage->nBlocksPerColumn;
1277 :
1278 : /* -------------------------------------------------------------------- */
1279 : /* Special exit conditions. */
1280 : /* -------------------------------------------------------------------- */
1281 3445 : if (nBand == 0)
1282 0 : return BLKREAD_FAIL;
1283 :
1284 3445 : if (psImage->panBlockStart[iFullBlock] == UINT_MAX)
1285 576 : return BLKREAD_NULL;
1286 :
1287 : /* -------------------------------------------------------------------- */
1288 : /* Special case for 1 bit data. NITFRasterBand::IReadBlock() */
1289 : /* already knows how to promote to byte. */
1290 : /* -------------------------------------------------------------------- */
1291 2869 : if ((EQUAL(psImage->szIC, "NC") || EQUAL(psImage->szIC, "NM")) &&
1292 2112 : psImage->nBitsPerSample == 1)
1293 : {
1294 10 : if (nBlockX != 0 || nBlockY != 0)
1295 : {
1296 0 : CPLError(CE_Failure, CPLE_AppDefined,
1297 : "assert nBlockX == 0 && nBlockY == 0 failed\n");
1298 0 : return BLKREAD_FAIL;
1299 : }
1300 10 : if (VSIFSeekL(psImage->psFile->fp,
1301 10 : psImage->panBlockStart[0] +
1302 10 : ((vsi_l_offset)psImage->nBlockWidth *
1303 10 : psImage->nBlockHeight +
1304 10 : 7) /
1305 10 : 8 * (nBand - 1),
1306 10 : SEEK_SET) == 0 &&
1307 10 : VSIFReadL(pData,
1308 10 : (psImage->nBlockWidth * psImage->nBlockHeight + 7) / 8, 1,
1309 10 : psImage->psFile->fp) == 1)
1310 : {
1311 10 : return BLKREAD_OK;
1312 : }
1313 0 : CPLError(CE_Failure, CPLE_FileIO, "I/O error");
1314 0 : return BLKREAD_FAIL;
1315 : }
1316 :
1317 : /* -------------------------------------------------------------------- */
1318 : /* Figure out how big the working buffer will need to be. */
1319 : /* -------------------------------------------------------------------- */
1320 2859 : if (psImage->nBitsPerSample != psImage->nWordSize * 8)
1321 43 : nWrkBufSize =
1322 43 : (int)psImage->nLineOffset * (psImage->nBlockHeight - 1) +
1323 43 : (psImage->nBitsPerSample * (psImage->nBlockWidth) + 7) / 8;
1324 : else
1325 2816 : nWrkBufSize = (int)psImage->nLineOffset * (psImage->nBlockHeight - 1) +
1326 2816 : (int)psImage->nPixelOffset * (psImage->nBlockWidth - 1) +
1327 2816 : psImage->nWordSize;
1328 :
1329 2859 : if (nWrkBufSize == 0)
1330 0 : nWrkBufSize = (psImage->nBlockWidth * psImage->nBlockHeight *
1331 0 : psImage->nBitsPerSample +
1332 : 7) /
1333 : 8;
1334 :
1335 : /* -------------------------------------------------------------------- */
1336 : /* Can we do a direct read into our buffer? */
1337 : /* -------------------------------------------------------------------- */
1338 2859 : if ((size_t)psImage->nWordSize == psImage->nPixelOffset &&
1339 2859 : (size_t)((psImage->nBitsPerSample * psImage->nBlockWidth + 7) / 8) ==
1340 2859 : psImage->nLineOffset &&
1341 2827 : psImage->szIC[0] != 'C' && psImage->szIC[0] != 'M' &&
1342 2070 : psImage->chIMODE != 'P')
1343 : {
1344 2070 : if (VSIFSeekL(psImage->psFile->fp, psImage->panBlockStart[iFullBlock],
1345 2070 : SEEK_SET) != 0 ||
1346 2070 : (int)VSIFReadL(pData, 1, nWrkBufSize, psImage->psFile->fp) !=
1347 : nWrkBufSize)
1348 : {
1349 0 : CPLError(CE_Failure, CPLE_FileIO,
1350 : "Unable to read %d byte block from " CPL_FRMT_GUIB ".",
1351 0 : nWrkBufSize, psImage->panBlockStart[iFullBlock]);
1352 0 : return BLKREAD_FAIL;
1353 : }
1354 : else
1355 : {
1356 : #ifdef CPL_LSB
1357 2070 : NITFSwapWords(psImage, pData,
1358 2070 : psImage->nBlockWidth * psImage->nBlockHeight);
1359 : #endif
1360 :
1361 2070 : return BLKREAD_OK;
1362 : }
1363 : }
1364 :
1365 789 : if (psImage->szIC[0] == 'N')
1366 : {
1367 : /* read all the data needed to get our requested band-block */
1368 32 : if (psImage->nBitsPerSample != psImage->nWordSize * 8)
1369 : {
1370 32 : if (psImage->chIMODE == 'S' ||
1371 32 : (psImage->chIMODE == 'B' && psImage->nBands == 1))
1372 : {
1373 32 : nWrkBufSize = ((psImage->nBlockWidth * psImage->nBlockHeight *
1374 32 : psImage->nBitsPerSample) +
1375 : 7) /
1376 : 8;
1377 32 : if (VSIFSeekL(psImage->psFile->fp,
1378 32 : psImage->panBlockStart[iFullBlock],
1379 32 : SEEK_SET) != 0 ||
1380 32 : (int)VSIFReadL(pData, 1, nWrkBufSize,
1381 32 : psImage->psFile->fp) != nWrkBufSize)
1382 : {
1383 0 : CPLError(CE_Failure, CPLE_FileIO,
1384 : "Unable to read %d byte block from %d.",
1385 : (int)nWrkBufSize,
1386 0 : (int)psImage->panBlockStart[iFullBlock]);
1387 0 : return BLKREAD_FAIL;
1388 : }
1389 :
1390 32 : return BLKREAD_OK;
1391 : }
1392 : else
1393 : {
1394 0 : CPLError(CE_Failure, CPLE_NotSupported,
1395 : "ABPP=%d and IMODE=%c not supported",
1396 0 : psImage->nBitsPerSample, psImage->chIMODE);
1397 0 : return BLKREAD_FAIL;
1398 : }
1399 : }
1400 : }
1401 :
1402 : /* -------------------------------------------------------------------- */
1403 : /* Read the requested information into a temporary buffer and */
1404 : /* pull out what we want. */
1405 : /* -------------------------------------------------------------------- */
1406 757 : if (psImage->szIC[0] == 'N')
1407 : {
1408 0 : GByte *pabyWrkBuf = (GByte *)VSI_MALLOC_VERBOSE(nWrkBufSize);
1409 : int iPixel, iLine;
1410 :
1411 0 : if (pabyWrkBuf == NULL)
1412 : {
1413 0 : return BLKREAD_FAIL;
1414 : }
1415 :
1416 : /* read all the data needed to get our requested band-block */
1417 0 : if (VSIFSeekL(psImage->psFile->fp, psImage->panBlockStart[iFullBlock],
1418 0 : SEEK_SET) != 0 ||
1419 0 : (int)VSIFReadL(pabyWrkBuf, 1, nWrkBufSize, psImage->psFile->fp) !=
1420 : nWrkBufSize)
1421 : {
1422 0 : CPLError(CE_Failure, CPLE_FileIO,
1423 : "Unable to read %d byte block from " CPL_FRMT_GUIB ".",
1424 0 : nWrkBufSize, psImage->panBlockStart[iFullBlock]);
1425 0 : CPLFree(pabyWrkBuf);
1426 0 : return BLKREAD_FAIL;
1427 : }
1428 :
1429 0 : for (iLine = 0; iLine < psImage->nBlockHeight; iLine++)
1430 : {
1431 : GByte *pabySrc, *pabyDst;
1432 :
1433 0 : pabySrc = pabyWrkBuf + iLine * psImage->nLineOffset;
1434 0 : pabyDst = ((GByte *)pData) +
1435 0 : iLine * (psImage->nWordSize * psImage->nBlockWidth);
1436 :
1437 0 : for (iPixel = 0; iPixel < psImage->nBlockWidth; iPixel++)
1438 : {
1439 0 : memcpy(pabyDst + iPixel * psImage->nWordSize,
1440 0 : pabySrc + iPixel * psImage->nPixelOffset,
1441 0 : psImage->nWordSize);
1442 : }
1443 : }
1444 :
1445 : #ifdef CPL_LSB
1446 0 : NITFSwapWords(psImage, pData,
1447 0 : psImage->nBlockWidth * psImage->nBlockHeight);
1448 : #endif
1449 :
1450 0 : CPLFree(pabyWrkBuf);
1451 :
1452 0 : return BLKREAD_OK;
1453 : }
1454 :
1455 : /* -------------------------------------------------------------------- */
1456 : /* Handle VQ compression. The VQ compression basically keeps a */
1457 : /* 64x64 array of 12bit code words. Each code word expands to */
1458 : /* a predefined 4x4 8 bit per pixel pattern. */
1459 : /* -------------------------------------------------------------------- */
1460 757 : else if (EQUAL(psImage->szIC, "C4") || EQUAL(psImage->szIC, "M4"))
1461 : {
1462 : GByte abyVQCoded[6144];
1463 :
1464 756 : if (psImage->apanVQLUT[0] == NULL)
1465 : {
1466 0 : CPLError(CE_Failure, CPLE_NotSupported,
1467 : "File lacks VQ LUTs, unable to decode imagery.");
1468 0 : return BLKREAD_FAIL;
1469 : }
1470 756 : if (psImage->nBlockWidth != 256 || psImage->nBlockHeight != 256)
1471 : {
1472 0 : CPLError(CE_Failure, CPLE_NotSupported,
1473 : "Invalid block dimension for VQ compressed data.");
1474 0 : return BLKREAD_FAIL;
1475 : }
1476 :
1477 : /* Read the codewords */
1478 756 : if (VSIFSeekL(psImage->psFile->fp, psImage->panBlockStart[iFullBlock],
1479 756 : SEEK_SET) != 0 ||
1480 756 : VSIFReadL(abyVQCoded, 1, sizeof(abyVQCoded), psImage->psFile->fp) !=
1481 : sizeof(abyVQCoded))
1482 : {
1483 0 : CPLError(CE_Failure, CPLE_FileIO,
1484 : "Unable to read %d byte block from " CPL_FRMT_GUIB ".",
1485 : (int)sizeof(abyVQCoded),
1486 0 : psImage->panBlockStart[iFullBlock]);
1487 0 : return BLKREAD_FAIL;
1488 : }
1489 :
1490 756 : NITFUncompressVQTile(psImage, abyVQCoded, pData);
1491 :
1492 756 : return BLKREAD_OK;
1493 : }
1494 :
1495 : /* -------------------------------------------------------------------- */
1496 : /* Handle ARIDPCM compression. */
1497 : /* -------------------------------------------------------------------- */
1498 1 : else if (EQUAL(psImage->szIC, "C2") || EQUAL(psImage->szIC, "M2"))
1499 : {
1500 : GIntBig nSignedRawBytes;
1501 : size_t nRawBytes;
1502 : NITFSegmentInfo *psSegInfo;
1503 : int success;
1504 : GByte *pabyRawData;
1505 :
1506 0 : if (psImage->nBitsPerSample != 8)
1507 : {
1508 0 : CPLError(
1509 : CE_Failure, CPLE_AppDefined,
1510 : "Unsupported bits per sample value (%d) for C2/M2 compression",
1511 : psImage->nBitsPerSample);
1512 0 : return BLKREAD_FAIL;
1513 : }
1514 :
1515 0 : if (iFullBlock < psImage->nBlocksPerRow * psImage->nBlocksPerColumn *
1516 0 : psImage->nBands -
1517 : 1)
1518 : {
1519 0 : nSignedRawBytes = (GIntBig)psImage->panBlockStart[iFullBlock + 1] -
1520 0 : (GIntBig)psImage->panBlockStart[iFullBlock];
1521 : }
1522 : else
1523 : {
1524 0 : psSegInfo = psImage->psFile->pasSegmentInfo + psImage->iSegment;
1525 0 : nSignedRawBytes = (GIntBig)psSegInfo->nSegmentStart +
1526 0 : (GIntBig)psSegInfo->nSegmentSize -
1527 0 : (GIntBig)psImage->panBlockStart[iFullBlock];
1528 : }
1529 0 : if (nSignedRawBytes <= 0 || nSignedRawBytes > INT_MAX)
1530 : {
1531 0 : CPLError(CE_Failure, CPLE_AppDefined,
1532 : "Invalid block size : " CPL_FRMT_GIB, nSignedRawBytes);
1533 0 : return BLKREAD_FAIL;
1534 : }
1535 :
1536 0 : nRawBytes = (size_t)nSignedRawBytes;
1537 0 : pabyRawData = (GByte *)VSI_MALLOC_VERBOSE(nRawBytes);
1538 0 : if (pabyRawData == NULL)
1539 : {
1540 0 : return BLKREAD_FAIL;
1541 : }
1542 :
1543 : /* Read the codewords */
1544 0 : if (VSIFSeekL(psImage->psFile->fp, psImage->panBlockStart[iFullBlock],
1545 0 : SEEK_SET) != 0 ||
1546 0 : VSIFReadL(pabyRawData, 1, nRawBytes, psImage->psFile->fp) !=
1547 : nRawBytes)
1548 : {
1549 0 : CPLError(CE_Failure, CPLE_FileIO,
1550 : "Unable to read %d byte block from " CPL_FRMT_GUIB ".",
1551 0 : (int)nRawBytes, psImage->panBlockStart[iFullBlock]);
1552 0 : CPLFree(pabyRawData);
1553 0 : return BLKREAD_FAIL;
1554 : }
1555 :
1556 : success =
1557 0 : NITFUncompressARIDPCM(psImage, pabyRawData, (int)nRawBytes, pData);
1558 :
1559 0 : CPLFree(pabyRawData);
1560 :
1561 0 : if (success)
1562 0 : return BLKREAD_OK;
1563 : else
1564 0 : return BLKREAD_FAIL;
1565 : }
1566 :
1567 : /* -------------------------------------------------------------------- */
1568 : /* Handle BILEVEL (C1) compression. */
1569 : /* -------------------------------------------------------------------- */
1570 1 : else if (EQUAL(psImage->szIC, "C1") || EQUAL(psImage->szIC, "M1"))
1571 : {
1572 : #ifdef HAVE_TIFF
1573 : GIntBig nSignedRawBytes;
1574 : size_t nRawBytes;
1575 : NITFSegmentInfo *psSegInfo;
1576 : int success;
1577 : GByte *pabyRawData;
1578 :
1579 1 : if (psImage->nBitsPerSample != 1)
1580 : {
1581 0 : CPLError(CE_Failure, CPLE_AppDefined,
1582 : "Invalid bits per sample value (%d) for C1/M1 compression",
1583 : psImage->nBitsPerSample);
1584 0 : return BLKREAD_FAIL;
1585 : }
1586 :
1587 1 : if (iFullBlock < psImage->nBlocksPerRow * psImage->nBlocksPerColumn *
1588 1 : psImage->nBands -
1589 : 1)
1590 : {
1591 0 : nSignedRawBytes = (GIntBig)psImage->panBlockStart[iFullBlock + 1] -
1592 0 : (GIntBig)psImage->panBlockStart[iFullBlock];
1593 : }
1594 : else
1595 : {
1596 1 : psSegInfo = psImage->psFile->pasSegmentInfo + psImage->iSegment;
1597 1 : nSignedRawBytes = (GIntBig)psSegInfo->nSegmentStart +
1598 1 : (GIntBig)psSegInfo->nSegmentSize -
1599 1 : (GIntBig)psImage->panBlockStart[iFullBlock];
1600 : }
1601 1 : if (nSignedRawBytes <= 0 || nSignedRawBytes > INT_MAX)
1602 : {
1603 0 : CPLError(CE_Failure, CPLE_AppDefined,
1604 : "Invalid block size : " CPL_FRMT_GIB, nSignedRawBytes);
1605 0 : return BLKREAD_FAIL;
1606 : }
1607 :
1608 1 : nRawBytes = (size_t)nSignedRawBytes;
1609 1 : pabyRawData = (GByte *)VSI_MALLOC_VERBOSE(nRawBytes);
1610 1 : if (pabyRawData == NULL)
1611 : {
1612 0 : return BLKREAD_FAIL;
1613 : }
1614 :
1615 : /* Read the codewords */
1616 1 : if (VSIFSeekL(psImage->psFile->fp, psImage->panBlockStart[iFullBlock],
1617 1 : SEEK_SET) != 0 ||
1618 1 : VSIFReadL(pabyRawData, 1, nRawBytes, psImage->psFile->fp) !=
1619 : nRawBytes)
1620 : {
1621 0 : CPLError(CE_Failure, CPLE_FileIO,
1622 : "Unable to read %d byte block from " CPL_FRMT_GUIB ".",
1623 0 : (int)nRawBytes, psImage->panBlockStart[iFullBlock]);
1624 0 : CPLFree(pabyRawData);
1625 0 : return BLKREAD_FAIL;
1626 : }
1627 :
1628 : success =
1629 1 : NITFUncompressBILEVEL(psImage, pabyRawData, (int)nRawBytes, pData);
1630 :
1631 1 : CPLFree(pabyRawData);
1632 :
1633 1 : if (success)
1634 1 : return BLKREAD_OK;
1635 : else
1636 0 : return BLKREAD_FAIL;
1637 : #else
1638 : CPLError(CE_Failure, CPLE_NotSupported,
1639 : "BILEVEL compression not supported because of lack of "
1640 : "TIFF support");
1641 : return BLKREAD_FAIL;
1642 : #endif
1643 : }
1644 :
1645 : /* -------------------------------------------------------------------- */
1646 : /* Report unsupported compression scheme(s). */
1647 : /* -------------------------------------------------------------------- */
1648 0 : else if (atoi(psImage->szIC + 1) > 0)
1649 : {
1650 0 : CPLError(CE_Failure, CPLE_NotSupported,
1651 : "Unsupported imagery compression format %s in NITF library.",
1652 0 : psImage->szIC);
1653 0 : return BLKREAD_FAIL;
1654 : }
1655 :
1656 0 : return BLKREAD_FAIL;
1657 : }
1658 :
1659 : /************************************************************************/
1660 : /* NITFWriteImageBlock() */
1661 : /************************************************************************/
1662 :
1663 644 : int NITFWriteImageBlock(NITFImage *psImage, int nBlockX, int nBlockY, int nBand,
1664 : void *pData)
1665 :
1666 : {
1667 : GUIntBig nWrkBufSize;
1668 644 : int iBaseBlock = nBlockX + nBlockY * psImage->nBlocksPerRow;
1669 644 : int iFullBlock = iBaseBlock + (nBand - 1) * psImage->nBlocksPerRow *
1670 644 : psImage->nBlocksPerColumn;
1671 :
1672 644 : if (nBand == 0)
1673 0 : return BLKREAD_FAIL;
1674 :
1675 644 : nWrkBufSize = psImage->nLineOffset * (psImage->nBlockHeight - 1) +
1676 644 : psImage->nPixelOffset * (psImage->nBlockWidth - 1) +
1677 644 : psImage->nWordSize;
1678 :
1679 644 : if (nWrkBufSize == 0)
1680 0 : nWrkBufSize = ((GUIntBig)psImage->nBlockWidth * psImage->nBlockHeight *
1681 0 : psImage->nBitsPerSample +
1682 : 7) /
1683 : 8;
1684 :
1685 : /* -------------------------------------------------------------------- */
1686 : /* Can we do a direct read into our buffer? */
1687 : /* -------------------------------------------------------------------- */
1688 644 : if ((size_t)psImage->nWordSize == psImage->nPixelOffset &&
1689 644 : (size_t)(psImage->nWordSize * psImage->nBlockWidth) ==
1690 644 : psImage->nLineOffset &&
1691 644 : psImage->szIC[0] != 'C' && psImage->szIC[0] != 'M')
1692 : {
1693 : #ifdef CPL_LSB
1694 644 : NITFSwapWords(psImage, pData,
1695 644 : psImage->nBlockWidth * psImage->nBlockHeight);
1696 : #endif
1697 :
1698 644 : if (VSIFSeekL(psImage->psFile->fp, psImage->panBlockStart[iFullBlock],
1699 644 : SEEK_SET) != 0 ||
1700 644 : (GUIntBig)VSIFWriteL(pData, 1, (size_t)nWrkBufSize,
1701 644 : psImage->psFile->fp) != nWrkBufSize)
1702 : {
1703 0 : CPLError(CE_Failure, CPLE_FileIO,
1704 : "Unable to write " CPL_FRMT_GUIB
1705 : " byte block from " CPL_FRMT_GUIB ".",
1706 0 : nWrkBufSize, psImage->panBlockStart[iFullBlock]);
1707 0 : return BLKREAD_FAIL;
1708 : }
1709 : else
1710 : {
1711 : #ifdef CPL_LSB
1712 : /* restore byte order to original */
1713 644 : NITFSwapWords(psImage, pData,
1714 644 : psImage->nBlockWidth * psImage->nBlockHeight);
1715 : #endif
1716 :
1717 644 : return BLKREAD_OK;
1718 : }
1719 : }
1720 :
1721 : /* -------------------------------------------------------------------- */
1722 : /* Other forms not supported at this time. */
1723 : /* -------------------------------------------------------------------- */
1724 0 : CPLError(CE_Failure, CPLE_NotSupported,
1725 : "Mapped, interleaved and compressed NITF forms not supported\n"
1726 : "for writing at this time.");
1727 :
1728 0 : return BLKREAD_FAIL;
1729 : }
1730 :
1731 : /************************************************************************/
1732 : /* NITFReadImageLine() */
1733 : /************************************************************************/
1734 :
1735 16551 : int NITFReadImageLine(NITFImage *psImage, int nLine, int nBand, void *pData)
1736 :
1737 : {
1738 : GUIntBig nLineOffsetInFile;
1739 : size_t nLineSize;
1740 : unsigned char *pabyLineBuf;
1741 :
1742 16551 : if (nBand == 0)
1743 0 : return BLKREAD_FAIL;
1744 :
1745 16551 : if (psImage->nBlocksPerRow != 1 || psImage->nBlocksPerColumn != 1)
1746 : {
1747 0 : CPLError(CE_Failure, CPLE_AppDefined,
1748 : "Scanline access not supported on tiled NITF files.");
1749 0 : return BLKREAD_FAIL;
1750 : }
1751 :
1752 16551 : if (psImage->nBlockWidth < psImage->nCols)
1753 : {
1754 0 : CPLError(CE_Failure, CPLE_AppDefined,
1755 : "For scanline access, block width cannot be lesser than the "
1756 : "number of columns.");
1757 0 : return BLKREAD_FAIL;
1758 : }
1759 :
1760 16551 : if (!EQUAL(psImage->szIC, "NC"))
1761 : {
1762 0 : CPLError(CE_Failure, CPLE_AppDefined,
1763 : "Scanline access not supported on compressed NITF files.");
1764 0 : return BLKREAD_FAIL;
1765 : }
1766 :
1767 : /* -------------------------------------------------------------------- */
1768 : /* Workout location and size of data in file. */
1769 : /* -------------------------------------------------------------------- */
1770 16551 : nLineOffsetInFile = psImage->panBlockStart[0] +
1771 16551 : psImage->nLineOffset * nLine +
1772 16551 : psImage->nBandOffset * (nBand - 1);
1773 :
1774 16551 : nLineSize = (size_t)psImage->nPixelOffset * (psImage->nBlockWidth - 1) +
1775 16551 : psImage->nWordSize;
1776 :
1777 16551 : if (nLineSize == 0 || psImage->nWordSize * 8 != psImage->nBitsPerSample)
1778 7 : nLineSize = (psImage->nBlockWidth * psImage->nBitsPerSample + 7) / 8;
1779 :
1780 16551 : if (VSIFSeekL(psImage->psFile->fp, nLineOffsetInFile, SEEK_SET) != 0)
1781 0 : return BLKREAD_FAIL;
1782 :
1783 : /* -------------------------------------------------------------------- */
1784 : /* Can we do a direct read into our buffer. */
1785 : /* -------------------------------------------------------------------- */
1786 16551 : if ((psImage->nBitsPerSample % 8) != 0 ||
1787 16544 : ((size_t)psImage->nWordSize == psImage->nPixelOffset &&
1788 16469 : (size_t)(psImage->nWordSize * psImage->nBlockWidth) ==
1789 16469 : psImage->nLineOffset))
1790 : {
1791 16476 : if (VSIFReadL(pData, 1, nLineSize, psImage->psFile->fp) != nLineSize)
1792 : {
1793 0 : CPLError(CE_Failure, CPLE_FileIO,
1794 : "Unable to read %d bytes for line %d.", (int)nLineSize,
1795 : nLine);
1796 0 : return BLKREAD_FAIL;
1797 : }
1798 :
1799 : #ifdef CPL_LSB
1800 16476 : NITFSwapWords(psImage, pData, psImage->nBlockWidth);
1801 : #endif
1802 :
1803 16476 : return BLKREAD_OK;
1804 : }
1805 :
1806 : /* -------------------------------------------------------------------- */
1807 : /* Allocate a buffer for all the interleaved data, and read */
1808 : /* it. */
1809 : /* -------------------------------------------------------------------- */
1810 75 : pabyLineBuf = (unsigned char *)VSI_MALLOC_VERBOSE(nLineSize);
1811 75 : if (pabyLineBuf == NULL)
1812 : {
1813 0 : return BLKREAD_FAIL;
1814 : }
1815 :
1816 75 : if (VSIFReadL(pabyLineBuf, 1, nLineSize, psImage->psFile->fp) != nLineSize)
1817 : {
1818 0 : CPLError(CE_Failure, CPLE_FileIO,
1819 : "Unable to read %d bytes for line %d.", (int)nLineSize, nLine);
1820 0 : CPLFree(pabyLineBuf);
1821 0 : return BLKREAD_FAIL;
1822 : }
1823 :
1824 : /* -------------------------------------------------------------------- */
1825 : /* Copy the desired data out of the interleaved buffer. */
1826 : /* -------------------------------------------------------------------- */
1827 : {
1828 : GByte *pabySrc, *pabyDst;
1829 : int iPixel;
1830 :
1831 75 : pabySrc = pabyLineBuf;
1832 75 : pabyDst = ((GByte *)pData);
1833 :
1834 19275 : for (iPixel = 0; iPixel < psImage->nBlockWidth; iPixel++)
1835 : {
1836 19200 : memcpy(pabyDst + iPixel * psImage->nWordSize,
1837 19200 : pabySrc + iPixel * psImage->nPixelOffset,
1838 19200 : psImage->nWordSize);
1839 : }
1840 :
1841 : #ifdef CPL_LSB
1842 75 : NITFSwapWords(psImage, pabyDst, psImage->nBlockWidth);
1843 : #endif
1844 : }
1845 :
1846 75 : CPLFree(pabyLineBuf);
1847 :
1848 75 : return BLKREAD_OK;
1849 : }
1850 :
1851 : /************************************************************************/
1852 : /* NITFWriteImageLine() */
1853 : /************************************************************************/
1854 :
1855 16881 : int NITFWriteImageLine(NITFImage *psImage, int nLine, int nBand, void *pData)
1856 :
1857 : {
1858 : GUIntBig nLineOffsetInFile;
1859 : size_t nLineSize;
1860 : unsigned char *pabyLineBuf;
1861 :
1862 16881 : if (nBand == 0)
1863 0 : return BLKREAD_FAIL;
1864 :
1865 16881 : if (psImage->nBlocksPerRow != 1 || psImage->nBlocksPerColumn != 1)
1866 : {
1867 0 : CPLError(CE_Failure, CPLE_AppDefined,
1868 : "Scanline access not supported on tiled NITF files.");
1869 0 : return BLKREAD_FAIL;
1870 : }
1871 :
1872 16881 : if (psImage->nBlockWidth < psImage->nCols)
1873 : {
1874 0 : CPLError(CE_Failure, CPLE_AppDefined,
1875 : "For scanline access, block width cannot be lesser than the "
1876 : "number of columns.");
1877 0 : return BLKREAD_FAIL;
1878 : }
1879 :
1880 16881 : if (!EQUAL(psImage->szIC, "NC"))
1881 : {
1882 0 : CPLError(CE_Failure, CPLE_AppDefined,
1883 : "Scanline access not supported on compressed NITF files.");
1884 0 : return BLKREAD_FAIL;
1885 : }
1886 :
1887 : /* -------------------------------------------------------------------- */
1888 : /* Workout location and size of data in file. */
1889 : /* -------------------------------------------------------------------- */
1890 16881 : nLineOffsetInFile = psImage->panBlockStart[0] +
1891 16881 : psImage->nLineOffset * nLine +
1892 16881 : psImage->nBandOffset * (nBand - 1);
1893 :
1894 16881 : nLineSize = (size_t)psImage->nPixelOffset * (psImage->nBlockWidth - 1) +
1895 16881 : psImage->nWordSize;
1896 :
1897 16881 : if (VSIFSeekL(psImage->psFile->fp, nLineOffsetInFile, SEEK_SET) != 0)
1898 : {
1899 0 : CPLError(CE_Failure, CPLE_FileIO, "I/O error");
1900 0 : return BLKREAD_FAIL;
1901 : }
1902 :
1903 : /* -------------------------------------------------------------------- */
1904 : /* Can we do a direct write into our buffer. */
1905 : /* -------------------------------------------------------------------- */
1906 16881 : if ((size_t)psImage->nWordSize == psImage->nPixelOffset &&
1907 16806 : (size_t)(psImage->nWordSize * psImage->nBlockWidth) ==
1908 16806 : psImage->nLineOffset)
1909 : {
1910 : #ifdef CPL_LSB
1911 16806 : NITFSwapWords(psImage, pData, psImage->nBlockWidth);
1912 : #endif
1913 :
1914 16806 : if (VSIFWriteL(pData, 1, nLineSize, psImage->psFile->fp) != nLineSize)
1915 : {
1916 0 : CPLError(CE_Failure, CPLE_FileIO, "I/O error");
1917 0 : return BLKREAD_FAIL;
1918 : }
1919 :
1920 : #ifdef CPL_LSB
1921 16806 : NITFSwapWords(psImage, pData, psImage->nBlockWidth);
1922 : #endif
1923 :
1924 16806 : return BLKREAD_OK;
1925 : }
1926 :
1927 : /* -------------------------------------------------------------------- */
1928 : /* Allocate a buffer for all the interleaved data, and read */
1929 : /* it. */
1930 : /* -------------------------------------------------------------------- */
1931 75 : pabyLineBuf = (unsigned char *)VSI_MALLOC_VERBOSE(nLineSize);
1932 75 : if (pabyLineBuf == NULL)
1933 : {
1934 0 : return BLKREAD_FAIL;
1935 : }
1936 :
1937 75 : if (VSIFReadL(pabyLineBuf, 1, nLineSize, psImage->psFile->fp) != nLineSize)
1938 : {
1939 0 : memset(pabyLineBuf, 0, nLineSize);
1940 : }
1941 :
1942 : /* -------------------------------------------------------------------- */
1943 : /* Copy the desired data into the interleaved buffer. */
1944 : /* -------------------------------------------------------------------- */
1945 : {
1946 : GByte *pabySrc, *pabyDst;
1947 : int iPixel;
1948 :
1949 75 : pabyDst = pabyLineBuf;
1950 75 : pabySrc = ((GByte *)pData);
1951 :
1952 : #ifdef CPL_LSB
1953 75 : NITFSwapWords(psImage, pData, psImage->nBlockWidth);
1954 : #endif
1955 :
1956 19275 : for (iPixel = 0; iPixel < psImage->nBlockWidth; iPixel++)
1957 : {
1958 19200 : memcpy(pabyDst + iPixel * psImage->nPixelOffset,
1959 19200 : pabySrc + iPixel * psImage->nWordSize, psImage->nWordSize);
1960 : }
1961 :
1962 : #ifdef CPL_LSB
1963 75 : NITFSwapWords(psImage, pData, psImage->nBlockWidth);
1964 : #endif
1965 : }
1966 :
1967 : /* -------------------------------------------------------------------- */
1968 : /* Write the results back out. */
1969 : /* -------------------------------------------------------------------- */
1970 150 : if (VSIFSeekL(psImage->psFile->fp, nLineOffsetInFile, SEEK_SET) != 0 ||
1971 75 : VSIFWriteL(pabyLineBuf, 1, nLineSize, psImage->psFile->fp) != nLineSize)
1972 : {
1973 0 : CPLFree(pabyLineBuf);
1974 0 : CPLError(CE_Failure, CPLE_FileIO, "I/O error");
1975 0 : return BLKREAD_FAIL;
1976 : }
1977 75 : CPLFree(pabyLineBuf);
1978 :
1979 75 : return BLKREAD_OK;
1980 : }
1981 :
1982 : /************************************************************************/
1983 : /* NITFEncodeDMSLoc() */
1984 : /************************************************************************/
1985 :
1986 808 : static void NITFEncodeDMSLoc(char *pszTarget, size_t nTargetLen, double dfValue,
1987 : const char *pszAxis)
1988 :
1989 : {
1990 : char chHemisphere;
1991 : int nDegrees, nMinutes, nSeconds;
1992 :
1993 808 : if (EQUAL(pszAxis, "Lat"))
1994 : {
1995 404 : if (dfValue < 0.0)
1996 70 : chHemisphere = 'S';
1997 : else
1998 334 : chHemisphere = 'N';
1999 : }
2000 : else
2001 : {
2002 404 : if (dfValue < 0.0)
2003 204 : chHemisphere = 'W';
2004 : else
2005 200 : chHemisphere = 'E';
2006 : }
2007 :
2008 808 : dfValue = fabs(dfValue);
2009 :
2010 808 : nDegrees = (int)dfValue;
2011 808 : dfValue = (dfValue - nDegrees) * 60.0;
2012 :
2013 808 : nMinutes = (int)dfValue;
2014 808 : dfValue = (dfValue - nMinutes) * 60.0;
2015 :
2016 : /* -------------------------------------------------------------------- */
2017 : /* Do careful rounding on seconds so that 59.9->60 is properly */
2018 : /* rolled into minutes and degrees. */
2019 : /* -------------------------------------------------------------------- */
2020 808 : nSeconds = (int)(dfValue + 0.5);
2021 808 : if (nSeconds == 60)
2022 : {
2023 161 : nSeconds = 0;
2024 161 : nMinutes += 1;
2025 161 : if (nMinutes == 60)
2026 : {
2027 7 : nMinutes = 0;
2028 7 : nDegrees += 1;
2029 : }
2030 : }
2031 :
2032 808 : if (EQUAL(pszAxis, "Lat"))
2033 404 : snprintf(pszTarget, nTargetLen, "%02d%02d%02d%c", nDegrees, nMinutes,
2034 : nSeconds, chHemisphere);
2035 : else
2036 404 : snprintf(pszTarget, nTargetLen, "%03d%02d%02d%c", nDegrees, nMinutes,
2037 : nSeconds, chHemisphere);
2038 808 : }
2039 :
2040 : /************************************************************************/
2041 : /* NITFWriteIGEOLO() */
2042 : /************************************************************************/
2043 :
2044 : /* Check that easting can be represented as a 6 character string */
2045 : #define CHECK_IGEOLO_UTM_X(name, x) \
2046 : if ((int)floor((x) + 0.5) <= -100000 || (int)floor((x) + 0.5) >= 1000000) \
2047 : { \
2048 : CPLError(CE_Failure, CPLE_AppDefined, \
2049 : "Attempt to write UTM easting %s=%d which is outside of " \
2050 : "valid range.", \
2051 : name, (int)floor((x) + 0.5)); \
2052 : return FALSE; \
2053 : }
2054 :
2055 : /* Check that northing can be represented as a 7 character string */
2056 : #define CHECK_IGEOLO_UTM_Y(name, y) \
2057 : if ((int)floor((y) + 0.5) <= -1000000 || \
2058 : (int)floor((y) + 0.5) >= 10000000) \
2059 : { \
2060 : CPLError(CE_Failure, CPLE_AppDefined, \
2061 : "Attempt to write UTM northing %s=%d which is outside of " \
2062 : "valid range.", \
2063 : name, (int)floor((y) + 0.5)); \
2064 : return FALSE; \
2065 : }
2066 :
2067 144 : int NITFWriteIGEOLO(NITFImage *psImage, char chICORDS, int nZone, double dfULX,
2068 : double dfULY, double dfURX, double dfURY, double dfLRX,
2069 : double dfLRY, double dfLLX, double dfLLY)
2070 :
2071 : {
2072 : char szIGEOLO[61];
2073 :
2074 : /* -------------------------------------------------------------------- */
2075 : /* Do some checking. */
2076 : /* -------------------------------------------------------------------- */
2077 144 : if (psImage->chICORDS == ' ')
2078 : {
2079 19 : CPLError(CE_Failure, CPLE_NotSupported,
2080 : "Apparently no space reserved for IGEOLO info in NITF file.\n"
2081 : "NITFWriteIGEOGLO() fails.");
2082 19 : return FALSE;
2083 : }
2084 :
2085 125 : if (EQUAL(psImage->psFile->szVersion, "NITF02.00"))
2086 : {
2087 33 : if (chICORDS == 'U')
2088 : {
2089 : // Could be done, but we don't need UTM for CADRG support
2090 0 : CPLError(CE_Failure, CPLE_NotSupported,
2091 : "Writing UTM MGRS coordinates for NITF02.00 is not "
2092 : "supported in this implementation.");
2093 0 : return FALSE;
2094 : }
2095 33 : else if (chICORDS != 'G' && chICORDS != 'D')
2096 : {
2097 0 : CPLError(CE_Failure, CPLE_NotSupported,
2098 : "Invalid ICOORDS value (%c) for NITFWriteIGEOLO().",
2099 : chICORDS);
2100 0 : return FALSE;
2101 : }
2102 : }
2103 : else
2104 : {
2105 92 : if (chICORDS != 'G' && chICORDS != 'N' && chICORDS != 'S' &&
2106 : chICORDS != 'D')
2107 : {
2108 0 : CPLError(CE_Failure, CPLE_NotSupported,
2109 : "Invalid ICOORDS value (%c) for NITFWriteIGEOLO().",
2110 : chICORDS);
2111 0 : return FALSE;
2112 : }
2113 : }
2114 :
2115 125 : if (chICORDS == 'G' || chICORDS == 'D')
2116 : {
2117 104 : if (fabs(dfULX) <= 180 && fabs(dfLLX) <= 180 && dfURX > 180 &&
2118 : dfLRX > 180)
2119 : {
2120 0 : dfURX -= 360;
2121 0 : dfLRX -= 360;
2122 : }
2123 104 : else if (dfULX < -180 && dfLLX < -180 && fabs(dfURX) <= 180 &&
2124 0 : fabs(dfLRX) <= 180)
2125 : {
2126 0 : dfULX += 360;
2127 0 : dfLLX += 360;
2128 : }
2129 :
2130 104 : if (fabs(dfULX) > 180 || fabs(dfURX) > 180 || fabs(dfLRX) > 180 ||
2131 104 : fabs(dfLLX) > 180 || fabs(dfULY) > 90 || fabs(dfURY) > 90 ||
2132 104 : fabs(dfLRY) > 90 || fabs(dfLLY) > 90)
2133 : {
2134 0 : CPLError(
2135 : CE_Failure, CPLE_AppDefined,
2136 : "Attempt to write geographic bound outside of legal range.");
2137 0 : return FALSE;
2138 : }
2139 : }
2140 :
2141 : /* -------------------------------------------------------------------- */
2142 : /* Format geographic coordinates in DMS */
2143 : /* -------------------------------------------------------------------- */
2144 125 : if (chICORDS == 'G')
2145 : {
2146 101 : NITFEncodeDMSLoc(szIGEOLO + 0, sizeof(szIGEOLO) - 0, dfULY, "Lat");
2147 101 : NITFEncodeDMSLoc(szIGEOLO + 7, sizeof(szIGEOLO) - 7, dfULX, "Long");
2148 101 : NITFEncodeDMSLoc(szIGEOLO + 15, sizeof(szIGEOLO) - 15, dfURY, "Lat");
2149 101 : NITFEncodeDMSLoc(szIGEOLO + 22, sizeof(szIGEOLO) - 22, dfURX, "Long");
2150 101 : NITFEncodeDMSLoc(szIGEOLO + 30, sizeof(szIGEOLO) - 30, dfLRY, "Lat");
2151 101 : NITFEncodeDMSLoc(szIGEOLO + 37, sizeof(szIGEOLO) - 37, dfLRX, "Long");
2152 101 : NITFEncodeDMSLoc(szIGEOLO + 45, sizeof(szIGEOLO) - 45, dfLLY, "Lat");
2153 101 : NITFEncodeDMSLoc(szIGEOLO + 52, sizeof(szIGEOLO) - 52, dfLLX, "Long");
2154 : }
2155 : /* -------------------------------------------------------------------- */
2156 : /* Format geographic coordinates in decimal degrees */
2157 : /* -------------------------------------------------------------------- */
2158 24 : else if (chICORDS == 'D')
2159 : {
2160 3 : CPLsnprintf(szIGEOLO + 0, sizeof(szIGEOLO), "%+#07.3f%+#08.3f", dfULY,
2161 : dfULX);
2162 3 : CPLsnprintf(szIGEOLO + 15, sizeof(szIGEOLO) - 15, "%+#07.3f%+#08.3f",
2163 : dfURY, dfURX);
2164 3 : CPLsnprintf(szIGEOLO + 30, sizeof(szIGEOLO) - 30, "%+#07.3f%+#08.3f",
2165 : dfLRY, dfLRX);
2166 3 : CPLsnprintf(szIGEOLO + 45, sizeof(szIGEOLO) - 45, "%+#07.3f%+#08.3f",
2167 : dfLLY, dfLLX);
2168 : }
2169 :
2170 : /* -------------------------------------------------------------------- */
2171 : /* Format UTM coordinates. */
2172 : /* -------------------------------------------------------------------- */
2173 21 : else if (chICORDS == 'N' || chICORDS == 'S')
2174 : {
2175 21 : CHECK_IGEOLO_UTM_X("dfULX", dfULX);
2176 21 : CHECK_IGEOLO_UTM_Y("dfULY", dfULY);
2177 21 : CHECK_IGEOLO_UTM_X("dfURX", dfURX);
2178 21 : CHECK_IGEOLO_UTM_Y("dfURY", dfURY);
2179 21 : CHECK_IGEOLO_UTM_X("dfLRX", dfLRX);
2180 21 : CHECK_IGEOLO_UTM_Y("dfLRY", dfLRY);
2181 21 : CHECK_IGEOLO_UTM_X("dfLLX", dfLLX);
2182 21 : CHECK_IGEOLO_UTM_Y("dfLLY", dfLLY);
2183 21 : CPLsnprintf(szIGEOLO + 0, sizeof(szIGEOLO), "%02d%06d%07d", nZone,
2184 21 : (int)floor(dfULX + 0.5), (int)floor(dfULY + 0.5));
2185 21 : CPLsnprintf(szIGEOLO + 15, sizeof(szIGEOLO) - 15, "%02d%06d%07d", nZone,
2186 21 : (int)floor(dfURX + 0.5), (int)floor(dfURY + 0.5));
2187 21 : CPLsnprintf(szIGEOLO + 30, sizeof(szIGEOLO) - 30, "%02d%06d%07d", nZone,
2188 21 : (int)floor(dfLRX + 0.5), (int)floor(dfLRY + 0.5));
2189 21 : CPLsnprintf(szIGEOLO + 45, sizeof(szIGEOLO) - 45, "%02d%06d%07d", nZone,
2190 21 : (int)floor(dfLLX + 0.5), (int)floor(dfLLY + 0.5));
2191 : }
2192 :
2193 : /* -------------------------------------------------------------------- */
2194 : /* Write IGEOLO data to disk. */
2195 : /* -------------------------------------------------------------------- */
2196 125 : int nOffset = 372;
2197 125 : if (EQUAL(psImage->psFile->szVersion, "NITF02.00"))
2198 : {
2199 : // Read ISDWNG field;
2200 33 : char szISDWNG[6 + 1] = {0};
2201 33 : if (VSIFSeekL(psImage->psFile->fp,
2202 33 : psImage->psFile->pasSegmentInfo[psImage->iSegment]
2203 33 : .nSegmentHeaderStart +
2204 : 284,
2205 33 : SEEK_SET) != 0 ||
2206 33 : VSIFReadL(szISDWNG, 1, 6, psImage->psFile->fp) != 6)
2207 : {
2208 0 : CPLError(CE_Failure, CPLE_AppDefined,
2209 : "I/O Error writing IGEOLO segment.\n%s",
2210 0 : VSIStrerror(errno));
2211 0 : return FALSE;
2212 : }
2213 33 : if (EQUAL(szISDWNG, "999998"))
2214 1 : nOffset += 40;
2215 : }
2216 125 : if (VSIFSeekL(psImage->psFile->fp,
2217 125 : psImage->psFile->pasSegmentInfo[psImage->iSegment]
2218 125 : .nSegmentHeaderStart +
2219 : nOffset,
2220 125 : SEEK_SET) == 0 &&
2221 125 : VSIFWriteL(szIGEOLO, 1, 60, psImage->psFile->fp) == 60)
2222 : {
2223 125 : return TRUE;
2224 : }
2225 : else
2226 : {
2227 0 : CPLError(CE_Failure, CPLE_AppDefined,
2228 0 : "I/O Error writing IGEOLO segment.\n%s", VSIStrerror(errno));
2229 0 : return FALSE;
2230 : }
2231 : }
2232 :
2233 : /************************************************************************/
2234 : /* NITFWriteLUT() */
2235 : /************************************************************************/
2236 :
2237 34 : int NITFWriteLUT(NITFImage *psImage, int nBand, int nColors,
2238 : unsigned char *pabyLUT)
2239 :
2240 : {
2241 : NITFBandInfo *psBandInfo;
2242 34 : int bSuccess = TRUE;
2243 :
2244 34 : if (nBand < 1 || nBand > psImage->nBands)
2245 0 : return FALSE;
2246 :
2247 34 : psBandInfo = psImage->pasBandInfo + (nBand - 1);
2248 :
2249 34 : if (nColors > psBandInfo->nSignificantLUTEntries)
2250 : {
2251 0 : CPLError(CE_Failure, CPLE_AppDefined,
2252 : "Unable to write all %d LUT entries, only able to write %d.",
2253 : nColors, psBandInfo->nSignificantLUTEntries);
2254 0 : nColors = psBandInfo->nSignificantLUTEntries;
2255 0 : bSuccess = FALSE;
2256 : }
2257 :
2258 34 : bSuccess &=
2259 34 : VSIFSeekL(psImage->psFile->fp, psBandInfo->nLUTLocation, SEEK_SET) == 0;
2260 34 : bSuccess &=
2261 34 : (int)VSIFWriteL(pabyLUT, 1, nColors, psImage->psFile->fp) == nColors;
2262 34 : bSuccess &=
2263 34 : VSIFSeekL(psImage->psFile->fp,
2264 34 : psBandInfo->nLUTLocation + psBandInfo->nSignificantLUTEntries,
2265 34 : SEEK_SET) == 0;
2266 68 : bSuccess &= (int)VSIFWriteL(pabyLUT + 256, 1, nColors,
2267 34 : psImage->psFile->fp) == nColors;
2268 68 : bSuccess &= VSIFSeekL(psImage->psFile->fp,
2269 34 : psBandInfo->nLUTLocation +
2270 34 : 2 * psBandInfo->nSignificantLUTEntries,
2271 34 : SEEK_SET) == 0;
2272 68 : bSuccess &= (int)VSIFWriteL(pabyLUT + 512, 1, nColors,
2273 34 : psImage->psFile->fp) == nColors;
2274 :
2275 34 : return bSuccess;
2276 : }
2277 :
2278 : /************************************************************************/
2279 : /* NITFTrimWhite() */
2280 : /* */
2281 : /* Trim any white space off the white of the passed string in */
2282 : /* place. */
2283 : /************************************************************************/
2284 :
2285 324357 : char *NITFTrimWhite(char *pszTarget)
2286 :
2287 : {
2288 : int i;
2289 :
2290 324357 : i = (int)strlen(pszTarget) - 1;
2291 1445920 : while (i >= 0 && pszTarget[i] == ' ')
2292 1121570 : pszTarget[i--] = '\0';
2293 :
2294 324357 : return pszTarget;
2295 : }
2296 :
2297 : /************************************************************************/
2298 : /* NITFSwapWords() */
2299 : /************************************************************************/
2300 :
2301 : #ifdef CPL_LSB
2302 :
2303 53654 : static void NITFSwapWordsInternal(void *pData, int nWordSize, int nWordCount,
2304 : int nWordSkip)
2305 :
2306 : {
2307 : int i;
2308 53654 : GByte *pabyData = (GByte *)pData;
2309 :
2310 53654 : switch (nWordSize)
2311 : {
2312 52753 : case 1:
2313 52753 : break;
2314 :
2315 401 : case 2:
2316 126337 : for (i = 0; i < nWordCount; i++)
2317 : {
2318 : GByte byTemp;
2319 :
2320 125936 : byTemp = pabyData[0];
2321 125936 : pabyData[0] = pabyData[1];
2322 125936 : pabyData[1] = byTemp;
2323 :
2324 125936 : pabyData += nWordSkip;
2325 : }
2326 401 : break;
2327 :
2328 420 : case 4:
2329 11420 : for (i = 0; i < nWordCount; i++)
2330 : {
2331 : GByte byTemp;
2332 :
2333 11000 : byTemp = pabyData[0];
2334 11000 : pabyData[0] = pabyData[3];
2335 11000 : pabyData[3] = byTemp;
2336 :
2337 11000 : byTemp = pabyData[1];
2338 11000 : pabyData[1] = pabyData[2];
2339 11000 : pabyData[2] = byTemp;
2340 :
2341 11000 : pabyData += nWordSkip;
2342 : }
2343 420 : break;
2344 :
2345 80 : case 8:
2346 1480 : for (i = 0; i < nWordCount; i++)
2347 : {
2348 : GByte byTemp;
2349 :
2350 1400 : byTemp = pabyData[0];
2351 1400 : pabyData[0] = pabyData[7];
2352 1400 : pabyData[7] = byTemp;
2353 :
2354 1400 : byTemp = pabyData[1];
2355 1400 : pabyData[1] = pabyData[6];
2356 1400 : pabyData[6] = byTemp;
2357 :
2358 1400 : byTemp = pabyData[2];
2359 1400 : pabyData[2] = pabyData[5];
2360 1400 : pabyData[5] = byTemp;
2361 :
2362 1400 : byTemp = pabyData[3];
2363 1400 : pabyData[3] = pabyData[4];
2364 1400 : pabyData[4] = byTemp;
2365 :
2366 1400 : pabyData += nWordSkip;
2367 : }
2368 80 : break;
2369 :
2370 0 : default:
2371 0 : break;
2372 : }
2373 53654 : }
2374 :
2375 : /* Swap real or complex types */
2376 53671 : static void NITFSwapWords(NITFImage *psImage, void *pData, int nWordCount)
2377 :
2378 : {
2379 53671 : if (psImage->nWordSize * 8 != psImage->nBitsPerSample)
2380 : {
2381 : // FIXME ?
2382 17 : return;
2383 : }
2384 :
2385 53654 : if (EQUAL(psImage->szPVType, "C"))
2386 : {
2387 : /* According to
2388 : * http://jitc.fhu.disa.mil/nitf/tag_reg/imagesubheader/pvtype.html */
2389 : /* "C values shall be represented with the Real and Imaginary parts,
2390 : * each represented */
2391 : /* in IEEE 32 or 64-bit floating point representation (IEEE 754) and
2392 : * appearing in */
2393 : /* adjacent four or eight-byte blocks, first Real, then Imaginary" */
2394 20 : NITFSwapWordsInternal(pData, psImage->nWordSize / 2, 2 * nWordCount,
2395 20 : psImage->nWordSize / 2);
2396 : }
2397 : else
2398 : {
2399 53634 : NITFSwapWordsInternal(pData, psImage->nWordSize, nWordCount,
2400 : psImage->nWordSize);
2401 : }
2402 : }
2403 :
2404 : #endif /* def CPL_LSB */
2405 :
2406 : /************************************************************************/
2407 : /* NITFReadCSEXRA() */
2408 : /* */
2409 : /* Read a CSEXRA TRE and return contents as metadata strings. */
2410 : /************************************************************************/
2411 :
2412 0 : char **NITFReadCSEXRA(NITFImage *psImage)
2413 :
2414 : {
2415 0 : return NITFGenericMetadataRead(NULL, NULL, psImage, "CSEXRA");
2416 : }
2417 :
2418 : /************************************************************************/
2419 : /* NITFReadPIAIMC() */
2420 : /* */
2421 : /* Read a PIAIMC TRE and return contents as metadata strings. */
2422 : /************************************************************************/
2423 :
2424 0 : char **NITFReadPIAIMC(NITFImage *psImage)
2425 :
2426 : {
2427 0 : return NITFGenericMetadataRead(NULL, NULL, psImage, "PIAIMC");
2428 : }
2429 :
2430 : /************************************************************************/
2431 : /* NITFFormatRPC00BCoefficient() */
2432 : /* */
2433 : /* Format coefficients like +X.XXXXXXE+X (12 bytes) */
2434 : /************************************************************************/
2435 1202 : static int NITFFormatRPC00BCoefficient(char *pszBuffer, double dfVal,
2436 : int *pbPrecisionLoss)
2437 : {
2438 : // We need 12 bytes + 2=3-1 bytes for MSVC potentially outputting exponents
2439 : // with 3 digits + 1 terminating byte
2440 : char szTemp[12 + 2 + 1];
2441 : #if defined(DEBUG) || defined(_WIN32)
2442 : int nLen;
2443 : #endif
2444 :
2445 1202 : if (fabs(dfVal) > 9.999999e9)
2446 : {
2447 1 : CPLError(CE_Failure, CPLE_AppDefined, "Coefficient out of range: %g",
2448 : dfVal);
2449 1 : return FALSE;
2450 : }
2451 :
2452 1201 : CPLsnprintf(szTemp, sizeof(szTemp), "%+.6E", dfVal);
2453 : #if defined(DEBUG) || defined(_WIN32)
2454 1201 : nLen = (int)strlen(szTemp);
2455 1201 : CPL_IGNORE_RET_VAL_INT(nLen);
2456 : #endif
2457 1201 : CPLAssert(szTemp[9] == 'E');
2458 : #ifdef _WIN32
2459 : if (nLen == 14) // Old MSVC versions: 3 digits for the exponent
2460 : {
2461 : if (szTemp[11] != DIGIT_ZERO || szTemp[12] != DIGIT_ZERO)
2462 : {
2463 : CPLError(CE_Warning, CPLE_AppDefined, "%g rounded to 0", dfVal);
2464 : snprintf(pszBuffer, 12 + 1, "%s", "+0.000000E+0");
2465 : if (pbPrecisionLoss)
2466 : *pbPrecisionLoss = TRUE;
2467 : return TRUE;
2468 : }
2469 : szTemp[11] = szTemp[13];
2470 : }
2471 : else // behavior of the standard: 2 digits for the exponent
2472 : #endif
2473 : {
2474 1201 : CPLAssert(nLen == 13);
2475 1201 : if (szTemp[11] != DIGIT_ZERO)
2476 : {
2477 2 : CPLError(CE_Warning, CPLE_AppDefined, "%g rounded to 0", dfVal);
2478 2 : snprintf(pszBuffer, 12 + 1, "%s", "+0.000000E+0");
2479 2 : if (pbPrecisionLoss)
2480 2 : *pbPrecisionLoss = TRUE;
2481 2 : return TRUE;
2482 : }
2483 1199 : szTemp[11] = szTemp[12];
2484 : }
2485 1199 : szTemp[12] = '\0';
2486 1199 : memcpy(pszBuffer, szTemp, strlen(szTemp) + 1);
2487 1199 : return TRUE;
2488 : }
2489 :
2490 : /************************************************************************/
2491 : /* NITFFormatRPC00BFromMetadata() */
2492 : /* */
2493 : /* Format the content of a RPC00B TRE from RPC metadata */
2494 : /************************************************************************/
2495 :
2496 26 : char *NITFFormatRPC00BFromMetadata(CSLConstList papszRPC, int *pbPrecisionLoss)
2497 : {
2498 : GDALRPCInfoV2 sRPC;
2499 : char *pszRPC00B;
2500 : double dfErrBIAS;
2501 : double dfErrRAND;
2502 : int nOffset;
2503 : int nLength;
2504 : int nRounded;
2505 : int i;
2506 : char szTemp[24];
2507 :
2508 26 : if (pbPrecisionLoss)
2509 26 : *pbPrecisionLoss = FALSE;
2510 :
2511 26 : if (!GDALExtractRPCInfoV2(papszRPC, &sRPC))
2512 0 : return NULL;
2513 :
2514 26 : pszRPC00B = (char *)CPLMalloc(1041 + 1);
2515 26 : pszRPC00B[0] = '1'; /* success flag */
2516 26 : nOffset = 1;
2517 :
2518 26 : dfErrBIAS = sRPC.dfERR_BIAS;
2519 26 : if (dfErrBIAS == -1.0) // value by default to indicate unknown
2520 : {
2521 1 : dfErrBIAS = 0.0;
2522 : }
2523 25 : else if (dfErrBIAS < 0)
2524 : {
2525 0 : CPLError(CE_Warning, CPLE_AppDefined,
2526 : "Correcting ERR_BIAS from %f to 0", dfErrBIAS);
2527 : }
2528 25 : else if (dfErrBIAS > 9999.99)
2529 : {
2530 0 : CPLError(CE_Warning, CPLE_AppDefined,
2531 : "ERR_BIAS out of range. Clamping to 9999.99");
2532 0 : dfErrBIAS = 9999.99;
2533 : }
2534 26 : nLength = 7;
2535 26 : CPLsnprintf(pszRPC00B + nOffset, nLength + 1, "%07.2f", dfErrBIAS);
2536 26 : nOffset += nLength;
2537 :
2538 26 : dfErrRAND = sRPC.dfERR_RAND;
2539 26 : if (dfErrRAND == -1.0) // value by default to indicate unknown
2540 : {
2541 1 : dfErrRAND = 0.0;
2542 : }
2543 25 : else if (dfErrRAND < 0)
2544 : {
2545 0 : CPLError(CE_Warning, CPLE_AppDefined,
2546 : "Correcting ERR_RAND from %f to 0", dfErrRAND);
2547 0 : if (pbPrecisionLoss)
2548 0 : *pbPrecisionLoss = TRUE;
2549 : }
2550 25 : else if (dfErrRAND > 9999.99)
2551 : {
2552 0 : CPLError(CE_Warning, CPLE_AppDefined,
2553 : "ERR_RAND out of range. Clamping to 9999.99");
2554 0 : dfErrRAND = 9999.99;
2555 0 : if (pbPrecisionLoss)
2556 0 : *pbPrecisionLoss = TRUE;
2557 : }
2558 26 : nLength = 7;
2559 26 : CPLsnprintf(pszRPC00B + nOffset, nLength + 1, "%07.2f", dfErrRAND);
2560 26 : nOffset += nLength;
2561 :
2562 26 : nLength = 6;
2563 26 : if (sRPC.dfLINE_OFF < 0 || sRPC.dfLINE_OFF >= 1e6)
2564 : {
2565 1 : CPLError(CE_Failure, CPLE_AppDefined, "LINE_OFF out of range.");
2566 1 : CPLFree(pszRPC00B);
2567 1 : return NULL;
2568 : }
2569 25 : nRounded = (int)floor(sRPC.dfLINE_OFF + 0.5);
2570 25 : if (fabs(nRounded - sRPC.dfLINE_OFF) > 1e-2)
2571 : {
2572 1 : CPLError(CE_Warning, CPLE_AppDefined,
2573 : "LINE_OFF was rounded from %f to %d", sRPC.dfLINE_OFF,
2574 : nRounded);
2575 1 : if (pbPrecisionLoss)
2576 1 : *pbPrecisionLoss = TRUE;
2577 : }
2578 25 : CPLsnprintf(pszRPC00B + nOffset, nLength + 1, "%06d", nRounded);
2579 25 : nOffset += nLength;
2580 :
2581 25 : nLength = 5;
2582 25 : if (sRPC.dfSAMP_OFF < 0 || sRPC.dfSAMP_OFF >= 1e5)
2583 : {
2584 1 : CPLError(CE_Failure, CPLE_AppDefined, "SAMP_OFF out of range.");
2585 1 : CPLFree(pszRPC00B);
2586 1 : return NULL;
2587 : }
2588 24 : nRounded = (int)floor(sRPC.dfSAMP_OFF + 0.5);
2589 24 : if (fabs(nRounded - sRPC.dfSAMP_OFF) > 1e-2)
2590 : {
2591 1 : CPLError(CE_Warning, CPLE_AppDefined,
2592 : "SAMP_OFF was rounded from %f to %d", sRPC.dfSAMP_OFF,
2593 : nRounded);
2594 1 : if (pbPrecisionLoss)
2595 1 : *pbPrecisionLoss = TRUE;
2596 : }
2597 24 : CPLsnprintf(pszRPC00B + nOffset, nLength + 1, "%05d", nRounded);
2598 24 : nOffset += nLength;
2599 :
2600 24 : nLength = 8;
2601 24 : if (fabs(sRPC.dfLAT_OFF) > 90)
2602 : {
2603 1 : CPLError(CE_Failure, CPLE_AppDefined, "LAT_OFF out of range.");
2604 1 : CPLFree(pszRPC00B);
2605 1 : return NULL;
2606 : }
2607 23 : CPLsnprintf(pszRPC00B + nOffset, nLength + 1, "%+08.4f", sRPC.dfLAT_OFF);
2608 23 : if (fabs(sRPC.dfLAT_OFF -
2609 23 : CPLAtof(NITFGetField(szTemp, pszRPC00B, nOffset, nLength))) > 1e-8)
2610 : {
2611 1 : CPLError(CE_Warning, CPLE_AppDefined,
2612 : "LAT_OFF was rounded from %f to %s", sRPC.dfLAT_OFF, szTemp);
2613 1 : if (pbPrecisionLoss)
2614 1 : *pbPrecisionLoss = TRUE;
2615 : }
2616 23 : nOffset += nLength;
2617 :
2618 23 : nLength = 9;
2619 23 : if (fabs(sRPC.dfLONG_OFF) > 180)
2620 : {
2621 1 : CPLError(CE_Failure, CPLE_AppDefined, "LONG_OFF out of range.");
2622 1 : CPLFree(pszRPC00B);
2623 1 : return NULL;
2624 : }
2625 22 : CPLsnprintf(pszRPC00B + nOffset, nLength + 1, "%+09.4f", sRPC.dfLONG_OFF);
2626 22 : if (fabs(sRPC.dfLONG_OFF -
2627 22 : CPLAtof(NITFGetField(szTemp, pszRPC00B, nOffset, nLength))) > 1e-8)
2628 : {
2629 1 : CPLError(CE_Warning, CPLE_AppDefined,
2630 : "LONG_OFF was rounded from %f to %s", sRPC.dfLONG_OFF, szTemp);
2631 1 : if (pbPrecisionLoss)
2632 1 : *pbPrecisionLoss = TRUE;
2633 : }
2634 22 : nOffset += nLength;
2635 :
2636 22 : nLength = 5;
2637 22 : if (fabs(sRPC.dfHEIGHT_OFF) > 9999)
2638 : {
2639 1 : CPLError(CE_Failure, CPLE_AppDefined, "HEIGHT_OFF out of range.");
2640 1 : CPLFree(pszRPC00B);
2641 1 : return NULL;
2642 : }
2643 21 : nRounded = (int)floor(sRPC.dfHEIGHT_OFF + 0.5);
2644 21 : if (fabs(nRounded - sRPC.dfHEIGHT_OFF) > 1e-2)
2645 : {
2646 1 : CPLError(CE_Warning, CPLE_AppDefined,
2647 : "HEIGHT_OFF was rounded from %f to %d", sRPC.dfHEIGHT_OFF,
2648 : nRounded);
2649 1 : if (pbPrecisionLoss)
2650 1 : *pbPrecisionLoss = TRUE;
2651 : }
2652 21 : CPLsnprintf(pszRPC00B + nOffset, nLength + 1, "%+05d", nRounded);
2653 21 : nOffset += nLength;
2654 :
2655 21 : nLength = 6;
2656 21 : if (sRPC.dfLINE_SCALE < 1 || sRPC.dfLINE_SCALE >= 999999)
2657 : {
2658 1 : CPLError(CE_Failure, CPLE_AppDefined, "LINE_SCALE out of range.");
2659 1 : CPLFree(pszRPC00B);
2660 1 : return NULL;
2661 : }
2662 20 : nRounded = (int)floor(sRPC.dfLINE_SCALE + 0.5);
2663 20 : if (fabs(nRounded - sRPC.dfLINE_SCALE) > 1e-2)
2664 : {
2665 1 : CPLError(CE_Warning, CPLE_AppDefined,
2666 : "LINE_SCALE was rounded from %f to %d", sRPC.dfLINE_SCALE,
2667 : nRounded);
2668 1 : if (pbPrecisionLoss)
2669 1 : *pbPrecisionLoss = TRUE;
2670 : }
2671 20 : CPLsnprintf(pszRPC00B + nOffset, nLength + 1, "%06d", nRounded);
2672 20 : nOffset += nLength;
2673 :
2674 20 : nLength = 5;
2675 20 : if (sRPC.dfSAMP_SCALE < 1 || sRPC.dfSAMP_SCALE >= 99999)
2676 : {
2677 1 : CPLError(CE_Failure, CPLE_AppDefined, "SAMP_SCALE out of range.");
2678 1 : CPLFree(pszRPC00B);
2679 1 : return NULL;
2680 : }
2681 19 : nRounded = (int)floor(sRPC.dfSAMP_SCALE + 0.5);
2682 19 : if (fabs(nRounded - sRPC.dfSAMP_SCALE) > 1e-2)
2683 : {
2684 1 : CPLError(CE_Warning, CPLE_AppDefined,
2685 : "SAMP_SCALE was rounded from %f to %d", sRPC.dfSAMP_SCALE,
2686 : nRounded);
2687 1 : if (pbPrecisionLoss)
2688 1 : *pbPrecisionLoss = TRUE;
2689 : }
2690 19 : CPLsnprintf(pszRPC00B + nOffset, nLength + 1, "%05d", nRounded);
2691 19 : nOffset += nLength;
2692 :
2693 19 : nLength = 8;
2694 19 : if (fabs(sRPC.dfLAT_SCALE) > 90)
2695 : {
2696 1 : CPLError(CE_Failure, CPLE_AppDefined, "LAT_SCALE out of range.");
2697 1 : CPLFree(pszRPC00B);
2698 1 : return NULL;
2699 : }
2700 18 : CPLsnprintf(pszRPC00B + nOffset, nLength + 1, "%+08.4f", sRPC.dfLAT_SCALE);
2701 18 : if (fabs(sRPC.dfLAT_SCALE -
2702 18 : CPLAtof(NITFGetField(szTemp, pszRPC00B, nOffset, nLength))) > 1e-8)
2703 : {
2704 1 : CPLError(CE_Warning, CPLE_AppDefined,
2705 : "LAT_SCALE was rounded from %f to %s", sRPC.dfLAT_SCALE,
2706 : szTemp);
2707 1 : if (pbPrecisionLoss)
2708 1 : *pbPrecisionLoss = TRUE;
2709 : }
2710 18 : nOffset += nLength;
2711 :
2712 18 : nLength = 9;
2713 18 : if (fabs(sRPC.dfLONG_SCALE) > 180)
2714 : {
2715 1 : CPLError(CE_Failure, CPLE_AppDefined, "LONG_SCALE out of range.");
2716 1 : CPLFree(pszRPC00B);
2717 1 : return NULL;
2718 : }
2719 17 : CPLsnprintf(pszRPC00B + nOffset, nLength + 1, "%+09.4f", sRPC.dfLONG_SCALE);
2720 17 : if (fabs(sRPC.dfLONG_SCALE -
2721 17 : CPLAtof(NITFGetField(szTemp, pszRPC00B, nOffset, nLength))) > 1e-8)
2722 : {
2723 1 : CPLError(CE_Warning, CPLE_AppDefined,
2724 : "LONG_SCALE was rounded from %f to %s", sRPC.dfLONG_SCALE,
2725 : szTemp);
2726 1 : if (pbPrecisionLoss)
2727 1 : *pbPrecisionLoss = TRUE;
2728 : }
2729 17 : nOffset += nLength;
2730 :
2731 17 : nLength = 5;
2732 17 : if (fabs(sRPC.dfHEIGHT_SCALE) > 9999)
2733 : {
2734 1 : CPLError(CE_Failure, CPLE_AppDefined, "HEIGHT_SCALE out of range.");
2735 1 : CPLFree(pszRPC00B);
2736 1 : return NULL;
2737 : }
2738 16 : nRounded = (int)floor(sRPC.dfHEIGHT_SCALE + 0.5);
2739 16 : if (fabs(nRounded - sRPC.dfHEIGHT_SCALE) > 1e-2)
2740 : {
2741 1 : CPLError(CE_Warning, CPLE_AppDefined,
2742 : "HEIGHT_SCALE was rounded from %f to %d", sRPC.dfHEIGHT_SCALE,
2743 : nRounded);
2744 1 : if (pbPrecisionLoss)
2745 1 : *pbPrecisionLoss = TRUE;
2746 : }
2747 16 : CPLsnprintf(pszRPC00B + nOffset, nLength + 1, "%+05d", nRounded);
2748 16 : nOffset += nLength;
2749 :
2750 : /* -------------------------------------------------------------------- */
2751 : /* Write coefficients. */
2752 : /* -------------------------------------------------------------------- */
2753 317 : for (i = 0; i < 20; i++)
2754 : {
2755 302 : if (!NITFFormatRPC00BCoefficient(pszRPC00B + nOffset,
2756 : sRPC.adfLINE_NUM_COEFF[i],
2757 : pbPrecisionLoss))
2758 : {
2759 1 : CPLFree(pszRPC00B);
2760 1 : return NULL;
2761 : }
2762 301 : nOffset += 12;
2763 : }
2764 315 : for (i = 0; i < 20; i++)
2765 : {
2766 300 : if (!NITFFormatRPC00BCoefficient(pszRPC00B + nOffset,
2767 : sRPC.adfLINE_DEN_COEFF[i],
2768 : pbPrecisionLoss))
2769 : {
2770 0 : CPLFree(pszRPC00B);
2771 0 : return NULL;
2772 : }
2773 300 : nOffset += 12;
2774 : }
2775 315 : for (i = 0; i < 20; i++)
2776 : {
2777 300 : if (!NITFFormatRPC00BCoefficient(pszRPC00B + nOffset,
2778 : sRPC.adfSAMP_NUM_COEFF[i],
2779 : pbPrecisionLoss))
2780 : {
2781 0 : CPLFree(pszRPC00B);
2782 0 : return NULL;
2783 : }
2784 300 : nOffset += 12;
2785 : }
2786 315 : for (i = 0; i < 20; i++)
2787 : {
2788 300 : if (!NITFFormatRPC00BCoefficient(pszRPC00B + nOffset,
2789 : sRPC.adfSAMP_DEN_COEFF[i],
2790 : pbPrecisionLoss))
2791 : {
2792 0 : CPLFree(pszRPC00B);
2793 0 : return NULL;
2794 : }
2795 300 : nOffset += 12;
2796 : }
2797 :
2798 15 : CPLAssert(nOffset == 1041);
2799 15 : pszRPC00B[nOffset] = '\0';
2800 15 : CPLAssert(strlen(pszRPC00B) == 1041);
2801 15 : CPLAssert(strchr(pszRPC00B, ' ') == NULL);
2802 :
2803 15 : return pszRPC00B;
2804 : }
2805 :
2806 : /************************************************************************/
2807 : /* NITFReadRPC00B() */
2808 : /* */
2809 : /* Read an RPC00A or RPC00B structure if the TRE is available. */
2810 : /* RPC00A is remapped into RPC00B organization. */
2811 : /************************************************************************/
2812 :
2813 752 : int NITFReadRPC00B(NITFImage *psImage, NITFRPC00BInfo *psRPC)
2814 :
2815 : {
2816 : const char *pachTRE;
2817 752 : int bIsRPC00A = FALSE;
2818 : int nTRESize;
2819 :
2820 752 : psRPC->SUCCESS = 0;
2821 :
2822 : /* -------------------------------------------------------------------- */
2823 : /* Do we have the TRE? */
2824 : /* -------------------------------------------------------------------- */
2825 : pachTRE =
2826 752 : NITFFindTRE(psImage->pachTRE, psImage->nTREBytes, "RPC00B", &nTRESize);
2827 :
2828 752 : if (pachTRE == NULL)
2829 : {
2830 700 : pachTRE = NITFFindTRE(psImage->pachTRE, psImage->nTREBytes, "RPC00A",
2831 : &nTRESize);
2832 700 : if (pachTRE)
2833 0 : bIsRPC00A = TRUE;
2834 : }
2835 :
2836 752 : if (pachTRE == NULL)
2837 : {
2838 : /* No RPC00 tag. Check to see if we have the IMASDA and IMRFCA
2839 : tags (DPPDB data) before returning. */
2840 700 : return NITFReadIMRFCA(psImage, psRPC);
2841 : }
2842 :
2843 52 : if (nTRESize < 801 + 19 * 12 + 12)
2844 : {
2845 0 : CPLError(CE_Failure, CPLE_AppDefined,
2846 : "Cannot read RPC00A/RPC00B TRE. Not enough bytes");
2847 0 : return FALSE;
2848 : }
2849 :
2850 52 : return NITFDeserializeRPC00B((const GByte *)pachTRE, psRPC, bIsRPC00A);
2851 : }
2852 :
2853 : /************************************************************************/
2854 : /* NITFDeserializeRPC00B() */
2855 : /************************************************************************/
2856 :
2857 52 : int NITFDeserializeRPC00B(const GByte *pabyTRE, NITFRPC00BInfo *psRPC,
2858 : int bIsRPC00A)
2859 : {
2860 52 : const char *pachTRE = (const char *)pabyTRE;
2861 : char szTemp[100];
2862 : int i;
2863 : static const int anRPC00AMap[] = /* See ticket #2040 */
2864 : {0, 1, 2, 3, 4, 5, 6, 10, 7, 8, 9, 11, 14, 17, 12, 15, 18, 13, 16, 19};
2865 :
2866 : /* -------------------------------------------------------------------- */
2867 : /* Parse out field values. */
2868 : /* -------------------------------------------------------------------- */
2869 52 : psRPC->SUCCESS = atoi(NITFGetField(szTemp, pachTRE, 0, 1));
2870 :
2871 52 : if (!psRPC->SUCCESS)
2872 : {
2873 0 : CPLError(CE_Warning, CPLE_AppDefined, "RPC Extension not Populated!");
2874 : }
2875 :
2876 52 : psRPC->ERR_BIAS = CPLAtof(NITFGetField(szTemp, pachTRE, 1, 7));
2877 52 : psRPC->ERR_RAND = CPLAtof(NITFGetField(szTemp, pachTRE, 8, 7));
2878 :
2879 52 : psRPC->LINE_OFF = CPLAtof(NITFGetField(szTemp, pachTRE, 15, 6));
2880 52 : psRPC->SAMP_OFF = CPLAtof(NITFGetField(szTemp, pachTRE, 21, 5));
2881 52 : psRPC->LAT_OFF = CPLAtof(NITFGetField(szTemp, pachTRE, 26, 8));
2882 52 : psRPC->LONG_OFF = CPLAtof(NITFGetField(szTemp, pachTRE, 34, 9));
2883 52 : psRPC->HEIGHT_OFF = CPLAtof(NITFGetField(szTemp, pachTRE, 43, 5));
2884 :
2885 52 : psRPC->LINE_SCALE = CPLAtof(NITFGetField(szTemp, pachTRE, 48, 6));
2886 52 : psRPC->SAMP_SCALE = CPLAtof(NITFGetField(szTemp, pachTRE, 54, 5));
2887 52 : psRPC->LAT_SCALE = CPLAtof(NITFGetField(szTemp, pachTRE, 59, 8));
2888 52 : psRPC->LONG_SCALE = CPLAtof(NITFGetField(szTemp, pachTRE, 67, 9));
2889 52 : psRPC->HEIGHT_SCALE = CPLAtof(NITFGetField(szTemp, pachTRE, 76, 5));
2890 :
2891 : /* -------------------------------------------------------------------- */
2892 : /* Parse out coefficients. */
2893 : /* -------------------------------------------------------------------- */
2894 1092 : for (i = 0; i < 20; i++)
2895 : {
2896 1040 : int iSrcCoef = i;
2897 :
2898 1040 : if (bIsRPC00A)
2899 0 : iSrcCoef = anRPC00AMap[i];
2900 :
2901 1040 : psRPC->LINE_NUM_COEFF[i] =
2902 1040 : CPLAtof(NITFGetField(szTemp, pachTRE, 81 + iSrcCoef * 12, 12));
2903 1040 : psRPC->LINE_DEN_COEFF[i] =
2904 1040 : CPLAtof(NITFGetField(szTemp, pachTRE, 321 + iSrcCoef * 12, 12));
2905 1040 : psRPC->SAMP_NUM_COEFF[i] =
2906 1040 : CPLAtof(NITFGetField(szTemp, pachTRE, 561 + iSrcCoef * 12, 12));
2907 1040 : psRPC->SAMP_DEN_COEFF[i] =
2908 1040 : CPLAtof(NITFGetField(szTemp, pachTRE, 801 + iSrcCoef * 12, 12));
2909 : }
2910 :
2911 52 : return TRUE;
2912 : }
2913 :
2914 : /************************************************************************/
2915 : /* NITFReadICHIPB() */
2916 : /* */
2917 : /* Read an ICHIPB structure if the TRE is available. */
2918 : /************************************************************************/
2919 :
2920 752 : int NITFReadICHIPB(NITFImage *psImage, NITFICHIPBInfo *psICHIP)
2921 :
2922 : {
2923 : const char *pachTRE;
2924 : char szTemp[32];
2925 : int nTRESize;
2926 :
2927 : /* -------------------------------------------------------------------- */
2928 : /* Do we have the TRE? */
2929 : /* -------------------------------------------------------------------- */
2930 : pachTRE =
2931 752 : NITFFindTRE(psImage->pachTRE, psImage->nTREBytes, "ICHIPB", &nTRESize);
2932 :
2933 752 : if (pachTRE == NULL)
2934 : {
2935 750 : pachTRE = NITFFindTRE(psImage->pachTRE, psImage->nTREBytes, "ICHIPA",
2936 : &nTRESize);
2937 : }
2938 :
2939 752 : if (pachTRE == NULL)
2940 : {
2941 750 : return FALSE;
2942 : }
2943 :
2944 2 : if (nTRESize < 2)
2945 : {
2946 0 : CPLError(CE_Failure, CPLE_AppDefined,
2947 : "Cannot read ICHIPA/ICHIPB TRE. Not enough bytes");
2948 0 : return FALSE;
2949 : }
2950 : /* -------------------------------------------------------------------- */
2951 : /* Parse out field values. */
2952 : /* -------------------------------------------------------------------- */
2953 2 : psICHIP->XFRM_FLAG = atoi(NITFGetField(szTemp, pachTRE, 0, 2));
2954 :
2955 2 : if (psICHIP->XFRM_FLAG == 0)
2956 : {
2957 2 : if (nTRESize < 216 + 8)
2958 : {
2959 0 : CPLError(CE_Failure, CPLE_AppDefined,
2960 : "Cannot read ICHIPA/ICHIPB TRE. Not enough bytes");
2961 0 : return FALSE;
2962 : }
2963 :
2964 2 : psICHIP->SCALE_FACTOR = CPLAtof(NITFGetField(szTemp, pachTRE, 2, 10));
2965 2 : psICHIP->ANAMORPH_CORR = atoi(NITFGetField(szTemp, pachTRE, 12, 2));
2966 2 : psICHIP->SCANBLK_NUM = atoi(NITFGetField(szTemp, pachTRE, 14, 2));
2967 :
2968 2 : psICHIP->OP_ROW_11 = CPLAtof(NITFGetField(szTemp, pachTRE, 16, 12));
2969 2 : psICHIP->OP_COL_11 = CPLAtof(NITFGetField(szTemp, pachTRE, 28, 12));
2970 :
2971 2 : psICHIP->OP_ROW_12 = CPLAtof(NITFGetField(szTemp, pachTRE, 40, 12));
2972 2 : psICHIP->OP_COL_12 = CPLAtof(NITFGetField(szTemp, pachTRE, 52, 12));
2973 :
2974 2 : psICHIP->OP_ROW_21 = CPLAtof(NITFGetField(szTemp, pachTRE, 64, 12));
2975 2 : psICHIP->OP_COL_21 = CPLAtof(NITFGetField(szTemp, pachTRE, 76, 12));
2976 :
2977 2 : psICHIP->OP_ROW_22 = CPLAtof(NITFGetField(szTemp, pachTRE, 88, 12));
2978 2 : psICHIP->OP_COL_22 = CPLAtof(NITFGetField(szTemp, pachTRE, 100, 12));
2979 :
2980 2 : psICHIP->FI_ROW_11 = CPLAtof(NITFGetField(szTemp, pachTRE, 112, 12));
2981 2 : psICHIP->FI_COL_11 = CPLAtof(NITFGetField(szTemp, pachTRE, 124, 12));
2982 :
2983 2 : psICHIP->FI_ROW_12 = CPLAtof(NITFGetField(szTemp, pachTRE, 136, 12));
2984 2 : psICHIP->FI_COL_12 = CPLAtof(NITFGetField(szTemp, pachTRE, 148, 12));
2985 :
2986 2 : psICHIP->FI_ROW_21 = CPLAtof(NITFGetField(szTemp, pachTRE, 160, 12));
2987 2 : psICHIP->FI_COL_21 = CPLAtof(NITFGetField(szTemp, pachTRE, 172, 12));
2988 :
2989 2 : psICHIP->FI_ROW_22 = CPLAtof(NITFGetField(szTemp, pachTRE, 184, 12));
2990 2 : psICHIP->FI_COL_22 = CPLAtof(NITFGetField(szTemp, pachTRE, 196, 12));
2991 :
2992 2 : psICHIP->FI_ROW = atoi(NITFGetField(szTemp, pachTRE, 208, 8));
2993 2 : psICHIP->FI_COL = atoi(NITFGetField(szTemp, pachTRE, 216, 8));
2994 : }
2995 : else
2996 : {
2997 0 : CPLError(CE_Warning, CPLE_AppDefined, "Chip is already de-warped?");
2998 : }
2999 :
3000 2 : return TRUE;
3001 : }
3002 :
3003 : /************************************************************************/
3004 : /* NITFReadUSE00A() */
3005 : /* */
3006 : /* Read a USE00A TRE and return contents as metadata strings. */
3007 : /************************************************************************/
3008 :
3009 0 : char **NITFReadUSE00A(NITFImage *psImage)
3010 :
3011 : {
3012 0 : return NITFGenericMetadataRead(NULL, NULL, psImage, "USE00A");
3013 : }
3014 :
3015 : /************************************************************************/
3016 : /* NITFReadBLOCKA() */
3017 : /* */
3018 : /* Read a BLOCKA SDE and return contents as metadata strings. */
3019 : /************************************************************************/
3020 :
3021 752 : char **NITFReadBLOCKA(NITFImage *psImage)
3022 :
3023 : {
3024 : const char *pachTRE;
3025 : int nTRESize;
3026 752 : char **papszMD = NULL;
3027 752 : int nBlockaCount = 0;
3028 : char szTemp[128];
3029 :
3030 : while (TRUE)
3031 : {
3032 : /* --------------------------------------------------------------------
3033 : */
3034 : /* Do we have the TRE? */
3035 : /* --------------------------------------------------------------------
3036 : */
3037 775 : pachTRE = NITFFindTREByIndex(psImage->pachTRE, psImage->nTREBytes,
3038 : "BLOCKA", nBlockaCount, &nTRESize);
3039 :
3040 775 : if (pachTRE == NULL)
3041 749 : break;
3042 :
3043 26 : if (nTRESize != 123)
3044 : {
3045 3 : CPLError(CE_Warning, CPLE_AppDefined,
3046 : "BLOCKA TRE wrong size, ignoring.");
3047 3 : break;
3048 : }
3049 :
3050 23 : nBlockaCount++;
3051 :
3052 : /* --------------------------------------------------------------------
3053 : */
3054 : /* Parse out field values. */
3055 : /* --------------------------------------------------------------------
3056 : */
3057 23 : snprintf(szTemp, sizeof(szTemp), "NITF_BLOCKA_BLOCK_INSTANCE_%02d",
3058 : nBlockaCount);
3059 23 : NITFExtractMetadata(&papszMD, pachTRE, 0, 2, szTemp);
3060 23 : snprintf(szTemp, sizeof(szTemp), "NITF_BLOCKA_N_GRAY_%02d",
3061 : nBlockaCount);
3062 23 : NITFExtractMetadata(&papszMD, pachTRE, 2, 5, szTemp);
3063 23 : snprintf(szTemp, sizeof(szTemp), "NITF_BLOCKA_L_LINES_%02d",
3064 : nBlockaCount);
3065 23 : NITFExtractMetadata(&papszMD, pachTRE, 7, 5, szTemp);
3066 23 : snprintf(szTemp, sizeof(szTemp), "NITF_BLOCKA_LAYOVER_ANGLE_%02d",
3067 : nBlockaCount);
3068 23 : NITFExtractMetadata(&papszMD, pachTRE, 12, 3, szTemp);
3069 23 : snprintf(szTemp, sizeof(szTemp), "NITF_BLOCKA_SHADOW_ANGLE_%02d",
3070 : nBlockaCount);
3071 23 : NITFExtractMetadata(&papszMD, pachTRE, 15, 3, szTemp);
3072 : /* reserved: 16 */
3073 23 : snprintf(szTemp, sizeof(szTemp), "NITF_BLOCKA_FRLC_LOC_%02d",
3074 : nBlockaCount);
3075 23 : NITFExtractMetadata(&papszMD, pachTRE, 34, 21, szTemp);
3076 23 : snprintf(szTemp, sizeof(szTemp), "NITF_BLOCKA_LRLC_LOC_%02d",
3077 : nBlockaCount);
3078 23 : NITFExtractMetadata(&papszMD, pachTRE, 55, 21, szTemp);
3079 23 : snprintf(szTemp, sizeof(szTemp), "NITF_BLOCKA_LRFC_LOC_%02d",
3080 : nBlockaCount);
3081 23 : NITFExtractMetadata(&papszMD, pachTRE, 76, 21, szTemp);
3082 23 : snprintf(szTemp, sizeof(szTemp), "NITF_BLOCKA_FRFC_LOC_%02d",
3083 : nBlockaCount);
3084 23 : NITFExtractMetadata(&papszMD, pachTRE, 97, 21, szTemp);
3085 : /* reserved: 5 -> 97 + 21 + 5 = 123 -> OK */
3086 : }
3087 :
3088 752 : if (nBlockaCount > 0)
3089 : {
3090 23 : snprintf(szTemp, sizeof(szTemp), "%02d", nBlockaCount);
3091 23 : papszMD = CSLSetNameValue(papszMD, "NITF_BLOCKA_BLOCK_COUNT", szTemp);
3092 : }
3093 :
3094 752 : return papszMD;
3095 : }
3096 :
3097 : /************************************************************************/
3098 : /* NITFGetGCP() */
3099 : /* */
3100 : /* Reads a geographical coordinate (lat, long) from the provided */
3101 : /* buffer. */
3102 : /************************************************************************/
3103 :
3104 8 : void NITFGetGCP(const char *pachCoord, double *pdfXYs, int iCoord)
3105 : {
3106 : char szTemp[128];
3107 :
3108 : // offset to selected coordinate.
3109 8 : pdfXYs += 2 * iCoord;
3110 :
3111 8 : if (pachCoord[0] == 'N' || pachCoord[0] == 'n' || pachCoord[0] == 'S' ||
3112 8 : pachCoord[0] == 's')
3113 : {
3114 : /* ------------------------------------------------------------ */
3115 : /* 0....+....1....+....2 */
3116 : /* Coordinates are in the form Xddmmss.ssYdddmmss.ss: */
3117 : /* The format Xddmmss.cc represents degrees (00 to 89), minutes */
3118 : /* (00 to 59), seconds (00 to 59), and hundredths of seconds */
3119 : /* (00 to 99) of latitude, with X = N for north or S for south, */
3120 : /* and Ydddmmss.cc represents degrees (000 to 179), minutes */
3121 : /* (00 to 59), seconds (00 to 59), and hundredths of seconds */
3122 : /* (00 to 99) of longitude, with Y = E for east or W for west. */
3123 : /* ------------------------------------------------------------ */
3124 :
3125 : // It is critical to do the fetching of the D, M, S components
3126 : // in 3 separate statements, otherwise if NITFGetField() is
3127 : // defined in this compilation unit, the MSVC optimizer will
3128 : // generate bad code, due to szTemp being overwritten before
3129 : // being evaluated by CPLAtof() !
3130 0 : pdfXYs[1] = CPLAtof(NITFGetField(szTemp, pachCoord, 1, 2));
3131 0 : pdfXYs[1] += CPLAtof(NITFGetField(szTemp, pachCoord, 3, 2)) / 60.0;
3132 0 : pdfXYs[1] += CPLAtof(NITFGetField(szTemp, pachCoord, 5, 5)) / 3600.0;
3133 :
3134 0 : if (pachCoord[0] == 's' || pachCoord[0] == 'S')
3135 0 : pdfXYs[1] *= -1;
3136 :
3137 : // It is critical to do the fetching of the D, M, S components
3138 : // in 3 separate statements, otherwise if NITFGetField() is
3139 : // defined in this compilation unit, the MSVC optimizer will
3140 : // generate bad code, due to szTemp being overwritten before
3141 : // being evaluated by CPLAtof() !
3142 0 : pdfXYs[0] = CPLAtof(NITFGetField(szTemp, pachCoord, 11, 3));
3143 0 : pdfXYs[0] += CPLAtof(NITFGetField(szTemp, pachCoord, 14, 2)) / 60.0;
3144 0 : pdfXYs[0] += CPLAtof(NITFGetField(szTemp, pachCoord, 16, 5)) / 3600.0;
3145 :
3146 0 : if (pachCoord[10] == 'w' || pachCoord[10] == 'W')
3147 0 : pdfXYs[0] *= -1;
3148 : }
3149 : else
3150 : {
3151 : /* ------------------------------------------------------------ */
3152 : /* 0....+....1....+....2 */
3153 : /* Coordinates are in the form ±dd.dddddd±ddd.dddddd: */
3154 : /* The format ±dd.dddddd indicates degrees of latitude (north */
3155 : /* is positive), and ±ddd.dddddd represents degrees of */
3156 : /* longitude (east is positive). */
3157 : /* ------------------------------------------------------------ */
3158 :
3159 8 : pdfXYs[1] = CPLAtof(NITFGetField(szTemp, pachCoord, 0, 10));
3160 8 : pdfXYs[0] = CPLAtof(NITFGetField(szTemp, pachCoord, 10, 11));
3161 : }
3162 8 : }
3163 :
3164 : /************************************************************************/
3165 : /* NITFReadBLOCKA_GCPs() */
3166 : /* */
3167 : /* The BLOCKA repeat earth coordinates image corner locations described */
3168 : /* by IGEOLO in the NITF image subheader, but provide higher precision. */
3169 : /************************************************************************/
3170 :
3171 8755 : int NITFReadBLOCKA_GCPs(NITFImage *psImage)
3172 : {
3173 : const char *pachTRE;
3174 : int nTRESize;
3175 : int nBlockaLines;
3176 : char szTemp[128];
3177 :
3178 : /* -------------------------------------------------------------------- */
3179 : /* Do we have the TRE? */
3180 : /* -------------------------------------------------------------------- */
3181 : pachTRE =
3182 8755 : NITFFindTRE(psImage->pachTRE, psImage->nTREBytes, "BLOCKA", &nTRESize);
3183 :
3184 8755 : if (pachTRE == NULL)
3185 8729 : return FALSE;
3186 :
3187 26 : if (nTRESize != 123)
3188 : {
3189 3 : return FALSE;
3190 : }
3191 :
3192 : /* -------------------------------------------------------------------- */
3193 : /* Parse out field values. */
3194 : /* -------------------------------------------------------------------- */
3195 :
3196 : /* ---------------------------------------------------------------- */
3197 : /* Make sure the BLOCKA geo coordinates are set. Spaces indicate */
3198 : /* the value of a coordinate is unavailable or inapplicable. */
3199 : /* ---------------------------------------------------------------- */
3200 23 : if (pachTRE[34] == ' ' || pachTRE[55] == ' ' || pachTRE[76] == ' ' ||
3201 23 : pachTRE[97] == ' ')
3202 : {
3203 0 : return FALSE;
3204 : }
3205 :
3206 : /* ---------------------------------------------------------------- */
3207 : /* Extract the L_LINES field of BLOCKA and see if this instance */
3208 : /* covers the whole image. This is the case if L_LINES is equal to */
3209 : /* the no of rows of this image. */
3210 : /* We use the BLOCKA only in that case! */
3211 : /* ---------------------------------------------------------------- */
3212 23 : nBlockaLines = atoi(NITFGetField(szTemp, pachTRE, 7, 5));
3213 23 : if (psImage->nRows != nBlockaLines)
3214 : {
3215 21 : return FALSE;
3216 : }
3217 :
3218 : /* ---------------------------------------------------------------- */
3219 : /* Note that the order of these coordinates is different from */
3220 : /* IGEOLO/NITFImage. */
3221 : /* IGEOLO BLOCKA */
3222 : /* 0, 0 0, MaxCol */
3223 : /* 0, MaxCol MaxRow, MaxCol */
3224 : /* MaxRow, MaxCol MaxRow, 0 */
3225 : /* MaxRow, 0 0, 0 */
3226 : /* ---------------------------------------------------------------- */
3227 : {
3228 2 : double *pdfXYs = &(psImage->dfULX);
3229 :
3230 2 : NITFGetGCP(pachTRE + 34, pdfXYs, 1);
3231 2 : NITFGetGCP(pachTRE + 55, pdfXYs, 2);
3232 2 : NITFGetGCP(pachTRE + 76, pdfXYs, 3);
3233 2 : NITFGetGCP(pachTRE + 97, pdfXYs, 0);
3234 :
3235 2 : psImage->bIsBoxCenterOfPixel = TRUE;
3236 : }
3237 :
3238 : /* ---------------------------------------------------------------- */
3239 : /* Regardless of the former value of ICORDS, the values are now in */
3240 : /* decimal degrees. */
3241 : /* ---------------------------------------------------------------- */
3242 :
3243 2 : psImage->chICORDS = 'D';
3244 :
3245 2 : return TRUE;
3246 : }
3247 :
3248 : /************************************************************************/
3249 : /* NITFReadGEOLOB() */
3250 : /* */
3251 : /* The GEOLOB contains high precision lat/long geotransform */
3252 : /* values. */
3253 : /************************************************************************/
3254 :
3255 8755 : static int NITFReadGEOLOB(NITFImage *psImage)
3256 : {
3257 : const char *pachTRE;
3258 : int nTRESize;
3259 : char szTemp[128];
3260 :
3261 : /* -------------------------------------------------------------------- */
3262 : /* Do we have the TRE? */
3263 : /* -------------------------------------------------------------------- */
3264 : pachTRE =
3265 8755 : NITFFindTRE(psImage->pachTRE, psImage->nTREBytes, "GEOLOB", &nTRESize);
3266 :
3267 8755 : if (pachTRE == NULL)
3268 8737 : return FALSE;
3269 :
3270 18 : if (!CPLTestBoolean(CPLGetConfigOption("NITF_USEGEOLOB", "YES")))
3271 : {
3272 0 : CPLDebug("NITF", "GEOLOB available, but ignored by request.");
3273 0 : return FALSE;
3274 : }
3275 :
3276 18 : if (nTRESize != 48)
3277 : {
3278 0 : CPLError(CE_Failure, CPLE_AppDefined,
3279 : "Cannot read GEOLOB TRE. Wrong size.");
3280 0 : return FALSE;
3281 : }
3282 :
3283 : /* -------------------------------------------------------------------- */
3284 : /* Parse out field values. */
3285 : /* -------------------------------------------------------------------- */
3286 : {
3287 18 : double dfARV = atoi(NITFGetField(szTemp, pachTRE, 0, 9));
3288 18 : double dfBRV = atoi(NITFGetField(szTemp, pachTRE, 9, 9));
3289 :
3290 18 : double dfLSO = CPLAtof(NITFGetField(szTemp, pachTRE, 18, 15));
3291 18 : double dfPSO = CPLAtof(NITFGetField(szTemp, pachTRE, 33, 15));
3292 :
3293 18 : double dfPixelWidth = 360.0 / dfARV;
3294 18 : double dfPixelHeight = 360.0 / dfBRV;
3295 :
3296 18 : psImage->dfULX = dfLSO;
3297 18 : psImage->dfURX = psImage->dfULX + psImage->nCols * dfPixelWidth;
3298 18 : psImage->dfLLX = psImage->dfULX;
3299 18 : psImage->dfLRX = psImage->dfURX;
3300 :
3301 18 : psImage->dfULY = dfPSO;
3302 18 : psImage->dfURY = psImage->dfULY;
3303 18 : psImage->dfLLY = psImage->dfULY - psImage->nRows * dfPixelHeight;
3304 18 : psImage->dfLRY = psImage->dfLLY;
3305 :
3306 18 : psImage->bIsBoxCenterOfPixel = FALSE; // GEOLOB is edge of pixel.
3307 18 : psImage->chICORDS = 'G';
3308 :
3309 18 : CPLDebug("NITF", "IGEOLO bounds overridden by GEOLOB TRE.");
3310 : }
3311 :
3312 18 : return TRUE;
3313 : }
3314 :
3315 : /************************************************************************/
3316 : /* NITFLoadAttributeSection() */
3317 : /* */
3318 : /* Load metadata items from selected attributes in the RPF */
3319 : /* attributes subsection. The items are defined in */
3320 : /* MIL-STD-2411-1 section 5.3.2. */
3321 : /************************************************************************/
3322 :
3323 : // MIL-STD-2411-1 section 5.3.2.
3324 : typedef enum
3325 : {
3326 : RPFAttr_ASCII,
3327 : RPFAttr_UINT,
3328 : RPFAttr_REAL,
3329 : RPFAttr_VARIABLE
3330 : } RPFAttributeType;
3331 :
3332 : typedef struct
3333 : {
3334 : int nAttrID;
3335 : const char *pszGDALMetadataItem;
3336 : int nParamID;
3337 : RPFAttributeType eType;
3338 : int nLength; /* bytes */
3339 : } RPFAttribute;
3340 :
3341 : static const RPFAttribute asRPFAttributes[] = {
3342 : {1, "CurrencyDate", 1, RPFAttr_ASCII, 8},
3343 : {2, "ProductionDate", 1, RPFAttr_ASCII, 8},
3344 : {3, "SignificantDate", 1, RPFAttr_ASCII, 8},
3345 : {4, "DataSeriesDesignation", 1, RPFAttr_ASCII, 10},
3346 : {4, "MapSeriesDesignation", 2, RPFAttr_ASCII, 8},
3347 : {4, "OldHorizontalDatumCode", 3, RPFAttr_ASCII, 4},
3348 : {4, "EditionIdentifier", 4, RPFAttr_ASCII, 7},
3349 : {5, "ProjectionCode", 1, RPFAttr_ASCII, 2},
3350 : {5, "ParameterA", 2, RPFAttr_REAL, 4},
3351 : {5, "ParameterB", 3, RPFAttr_REAL, 4},
3352 : {5, "ParameterC", 4, RPFAttr_REAL, 4},
3353 : {5, "ParameterD", 5, RPFAttr_REAL, 4},
3354 : {6, "VerticalDatumCode", 1, RPFAttr_ASCII, 4},
3355 : {7, "HorizontalDatumCode", 1, RPFAttr_ASCII, 4}, // not in CADRG
3356 : {8, "VerticalAbsoluteAccuracy", 1, RPFAttr_UINT, 4},
3357 : {8, "VerticalAbsoluteAccuracyUnits", 2, RPFAttr_UINT, 2},
3358 : {9, "HorizontalAbsoluteAccuracy", 1, RPFAttr_UINT, 4},
3359 : {9, "HorizontalAbsoluteAccuracyUnits", 2, RPFAttr_UINT, 2},
3360 : {10, "VerticalRelativeAccuracy", 1, RPFAttr_UINT, 4},
3361 : {10, "VerticalRelativeAccuracyUnits", 2, RPFAttr_UINT, 2},
3362 : {11, "HorizontalRelativeAccuracy", 1, RPFAttr_UINT, 4},
3363 : {11, "HorizontalRelativeAccuracyUnits", 2, RPFAttr_UINT, 2},
3364 : {12, "EllipsoidCode", 1, RPFAttr_ASCII, 3},
3365 : {13, "SoundingDatum", 1, RPFAttr_ASCII, 4},
3366 : {14, "NavigationSystemsCode", 1, RPFAttr_UINT, 2},
3367 : {15, "GridCode", 1, RPFAttr_ASCII, 2},
3368 : {16, "EasterlyAnnualMagneticChange", 1, RPFAttr_REAL, 4},
3369 : {16, "EasterlyAnnualMagneticChangeUnits", 2, RPFAttr_UINT, 2},
3370 : {17, "WesterlyAnnualMagneticChange", 1, RPFAttr_REAL, 4},
3371 : {17, "WesterlyAnnualMagneticChangeUnits", 2, RPFAttr_UINT, 2},
3372 : {18, "GridNorthMagneticAngle", 1, RPFAttr_REAL, 4},
3373 : {18, "GridNorthMagneticAngleUnits", 2, RPFAttr_UINT, 2},
3374 : {19, "GridConvergenceAngle", 1, RPFAttr_REAL, 4},
3375 : {19, "GridConvergenceAngleUnits", 2, RPFAttr_UINT, 2},
3376 : {20, "MaximumElevation", 1, RPFAttr_REAL, 8},
3377 : {20, "MaximumElevationUnits", 2, RPFAttr_UINT, 2},
3378 : {20, "MaximumElevationLatitude", 3, RPFAttr_REAL, 8},
3379 : {20, "MaximumElevationLongitude", 4, RPFAttr_REAL, 8},
3380 : {21, "LegendFileName", 1, RPFAttr_ASCII, 12},
3381 : {22, "DataSource", 1, RPFAttr_ASCII, 12},
3382 : {22, "GSD", 2, RPFAttr_UINT, 4},
3383 : {23, "DataLevel", 1, RPFAttr_UINT, 2},
3384 : // Following from MIL-PRF-89038_AMENDMENT-2.pdf
3385 : {24, "NumberOfUpdates", 1, RPFAttr_UINT, 2},
3386 : {24, "UpdateNumber", 2, RPFAttr_UINT, 2},
3387 : {24, "UpdateDate", 3, RPFAttr_ASCII, 8},
3388 : {24, "NumberOfSubframesImpacted", 4, RPFAttr_UINT, 2},
3389 : {24, "ListOfSubframes", 5, RPFAttr_VARIABLE, 0 /* variable */},
3390 : {24, "NumberOfCharactersInDescription", 6, RPFAttr_UINT, 2},
3391 : {24, "ChangeDescription", 7, RPFAttr_ASCII, 0}, // given by previous attr
3392 : {25, "ContourInterval", 1, RPFAttr_UINT, 2},
3393 : {25, "ContourIntervalUnits", 2, RPFAttr_UINT, 2},
3394 : };
3395 :
3396 8755 : static void NITFLoadAttributeSection(NITFImage *psImage)
3397 :
3398 : {
3399 8755 : GUInt32 nASHOffset = 0, /* nASHSize=0, */ nASSOffset = 0, nASSSize = 0,
3400 8755 : nNextOffset = 0;
3401 : GInt16 nAttrCount;
3402 : GByte *pabyAttributeSubsection;
3403 :
3404 10536 : for (int i = 0; i < psImage->nLocCount; i++)
3405 : {
3406 1781 : if (psImage->pasLocations[i].nLocId == LID_AttributeSectionSubheader)
3407 : {
3408 120 : nASHOffset = psImage->pasLocations[i].nLocOffset;
3409 : /* nASHSize = psImage->pasLocations[i].nLocSize; */
3410 : }
3411 1661 : else if (psImage->pasLocations[i].nLocId == LID_AttributeSubsection)
3412 : {
3413 120 : nASSOffset = psImage->pasLocations[i].nLocOffset;
3414 120 : nASSSize = psImage->pasLocations[i].nLocSize;
3415 : }
3416 : }
3417 :
3418 8755 : if (nASSOffset == 0 || nASHOffset == 0)
3419 8635 : return;
3420 :
3421 : /* -------------------------------------------------------------------- */
3422 : /* How many attribute records do we have? */
3423 : /* -------------------------------------------------------------------- */
3424 240 : if (VSIFSeekL(psImage->psFile->fp, nASHOffset, SEEK_SET) != 0 ||
3425 120 : VSIFReadL(&nAttrCount, 2, 1, psImage->psFile->fp) != 1)
3426 0 : return;
3427 :
3428 120 : CPL_MSBPTR16(&nAttrCount);
3429 :
3430 : /* -------------------------------------------------------------------- */
3431 : /* nASSSize Hack */
3432 : /* -------------------------------------------------------------------- */
3433 : /* OK, now, as often with RPF/CADRG, here is the necessary dirty hack */
3434 : /* -- Begin of lengthy explanation -- */
3435 : /* A lot of CADRG files have a nASSSize value that reports a size */
3436 : /* smaller than the genuine size of the attribute subsection in the */
3437 : /* file, so if we trust the nASSSize value, we'll reject existing */
3438 : /* attributes. This is for example the case for */
3439 : /* http://download.osgeo.org/gdal/data/nitf/0000M033.GN3 */
3440 : /* where nASSSize is reported to be 302 bytes for 52 attributes (which */
3441 : /* is odd since 52 * 8 < 302), but a binary inspection of the attribute */
3442 : /* subsection shows that the actual size is 608 bytes, which is also
3443 : * confirmed*/
3444 : /* by the fact that the next subsection (quite often
3445 : * LID_ExplicitArealCoverageTable but not always) */
3446 : /* begins right after. So if this next subsection is found and that the */
3447 : /* difference in offset is larger than the original nASSSize, use it. */
3448 : /* I have observed that nowhere in the NITF driver we make use of the
3449 : * .nLocSize field */
3450 : /* -- End of lengthy explanation -- */
3451 :
3452 1560 : for (int i = 0; i < psImage->nLocCount; i++)
3453 : {
3454 1440 : if (psImage->pasLocations[i].nLocOffset > nASSOffset)
3455 : {
3456 0 : if (nNextOffset == 0 ||
3457 0 : nNextOffset > psImage->pasLocations[i].nLocOffset)
3458 0 : nNextOffset = psImage->pasLocations[i].nLocOffset;
3459 : }
3460 : }
3461 :
3462 120 : if (nNextOffset > 0 && nNextOffset - nASSOffset > nASSSize)
3463 0 : nASSSize = nNextOffset - nASSOffset;
3464 :
3465 : /* -------------------------------------------------------------------- */
3466 : /* Be sure that the attribute subsection is large enough to */
3467 : /* hold the offset table (otherwise NITFFetchAttribute could */
3468 : /* read out of the buffer) */
3469 : /* -------------------------------------------------------------------- */
3470 120 : if (nASSSize < (size_t)(8 * nAttrCount))
3471 : {
3472 0 : CPLError(CE_Warning, CPLE_AppDefined,
3473 : "Attribute subsection not large enough (%d bytes) to contain "
3474 : "%d attributes.",
3475 : nASSSize, nAttrCount);
3476 0 : return;
3477 : }
3478 :
3479 : /* -------------------------------------------------------------------- */
3480 : /* Load the attribute table. */
3481 : /* -------------------------------------------------------------------- */
3482 120 : pabyAttributeSubsection = (GByte *)VSIMalloc(nASSSize);
3483 120 : if (pabyAttributeSubsection == NULL)
3484 : {
3485 0 : CPLError(
3486 : CE_Warning, CPLE_AppDefined,
3487 : "Out of memory failure reading %d bytes of attribute subsection.",
3488 : nASSSize);
3489 0 : return;
3490 : }
3491 :
3492 120 : if (VSIFSeekL(psImage->psFile->fp, nASSOffset, SEEK_SET) != 0 ||
3493 120 : VSIFReadL(pabyAttributeSubsection, 1, nASSSize, psImage->psFile->fp) !=
3494 : nASSSize)
3495 : {
3496 0 : CPLError(CE_Warning, CPLE_FileIO,
3497 : "I/O error when reading attribute subsection.");
3498 0 : CPLFree(pabyAttributeSubsection);
3499 0 : return;
3500 : }
3501 :
3502 : /* -------------------------------------------------------------------- */
3503 : /* Scan the attribute offset table */
3504 : /* -------------------------------------------------------------------- */
3505 : GByte abyBuffer[12]; // max size is for LegendFileName
3506 120 : const int nRPFAttributeDictSize =
3507 : (int)(sizeof(asRPFAttributes) / sizeof(asRPFAttributes[0]));
3508 120 : const bool bShowAllAttributes =
3509 120 : CPLTestBoolean(CPLGetConfigOption("RPF_SHOW_ALL_ATTRIBUTES", "NO"));
3510 612 : for (int i = 0; i < nAttrCount; i++)
3511 : {
3512 492 : const GByte *pabyOffsetRec = pabyAttributeSubsection + i * 8;
3513 7584 : for (int iRPFAttrDict = 0; iRPFAttrDict < nRPFAttributeDictSize;
3514 7092 : iRPFAttrDict++)
3515 : {
3516 7452 : const RPFAttribute *psAttr = &(asRPFAttributes[iRPFAttrDict]);
3517 7452 : const int nAttrID = pabyOffsetRec[0] * 256 + pabyOffsetRec[1];
3518 7452 : const int nParamID = pabyOffsetRec[2];
3519 7452 : if (nAttrID == psAttr->nAttrID && nParamID == psAttr->nParamID &&
3520 : // By default only shows the first three attributes.
3521 132 : (nAttrID <= 3 || bShowAllAttributes))
3522 : {
3523 : // const int nArealCoverageSeqNumber = pabyOffsetRec[3];
3524 :
3525 360 : GUInt32 nAttrOffset = 0;
3526 360 : memcpy(&nAttrOffset, pabyOffsetRec + 4, 4);
3527 360 : CPL_MSBPTR32(&nAttrOffset);
3528 :
3529 360 : const char *pszName = psAttr->pszGDALMetadataItem;
3530 360 : const int nLength = psAttr->nLength;
3531 360 : if (nLength != 0 && (GUInt32)nLength <= nASSSize &&
3532 360 : nAttrOffset <= nASSSize - nLength)
3533 : {
3534 360 : memcpy(abyBuffer, pabyAttributeSubsection + nAttrOffset,
3535 : nLength);
3536 360 : if (psAttr->eType == RPFAttr_ASCII)
3537 : {
3538 360 : NITFExtractMetadata(&(psImage->papszMetadata),
3539 : (char *)abyBuffer, 0, nLength,
3540 : CPLSPrintf("NITF_RPF_%s", pszName));
3541 : }
3542 0 : else if (psAttr->eType == RPFAttr_UINT)
3543 : {
3544 0 : if (nLength == 2)
3545 : {
3546 0 : const uint16_t nVal =
3547 0 : abyBuffer[0] * 256 + abyBuffer[1];
3548 0 : psImage->papszMetadata = CSLSetNameValue(
3549 : psImage->papszMetadata,
3550 : CPLSPrintf("NITF_RPF_%s", pszName),
3551 : CPLSPrintf("%d", nVal));
3552 : }
3553 : else
3554 : {
3555 0 : CPLAssert(nLength == 4);
3556 : uint32_t nVal;
3557 0 : memcpy(&nVal, abyBuffer, sizeof(nVal));
3558 0 : CPL_MSBPTR32(&nVal);
3559 0 : psImage->papszMetadata = CSLSetNameValue(
3560 : psImage->papszMetadata,
3561 : CPLSPrintf("NITF_RPF_%s", pszName),
3562 : CPLSPrintf("%u", nVal));
3563 : }
3564 : }
3565 : else
3566 : {
3567 0 : CPLAssert(psAttr->eType == RPFAttr_REAL);
3568 0 : if (nLength == 4)
3569 : {
3570 : float fVal;
3571 0 : memcpy(&fVal, abyBuffer, sizeof(fVal));
3572 0 : CPL_MSBPTR32(&fVal);
3573 0 : psImage->papszMetadata = CSLSetNameValue(
3574 : psImage->papszMetadata,
3575 : CPLSPrintf("NITF_RPF_%s", pszName),
3576 : CPLSPrintf("%.8g", fVal));
3577 : }
3578 : else
3579 : {
3580 0 : CPLAssert(nLength == 8);
3581 : double dfVal;
3582 0 : memcpy(&dfVal, abyBuffer, sizeof(dfVal));
3583 0 : CPL_MSBPTR64(&dfVal);
3584 0 : psImage->papszMetadata = CSLSetNameValue(
3585 : psImage->papszMetadata,
3586 : CPLSPrintf("NITF_RPF_%s", pszName),
3587 : CPLSPrintf("%.17g", dfVal));
3588 : }
3589 : }
3590 : }
3591 360 : break;
3592 : }
3593 : }
3594 : }
3595 :
3596 120 : CPLFree(pabyAttributeSubsection);
3597 : }
3598 :
3599 : /************************************************************************/
3600 : /* NITFLoadColormapSubSection() */
3601 : /************************************************************************/
3602 :
3603 : /* This function is directly inspired by function parse_clut coming from
3604 : ogdi/driver/rpf/utils.c and placed under the following copyright */
3605 :
3606 : /*
3607 : ******************************************************************************
3608 : * Copyright (C) 1995 Logiciels et Applications Scientifiques (L.A.S.) Inc
3609 : * Permission to use, copy, modify and distribute this software and
3610 : * its documentation for any purpose and without fee is hereby granted,
3611 : * provided that the above copyright notice appear in all copies, that
3612 : * both the copyright notice and this permission notice appear in
3613 : * supporting documentation, and that the name of L.A.S. Inc not be used
3614 : * in advertising or publicity pertaining to distribution of the software
3615 : * without specific, written prior permission. L.A.S. Inc. makes no
3616 : * representations about the suitability of this software for any purpose.
3617 : * It is provided "as is" without express or implied warranty.
3618 : ******************************************************************************
3619 : */
3620 :
3621 8608 : static void NITFLoadColormapSubSection(NITFImage *psImage)
3622 : {
3623 8608 : int nLocBaseColorGrayscaleSection = 0;
3624 8608 : int nLocBaseColormapSubSection = 0;
3625 : /* int colorGrayscaleSectionSize = 0; */
3626 : /* int colormapSubSectionSize = 0; */
3627 8608 : NITFFile *psFile = psImage->psFile;
3628 : unsigned int i, j;
3629 : unsigned char nOffsetRecs;
3630 : NITFColormapRecord *colormapRecords;
3631 : unsigned int colormapOffsetTableOffset;
3632 : unsigned short offsetRecLen;
3633 8608 : int bOK = TRUE;
3634 :
3635 8608 : NITFBandInfo *psBandInfo = psImage->pasBandInfo;
3636 :
3637 10389 : for (i = 0; (int)i < psImage->nLocCount; i++)
3638 : {
3639 1781 : if (psImage->pasLocations[i].nLocId ==
3640 : LID_ColorGrayscaleSectionSubheader)
3641 : {
3642 154 : nLocBaseColorGrayscaleSection = psImage->pasLocations[i].nLocOffset;
3643 : /* colorGrayscaleSectionSize = psImage->pasLocations[i].nLocSize; */
3644 : }
3645 1627 : else if (psImage->pasLocations[i].nLocId == LID_ColormapSubsection)
3646 : {
3647 154 : nLocBaseColormapSubSection = psImage->pasLocations[i].nLocOffset;
3648 : /* colormapSubSectionSize = psImage->pasLocations[i].nLocSize; */
3649 : }
3650 : }
3651 8608 : if (nLocBaseColorGrayscaleSection == 0)
3652 : {
3653 8454 : return;
3654 : }
3655 154 : if (nLocBaseColormapSubSection == 0)
3656 : {
3657 0 : return;
3658 : }
3659 :
3660 308 : if (VSIFSeekL(psFile->fp, nLocBaseColorGrayscaleSection, SEEK_SET) != 0 ||
3661 154 : VSIFReadL(&nOffsetRecs, 1, 1, psFile->fp) != 1)
3662 : {
3663 0 : CPLError(CE_Failure, CPLE_FileIO, "Failed to seek to %d.",
3664 : nLocBaseColorGrayscaleSection);
3665 0 : return;
3666 : }
3667 :
3668 154 : if (VSIFSeekL(psFile->fp, nLocBaseColormapSubSection, SEEK_SET) != 0)
3669 : {
3670 0 : CPLError(CE_Failure, CPLE_FileIO, "Failed to seek to %d.",
3671 : nLocBaseColormapSubSection);
3672 0 : return;
3673 : }
3674 :
3675 154 : colormapRecords = (NITFColormapRecord *)CPLMalloc(
3676 : nOffsetRecs * sizeof(NITFColormapRecord));
3677 :
3678 : /* colormap offset table offset length */
3679 154 : bOK &= VSIFReadL(&colormapOffsetTableOffset,
3680 154 : sizeof(colormapOffsetTableOffset), 1, psFile->fp) == 1;
3681 154 : CPL_MSBPTR32(&colormapOffsetTableOffset);
3682 :
3683 : /* offset record length */
3684 154 : bOK &= VSIFReadL(&offsetRecLen, sizeof(offsetRecLen), 1, psFile->fp) == 1;
3685 154 : CPL_MSBPTR16(&offsetRecLen);
3686 :
3687 616 : for (i = 0; bOK && i < nOffsetRecs; i++)
3688 : {
3689 462 : bOK &=
3690 462 : VSIFReadL(&colormapRecords[i].tableId,
3691 462 : sizeof(colormapRecords[i].tableId), 1, psFile->fp) == 1;
3692 462 : CPL_MSBPTR16(&colormapRecords[i].tableId);
3693 :
3694 462 : bOK &=
3695 462 : VSIFReadL(&colormapRecords[i].nRecords,
3696 462 : sizeof(colormapRecords[i].nRecords), 1, psFile->fp) == 1;
3697 462 : CPL_MSBPTR32(&colormapRecords[i].nRecords);
3698 :
3699 462 : bOK &= VSIFReadL(&colormapRecords[i].elementLength,
3700 : sizeof(colormapRecords[i].elementLength), 1,
3701 462 : psFile->fp) == 1;
3702 :
3703 462 : bOK &= VSIFReadL(&colormapRecords[i].histogramRecordLength,
3704 : sizeof(colormapRecords[i].histogramRecordLength), 1,
3705 462 : psFile->fp) == 1;
3706 462 : CPL_MSBPTR16(&colormapRecords[i].histogramRecordLength);
3707 :
3708 462 : bOK &= VSIFReadL(&colormapRecords[i].colorTableOffset,
3709 : sizeof(colormapRecords[i].colorTableOffset), 1,
3710 462 : psFile->fp) == 1;
3711 462 : CPL_MSBPTR32(&colormapRecords[i].colorTableOffset);
3712 :
3713 462 : bOK &= VSIFReadL(&colormapRecords[i].histogramTableOffset,
3714 : sizeof(colormapRecords[i].histogramTableOffset), 1,
3715 462 : psFile->fp) == 1;
3716 462 : CPL_MSBPTR32(&colormapRecords[i].histogramTableOffset);
3717 : }
3718 :
3719 616 : for (i = 0; bOK && i < nOffsetRecs; i++)
3720 : {
3721 462 : vsi_l_offset nOffset = (vsi_l_offset)nLocBaseColormapSubSection +
3722 462 : colormapRecords[i].colorTableOffset;
3723 462 : if (VSIFSeekL(psFile->fp, nOffset, SEEK_SET) != 0)
3724 : {
3725 0 : CPLError(CE_Failure, CPLE_FileIO,
3726 : "Failed to seek to " CPL_FRMT_GUIB ".", nOffset);
3727 0 : CPLFree(colormapRecords);
3728 0 : return;
3729 : }
3730 :
3731 : /* This test is very CADRG specific. See MIL-C-89038, paragraph 3.12.5.a
3732 : */
3733 462 : if (i == 0 && colormapRecords[i].tableId == 2 &&
3734 154 : colormapRecords[i].elementLength == 4 &&
3735 154 : colormapRecords[i].nRecords == 216) /* read, use colortable */
3736 : {
3737 154 : GByte *rgbm = (GByte *)CPLMalloc(colormapRecords[i].nRecords * 4);
3738 154 : if (VSIFReadL(rgbm, 1, colormapRecords[i].nRecords * 4,
3739 154 : psFile->fp) != colormapRecords[i].nRecords * 4)
3740 : {
3741 0 : CPLError(CE_Failure, CPLE_FileIO,
3742 : "Failed to read %d byte rgbm.",
3743 0 : colormapRecords[i].nRecords * 4);
3744 0 : CPLFree(rgbm);
3745 0 : CPLFree(colormapRecords);
3746 0 : return;
3747 : }
3748 33418 : for (j = 0; j < colormapRecords[i].nRecords; j++)
3749 : {
3750 33264 : psBandInfo->pabyLUT[j] = rgbm[4 * j];
3751 33264 : psBandInfo->pabyLUT[j + 256] = rgbm[4 * j + 1];
3752 33264 : psBandInfo->pabyLUT[j + 512] = rgbm[4 * j + 2];
3753 : }
3754 154 : CPLFree(rgbm);
3755 : }
3756 : }
3757 :
3758 154 : CPLFree(colormapRecords);
3759 : }
3760 :
3761 : /************************************************************************/
3762 : /* NITFLoadSubframeMaskTable() */
3763 : /************************************************************************/
3764 :
3765 : /* Fixes bug #913 */
3766 8755 : static void NITFLoadSubframeMaskTable(NITFImage *psImage,
3767 : bool *pbBlockStartRead)
3768 : {
3769 : int i;
3770 8755 : NITFFile *psFile = psImage->psFile;
3771 8755 : NITFSegmentInfo *psSegInfo = psFile->pasSegmentInfo + psImage->iSegment;
3772 8755 : vsi_l_offset nLocBaseSpatialDataSubsection = psSegInfo->nSegmentStart;
3773 8755 : GUInt32 nLocBaseMaskSubsection = 0;
3774 8755 : vsi_l_offset nLocImageDescriptionSubheader = 0;
3775 : GUInt16 subframeSequenceRecordLength, transparencySequenceRecordLength,
3776 : transparencyOutputPixelCodeLength;
3777 8755 : bool bOK = true;
3778 :
3779 10536 : for (i = 0; i < psImage->nLocCount; i++)
3780 : {
3781 1781 : if (psImage->pasLocations[i].nLocId == LID_SpatialDataSubsection)
3782 : {
3783 154 : nLocBaseSpatialDataSubsection = psImage->pasLocations[i].nLocOffset;
3784 : }
3785 1627 : else if (psImage->pasLocations[i].nLocId == LID_MaskSubsection)
3786 : {
3787 154 : nLocBaseMaskSubsection = psImage->pasLocations[i].nLocOffset;
3788 : }
3789 1473 : else if (psImage->pasLocations[i].nLocId ==
3790 : LID_ImageDescriptionSubheader)
3791 : {
3792 154 : nLocImageDescriptionSubheader = psImage->pasLocations[i].nLocOffset;
3793 : }
3794 : }
3795 8755 : if (nLocBaseMaskSubsection == 0)
3796 : {
3797 : // fprintf(stderr, "nLocBase(LID_MaskSubsection) == 0\n");
3798 8721 : return;
3799 : }
3800 :
3801 : // Reasonable default if ImageDescriptionSubheader is missing assuming
3802 : // the offset follow immediately the header of MaskSubsection which they
3803 : // generally do except for product cjga/cjgaz01/0105f033.ja1, which has
3804 : // however an explicit correct value for SUBFRAME_MASK_TABLE_OFFSET
3805 154 : GUInt32 nSUBFRAME_MASK_TABLE_OFFSET = 6;
3806 154 : if (nLocImageDescriptionSubheader > 0)
3807 : {
3808 154 : if (VSIFSeekL(psFile->fp, nLocImageDescriptionSubheader + 20,
3809 : SEEK_SET) != 0)
3810 : {
3811 0 : CPLError(CE_Failure, CPLE_FileIO, "Failed to seek to %" PRIu64,
3812 : ((uint64_t)nLocImageDescriptionSubheader) + 20);
3813 0 : return;
3814 : }
3815 :
3816 154 : bOK &=
3817 154 : VSIFReadL(&nSUBFRAME_MASK_TABLE_OFFSET,
3818 154 : sizeof(nSUBFRAME_MASK_TABLE_OFFSET), 1, psFile->fp) == 1;
3819 154 : CPL_MSBPTR32(&nSUBFRAME_MASK_TABLE_OFFSET);
3820 : }
3821 :
3822 : // fprintf(stderr, "nLocBaseMaskSubsection = %d\n", nLocBaseMaskSubsection);
3823 154 : if (VSIFSeekL(psFile->fp, nLocBaseMaskSubsection, SEEK_SET) != 0)
3824 : {
3825 0 : CPLError(CE_Failure, CPLE_FileIO, "Failed to seek to %u",
3826 : nLocBaseMaskSubsection);
3827 0 : return;
3828 : }
3829 :
3830 154 : bOK &= VSIFReadL(&subframeSequenceRecordLength,
3831 154 : sizeof(subframeSequenceRecordLength), 1, psFile->fp) == 1;
3832 154 : CPL_MSBPTR16(&subframeSequenceRecordLength);
3833 :
3834 154 : bOK &=
3835 154 : VSIFReadL(&transparencySequenceRecordLength,
3836 154 : sizeof(transparencySequenceRecordLength), 1, psFile->fp) == 1;
3837 154 : CPL_MSBPTR16(&transparencySequenceRecordLength);
3838 :
3839 : /* in bits */
3840 154 : bOK &= VSIFReadL(&transparencyOutputPixelCodeLength,
3841 : sizeof(transparencyOutputPixelCodeLength), 1,
3842 154 : psFile->fp) == 1;
3843 154 : CPL_MSBPTR16(&transparencyOutputPixelCodeLength);
3844 :
3845 : // fprintf(stderr, "transparencyOutputPixelCodeLength=%d\n",
3846 : // transparencyOutputPixelCodeLength);
3847 :
3848 154 : if (transparencyOutputPixelCodeLength == 8)
3849 : {
3850 : GByte byNodata;
3851 :
3852 104 : if (bOK && VSIFReadL(&byNodata, 1, 1, psFile->fp) == 1)
3853 : {
3854 104 : psImage->bNoDataSet = TRUE;
3855 104 : psImage->nNoDataValue = byNodata;
3856 : }
3857 : }
3858 : else
3859 : {
3860 50 : bOK &=
3861 50 : VSIFSeekL(psFile->fp, (transparencyOutputPixelCodeLength + 7) / 8,
3862 50 : SEEK_CUR) == 0;
3863 : }
3864 :
3865 : /* Fix for rpf/cjnc/cjncz01/0001f023.jn1 */
3866 154 : if (!bOK || subframeSequenceRecordLength != 4 ||
3867 34 : nSUBFRAME_MASK_TABLE_OFFSET == UINT_MAX)
3868 : {
3869 : // fprintf(stderr, "subframeSequenceRecordLength=%d\n",
3870 : // subframeSequenceRecordLength);
3871 120 : return;
3872 : }
3873 34 : if (nSUBFRAME_MASK_TABLE_OFFSET < 6)
3874 : {
3875 0 : CPLError(CE_Warning, CPLE_AppDefined,
3876 : "Invalid value for SUBFRAME_MASK_TABLE_OFFSET: %u. Ignoring "
3877 : "block start table",
3878 : nSUBFRAME_MASK_TABLE_OFFSET);
3879 0 : return;
3880 : }
3881 :
3882 68 : bOK &= (VSIFSeekL(psFile->fp,
3883 34 : nLocBaseMaskSubsection + nSUBFRAME_MASK_TABLE_OFFSET,
3884 34 : SEEK_SET) == 0);
3885 :
3886 1258 : for (i = 0; bOK && i < psImage->nBlocksPerRow * psImage->nBlocksPerColumn;
3887 1224 : i++)
3888 : {
3889 : unsigned int offset;
3890 1224 : bOK = VSIFReadL(&offset, sizeof(offset), 1, psFile->fp) == 1;
3891 1224 : CPL_MSBPTR32(&offset);
3892 : // fprintf(stderr, "%u : %d\n", i, offset);
3893 1224 : if (!bOK || offset == UINT_MAX)
3894 1224 : psImage->panBlockStart[i] = UINT_MAX;
3895 : else
3896 0 : psImage->panBlockStart[i] = nLocBaseSpatialDataSubsection + offset;
3897 : }
3898 :
3899 34 : *pbBlockStartRead = bOK;
3900 : }
3901 :
3902 2351 : static GUInt16 NITFReadMSBGUInt16(VSILFILE *fp, int *pbSuccess)
3903 : {
3904 : GUInt16 nVal;
3905 2351 : if (VSIFReadL(&nVal, 1, sizeof(nVal), fp) != sizeof(nVal))
3906 : {
3907 0 : *pbSuccess = FALSE;
3908 0 : return 0;
3909 : }
3910 2351 : CPL_MSBPTR16(&nVal);
3911 2351 : return nVal;
3912 : }
3913 :
3914 4022 : static GUInt32 NITFReadMSBGUInt32(VSILFILE *fp, int *pbSuccess)
3915 : {
3916 : GUInt32 nVal;
3917 4022 : if (VSIFReadL(&nVal, 1, sizeof(nVal), fp) != sizeof(nVal))
3918 : {
3919 0 : *pbSuccess = FALSE;
3920 0 : return 0;
3921 : }
3922 4022 : CPL_MSBPTR32(&nVal);
3923 4022 : return nVal;
3924 : }
3925 :
3926 : /************************************************************************/
3927 : /* NITFReadRPFLocationTable() */
3928 : /************************************************************************/
3929 :
3930 170 : NITFLocation *NITFReadRPFLocationTable(VSILFILE *fp, int *pnLocCount)
3931 : {
3932 : /* GUInt16 nLocSectionLength; */
3933 : GUInt32 nLocSectionOffset;
3934 : GUInt16 iLoc;
3935 : GUInt16 nLocCount;
3936 : GUInt16 nLocRecordLength;
3937 : /* GUInt32 nLocComponentAggregateLength; */
3938 170 : NITFLocation *pasLocations = NULL;
3939 : int bSuccess;
3940 : GUIntBig nCurOffset;
3941 :
3942 170 : if (fp == NULL || pnLocCount == NULL)
3943 0 : return NULL;
3944 :
3945 170 : *pnLocCount = 0;
3946 :
3947 170 : nCurOffset = VSIFTellL(fp);
3948 :
3949 170 : bSuccess = TRUE;
3950 170 : /* nLocSectionLength = */ NITFReadMSBGUInt16(fp, &bSuccess);
3951 170 : nLocSectionOffset = NITFReadMSBGUInt32(fp, &bSuccess);
3952 170 : if (nLocSectionOffset != 14)
3953 : {
3954 0 : CPLDebug("NITF", "Unusual location section offset : %d",
3955 : nLocSectionOffset);
3956 : }
3957 :
3958 170 : nLocCount = NITFReadMSBGUInt16(fp, &bSuccess);
3959 :
3960 170 : if (!bSuccess || nLocCount == 0)
3961 : {
3962 0 : return NULL;
3963 : }
3964 :
3965 170 : nLocRecordLength = NITFReadMSBGUInt16(fp, &bSuccess);
3966 170 : if (nLocRecordLength != 10)
3967 : {
3968 0 : CPLError(CE_Failure, CPLE_AppDefined,
3969 : "Did not get expected record length : %d", nLocRecordLength);
3970 0 : return NULL;
3971 : }
3972 :
3973 170 : /* nLocComponentAggregateLength = */ NITFReadMSBGUInt32(fp, &bSuccess);
3974 :
3975 170 : bSuccess = VSIFSeekL(fp, nCurOffset + nLocSectionOffset, SEEK_SET) == 0;
3976 :
3977 : pasLocations =
3978 170 : (NITFLocation *)VSI_CALLOC_VERBOSE(sizeof(NITFLocation), nLocCount);
3979 170 : if (pasLocations == NULL)
3980 : {
3981 0 : return NULL;
3982 : }
3983 :
3984 : /* -------------------------------------------------------------------- */
3985 : /* Process the locations. */
3986 : /* -------------------------------------------------------------------- */
3987 2011 : for (iLoc = 0; bSuccess && iLoc < nLocCount; iLoc++)
3988 : {
3989 1841 : pasLocations[iLoc].nLocId = NITFReadMSBGUInt16(fp, &bSuccess);
3990 1841 : pasLocations[iLoc].nLocSize = NITFReadMSBGUInt32(fp, &bSuccess);
3991 1841 : pasLocations[iLoc].nLocOffset = NITFReadMSBGUInt32(fp, &bSuccess);
3992 1841 : CPLDebugOnly("NITF", "Location[%d]: id=%d, size=%u, offset=%u", iLoc,
3993 : pasLocations[iLoc].nLocId, pasLocations[iLoc].nLocSize,
3994 : pasLocations[iLoc].nLocOffset);
3995 : }
3996 :
3997 170 : if (!bSuccess)
3998 : {
3999 0 : CPLFree(pasLocations);
4000 0 : return NULL;
4001 : }
4002 :
4003 170 : *pnLocCount = nLocCount;
4004 170 : return pasLocations;
4005 : }
4006 :
4007 : /************************************************************************/
4008 : /* NITFLoadLocationTable() */
4009 : /************************************************************************/
4010 :
4011 8755 : static void NITFLoadLocationTable(NITFImage *psImage)
4012 :
4013 : {
4014 : /* -------------------------------------------------------------------- */
4015 : /* Get the location table out of the RPFIMG TRE on the image. */
4016 : /* -------------------------------------------------------------------- */
4017 : const char *pszTRE;
4018 8755 : GUInt32 nHeaderOffset = 0;
4019 : int i;
4020 : int nTRESize;
4021 : char szTempFileName[256];
4022 : VSILFILE *fpTemp;
4023 :
4024 : pszTRE =
4025 8755 : NITFFindTRE(psImage->pachTRE, psImage->nTREBytes, "RPFIMG", &nTRESize);
4026 8755 : if (pszTRE == NULL)
4027 8600 : return;
4028 :
4029 155 : snprintf(szTempFileName, sizeof(szTempFileName), "%s",
4030 : VSIMemGenerateHiddenFilename("nitf_tre"));
4031 : fpTemp =
4032 155 : VSIFileFromMemBuffer(szTempFileName, (GByte *)pszTRE, nTRESize, FALSE);
4033 155 : psImage->pasLocations =
4034 155 : NITFReadRPFLocationTable(fpTemp, &psImage->nLocCount);
4035 155 : CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fpTemp));
4036 155 : VSIUnlink(szTempFileName);
4037 :
4038 155 : if (psImage->nLocCount == 0)
4039 0 : return;
4040 :
4041 : /* -------------------------------------------------------------------- */
4042 : /* It seems that sometimes (at least for bug #1313 and #1714) */
4043 : /* the RPF headers are improperly placed. We check by looking */
4044 : /* to see if the RPFHDR is where it should be. If not, we */
4045 : /* disregard the location table. */
4046 : /* */
4047 : /* The NITF21_CGM_ANNO_Uncompressed_unmasked.ntf sample data */
4048 : /* file (see gdal data downloads) is an example of this. */
4049 : /* -------------------------------------------------------------------- */
4050 1936 : for (i = 0; i < psImage->nLocCount; i++)
4051 : {
4052 1781 : if (psImage->pasLocations[i].nLocId == LID_HeaderComponent)
4053 : {
4054 0 : nHeaderOffset = psImage->pasLocations[i].nLocOffset;
4055 0 : break;
4056 : }
4057 : }
4058 :
4059 155 : if (nHeaderOffset > 11)
4060 : {
4061 : char achHeaderChunk[1000];
4062 :
4063 0 : if (VSIFSeekL(psImage->psFile->fp, nHeaderOffset - 11, SEEK_SET) != 0 ||
4064 0 : VSIFReadL(achHeaderChunk, sizeof(achHeaderChunk), 1,
4065 0 : psImage->psFile->fp) != 1)
4066 : {
4067 0 : CPLFree(psImage->pasLocations);
4068 0 : psImage->pasLocations = NULL;
4069 0 : psImage->nLocCount = 0;
4070 0 : return;
4071 : }
4072 :
4073 : /* You can define NITF_DISABLE_RPF_LOCATION_TABLE_SANITY_TESTS to TRUE
4074 : */
4075 : /* to blindly trust the RPF location table even if it doesn't look */
4076 : /* sane. Necessary for dataset attached to
4077 : * http://trac.osgeo.org/gdal/ticket/3930 */
4078 0 : if (!STARTS_WITH_CI(achHeaderChunk, "RPFHDR") &&
4079 0 : !CPLTestBoolean(CPLGetConfigOption(
4080 : "NITF_DISABLE_RPF_LOCATION_TABLE_SANITY_TESTS", "FALSE")))
4081 : {
4082 : /* Image of http://trac.osgeo.org/gdal/ticket/3848 has incorrect */
4083 : /* RPFHDR offset, but all other locations are correct... */
4084 : /* So if we find LID_CoverageSectionSubheader and
4085 : * LID_CompressionLookupSubsection */
4086 : /* we check whether their content is valid. */
4087 0 : int bFoundValidLocation = FALSE;
4088 0 : for (i = 0; i < psImage->nLocCount; i++)
4089 : {
4090 0 : if (psImage->pasLocations[i].nLocId ==
4091 0 : LID_CoverageSectionSubheader &&
4092 0 : (psImage->chICORDS == 'G' || psImage->chICORDS == 'D'))
4093 0 : {
4094 : /* Does that look like valid latitude/longitude values ? */
4095 : /* We test that they are close enough from the values of the
4096 : * IGEOLO record */
4097 : double adfTarget[8];
4098 :
4099 0 : if (VSIFSeekL(psImage->psFile->fp,
4100 0 : psImage->pasLocations[i].nLocOffset,
4101 0 : SEEK_SET) != 0 ||
4102 0 : VSIFReadL(adfTarget, 8, 8, psImage->psFile->fp) != 8)
4103 : {
4104 0 : CPLFree(psImage->pasLocations);
4105 0 : psImage->pasLocations = NULL;
4106 0 : psImage->nLocCount = 0;
4107 0 : return;
4108 : }
4109 0 : for (i = 0; i < 8; i++)
4110 0 : CPL_MSBPTR64((adfTarget + i));
4111 :
4112 0 : if (fabs(psImage->dfULX - adfTarget[1]) < 0.1 &&
4113 0 : fabs(psImage->dfULY - adfTarget[0]) < 0.1 &&
4114 0 : fabs(psImage->dfLLX - adfTarget[3]) < 0.1 &&
4115 0 : fabs(psImage->dfLLY - adfTarget[2]) < 0.1 &&
4116 0 : fabs(psImage->dfURX - adfTarget[5]) < 0.1 &&
4117 0 : fabs(psImage->dfURY - adfTarget[4]) < 0.1 &&
4118 0 : fabs(psImage->dfLRX - adfTarget[7]) < 0.1 &&
4119 0 : fabs(psImage->dfLRY - adfTarget[6]) < 0.1)
4120 : {
4121 0 : bFoundValidLocation = TRUE;
4122 : }
4123 : else
4124 : {
4125 0 : CPLDebug("NITF", "The CoverageSectionSubheader content "
4126 : "isn't consistent");
4127 0 : bFoundValidLocation = FALSE;
4128 0 : break;
4129 : }
4130 : }
4131 0 : else if (psImage->pasLocations[i].nLocId ==
4132 : LID_CompressionLookupSubsection)
4133 : {
4134 0 : if (NITFLoadVQTables(psImage, FALSE))
4135 : {
4136 0 : bFoundValidLocation = TRUE;
4137 : }
4138 : else
4139 : {
4140 0 : CPLDebug("NITF",
4141 : "The VQ tables content aren't consistent");
4142 0 : bFoundValidLocation = FALSE;
4143 0 : break;
4144 : }
4145 : }
4146 : }
4147 0 : if (bFoundValidLocation)
4148 : {
4149 0 : CPLDebug("NITF", "RPFHDR is not correctly placed, but other "
4150 : "locations seem correct. Going on...");
4151 : }
4152 : else
4153 : {
4154 0 : CPLError(CE_Warning, CPLE_AppDefined,
4155 : "Ignoring NITF RPF Location table since it seems to "
4156 : "be corrupt.");
4157 0 : CPLFree(psImage->pasLocations);
4158 0 : psImage->pasLocations = NULL;
4159 0 : psImage->nLocCount = 0;
4160 : }
4161 : }
4162 : }
4163 : }
4164 :
4165 : /************************************************************************/
4166 : /* NITFLoadVQTables() */
4167 : /************************************************************************/
4168 :
4169 8755 : static int NITFLoadVQTables(NITFImage *psImage, int bTryGuessingOffset)
4170 :
4171 : {
4172 : int i;
4173 8755 : GUInt32 nVQOffset = 0 /*, nVQSize=0 */;
4174 : GByte abyTestChunk[1000];
4175 8755 : const GByte abySignature[6] = {0x00, 0x00, 0x00, 0x06, 0x00, 0x0E};
4176 :
4177 : /* -------------------------------------------------------------------- */
4178 : /* Do we already have the VQ tables? */
4179 : /* -------------------------------------------------------------------- */
4180 8755 : if (psImage->apanVQLUT[0] != NULL)
4181 0 : return TRUE;
4182 :
4183 : /* -------------------------------------------------------------------- */
4184 : /* Do we have the location information? */
4185 : /* -------------------------------------------------------------------- */
4186 10536 : for (i = 0; i < psImage->nLocCount; i++)
4187 : {
4188 1781 : if (psImage->pasLocations[i].nLocId == LID_CompressionLookupSubsection)
4189 : {
4190 154 : nVQOffset = psImage->pasLocations[i].nLocOffset;
4191 : /* nVQSize = psImage->pasLocations[i].nLocSize; */
4192 : }
4193 : }
4194 :
4195 8755 : if (nVQOffset == 0)
4196 8601 : return FALSE;
4197 :
4198 : /* -------------------------------------------------------------------- */
4199 : /* Does it look like we have the tables properly identified? */
4200 : /* -------------------------------------------------------------------- */
4201 308 : if (VSIFSeekL(psImage->psFile->fp, nVQOffset, SEEK_SET) != 0 ||
4202 154 : VSIFReadL(abyTestChunk, sizeof(abyTestChunk), 1, psImage->psFile->fp) !=
4203 : 1)
4204 : {
4205 0 : return FALSE;
4206 : }
4207 :
4208 154 : if (memcmp(abyTestChunk, abySignature, sizeof(abySignature)) != 0)
4209 : {
4210 0 : int bFoundSignature = FALSE;
4211 0 : if (!bTryGuessingOffset)
4212 0 : return FALSE;
4213 :
4214 0 : for (i = 0; (size_t)i < sizeof(abyTestChunk) - sizeof(abySignature);
4215 0 : i++)
4216 : {
4217 0 : if (memcmp(abyTestChunk + i, abySignature, sizeof(abySignature)) ==
4218 : 0)
4219 : {
4220 0 : bFoundSignature = TRUE;
4221 0 : nVQOffset += i;
4222 0 : CPLDebug("NITF",
4223 : "VQ CompressionLookupSubsection offsets off by %d "
4224 : "bytes, adjusting accordingly.",
4225 : i);
4226 0 : break;
4227 : }
4228 : }
4229 0 : if (!bFoundSignature)
4230 0 : return FALSE;
4231 : }
4232 :
4233 : /* -------------------------------------------------------------------- */
4234 : /* Load the tables. */
4235 : /* -------------------------------------------------------------------- */
4236 770 : for (i = 0; i < 4; i++)
4237 : {
4238 : GUInt32 nVQVector;
4239 : int bOK;
4240 :
4241 616 : psImage->apanVQLUT[i] = (GUInt32 *)CPLCalloc(4096, sizeof(GUInt32));
4242 :
4243 616 : bOK = VSIFSeekL(psImage->psFile->fp, nVQOffset + 6 + i * 14 + 10,
4244 616 : SEEK_SET) == 0;
4245 616 : bOK &= VSIFReadL(&nVQVector, 1, 4, psImage->psFile->fp) == 4;
4246 616 : nVQVector = CPL_MSBWORD32(nVQVector);
4247 :
4248 1232 : bOK &= VSIFSeekL(psImage->psFile->fp,
4249 616 : (vsi_l_offset)(nVQOffset) + nVQVector, SEEK_SET) == 0;
4250 616 : bOK &= VSIFReadL(psImage->apanVQLUT[i], 4, 4096, psImage->psFile->fp) ==
4251 : 4096;
4252 616 : if (!bOK)
4253 : {
4254 0 : for (i = 0; i < 4; i++)
4255 : {
4256 0 : CPLFree(psImage->apanVQLUT[i]);
4257 0 : psImage->apanVQLUT[i] = NULL;
4258 : }
4259 0 : return FALSE;
4260 : }
4261 : }
4262 :
4263 154 : return TRUE;
4264 : }
4265 :
4266 : /************************************************************************/
4267 : /* NITFReadSTDIDC() */
4268 : /* */
4269 : /* Read a STDIDC TRE and return contents as metadata strings. */
4270 : /************************************************************************/
4271 :
4272 0 : char **NITFReadSTDIDC(NITFImage *psImage)
4273 :
4274 : {
4275 0 : return NITFGenericMetadataRead(NULL, NULL, psImage, "STDIDC");
4276 : }
4277 :
4278 : /************************************************************************/
4279 : /* NITFRPCGeoToImage() */
4280 : /************************************************************************/
4281 :
4282 0 : int NITFRPCGeoToImage(NITFRPC00BInfo *psRPC, double dfLong, double dfLat,
4283 : double dfHeight, double *pdfPixel, double *pdfLine)
4284 :
4285 : {
4286 : double dfLineNumerator, dfLineDenominator, dfPixelNumerator,
4287 : dfPixelDenominator;
4288 : double dfPolyTerm[20];
4289 0 : double *pdfPolyTerm = dfPolyTerm;
4290 : int i;
4291 :
4292 : /* -------------------------------------------------------------------- */
4293 : /* Normalize Lat/Long position. */
4294 : /* -------------------------------------------------------------------- */
4295 0 : dfLong = (dfLong - psRPC->LONG_OFF) / psRPC->LONG_SCALE;
4296 0 : dfLat = (dfLat - psRPC->LAT_OFF) / psRPC->LAT_SCALE;
4297 0 : dfHeight = (dfHeight - psRPC->HEIGHT_OFF) / psRPC->HEIGHT_SCALE;
4298 :
4299 : /* -------------------------------------------------------------------- */
4300 : /* Compute the 20 terms. */
4301 : /* -------------------------------------------------------------------- */
4302 :
4303 0 : pdfPolyTerm[0] = 1.0; /* workaround cppcheck false positive */
4304 0 : dfPolyTerm[1] = dfLong;
4305 0 : dfPolyTerm[2] = dfLat;
4306 0 : dfPolyTerm[3] = dfHeight;
4307 0 : dfPolyTerm[4] = dfLong * dfLat;
4308 0 : dfPolyTerm[5] = dfLong * dfHeight;
4309 0 : dfPolyTerm[6] = dfLat * dfHeight;
4310 0 : dfPolyTerm[7] = dfLong * dfLong;
4311 0 : dfPolyTerm[8] = dfLat * dfLat;
4312 0 : dfPolyTerm[9] = dfHeight * dfHeight;
4313 :
4314 0 : dfPolyTerm[10] = dfLong * dfLat * dfHeight;
4315 0 : dfPolyTerm[11] = dfLong * dfLong * dfLong;
4316 0 : dfPolyTerm[12] = dfLong * dfLat * dfLat;
4317 0 : dfPolyTerm[13] = dfLong * dfHeight * dfHeight;
4318 0 : dfPolyTerm[14] = dfLong * dfLong * dfLat;
4319 0 : dfPolyTerm[15] = dfLat * dfLat * dfLat;
4320 0 : dfPolyTerm[16] = dfLat * dfHeight * dfHeight;
4321 0 : dfPolyTerm[17] = dfLong * dfLong * dfHeight;
4322 0 : dfPolyTerm[18] = dfLat * dfLat * dfHeight;
4323 0 : dfPolyTerm[19] = dfHeight * dfHeight * dfHeight;
4324 :
4325 : /* -------------------------------------------------------------------- */
4326 : /* Compute numerator and denominator sums. */
4327 : /* -------------------------------------------------------------------- */
4328 0 : dfPixelNumerator = 0.0;
4329 0 : dfPixelDenominator = 0.0;
4330 0 : dfLineNumerator = 0.0;
4331 0 : dfLineDenominator = 0.0;
4332 :
4333 0 : for (i = 0; i < 20; i++)
4334 : {
4335 0 : dfPixelNumerator += psRPC->SAMP_NUM_COEFF[i] * dfPolyTerm[i];
4336 0 : dfPixelDenominator += psRPC->SAMP_DEN_COEFF[i] * dfPolyTerm[i];
4337 0 : dfLineNumerator += psRPC->LINE_NUM_COEFF[i] * dfPolyTerm[i];
4338 0 : dfLineDenominator += psRPC->LINE_DEN_COEFF[i] * dfPolyTerm[i];
4339 : }
4340 :
4341 : /* -------------------------------------------------------------------- */
4342 : /* Compute normalized pixel and line values. */
4343 : /* -------------------------------------------------------------------- */
4344 0 : *pdfPixel = dfPixelNumerator / dfPixelDenominator;
4345 0 : *pdfLine = dfLineNumerator / dfLineDenominator;
4346 :
4347 : /* -------------------------------------------------------------------- */
4348 : /* Denormalize. */
4349 : /* -------------------------------------------------------------------- */
4350 0 : *pdfPixel = *pdfPixel * psRPC->SAMP_SCALE + psRPC->SAMP_OFF;
4351 0 : *pdfLine = *pdfLine * psRPC->LINE_SCALE + psRPC->LINE_OFF;
4352 :
4353 0 : return TRUE;
4354 : }
4355 :
4356 : /************************************************************************/
4357 : /* NITFIHFieldOffset() */
4358 : /* */
4359 : /* Find the file offset for the beginning of a particular field */
4360 : /* in this image header. Only implemented for selected fields. */
4361 : /************************************************************************/
4362 :
4363 33 : GUIntBig NITFIHFieldOffset(NITFImage *psImage, const char *pszFieldName)
4364 :
4365 : {
4366 : char szTemp[128];
4367 : int nNICOM;
4368 : GUIntBig nWrkOffset;
4369 33 : GUIntBig nIMOffset =
4370 33 : psImage->psFile->pasSegmentInfo[psImage->iSegment].nSegmentHeaderStart;
4371 :
4372 : // We only support files we created.
4373 33 : if (!STARTS_WITH_CI(psImage->psFile->szVersion, "NITF02.1"))
4374 : {
4375 0 : CPLError(CE_Failure, CPLE_AppDefined,
4376 : "NITFIHFieldOffset() only works with NITF 2.1 images");
4377 0 : return 0;
4378 : }
4379 :
4380 33 : if (EQUAL(pszFieldName, "IM"))
4381 0 : return nIMOffset;
4382 :
4383 33 : if (EQUAL(pszFieldName, "PJUST"))
4384 0 : return nIMOffset + 370;
4385 :
4386 33 : if (EQUAL(pszFieldName, "ICORDS"))
4387 0 : return nIMOffset + 371;
4388 :
4389 33 : if (EQUAL(pszFieldName, "IGEOLO"))
4390 : {
4391 0 : if (!psImage->bHaveIGEOLO)
4392 0 : return 0;
4393 : else
4394 0 : return nIMOffset + 372;
4395 : }
4396 :
4397 : /* -------------------------------------------------------------------- */
4398 : /* Keep working offset from here on in since everything else is */
4399 : /* variable. */
4400 : /* -------------------------------------------------------------------- */
4401 33 : nWrkOffset = 372 + nIMOffset;
4402 :
4403 33 : if (psImage->bHaveIGEOLO)
4404 30 : nWrkOffset += 60;
4405 :
4406 : /* -------------------------------------------------------------------- */
4407 : /* Comments. */
4408 : /* -------------------------------------------------------------------- */
4409 66 : nNICOM = atoi(NITFGetField(szTemp, psImage->pachHeader,
4410 33 : (int)(nWrkOffset - nIMOffset), 1));
4411 :
4412 33 : if (EQUAL(pszFieldName, "NICOM"))
4413 0 : return nWrkOffset;
4414 :
4415 33 : nWrkOffset++;
4416 :
4417 33 : if (EQUAL(pszFieldName, "ICOM"))
4418 0 : return nWrkOffset;
4419 :
4420 33 : nWrkOffset += 80 * nNICOM;
4421 :
4422 : /* -------------------------------------------------------------------- */
4423 : /* IC */
4424 : /* -------------------------------------------------------------------- */
4425 33 : if (EQUAL(pszFieldName, "IC"))
4426 0 : return nWrkOffset;
4427 :
4428 33 : nWrkOffset += 2;
4429 :
4430 : /* -------------------------------------------------------------------- */
4431 : /* COMRAT */
4432 : /* -------------------------------------------------------------------- */
4433 :
4434 33 : if (psImage->szIC[0] != 'N')
4435 : {
4436 3 : if (EQUAL(pszFieldName, "COMRAT"))
4437 0 : return nWrkOffset;
4438 3 : nWrkOffset += 4;
4439 : }
4440 :
4441 : /* -------------------------------------------------------------------- */
4442 : /* NBANDS */
4443 : /* -------------------------------------------------------------------- */
4444 33 : if (EQUAL(pszFieldName, "NBANDS"))
4445 0 : return nWrkOffset;
4446 :
4447 33 : nWrkOffset += 1;
4448 :
4449 : /* -------------------------------------------------------------------- */
4450 : /* XBANDS */
4451 : /* -------------------------------------------------------------------- */
4452 33 : if (EQUAL(pszFieldName, "XBANDS"))
4453 0 : return nWrkOffset;
4454 :
4455 33 : if (psImage->nBands > 9)
4456 0 : nWrkOffset += 5;
4457 :
4458 : /* -------------------------------------------------------------------- */
4459 : /* IREPBAND */
4460 : /* -------------------------------------------------------------------- */
4461 33 : if (EQUAL(pszFieldName, "IREPBAND"))
4462 33 : return nWrkOffset;
4463 :
4464 : // nWrkOffset += 2 * psImage->nBands;
4465 :
4466 0 : return 0;
4467 : }
4468 :
4469 : /************************************************************************/
4470 : /* NITFDoLinesIntersect() */
4471 : /************************************************************************/
4472 :
4473 386 : static int NITFDoLinesIntersect(double dfL1X1, double dfL1Y1, double dfL1X2,
4474 : double dfL1Y2, double dfL2X1, double dfL2Y1,
4475 : double dfL2X2, double dfL2Y2)
4476 :
4477 : {
4478 : double dfL1M, dfL1B, dfL2M, dfL2B;
4479 :
4480 386 : if (dfL1X1 == dfL1X2)
4481 : {
4482 353 : dfL1M = 1e10;
4483 353 : dfL1B = 0.0;
4484 : }
4485 : else
4486 : {
4487 33 : dfL1M = (dfL1Y2 - dfL1Y1) / (dfL1X2 - dfL1X1);
4488 33 : dfL1B = dfL1Y2 - dfL1M * dfL1X2;
4489 : }
4490 :
4491 386 : if (dfL2X1 == dfL2X2)
4492 : {
4493 353 : dfL2M = 1e10;
4494 353 : dfL2B = 0.0;
4495 : }
4496 : else
4497 : {
4498 33 : dfL2M = (dfL2Y2 - dfL2Y1) / (dfL2X2 - dfL2X1);
4499 33 : dfL2B = dfL2Y2 - dfL2M * dfL2X2;
4500 : }
4501 :
4502 386 : if (dfL2M == dfL1M)
4503 : {
4504 : // parallel .. no meaningful intersection.
4505 358 : return FALSE;
4506 : }
4507 : else
4508 : {
4509 : double dfX /*, dfY*/;
4510 :
4511 28 : dfX = (dfL2B - dfL1B) / (dfL1M - dfL2M);
4512 : /* dfY = dfL2M * dfX + dfL2B; */
4513 :
4514 : /*
4515 : ** Is this intersection on the line between
4516 : ** our corner points or "out somewhere" else?
4517 : */
4518 28 : return ((dfX >= dfL1X1 && dfX <= dfL1X2) ||
4519 56 : (dfX >= dfL1X2 && dfX <= dfL1X1)) &&
4520 0 : ((dfX >= dfL2X1 && dfX <= dfL2X2) ||
4521 0 : (dfX >= dfL2X2 && dfX <= dfL2X1));
4522 : }
4523 : }
4524 :
4525 : /************************************************************************/
4526 : /* NITFPossibleIGEOLOReorientation() */
4527 : /************************************************************************/
4528 :
4529 386 : static void NITFPossibleIGEOLOReorientation(NITFImage *psImage)
4530 :
4531 : {
4532 : /* -------------------------------------------------------------------- */
4533 : /* Check whether the vector from top left to bottom left */
4534 : /* intersects the line from top right to bottom right. If this */
4535 : /* is true, then we believe the corner coordinate order was */
4536 : /* written improperly. */
4537 : /* -------------------------------------------------------------------- */
4538 : #if 1
4539 386 : if (!NITFDoLinesIntersect(psImage->dfULX, psImage->dfULY, psImage->dfLLX,
4540 : psImage->dfLLY, psImage->dfURX, psImage->dfURY,
4541 : psImage->dfLRX, psImage->dfLRY))
4542 386 : return;
4543 : else
4544 0 : CPLDebug("NITF", "It appears the IGEOLO corner coordinates were "
4545 : "written improperly!");
4546 : #endif
4547 :
4548 : /* -------------------------------------------------------------------- */
4549 : /* Divide the lat/long extents of this image into four */
4550 : /* quadrants and assign the corners based on which point falls */
4551 : /* into which quadrant. This is intended to correct images */
4552 : /* with the corner points written improperly. Unfortunately it */
4553 : /* also breaks images which are mirrored, or rotated more than */
4554 : /* 90 degrees from simple north up. */
4555 : /* -------------------------------------------------------------------- */
4556 : {
4557 :
4558 0 : double dfXMax = CPL_MAX(CPL_MAX(psImage->dfULX, psImage->dfURX),
4559 : CPL_MAX(psImage->dfLRX, psImage->dfLLX));
4560 0 : double dfXMin = CPL_MIN(CPL_MIN(psImage->dfULX, psImage->dfURX),
4561 : CPL_MIN(psImage->dfLRX, psImage->dfLLX));
4562 0 : double dfYMax = CPL_MAX(CPL_MAX(psImage->dfULY, psImage->dfURY),
4563 : CPL_MAX(psImage->dfLRY, psImage->dfLLY));
4564 0 : double dfYMin = CPL_MIN(CPL_MIN(psImage->dfULY, psImage->dfURY),
4565 : CPL_MIN(psImage->dfLRY, psImage->dfLLY));
4566 0 : double dfXPivot = (dfXMax + dfXMin) * 0.5;
4567 0 : double dfYPivot = (dfYMax + dfYMin) * 0.5;
4568 :
4569 0 : double dfNewULX = 0., dfNewULY = 0., dfNewURX = 0., dfNewURY = 0.,
4570 0 : dfNewLLX = 0., dfNewLLY = 0., dfNewLRX = 0., dfNewLRY = 0.;
4571 0 : int bGotUL = FALSE, bGotUR = FALSE, bGotLL = FALSE, bGotLR = FALSE;
4572 0 : int iCoord, bChange = FALSE;
4573 :
4574 0 : for (iCoord = 0; iCoord < 4; iCoord++)
4575 : {
4576 0 : double *pdfXY = &(psImage->dfULX) + iCoord * 2;
4577 :
4578 0 : if (pdfXY[0] < dfXPivot && pdfXY[1] < dfYPivot)
4579 : {
4580 0 : bGotLL = TRUE;
4581 0 : dfNewLLX = pdfXY[0];
4582 0 : dfNewLLY = pdfXY[1];
4583 0 : bChange |= iCoord != 3;
4584 : }
4585 0 : else if (pdfXY[0] > dfXPivot && pdfXY[1] < dfYPivot)
4586 : {
4587 0 : bGotLR = TRUE;
4588 0 : dfNewLRX = pdfXY[0];
4589 0 : dfNewLRY = pdfXY[1];
4590 0 : bChange |= iCoord != 2;
4591 : }
4592 0 : else if (pdfXY[0] > dfXPivot && pdfXY[1] > dfYPivot)
4593 : {
4594 0 : bGotUR = TRUE;
4595 0 : dfNewURX = pdfXY[0];
4596 0 : dfNewURY = pdfXY[1];
4597 0 : bChange |= iCoord != 1;
4598 : }
4599 : else
4600 : {
4601 0 : bGotUL = TRUE;
4602 0 : dfNewULX = pdfXY[0];
4603 0 : dfNewULY = pdfXY[1];
4604 0 : bChange |= iCoord != 0;
4605 : }
4606 : }
4607 :
4608 0 : if (!bGotUL || !bGotUR || !bGotLL || !bGotLR)
4609 : {
4610 0 : CPLDebug("NITF", "Unable to reorient corner points sensibly in "
4611 : "NITFPossibleIGEOLOReorganization(), discarding "
4612 : "IGEOLO locations.");
4613 0 : psImage->bHaveIGEOLO = FALSE;
4614 0 : return;
4615 : }
4616 :
4617 0 : if (!bChange)
4618 0 : return;
4619 :
4620 0 : psImage->dfULX = dfNewULX;
4621 0 : psImage->dfULY = dfNewULY;
4622 0 : psImage->dfURX = dfNewURX;
4623 0 : psImage->dfURY = dfNewURY;
4624 0 : psImage->dfLRX = dfNewLRX;
4625 0 : psImage->dfLRY = dfNewLRY;
4626 0 : psImage->dfLLX = dfNewLLX;
4627 0 : psImage->dfLLY = dfNewLLY;
4628 :
4629 0 : CPLDebug("NITF", "IGEOLO corners have been reoriented by "
4630 : "NITFPossibleIGEOLOReorientation().");
4631 : }
4632 : }
4633 :
4634 : /************************************************************************/
4635 : /* NITFReadIMRFCA() */
4636 : /* */
4637 : /* Read DPPDB IMRFCA TRE (and the associated IMASDA TRE) if it is */
4638 : /* available. IMRFCA RPC coefficients are remapped into RPC00B */
4639 : /* organization. */
4640 : /* See table 68 for IMASDA and table 69 for IMRFCA in */
4641 : /* http://earth-info.nga.mil/publications/specs/printed/89034/89034DPPDB.pdf
4642 : */
4643 : /************************************************************************/
4644 700 : int NITFReadIMRFCA(NITFImage *psImage, NITFRPC00BInfo *psRPC)
4645 : {
4646 : char szTemp[100];
4647 700 : const char *pachTreIMASDA = NULL;
4648 700 : const char *pachTreIMRFCA = NULL;
4649 700 : double dfTolerance = 1.0e-10;
4650 700 : int count = 0;
4651 700 : int nTreIMASDASize = 0;
4652 700 : int nTreIMRFCASize = 0;
4653 :
4654 700 : if ((psImage == NULL) || (psRPC == NULL))
4655 0 : return FALSE;
4656 :
4657 : /* Check to see if we have the IMASDA and IMRFCA tag (DPPDB data). */
4658 :
4659 700 : pachTreIMASDA = NITFFindTRE(psImage->pachTRE, psImage->nTREBytes, "IMASDA",
4660 : &nTreIMASDASize);
4661 700 : pachTreIMRFCA = NITFFindTRE(psImage->pachTRE, psImage->nTREBytes, "IMRFCA",
4662 : &nTreIMRFCASize);
4663 :
4664 700 : if ((pachTreIMASDA == NULL) || (pachTreIMRFCA == NULL))
4665 694 : return FALSE;
4666 :
4667 6 : if (nTreIMASDASize < 242 || nTreIMRFCASize < 1760)
4668 : {
4669 4 : CPLError(CE_Failure, CPLE_AppDefined,
4670 : "Cannot read DPPDB IMASDA/IMRFCA TREs; not enough bytes.");
4671 :
4672 4 : return FALSE;
4673 : }
4674 :
4675 : /* Parse out the field values. */
4676 :
4677 : /* Set the errors to 0.0 for now. */
4678 :
4679 2 : psRPC->ERR_BIAS = 0.0;
4680 2 : psRPC->ERR_RAND = 0.0;
4681 :
4682 2 : psRPC->LONG_OFF = CPLAtof(NITFGetField(szTemp, pachTreIMASDA, 0, 22));
4683 2 : psRPC->LAT_OFF = CPLAtof(NITFGetField(szTemp, pachTreIMASDA, 22, 22));
4684 2 : psRPC->HEIGHT_OFF = CPLAtof(NITFGetField(szTemp, pachTreIMASDA, 44, 22));
4685 2 : psRPC->LONG_SCALE = CPLAtof(NITFGetField(szTemp, pachTreIMASDA, 66, 22));
4686 2 : psRPC->LAT_SCALE = CPLAtof(NITFGetField(szTemp, pachTreIMASDA, 88, 22));
4687 2 : psRPC->HEIGHT_SCALE = CPLAtof(NITFGetField(szTemp, pachTreIMASDA, 110, 22));
4688 2 : psRPC->SAMP_OFF = CPLAtof(NITFGetField(szTemp, pachTreIMASDA, 132, 22));
4689 2 : psRPC->LINE_OFF = CPLAtof(NITFGetField(szTemp, pachTreIMASDA, 154, 22));
4690 2 : psRPC->SAMP_SCALE = CPLAtof(NITFGetField(szTemp, pachTreIMASDA, 176, 22));
4691 2 : psRPC->LINE_SCALE = CPLAtof(NITFGetField(szTemp, pachTreIMASDA, 198, 22));
4692 :
4693 2 : if (psRPC->HEIGHT_SCALE == 0.0)
4694 2 : psRPC->HEIGHT_SCALE = dfTolerance;
4695 2 : if (psRPC->LAT_SCALE == 0.0)
4696 2 : psRPC->LAT_SCALE = dfTolerance;
4697 2 : if (psRPC->LINE_SCALE == 0.0)
4698 2 : psRPC->LINE_SCALE = dfTolerance;
4699 2 : if (psRPC->LONG_SCALE == 0.0)
4700 2 : psRPC->LONG_SCALE = dfTolerance;
4701 2 : if (psRPC->SAMP_SCALE == 0.0)
4702 2 : psRPC->SAMP_SCALE = dfTolerance;
4703 :
4704 2 : psRPC->HEIGHT_SCALE = 1.0 / psRPC->HEIGHT_SCALE;
4705 2 : psRPC->LAT_SCALE = 1.0 / psRPC->LAT_SCALE;
4706 2 : psRPC->LINE_SCALE = 1.0 / psRPC->LINE_SCALE;
4707 2 : psRPC->LONG_SCALE = 1.0 / psRPC->LONG_SCALE;
4708 2 : psRPC->SAMP_SCALE = 1.0 / psRPC->SAMP_SCALE;
4709 :
4710 : /* Parse out the RPC coefficients. */
4711 :
4712 42 : for (count = 0; count < 20; ++count)
4713 : {
4714 40 : psRPC->SAMP_NUM_COEFF[count] =
4715 40 : CPLAtof(NITFGetField(szTemp, pachTreIMRFCA, count * 22, 22));
4716 40 : psRPC->SAMP_DEN_COEFF[count] =
4717 40 : CPLAtof(NITFGetField(szTemp, pachTreIMRFCA, 440 + count * 22, 22));
4718 :
4719 40 : psRPC->LINE_NUM_COEFF[count] =
4720 40 : CPLAtof(NITFGetField(szTemp, pachTreIMRFCA, 880 + count * 22, 22));
4721 40 : psRPC->LINE_DEN_COEFF[count] =
4722 40 : CPLAtof(NITFGetField(szTemp, pachTreIMRFCA, 1320 + count * 22, 22));
4723 : }
4724 :
4725 2 : psRPC->SUCCESS = 1;
4726 :
4727 2 : return TRUE;
4728 : }
|