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