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