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