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