1 : /******************************************************************************
2 : * $Id: nitffile.c 23492 2011-12-07 20:50:52Z rouault $
3 : *
4 : * Project: NITF Read/Write Library
5 : * Purpose: Module responsible for opening NITF file, populating NITFFile
6 : * structure, and instantiating segment specific access objects.
7 : * Author: Frank Warmerdam, warmerdam@pobox.com
8 : *
9 : **********************************************************************
10 : * Copyright (c) 2002, Frank Warmerdam
11 : *
12 : * Permission is hereby granted, free of charge, to any person obtaining a
13 : * copy of this software and associated documentation files (the "Software"),
14 : * to deal in the Software without restriction, including without limitation
15 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 : * and/or sell copies of the Software, and to permit persons to whom the
17 : * Software is furnished to do so, subject to the following conditions:
18 : *
19 : * The above copyright notice and this permission notice shall be included
20 : * in all copies or substantial portions of the Software.
21 : *
22 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 : * DEALINGS IN THE SOFTWARE.
29 : ****************************************************************************/
30 :
31 : #include "nitflib.h"
32 : #include "cpl_vsi.h"
33 : #include "cpl_conv.h"
34 : #include "cpl_string.h"
35 :
36 : CPL_CVSID("$Id: nitffile.c 23492 2011-12-07 20:50:52Z rouault $");
37 :
38 : static int NITFWriteBLOCKA( VSILFILE* fp, vsi_l_offset nOffsetUDIDL,
39 : vsi_l_offset nOffsetTRE,
40 : int *pnOffset,
41 : char **papszOptions );
42 : static int NITFWriteTREsFromOptions(
43 : VSILFILE* fp,
44 : vsi_l_offset nOffsetUDIDL, vsi_l_offset nOffsetTRE,
45 : int *pnOffset,
46 : char **papszOptions,
47 : const char* pszTREPrefix);
48 :
49 : static int
50 : NITFCollectSegmentInfo( NITFFile *psFile, int nFileHeaderLenSize, int nOffset,
51 : const char szType[3],
52 : int nHeaderLenSize, int nDataLenSize,
53 : GUIntBig *pnNextData );
54 :
55 : /************************************************************************/
56 : /* NITFOpen() */
57 : /************************************************************************/
58 :
59 1186 : NITFFile *NITFOpen( const char *pszFilename, int bUpdatable )
60 :
61 : {
62 : VSILFILE *fp;
63 : char *pachHeader;
64 : NITFFile *psFile;
65 : int nHeaderLen, nOffset, nHeaderLenOffset;
66 : GUIntBig nNextData;
67 : char szTemp[128], achFSDWNG[6];
68 : GIntBig currentPos;
69 1186 : int bTriedStreamingFileHeader = FALSE;
70 :
71 : /* -------------------------------------------------------------------- */
72 : /* Open the file. */
73 : /* -------------------------------------------------------------------- */
74 1186 : if( bUpdatable )
75 426 : fp = VSIFOpenL( pszFilename, "r+b" );
76 : else
77 760 : fp = VSIFOpenL( pszFilename, "rb" );
78 :
79 1186 : if( fp == NULL )
80 : {
81 0 : CPLError( CE_Failure, CPLE_OpenFailed,
82 : "Failed to open file %s.",
83 : pszFilename );
84 0 : return NULL;
85 : }
86 :
87 : /* -------------------------------------------------------------------- */
88 : /* Check file type. */
89 : /* -------------------------------------------------------------------- */
90 1186 : VSIFReadL( szTemp, 1, 9, fp );
91 :
92 1186 : if( !EQUALN(szTemp,"NITF",4) && !EQUALN(szTemp,"NSIF",4) )
93 : {
94 0 : CPLError( CE_Failure, CPLE_AppDefined,
95 : "The file %s is not an NITF file.",
96 : pszFilename );
97 0 : VSIFCloseL(fp);
98 0 : return NULL;
99 : }
100 :
101 : /* -------------------------------------------------------------------- */
102 : /* Read the FSDWNG field. */
103 : /* -------------------------------------------------------------------- */
104 2372 : if( VSIFSeekL( fp, 280, SEEK_SET ) != 0
105 2372 : || VSIFReadL( achFSDWNG, 1, 6, fp ) != 6 )
106 : {
107 2 : CPLError( CE_Failure, CPLE_NotSupported,
108 : "Unable to read FSDWNG field from NITF file. File is either corrupt\n"
109 : "or empty." );
110 2 : VSIFCloseL(fp);
111 2 : return NULL;
112 : }
113 :
114 : /* -------------------------------------------------------------------- */
115 : /* Get header length. */
116 : /* -------------------------------------------------------------------- */
117 1202 : if( EQUALN(szTemp,"NITF01.",7) || EQUALN(achFSDWNG,"999998",6) )
118 18 : nHeaderLenOffset = 394;
119 : else
120 1166 : nHeaderLenOffset = 354;
121 :
122 2368 : if( VSIFSeekL( fp, nHeaderLenOffset, SEEK_SET ) != 0
123 2368 : || VSIFReadL( szTemp, 1, 6, fp ) != 6 )
124 : {
125 4 : CPLError( CE_Failure, CPLE_NotSupported,
126 : "Unable to read header length from NITF file. File is either corrupt\n"
127 : "or empty." );
128 4 : VSIFCloseL(fp);
129 4 : return NULL;
130 : }
131 :
132 1180 : szTemp[6] = '\0';
133 1180 : nHeaderLen = atoi(szTemp);
134 :
135 1180 : VSIFSeekL( fp, nHeaderLen, SEEK_SET );
136 1180 : currentPos = VSIFTellL( fp ) ;
137 1180 : if( nHeaderLen < nHeaderLenOffset || nHeaderLen > currentPos )
138 : {
139 2 : CPLError( CE_Failure, CPLE_NotSupported,
140 : "NITF Header Length (%d) seems to be corrupt.",
141 : nHeaderLen );
142 2 : VSIFCloseL(fp);
143 2 : return NULL;
144 : }
145 :
146 : /* -------------------------------------------------------------------- */
147 : /* Read the whole file header. */
148 : /* -------------------------------------------------------------------- */
149 1178 : pachHeader = (char *) VSIMalloc(nHeaderLen);
150 1178 : if (pachHeader == NULL)
151 : {
152 0 : CPLError( CE_Failure, CPLE_OutOfMemory,
153 : "Cannot allocate memory for NITF header");
154 0 : VSIFCloseL(fp);
155 0 : return NULL;
156 : }
157 1178 : VSIFSeekL( fp, 0, SEEK_SET );
158 1178 : if ((int)VSIFReadL( pachHeader, 1, nHeaderLen, fp ) != nHeaderLen)
159 : {
160 2 : CPLError( CE_Failure, CPLE_OutOfMemory,
161 : "Cannot read %d bytes for NITF header", (nHeaderLen));
162 2 : VSIFCloseL(fp);
163 2 : CPLFree(pachHeader);
164 2 : return NULL;
165 : }
166 :
167 : /* -------------------------------------------------------------------- */
168 : /* Create and initialize info structure about file. */
169 : /* -------------------------------------------------------------------- */
170 1176 : psFile = (NITFFile *) CPLCalloc(sizeof(NITFFile),1);
171 1176 : psFile->fp = fp;
172 1176 : psFile->pachHeader = pachHeader;
173 :
174 : retry_read_header:
175 : /* -------------------------------------------------------------------- */
176 : /* Get version. */
177 : /* -------------------------------------------------------------------- */
178 1178 : NITFGetField( psFile->szVersion, pachHeader, 0, 9 );
179 :
180 : /* -------------------------------------------------------------------- */
181 : /* Collect a variety of information as metadata. */
182 : /* -------------------------------------------------------------------- */
183 : #define GetMD( target, hdr, start, length, name ) \
184 : NITFExtractMetadata( &(target->papszMetadata), hdr, \
185 : start, length, \
186 : "NITF_" #name );
187 :
188 2392 : if( EQUAL(psFile->szVersion,"NITF02.10")
189 116 : || EQUAL(psFile->szVersion,"NSIF01.00") )
190 : {
191 : char szWork[100];
192 :
193 1098 : GetMD( psFile, pachHeader, 0, 9, FHDR );
194 1098 : GetMD( psFile, pachHeader, 9, 2, CLEVEL );
195 1098 : GetMD( psFile, pachHeader, 11, 4, STYPE );
196 1098 : GetMD( psFile, pachHeader, 15, 10, OSTAID );
197 1098 : GetMD( psFile, pachHeader, 25, 14, FDT );
198 1098 : GetMD( psFile, pachHeader, 39, 80, FTITLE );
199 1098 : GetMD( psFile, pachHeader, 119, 1, FSCLAS );
200 1098 : GetMD( psFile, pachHeader, 120, 2, FSCLSY );
201 1098 : GetMD( psFile, pachHeader, 122, 11, FSCODE );
202 1098 : GetMD( psFile, pachHeader, 133, 2, FSCTLH );
203 1098 : GetMD( psFile, pachHeader, 135, 20, FSREL );
204 1098 : GetMD( psFile, pachHeader, 155, 2, FSDCTP );
205 1098 : GetMD( psFile, pachHeader, 157, 8, FSDCDT );
206 1098 : GetMD( psFile, pachHeader, 165, 4, FSDCXM );
207 1098 : GetMD( psFile, pachHeader, 169, 1, FSDG );
208 1098 : GetMD( psFile, pachHeader, 170, 8, FSDGDT );
209 1098 : GetMD( psFile, pachHeader, 178, 43, FSCLTX );
210 1098 : GetMD( psFile, pachHeader, 221, 1, FSCATP );
211 1098 : GetMD( psFile, pachHeader, 222, 40, FSCAUT );
212 1098 : GetMD( psFile, pachHeader, 262, 1, FSCRSN );
213 1098 : GetMD( psFile, pachHeader, 263, 8, FSSRDT );
214 1098 : GetMD( psFile, pachHeader, 271, 15, FSCTLN );
215 1098 : GetMD( psFile, pachHeader, 286, 5, FSCOP );
216 1098 : GetMD( psFile, pachHeader, 291, 5, FSCPYS );
217 1098 : GetMD( psFile, pachHeader, 296, 1, ENCRYP );
218 3294 : sprintf( szWork, "%3d,%3d,%3d",
219 1098 : ((GByte *)pachHeader)[297],
220 1098 : ((GByte *)pachHeader)[298],
221 1098 : ((GByte *)pachHeader)[299] );
222 1098 : GetMD( psFile, szWork, 0, 11, FBKGC );
223 1098 : GetMD( psFile, pachHeader, 300, 24, ONAME );
224 1098 : GetMD( psFile, pachHeader, 324, 18, OPHONE );
225 1098 : NITFGetField(szTemp, pachHeader, 342, 12);
226 : }
227 80 : else if( EQUAL(psFile->szVersion,"NITF02.00") )
228 : {
229 68 : int nCOff = 0;
230 :
231 68 : GetMD( psFile, pachHeader, 0, 9, FHDR );
232 68 : GetMD( psFile, pachHeader, 9, 2, CLEVEL );
233 68 : GetMD( psFile, pachHeader, 11, 4, STYPE );
234 68 : GetMD( psFile, pachHeader, 15, 10, OSTAID );
235 68 : GetMD( psFile, pachHeader, 25, 14, FDT );
236 68 : GetMD( psFile, pachHeader, 39, 80, FTITLE );
237 68 : GetMD( psFile, pachHeader, 119, 1, FSCLAS );
238 68 : GetMD( psFile, pachHeader, 120, 40, FSCODE );
239 68 : GetMD( psFile, pachHeader, 160, 40, FSCTLH );
240 68 : GetMD( psFile, pachHeader, 200, 40, FSREL );
241 68 : GetMD( psFile, pachHeader, 240, 20, FSCAUT );
242 68 : GetMD( psFile, pachHeader, 260, 20, FSCTLN );
243 68 : GetMD( psFile, pachHeader, 280, 6, FSDWNG );
244 68 : if( EQUALN(pachHeader+280,"999998",6) )
245 : {
246 4 : GetMD( psFile, pachHeader, 286, 40, FSDEVT );
247 4 : nCOff += 40;
248 : }
249 68 : GetMD( psFile, pachHeader, 286+nCOff, 5, FSCOP );
250 68 : GetMD( psFile, pachHeader, 291+nCOff, 5, FSCPYS );
251 68 : GetMD( psFile, pachHeader, 296+nCOff, 1, ENCRYP );
252 68 : GetMD( psFile, pachHeader, 297+nCOff, 27, ONAME );
253 68 : GetMD( psFile, pachHeader, 324+nCOff, 18, OPHONE );
254 68 : NITFGetField(szTemp, pachHeader, 342+nCOff, 12);
255 : }
256 :
257 2354 : if (!bTriedStreamingFileHeader &&
258 1176 : EQUAL(szTemp, "999999999999"))
259 : {
260 : GUIntBig nFileSize;
261 : GByte abyDELIM2_L2[12];
262 : GByte abyL1_DELIM1[11];
263 :
264 2 : bTriedStreamingFileHeader = TRUE;
265 2 : CPLDebug("NITF", "Total file unknown. Trying to get a STREAMING_FILE_HEADER");
266 :
267 2 : VSIFSeekL( fp, 0, SEEK_END );
268 2 : nFileSize = VSIFTellL(fp);
269 :
270 2 : VSIFSeekL( fp, nFileSize - 11, SEEK_SET );
271 2 : abyDELIM2_L2[11] = '\0';
272 :
273 10 : if (VSIFReadL( abyDELIM2_L2, 1, 11, fp ) == 11 &&
274 4 : abyDELIM2_L2[0] == 0x0E && abyDELIM2_L2[1] == 0xCA &&
275 4 : abyDELIM2_L2[2] == 0x14 && abyDELIM2_L2[3] == 0xBF)
276 : {
277 2 : int SFHL2 = atoi((const char*)(abyDELIM2_L2 + 4));
278 2 : if (SFHL2 > 0 && nFileSize > 11 + SFHL2 + 11 )
279 : {
280 2 : VSIFSeekL( fp, nFileSize - 11 - SFHL2 - 11 , SEEK_SET );
281 :
282 12 : if ( VSIFReadL( abyL1_DELIM1, 1, 11, fp ) == 11 &&
283 4 : abyL1_DELIM1[7] == 0x0A && abyL1_DELIM1[8] == 0x6E &&
284 4 : abyL1_DELIM1[9] == 0x1D && abyL1_DELIM1[10] == 0x97 &&
285 2 : memcmp(abyL1_DELIM1, abyDELIM2_L2 + 4, 7) == 0 )
286 : {
287 2 : if (SFHL2 == nHeaderLen)
288 : {
289 2 : CSLDestroy(psFile->papszMetadata);
290 2 : psFile->papszMetadata = NULL;
291 :
292 2 : if ( (int)VSIFReadL( pachHeader, 1, SFHL2, fp ) != SFHL2 )
293 : {
294 0 : VSIFCloseL(fp);
295 0 : CPLFree(pachHeader);
296 0 : CPLFree(psFile);
297 0 : return NULL;
298 : }
299 :
300 2 : goto retry_read_header;
301 : }
302 : }
303 : }
304 : }
305 : }
306 :
307 : /* -------------------------------------------------------------------- */
308 : /* Collect segment info for the types we care about. */
309 : /* -------------------------------------------------------------------- */
310 1176 : nNextData = nHeaderLen;
311 :
312 1176 : nOffset = nHeaderLenOffset + 6;
313 :
314 1176 : nOffset = NITFCollectSegmentInfo( psFile, nHeaderLen, nOffset,"IM",6, 10, &nNextData );
315 :
316 1176 : if (nOffset != -1)
317 1168 : nOffset = NITFCollectSegmentInfo( psFile, nHeaderLen, nOffset, "GR", 4, 6, &nNextData);
318 :
319 : /* LA Called NUMX in NITF 2.1 */
320 1176 : if (nOffset != -1)
321 1168 : nOffset = NITFCollectSegmentInfo( psFile, nHeaderLen, nOffset, "LA", 4, 3, &nNextData);
322 :
323 1176 : if (nOffset != -1)
324 1168 : nOffset = NITFCollectSegmentInfo( psFile, nHeaderLen, nOffset, "TX", 4, 5, &nNextData);
325 :
326 1176 : if (nOffset != -1)
327 1168 : nOffset = NITFCollectSegmentInfo( psFile, nHeaderLen, nOffset, "DE", 4, 9, &nNextData);
328 :
329 1176 : if (nOffset != -1)
330 1168 : nOffset = NITFCollectSegmentInfo( psFile, nHeaderLen, nOffset, "RE", 4, 7, &nNextData);
331 : else
332 : {
333 8 : NITFClose(psFile);
334 8 : return NULL;
335 : }
336 :
337 : /* -------------------------------------------------------------------- */
338 : /* Is there User Define Header Data? (TREs) */
339 : /* -------------------------------------------------------------------- */
340 1168 : if (nHeaderLen < nOffset + 5)
341 : {
342 2 : CPLError(CE_Failure, CPLE_AppDefined, "NITF header too small");
343 2 : NITFClose(psFile);
344 2 : return NULL;
345 : }
346 :
347 1166 : psFile->nTREBytes =
348 1166 : atoi(NITFGetField( szTemp, pachHeader, nOffset, 5 ));
349 1166 : if (psFile->nTREBytes < 0)
350 : {
351 2 : CPLError(CE_Failure, CPLE_AppDefined,
352 : "Invalid TRE size : %d", psFile->nTREBytes);
353 2 : NITFClose(psFile);
354 2 : return NULL;
355 : }
356 1164 : nOffset += 5;
357 :
358 1164 : if( psFile->nTREBytes == 3 )
359 : {
360 0 : nOffset += 3; /* UDHOFL */
361 0 : psFile->nTREBytes = 0;
362 : }
363 1164 : else if( psFile->nTREBytes > 3 )
364 : {
365 56 : nOffset += 3; /* UDHOFL */
366 56 : psFile->nTREBytes -= 3;
367 :
368 56 : if (nHeaderLen < nOffset + psFile->nTREBytes)
369 : {
370 0 : CPLError(CE_Failure, CPLE_AppDefined, "NITF header too small");
371 0 : NITFClose(psFile);
372 0 : return NULL;
373 : }
374 :
375 56 : psFile->pachTRE = (char *) VSIMalloc(psFile->nTREBytes);
376 56 : if (psFile->pachTRE == NULL)
377 : {
378 0 : CPLError(CE_Failure, CPLE_OutOfMemory,
379 : "Cannot allocate %d bytes", psFile->nTREBytes);
380 0 : NITFClose(psFile);
381 0 : return NULL;
382 : }
383 56 : memcpy( psFile->pachTRE, pachHeader + nOffset,
384 56 : psFile->nTREBytes );
385 : }
386 :
387 : /* -------------------------------------------------------------------- */
388 : /* Is there Extended Header Data? (More TREs) */
389 : /* -------------------------------------------------------------------- */
390 1164 : if( nHeaderLen > nOffset + 8 )
391 : {
392 : int nXHDL =
393 86 : atoi(NITFGetField( szTemp, pachHeader, nOffset, 5 ));
394 86 : if (nXHDL < 0)
395 : {
396 2 : CPLError(CE_Failure, CPLE_AppDefined,
397 : "Invalid XHDL value : %d", nXHDL);
398 2 : NITFClose(psFile);
399 2 : return NULL;
400 : }
401 :
402 84 : nOffset += 5; /* XHDL */
403 :
404 84 : if( nXHDL > 3 )
405 : {
406 : char* pachNewTRE;
407 :
408 28 : nOffset += 3; /* XHDLOFL */
409 28 : nXHDL -= 3;
410 :
411 28 : if (nHeaderLen < nOffset + nXHDL)
412 : {
413 2 : CPLError(CE_Failure, CPLE_AppDefined, "NITF header too small");
414 2 : NITFClose(psFile);
415 2 : return NULL;
416 : }
417 :
418 52 : pachNewTRE = (char *)
419 26 : VSIRealloc( psFile->pachTRE,
420 26 : psFile->nTREBytes + nXHDL );
421 26 : if (pachNewTRE == NULL)
422 : {
423 0 : CPLError(CE_Failure, CPLE_OutOfMemory,
424 : "Cannot allocate %d bytes", psFile->nTREBytes + nXHDL);
425 0 : NITFClose(psFile);
426 0 : return NULL;
427 : }
428 26 : psFile->pachTRE = pachNewTRE;
429 26 : memcpy( psFile->pachTRE, pachHeader + nOffset, nXHDL );
430 26 : psFile->nTREBytes += nXHDL;
431 : }
432 : }
433 :
434 1160 : return psFile;
435 : }
436 :
437 : /************************************************************************/
438 : /* NITFClose() */
439 : /************************************************************************/
440 :
441 1176 : void NITFClose( NITFFile *psFile )
442 :
443 : {
444 : int iSegment;
445 :
446 13846 : for( iSegment = 0; iSegment < psFile->nSegmentCount; iSegment++ )
447 : {
448 12670 : NITFSegmentInfo *psSegInfo = psFile->pasSegmentInfo + iSegment;
449 :
450 12670 : if( psSegInfo->hAccess == NULL )
451 3510 : continue;
452 :
453 9160 : if( EQUAL(psSegInfo->szSegmentType,"IM"))
454 9160 : NITFImageDeaccess( (NITFImage *) psSegInfo->hAccess );
455 0 : else if( EQUAL(psSegInfo->szSegmentType,"DE"))
456 0 : NITFDESDeaccess( (NITFDES *) psSegInfo->hAccess );
457 : else
458 : {
459 0 : CPLAssert( FALSE );
460 : }
461 : }
462 :
463 1176 : CPLFree( psFile->pasSegmentInfo );
464 1176 : if( psFile->fp != NULL )
465 1176 : VSIFCloseL( psFile->fp );
466 1176 : CPLFree( psFile->pachHeader );
467 1176 : CSLDestroy( psFile->papszMetadata );
468 1176 : CPLFree( psFile->pachTRE );
469 :
470 1176 : if (psFile->psNITFSpecNode)
471 1100 : CPLDestroyXMLNode(psFile->psNITFSpecNode);
472 :
473 1176 : CPLFree( psFile );
474 1176 : }
475 :
476 571516 : static void NITFGotoOffset(VSILFILE* fp, GUIntBig nLocation)
477 : {
478 571516 : GUIntBig nCurrentLocation = VSIFTellL(fp);
479 571516 : if (nLocation > nCurrentLocation)
480 : {
481 : GUIntBig nFileSize;
482 : int iFill;
483 347718 : char cSpace = ' ';
484 :
485 347718 : VSIFSeekL(fp, 0, SEEK_END);
486 347718 : nFileSize = VSIFTellL(fp);
487 347718 : if (nLocation > nFileSize)
488 : {
489 2639774 : for(iFill = 0; iFill < nLocation - nFileSize; iFill++)
490 2296536 : VSIFWriteL(&cSpace, 1, 1, fp);
491 : }
492 : else
493 4480 : VSIFSeekL(fp, nLocation, SEEK_SET);
494 : }
495 223798 : else if (nLocation < nCurrentLocation)
496 : {
497 5278 : VSIFSeekL(fp, nLocation, SEEK_SET);
498 : }
499 :
500 571516 : }
501 :
502 : /************************************************************************/
503 : /* NITFCreate() */
504 : /* */
505 : /* Create a new uncompressed NITF file. */
506 : /************************************************************************/
507 :
508 424 : int NITFCreate( const char *pszFilename,
509 : int nPixels, int nLines, int nBands,
510 : int nBitsPerSample, const char *pszPVType,
511 : char **papszOptions )
512 :
513 : {
514 : VSILFILE *fp;
515 424 : GUIntBig nCur = 0;
516 424 : int nOffset = 0, iBand, nIHSize, nNPPBH, nNPPBV;
517 : GIntBig nImageSize;
518 : int nNBPR, nNBPC;
519 : const char *pszIREP;
520 424 : const char *pszIC = CSLFetchNameValue(papszOptions,"IC");
521 : int nCLevel;
522 : const char *pszNUMT;
523 424 : int nHL, nNUMT = 0;
524 : int nUDIDLOffset;
525 : const char *pszVersion;
526 424 : int iIM, nIM = 1;
527 : const char *pszNUMI;
528 424 : int iGS, nGS = 0; // number of graphic segment
529 : const char *pszNUMS; // graphic segment option string
530 :
531 424 : if (nBands <= 0 || nBands > 99999)
532 : {
533 4 : CPLError(CE_Failure, CPLE_NotSupported,
534 : "Invalid band number : %d", nBands);
535 4 : return FALSE;
536 : }
537 :
538 420 : if( pszIC == NULL )
539 400 : pszIC = "NC";
540 :
541 : /* -------------------------------------------------------------------- */
542 : /* Fetch some parameter overrides. */
543 : /* -------------------------------------------------------------------- */
544 420 : pszIREP = CSLFetchNameValue( papszOptions, "IREP" );
545 420 : if( pszIREP == NULL )
546 324 : pszIREP = "MONO";
547 :
548 420 : pszNUMT = CSLFetchNameValue( papszOptions, "NUMT" );
549 420 : if( pszNUMT != NULL )
550 : {
551 10 : nNUMT = atoi(pszNUMT);
552 10 : if (nNUMT < 0 || nNUMT > 999)
553 : {
554 2 : CPLError( CE_Failure, CPLE_AppDefined,
555 : "Invalid NUMT value : %s", pszNUMT);
556 2 : return FALSE;
557 : }
558 : }
559 :
560 418 : pszNUMI = CSLFetchNameValue( papszOptions, "NUMI" );
561 418 : if (pszNUMI != NULL)
562 : {
563 8 : nIM = atoi(pszNUMI);
564 8 : if (nIM < 1 || nIM > 999)
565 : {
566 2 : CPLError( CE_Failure, CPLE_AppDefined,
567 : "Invalid NUMI value : %s", pszNUMI);
568 2 : return FALSE;
569 : }
570 6 : if (nIM != 1 && !EQUAL(pszIC, "NC"))
571 : {
572 2 : CPLError( CE_Failure, CPLE_AppDefined,
573 : "Unable to create file with multiple images and compression at the same time");
574 2 : return FALSE;
575 : }
576 : }
577 :
578 : // Reads and validates graphics segment number option
579 414 : pszNUMS = CSLFetchNameValue(papszOptions, "NUMS");
580 414 : if (pszNUMS != NULL)
581 : {
582 18 : nGS = atoi(pszNUMS);
583 18 : if (nGS < 0 || nGS > 999)
584 : {
585 2 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid NUMS value : %s",
586 : pszNUMS);
587 2 : return FALSE;
588 : }
589 : }
590 :
591 :
592 :
593 : /* -------------------------------------------------------------------- */
594 : /* Compute raw image size, blocking factors and so forth. */
595 : /* -------------------------------------------------------------------- */
596 412 : nNPPBH = nPixels;
597 412 : nNPPBV = nLines;
598 :
599 412 : if( CSLFetchNameValue( papszOptions, "BLOCKSIZE" ) != NULL )
600 8 : nNPPBH = nNPPBV = atoi(CSLFetchNameValue( papszOptions, "BLOCKSIZE" ));
601 :
602 412 : if( CSLFetchNameValue( papszOptions, "BLOCKXSIZE" ) != NULL )
603 12 : nNPPBH = atoi(CSLFetchNameValue( papszOptions, "BLOCKXSIZE" ));
604 :
605 412 : if( CSLFetchNameValue( papszOptions, "BLOCKYSIZE" ) != NULL )
606 8 : nNPPBV = atoi(CSLFetchNameValue( papszOptions, "BLOCKYSIZE" ));
607 :
608 412 : if( CSLFetchNameValue( papszOptions, "NPPBH" ) != NULL )
609 0 : nNPPBH = atoi(CSLFetchNameValue( papszOptions, "NPPBH" ));
610 :
611 412 : if( CSLFetchNameValue( papszOptions, "NPPBV" ) != NULL )
612 0 : nNPPBV = atoi(CSLFetchNameValue( papszOptions, "NPPBV" ));
613 :
614 :
615 420 : if (EQUAL(pszIC, "NC") &&
616 : (nPixels > 8192 || nLines > 8192) &&
617 : nNPPBH == nPixels && nNPPBV == nLines)
618 : {
619 : /* See MIL-STD-2500-C, paragraph 5.4.2.2-d (#3263) */
620 8 : nNBPR = 1;
621 8 : nNBPC = 1;
622 8 : nNPPBH = 0;
623 8 : nNPPBV = 0;
624 :
625 8 : nImageSize =
626 16 : ((nBitsPerSample)/8)
627 8 : * ((GIntBig) nPixels *nLines)
628 16 : * nBands;
629 : }
630 404 : else if (EQUAL(pszIC, "NC") &&
631 : nPixels > 8192 && nNPPBH == nPixels)
632 : {
633 : /* See MIL-STD-2500-C, paragraph 5.4.2.2-d */
634 0 : nNBPR = 1;
635 0 : nNPPBH = 0;
636 0 : nNBPC = (nLines + nNPPBV - 1) / nNPPBV;
637 :
638 0 : if ( nNBPC > 9999 )
639 : {
640 0 : CPLError( CE_Failure, CPLE_AppDefined,
641 : "Unable to create file %s,\n"
642 : "Too many blocks : %d x %d",
643 : pszFilename, nNBPR, nNBPC);
644 0 : return FALSE;
645 : }
646 :
647 0 : nImageSize =
648 0 : ((nBitsPerSample)/8)
649 0 : * ((GIntBig) nPixels * (nNBPC * nNPPBV))
650 0 : * nBands;
651 : }
652 406 : else if (EQUAL(pszIC, "NC") &&
653 : nLines > 8192 && nNPPBV == nLines)
654 : {
655 : /* See MIL-STD-2500-C, paragraph 5.4.2.2-d */
656 2 : nNBPC = 1;
657 2 : nNPPBV = 0;
658 2 : nNBPR = (nPixels + nNPPBH - 1) / nNPPBH;
659 :
660 2 : if ( nNBPR > 9999 )
661 : {
662 0 : CPLError( CE_Failure, CPLE_AppDefined,
663 : "Unable to create file %s,\n"
664 : "Too many blocks : %d x %d",
665 : pszFilename, nNBPR, nNBPC);
666 0 : return FALSE;
667 : }
668 :
669 2 : nImageSize =
670 4 : ((nBitsPerSample)/8)
671 2 : * ((GIntBig) nLines * (nNBPR * nNPPBH))
672 4 : * nBands;
673 : }
674 : else
675 : {
676 402 : if( nNPPBH <= 0 || nNPPBV <= 0 ||
677 : nNPPBH > 9999 || nNPPBV > 9999 )
678 0 : nNPPBH = nNPPBV = 256;
679 :
680 402 : nNBPR = (nPixels + nNPPBH - 1) / nNPPBH;
681 402 : nNBPC = (nLines + nNPPBV - 1) / nNPPBV;
682 402 : if ( nNBPR > 9999 || nNBPC > 9999 )
683 : {
684 2 : CPLError( CE_Failure, CPLE_AppDefined,
685 : "Unable to create file %s,\n"
686 : "Too many blocks : %d x %d",
687 : pszFilename, nNBPR, nNBPC);
688 2 : return FALSE;
689 : }
690 :
691 400 : nImageSize =
692 800 : ((nBitsPerSample)/8)
693 400 : * ((GIntBig) nNBPR * nNBPC)
694 800 : * nNPPBH * nNPPBV * nBands;
695 : }
696 :
697 410 : if (EQUAL(pszIC, "NC"))
698 : {
699 394 : if ((double)nImageSize >= 1e10 - 1)
700 : {
701 2 : CPLError( CE_Failure, CPLE_AppDefined,
702 : "Unable to create file %s,\n"
703 : "Too big image size : " CPL_FRMT_GUIB,
704 : pszFilename, nImageSize );
705 2 : return FALSE;
706 : }
707 392 : if ((double)(nImageSize * nIM) >= 1e12 - 1)
708 : {
709 2 : CPLError( CE_Failure, CPLE_AppDefined,
710 : "Unable to create file %s,\n"
711 : "Too big file size : " CPL_FRMT_GUIB,
712 : pszFilename, nImageSize * nIM );
713 2 : return FALSE;
714 : }
715 : }
716 :
717 : /* -------------------------------------------------------------------- */
718 : /* Open new file. */
719 : /* -------------------------------------------------------------------- */
720 406 : fp = VSIFOpenL( pszFilename, "wb+" );
721 406 : if( fp == NULL )
722 : {
723 6 : CPLError( CE_Failure, CPLE_OpenFailed,
724 : "Unable to create file %s,\n"
725 : "check path and permissions.",
726 : pszFilename );
727 6 : return FALSE;
728 : }
729 :
730 :
731 : /* -------------------------------------------------------------------- */
732 : /* Work out the version we are producing. For now we really */
733 : /* only support creating NITF02.10 or the nato analog */
734 : /* NSIF01.00. */
735 : /* -------------------------------------------------------------------- */
736 400 : pszVersion = CSLFetchNameValue( papszOptions, "FHDR" );
737 400 : if( pszVersion == NULL )
738 388 : pszVersion = "NITF02.10";
739 16 : else if( !EQUAL(pszVersion,"NITF02.10")
740 4 : && !EQUAL(pszVersion,"NSIF01.00") )
741 : {
742 2 : CPLError( CE_Warning, CPLE_AppDefined,
743 : "FHDR=%s not supported, switching to NITF02.10.",
744 : pszVersion );
745 2 : pszVersion = "NITF02.10";
746 : }
747 :
748 : /* -------------------------------------------------------------------- */
749 : /* Prepare the file header. */
750 : /* -------------------------------------------------------------------- */
751 :
752 : #define PLACE(location,name,text) { \
753 : const char* _text = text; \
754 : NITFGotoOffset(fp, location); \
755 : VSIFWriteL(_text, 1, strlen(_text), fp); }
756 :
757 : #define OVR(width,location,name,text) { \
758 : const char* _text = text; \
759 : const char *pszParmValue; \
760 : pszParmValue = CSLFetchNameValue( papszOptions, #name ); \
761 : if( pszParmValue == NULL ) \
762 : pszParmValue = _text; \
763 : NITFGotoOffset(fp, location); \
764 : VSIFWriteL(pszParmValue, 1, MIN(width,strlen(pszParmValue)), fp); }
765 :
766 : #define WRITE_BYTE(location, val) { \
767 : char cVal = val; \
768 : NITFGotoOffset(fp, location); \
769 : VSIFWriteL(&cVal, 1, 1, fp); }
770 :
771 400 : VSIFSeekL(fp, 0, SEEK_SET);
772 :
773 400 : PLACE ( 0, FDHR_FVER, pszVersion );
774 400 : OVR( 2, 9, CLEVEL, "03" ); /* Patched at the end */
775 400 : PLACE ( 11, STYPE ,"BF01" );
776 400 : OVR(10, 15, OSTAID ,"GDAL" );
777 400 : OVR(14, 25, FDT ,"20021216151629" );
778 400 : OVR(80, 39, FTITLE ,"" );
779 400 : OVR( 1,119, FSCLAS ,"U" );
780 400 : OVR( 2,120, FSCLSY ,"" );
781 400 : OVR(11,122, FSCODE ,"" );
782 400 : OVR( 2,133, FSCTLH ,"" );
783 400 : OVR(20,135, FSREL ,"" );
784 400 : OVR( 2,155, FSDCTP ,"" );
785 400 : OVR( 8,157, FSDCDT ,"" );
786 400 : OVR( 4,165, FSDCXM ,"" );
787 400 : OVR( 1,169, FSDG ,"" );
788 400 : OVR( 8,170, FSDGDT ,"" );
789 400 : OVR(43,178, FSCLTX ,"" );
790 400 : OVR( 1,221, FSCATP ,"" );
791 400 : OVR(40,222, FSCAUT ,"" );
792 400 : OVR( 1,262, FSCRSN ,"" );
793 400 : OVR( 8,263, FSSRDT ,"" );
794 400 : OVR(15,271, FSCTLN ,"" );
795 400 : OVR( 5,286, FSCOP ,"00000" );
796 400 : OVR( 5,291, FSCPYS ,"00000" );
797 400 : PLACE (296, ENCRYP ,"0" );
798 400 : WRITE_BYTE(297, 0x00); /* FBKGC */
799 400 : WRITE_BYTE(298, 0x00);
800 400 : WRITE_BYTE(299, 0x00);
801 400 : OVR(24,300, ONAME ,"" );
802 400 : OVR(18,324, OPHONE ,"" );
803 400 : PLACE (342, FL ,"????????????" );
804 400 : PLACE (354, HL ,"??????" );
805 400 : PLACE (360, NUMI ,CPLSPrintf("%03d", nIM) );
806 :
807 400 : nHL = 363;
808 2796 : for(iIM=0;iIM<nIM;iIM++)
809 : {
810 2396 : PLACE (nHL, LISHi ,"??????" );
811 2396 : PLACE (nHL + 6, LIi ,CPLSPrintf("%010" CPL_FRMT_GB_WITHOUT_PREFIX "d", nImageSize) );
812 2396 : nHL += 6 + 10;
813 : }
814 :
815 : // Creates Header entries for graphic segment
816 : // NUMS: number of segment
817 : // For each segment:
818 : // LSSH[i]: subheader length (4 byte), set to be 258, the size for
819 : // minimal amount of information.
820 : // LS[i] data length (6 byte)
821 400 : PLACE (nHL, NUMS ,CPLSPrintf("%03d",nGS) );
822 400 : nHL += 3; // Move three characters
823 408 : for (iGS = 0; iGS < nGS; iGS++)
824 : {
825 8 : PLACE (nHL, LSSHi ,CPLSPrintf("0000") );
826 8 : PLACE (nHL + 4, LSi ,CPLSPrintf("000000") );
827 8 : nHL += 4 + 6;
828 : }
829 :
830 400 : PLACE (nHL, NUMX ,"000" );
831 400 : PLACE (nHL + 3, NUMT ,CPLSPrintf("%03d",nNUMT) );
832 :
833 400 : PLACE (nHL + 6, LTSHnLTn ,"" );
834 :
835 400 : nHL += 6 + (4+5) * nNUMT;
836 :
837 400 : PLACE (nHL, NUMDES ,"000" );
838 400 : nHL += 3;
839 400 : PLACE (nHL, NUMRES ,"000" );
840 400 : nHL += 3;
841 400 : PLACE (nHL, UDHDL ,"00000" );
842 400 : nHL += 5;
843 400 : PLACE (nHL, XHDL ,"00000" );
844 400 : nHL += 5;
845 :
846 400 : if( CSLFetchNameValue(papszOptions,"FILE_TRE") != NULL )
847 : {
848 16 : NITFWriteTREsFromOptions(
849 : fp,
850 8 : nHL - 10,
851 : nHL,
852 : &nHL,
853 : papszOptions, "FILE_TRE=" );
854 : }
855 :
856 400 : if (nHL > 999999)
857 : {
858 0 : CPLError(CE_Failure, CPLE_AppDefined,
859 : "Too big file header length : %d", nHL);
860 0 : VSIFCloseL( fp );
861 0 : return FALSE;
862 : }
863 :
864 : // update header length
865 400 : PLACE (354, HL ,CPLSPrintf("%06d",nHL) );
866 :
867 400 : nCur = nHL;
868 :
869 : /* -------------------------------------------------------------------- */
870 : /* Prepare the image header. */
871 : /* -------------------------------------------------------------------- */
872 2796 : for(iIM=0;iIM<nIM;iIM++)
873 : {
874 2396 : char** papszIREPBANDTokens = NULL;
875 2396 : char** papszISUBCATTokens = NULL;
876 :
877 2396 : if( CSLFetchNameValue(papszOptions,"IREPBAND") != NULL )
878 : {
879 0 : papszIREPBANDTokens = CSLTokenizeStringComplex(
880 : CSLFetchNameValue(papszOptions,"IREPBAND"), ",", 0, 0 );
881 0 : if( papszIREPBANDTokens != NULL && CSLCount( papszIREPBANDTokens ) != nBands)
882 : {
883 0 : CSLDestroy( papszIREPBANDTokens );
884 0 : papszIREPBANDTokens = NULL;
885 : }
886 : }
887 2396 : if( CSLFetchNameValue(papszOptions,"ISUBCAT") != NULL )
888 : {
889 0 : papszISUBCATTokens = CSLTokenizeStringComplex(
890 : CSLFetchNameValue(papszOptions,"ISUBCAT"), ",", 0, 0 );
891 0 : if( papszISUBCATTokens != NULL && CSLCount( papszISUBCATTokens ) != nBands)
892 : {
893 0 : CSLDestroy( papszISUBCATTokens );
894 0 : papszISUBCATTokens = NULL;
895 : }
896 : }
897 :
898 2396 : VSIFSeekL(fp, nCur, SEEK_SET);
899 :
900 2396 : PLACE (nCur+ 0, IM , "IM" );
901 2396 : OVR(10,nCur+ 2, IID1 , "Missing" );
902 2396 : OVR(14,nCur+ 12, IDATIM , "20021216151629" );
903 2396 : OVR(17,nCur+ 26, TGTID , "" );
904 2396 : OVR(80,nCur+ 43, IID2 , "" );
905 2396 : OVR( 1,nCur+123, ISCLAS , "U" );
906 2396 : OVR( 2,nCur+124, ISCLSY , "" );
907 2396 : OVR(11,nCur+126, ISCODE , "" );
908 2396 : OVR( 2,nCur+137, ISCTLH , "" );
909 2396 : OVR(20,nCur+139, ISREL , "" );
910 2396 : OVR( 2,nCur+159, ISDCTP , "" );
911 2396 : OVR( 8,nCur+161, ISDCDT , "" );
912 2396 : OVR( 4,nCur+169, ISDCXM , "" );
913 2396 : OVR( 1,nCur+173, ISDG , "" );
914 2396 : OVR( 8,nCur+174, ISDGDT , "" );
915 2396 : OVR(43,nCur+182, ISCLTX , "" );
916 2396 : OVR( 1,nCur+225, ISCATP , "" );
917 2396 : OVR(40,nCur+226, ISCAUT , "" );
918 2396 : OVR( 1,nCur+266, ISCRSN , "" );
919 2396 : OVR( 8,nCur+267, ISSRDT , "" );
920 2396 : OVR(15,nCur+275, ISCTLN , "" );
921 2396 : PLACE (nCur+290, ENCRYP , "0" );
922 2396 : OVR(42,nCur+291, ISORCE , "Unknown" );
923 2396 : PLACE (nCur+333, NROWS , CPLSPrintf("%08d", nLines) );
924 2396 : PLACE (nCur+341, NCOLS , CPLSPrintf("%08d", nPixels) );
925 2396 : PLACE (nCur+349, PVTYPE , pszPVType );
926 2396 : PLACE (nCur+352, IREP , pszIREP );
927 2396 : OVR( 8,nCur+360, ICAT , "VIS" );
928 2396 : OVR( 2,nCur+368, ABPP , CPLSPrintf("%02d",nBitsPerSample) );
929 2396 : OVR( 1,nCur+370, PJUST , "R" );
930 2396 : OVR( 1,nCur+371, ICORDS , " " );
931 :
932 2396 : nOffset = 372;
933 :
934 : {
935 : const char *pszParmValue;
936 2396 : pszParmValue = CSLFetchNameValue( papszOptions, "ICORDS" );
937 2396 : if( pszParmValue == NULL )
938 2294 : pszParmValue = " ";
939 2396 : if( *pszParmValue != ' ' )
940 : {
941 102 : OVR(60,nCur+nOffset, IGEOLO, "" );
942 102 : nOffset += 60;
943 : }
944 : }
945 :
946 : {
947 2396 : const char* pszICOM = CSLFetchNameValue( papszOptions, "ICOM");
948 2396 : if (pszICOM != NULL)
949 : {
950 2 : int nLenICOM = strlen(pszICOM);
951 2 : int nICOM = (79 + nLenICOM) / 80;
952 2 : if (nICOM > 9)
953 : {
954 0 : CPLError(CE_Warning, CPLE_NotSupported, "ICOM will be truncated");
955 0 : nICOM = 9;
956 : }
957 2 : PLACE (nCur+nOffset, NICOM , CPLSPrintf("%01d",nICOM) );
958 2 : VSIFWriteL(pszICOM, 1, MIN(nICOM * 80, nLenICOM), fp);
959 2 : nOffset += nICOM * 80;
960 : }
961 : else
962 : {
963 2394 : PLACE (nCur+nOffset, NICOM , "0" );
964 : }
965 : }
966 :
967 2396 : OVR( 2,nCur+nOffset+1, IC , "NC" );
968 :
969 2396 : if( pszIC[0] != 'N' )
970 : {
971 16 : OVR( 4,nCur+nOffset+3, COMRAT , " " );
972 16 : nOffset += 4;
973 : }
974 :
975 2396 : if (nBands <= 9)
976 : {
977 2390 : PLACE (nCur+nOffset+3, NBANDS , CPLSPrintf("%d",nBands) );
978 : }
979 : else
980 : {
981 6 : PLACE (nCur+nOffset+3, NBANDS , "0" );
982 6 : PLACE (nCur+nOffset+4, XBANDS , CPLSPrintf("%05d",nBands) );
983 6 : nOffset += 5;
984 : }
985 :
986 2396 : nOffset += 4;
987 :
988 : /* -------------------------------------------------------------------- */
989 : /* Per band info */
990 : /* -------------------------------------------------------------------- */
991 144974 : for( iBand = 0; iBand < nBands; iBand++ )
992 : {
993 142578 : const char *pszIREPBAND = "M";
994 :
995 142578 : if( papszIREPBANDTokens != NULL )
996 : {
997 0 : if (strlen(papszIREPBANDTokens[iBand]) > 2)
998 : {
999 0 : papszIREPBANDTokens[iBand][2] = '\0';
1000 0 : CPLError(CE_Warning, CPLE_NotSupported,
1001 : "Truncating IREPBAND[%d] to '%s'",
1002 0 : iBand + 1, papszIREPBANDTokens[iBand]);
1003 : }
1004 0 : pszIREPBAND = papszIREPBANDTokens[iBand];
1005 : }
1006 142578 : else if( EQUAL(pszIREP,"RGB/LUT") )
1007 10 : pszIREPBAND = "LU";
1008 142568 : else if( EQUAL(pszIREP,"RGB") )
1009 : {
1010 26 : if( iBand == 0 )
1011 8 : pszIREPBAND = "R";
1012 18 : else if( iBand == 1 )
1013 8 : pszIREPBAND = "G";
1014 10 : else if( iBand == 2 )
1015 8 : pszIREPBAND = "B";
1016 : }
1017 142542 : else if( EQUALN(pszIREP,"YCbCr",5) )
1018 : {
1019 18 : if( iBand == 0 )
1020 6 : pszIREPBAND = "Y";
1021 12 : else if( iBand == 1 )
1022 6 : pszIREPBAND = "Cb";
1023 6 : else if( iBand == 2 )
1024 6 : pszIREPBAND = "Cr";
1025 : }
1026 :
1027 142578 : PLACE(nCur+nOffset+ 0, IREPBANDn, pszIREPBAND );
1028 :
1029 142578 : if( papszISUBCATTokens != NULL )
1030 : {
1031 0 : if (strlen(papszISUBCATTokens[iBand]) > 6)
1032 : {
1033 0 : papszISUBCATTokens[iBand][6] = '\0';
1034 0 : CPLError(CE_Warning, CPLE_NotSupported,
1035 : "Truncating ISUBCAT[%d] to '%s'",
1036 0 : iBand + 1, papszISUBCATTokens[iBand]);
1037 : }
1038 0 : PLACE(nCur+nOffset+ 2, ISUBCATn, papszISUBCATTokens[iBand] );
1039 : }
1040 : // else
1041 : // PLACE(nCur+nOffset+ 2, ISUBCATn, "" );
1042 :
1043 142578 : PLACE(nCur+nOffset+ 8, IFCn , "N" );
1044 : // PLACE(nCur+nOffset+ 9, IMFLTn, "" );
1045 :
1046 142578 : if( !EQUAL(pszIREP,"RGB/LUT") )
1047 : {
1048 142568 : PLACE(nCur+nOffset+12, NLUTSn, "0" );
1049 142568 : nOffset += 13;
1050 : }
1051 : else
1052 : {
1053 10 : int iC, nCount=256;
1054 :
1055 10 : if( CSLFetchNameValue(papszOptions,"LUT_SIZE") != NULL )
1056 10 : nCount = atoi(CSLFetchNameValue(papszOptions,"LUT_SIZE"));
1057 :
1058 10 : if (!(nCount >= 0 && nCount <= 99999))
1059 : {
1060 2 : CPLError(CE_Warning, CPLE_AppDefined,
1061 : "Invalid LUT value : %d. Defaulting to 256", nCount);
1062 2 : nCount = 256;
1063 : }
1064 10 : PLACE(nCur+nOffset+12, NLUTSn, "3" );
1065 10 : PLACE(nCur+nOffset+13, NELUTn, CPLSPrintf("%05d",nCount) );
1066 :
1067 2060 : for( iC = 0; iC < nCount; iC++ )
1068 : {
1069 2050 : WRITE_BYTE(nCur+nOffset+18+iC+ 0, (char) iC);
1070 2050 : WRITE_BYTE(nCur+nOffset+18+iC+nCount*1, (char) iC);
1071 2050 : WRITE_BYTE(nCur+nOffset+18+iC+nCount*2, (char) iC);
1072 : }
1073 10 : nOffset += 18 + nCount*3;
1074 : }
1075 : }
1076 :
1077 2396 : CSLDestroy(papszIREPBANDTokens);
1078 2396 : CSLDestroy(papszISUBCATTokens);
1079 :
1080 : /* -------------------------------------------------------------------- */
1081 : /* Remainder of image header info. */
1082 : /* -------------------------------------------------------------------- */
1083 2396 : PLACE(nCur+nOffset+ 0, ISYNC , "0" );
1084 :
1085 : /* RGB JPEG compressed NITF requires IMODE=P (see #3345) */
1086 2402 : if (nBands >= 3 && (EQUAL(pszIC, "C3") || EQUAL(pszIC, "M3")))
1087 : {
1088 6 : PLACE(nCur+nOffset+ 1, IMODE , "P" );
1089 : }
1090 : else
1091 : {
1092 2390 : PLACE(nCur+nOffset+ 1, IMODE , "B" );
1093 : }
1094 2396 : PLACE(nCur+nOffset+ 2, NBPR , CPLSPrintf("%04d",nNBPR) );
1095 2396 : PLACE(nCur+nOffset+ 6, NBPC , CPLSPrintf("%04d",nNBPC) );
1096 2396 : PLACE(nCur+nOffset+ 10, NPPBH , CPLSPrintf("%04d",nNPPBH) );
1097 2396 : PLACE(nCur+nOffset+ 14, NPPBV , CPLSPrintf("%04d",nNPPBV) );
1098 2396 : PLACE(nCur+nOffset+ 18, NBPP , CPLSPrintf("%02d",nBitsPerSample) );
1099 2396 : PLACE(nCur+nOffset+ 20, IDLVL , "001" );
1100 2396 : PLACE(nCur+nOffset+ 23, IALVL , "000" );
1101 2396 : PLACE(nCur+nOffset+ 26, ILOC , "0000000000" );
1102 2396 : PLACE(nCur+nOffset+ 36, IMAG , "1.0 " );
1103 2396 : PLACE(nCur+nOffset+ 40, UDIDL , "00000" );
1104 2396 : PLACE(nCur+nOffset+ 45, IXSHDL, "00000" );
1105 :
1106 2396 : nUDIDLOffset = nOffset + 40;
1107 2396 : nOffset += 50;
1108 :
1109 : /* -------------------------------------------------------------------- */
1110 : /* Add BLOCKA TRE if requested. */
1111 : /* -------------------------------------------------------------------- */
1112 2396 : if( CSLFetchNameValue(papszOptions,"BLOCKA_BLOCK_COUNT") != NULL )
1113 : {
1114 6 : NITFWriteBLOCKA( fp,
1115 : nCur + (GUIntBig)nUDIDLOffset,
1116 : nCur + (GUIntBig)nOffset,
1117 : &nOffset,
1118 : papszOptions );
1119 : }
1120 :
1121 2396 : if( CSLFetchNameValue(papszOptions,"TRE") != NULL )
1122 : {
1123 32 : NITFWriteTREsFromOptions(
1124 : fp,
1125 : nCur + (GUIntBig)nUDIDLOffset,
1126 : nCur + (GUIntBig)nOffset,
1127 : &nOffset,
1128 : papszOptions, "TRE=" );
1129 : }
1130 :
1131 : /* -------------------------------------------------------------------- */
1132 : /* Update the image header length in the file header. */
1133 : /* -------------------------------------------------------------------- */
1134 2396 : nIHSize = nOffset;
1135 :
1136 2396 : if (nIHSize > 999999)
1137 : {
1138 0 : CPLError(CE_Failure, CPLE_AppDefined,
1139 : "Too big image header length : %d", nIHSize);
1140 0 : VSIFCloseL( fp );
1141 0 : return FALSE;
1142 : }
1143 :
1144 2396 : PLACE( 363 + iIM * 16, LISH1, CPLSPrintf("%06d",nIHSize) );
1145 :
1146 2396 : nCur += nIHSize + nImageSize;
1147 : }
1148 :
1149 : /* -------------------------------------------------------------------- */
1150 : /* Compute and update CLEVEL ("complexity" level). */
1151 : /* See: http://164.214.2.51/ntb/baseline/docs/2500b/2500b_not2.pdf */
1152 : /* page 96u */
1153 : /* -------------------------------------------------------------------- */
1154 400 : nCLevel = 3;
1155 400 : if (nBands > 9 || nIM > 20 || nPixels > 2048 || nLines > 2048 ||
1156 : nNPPBH > 2048 || nNPPBV > 2048 || nCur > 52428799 )
1157 : {
1158 20 : nCLevel = 5;
1159 : }
1160 400 : if (nPixels > 8192 || nLines > 8192 ||
1161 : nNPPBH > 8192 || nNPPBV > 8192 || nCur > 1073741833)
1162 : {
1163 8 : nCLevel = 6;
1164 : }
1165 400 : if (nBands > 256 || nPixels > 65536 || nLines > 65536 ||
1166 : nCur > 2147483647)
1167 : {
1168 4 : nCLevel = 7;
1169 : }
1170 400 : OVR( 2, 9, CLEVEL, CPLSPrintf("%02d", nCLevel) );
1171 :
1172 : /* -------------------------------------------------------------------- */
1173 : /* Update total file length */
1174 : /* -------------------------------------------------------------------- */
1175 :
1176 : /* According to the spec, CLEVEL 7 supports up to 10,737,418,330 bytes */
1177 : /* but we can support technically much more */
1178 400 : if (EQUAL(pszIC, "NC") && GUINTBIG_TO_DOUBLE(nCur) >= 1e12 - 1)
1179 : {
1180 0 : CPLError(CE_Failure, CPLE_AppDefined,
1181 : "Too big file : " CPL_FRMT_GUIB, nCur);
1182 0 : VSIFCloseL( fp );
1183 0 : return FALSE;
1184 : }
1185 :
1186 400 : PLACE( 342, FL,
1187 : CPLSPrintf( "%012" CPL_FRMT_GB_WITHOUT_PREFIX "d", nCur) );
1188 :
1189 : /* -------------------------------------------------------------------- */
1190 : /* Grow file to full required size by writing one byte at the end. */
1191 : /* -------------------------------------------------------------------- */
1192 400 : if( EQUAL(pszIC,"NC") )
1193 : {
1194 384 : char cNul = 0;
1195 384 : VSIFSeekL( fp, nCur-1, SEEK_SET );
1196 384 : VSIFWriteL( &cNul, 1, 1, fp );
1197 : }
1198 :
1199 400 : VSIFCloseL( fp );
1200 :
1201 400 : return TRUE;
1202 : }
1203 :
1204 : /************************************************************************/
1205 : /* NITFWriteTRE() */
1206 : /************************************************************************/
1207 :
1208 46 : static int NITFWriteTRE( VSILFILE* fp,
1209 : vsi_l_offset nOffsetUDIDL,
1210 : vsi_l_offset nOffsetTREInHeader,
1211 : int *pnOffset,
1212 : const char *pszTREName, char *pabyTREData, int nTREDataSize )
1213 :
1214 : {
1215 : char szTemp[12];
1216 : int nOldOffset;
1217 :
1218 : /* -------------------------------------------------------------------- */
1219 : /* Update IXSHDL. */
1220 : /* -------------------------------------------------------------------- */
1221 46 : VSIFSeekL(fp, nOffsetUDIDL + 5, SEEK_SET);
1222 46 : VSIFReadL(szTemp, 1, 5, fp);
1223 46 : szTemp[5] = 0;
1224 46 : nOldOffset = atoi(szTemp);
1225 :
1226 46 : if( nOldOffset == 0 )
1227 : {
1228 40 : nOldOffset = 3;
1229 40 : PLACE(nOffsetUDIDL+10, IXSOFL, "000" );
1230 40 : *pnOffset += 3;
1231 : }
1232 :
1233 46 : if (nOldOffset + 11 + nTREDataSize > 99999 || nTREDataSize > 99999)
1234 : {
1235 4 : CPLError(CE_Failure, CPLE_AppDefined, "Too big TRE to be written");
1236 4 : return FALSE;
1237 : }
1238 :
1239 42 : sprintf( szTemp, "%05d", nOldOffset + 11 + nTREDataSize );
1240 42 : PLACE( nOffsetUDIDL + 5, IXSHDL, szTemp );
1241 :
1242 : /* -------------------------------------------------------------------- */
1243 : /* Create TRE prefix. */
1244 : /* -------------------------------------------------------------------- */
1245 42 : sprintf( szTemp, "%-6s%05d",
1246 : pszTREName, nTREDataSize );
1247 42 : VSIFSeekL(fp, nOffsetTREInHeader + nOldOffset, SEEK_SET);
1248 42 : VSIFWriteL(szTemp, 11, 1, fp);
1249 42 : VSIFWriteL(pabyTREData, nTREDataSize, 1, fp);
1250 :
1251 : /* -------------------------------------------------------------------- */
1252 : /* Increment values. */
1253 : /* -------------------------------------------------------------------- */
1254 42 : *pnOffset += nTREDataSize + 11;
1255 :
1256 42 : return TRUE;
1257 : }
1258 :
1259 : /************************************************************************/
1260 : /* NITFWriteTREsFromOptions() */
1261 : /************************************************************************/
1262 :
1263 40 : static int NITFWriteTREsFromOptions(
1264 : VSILFILE* fp,
1265 : vsi_l_offset nOffsetUDIDL, vsi_l_offset nOffsetTRE,
1266 : int *pnOffset,
1267 : char **papszOptions, const char* pszTREPrefix )
1268 :
1269 : {
1270 : int bIgnoreBLOCKA =
1271 40 : CSLFetchNameValue(papszOptions,"BLOCKA_BLOCK_COUNT") != NULL;
1272 : int iOption;
1273 40 : int nTREPrefixLen = strlen(pszTREPrefix);
1274 :
1275 40 : if( papszOptions == NULL )
1276 0 : return TRUE;
1277 :
1278 136 : for( iOption = 0; papszOptions[iOption] != NULL; iOption++ )
1279 : {
1280 : const char *pszEscapedContents;
1281 : char *pszUnescapedContents;
1282 : char *pszTREName;
1283 : int nContentLength;
1284 : const char* pszSpace;
1285 :
1286 102 : if( !EQUALN(papszOptions[iOption], pszTREPrefix, nTREPrefixLen) )
1287 56 : continue;
1288 :
1289 46 : if( EQUALN(papszOptions[iOption]+nTREPrefixLen,"BLOCKA=",7)
1290 : && bIgnoreBLOCKA )
1291 2 : continue;
1292 :
1293 : /* We do no longer use CPLParseNameValue() as it removes leading spaces */
1294 : /* from the value (see #3088) */
1295 44 : pszSpace = strchr(papszOptions[iOption]+nTREPrefixLen, '=');
1296 44 : if (pszSpace == NULL)
1297 : {
1298 2 : CPLError(CE_Failure, CPLE_AppDefined,
1299 2 : "Could not parse creation options %s", papszOptions[iOption]+nTREPrefixLen);
1300 2 : return FALSE;
1301 : }
1302 :
1303 42 : pszTREName = CPLStrdup(papszOptions[iOption]+nTREPrefixLen);
1304 42 : pszTREName[MIN(6, pszSpace - (papszOptions[iOption]+nTREPrefixLen))] = '\0';
1305 42 : pszEscapedContents = pszSpace + 1;
1306 :
1307 42 : pszUnescapedContents =
1308 42 : CPLUnescapeString( pszEscapedContents, &nContentLength,
1309 : CPLES_BackslashQuotable );
1310 :
1311 42 : if( !NITFWriteTRE( fp,
1312 : nOffsetUDIDL, nOffsetTRE,
1313 : pnOffset,
1314 : pszTREName, pszUnescapedContents,
1315 : nContentLength ) )
1316 : {
1317 4 : CPLFree( pszTREName );
1318 4 : CPLFree( pszUnescapedContents );
1319 4 : return FALSE;
1320 : }
1321 :
1322 38 : CPLFree( pszTREName );
1323 38 : CPLFree( pszUnescapedContents );
1324 :
1325 : }
1326 :
1327 34 : return TRUE;
1328 : }
1329 :
1330 : /************************************************************************/
1331 : /* NITFWriteBLOCKA() */
1332 : /************************************************************************/
1333 :
1334 6 : static int NITFWriteBLOCKA( VSILFILE* fp, vsi_l_offset nOffsetUDIDL,
1335 : vsi_l_offset nOffsetTRE,
1336 : int *pnOffset,
1337 : char **papszOptions )
1338 :
1339 : {
1340 : static const char *apszFields[] = {
1341 : "BLOCK_INSTANCE", "0", "2",
1342 : "N_GRAY", "2", "5",
1343 : "L_LINES", "7", "5",
1344 : "LAYOVER_ANGLE", "12", "3",
1345 : "SHADOW_ANGLE", "15", "3",
1346 : "BLANKS", "18", "16",
1347 : "FRLC_LOC", "34", "21",
1348 : "LRLC_LOC", "55", "21",
1349 : "LRFC_LOC", "76", "21",
1350 : "FRFC_LOC", "97", "21",
1351 : NULL, NULL, NULL };
1352 : int nBlockCount =
1353 6 : atoi(CSLFetchNameValue( papszOptions, "BLOCKA_BLOCK_COUNT" ));
1354 : int iBlock;
1355 :
1356 : /* ==================================================================== */
1357 : /* Loop over all the blocks we have metadata for. */
1358 : /* ==================================================================== */
1359 10 : for( iBlock = 1; iBlock <= nBlockCount; iBlock++ )
1360 : {
1361 : char szBLOCKA[123];
1362 : int iField;
1363 :
1364 : /* -------------------------------------------------------------------- */
1365 : /* Write all fields. */
1366 : /* -------------------------------------------------------------------- */
1367 64 : for( iField = 0; apszFields[iField*3] != NULL; iField++ )
1368 : {
1369 : char szFullFieldName[64];
1370 60 : int iStart = atoi(apszFields[iField*3+1]);
1371 60 : int iSize = atoi(apszFields[iField*3+2]);
1372 : const char *pszValue;
1373 :
1374 60 : sprintf( szFullFieldName, "BLOCKA_%s_%02d",
1375 60 : apszFields[iField*3 + 0], iBlock );
1376 :
1377 60 : pszValue = CSLFetchNameValue( papszOptions, szFullFieldName );
1378 60 : if( pszValue == NULL )
1379 28 : pszValue = "";
1380 :
1381 60 : if (strlen(pszValue) > (size_t)iSize)
1382 : {
1383 2 : CPLError(CE_Failure, CPLE_AppDefined,
1384 : "Too much data for %s. Got %d bytes, max allowed is %d",
1385 : szFullFieldName, (int)strlen(pszValue), iSize);
1386 2 : return FALSE;
1387 : }
1388 :
1389 : /* Right align value and left pad with spaces */
1390 58 : memset( szBLOCKA + iStart, ' ', iSize );
1391 58 : memcpy( szBLOCKA + iStart + MAX((size_t)0,iSize-strlen(pszValue)),
1392 : pszValue, strlen(pszValue) );
1393 : }
1394 :
1395 : // required field - semantics unknown.
1396 4 : memcpy( szBLOCKA + 118, "010.0", 5);
1397 :
1398 4 : if( !NITFWriteTRE( fp,
1399 : nOffsetUDIDL, nOffsetTRE,
1400 : pnOffset,
1401 : "BLOCKA", szBLOCKA, 123 ) )
1402 0 : return FALSE;
1403 : }
1404 :
1405 4 : return TRUE;
1406 : }
1407 :
1408 : /************************************************************************/
1409 : /* NITFCollectSegmentInfo() */
1410 : /* */
1411 : /* Collect the information about a set of segments of a */
1412 : /* particular type from the NITF file header, and add them to */
1413 : /* the segment list in the NITFFile object. */
1414 : /************************************************************************/
1415 :
1416 : static int
1417 7016 : NITFCollectSegmentInfo( NITFFile *psFile, int nFileHeaderLen, int nOffset, const char szType[3],
1418 : int nHeaderLenSize, int nDataLenSize, GUIntBig *pnNextData )
1419 :
1420 : {
1421 : char szTemp[12];
1422 : int nCount, nSegDefSize, iSegment;
1423 :
1424 : /* -------------------------------------------------------------------- */
1425 : /* Get the segment count, and grow the segmentinfo array */
1426 : /* accordingly. */
1427 : /* -------------------------------------------------------------------- */
1428 7016 : if ( nFileHeaderLen < nOffset + 3 )
1429 : {
1430 2 : CPLError(CE_Failure, CPLE_AppDefined, "Not enough bytes to read segment count");
1431 2 : return -1;
1432 : }
1433 :
1434 7014 : NITFGetField( szTemp, psFile->pachHeader, nOffset, 3 );
1435 7014 : nCount = atoi(szTemp);
1436 :
1437 7014 : if( nCount <= 0 )
1438 5732 : return nOffset + 3;
1439 :
1440 1282 : nSegDefSize = nCount * (nHeaderLenSize + nDataLenSize);
1441 1282 : if ( nFileHeaderLen < nOffset + 3 + nSegDefSize)
1442 : {
1443 2 : CPLError(CE_Failure, CPLE_AppDefined, "Not enough bytes to read segment info");
1444 2 : return -1;
1445 : }
1446 :
1447 1280 : if( psFile->pasSegmentInfo == NULL )
1448 1172 : psFile->pasSegmentInfo = (NITFSegmentInfo *)
1449 : CPLMalloc( sizeof(NITFSegmentInfo) * nCount );
1450 : else
1451 216 : psFile->pasSegmentInfo = (NITFSegmentInfo *)
1452 108 : CPLRealloc( psFile->pasSegmentInfo,
1453 : sizeof(NITFSegmentInfo)
1454 108 : * (psFile->nSegmentCount+nCount) );
1455 :
1456 : /* -------------------------------------------------------------------- */
1457 : /* Collect detailed about segment. */
1458 : /* -------------------------------------------------------------------- */
1459 13950 : for( iSegment = 0; iSegment < nCount; iSegment++ )
1460 : {
1461 12674 : NITFSegmentInfo *psInfo = psFile->pasSegmentInfo+psFile->nSegmentCount;
1462 :
1463 12674 : psInfo->nDLVL = -1;
1464 12674 : psInfo->nALVL = -1;
1465 12674 : psInfo->nLOC_R = -1;
1466 12674 : psInfo->nLOC_C = -1;
1467 12674 : psInfo->nCCS_R = -1;
1468 12674 : psInfo->nCCS_C = -1;
1469 :
1470 12674 : psInfo->hAccess = NULL;
1471 12674 : strcpy( psInfo->szSegmentType, szType );
1472 :
1473 12674 : psInfo->nSegmentHeaderSize =
1474 12674 : atoi(NITFGetField(szTemp, psFile->pachHeader,
1475 12674 : nOffset + 3 + iSegment * (nHeaderLenSize+nDataLenSize),
1476 : nHeaderLenSize));
1477 12674 : if (strchr(szTemp, '-') != NULL) /* Avoid negative values being mapped to huge unsigned values */
1478 : {
1479 2 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid segment header size : %s", szTemp);
1480 2 : return -1;
1481 : }
1482 :
1483 12672 : if (strcmp(szType, "DE") == 0 && psInfo->nSegmentHeaderSize == 207)
1484 : {
1485 : /* DMAAC A.TOC files have a wrong header size. It says 207 but it is 209 really */
1486 0 : psInfo->nSegmentHeaderSize = 209;
1487 : }
1488 :
1489 12672 : psInfo->nSegmentSize =
1490 12672 : CPLScanUIntBig(NITFGetField(szTemp,psFile->pachHeader,
1491 12672 : nOffset + 3 + iSegment * (nHeaderLenSize+nDataLenSize)
1492 12672 : + nHeaderLenSize,
1493 : nDataLenSize), nDataLenSize);
1494 12672 : if (strchr(szTemp, '-') != NULL) /* Avoid negative values being mapped to huge unsigned values */
1495 : {
1496 2 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid segment size : %s", szTemp);
1497 2 : return -1;
1498 : }
1499 :
1500 12670 : psInfo->nSegmentHeaderStart = *pnNextData;
1501 12670 : psInfo->nSegmentStart = *pnNextData + psInfo->nSegmentHeaderSize;
1502 :
1503 12670 : *pnNextData += (psInfo->nSegmentHeaderSize+psInfo->nSegmentSize);
1504 12670 : psFile->nSegmentCount++;
1505 : }
1506 :
1507 1276 : return nOffset + nSegDefSize + 3;
1508 : }
1509 :
1510 : /************************************************************************/
1511 : /* NITFGetField() */
1512 : /* */
1513 : /* Copy a field from a passed in header buffer into a temporary */
1514 : /* buffer and zero terminate it. */
1515 : /************************************************************************/
1516 :
1517 1822974 : char *NITFGetField( char *pszTarget, const char *pszSource,
1518 : int nStart, int nLength )
1519 :
1520 : {
1521 1822974 : memcpy( pszTarget, pszSource + nStart, nLength );
1522 1822974 : pszTarget[nLength] = '\0';
1523 :
1524 1822974 : return pszTarget;
1525 : }
1526 :
1527 : /************************************************************************/
1528 : /* NITFFindTRE() */
1529 : /************************************************************************/
1530 :
1531 50556 : const char *NITFFindTRE( const char *pszTREData, int nTREBytes,
1532 : const char *pszTag, int *pnFoundTRESize )
1533 :
1534 : {
1535 : char szTemp[100];
1536 :
1537 395574 : while( nTREBytes >= 11 )
1538 : {
1539 294746 : int nThisTRESize = atoi(NITFGetField(szTemp, pszTREData, 6, 5 ));
1540 294746 : if (nThisTRESize < 0)
1541 : {
1542 64 : NITFGetField(szTemp, pszTREData, 0, 6 );
1543 64 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid size (%d) for TRE %s",
1544 : nThisTRESize, szTemp);
1545 64 : return NULL;
1546 : }
1547 294682 : if (nTREBytes - 11 < nThisTRESize)
1548 : {
1549 64 : NITFGetField(szTemp, pszTREData, 0, 6 );
1550 64 : if (EQUALN(szTemp, "RPFIMG",6))
1551 : {
1552 : /* See #3848 */
1553 0 : CPLDebug("NITF", "Adjusting RPFIMG TRE size from %d to %d, which is the remaining size", nThisTRESize, nTREBytes - 11);
1554 0 : nThisTRESize = nTREBytes - 11;
1555 : }
1556 : else
1557 : {
1558 64 : CPLError(CE_Failure, CPLE_AppDefined,
1559 : "Cannot read %s TRE. Not enough bytes : remaining %d, expected %d",
1560 : szTemp, nTREBytes - 11, nThisTRESize);
1561 64 : return NULL;
1562 : }
1563 : }
1564 :
1565 294618 : if( EQUALN(pszTREData,pszTag,6) )
1566 : {
1567 156 : if( pnFoundTRESize != NULL )
1568 156 : *pnFoundTRESize = nThisTRESize;
1569 :
1570 156 : return pszTREData + 11;
1571 : }
1572 :
1573 294462 : nTREBytes -= (nThisTRESize + 11);
1574 294462 : pszTREData += (nThisTRESize + 11);
1575 : }
1576 :
1577 50272 : return NULL;
1578 : }
1579 :
1580 : /************************************************************************/
1581 : /* NITFFindTREByIndex() */
1582 : /************************************************************************/
1583 :
1584 1128 : const char *NITFFindTREByIndex( const char *pszTREData, int nTREBytes,
1585 : const char *pszTag, int nTreIndex,
1586 : int *pnFoundTRESize )
1587 :
1588 : {
1589 : char szTemp[100];
1590 :
1591 2450 : while( nTREBytes >= 11 )
1592 : {
1593 230 : int nThisTRESize = atoi(NITFGetField(szTemp, pszTREData, 6, 5 ));
1594 230 : if (nThisTRESize < 0)
1595 : {
1596 4 : NITFGetField(szTemp, pszTREData, 0, 6 );
1597 4 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid size (%d) for TRE %s",
1598 : nThisTRESize, szTemp);
1599 4 : return NULL;
1600 : }
1601 226 : if (nTREBytes - 11 < nThisTRESize)
1602 : {
1603 4 : NITFGetField(szTemp, pszTREData, 0, 6 );
1604 4 : if (EQUALN(szTemp, "RPFIMG",6))
1605 : {
1606 : /* See #3848 */
1607 0 : CPLDebug("NITF", "Adjusting RPFIMG TRE size from %d to %d, which is the remaining size", nThisTRESize, nTREBytes - 11);
1608 0 : nThisTRESize = nTREBytes - 11;
1609 : }
1610 : else
1611 : {
1612 4 : CPLError(CE_Failure, CPLE_AppDefined,
1613 : "Cannot read %s TRE. Not enough bytes : remaining %d, expected %d",
1614 : szTemp, nTREBytes - 11, nThisTRESize);
1615 4 : return NULL;
1616 : }
1617 : }
1618 :
1619 222 : if( EQUALN(pszTREData,pszTag,6) )
1620 : {
1621 56 : if ( nTreIndex <= 0)
1622 : {
1623 28 : if( pnFoundTRESize != NULL )
1624 28 : *pnFoundTRESize = nThisTRESize;
1625 :
1626 28 : return pszTREData + 11;
1627 : }
1628 :
1629 : /* Found a prevoius one - skip it ... */
1630 28 : nTreIndex--;
1631 : }
1632 :
1633 194 : nTREBytes -= (nThisTRESize + 11);
1634 194 : pszTREData += (nThisTRESize + 11);
1635 : }
1636 :
1637 1092 : return NULL;
1638 : }
1639 :
1640 : /************************************************************************/
1641 : /* NITFExtractMetadata() */
1642 : /************************************************************************/
1643 :
1644 281266 : void NITFExtractMetadata( char ***ppapszMetadata, const char *pachHeader,
1645 : int nStart, int nLength, const char *pszName )
1646 :
1647 : {
1648 : char szWork[400];
1649 : char* pszWork;
1650 :
1651 281266 : if (nLength >= sizeof(szWork) - 1)
1652 0 : pszWork = (char*)CPLMalloc(nLength + 1);
1653 : else
1654 281266 : pszWork = szWork;
1655 :
1656 : /* trim white space */
1657 3760514 : while( nLength > 0 && pachHeader[nStart + nLength - 1] == ' ' )
1658 3197982 : nLength--;
1659 :
1660 281266 : memcpy( pszWork, pachHeader + nStart, nLength );
1661 281266 : pszWork[nLength] = '\0';
1662 :
1663 281266 : *ppapszMetadata = CSLSetNameValue( *ppapszMetadata, pszName, pszWork );
1664 :
1665 281266 : if (szWork != pszWork)
1666 0 : CPLFree(pszWork);
1667 281266 : }
1668 :
1669 : /************************************************************************/
1670 : /* NITF_WGS84_Geocentric_Latitude_To_Geodetic_Latitude() */
1671 : /* */
1672 : /* The input is a geocentric latitude in degrees. The output */
1673 : /* is a geodetic latitude in degrees. */
1674 : /************************************************************************/
1675 :
1676 : /*
1677 : * "The angle L' is called "geocentric latitude" and is defined as the
1678 : * angle between the equatorial plane and the radius from the geocenter.
1679 : *
1680 : * The angle L is called "geodetic latitude" and is defined as the angle
1681 : * between the equatorial plane and the normal to the surface of the
1682 : * ellipsoid. The word "latitude" usually means geodetic latitude. This
1683 : * is the basis for most of the maps and charts we use. The normal to the
1684 : * surface is the direction that a plumb bob would hang were it not for
1685 : * local anomalies in the earth's gravitational field."
1686 : */
1687 :
1688 0 : double NITF_WGS84_Geocentric_Latitude_To_Geodetic_Latitude( double dfLat )
1689 :
1690 : {
1691 : /* WGS84 Ellipsoid */
1692 0 : double a = 6378137.0;
1693 0 : double b = 6356752.3142;
1694 0 : double dfPI = 3.14159265358979323;
1695 :
1696 : /* convert to radians */
1697 0 : dfLat = dfLat * dfPI / 180.0;
1698 :
1699 : /* convert to geodetic */
1700 0 : dfLat = atan( ((a*a)/(b*b)) * tan(dfLat) );
1701 :
1702 : /* convert back to degrees */
1703 0 : dfLat = dfLat * 180.0 / dfPI;
1704 :
1705 0 : return dfLat;
1706 : }
1707 :
1708 :
1709 : /************************************************************************/
1710 : /* NITFGetSeriesInfo() */
1711 : /************************************************************************/
1712 :
1713 : static const NITFSeries nitfSeries[] =
1714 : {
1715 : { "GN", "GNC", "1:5M", "Global Navigation Chart", "CADRG"},
1716 : { "JN", "JNC", "1:2M", "Jet Navigation Chart", "CADRG"},
1717 : { "OH", "VHRC", "1:1M", "VFR Helicopter Route Chart", "CADRG"},
1718 : { "ON", "ONC", "1:1M", "Operational Navigation Chart", "CADRG"},
1719 : { "OW", "WAC", "1:1M", "High Flying Chart - Host Nation", "CADRG"},
1720 : { "TP", "TPC", "1:500K", "Tactical Pilotage Chart", "CADRG"},
1721 : { "LF", "LFC-FR (Day)", "1:500K", "Low Flying Chart (Day) - Host Nation", "CADRG"},
1722 : { "L1", "LFC-1", "1:500K", "Low Flying Chart (TED #1)", "CADRG"},
1723 : { "L2", "LFC-2", "1:500K", "Low Flying Chart (TED #2)", "CADRG"},
1724 : { "L3", "LFC-3", "1:500K", "Low Flying Chart (TED #3)", "CADRG"},
1725 : { "L4", "LFC-4", "1:500K", "Low Flying Chart (TED #4)", "CADRG"},
1726 : { "L5", "LFC-5", "1:500K", "Low Flying Chart (TED #5)", "CADRG"},
1727 : { "LN", "LN (Night)", "1:500K", "Low Flying Chart (Night) - Host Nation", "CADRG"},
1728 : { "JG", "JOG", "1:250K", "Joint Operation Graphic", "CADRG"},
1729 : { "JA", "JOG-A", "1:250K", "Joint Operation Graphic - Air", "CADRG"},
1730 : { "JR", "JOG-R", "1:250K", "Joint Operation Graphic - Radar", "CADRG"},
1731 : { "JO", "OPG", "1:250K", "Operational Planning Graphic", "CADRG"},
1732 : { "VT", "VTAC", "1:250K", "VFR Terminal Area Chart", "CADRG"},
1733 : { "F1", "TFC-1", "1:250K", "Transit Flying Chart (TED #1)", "CADRG"},
1734 : { "F2", "TFC-2", "1:250K", "Transit Flying Chart (TED #2)", "CADRG"},
1735 : { "F3", "TFC-3", "1:250K", "Transit Flying Chart (TED #3)", "CADRG"},
1736 : { "F4", "TFC-4", "1:250K", "Transit Flying Chart (TED #4)", "CADRG"},
1737 : { "F5", "TFC-5", "1:250K", "Transit Flying Chart (TED #5)", "CADRG"},
1738 : { "AT", "ATC", "1:200K", "Series 200 Air Target Chart", "CADRG"},
1739 : { "VH", "HRC", "1:125K", "Helicopter Route Chart", "CADRG"},
1740 : { "TN", "TFC (Night)", "1:250K", "Transit Flying Charget (Night) - Host Nation", "CADRG"},
1741 : { "TR", "TLM 200", "1:200K", "Topographic Line Map 1:200,000 scale", "CADRG"},
1742 : { "TC", "TLM 100", "1:100K", "Topographic Line Map 1:100,000 scale", "CADRG"},
1743 : { "RV", "Riverine", "1:50K", "Riverine Map 1:50,000 scale", "CADRG"},
1744 : { "TL", "TLM 50", "1:50K", "Topographic Line Map 1:50,000 scale", "CADRG"},
1745 : { "UL", "TLM 50 - Other", "1:50K", "Topographic Line Map (other 1:50,000 scale)", "CADRG"},
1746 : { "TT", "TLM 25", "1:25K", "Topographic Line Map 1:25,000 scale", "CADRG"},
1747 : { "TQ", "TLM 24", "1:24K", "Topographic Line Map 1:24,000 scale", "CADRG"},
1748 : { "HA", "HA", "Various", "Harbor and Approach Charts", "CADRG"},
1749 : { "CO", "CO", "Various", "Coastal Charts", "CADRG"},
1750 : { "OA", "OPAREA", "Various", "Naval Range Operation Area Chart", "CADRG"},
1751 : { "CG", "CG", "Various", "City Graphics", "CADRG"},
1752 : { "C1", "CG", "1:10000", "City Graphics", "CADRG"},
1753 : { "C2", "CG", "1:10560", "City Graphics", "CADRG"},
1754 : { "C3", "CG", "1:11000", "City Graphics", "CADRG"},
1755 : { "C4", "CG", "1:11800", "City Graphics", "CADRG"},
1756 : { "C5", "CG", "1:12000", "City Graphics", "CADRG"},
1757 : { "C6", "CG", "1:12500", "City Graphics", "CADRG"},
1758 : { "C7", "CG", "1:12800", "City Graphics", "CADRG"},
1759 : { "C8", "CG", "1:14000", "City Graphics", "CADRG"},
1760 : { "C9", "CG", "1:14700", "City Graphics", "CADRG"},
1761 : { "CA", "CG", "1:15000", "City Graphics", "CADRG"},
1762 : { "CB", "CG", "1:15500", "City Graphics", "CADRG"},
1763 : { "CC", "CG", "1:16000", "City Graphics", "CADRG"},
1764 : { "CD", "CG", "1:16666", "City Graphics", "CADRG"},
1765 : { "CE", "CG", "1:17000", "City Graphics", "CADRG"},
1766 : { "CF", "CG", "1:17500", "City Graphics", "CADRG"},
1767 : { "CH", "CG", "1:18000", "City Graphics", "CADRG"},
1768 : { "CJ", "CG", "1:20000", "City Graphics", "CADRG"},
1769 : { "CK", "CG", "1:21000", "City Graphics", "CADRG"},
1770 : { "CL", "CG", "1:21120", "City Graphics", "CADRG"},
1771 : { "CN", "CG", "1:22000", "City Graphics", "CADRG"},
1772 : { "CP", "CG", "1:23000", "City Graphics", "CADRG"},
1773 : { "CQ", "CG", "1:25000", "City Graphics", "CADRG"},
1774 : { "CR", "CG", "1:26000", "City Graphics", "CADRG"},
1775 : { "CS", "CG", "1:35000", "City Graphics", "CADRG"},
1776 : { "CT", "CG", "1:36000", "City Graphics", "CADRG"},
1777 : { "CM", "CM", "Various", "Combat Charts", "CADRG"},
1778 : { "A1", "CM", "1:10K", "Combat Charts (1:10K)", "CADRG"},
1779 : { "A2", "CM", "1:25K", "Combat Charts (1:25K)", "CADRG"},
1780 : { "A3", "CM", "1:50K", "Combat Charts (1:50K)", "CADRG"},
1781 : { "A4", "CM", "1:100K", "Combat Charts (1:100K)", "CADRG"},
1782 : { "MI", "MIM", "1:50K", "Military Installation Maps", "CADRG"},
1783 : { "M1", "MIM", "Various", "Military Installation Maps (TED #1)", "CADRG"},
1784 : { "M2", "MIM", "Various", "Military Installation Maps (TED #2)", "CADRG"},
1785 : { "VN", "VNC", "1:500K", "Visual Navigation Charts", "CADRG"},
1786 : { "MM", "", "Various", "(Miscellaneous Maps & Charts)", "CADRG"},
1787 :
1788 : { "I1", "", "10m", "Imagery, 10 meter resolution", "CIB"},
1789 : { "I2", "", "5m", "Imagery, 5 meter resolution", "CIB"},
1790 : { "I3", "", "2m", "Imagery, 2 meter resolution", "CIB"},
1791 : { "I4", "", "1m", "Imagery, 1 meter resolution", "CIB"},
1792 : { "I5", "", ".5m", "Imagery, .5 (half) meter resolution", "CIB"},
1793 : { "IV", "", "Various > 10m", "Imagery, greater than 10 meter resolution", "CIB"},
1794 :
1795 : { "D1", "", "100m", "Elevation Data from DTED level 1", "CDTED"},
1796 : { "D2", "", "30m", "Elevation Data from DTED level 2", "CDTED"},
1797 : };
1798 :
1799 : /* See 24111CN1.pdf paragraph 5.1.4 */
1800 1122 : const NITFSeries* NITFGetSeriesInfo(const char* pszFilename)
1801 : {
1802 : int i;
1803 1122 : char seriesCode[3] = {0,0,0};
1804 1122 : if (pszFilename == NULL) return NULL;
1805 7078 : for (i=strlen(pszFilename)-1;i>=0;i--)
1806 : {
1807 6978 : if (pszFilename[i] == '.')
1808 : {
1809 1032 : if (i < (int)strlen(pszFilename) - 3)
1810 : {
1811 1022 : seriesCode[0] = pszFilename[i+1];
1812 1022 : seriesCode[1] = pszFilename[i+2];
1813 77114 : for(i=0;i<sizeof(nitfSeries) / sizeof(nitfSeries[0]); i++)
1814 : {
1815 76166 : if (EQUAL(seriesCode, nitfSeries[i].code))
1816 : {
1817 74 : return &nitfSeries[i];
1818 : }
1819 : }
1820 948 : return NULL;
1821 : }
1822 : }
1823 : }
1824 100 : return NULL;
1825 : }
1826 :
1827 : /************************************************************************/
1828 : /* NITFCollectAttachments() */
1829 : /* */
1830 : /* Collect attachment, display level and location info into the */
1831 : /* segmentinfo structures. */
1832 : /************************************************************************/
1833 :
1834 826 : int NITFCollectAttachments( NITFFile *psFile )
1835 :
1836 : {
1837 : int iSegment;
1838 :
1839 : /* ==================================================================== */
1840 : /* Loop over all segments. */
1841 : /* ==================================================================== */
1842 11114 : for( iSegment = 0; iSegment < psFile->nSegmentCount; iSegment++ )
1843 : {
1844 10326 : NITFSegmentInfo *psSegInfo = psFile->pasSegmentInfo + iSegment;
1845 :
1846 : /* -------------------------------------------------------------------- */
1847 : /* For image segments, we use the normal image access stuff. */
1848 : /* -------------------------------------------------------------------- */
1849 10326 : if( EQUAL(psSegInfo->szSegmentType,"IM") )
1850 : {
1851 8880 : NITFImage *psImage = NITFImageAccess( psFile, iSegment );
1852 8880 : if (psImage == NULL)
1853 38 : return FALSE;
1854 :
1855 8842 : psSegInfo->nDLVL = psImage->nIDLVL;
1856 8842 : psSegInfo->nALVL = psImage->nIALVL;
1857 8842 : psSegInfo->nLOC_R = psImage->nILOCRow;
1858 8842 : psSegInfo->nLOC_C = psImage->nILOCColumn;
1859 : }
1860 : /* -------------------------------------------------------------------- */
1861 : /* For graphic file we need to process the header. */
1862 : /* -------------------------------------------------------------------- */
1863 2892 : else if( EQUAL(psSegInfo->szSegmentType,"SY")
1864 1446 : || EQUAL(psSegInfo->szSegmentType,"GR") )
1865 : {
1866 : char achSubheader[298];
1867 : int nSTYPEOffset;
1868 : char szTemp[100];
1869 :
1870 : /* -------------------------------------------------------------------- */
1871 : /* Load the graphic subheader. */
1872 : /* -------------------------------------------------------------------- */
1873 1444 : if( VSIFSeekL( psFile->fp, psSegInfo->nSegmentHeaderStart,
1874 : SEEK_SET ) != 0
1875 722 : || VSIFReadL( achSubheader, 1, sizeof(achSubheader),
1876 722 : psFile->fp ) < 258 )
1877 : {
1878 2 : CPLError( CE_Warning, CPLE_FileIO,
1879 : "Failed to read graphic subheader at " CPL_FRMT_GUIB ".",
1880 : psSegInfo->nSegmentHeaderStart );
1881 2 : continue;
1882 : }
1883 :
1884 : // NITF 2.0. (also works for NITF 2.1)
1885 720 : nSTYPEOffset = 200;
1886 720 : if( EQUALN(achSubheader+193,"999998",6) )
1887 636 : nSTYPEOffset += 40;
1888 :
1889 : /* -------------------------------------------------------------------- */
1890 : /* Report some standard info. */
1891 : /* -------------------------------------------------------------------- */
1892 720 : psSegInfo->nDLVL = atoi(NITFGetField(szTemp,achSubheader,
1893 : nSTYPEOffset + 14, 3));
1894 720 : psSegInfo->nALVL = atoi(NITFGetField(szTemp,achSubheader,
1895 : nSTYPEOffset + 17, 3));
1896 720 : psSegInfo->nLOC_R = atoi(NITFGetField(szTemp,achSubheader,
1897 : nSTYPEOffset + 20, 5));
1898 720 : psSegInfo->nLOC_C = atoi(NITFGetField(szTemp,achSubheader,
1899 : nSTYPEOffset + 25, 5));
1900 : }
1901 : }
1902 :
1903 788 : return TRUE;
1904 : }
1905 :
1906 : /************************************************************************/
1907 : /* NITFReconcileAttachments() */
1908 : /* */
1909 : /* Generate the CCS location information for all the segments */
1910 : /* if possible. */
1911 : /************************************************************************/
1912 :
1913 842 : int NITFReconcileAttachments( NITFFile *psFile )
1914 :
1915 : {
1916 : int iSegment;
1917 842 : int bSuccess = TRUE;
1918 842 : int bMadeProgress = FALSE;
1919 :
1920 11392 : for( iSegment = 0; iSegment < psFile->nSegmentCount; iSegment++ )
1921 : {
1922 10550 : NITFSegmentInfo *psSegInfo = psFile->pasSegmentInfo + iSegment;
1923 : int iOther;
1924 :
1925 : // already processed?
1926 10550 : if( psSegInfo->nCCS_R != -1 )
1927 96 : continue;
1928 :
1929 : // unattached segments are straight forward.
1930 10454 : if( psSegInfo->nALVL < 1 )
1931 : {
1932 10124 : psSegInfo->nCCS_R = psSegInfo->nLOC_R;
1933 10124 : psSegInfo->nCCS_C = psSegInfo->nLOC_C;
1934 10124 : if( psSegInfo->nCCS_R != -1 )
1935 9280 : bMadeProgress = TRUE;
1936 10124 : continue;
1937 : }
1938 :
1939 : // Loc for segment to which we are attached.
1940 1224 : for( iOther = 0; iOther < psFile->nSegmentCount; iOther++ )
1941 : {
1942 1176 : NITFSegmentInfo *psOtherSegInfo = psFile->pasSegmentInfo + iOther;
1943 :
1944 1176 : if( psSegInfo->nALVL == psOtherSegInfo->nDLVL )
1945 : {
1946 282 : if( psOtherSegInfo->nCCS_R != -1 )
1947 : {
1948 266 : psSegInfo->nCCS_R = psOtherSegInfo->nLOC_R + psSegInfo->nLOC_R;
1949 266 : psSegInfo->nCCS_C = psOtherSegInfo->nLOC_C + psSegInfo->nLOC_C;
1950 266 : if ( psSegInfo->nCCS_R != -1 )
1951 266 : bMadeProgress = TRUE;
1952 : }
1953 : else
1954 : {
1955 16 : bSuccess = FALSE;
1956 : }
1957 282 : break;
1958 : }
1959 : }
1960 :
1961 330 : if( iOther == psFile->nSegmentCount )
1962 48 : bSuccess = FALSE;
1963 : }
1964 :
1965 : /* -------------------------------------------------------------------- */
1966 : /* If succeeded or made no progress then return our success */
1967 : /* flag. Otherwise make another pass, hopefully filling in */
1968 : /* more values. */
1969 : /* -------------------------------------------------------------------- */
1970 842 : if( bSuccess || !bMadeProgress )
1971 826 : return bSuccess;
1972 : else
1973 16 : return NITFReconcileAttachments( psFile );
1974 : }
1975 :
1976 : /************************************************************************/
1977 : /* NITFFindValFromEnd() */
1978 : /************************************************************************/
1979 :
1980 182 : static const char* NITFFindValFromEnd(char** papszMD,
1981 : int nMDSize,
1982 : const char* pszVar,
1983 : const char* pszDefault)
1984 : {
1985 182 : int nVarLen = strlen(pszVar);
1986 182 : int nIter = nMDSize-1;
1987 990 : for(;nIter >= 0;nIter--)
1988 : {
1989 1174 : if (strncmp(papszMD[nIter], pszVar, nVarLen) == 0 &&
1990 184 : papszMD[nIter][nVarLen] == '=')
1991 182 : return papszMD[nIter] + nVarLen + 1;
1992 : }
1993 0 : return NULL;
1994 : }
1995 :
1996 : /************************************************************************/
1997 : /* NITFGenericMetadataReadTREInternal() */
1998 : /************************************************************************/
1999 :
2000 488 : static char** NITFGenericMetadataReadTREInternal(char **papszMD,
2001 : int* pnMDSize,
2002 : int* pnMDAlloc,
2003 : CPLXMLNode* psOutXMLNode,
2004 : const char* pszTREName,
2005 : const char *pachTRE,
2006 : int nTRESize,
2007 : CPLXMLNode* psTreNode,
2008 : int *pnTreOffset,
2009 : const char* pszMDPrefix,
2010 : int *pbError)
2011 : {
2012 : CPLXMLNode* psIter;
2013 8412 : for(psIter = psTreNode->psChild;
2014 3718 : psIter != NULL && *pbError == FALSE;
2015 3718 : psIter = psIter->psNext)
2016 : {
2017 9758 : if (psIter->eType == CXT_Element &&
2018 2072 : psIter->pszValue != NULL &&
2019 2072 : strcmp(psIter->pszValue, "field") == 0)
2020 : {
2021 1896 : const char* pszName = CPLGetXMLValue(psIter, "name", NULL);
2022 1896 : const char* pszLongName = CPLGetXMLValue(psIter, "longname", NULL);
2023 1896 : const char* pszLength = CPLGetXMLValue(psIter, "length", NULL);
2024 1896 : int nLength = -1;
2025 1896 : if (pszLength != NULL)
2026 1896 : nLength = atoi(pszLength);
2027 : else
2028 : {
2029 0 : const char* pszLengthVar = CPLGetXMLValue(psIter, "length_var", NULL);
2030 0 : if (pszLengthVar != NULL)
2031 : {
2032 0 : char** papszMDIter = papszMD;
2033 0 : while(papszMDIter != NULL && *papszMDIter != NULL)
2034 : {
2035 0 : if (strstr(*papszMDIter, pszLengthVar) != NULL)
2036 : {
2037 0 : const char* pszEqual = strchr(*papszMDIter, '=');
2038 0 : if (pszEqual != NULL)
2039 : {
2040 0 : nLength = atoi(pszEqual + 1);
2041 0 : break;
2042 : }
2043 : }
2044 0 : papszMDIter ++;
2045 : }
2046 : }
2047 : }
2048 3628 : if (pszName != NULL && nLength > 0)
2049 : {
2050 : char* pszMDItemName;
2051 1732 : char** papszTmp = NULL;
2052 :
2053 1732 : if (*pnTreOffset + nLength > nTRESize)
2054 : {
2055 0 : *pbError = TRUE;
2056 0 : CPLError( CE_Warning, CPLE_AppDefined,
2057 : "Not enough bytes when reading %s TRE "
2058 : "(at least %d needed, only %d available)",
2059 0 : pszTREName, *pnTreOffset + nLength, nTRESize );
2060 0 : break;
2061 : }
2062 :
2063 1732 : pszMDItemName = CPLStrdup(
2064 : CPLSPrintf("%s%s", pszMDPrefix, pszName));
2065 :
2066 1732 : NITFExtractMetadata( &papszTmp, pachTRE, *pnTreOffset,
2067 : nLength, pszMDItemName );
2068 1732 : if (*pnMDSize + 1 >= *pnMDAlloc)
2069 : {
2070 74 : *pnMDAlloc = (*pnMDAlloc * 4 / 3) + 32;
2071 74 : papszMD = (char**)CPLRealloc(papszMD, *pnMDAlloc * sizeof(char**));
2072 : }
2073 1732 : papszMD[*pnMDSize] = papszTmp[0];
2074 1732 : papszMD[(*pnMDSize) + 1] = NULL;
2075 1732 : (*pnMDSize) ++;
2076 1732 : papszTmp[0] = NULL;
2077 1732 : CPLFree(papszTmp);
2078 :
2079 1732 : if (psOutXMLNode != NULL)
2080 : {
2081 1532 : const char* pszVal = strchr(papszMD[(*pnMDSize) - 1], '=') + 1;
2082 : CPLXMLNode* psFieldNode;
2083 : CPLXMLNode* psNameNode;
2084 : CPLXMLNode* psValueNode;
2085 :
2086 1532 : CPLAssert(pszVal != NULL);
2087 1532 : psFieldNode =
2088 1532 : CPLCreateXMLNode(psOutXMLNode, CXT_Element, "field");
2089 1532 : psNameNode =
2090 1532 : CPLCreateXMLNode(psFieldNode, CXT_Attribute, "name");
2091 1532 : psValueNode =
2092 1532 : CPLCreateXMLNode(psFieldNode, CXT_Attribute, "value");
2093 1532 : CPLCreateXMLNode(psNameNode, CXT_Text,
2094 1532 : (pszName[0] || pszLongName == NULL) ? pszName : pszLongName);
2095 1532 : CPLCreateXMLNode(psValueNode, CXT_Text, pszVal);
2096 : }
2097 :
2098 1732 : CPLFree(pszMDItemName);
2099 :
2100 1732 : *pnTreOffset += nLength;
2101 : }
2102 164 : else if (nLength > 0)
2103 : {
2104 164 : *pnTreOffset += nLength;
2105 : }
2106 : else
2107 : {
2108 0 : *pbError = TRUE;
2109 0 : CPLError( CE_Warning, CPLE_AppDefined,
2110 : "Invalid item construct in %s TRE in XML ressource",
2111 : pszTREName );
2112 0 : break;
2113 : }
2114 : }
2115 2260 : else if (psIter->eType == CXT_Element &&
2116 176 : psIter->pszValue != NULL &&
2117 176 : strcmp(psIter->pszValue, "loop") == 0)
2118 : {
2119 86 : const char* pszCounter = CPLGetXMLValue(psIter, "counter", NULL);
2120 86 : const char* pszIterations = CPLGetXMLValue(psIter, "iterations", NULL);
2121 86 : const char* pszFormula = CPLGetXMLValue(psIter, "formula", NULL);
2122 86 : const char* pszMDSubPrefix = CPLGetXMLValue(psIter, "md_prefix", NULL);
2123 86 : int nIterations = -1;
2124 :
2125 86 : if (pszCounter != NULL)
2126 : {
2127 80 : char* pszMDItemName = CPLStrdup(
2128 80 : CPLSPrintf("%s%s", pszMDPrefix, pszCounter));
2129 80 : nIterations = atoi(NITFFindValFromEnd(papszMD, *pnMDSize, pszMDItemName, "-1"));
2130 80 : CPLFree(pszMDItemName);
2131 80 : if (nIterations < 0)
2132 : {
2133 0 : CPLError( CE_Warning, CPLE_AppDefined,
2134 : "Invalid loop construct in %s TRE in XML ressource : "
2135 : "invalid 'counter' %s",
2136 : pszTREName, pszCounter );
2137 0 : *pbError = TRUE;
2138 0 : break;
2139 : }
2140 : }
2141 6 : else if (pszIterations != NULL)
2142 : {
2143 0 : nIterations = atoi(pszIterations);
2144 : }
2145 14 : else if (pszFormula != NULL &&
2146 6 : strcmp(pszFormula, "(NPART+1)*(NPART)/2") == 0)
2147 : {
2148 2 : char* pszMDItemName = CPLStrdup(
2149 2 : CPLSPrintf("%s%s", pszMDPrefix, "NPART"));
2150 2 : int NPART = atoi(NITFFindValFromEnd(papszMD, *pnMDSize, pszMDItemName, "-1"));
2151 2 : CPLFree(pszMDItemName);
2152 2 : if (NPART < 0)
2153 : {
2154 0 : CPLError( CE_Warning, CPLE_AppDefined,
2155 : "Invalid loop construct in %s TRE in XML ressource : "
2156 : "invalid 'counter' %s",
2157 : pszTREName, "NPART" );
2158 0 : *pbError = TRUE;
2159 0 : break;
2160 : }
2161 2 : nIterations = NPART * (NPART + 1) / 2;
2162 : }
2163 10 : else if (pszFormula != NULL &&
2164 4 : strcmp(pszFormula, "(NUMOPG+1)*(NUMOPG)/2") == 0)
2165 : {
2166 2 : char* pszMDItemName = CPLStrdup(
2167 2 : CPLSPrintf("%s%s", pszMDPrefix, "NUMOPG"));
2168 2 : int NUMOPG = atoi(NITFFindValFromEnd(papszMD, *pnMDSize, pszMDItemName, "-1"));
2169 2 : CPLFree(pszMDItemName);
2170 2 : if (NUMOPG < 0)
2171 : {
2172 0 : CPLError( CE_Warning, CPLE_AppDefined,
2173 : "Invalid loop construct in %s TRE in XML ressource : "
2174 : "invalid 'counter' %s",
2175 : pszTREName, "NUMOPG" );
2176 0 : *pbError = TRUE;
2177 0 : break;
2178 : }
2179 2 : nIterations = NUMOPG * (NUMOPG + 1) / 2;
2180 : }
2181 6 : else if (pszFormula != NULL &&
2182 2 : strcmp(pszFormula, "NPAR*NPARO") == 0)
2183 : {
2184 2 : char* pszMDNPARName = CPLStrdup(
2185 2 : CPLSPrintf("%s%s", pszMDPrefix, "NPAR"));
2186 2 : int NPAR = atoi(NITFFindValFromEnd(papszMD, *pnMDSize, pszMDNPARName, "-1"));
2187 2 : char* pszMDNPAROName = CPLStrdup(
2188 2 : CPLSPrintf("%s%s", pszMDPrefix, "NPARO"));
2189 2 : int NPARO= atoi(NITFFindValFromEnd(papszMD, *pnMDSize, pszMDNPAROName, "-1"));
2190 2 : CPLFree(pszMDNPARName);
2191 2 : CPLFree(pszMDNPAROName);
2192 2 : if (NPAR < 0)
2193 : {
2194 0 : CPLError( CE_Warning, CPLE_AppDefined,
2195 : "Invalid loop construct in %s TRE in XML ressource : "
2196 : "invalid 'counter' %s",
2197 : pszTREName, "NPAR" );
2198 0 : *pbError = TRUE;
2199 0 : break;
2200 : }
2201 2 : if (NPARO < 0)
2202 : {
2203 0 : CPLError( CE_Warning, CPLE_AppDefined,
2204 : "Invalid loop construct in %s TRE in XML ressource : "
2205 : "invalid 'counter' %s",
2206 : pszTREName, "NPAR0" );
2207 0 : *pbError = TRUE;
2208 0 : break;
2209 : }
2210 2 : nIterations = NPAR*NPARO;
2211 : }
2212 0 : else if (pszFormula != NULL &&
2213 0 : strcmp(pszFormula, "NPLN-1") == 0)
2214 : {
2215 0 : char* pszMDItemName = CPLStrdup(
2216 0 : CPLSPrintf("%s%s", pszMDPrefix, "NPLN"));
2217 0 : int NPLN = atoi(NITFFindValFromEnd(papszMD, *pnMDSize, pszMDItemName, "-1"));
2218 0 : CPLFree(pszMDItemName);
2219 0 : if (NPLN < 0)
2220 : {
2221 0 : CPLError( CE_Warning, CPLE_AppDefined,
2222 : "Invalid loop construct in %s TRE in XML ressource : "
2223 : "invalid 'counter' %s",
2224 : pszTREName, "NPLN" );
2225 0 : *pbError = TRUE;
2226 0 : break;
2227 : }
2228 0 : nIterations = NPLN-1;
2229 : }
2230 0 : else if (pszFormula != NULL &&
2231 0 : strcmp(pszFormula, "NXPTS*NYPTS") == 0)
2232 : {
2233 0 : char* pszMDNPARName = CPLStrdup(
2234 0 : CPLSPrintf("%s%s", pszMDPrefix, "NXPTS"));
2235 0 : int NXPTS = atoi(NITFFindValFromEnd(papszMD, *pnMDSize, pszMDNPARName, "-1"));
2236 0 : char* pszMDNPAROName = CPLStrdup(
2237 0 : CPLSPrintf("%s%s", pszMDPrefix, "NYPTS"));
2238 0 : int NYPTS= atoi(NITFFindValFromEnd(papszMD, *pnMDSize, pszMDNPAROName, "-1"));
2239 0 : CPLFree(pszMDNPARName);
2240 0 : CPLFree(pszMDNPAROName);
2241 0 : if (NXPTS < 0)
2242 : {
2243 0 : CPLError( CE_Warning, CPLE_AppDefined,
2244 : "Invalid loop construct in %s TRE in XML ressource : "
2245 : "invalid 'counter' %s",
2246 : pszTREName, "NXPTS" );
2247 0 : *pbError = TRUE;
2248 0 : break;
2249 : }
2250 0 : if (NYPTS < 0)
2251 : {
2252 0 : CPLError( CE_Warning, CPLE_AppDefined,
2253 : "Invalid loop construct in %s TRE in XML ressource : "
2254 : "invalid 'counter' %s",
2255 : pszTREName, "NYPTS" );
2256 0 : *pbError = TRUE;
2257 0 : break;
2258 : }
2259 0 : nIterations = NXPTS*NYPTS;
2260 : }
2261 : else
2262 : {
2263 0 : CPLError( CE_Warning, CPLE_AppDefined,
2264 : "Invalid loop construct in %s TRE in XML ressource : "
2265 : "missing or invalid 'counter' or 'iterations' or 'formula'",
2266 : pszTREName );
2267 0 : *pbError = TRUE;
2268 0 : break;
2269 : }
2270 :
2271 86 : if (nIterations > 0)
2272 : {
2273 : int iIter;
2274 : const char* pszPercent;
2275 66 : int bHasValidPercentD = FALSE;
2276 66 : CPLXMLNode* psRepeatedNode = NULL;
2277 66 : CPLXMLNode* psLastChild = NULL;
2278 :
2279 : /* Check that md_prefix has one and only %XXXXd pattern */
2280 132 : if (pszMDSubPrefix != NULL &&
2281 : (pszPercent = strchr(pszMDSubPrefix, '%')) != NULL &&
2282 66 : strchr(pszPercent+1,'%') == NULL)
2283 : {
2284 66 : const char* pszIter = pszPercent + 1;
2285 248 : while(*pszIter != '\0')
2286 : {
2287 298 : if (*pszIter >= '0' && *pszIter <= '9')
2288 116 : pszIter ++;
2289 66 : else if (*pszIter == 'd')
2290 : {
2291 66 : bHasValidPercentD = atoi(pszPercent + 1) <= 10;
2292 66 : break;
2293 : }
2294 : else
2295 0 : break;
2296 : }
2297 : }
2298 :
2299 66 : if (psOutXMLNode != NULL)
2300 : {
2301 : CPLXMLNode* psNumberNode;
2302 : CPLXMLNode* psNameNode;
2303 66 : const char* pszName = CPLGetXMLValue(psIter, "name", NULL);
2304 66 : psRepeatedNode = CPLCreateXMLNode(psOutXMLNode, CXT_Element, "repeated");
2305 66 : if (pszName)
2306 : {
2307 66 : psNameNode = CPLCreateXMLNode(psRepeatedNode, CXT_Attribute, "name");
2308 66 : CPLCreateXMLNode(psNameNode, CXT_Text, pszName);
2309 : }
2310 66 : psNumberNode = CPLCreateXMLNode(psRepeatedNode, CXT_Attribute, "number");
2311 66 : CPLCreateXMLNode(psNumberNode, CXT_Text, CPLSPrintf("%d", nIterations));
2312 :
2313 66 : psLastChild = psRepeatedNode->psChild;
2314 198 : while(psLastChild->psNext != NULL)
2315 66 : psLastChild = psLastChild->psNext;
2316 : }
2317 :
2318 494 : for(iIter = 0; iIter < nIterations && *pbError == FALSE; iIter++)
2319 : {
2320 428 : char* pszMDNewPrefix = NULL;
2321 428 : CPLXMLNode* psGroupNode = NULL;
2322 428 : if (pszMDSubPrefix != NULL)
2323 : {
2324 428 : if (bHasValidPercentD)
2325 : {
2326 428 : char* szTmp = (char*)CPLMalloc(
2327 428 : strlen(pszMDSubPrefix) + 10 + 1);
2328 428 : sprintf(szTmp, pszMDSubPrefix, iIter + 1);
2329 428 : pszMDNewPrefix = CPLStrdup(CPLSPrintf("%s%s",
2330 : pszMDPrefix, szTmp));
2331 428 : CPLFree(szTmp);
2332 : }
2333 : else
2334 0 : pszMDNewPrefix = CPLStrdup(CPLSPrintf("%s%s%04d_",
2335 : pszMDPrefix, pszMDSubPrefix, iIter + 1));
2336 : }
2337 : else
2338 0 : pszMDNewPrefix = CPLStrdup(CPLSPrintf("%s%04d_",
2339 : pszMDPrefix, iIter + 1));
2340 :
2341 428 : if (psRepeatedNode != NULL)
2342 : {
2343 : CPLXMLNode* psIndexNode;
2344 428 : psGroupNode = CPLCreateXMLNode(NULL, CXT_Element, "group");
2345 428 : CPLAssert(psLastChild->psNext == NULL);
2346 428 : psLastChild->psNext = psGroupNode;
2347 428 : psLastChild = psGroupNode;
2348 428 : psIndexNode = CPLCreateXMLNode(psGroupNode, CXT_Attribute, "index");
2349 428 : CPLCreateXMLNode(psIndexNode, CXT_Text, CPLSPrintf("%d", iIter));
2350 : }
2351 :
2352 428 : papszMD = NITFGenericMetadataReadTREInternal(papszMD,
2353 : pnMDSize,
2354 : pnMDAlloc,
2355 : psGroupNode,
2356 : pszTREName,
2357 : pachTRE,
2358 : nTRESize,
2359 : psIter,
2360 : pnTreOffset,
2361 : pszMDNewPrefix,
2362 : pbError);
2363 428 : CPLFree(pszMDNewPrefix);
2364 : }
2365 : }
2366 : }
2367 2004 : else if (psIter->eType == CXT_Element &&
2368 90 : psIter->pszValue != NULL &&
2369 90 : strcmp(psIter->pszValue, "if") == 0)
2370 : {
2371 88 : const char* pszCond = CPLGetXMLValue(psIter, "cond", NULL);
2372 88 : const char* pszEqual = NULL;
2373 94 : if (pszCond != NULL && strcmp(pszCond, "QSS!=U AND QOD!=Y") == 0)
2374 : {
2375 6 : char* pszQSSName = CPLStrdup(
2376 6 : CPLSPrintf("%s%s", pszMDPrefix, "QSS"));
2377 6 : char* pszQODName = CPLStrdup(
2378 6 : CPLSPrintf("%s%s", pszMDPrefix, "QOD"));
2379 6 : const char* pszQSSVal = NITFFindValFromEnd(papszMD, *pnMDSize, pszQSSName, NULL);
2380 6 : const char* pszQODVal = NITFFindValFromEnd(papszMD, *pnMDSize, pszQODName, NULL);
2381 6 : if (pszQSSVal == NULL)
2382 : {
2383 0 : CPLDebug("NITF", "Cannot find if cond variable %s", "QSS");
2384 : }
2385 6 : else if (pszQODVal == NULL)
2386 : {
2387 0 : CPLDebug("NITF", "Cannot find if cond variable %s", "QOD");
2388 : }
2389 6 : else if (strcmp(pszQSSVal, "U") != 0 && strcmp(pszQODVal, "Y") != 0)
2390 : {
2391 0 : papszMD = NITFGenericMetadataReadTREInternal(papszMD,
2392 : pnMDSize,
2393 : pnMDAlloc,
2394 : psOutXMLNode,
2395 : pszTREName,
2396 : pachTRE,
2397 : nTRESize,
2398 : psIter,
2399 : pnTreOffset,
2400 : pszMDPrefix,
2401 : pbError);
2402 : }
2403 6 : CPLFree(pszQSSName);
2404 6 : CPLFree(pszQODName);
2405 : }
2406 164 : else if (pszCond != NULL && (pszEqual = strchr(pszCond, '=')) != NULL)
2407 : {
2408 82 : char* pszCondVar = (char*)CPLMalloc(pszEqual - pszCond + 1);
2409 82 : const char* pszCondExpectedVal = pszEqual + 1;
2410 : char* pszMDItemName;
2411 : const char* pszCondVal;
2412 82 : int bTestEqual = TRUE;
2413 82 : memcpy(pszCondVar, pszCond, pszEqual - pszCond);
2414 82 : if (pszEqual - pszCond > 1 && pszCondVar[pszEqual - pszCond - 1] == '!')
2415 : {
2416 78 : bTestEqual = FALSE;
2417 78 : pszCondVar[pszEqual - pszCond - 1] = '\0';
2418 : }
2419 82 : pszCondVar[pszEqual - pszCond] = '\0';
2420 82 : pszMDItemName = CPLStrdup(
2421 : CPLSPrintf("%s%s", pszMDPrefix, pszCondVar));
2422 82 : pszCondVal = NITFFindValFromEnd(papszMD, *pnMDSize, pszMDItemName, NULL);
2423 82 : if (pszCondVal == NULL)
2424 : {
2425 0 : CPLDebug("NITF", "Cannot find if cond variable %s",
2426 : pszMDItemName);
2427 : }
2428 160 : else if ((bTestEqual && strcmp(pszCondVal, pszCondExpectedVal) == 0) ||
2429 78 : (!bTestEqual && strcmp(pszCondVal, pszCondExpectedVal) != 0))
2430 : {
2431 14 : papszMD = NITFGenericMetadataReadTREInternal(papszMD,
2432 : pnMDSize,
2433 : pnMDAlloc,
2434 : psOutXMLNode,
2435 : pszTREName,
2436 : pachTRE,
2437 : nTRESize,
2438 : psIter,
2439 : pnTreOffset,
2440 : pszMDPrefix,
2441 : pbError);
2442 : }
2443 82 : CPLFree(pszMDItemName);
2444 82 : CPLFree(pszCondVar);
2445 : }
2446 : else
2447 : {
2448 0 : CPLError( CE_Warning, CPLE_AppDefined,
2449 : "Invalid if construct in %s TRE in XML ressource : "
2450 : "missing or invalid 'cond' attribute",
2451 : pszTREName );
2452 0 : *pbError = TRUE;
2453 0 : break;
2454 : }
2455 : }
2456 1652 : else if (psIter->eType == CXT_Element &&
2457 2 : psIter->pszValue != NULL &&
2458 2 : strcmp(psIter->pszValue, "if_remaining_bytes") == 0)
2459 : {
2460 2 : if (*pnTreOffset < nTRESize)
2461 : {
2462 0 : papszMD = NITFGenericMetadataReadTREInternal(papszMD,
2463 : pnMDSize,
2464 : pnMDAlloc,
2465 : psOutXMLNode,
2466 : pszTREName,
2467 : pachTRE,
2468 : nTRESize,
2469 : psIter,
2470 : pnTreOffset,
2471 : pszMDPrefix,
2472 : pbError);
2473 : }
2474 : }
2475 : else
2476 : {
2477 : //CPLDebug("NITF", "Unknown element : %s", psIter->pszValue ? psIter->pszValue : "null");
2478 : }
2479 : }
2480 488 : return papszMD;
2481 : }
2482 :
2483 : /************************************************************************/
2484 : /* NITFGenericMetadataReadTRE() */
2485 : /************************************************************************/
2486 :
2487 : static
2488 16 : char **NITFGenericMetadataReadTRE(char **papszMD,
2489 : const char* pszTREName,
2490 : const char *pachTRE,
2491 : int nTRESize,
2492 : CPLXMLNode* psTreNode)
2493 : {
2494 16 : int nTreLength, nTreMinLength = -1, nTreMaxLength = -1;
2495 16 : int bError = FALSE;
2496 16 : int nTreOffset = 0;
2497 : const char* pszMDPrefix;
2498 : int nMDSize, nMDAlloc;
2499 :
2500 16 : nTreLength = atoi(CPLGetXMLValue(psTreNode, "length", "-1"));
2501 16 : nTreMinLength = atoi(CPLGetXMLValue(psTreNode, "minlength", "-1"));
2502 16 : nTreMaxLength = atoi(CPLGetXMLValue(psTreNode, "maxlength", "-1"));
2503 :
2504 16 : if( (nTreLength > 0 && nTRESize != nTreLength) ||
2505 : (nTreMinLength > 0 && nTRESize < nTreMinLength) )
2506 : {
2507 0 : CPLError( CE_Warning, CPLE_AppDefined,
2508 : "%s TRE wrong size, ignoring.", pszTREName );
2509 0 : return papszMD;
2510 : }
2511 :
2512 16 : pszMDPrefix = CPLGetXMLValue(psTreNode, "md_prefix", "");
2513 :
2514 16 : nMDSize = nMDAlloc = CSLCount(papszMD);
2515 :
2516 16 : papszMD = NITFGenericMetadataReadTREInternal(papszMD,
2517 : &nMDSize,
2518 : &nMDAlloc,
2519 : NULL,
2520 : pszTREName,
2521 : pachTRE,
2522 : nTRESize,
2523 : psTreNode,
2524 : &nTreOffset,
2525 : pszMDPrefix,
2526 : &bError);
2527 :
2528 16 : if (bError == FALSE && nTreLength > 0 && nTreOffset != nTreLength)
2529 : {
2530 0 : CPLError( CE_Warning, CPLE_AppDefined,
2531 : "Inconsistant declaration of %s TRE",
2532 : pszTREName );
2533 : }
2534 16 : if (nTreOffset < nTRESize)
2535 0 : CPLDebug("NITF", "%d remaining bytes at end of %s TRE",
2536 : nTRESize -nTreOffset, pszTREName);
2537 :
2538 16 : return papszMD;
2539 : }
2540 :
2541 :
2542 : /************************************************************************/
2543 : /* NITFLoadXMLSpec() */
2544 : /************************************************************************/
2545 :
2546 : #define NITF_SPEC_FILE "nitf_spec.xml"
2547 :
2548 1134 : static CPLXMLNode* NITFLoadXMLSpec(NITFFile* psFile)
2549 : {
2550 :
2551 1134 : if (psFile->psNITFSpecNode == NULL)
2552 : {
2553 1100 : const char* pszXMLDescFilename = CPLFindFile("gdal", NITF_SPEC_FILE);
2554 1100 : if (pszXMLDescFilename == NULL)
2555 : {
2556 0 : CPLDebug("NITF", "Cannot find XML file : %s", NITF_SPEC_FILE);
2557 0 : return NULL;
2558 : }
2559 1100 : psFile->psNITFSpecNode = CPLParseXMLFile(pszXMLDescFilename);
2560 1100 : if (psFile->psNITFSpecNode == NULL)
2561 : {
2562 0 : CPLDebug("NITF", "Invalid XML file : %s", pszXMLDescFilename);
2563 0 : return NULL;
2564 : }
2565 : }
2566 :
2567 1134 : return psFile->psNITFSpecNode;
2568 : }
2569 :
2570 : /************************************************************************/
2571 : /* NITFFindTREXMLDescFromName() */
2572 : /************************************************************************/
2573 :
2574 34 : static CPLXMLNode* NITFFindTREXMLDescFromName(NITFFile* psFile,
2575 : const char* pszTREName)
2576 : {
2577 : CPLXMLNode* psTreeNode;
2578 : CPLXMLNode* psTresNode;
2579 : CPLXMLNode* psIter;
2580 :
2581 34 : psTreeNode = NITFLoadXMLSpec(psFile);
2582 34 : if (psTreeNode == NULL)
2583 0 : return NULL;
2584 :
2585 34 : psTresNode = CPLGetXMLNode(psTreeNode, "=tres");
2586 34 : if (psTresNode == NULL)
2587 : {
2588 0 : CPLDebug("NITF", "Cannot find <tres> root element");
2589 0 : return NULL;
2590 : }
2591 :
2592 636 : for(psIter = psTresNode->psChild;psIter != NULL;psIter = psIter->psNext)
2593 : {
2594 1868 : if (psIter->eType == CXT_Element &&
2595 618 : psIter->pszValue != NULL &&
2596 618 : strcmp(psIter->pszValue, "tre") == 0)
2597 : {
2598 618 : const char* pszName = CPLGetXMLValue(psIter, "name", NULL);
2599 618 : if (pszName != NULL && strcmp(pszName, pszTREName) == 0)
2600 : {
2601 30 : return psIter;
2602 : }
2603 : }
2604 : }
2605 :
2606 4 : return NULL;
2607 : }
2608 :
2609 : /************************************************************************/
2610 : /* NITFCreateXMLTre() */
2611 : /************************************************************************/
2612 :
2613 34 : CPLXMLNode* NITFCreateXMLTre(NITFFile* psFile,
2614 : const char* pszTREName,
2615 : const char *pachTRE,
2616 : int nTRESize)
2617 : {
2618 34 : int nTreLength, nTreMinLength = -1, nTreMaxLength = -1;
2619 34 : int bError = FALSE;
2620 34 : int nTreOffset = 0;
2621 : CPLXMLNode* psTreNode;
2622 34 : CPLXMLNode* psOutXMLNode = NULL;
2623 34 : int nMDSize = 0, nMDAlloc = 0;
2624 :
2625 34 : psTreNode = NITFFindTREXMLDescFromName(psFile, pszTREName);
2626 34 : if (psTreNode == NULL)
2627 : {
2628 4 : if (!(EQUALN(pszTREName, "RPF", 3) || strcmp(pszTREName, "XXXXXX") == 0))
2629 : {
2630 4 : CPLDebug("NITF", "Cannot find definition of TRE %s in %s",
2631 : pszTREName, NITF_SPEC_FILE);
2632 : }
2633 4 : return NULL;
2634 : }
2635 :
2636 30 : nTreLength = atoi(CPLGetXMLValue(psTreNode, "length", "-1"));
2637 30 : nTreMinLength = atoi(CPLGetXMLValue(psTreNode, "minlength", "-1"));
2638 30 : nTreMaxLength = atoi(CPLGetXMLValue(psTreNode, "maxlength", "-1"));
2639 :
2640 30 : if( (nTreLength > 0 && nTRESize != nTreLength) ||
2641 : (nTreMinLength > 0 && nTRESize < nTreMinLength) )
2642 : {
2643 0 : CPLError( CE_Warning, CPLE_AppDefined,
2644 : "%s TRE wrong size, ignoring.", pszTREName );
2645 0 : return NULL;
2646 : }
2647 :
2648 30 : psOutXMLNode = CPLCreateXMLNode(NULL, CXT_Element, "tre");
2649 30 : CPLCreateXMLNode(CPLCreateXMLNode(psOutXMLNode, CXT_Attribute, "name"),
2650 : CXT_Text, pszTREName);
2651 :
2652 30 : CSLDestroy(NITFGenericMetadataReadTREInternal(NULL,
2653 : &nMDSize,
2654 : &nMDAlloc,
2655 : psOutXMLNode,
2656 : pszTREName,
2657 : pachTRE,
2658 : nTRESize,
2659 : psTreNode,
2660 : &nTreOffset,
2661 : "",
2662 : &bError));
2663 :
2664 30 : if (bError == FALSE && nTreLength > 0 && nTreOffset != nTreLength)
2665 : {
2666 0 : CPLError( CE_Warning, CPLE_AppDefined,
2667 : "Inconsistant declaration of %s TRE",
2668 : pszTREName );
2669 : }
2670 30 : if (nTreOffset < nTRESize)
2671 0 : CPLDebug("NITF", "%d remaining bytes at end of %s TRE",
2672 : nTRESize -nTreOffset, pszTREName);
2673 :
2674 30 : return psOutXMLNode;
2675 : }
2676 :
2677 : /************************************************************************/
2678 : /* NITFGenericMetadataRead() */
2679 : /* */
2680 : /* Add metadata from TREs of file and image objects in the papszMD list */
2681 : /* pszSpecificTRE can be NULL, in which case all TREs listed in */
2682 : /* data/nitf_resources.xml that have md_prefix defined will be looked */
2683 : /* for. If not NULL, only the specified one will be looked for. */
2684 : /************************************************************************/
2685 :
2686 1100 : char **NITFGenericMetadataRead( char **papszMD,
2687 : NITFFile* psFile,
2688 : NITFImage *psImage,
2689 : const char* pszSpecificTREName)
2690 : {
2691 1100 : CPLXMLNode* psTreeNode = NULL;
2692 1100 : CPLXMLNode* psTresNode = NULL;
2693 1100 : CPLXMLNode* psIter = NULL;
2694 :
2695 1100 : if (psFile == NULL && psImage == NULL)
2696 0 : return papszMD;
2697 :
2698 1100 : psTreeNode = NITFLoadXMLSpec(psFile ? psFile : psImage->psFile);
2699 1100 : if (psTreeNode == NULL)
2700 0 : return papszMD;
2701 :
2702 1100 : psTresNode = CPLGetXMLNode(psTreeNode, "=tres");
2703 1100 : if (psTresNode == NULL)
2704 : {
2705 0 : CPLDebug("NITF", "Cannot find <tres> root element");
2706 0 : return papszMD;
2707 : }
2708 :
2709 41800 : for(psIter = psTresNode->psChild;psIter!=NULL;psIter = psIter->psNext)
2710 : {
2711 119900 : if (psIter->eType == CXT_Element &&
2712 39600 : psIter->pszValue != NULL &&
2713 39600 : strcmp(psIter->pszValue, "tre") == 0)
2714 : {
2715 39600 : const char* pszName = CPLGetXMLValue(psIter, "name", NULL);
2716 39600 : const char* pszMDPrefix = CPLGetXMLValue(psIter, "md_prefix", NULL);
2717 39600 : if (pszName != NULL && ((pszSpecificTREName == NULL && pszMDPrefix != NULL) ||
2718 0 : (pszSpecificTREName != NULL && strcmp(pszName, pszSpecificTREName) == 0)))
2719 : {
2720 6600 : if (psFile != NULL)
2721 : {
2722 6600 : const char *pachTRE = NULL;
2723 6600 : int nTRESize = 0;
2724 :
2725 6600 : pachTRE = NITFFindTRE( psFile->pachTRE, psFile->nTREBytes,
2726 : pszName, &nTRESize);
2727 6600 : if( pachTRE != NULL )
2728 0 : papszMD = NITFGenericMetadataReadTRE(
2729 : papszMD, pszName, pachTRE, nTRESize, psIter);
2730 : }
2731 6600 : if (psImage != NULL)
2732 : {
2733 6600 : const char *pachTRE = NULL;
2734 6600 : int nTRESize = 0;
2735 :
2736 6600 : pachTRE = NITFFindTRE( psImage->pachTRE, psImage->nTREBytes,
2737 : pszName, &nTRESize);
2738 6600 : if( pachTRE != NULL )
2739 16 : papszMD = NITFGenericMetadataReadTRE(
2740 : papszMD, pszName, pachTRE, nTRESize, psIter);
2741 : }
2742 6600 : if (pszSpecificTREName)
2743 0 : break;
2744 : }
2745 : }
2746 : }
2747 :
2748 1100 : return papszMD;
2749 : }
|