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