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 589 : 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 589 : int bTriedStreamingFileHeader = FALSE;
70 :
71 : /* -------------------------------------------------------------------- */
72 : /* Open the file. */
73 : /* -------------------------------------------------------------------- */
74 589 : if( bUpdatable )
75 211 : fp = VSIFOpenL( pszFilename, "r+b" );
76 : else
77 378 : fp = VSIFOpenL( pszFilename, "rb" );
78 :
79 589 : 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 589 : VSIFReadL( szTemp, 1, 9, fp );
91 :
92 589 : 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 1178 : if( VSIFSeekL( fp, 280, SEEK_SET ) != 0
105 1178 : || VSIFReadL( achFSDWNG, 1, 6, fp ) != 6 )
106 : {
107 1 : CPLError( CE_Failure, CPLE_NotSupported,
108 : "Unable to read FSDWNG field from NITF file. File is either corrupt\n"
109 : "or empty." );
110 1 : VSIFCloseL(fp);
111 1 : return NULL;
112 : }
113 :
114 : /* -------------------------------------------------------------------- */
115 : /* Get header length. */
116 : /* -------------------------------------------------------------------- */
117 597 : if( EQUALN(szTemp,"NITF01.",7) || EQUALN(achFSDWNG,"999998",6) )
118 9 : nHeaderLenOffset = 394;
119 : else
120 579 : nHeaderLenOffset = 354;
121 :
122 1176 : if( VSIFSeekL( fp, nHeaderLenOffset, SEEK_SET ) != 0
123 1176 : || VSIFReadL( szTemp, 1, 6, fp ) != 6 )
124 : {
125 2 : CPLError( CE_Failure, CPLE_NotSupported,
126 : "Unable to read header length from NITF file. File is either corrupt\n"
127 : "or empty." );
128 2 : VSIFCloseL(fp);
129 2 : return NULL;
130 : }
131 :
132 586 : szTemp[6] = '\0';
133 586 : nHeaderLen = atoi(szTemp);
134 :
135 586 : VSIFSeekL( fp, nHeaderLen, SEEK_SET );
136 586 : currentPos = VSIFTellL( fp ) ;
137 586 : if( nHeaderLen < nHeaderLenOffset || nHeaderLen > currentPos )
138 : {
139 1 : CPLError( CE_Failure, CPLE_NotSupported,
140 : "NITF Header Length (%d) seems to be corrupt.",
141 : nHeaderLen );
142 1 : VSIFCloseL(fp);
143 1 : return NULL;
144 : }
145 :
146 : /* -------------------------------------------------------------------- */
147 : /* Read the whole file header. */
148 : /* -------------------------------------------------------------------- */
149 585 : pachHeader = (char *) VSIMalloc(nHeaderLen);
150 585 : 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 585 : VSIFSeekL( fp, 0, SEEK_SET );
158 585 : if ((int)VSIFReadL( pachHeader, 1, nHeaderLen, fp ) != nHeaderLen)
159 : {
160 1 : CPLError( CE_Failure, CPLE_OutOfMemory,
161 : "Cannot read %d bytes for NITF header", (nHeaderLen));
162 1 : VSIFCloseL(fp);
163 1 : CPLFree(pachHeader);
164 1 : return NULL;
165 : }
166 :
167 : /* -------------------------------------------------------------------- */
168 : /* Create and initialize info structure about file. */
169 : /* -------------------------------------------------------------------- */
170 584 : psFile = (NITFFile *) CPLCalloc(sizeof(NITFFile),1);
171 584 : psFile->fp = fp;
172 584 : psFile->pachHeader = pachHeader;
173 :
174 : retry_read_header:
175 : /* -------------------------------------------------------------------- */
176 : /* Get version. */
177 : /* -------------------------------------------------------------------- */
178 585 : 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 1188 : if( EQUAL(psFile->szVersion,"NITF02.10")
189 58 : || EQUAL(psFile->szVersion,"NSIF01.00") )
190 : {
191 : char szWork[100];
192 :
193 545 : GetMD( psFile, pachHeader, 0, 9, FHDR );
194 545 : GetMD( psFile, pachHeader, 9, 2, CLEVEL );
195 545 : GetMD( psFile, pachHeader, 11, 4, STYPE );
196 545 : GetMD( psFile, pachHeader, 15, 10, OSTAID );
197 545 : GetMD( psFile, pachHeader, 25, 14, FDT );
198 545 : GetMD( psFile, pachHeader, 39, 80, FTITLE );
199 545 : GetMD( psFile, pachHeader, 119, 1, FSCLAS );
200 545 : GetMD( psFile, pachHeader, 120, 2, FSCLSY );
201 545 : GetMD( psFile, pachHeader, 122, 11, FSCODE );
202 545 : GetMD( psFile, pachHeader, 133, 2, FSCTLH );
203 545 : GetMD( psFile, pachHeader, 135, 20, FSREL );
204 545 : GetMD( psFile, pachHeader, 155, 2, FSDCTP );
205 545 : GetMD( psFile, pachHeader, 157, 8, FSDCDT );
206 545 : GetMD( psFile, pachHeader, 165, 4, FSDCXM );
207 545 : GetMD( psFile, pachHeader, 169, 1, FSDG );
208 545 : GetMD( psFile, pachHeader, 170, 8, FSDGDT );
209 545 : GetMD( psFile, pachHeader, 178, 43, FSCLTX );
210 545 : GetMD( psFile, pachHeader, 221, 1, FSCATP );
211 545 : GetMD( psFile, pachHeader, 222, 40, FSCAUT );
212 545 : GetMD( psFile, pachHeader, 262, 1, FSCRSN );
213 545 : GetMD( psFile, pachHeader, 263, 8, FSSRDT );
214 545 : GetMD( psFile, pachHeader, 271, 15, FSCTLN );
215 545 : GetMD( psFile, pachHeader, 286, 5, FSCOP );
216 545 : GetMD( psFile, pachHeader, 291, 5, FSCPYS );
217 545 : GetMD( psFile, pachHeader, 296, 1, ENCRYP );
218 1635 : sprintf( szWork, "%3d,%3d,%3d",
219 545 : ((GByte *)pachHeader)[297],
220 545 : ((GByte *)pachHeader)[298],
221 545 : ((GByte *)pachHeader)[299] );
222 545 : GetMD( psFile, szWork, 0, 11, FBKGC );
223 545 : GetMD( psFile, pachHeader, 300, 24, ONAME );
224 545 : GetMD( psFile, pachHeader, 324, 18, OPHONE );
225 545 : NITFGetField(szTemp, pachHeader, 342, 12);
226 : }
227 40 : else if( EQUAL(psFile->szVersion,"NITF02.00") )
228 : {
229 34 : int nCOff = 0;
230 :
231 34 : GetMD( psFile, pachHeader, 0, 9, FHDR );
232 34 : GetMD( psFile, pachHeader, 9, 2, CLEVEL );
233 34 : GetMD( psFile, pachHeader, 11, 4, STYPE );
234 34 : GetMD( psFile, pachHeader, 15, 10, OSTAID );
235 34 : GetMD( psFile, pachHeader, 25, 14, FDT );
236 34 : GetMD( psFile, pachHeader, 39, 80, FTITLE );
237 34 : GetMD( psFile, pachHeader, 119, 1, FSCLAS );
238 34 : GetMD( psFile, pachHeader, 120, 40, FSCODE );
239 34 : GetMD( psFile, pachHeader, 160, 40, FSCTLH );
240 34 : GetMD( psFile, pachHeader, 200, 40, FSREL );
241 34 : GetMD( psFile, pachHeader, 240, 20, FSCAUT );
242 34 : GetMD( psFile, pachHeader, 260, 20, FSCTLN );
243 34 : GetMD( psFile, pachHeader, 280, 6, FSDWNG );
244 34 : if( EQUALN(pachHeader+280,"999998",6) )
245 : {
246 2 : GetMD( psFile, pachHeader, 286, 40, FSDEVT );
247 2 : nCOff += 40;
248 : }
249 34 : GetMD( psFile, pachHeader, 286+nCOff, 5, FSCOP );
250 34 : GetMD( psFile, pachHeader, 291+nCOff, 5, FSCPYS );
251 34 : GetMD( psFile, pachHeader, 296+nCOff, 1, ENCRYP );
252 34 : GetMD( psFile, pachHeader, 297+nCOff, 27, ONAME );
253 34 : GetMD( psFile, pachHeader, 324+nCOff, 18, OPHONE );
254 34 : NITFGetField(szTemp, pachHeader, 342+nCOff, 12);
255 : }
256 :
257 1169 : if (!bTriedStreamingFileHeader &&
258 584 : EQUAL(szTemp, "999999999999"))
259 : {
260 : GUIntBig nFileSize;
261 : GByte abyDELIM2_L2[12];
262 : GByte abyL1_DELIM1[11];
263 :
264 1 : bTriedStreamingFileHeader = TRUE;
265 1 : CPLDebug("NITF", "Total file unknown. Trying to get a STREAMING_FILE_HEADER");
266 :
267 1 : VSIFSeekL( fp, 0, SEEK_END );
268 1 : nFileSize = VSIFTellL(fp);
269 :
270 1 : VSIFSeekL( fp, nFileSize - 11, SEEK_SET );
271 1 : abyDELIM2_L2[11] = '\0';
272 :
273 5 : if (VSIFReadL( abyDELIM2_L2, 1, 11, fp ) == 11 &&
274 2 : abyDELIM2_L2[0] == 0x0E && abyDELIM2_L2[1] == 0xCA &&
275 2 : abyDELIM2_L2[2] == 0x14 && abyDELIM2_L2[3] == 0xBF)
276 : {
277 1 : int SFHL2 = atoi((const char*)(abyDELIM2_L2 + 4));
278 1 : if (SFHL2 > 0 && nFileSize > 11 + SFHL2 + 11 )
279 : {
280 1 : VSIFSeekL( fp, nFileSize - 11 - SFHL2 - 11 , SEEK_SET );
281 :
282 6 : if ( VSIFReadL( abyL1_DELIM1, 1, 11, fp ) == 11 &&
283 2 : abyL1_DELIM1[7] == 0x0A && abyL1_DELIM1[8] == 0x6E &&
284 2 : abyL1_DELIM1[9] == 0x1D && abyL1_DELIM1[10] == 0x97 &&
285 1 : memcmp(abyL1_DELIM1, abyDELIM2_L2 + 4, 7) == 0 )
286 : {
287 1 : if (SFHL2 == nHeaderLen)
288 : {
289 1 : CSLDestroy(psFile->papszMetadata);
290 1 : psFile->papszMetadata = NULL;
291 :
292 1 : 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 1 : goto retry_read_header;
301 : }
302 : }
303 : }
304 : }
305 : }
306 :
307 : /* -------------------------------------------------------------------- */
308 : /* Collect segment info for the types we care about. */
309 : /* -------------------------------------------------------------------- */
310 584 : nNextData = nHeaderLen;
311 :
312 584 : nOffset = nHeaderLenOffset + 6;
313 :
314 584 : nOffset = NITFCollectSegmentInfo( psFile, nHeaderLen, nOffset,"IM",6, 10, &nNextData );
315 :
316 584 : if (nOffset != -1)
317 580 : nOffset = NITFCollectSegmentInfo( psFile, nHeaderLen, nOffset, "GR", 4, 6, &nNextData);
318 :
319 : /* LA Called NUMX in NITF 2.1 */
320 584 : if (nOffset != -1)
321 580 : nOffset = NITFCollectSegmentInfo( psFile, nHeaderLen, nOffset, "LA", 4, 3, &nNextData);
322 :
323 584 : if (nOffset != -1)
324 580 : nOffset = NITFCollectSegmentInfo( psFile, nHeaderLen, nOffset, "TX", 4, 5, &nNextData);
325 :
326 584 : if (nOffset != -1)
327 580 : nOffset = NITFCollectSegmentInfo( psFile, nHeaderLen, nOffset, "DE", 4, 9, &nNextData);
328 :
329 584 : if (nOffset != -1)
330 580 : nOffset = NITFCollectSegmentInfo( psFile, nHeaderLen, nOffset, "RE", 4, 7, &nNextData);
331 : else
332 : {
333 4 : NITFClose(psFile);
334 4 : return NULL;
335 : }
336 :
337 : /* -------------------------------------------------------------------- */
338 : /* Is there User Define Header Data? (TREs) */
339 : /* -------------------------------------------------------------------- */
340 580 : if (nHeaderLen < nOffset + 5)
341 : {
342 1 : CPLError(CE_Failure, CPLE_AppDefined, "NITF header too small");
343 1 : NITFClose(psFile);
344 1 : return NULL;
345 : }
346 :
347 579 : psFile->nTREBytes =
348 579 : atoi(NITFGetField( szTemp, pachHeader, nOffset, 5 ));
349 579 : if (psFile->nTREBytes < 0)
350 : {
351 1 : CPLError(CE_Failure, CPLE_AppDefined,
352 : "Invalid TRE size : %d", psFile->nTREBytes);
353 1 : NITFClose(psFile);
354 1 : return NULL;
355 : }
356 578 : nOffset += 5;
357 :
358 578 : if( psFile->nTREBytes == 3 )
359 : {
360 0 : nOffset += 3; /* UDHOFL */
361 0 : psFile->nTREBytes = 0;
362 : }
363 578 : else if( psFile->nTREBytes > 3 )
364 : {
365 28 : nOffset += 3; /* UDHOFL */
366 28 : psFile->nTREBytes -= 3;
367 :
368 28 : 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 28 : psFile->pachTRE = (char *) VSIMalloc(psFile->nTREBytes);
376 28 : 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 28 : memcpy( psFile->pachTRE, pachHeader + nOffset,
384 28 : psFile->nTREBytes );
385 : }
386 :
387 : /* -------------------------------------------------------------------- */
388 : /* Is there Extended Header Data? (More TREs) */
389 : /* -------------------------------------------------------------------- */
390 578 : if( nHeaderLen > nOffset + 8 )
391 : {
392 : int nXHDL =
393 43 : atoi(NITFGetField( szTemp, pachHeader, nOffset, 5 ));
394 43 : if (nXHDL < 0)
395 : {
396 1 : CPLError(CE_Failure, CPLE_AppDefined,
397 : "Invalid XHDL value : %d", nXHDL);
398 1 : NITFClose(psFile);
399 1 : return NULL;
400 : }
401 :
402 42 : nOffset += 5; /* XHDL */
403 :
404 42 : if( nXHDL > 3 )
405 : {
406 : char* pachNewTRE;
407 :
408 14 : nOffset += 3; /* XHDLOFL */
409 14 : nXHDL -= 3;
410 :
411 14 : if (nHeaderLen < nOffset + nXHDL)
412 : {
413 1 : CPLError(CE_Failure, CPLE_AppDefined, "NITF header too small");
414 1 : NITFClose(psFile);
415 1 : return NULL;
416 : }
417 :
418 26 : pachNewTRE = (char *)
419 13 : VSIRealloc( psFile->pachTRE,
420 13 : psFile->nTREBytes + nXHDL );
421 13 : 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 13 : psFile->pachTRE = pachNewTRE;
429 13 : memcpy( psFile->pachTRE, pachHeader + nOffset, nXHDL );
430 13 : psFile->nTREBytes += nXHDL;
431 : }
432 : }
433 :
434 576 : return psFile;
435 : }
436 :
437 : /************************************************************************/
438 : /* NITFClose() */
439 : /************************************************************************/
440 :
441 584 : void NITFClose( NITFFile *psFile )
442 :
443 : {
444 : int iSegment;
445 :
446 6915 : for( iSegment = 0; iSegment < psFile->nSegmentCount; iSegment++ )
447 : {
448 6331 : NITFSegmentInfo *psSegInfo = psFile->pasSegmentInfo + iSegment;
449 :
450 6331 : if( psSegInfo->hAccess == NULL )
451 1755 : continue;
452 :
453 4576 : if( EQUAL(psSegInfo->szSegmentType,"IM"))
454 4576 : 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 584 : CPLFree( psFile->pasSegmentInfo );
464 584 : if( psFile->fp != NULL )
465 584 : VSIFCloseL( psFile->fp );
466 584 : CPLFree( psFile->pachHeader );
467 584 : CSLDestroy( psFile->papszMetadata );
468 584 : CPLFree( psFile->pachTRE );
469 :
470 584 : if (psFile->psNITFSpecNode)
471 546 : CPLDestroyXMLNode(psFile->psNITFSpecNode);
472 :
473 584 : CPLFree( psFile );
474 584 : }
475 :
476 285562 : static void NITFGotoOffset(VSILFILE* fp, GUIntBig nLocation)
477 : {
478 285562 : GUIntBig nCurrentLocation = VSIFTellL(fp);
479 285562 : if (nLocation > nCurrentLocation)
480 : {
481 : GUIntBig nFileSize;
482 : int iFill;
483 173771 : char cSpace = ' ';
484 :
485 173771 : VSIFSeekL(fp, 0, SEEK_END);
486 173771 : nFileSize = VSIFTellL(fp);
487 173771 : if (nLocation > nFileSize)
488 : {
489 1318453 : for(iFill = 0; iFill < nLocation - nFileSize; iFill++)
490 1146920 : VSIFWriteL(&cSpace, 1, 1, fp);
491 : }
492 : else
493 2238 : VSIFSeekL(fp, nLocation, SEEK_SET);
494 : }
495 111791 : else if (nLocation < nCurrentLocation)
496 : {
497 2633 : VSIFSeekL(fp, nLocation, SEEK_SET);
498 : }
499 :
500 285562 : }
501 :
502 : /************************************************************************/
503 : /* NITFCreate() */
504 : /* */
505 : /* Create a new uncompressed NITF file. */
506 : /************************************************************************/
507 :
508 210 : 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 210 : GUIntBig nCur = 0;
516 210 : int nOffset = 0, iBand, nIHSize, nNPPBH, nNPPBV;
517 : GIntBig nImageSize;
518 : int nNBPR, nNBPC;
519 : const char *pszIREP;
520 210 : const char *pszIC = CSLFetchNameValue(papszOptions,"IC");
521 : int nCLevel;
522 : const char *pszNUMT;
523 210 : int nHL, nNUMT = 0;
524 : int nUDIDLOffset;
525 : const char *pszVersion;
526 210 : int iIM, nIM = 1;
527 : const char *pszNUMI;
528 210 : int iGS, nGS = 0; // number of graphic segment
529 : const char *pszNUMS; // graphic segment option string
530 :
531 210 : if (nBands <= 0 || nBands > 99999)
532 : {
533 2 : CPLError(CE_Failure, CPLE_NotSupported,
534 : "Invalid band number : %d", nBands);
535 2 : return FALSE;
536 : }
537 :
538 208 : if( pszIC == NULL )
539 198 : pszIC = "NC";
540 :
541 : /* -------------------------------------------------------------------- */
542 : /* Fetch some parameter overrides. */
543 : /* -------------------------------------------------------------------- */
544 208 : pszIREP = CSLFetchNameValue( papszOptions, "IREP" );
545 208 : if( pszIREP == NULL )
546 161 : pszIREP = "MONO";
547 :
548 208 : pszNUMT = CSLFetchNameValue( papszOptions, "NUMT" );
549 208 : if( pszNUMT != NULL )
550 : {
551 5 : nNUMT = atoi(pszNUMT);
552 5 : if (nNUMT < 0 || nNUMT > 999)
553 : {
554 1 : CPLError( CE_Failure, CPLE_AppDefined,
555 : "Invalid NUMT value : %s", pszNUMT);
556 1 : return FALSE;
557 : }
558 : }
559 :
560 207 : pszNUMI = CSLFetchNameValue( papszOptions, "NUMI" );
561 207 : if (pszNUMI != NULL)
562 : {
563 4 : nIM = atoi(pszNUMI);
564 4 : if (nIM < 1 || nIM > 999)
565 : {
566 1 : CPLError( CE_Failure, CPLE_AppDefined,
567 : "Invalid NUMI value : %s", pszNUMI);
568 1 : return FALSE;
569 : }
570 3 : if (nIM != 1 && !EQUAL(pszIC, "NC"))
571 : {
572 1 : CPLError( CE_Failure, CPLE_AppDefined,
573 : "Unable to create file with multiple images and compression at the same time");
574 1 : return FALSE;
575 : }
576 : }
577 :
578 : // Reads and validates graphics segment number option
579 205 : pszNUMS = CSLFetchNameValue(papszOptions, "NUMS");
580 205 : if (pszNUMS != NULL)
581 : {
582 9 : nGS = atoi(pszNUMS);
583 9 : if (nGS < 0 || nGS > 999)
584 : {
585 1 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid NUMS value : %s",
586 : pszNUMS);
587 1 : return FALSE;
588 : }
589 : }
590 :
591 :
592 :
593 : /* -------------------------------------------------------------------- */
594 : /* Compute raw image size, blocking factors and so forth. */
595 : /* -------------------------------------------------------------------- */
596 204 : nNPPBH = nPixels;
597 204 : nNPPBV = nLines;
598 :
599 204 : if( CSLFetchNameValue( papszOptions, "BLOCKSIZE" ) != NULL )
600 4 : nNPPBH = nNPPBV = atoi(CSLFetchNameValue( papszOptions, "BLOCKSIZE" ));
601 :
602 204 : if( CSLFetchNameValue( papszOptions, "BLOCKXSIZE" ) != NULL )
603 6 : nNPPBH = atoi(CSLFetchNameValue( papszOptions, "BLOCKXSIZE" ));
604 :
605 204 : if( CSLFetchNameValue( papszOptions, "BLOCKYSIZE" ) != NULL )
606 4 : nNPPBV = atoi(CSLFetchNameValue( papszOptions, "BLOCKYSIZE" ));
607 :
608 204 : if( CSLFetchNameValue( papszOptions, "NPPBH" ) != NULL )
609 0 : nNPPBH = atoi(CSLFetchNameValue( papszOptions, "NPPBH" ));
610 :
611 204 : if( CSLFetchNameValue( papszOptions, "NPPBV" ) != NULL )
612 0 : nNPPBV = atoi(CSLFetchNameValue( papszOptions, "NPPBV" ));
613 :
614 :
615 208 : 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 4 : nNBPR = 1;
621 4 : nNBPC = 1;
622 4 : nNPPBH = 0;
623 4 : nNPPBV = 0;
624 :
625 4 : nImageSize =
626 8 : ((nBitsPerSample)/8)
627 4 : * ((GIntBig) nPixels *nLines)
628 8 : * nBands;
629 : }
630 200 : 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 201 : else if (EQUAL(pszIC, "NC") &&
653 : nLines > 8192 && nNPPBV == nLines)
654 : {
655 : /* See MIL-STD-2500-C, paragraph 5.4.2.2-d */
656 1 : nNBPC = 1;
657 1 : nNPPBV = 0;
658 1 : nNBPR = (nPixels + nNPPBH - 1) / nNPPBH;
659 :
660 1 : 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 1 : nImageSize =
670 2 : ((nBitsPerSample)/8)
671 1 : * ((GIntBig) nLines * (nNBPR * nNPPBH))
672 2 : * nBands;
673 : }
674 : else
675 : {
676 199 : if( nNPPBH <= 0 || nNPPBV <= 0 ||
677 : nNPPBH > 9999 || nNPPBV > 9999 )
678 0 : nNPPBH = nNPPBV = 256;
679 :
680 199 : nNBPR = (nPixels + nNPPBH - 1) / nNPPBH;
681 199 : nNBPC = (nLines + nNPPBV - 1) / nNPPBV;
682 199 : if ( nNBPR > 9999 || nNBPC > 9999 )
683 : {
684 1 : CPLError( CE_Failure, CPLE_AppDefined,
685 : "Unable to create file %s,\n"
686 : "Too many blocks : %d x %d",
687 : pszFilename, nNBPR, nNBPC);
688 1 : return FALSE;
689 : }
690 :
691 198 : nImageSize =
692 396 : ((nBitsPerSample)/8)
693 198 : * ((GIntBig) nNBPR * nNBPC)
694 396 : * nNPPBH * nNPPBV * nBands;
695 : }
696 :
697 203 : if (EQUAL(pszIC, "NC"))
698 : {
699 195 : if ((double)nImageSize >= 1e10 - 1)
700 : {
701 1 : CPLError( CE_Failure, CPLE_AppDefined,
702 : "Unable to create file %s,\n"
703 : "Too big image size : " CPL_FRMT_GUIB,
704 : pszFilename, nImageSize );
705 1 : return FALSE;
706 : }
707 194 : if ((double)(nImageSize * nIM) >= 1e12 - 1)
708 : {
709 1 : 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 1 : return FALSE;
714 : }
715 : }
716 :
717 : /* -------------------------------------------------------------------- */
718 : /* Open new file. */
719 : /* -------------------------------------------------------------------- */
720 201 : fp = VSIFOpenL( pszFilename, "wb+" );
721 201 : if( fp == NULL )
722 : {
723 3 : CPLError( CE_Failure, CPLE_OpenFailed,
724 : "Unable to create file %s,\n"
725 : "check path and permissions.",
726 : pszFilename );
727 3 : 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 198 : pszVersion = CSLFetchNameValue( papszOptions, "FHDR" );
737 198 : if( pszVersion == NULL )
738 192 : pszVersion = "NITF02.10";
739 8 : else if( !EQUAL(pszVersion,"NITF02.10")
740 2 : && !EQUAL(pszVersion,"NSIF01.00") )
741 : {
742 1 : CPLError( CE_Warning, CPLE_AppDefined,
743 : "FHDR=%s not supported, switching to NITF02.10.",
744 : pszVersion );
745 1 : 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 198 : VSIFSeekL(fp, 0, SEEK_SET);
772 :
773 198 : PLACE ( 0, FDHR_FVER, pszVersion );
774 198 : OVR( 2, 9, CLEVEL, "03" ); /* Patched at the end */
775 198 : PLACE ( 11, STYPE ,"BF01" );
776 198 : OVR(10, 15, OSTAID ,"GDAL" );
777 198 : OVR(14, 25, FDT ,"20021216151629" );
778 198 : OVR(80, 39, FTITLE ,"" );
779 198 : OVR( 1,119, FSCLAS ,"U" );
780 198 : OVR( 2,120, FSCLSY ,"" );
781 198 : OVR(11,122, FSCODE ,"" );
782 198 : OVR( 2,133, FSCTLH ,"" );
783 198 : OVR(20,135, FSREL ,"" );
784 198 : OVR( 2,155, FSDCTP ,"" );
785 198 : OVR( 8,157, FSDCDT ,"" );
786 198 : OVR( 4,165, FSDCXM ,"" );
787 198 : OVR( 1,169, FSDG ,"" );
788 198 : OVR( 8,170, FSDGDT ,"" );
789 198 : OVR(43,178, FSCLTX ,"" );
790 198 : OVR( 1,221, FSCATP ,"" );
791 198 : OVR(40,222, FSCAUT ,"" );
792 198 : OVR( 1,262, FSCRSN ,"" );
793 198 : OVR( 8,263, FSSRDT ,"" );
794 198 : OVR(15,271, FSCTLN ,"" );
795 198 : OVR( 5,286, FSCOP ,"00000" );
796 198 : OVR( 5,291, FSCPYS ,"00000" );
797 198 : PLACE (296, ENCRYP ,"0" );
798 198 : WRITE_BYTE(297, 0x00); /* FBKGC */
799 198 : WRITE_BYTE(298, 0x00);
800 198 : WRITE_BYTE(299, 0x00);
801 198 : OVR(24,300, ONAME ,"" );
802 198 : OVR(18,324, OPHONE ,"" );
803 198 : PLACE (342, FL ,"????????????" );
804 198 : PLACE (354, HL ,"??????" );
805 198 : PLACE (360, NUMI ,CPLSPrintf("%03d", nIM) );
806 :
807 198 : nHL = 363;
808 1394 : for(iIM=0;iIM<nIM;iIM++)
809 : {
810 1196 : PLACE (nHL, LISHi ,"??????" );
811 1196 : PLACE (nHL + 6, LIi ,CPLSPrintf("%010" CPL_FRMT_GB_WITHOUT_PREFIX "d", nImageSize) );
812 1196 : 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 198 : PLACE (nHL, NUMS ,CPLSPrintf("%03d",nGS) );
822 198 : nHL += 3; // Move three characters
823 202 : for (iGS = 0; iGS < nGS; iGS++)
824 : {
825 4 : PLACE (nHL, LSSHi ,CPLSPrintf("0000") );
826 4 : PLACE (nHL + 4, LSi ,CPLSPrintf("000000") );
827 4 : nHL += 4 + 6;
828 : }
829 :
830 198 : PLACE (nHL, NUMX ,"000" );
831 198 : PLACE (nHL + 3, NUMT ,CPLSPrintf("%03d",nNUMT) );
832 :
833 198 : PLACE (nHL + 6, LTSHnLTn ,"" );
834 :
835 198 : nHL += 6 + (4+5) * nNUMT;
836 :
837 198 : PLACE (nHL, NUMDES ,"000" );
838 198 : nHL += 3;
839 198 : PLACE (nHL, NUMRES ,"000" );
840 198 : nHL += 3;
841 198 : PLACE (nHL, UDHDL ,"00000" );
842 198 : nHL += 5;
843 198 : PLACE (nHL, XHDL ,"00000" );
844 198 : nHL += 5;
845 :
846 198 : if( CSLFetchNameValue(papszOptions,"FILE_TRE") != NULL )
847 : {
848 8 : NITFWriteTREsFromOptions(
849 : fp,
850 4 : nHL - 10,
851 : nHL,
852 : &nHL,
853 : papszOptions, "FILE_TRE=" );
854 : }
855 :
856 198 : 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 198 : PLACE (354, HL ,CPLSPrintf("%06d",nHL) );
866 :
867 198 : nCur = nHL;
868 :
869 : /* -------------------------------------------------------------------- */
870 : /* Prepare the image header. */
871 : /* -------------------------------------------------------------------- */
872 1394 : for(iIM=0;iIM<nIM;iIM++)
873 : {
874 1196 : char** papszIREPBANDTokens = NULL;
875 1196 : char** papszISUBCATTokens = NULL;
876 :
877 1196 : 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 1196 : 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 1196 : VSIFSeekL(fp, nCur, SEEK_SET);
899 :
900 1196 : PLACE (nCur+ 0, IM , "IM" );
901 1196 : OVR(10,nCur+ 2, IID1 , "Missing" );
902 1196 : OVR(14,nCur+ 12, IDATIM , "20021216151629" );
903 1196 : OVR(17,nCur+ 26, TGTID , "" );
904 1196 : OVR(80,nCur+ 43, IID2 , "" );
905 1196 : OVR( 1,nCur+123, ISCLAS , "U" );
906 1196 : OVR( 2,nCur+124, ISCLSY , "" );
907 1196 : OVR(11,nCur+126, ISCODE , "" );
908 1196 : OVR( 2,nCur+137, ISCTLH , "" );
909 1196 : OVR(20,nCur+139, ISREL , "" );
910 1196 : OVR( 2,nCur+159, ISDCTP , "" );
911 1196 : OVR( 8,nCur+161, ISDCDT , "" );
912 1196 : OVR( 4,nCur+169, ISDCXM , "" );
913 1196 : OVR( 1,nCur+173, ISDG , "" );
914 1196 : OVR( 8,nCur+174, ISDGDT , "" );
915 1196 : OVR(43,nCur+182, ISCLTX , "" );
916 1196 : OVR( 1,nCur+225, ISCATP , "" );
917 1196 : OVR(40,nCur+226, ISCAUT , "" );
918 1196 : OVR( 1,nCur+266, ISCRSN , "" );
919 1196 : OVR( 8,nCur+267, ISSRDT , "" );
920 1196 : OVR(15,nCur+275, ISCTLN , "" );
921 1196 : PLACE (nCur+290, ENCRYP , "0" );
922 1196 : OVR(42,nCur+291, ISORCE , "Unknown" );
923 1196 : PLACE (nCur+333, NROWS , CPLSPrintf("%08d", nLines) );
924 1196 : PLACE (nCur+341, NCOLS , CPLSPrintf("%08d", nPixels) );
925 1196 : PLACE (nCur+349, PVTYPE , pszPVType );
926 1196 : PLACE (nCur+352, IREP , pszIREP );
927 1196 : OVR( 8,nCur+360, ICAT , "VIS" );
928 1196 : OVR( 2,nCur+368, ABPP , CPLSPrintf("%02d",nBitsPerSample) );
929 1196 : OVR( 1,nCur+370, PJUST , "R" );
930 1196 : OVR( 1,nCur+371, ICORDS , " " );
931 :
932 1196 : nOffset = 372;
933 :
934 : {
935 : const char *pszParmValue;
936 1196 : pszParmValue = CSLFetchNameValue( papszOptions, "ICORDS" );
937 1196 : if( pszParmValue == NULL )
938 1147 : pszParmValue = " ";
939 1196 : if( *pszParmValue != ' ' )
940 : {
941 49 : OVR(60,nCur+nOffset, IGEOLO, "" );
942 49 : nOffset += 60;
943 : }
944 : }
945 :
946 : {
947 1196 : const char* pszICOM = CSLFetchNameValue( papszOptions, "ICOM");
948 1196 : if (pszICOM != NULL)
949 : {
950 1 : int nLenICOM = strlen(pszICOM);
951 1 : int nICOM = (79 + nLenICOM) / 80;
952 1 : if (nICOM > 9)
953 : {
954 0 : CPLError(CE_Warning, CPLE_NotSupported, "ICOM will be truncated");
955 0 : nICOM = 9;
956 : }
957 1 : PLACE (nCur+nOffset, NICOM , CPLSPrintf("%01d",nICOM) );
958 1 : VSIFWriteL(pszICOM, 1, MIN(nICOM * 80, nLenICOM), fp);
959 1 : nOffset += nICOM * 80;
960 : }
961 : else
962 : {
963 1195 : PLACE (nCur+nOffset, NICOM , "0" );
964 : }
965 : }
966 :
967 1196 : OVR( 2,nCur+nOffset+1, IC , "NC" );
968 :
969 1196 : if( pszIC[0] != 'N' )
970 : {
971 8 : OVR( 4,nCur+nOffset+3, COMRAT , " " );
972 8 : nOffset += 4;
973 : }
974 :
975 1196 : if (nBands <= 9)
976 : {
977 1193 : PLACE (nCur+nOffset+3, NBANDS , CPLSPrintf("%d",nBands) );
978 : }
979 : else
980 : {
981 3 : PLACE (nCur+nOffset+3, NBANDS , "0" );
982 3 : PLACE (nCur+nOffset+4, XBANDS , CPLSPrintf("%05d",nBands) );
983 3 : nOffset += 5;
984 : }
985 :
986 1196 : nOffset += 4;
987 :
988 : /* -------------------------------------------------------------------- */
989 : /* Per band info */
990 : /* -------------------------------------------------------------------- */
991 72483 : for( iBand = 0; iBand < nBands; iBand++ )
992 : {
993 71287 : const char *pszIREPBAND = "M";
994 :
995 71287 : 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 71287 : else if( EQUAL(pszIREP,"RGB/LUT") )
1007 5 : pszIREPBAND = "LU";
1008 71282 : else if( EQUAL(pszIREP,"RGB") )
1009 : {
1010 13 : if( iBand == 0 )
1011 4 : pszIREPBAND = "R";
1012 9 : else if( iBand == 1 )
1013 4 : pszIREPBAND = "G";
1014 5 : else if( iBand == 2 )
1015 4 : pszIREPBAND = "B";
1016 : }
1017 71269 : else if( EQUALN(pszIREP,"YCbCr",5) )
1018 : {
1019 9 : if( iBand == 0 )
1020 3 : pszIREPBAND = "Y";
1021 6 : else if( iBand == 1 )
1022 3 : pszIREPBAND = "Cb";
1023 3 : else if( iBand == 2 )
1024 3 : pszIREPBAND = "Cr";
1025 : }
1026 :
1027 71287 : PLACE(nCur+nOffset+ 0, IREPBANDn, pszIREPBAND );
1028 :
1029 71287 : 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 71287 : PLACE(nCur+nOffset+ 8, IFCn , "N" );
1044 : // PLACE(nCur+nOffset+ 9, IMFLTn, "" );
1045 :
1046 71287 : if( !EQUAL(pszIREP,"RGB/LUT") )
1047 : {
1048 71282 : PLACE(nCur+nOffset+12, NLUTSn, "0" );
1049 71282 : nOffset += 13;
1050 : }
1051 : else
1052 : {
1053 5 : int iC, nCount=256;
1054 :
1055 5 : if( CSLFetchNameValue(papszOptions,"LUT_SIZE") != NULL )
1056 5 : nCount = atoi(CSLFetchNameValue(papszOptions,"LUT_SIZE"));
1057 :
1058 5 : if (!(nCount >= 0 && nCount <= 99999))
1059 : {
1060 1 : CPLError(CE_Warning, CPLE_AppDefined,
1061 : "Invalid LUT value : %d. Defaulting to 256", nCount);
1062 1 : nCount = 256;
1063 : }
1064 5 : PLACE(nCur+nOffset+12, NLUTSn, "3" );
1065 5 : PLACE(nCur+nOffset+13, NELUTn, CPLSPrintf("%05d",nCount) );
1066 :
1067 1030 : for( iC = 0; iC < nCount; iC++ )
1068 : {
1069 1025 : WRITE_BYTE(nCur+nOffset+18+iC+ 0, (char) iC);
1070 1025 : WRITE_BYTE(nCur+nOffset+18+iC+nCount*1, (char) iC);
1071 1025 : WRITE_BYTE(nCur+nOffset+18+iC+nCount*2, (char) iC);
1072 : }
1073 5 : nOffset += 18 + nCount*3;
1074 : }
1075 : }
1076 :
1077 1196 : CSLDestroy(papszIREPBANDTokens);
1078 1196 : CSLDestroy(papszISUBCATTokens);
1079 :
1080 : /* -------------------------------------------------------------------- */
1081 : /* Remainder of image header info. */
1082 : /* -------------------------------------------------------------------- */
1083 1196 : PLACE(nCur+nOffset+ 0, ISYNC , "0" );
1084 :
1085 : /* RGB JPEG compressed NITF requires IMODE=P (see #3345) */
1086 1199 : if (nBands >= 3 && (EQUAL(pszIC, "C3") || EQUAL(pszIC, "M3")))
1087 : {
1088 3 : PLACE(nCur+nOffset+ 1, IMODE , "P" );
1089 : }
1090 : else
1091 : {
1092 1193 : PLACE(nCur+nOffset+ 1, IMODE , "B" );
1093 : }
1094 1196 : PLACE(nCur+nOffset+ 2, NBPR , CPLSPrintf("%04d",nNBPR) );
1095 1196 : PLACE(nCur+nOffset+ 6, NBPC , CPLSPrintf("%04d",nNBPC) );
1096 1196 : PLACE(nCur+nOffset+ 10, NPPBH , CPLSPrintf("%04d",nNPPBH) );
1097 1196 : PLACE(nCur+nOffset+ 14, NPPBV , CPLSPrintf("%04d",nNPPBV) );
1098 1196 : PLACE(nCur+nOffset+ 18, NBPP , CPLSPrintf("%02d",nBitsPerSample) );
1099 1196 : PLACE(nCur+nOffset+ 20, IDLVL , "001" );
1100 1196 : PLACE(nCur+nOffset+ 23, IALVL , "000" );
1101 1196 : PLACE(nCur+nOffset+ 26, ILOC , "0000000000" );
1102 1196 : PLACE(nCur+nOffset+ 36, IMAG , "1.0 " );
1103 1196 : PLACE(nCur+nOffset+ 40, UDIDL , "00000" );
1104 1196 : PLACE(nCur+nOffset+ 45, IXSHDL, "00000" );
1105 :
1106 1196 : nUDIDLOffset = nOffset + 40;
1107 1196 : nOffset += 50;
1108 :
1109 : /* -------------------------------------------------------------------- */
1110 : /* Add BLOCKA TRE if requested. */
1111 : /* -------------------------------------------------------------------- */
1112 1196 : if( CSLFetchNameValue(papszOptions,"BLOCKA_BLOCK_COUNT") != NULL )
1113 : {
1114 3 : NITFWriteBLOCKA( fp,
1115 : nCur + (GUIntBig)nUDIDLOffset,
1116 : nCur + (GUIntBig)nOffset,
1117 : &nOffset,
1118 : papszOptions );
1119 : }
1120 :
1121 1196 : if( CSLFetchNameValue(papszOptions,"TRE") != NULL )
1122 : {
1123 16 : 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 1196 : nIHSize = nOffset;
1135 :
1136 1196 : 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 1196 : PLACE( 363 + iIM * 16, LISH1, CPLSPrintf("%06d",nIHSize) );
1145 :
1146 1196 : 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 198 : nCLevel = 3;
1155 198 : if (nBands > 9 || nIM > 20 || nPixels > 2048 || nLines > 2048 ||
1156 : nNPPBH > 2048 || nNPPBV > 2048 || nCur > 52428799 )
1157 : {
1158 10 : nCLevel = 5;
1159 : }
1160 198 : if (nPixels > 8192 || nLines > 8192 ||
1161 : nNPPBH > 8192 || nNPPBV > 8192 || nCur > 1073741833)
1162 : {
1163 4 : nCLevel = 6;
1164 : }
1165 198 : if (nBands > 256 || nPixels > 65536 || nLines > 65536 ||
1166 : nCur > 2147483647)
1167 : {
1168 2 : nCLevel = 7;
1169 : }
1170 198 : 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 198 : 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 198 : 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 198 : if( EQUAL(pszIC,"NC") )
1193 : {
1194 190 : char cNul = 0;
1195 190 : VSIFSeekL( fp, nCur-1, SEEK_SET );
1196 190 : VSIFWriteL( &cNul, 1, 1, fp );
1197 : }
1198 :
1199 198 : VSIFCloseL( fp );
1200 :
1201 198 : return TRUE;
1202 : }
1203 :
1204 : /************************************************************************/
1205 : /* NITFWriteTRE() */
1206 : /************************************************************************/
1207 :
1208 23 : 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 23 : VSIFSeekL(fp, nOffsetUDIDL + 5, SEEK_SET);
1222 23 : VSIFReadL(szTemp, 1, 5, fp);
1223 23 : szTemp[5] = 0;
1224 23 : nOldOffset = atoi(szTemp);
1225 :
1226 23 : if( nOldOffset == 0 )
1227 : {
1228 20 : nOldOffset = 3;
1229 20 : PLACE(nOffsetUDIDL+10, IXSOFL, "000" );
1230 20 : *pnOffset += 3;
1231 : }
1232 :
1233 23 : if (nOldOffset + 11 + nTREDataSize > 99999 || nTREDataSize > 99999)
1234 : {
1235 2 : CPLError(CE_Failure, CPLE_AppDefined, "Too big TRE to be written");
1236 2 : return FALSE;
1237 : }
1238 :
1239 21 : sprintf( szTemp, "%05d", nOldOffset + 11 + nTREDataSize );
1240 21 : PLACE( nOffsetUDIDL + 5, IXSHDL, szTemp );
1241 :
1242 : /* -------------------------------------------------------------------- */
1243 : /* Create TRE prefix. */
1244 : /* -------------------------------------------------------------------- */
1245 21 : sprintf( szTemp, "%-6s%05d",
1246 : pszTREName, nTREDataSize );
1247 21 : VSIFSeekL(fp, nOffsetTREInHeader + nOldOffset, SEEK_SET);
1248 21 : VSIFWriteL(szTemp, 11, 1, fp);
1249 21 : VSIFWriteL(pabyTREData, nTREDataSize, 1, fp);
1250 :
1251 : /* -------------------------------------------------------------------- */
1252 : /* Increment values. */
1253 : /* -------------------------------------------------------------------- */
1254 21 : *pnOffset += nTREDataSize + 11;
1255 :
1256 21 : return TRUE;
1257 : }
1258 :
1259 : /************************************************************************/
1260 : /* NITFWriteTREsFromOptions() */
1261 : /************************************************************************/
1262 :
1263 20 : 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 20 : CSLFetchNameValue(papszOptions,"BLOCKA_BLOCK_COUNT") != NULL;
1272 : int iOption;
1273 20 : int nTREPrefixLen = strlen(pszTREPrefix);
1274 :
1275 20 : if( papszOptions == NULL )
1276 0 : return TRUE;
1277 :
1278 68 : 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 51 : if( !EQUALN(papszOptions[iOption], pszTREPrefix, nTREPrefixLen) )
1287 28 : continue;
1288 :
1289 23 : if( EQUALN(papszOptions[iOption]+nTREPrefixLen,"BLOCKA=",7)
1290 : && bIgnoreBLOCKA )
1291 1 : continue;
1292 :
1293 : /* We do no longer use CPLParseNameValue() as it removes leading spaces */
1294 : /* from the value (see #3088) */
1295 22 : pszSpace = strchr(papszOptions[iOption]+nTREPrefixLen, '=');
1296 22 : if (pszSpace == NULL)
1297 : {
1298 1 : CPLError(CE_Failure, CPLE_AppDefined,
1299 1 : "Could not parse creation options %s", papszOptions[iOption]+nTREPrefixLen);
1300 1 : return FALSE;
1301 : }
1302 :
1303 21 : pszTREName = CPLStrdup(papszOptions[iOption]+nTREPrefixLen);
1304 21 : pszTREName[MIN(6, pszSpace - (papszOptions[iOption]+nTREPrefixLen))] = '\0';
1305 21 : pszEscapedContents = pszSpace + 1;
1306 :
1307 21 : pszUnescapedContents =
1308 21 : CPLUnescapeString( pszEscapedContents, &nContentLength,
1309 : CPLES_BackslashQuotable );
1310 :
1311 21 : if( !NITFWriteTRE( fp,
1312 : nOffsetUDIDL, nOffsetTRE,
1313 : pnOffset,
1314 : pszTREName, pszUnescapedContents,
1315 : nContentLength ) )
1316 : {
1317 2 : CPLFree( pszTREName );
1318 2 : CPLFree( pszUnescapedContents );
1319 2 : return FALSE;
1320 : }
1321 :
1322 19 : CPLFree( pszTREName );
1323 19 : CPLFree( pszUnescapedContents );
1324 :
1325 : }
1326 :
1327 17 : return TRUE;
1328 : }
1329 :
1330 : /************************************************************************/
1331 : /* NITFWriteBLOCKA() */
1332 : /************************************************************************/
1333 :
1334 3 : 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 3 : atoi(CSLFetchNameValue( papszOptions, "BLOCKA_BLOCK_COUNT" ));
1354 : int iBlock;
1355 :
1356 : /* ==================================================================== */
1357 : /* Loop over all the blocks we have metadata for. */
1358 : /* ==================================================================== */
1359 5 : for( iBlock = 1; iBlock <= nBlockCount; iBlock++ )
1360 : {
1361 : char szBLOCKA[123];
1362 : int iField;
1363 :
1364 : /* -------------------------------------------------------------------- */
1365 : /* Write all fields. */
1366 : /* -------------------------------------------------------------------- */
1367 32 : for( iField = 0; apszFields[iField*3] != NULL; iField++ )
1368 : {
1369 : char szFullFieldName[64];
1370 30 : int iStart = atoi(apszFields[iField*3+1]);
1371 30 : int iSize = atoi(apszFields[iField*3+2]);
1372 : const char *pszValue;
1373 :
1374 30 : sprintf( szFullFieldName, "BLOCKA_%s_%02d",
1375 30 : apszFields[iField*3 + 0], iBlock );
1376 :
1377 30 : pszValue = CSLFetchNameValue( papszOptions, szFullFieldName );
1378 30 : if( pszValue == NULL )
1379 14 : pszValue = "";
1380 :
1381 30 : if (strlen(pszValue) > (size_t)iSize)
1382 : {
1383 1 : 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 1 : return FALSE;
1387 : }
1388 :
1389 : /* Right align value and left pad with spaces */
1390 29 : memset( szBLOCKA + iStart, ' ', iSize );
1391 29 : memcpy( szBLOCKA + iStart + MAX((size_t)0,iSize-strlen(pszValue)),
1392 : pszValue, strlen(pszValue) );
1393 : }
1394 :
1395 : // required field - semantics unknown.
1396 2 : memcpy( szBLOCKA + 118, "010.0", 5);
1397 :
1398 2 : if( !NITFWriteTRE( fp,
1399 : nOffsetUDIDL, nOffsetTRE,
1400 : pnOffset,
1401 : "BLOCKA", szBLOCKA, 123 ) )
1402 0 : return FALSE;
1403 : }
1404 :
1405 2 : 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 3484 : 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 3484 : if ( nFileHeaderLen < nOffset + 3 )
1429 : {
1430 1 : CPLError(CE_Failure, CPLE_AppDefined, "Not enough bytes to read segment count");
1431 1 : return -1;
1432 : }
1433 :
1434 3483 : NITFGetField( szTemp, psFile->pachHeader, nOffset, 3 );
1435 3483 : nCount = atoi(szTemp);
1436 :
1437 3483 : if( nCount <= 0 )
1438 2846 : return nOffset + 3;
1439 :
1440 637 : nSegDefSize = nCount * (nHeaderLenSize + nDataLenSize);
1441 637 : if ( nFileHeaderLen < nOffset + 3 + nSegDefSize)
1442 : {
1443 1 : CPLError(CE_Failure, CPLE_AppDefined, "Not enough bytes to read segment info");
1444 1 : return -1;
1445 : }
1446 :
1447 636 : if( psFile->pasSegmentInfo == NULL )
1448 582 : psFile->pasSegmentInfo = (NITFSegmentInfo *)
1449 : CPLMalloc( sizeof(NITFSegmentInfo) * nCount );
1450 : else
1451 108 : psFile->pasSegmentInfo = (NITFSegmentInfo *)
1452 54 : CPLRealloc( psFile->pasSegmentInfo,
1453 : sizeof(NITFSegmentInfo)
1454 54 : * (psFile->nSegmentCount+nCount) );
1455 :
1456 : /* -------------------------------------------------------------------- */
1457 : /* Collect detailed about segment. */
1458 : /* -------------------------------------------------------------------- */
1459 6967 : for( iSegment = 0; iSegment < nCount; iSegment++ )
1460 : {
1461 6333 : NITFSegmentInfo *psInfo = psFile->pasSegmentInfo+psFile->nSegmentCount;
1462 :
1463 6333 : psInfo->nDLVL = -1;
1464 6333 : psInfo->nALVL = -1;
1465 6333 : psInfo->nLOC_R = -1;
1466 6333 : psInfo->nLOC_C = -1;
1467 6333 : psInfo->nCCS_R = -1;
1468 6333 : psInfo->nCCS_C = -1;
1469 :
1470 6333 : psInfo->hAccess = NULL;
1471 6333 : strcpy( psInfo->szSegmentType, szType );
1472 :
1473 6333 : psInfo->nSegmentHeaderSize =
1474 6333 : atoi(NITFGetField(szTemp, psFile->pachHeader,
1475 6333 : nOffset + 3 + iSegment * (nHeaderLenSize+nDataLenSize),
1476 : nHeaderLenSize));
1477 6333 : if (strchr(szTemp, '-') != NULL) /* Avoid negative values being mapped to huge unsigned values */
1478 : {
1479 1 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid segment header size : %s", szTemp);
1480 1 : return -1;
1481 : }
1482 :
1483 6332 : 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 6332 : psInfo->nSegmentSize =
1490 6332 : CPLScanUIntBig(NITFGetField(szTemp,psFile->pachHeader,
1491 6332 : nOffset + 3 + iSegment * (nHeaderLenSize+nDataLenSize)
1492 6332 : + nHeaderLenSize,
1493 : nDataLenSize), nDataLenSize);
1494 6332 : if (strchr(szTemp, '-') != NULL) /* Avoid negative values being mapped to huge unsigned values */
1495 : {
1496 1 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid segment size : %s", szTemp);
1497 1 : return -1;
1498 : }
1499 :
1500 6331 : psInfo->nSegmentHeaderStart = *pnNextData;
1501 6331 : psInfo->nSegmentStart = *pnNextData + psInfo->nSegmentHeaderSize;
1502 :
1503 6331 : *pnNextData += (psInfo->nSegmentHeaderSize+psInfo->nSegmentSize);
1504 6331 : psFile->nSegmentCount++;
1505 : }
1506 :
1507 634 : 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 911251 : char *NITFGetField( char *pszTarget, const char *pszSource,
1518 : int nStart, int nLength )
1519 :
1520 : {
1521 911251 : memcpy( pszTarget, pszSource + nStart, nLength );
1522 911251 : pszTarget[nLength] = '\0';
1523 :
1524 911251 : return pszTarget;
1525 : }
1526 :
1527 : /************************************************************************/
1528 : /* NITFFindTRE() */
1529 : /************************************************************************/
1530 :
1531 25182 : const char *NITFFindTRE( const char *pszTREData, int nTREBytes,
1532 : const char *pszTag, int *pnFoundTRESize )
1533 :
1534 : {
1535 : char szTemp[100];
1536 :
1537 197595 : while( nTREBytes >= 11 )
1538 : {
1539 147373 : int nThisTRESize = atoi(NITFGetField(szTemp, pszTREData, 6, 5 ));
1540 147373 : if (nThisTRESize < 0)
1541 : {
1542 32 : NITFGetField(szTemp, pszTREData, 0, 6 );
1543 32 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid size (%d) for TRE %s",
1544 : nThisTRESize, szTemp);
1545 32 : return NULL;
1546 : }
1547 147341 : if (nTREBytes - 11 < nThisTRESize)
1548 : {
1549 32 : NITFGetField(szTemp, pszTREData, 0, 6 );
1550 32 : 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 32 : CPLError(CE_Failure, CPLE_AppDefined,
1559 : "Cannot read %s TRE. Not enough bytes : remaining %d, expected %d",
1560 : szTemp, nTREBytes - 11, nThisTRESize);
1561 32 : return NULL;
1562 : }
1563 : }
1564 :
1565 147309 : if( EQUALN(pszTREData,pszTag,6) )
1566 : {
1567 78 : if( pnFoundTRESize != NULL )
1568 78 : *pnFoundTRESize = nThisTRESize;
1569 :
1570 78 : return pszTREData + 11;
1571 : }
1572 :
1573 147231 : nTREBytes -= (nThisTRESize + 11);
1574 147231 : pszTREData += (nThisTRESize + 11);
1575 : }
1576 :
1577 25040 : return NULL;
1578 : }
1579 :
1580 : /************************************************************************/
1581 : /* NITFFindTREByIndex() */
1582 : /************************************************************************/
1583 :
1584 560 : 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 1217 : while( nTREBytes >= 11 )
1592 : {
1593 115 : int nThisTRESize = atoi(NITFGetField(szTemp, pszTREData, 6, 5 ));
1594 115 : if (nThisTRESize < 0)
1595 : {
1596 2 : NITFGetField(szTemp, pszTREData, 0, 6 );
1597 2 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid size (%d) for TRE %s",
1598 : nThisTRESize, szTemp);
1599 2 : return NULL;
1600 : }
1601 113 : if (nTREBytes - 11 < nThisTRESize)
1602 : {
1603 2 : NITFGetField(szTemp, pszTREData, 0, 6 );
1604 2 : 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 2 : CPLError(CE_Failure, CPLE_AppDefined,
1613 : "Cannot read %s TRE. Not enough bytes : remaining %d, expected %d",
1614 : szTemp, nTREBytes - 11, nThisTRESize);
1615 2 : return NULL;
1616 : }
1617 : }
1618 :
1619 111 : if( EQUALN(pszTREData,pszTag,6) )
1620 : {
1621 28 : if ( nTreIndex <= 0)
1622 : {
1623 14 : if( pnFoundTRESize != NULL )
1624 14 : *pnFoundTRESize = nThisTRESize;
1625 :
1626 14 : return pszTREData + 11;
1627 : }
1628 :
1629 : /* Found a prevoius one - skip it ... */
1630 14 : nTreIndex--;
1631 : }
1632 :
1633 97 : nTREBytes -= (nThisTRESize + 11);
1634 97 : pszTREData += (nThisTRESize + 11);
1635 : }
1636 :
1637 542 : return NULL;
1638 : }
1639 :
1640 : /************************************************************************/
1641 : /* NITFExtractMetadata() */
1642 : /************************************************************************/
1643 :
1644 140409 : 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 140409 : if (nLength >= sizeof(szWork) - 1)
1652 0 : pszWork = (char*)CPLMalloc(nLength + 1);
1653 : else
1654 140409 : pszWork = szWork;
1655 :
1656 : /* trim white space */
1657 1877273 : while( nLength > 0 && pachHeader[nStart + nLength - 1] == ' ' )
1658 1596455 : nLength--;
1659 :
1660 140409 : memcpy( pszWork, pachHeader + nStart, nLength );
1661 140409 : pszWork[nLength] = '\0';
1662 :
1663 140409 : *ppapszMetadata = CSLSetNameValue( *ppapszMetadata, pszName, pszWork );
1664 :
1665 140409 : if (szWork != pszWork)
1666 0 : CPLFree(pszWork);
1667 140409 : }
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 557 : const NITFSeries* NITFGetSeriesInfo(const char* pszFilename)
1801 : {
1802 : int i;
1803 557 : char seriesCode[3] = {0,0,0};
1804 557 : if (pszFilename == NULL) return NULL;
1805 3523 : for (i=strlen(pszFilename)-1;i>=0;i--)
1806 : {
1807 3473 : if (pszFilename[i] == '.')
1808 : {
1809 512 : if (i < (int)strlen(pszFilename) - 3)
1810 : {
1811 507 : seriesCode[0] = pszFilename[i+1];
1812 507 : seriesCode[1] = pszFilename[i+2];
1813 38233 : for(i=0;i<sizeof(nitfSeries) / sizeof(nitfSeries[0]); i++)
1814 : {
1815 37763 : if (EQUAL(seriesCode, nitfSeries[i].code))
1816 : {
1817 37 : return &nitfSeries[i];
1818 : }
1819 : }
1820 470 : return NULL;
1821 : }
1822 : }
1823 : }
1824 50 : return NULL;
1825 : }
1826 :
1827 : /************************************************************************/
1828 : /* NITFCollectAttachments() */
1829 : /* */
1830 : /* Collect attachment, display level and location info into the */
1831 : /* segmentinfo structures. */
1832 : /************************************************************************/
1833 :
1834 410 : int NITFCollectAttachments( NITFFile *psFile )
1835 :
1836 : {
1837 : int iSegment;
1838 :
1839 : /* ==================================================================== */
1840 : /* Loop over all segments. */
1841 : /* ==================================================================== */
1842 5551 : for( iSegment = 0; iSegment < psFile->nSegmentCount; iSegment++ )
1843 : {
1844 5160 : NITFSegmentInfo *psSegInfo = psFile->pasSegmentInfo + iSegment;
1845 :
1846 : /* -------------------------------------------------------------------- */
1847 : /* For image segments, we use the normal image access stuff. */
1848 : /* -------------------------------------------------------------------- */
1849 5160 : if( EQUAL(psSegInfo->szSegmentType,"IM") )
1850 : {
1851 4437 : NITFImage *psImage = NITFImageAccess( psFile, iSegment );
1852 4437 : if (psImage == NULL)
1853 19 : return FALSE;
1854 :
1855 4418 : psSegInfo->nDLVL = psImage->nIDLVL;
1856 4418 : psSegInfo->nALVL = psImage->nIALVL;
1857 4418 : psSegInfo->nLOC_R = psImage->nILOCRow;
1858 4418 : psSegInfo->nLOC_C = psImage->nILOCColumn;
1859 : }
1860 : /* -------------------------------------------------------------------- */
1861 : /* For graphic file we need to process the header. */
1862 : /* -------------------------------------------------------------------- */
1863 1446 : else if( EQUAL(psSegInfo->szSegmentType,"SY")
1864 723 : || 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 722 : if( VSIFSeekL( psFile->fp, psSegInfo->nSegmentHeaderStart,
1874 : SEEK_SET ) != 0
1875 361 : || VSIFReadL( achSubheader, 1, sizeof(achSubheader),
1876 361 : psFile->fp ) < 258 )
1877 : {
1878 1 : CPLError( CE_Warning, CPLE_FileIO,
1879 : "Failed to read graphic subheader at " CPL_FRMT_GUIB ".",
1880 : psSegInfo->nSegmentHeaderStart );
1881 1 : continue;
1882 : }
1883 :
1884 : // NITF 2.0. (also works for NITF 2.1)
1885 360 : nSTYPEOffset = 200;
1886 360 : if( EQUALN(achSubheader+193,"999998",6) )
1887 318 : nSTYPEOffset += 40;
1888 :
1889 : /* -------------------------------------------------------------------- */
1890 : /* Report some standard info. */
1891 : /* -------------------------------------------------------------------- */
1892 360 : psSegInfo->nDLVL = atoi(NITFGetField(szTemp,achSubheader,
1893 : nSTYPEOffset + 14, 3));
1894 360 : psSegInfo->nALVL = atoi(NITFGetField(szTemp,achSubheader,
1895 : nSTYPEOffset + 17, 3));
1896 360 : psSegInfo->nLOC_R = atoi(NITFGetField(szTemp,achSubheader,
1897 : nSTYPEOffset + 20, 5));
1898 360 : psSegInfo->nLOC_C = atoi(NITFGetField(szTemp,achSubheader,
1899 : nSTYPEOffset + 25, 5));
1900 : }
1901 : }
1902 :
1903 391 : return TRUE;
1904 : }
1905 :
1906 : /************************************************************************/
1907 : /* NITFReconcileAttachments() */
1908 : /* */
1909 : /* Generate the CCS location information for all the segments */
1910 : /* if possible. */
1911 : /************************************************************************/
1912 :
1913 418 : int NITFReconcileAttachments( NITFFile *psFile )
1914 :
1915 : {
1916 : int iSegment;
1917 418 : int bSuccess = TRUE;
1918 418 : int bMadeProgress = FALSE;
1919 :
1920 5690 : for( iSegment = 0; iSegment < psFile->nSegmentCount; iSegment++ )
1921 : {
1922 5272 : NITFSegmentInfo *psSegInfo = psFile->pasSegmentInfo + iSegment;
1923 : int iOther;
1924 :
1925 : // already processed?
1926 5272 : if( psSegInfo->nCCS_R != -1 )
1927 48 : continue;
1928 :
1929 : // unattached segments are straight forward.
1930 5224 : if( psSegInfo->nALVL < 1 )
1931 : {
1932 5059 : psSegInfo->nCCS_R = psSegInfo->nLOC_R;
1933 5059 : psSegInfo->nCCS_C = psSegInfo->nLOC_C;
1934 5059 : if( psSegInfo->nCCS_R != -1 )
1935 4637 : bMadeProgress = TRUE;
1936 5059 : continue;
1937 : }
1938 :
1939 : // Loc for segment to which we are attached.
1940 612 : for( iOther = 0; iOther < psFile->nSegmentCount; iOther++ )
1941 : {
1942 588 : NITFSegmentInfo *psOtherSegInfo = psFile->pasSegmentInfo + iOther;
1943 :
1944 588 : if( psSegInfo->nALVL == psOtherSegInfo->nDLVL )
1945 : {
1946 141 : if( psOtherSegInfo->nCCS_R != -1 )
1947 : {
1948 133 : psSegInfo->nCCS_R = psOtherSegInfo->nLOC_R + psSegInfo->nLOC_R;
1949 133 : psSegInfo->nCCS_C = psOtherSegInfo->nLOC_C + psSegInfo->nLOC_C;
1950 133 : if ( psSegInfo->nCCS_R != -1 )
1951 133 : bMadeProgress = TRUE;
1952 : }
1953 : else
1954 : {
1955 8 : bSuccess = FALSE;
1956 : }
1957 141 : break;
1958 : }
1959 : }
1960 :
1961 165 : if( iOther == psFile->nSegmentCount )
1962 24 : 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 418 : if( bSuccess || !bMadeProgress )
1971 410 : return bSuccess;
1972 : else
1973 8 : return NITFReconcileAttachments( psFile );
1974 : }
1975 :
1976 : /************************************************************************/
1977 : /* NITFFindValFromEnd() */
1978 : /************************************************************************/
1979 :
1980 91 : static const char* NITFFindValFromEnd(char** papszMD,
1981 : int nMDSize,
1982 : const char* pszVar,
1983 : const char* pszDefault)
1984 : {
1985 91 : int nVarLen = strlen(pszVar);
1986 91 : int nIter = nMDSize-1;
1987 495 : for(;nIter >= 0;nIter--)
1988 : {
1989 587 : if (strncmp(papszMD[nIter], pszVar, nVarLen) == 0 &&
1990 92 : papszMD[nIter][nVarLen] == '=')
1991 91 : return papszMD[nIter] + nVarLen + 1;
1992 : }
1993 0 : return NULL;
1994 : }
1995 :
1996 : /************************************************************************/
1997 : /* NITFGenericMetadataReadTREInternal() */
1998 : /************************************************************************/
1999 :
2000 244 : 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 4206 : for(psIter = psTreNode->psChild;
2014 1859 : psIter != NULL && *pbError == FALSE;
2015 1859 : psIter = psIter->psNext)
2016 : {
2017 4879 : if (psIter->eType == CXT_Element &&
2018 1036 : psIter->pszValue != NULL &&
2019 1036 : strcmp(psIter->pszValue, "field") == 0)
2020 : {
2021 948 : const char* pszName = CPLGetXMLValue(psIter, "name", NULL);
2022 948 : const char* pszLongName = CPLGetXMLValue(psIter, "longname", NULL);
2023 948 : const char* pszLength = CPLGetXMLValue(psIter, "length", NULL);
2024 948 : int nLength = -1;
2025 948 : if (pszLength != NULL)
2026 948 : 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 1814 : if (pszName != NULL && nLength > 0)
2049 : {
2050 : char* pszMDItemName;
2051 866 : char** papszTmp = NULL;
2052 :
2053 866 : 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 866 : pszMDItemName = CPLStrdup(
2064 : CPLSPrintf("%s%s", pszMDPrefix, pszName));
2065 :
2066 866 : NITFExtractMetadata( &papszTmp, pachTRE, *pnTreOffset,
2067 : nLength, pszMDItemName );
2068 866 : if (*pnMDSize + 1 >= *pnMDAlloc)
2069 : {
2070 37 : *pnMDAlloc = (*pnMDAlloc * 4 / 3) + 32;
2071 37 : papszMD = (char**)CPLRealloc(papszMD, *pnMDAlloc * sizeof(char**));
2072 : }
2073 866 : papszMD[*pnMDSize] = papszTmp[0];
2074 866 : papszMD[(*pnMDSize) + 1] = NULL;
2075 866 : (*pnMDSize) ++;
2076 866 : papszTmp[0] = NULL;
2077 866 : CPLFree(papszTmp);
2078 :
2079 866 : if (psOutXMLNode != NULL)
2080 : {
2081 766 : const char* pszVal = strchr(papszMD[(*pnMDSize) - 1], '=') + 1;
2082 : CPLXMLNode* psFieldNode;
2083 : CPLXMLNode* psNameNode;
2084 : CPLXMLNode* psValueNode;
2085 :
2086 766 : CPLAssert(pszVal != NULL);
2087 766 : psFieldNode =
2088 766 : CPLCreateXMLNode(psOutXMLNode, CXT_Element, "field");
2089 766 : psNameNode =
2090 766 : CPLCreateXMLNode(psFieldNode, CXT_Attribute, "name");
2091 766 : psValueNode =
2092 766 : CPLCreateXMLNode(psFieldNode, CXT_Attribute, "value");
2093 766 : CPLCreateXMLNode(psNameNode, CXT_Text,
2094 766 : (pszName[0] || pszLongName == NULL) ? pszName : pszLongName);
2095 766 : CPLCreateXMLNode(psValueNode, CXT_Text, pszVal);
2096 : }
2097 :
2098 866 : CPLFree(pszMDItemName);
2099 :
2100 866 : *pnTreOffset += nLength;
2101 : }
2102 82 : else if (nLength > 0)
2103 : {
2104 82 : *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 1130 : else if (psIter->eType == CXT_Element &&
2116 88 : psIter->pszValue != NULL &&
2117 88 : strcmp(psIter->pszValue, "loop") == 0)
2118 : {
2119 43 : const char* pszCounter = CPLGetXMLValue(psIter, "counter", NULL);
2120 43 : const char* pszIterations = CPLGetXMLValue(psIter, "iterations", NULL);
2121 43 : const char* pszFormula = CPLGetXMLValue(psIter, "formula", NULL);
2122 43 : const char* pszMDSubPrefix = CPLGetXMLValue(psIter, "md_prefix", NULL);
2123 43 : int nIterations = -1;
2124 :
2125 43 : if (pszCounter != NULL)
2126 : {
2127 40 : char* pszMDItemName = CPLStrdup(
2128 40 : CPLSPrintf("%s%s", pszMDPrefix, pszCounter));
2129 40 : nIterations = atoi(NITFFindValFromEnd(papszMD, *pnMDSize, pszMDItemName, "-1"));
2130 40 : CPLFree(pszMDItemName);
2131 40 : 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 3 : else if (pszIterations != NULL)
2142 : {
2143 0 : nIterations = atoi(pszIterations);
2144 : }
2145 7 : else if (pszFormula != NULL &&
2146 3 : strcmp(pszFormula, "(NPART+1)*(NPART)/2") == 0)
2147 : {
2148 1 : char* pszMDItemName = CPLStrdup(
2149 1 : CPLSPrintf("%s%s", pszMDPrefix, "NPART"));
2150 1 : int NPART = atoi(NITFFindValFromEnd(papszMD, *pnMDSize, pszMDItemName, "-1"));
2151 1 : CPLFree(pszMDItemName);
2152 1 : 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 1 : nIterations = NPART * (NPART + 1) / 2;
2162 : }
2163 5 : else if (pszFormula != NULL &&
2164 2 : strcmp(pszFormula, "(NUMOPG+1)*(NUMOPG)/2") == 0)
2165 : {
2166 1 : char* pszMDItemName = CPLStrdup(
2167 1 : CPLSPrintf("%s%s", pszMDPrefix, "NUMOPG"));
2168 1 : int NUMOPG = atoi(NITFFindValFromEnd(papszMD, *pnMDSize, pszMDItemName, "-1"));
2169 1 : CPLFree(pszMDItemName);
2170 1 : 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 1 : nIterations = NUMOPG * (NUMOPG + 1) / 2;
2180 : }
2181 3 : else if (pszFormula != NULL &&
2182 1 : strcmp(pszFormula, "NPAR*NPARO") == 0)
2183 : {
2184 1 : char* pszMDNPARName = CPLStrdup(
2185 1 : CPLSPrintf("%s%s", pszMDPrefix, "NPAR"));
2186 1 : int NPAR = atoi(NITFFindValFromEnd(papszMD, *pnMDSize, pszMDNPARName, "-1"));
2187 1 : char* pszMDNPAROName = CPLStrdup(
2188 1 : CPLSPrintf("%s%s", pszMDPrefix, "NPARO"));
2189 1 : int NPARO= atoi(NITFFindValFromEnd(papszMD, *pnMDSize, pszMDNPAROName, "-1"));
2190 1 : CPLFree(pszMDNPARName);
2191 1 : CPLFree(pszMDNPAROName);
2192 1 : 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 1 : 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 1 : 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 43 : if (nIterations > 0)
2272 : {
2273 : int iIter;
2274 : const char* pszPercent;
2275 33 : int bHasValidPercentD = FALSE;
2276 33 : CPLXMLNode* psRepeatedNode = NULL;
2277 33 : CPLXMLNode* psLastChild = NULL;
2278 :
2279 : /* Check that md_prefix has one and only %XXXXd pattern */
2280 66 : if (pszMDSubPrefix != NULL &&
2281 : (pszPercent = strchr(pszMDSubPrefix, '%')) != NULL &&
2282 33 : strchr(pszPercent+1,'%') == NULL)
2283 : {
2284 33 : const char* pszIter = pszPercent + 1;
2285 124 : while(*pszIter != '\0')
2286 : {
2287 149 : if (*pszIter >= '0' && *pszIter <= '9')
2288 58 : pszIter ++;
2289 33 : else if (*pszIter == 'd')
2290 : {
2291 33 : bHasValidPercentD = atoi(pszPercent + 1) <= 10;
2292 33 : break;
2293 : }
2294 : else
2295 0 : break;
2296 : }
2297 : }
2298 :
2299 33 : if (psOutXMLNode != NULL)
2300 : {
2301 : CPLXMLNode* psNumberNode;
2302 : CPLXMLNode* psNameNode;
2303 33 : const char* pszName = CPLGetXMLValue(psIter, "name", NULL);
2304 33 : psRepeatedNode = CPLCreateXMLNode(psOutXMLNode, CXT_Element, "repeated");
2305 33 : if (pszName)
2306 : {
2307 33 : psNameNode = CPLCreateXMLNode(psRepeatedNode, CXT_Attribute, "name");
2308 33 : CPLCreateXMLNode(psNameNode, CXT_Text, pszName);
2309 : }
2310 33 : psNumberNode = CPLCreateXMLNode(psRepeatedNode, CXT_Attribute, "number");
2311 33 : CPLCreateXMLNode(psNumberNode, CXT_Text, CPLSPrintf("%d", nIterations));
2312 :
2313 33 : psLastChild = psRepeatedNode->psChild;
2314 99 : while(psLastChild->psNext != NULL)
2315 33 : psLastChild = psLastChild->psNext;
2316 : }
2317 :
2318 247 : for(iIter = 0; iIter < nIterations && *pbError == FALSE; iIter++)
2319 : {
2320 214 : char* pszMDNewPrefix = NULL;
2321 214 : CPLXMLNode* psGroupNode = NULL;
2322 214 : if (pszMDSubPrefix != NULL)
2323 : {
2324 214 : if (bHasValidPercentD)
2325 : {
2326 214 : char* szTmp = (char*)CPLMalloc(
2327 214 : strlen(pszMDSubPrefix) + 10 + 1);
2328 214 : sprintf(szTmp, pszMDSubPrefix, iIter + 1);
2329 214 : pszMDNewPrefix = CPLStrdup(CPLSPrintf("%s%s",
2330 : pszMDPrefix, szTmp));
2331 214 : 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 214 : if (psRepeatedNode != NULL)
2342 : {
2343 : CPLXMLNode* psIndexNode;
2344 214 : psGroupNode = CPLCreateXMLNode(NULL, CXT_Element, "group");
2345 214 : CPLAssert(psLastChild->psNext == NULL);
2346 214 : psLastChild->psNext = psGroupNode;
2347 214 : psLastChild = psGroupNode;
2348 214 : psIndexNode = CPLCreateXMLNode(psGroupNode, CXT_Attribute, "index");
2349 214 : CPLCreateXMLNode(psIndexNode, CXT_Text, CPLSPrintf("%d", iIter));
2350 : }
2351 :
2352 214 : papszMD = NITFGenericMetadataReadTREInternal(papszMD,
2353 : pnMDSize,
2354 : pnMDAlloc,
2355 : psGroupNode,
2356 : pszTREName,
2357 : pachTRE,
2358 : nTRESize,
2359 : psIter,
2360 : pnTreOffset,
2361 : pszMDNewPrefix,
2362 : pbError);
2363 214 : CPLFree(pszMDNewPrefix);
2364 : }
2365 : }
2366 : }
2367 1002 : else if (psIter->eType == CXT_Element &&
2368 45 : psIter->pszValue != NULL &&
2369 45 : strcmp(psIter->pszValue, "if") == 0)
2370 : {
2371 44 : const char* pszCond = CPLGetXMLValue(psIter, "cond", NULL);
2372 44 : const char* pszEqual = NULL;
2373 47 : if (pszCond != NULL && strcmp(pszCond, "QSS!=U AND QOD!=Y") == 0)
2374 : {
2375 3 : char* pszQSSName = CPLStrdup(
2376 3 : CPLSPrintf("%s%s", pszMDPrefix, "QSS"));
2377 3 : char* pszQODName = CPLStrdup(
2378 3 : CPLSPrintf("%s%s", pszMDPrefix, "QOD"));
2379 3 : const char* pszQSSVal = NITFFindValFromEnd(papszMD, *pnMDSize, pszQSSName, NULL);
2380 3 : const char* pszQODVal = NITFFindValFromEnd(papszMD, *pnMDSize, pszQODName, NULL);
2381 3 : if (pszQSSVal == NULL)
2382 : {
2383 0 : CPLDebug("NITF", "Cannot find if cond variable %s", "QSS");
2384 : }
2385 3 : else if (pszQODVal == NULL)
2386 : {
2387 0 : CPLDebug("NITF", "Cannot find if cond variable %s", "QOD");
2388 : }
2389 3 : 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 3 : CPLFree(pszQSSName);
2404 3 : CPLFree(pszQODName);
2405 : }
2406 82 : else if (pszCond != NULL && (pszEqual = strchr(pszCond, '=')) != NULL)
2407 : {
2408 41 : char* pszCondVar = (char*)CPLMalloc(pszEqual - pszCond + 1);
2409 41 : const char* pszCondExpectedVal = pszEqual + 1;
2410 : char* pszMDItemName;
2411 : const char* pszCondVal;
2412 41 : int bTestEqual = TRUE;
2413 41 : memcpy(pszCondVar, pszCond, pszEqual - pszCond);
2414 41 : if (pszEqual - pszCond > 1 && pszCondVar[pszEqual - pszCond - 1] == '!')
2415 : {
2416 39 : bTestEqual = FALSE;
2417 39 : pszCondVar[pszEqual - pszCond - 1] = '\0';
2418 : }
2419 41 : pszCondVar[pszEqual - pszCond] = '\0';
2420 41 : pszMDItemName = CPLStrdup(
2421 : CPLSPrintf("%s%s", pszMDPrefix, pszCondVar));
2422 41 : pszCondVal = NITFFindValFromEnd(papszMD, *pnMDSize, pszMDItemName, NULL);
2423 41 : if (pszCondVal == NULL)
2424 : {
2425 0 : CPLDebug("NITF", "Cannot find if cond variable %s",
2426 : pszMDItemName);
2427 : }
2428 80 : else if ((bTestEqual && strcmp(pszCondVal, pszCondExpectedVal) == 0) ||
2429 39 : (!bTestEqual && strcmp(pszCondVal, pszCondExpectedVal) != 0))
2430 : {
2431 7 : 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 41 : CPLFree(pszMDItemName);
2444 41 : 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 826 : else if (psIter->eType == CXT_Element &&
2457 1 : psIter->pszValue != NULL &&
2458 1 : strcmp(psIter->pszValue, "if_remaining_bytes") == 0)
2459 : {
2460 1 : 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 244 : return papszMD;
2481 : }
2482 :
2483 : /************************************************************************/
2484 : /* NITFGenericMetadataReadTRE() */
2485 : /************************************************************************/
2486 :
2487 : static
2488 8 : char **NITFGenericMetadataReadTRE(char **papszMD,
2489 : const char* pszTREName,
2490 : const char *pachTRE,
2491 : int nTRESize,
2492 : CPLXMLNode* psTreNode)
2493 : {
2494 8 : int nTreLength, nTreMinLength = -1, nTreMaxLength = -1;
2495 8 : int bError = FALSE;
2496 8 : int nTreOffset = 0;
2497 : const char* pszMDPrefix;
2498 : int nMDSize, nMDAlloc;
2499 :
2500 8 : nTreLength = atoi(CPLGetXMLValue(psTreNode, "length", "-1"));
2501 8 : nTreMinLength = atoi(CPLGetXMLValue(psTreNode, "minlength", "-1"));
2502 8 : nTreMaxLength = atoi(CPLGetXMLValue(psTreNode, "maxlength", "-1"));
2503 :
2504 8 : 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 8 : pszMDPrefix = CPLGetXMLValue(psTreNode, "md_prefix", "");
2513 :
2514 8 : nMDSize = nMDAlloc = CSLCount(papszMD);
2515 :
2516 8 : 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 8 : 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 8 : if (nTreOffset < nTRESize)
2535 0 : CPLDebug("NITF", "%d remaining bytes at end of %s TRE",
2536 : nTRESize -nTreOffset, pszTREName);
2537 :
2538 8 : return papszMD;
2539 : }
2540 :
2541 :
2542 : /************************************************************************/
2543 : /* NITFLoadXMLSpec() */
2544 : /************************************************************************/
2545 :
2546 : #define NITF_SPEC_FILE "nitf_spec.xml"
2547 :
2548 563 : static CPLXMLNode* NITFLoadXMLSpec(NITFFile* psFile)
2549 : {
2550 :
2551 563 : if (psFile->psNITFSpecNode == NULL)
2552 : {
2553 546 : const char* pszXMLDescFilename = CPLFindFile("gdal", NITF_SPEC_FILE);
2554 546 : if (pszXMLDescFilename == NULL)
2555 : {
2556 0 : CPLDebug("NITF", "Cannot find XML file : %s", NITF_SPEC_FILE);
2557 0 : return NULL;
2558 : }
2559 546 : psFile->psNITFSpecNode = CPLParseXMLFile(pszXMLDescFilename);
2560 546 : if (psFile->psNITFSpecNode == NULL)
2561 : {
2562 0 : CPLDebug("NITF", "Invalid XML file : %s", pszXMLDescFilename);
2563 0 : return NULL;
2564 : }
2565 : }
2566 :
2567 563 : return psFile->psNITFSpecNode;
2568 : }
2569 :
2570 : /************************************************************************/
2571 : /* NITFFindTREXMLDescFromName() */
2572 : /************************************************************************/
2573 :
2574 17 : static CPLXMLNode* NITFFindTREXMLDescFromName(NITFFile* psFile,
2575 : const char* pszTREName)
2576 : {
2577 : CPLXMLNode* psTreeNode;
2578 : CPLXMLNode* psTresNode;
2579 : CPLXMLNode* psIter;
2580 :
2581 17 : psTreeNode = NITFLoadXMLSpec(psFile);
2582 17 : if (psTreeNode == NULL)
2583 0 : return NULL;
2584 :
2585 17 : psTresNode = CPLGetXMLNode(psTreeNode, "=tres");
2586 17 : if (psTresNode == NULL)
2587 : {
2588 0 : CPLDebug("NITF", "Cannot find <tres> root element");
2589 0 : return NULL;
2590 : }
2591 :
2592 286 : for(psIter = psTresNode->psChild;psIter != NULL;psIter = psIter->psNext)
2593 : {
2594 838 : if (psIter->eType == CXT_Element &&
2595 277 : psIter->pszValue != NULL &&
2596 277 : strcmp(psIter->pszValue, "tre") == 0)
2597 : {
2598 277 : const char* pszName = CPLGetXMLValue(psIter, "name", NULL);
2599 277 : if (pszName != NULL && strcmp(pszName, pszTREName) == 0)
2600 : {
2601 15 : return psIter;
2602 : }
2603 : }
2604 : }
2605 :
2606 2 : return NULL;
2607 : }
2608 :
2609 : /************************************************************************/
2610 : /* NITFCreateXMLTre() */
2611 : /************************************************************************/
2612 :
2613 17 : CPLXMLNode* NITFCreateXMLTre(NITFFile* psFile,
2614 : const char* pszTREName,
2615 : const char *pachTRE,
2616 : int nTRESize)
2617 : {
2618 17 : int nTreLength, nTreMinLength = -1, nTreMaxLength = -1;
2619 17 : int bError = FALSE;
2620 17 : int nTreOffset = 0;
2621 : CPLXMLNode* psTreNode;
2622 17 : CPLXMLNode* psOutXMLNode = NULL;
2623 17 : int nMDSize = 0, nMDAlloc = 0;
2624 :
2625 17 : psTreNode = NITFFindTREXMLDescFromName(psFile, pszTREName);
2626 17 : if (psTreNode == NULL)
2627 : {
2628 2 : if (!(EQUALN(pszTREName, "RPF", 3) || strcmp(pszTREName, "XXXXXX") == 0))
2629 : {
2630 2 : CPLDebug("NITF", "Cannot find definition of TRE %s in %s",
2631 : pszTREName, NITF_SPEC_FILE);
2632 : }
2633 2 : return NULL;
2634 : }
2635 :
2636 15 : nTreLength = atoi(CPLGetXMLValue(psTreNode, "length", "-1"));
2637 15 : nTreMinLength = atoi(CPLGetXMLValue(psTreNode, "minlength", "-1"));
2638 15 : nTreMaxLength = atoi(CPLGetXMLValue(psTreNode, "maxlength", "-1"));
2639 :
2640 15 : 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 15 : psOutXMLNode = CPLCreateXMLNode(NULL, CXT_Element, "tre");
2649 15 : CPLCreateXMLNode(CPLCreateXMLNode(psOutXMLNode, CXT_Attribute, "name"),
2650 : CXT_Text, pszTREName);
2651 :
2652 15 : CSLDestroy(NITFGenericMetadataReadTREInternal(NULL,
2653 : &nMDSize,
2654 : &nMDAlloc,
2655 : psOutXMLNode,
2656 : pszTREName,
2657 : pachTRE,
2658 : nTRESize,
2659 : psTreNode,
2660 : &nTreOffset,
2661 : "",
2662 : &bError));
2663 :
2664 15 : 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 15 : if (nTreOffset < nTRESize)
2671 0 : CPLDebug("NITF", "%d remaining bytes at end of %s TRE",
2672 : nTRESize -nTreOffset, pszTREName);
2673 :
2674 15 : 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 546 : char **NITFGenericMetadataRead( char **papszMD,
2687 : NITFFile* psFile,
2688 : NITFImage *psImage,
2689 : const char* pszSpecificTREName)
2690 : {
2691 546 : CPLXMLNode* psTreeNode = NULL;
2692 546 : CPLXMLNode* psTresNode = NULL;
2693 546 : CPLXMLNode* psIter = NULL;
2694 :
2695 546 : if (psFile == NULL && psImage == NULL)
2696 0 : return papszMD;
2697 :
2698 546 : psTreeNode = NITFLoadXMLSpec(psFile ? psFile : psImage->psFile);
2699 546 : if (psTreeNode == NULL)
2700 0 : return papszMD;
2701 :
2702 546 : psTresNode = CPLGetXMLNode(psTreeNode, "=tres");
2703 546 : if (psTresNode == NULL)
2704 : {
2705 0 : CPLDebug("NITF", "Cannot find <tres> root element");
2706 0 : return papszMD;
2707 : }
2708 :
2709 19656 : for(psIter = psTresNode->psChild;psIter!=NULL;psIter = psIter->psNext)
2710 : {
2711 56238 : if (psIter->eType == CXT_Element &&
2712 18564 : psIter->pszValue != NULL &&
2713 18564 : strcmp(psIter->pszValue, "tre") == 0)
2714 : {
2715 18564 : const char* pszName = CPLGetXMLValue(psIter, "name", NULL);
2716 18564 : const char* pszMDPrefix = CPLGetXMLValue(psIter, "md_prefix", NULL);
2717 18564 : if (pszName != NULL && ((pszSpecificTREName == NULL && pszMDPrefix != NULL) ||
2718 0 : (pszSpecificTREName != NULL && strcmp(pszName, pszSpecificTREName) == 0)))
2719 : {
2720 3276 : if (psFile != NULL)
2721 : {
2722 3276 : const char *pachTRE = NULL;
2723 3276 : int nTRESize = 0;
2724 :
2725 3276 : pachTRE = NITFFindTRE( psFile->pachTRE, psFile->nTREBytes,
2726 : pszName, &nTRESize);
2727 3276 : if( pachTRE != NULL )
2728 0 : papszMD = NITFGenericMetadataReadTRE(
2729 : papszMD, pszName, pachTRE, nTRESize, psIter);
2730 : }
2731 3276 : if (psImage != NULL)
2732 : {
2733 3276 : const char *pachTRE = NULL;
2734 3276 : int nTRESize = 0;
2735 :
2736 3276 : pachTRE = NITFFindTRE( psImage->pachTRE, psImage->nTREBytes,
2737 : pszName, &nTRESize);
2738 3276 : if( pachTRE != NULL )
2739 8 : papszMD = NITFGenericMetadataReadTRE(
2740 : papszMD, pszName, pachTRE, nTRESize, psIter);
2741 : }
2742 3276 : if (pszSpecificTREName)
2743 0 : break;
2744 : }
2745 : }
2746 : }
2747 :
2748 546 : return papszMD;
2749 : }
|