~ubuntu-branches/debian/sid/gdal/sid

« back to all changes in this revision

Viewing changes to frmts/nitf/nitffile.c

  • Committer: Package Import Robot
  • Author(s): Francesco Paolo Lovergine
  • Date: 2012-05-07 15:04:42 UTC
  • mfrom: (5.5.16 experimental)
  • Revision ID: package-import@ubuntu.com-20120507150442-2eks97loeh6rq005
Tags: 1.9.0-1
* Ready for sid, starting transition.
* All symfiles updated to latest builds.
* Added dh_numpy call in debian/rules to depend on numpy ABI.
* Policy bumped to 3.9.3, no changes required.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/******************************************************************************
2
 
 * $Id: nitffile.c 18667 2010-01-26 20:15:09Z rouault $
 
2
 * $Id: nitffile.c 23492 2011-12-07 20:50:52Z rouault $
3
3
 *
4
4
 * Project:  NITF Read/Write Library
5
5
 * Purpose:  Module responsible for opening NITF file, populating NITFFile
33
33
#include "cpl_conv.h"
34
34
#include "cpl_string.h"
35
35
 
36
 
CPL_CVSID("$Id: nitffile.c 18667 2010-01-26 20:15:09Z rouault $");
 
36
CPL_CVSID("$Id: nitffile.c 23492 2011-12-07 20:50:52Z rouault $");
37
37
 
38
 
static int NITFWriteBLOCKA( FILE* fp, vsi_l_offset nOffsetUDIDL, 
 
38
static int NITFWriteBLOCKA( VSILFILE* fp, vsi_l_offset nOffsetUDIDL,
39
39
                            vsi_l_offset nOffsetTRE, 
40
40
                            int *pnOffset,
41
41
                            char **papszOptions );
42
42
static int NITFWriteTREsFromOptions(
43
 
    FILE* fp,
 
43
    VSILFILE* fp,
44
44
    vsi_l_offset nOffsetUDIDL, vsi_l_offset nOffsetTRE,
45
45
    int *pnOffset,
46
 
    char **papszOptions );
 
46
    char **papszOptions,
 
47
    const char* pszTREPrefix);
47
48
 
48
49
static int 
49
 
NITFCollectSegmentInfo( NITFFile *psFile, int nOffset, char *pszType,
 
50
NITFCollectSegmentInfo( NITFFile *psFile, int nFileHeaderLenSize, int nOffset,
 
51
                        const char szType[3],
50
52
                        int nHeaderLenSize, int nDataLenSize, 
51
53
                        GUIntBig *pnNextData );
52
54
 
57
59
NITFFile *NITFOpen( const char *pszFilename, int bUpdatable )
58
60
 
59
61
{
60
 
    FILE        *fp;
 
62
    VSILFILE    *fp;
61
63
    char        *pachHeader;
62
64
    NITFFile    *psFile;
63
65
    int         nHeaderLen, nOffset, nHeaderLenOffset;
64
66
    GUIntBig    nNextData;
65
67
    char        szTemp[128], achFSDWNG[6];
66
68
    GIntBig     currentPos;
 
69
    int         bTriedStreamingFileHeader = FALSE;
67
70
 
68
71
/* -------------------------------------------------------------------- */
69
72
/*      Open the file.                                                  */
152
155
        return NULL;
153
156
    }
154
157
    VSIFSeekL( fp, 0, SEEK_SET );
155
 
    VSIFReadL( pachHeader, 1, nHeaderLen, fp );
 
158
    if ((int)VSIFReadL( pachHeader, 1, nHeaderLen, fp ) != nHeaderLen)
 
159
    {
 
160
        CPLError( CE_Failure, CPLE_OutOfMemory, 
 
161
                  "Cannot read %d bytes for NITF header", (nHeaderLen));
 
162
        VSIFCloseL(fp);
 
163
        CPLFree(pachHeader);
 
164
        return NULL;
 
165
    }
156
166
 
157
167
/* -------------------------------------------------------------------- */
158
168
/*      Create and initialize info structure about file.                */
161
171
    psFile->fp = fp;
162
172
    psFile->pachHeader = pachHeader;
163
173
 
 
174
retry_read_header:
164
175
/* -------------------------------------------------------------------- */
165
176
/*      Get version.                                                    */
166
177
/* -------------------------------------------------------------------- */
211
222
        GetMD( psFile, szWork, 0, 11, FBKGC );
212
223
        GetMD( psFile, pachHeader, 300,  24, ONAME  );
213
224
        GetMD( psFile, pachHeader, 324,  18, OPHONE );
 
225
        NITFGetField(szTemp, pachHeader, 342, 12);
214
226
    }
215
227
    else if( EQUAL(psFile->szVersion,"NITF02.00") )
216
228
    {
239
251
        GetMD( psFile, pachHeader, 296+nCOff,   1, ENCRYP );
240
252
        GetMD( psFile, pachHeader, 297+nCOff,  27, ONAME  );
241
253
        GetMD( psFile, pachHeader, 324+nCOff,  18, OPHONE );
 
254
        NITFGetField(szTemp, pachHeader, 342+nCOff, 12);
 
255
    }
 
256
 
 
257
    if (!bTriedStreamingFileHeader &&
 
258
         EQUAL(szTemp, "999999999999"))
 
259
    {
 
260
        GUIntBig nFileSize;
 
261
        GByte abyDELIM2_L2[12];
 
262
        GByte abyL1_DELIM1[11];
 
263
 
 
264
        bTriedStreamingFileHeader = TRUE;
 
265
        CPLDebug("NITF", "Total file unknown. Trying to get a STREAMING_FILE_HEADER");
 
266
 
 
267
        VSIFSeekL( fp, 0, SEEK_END );
 
268
        nFileSize = VSIFTellL(fp);
 
269
 
 
270
        VSIFSeekL( fp, nFileSize - 11, SEEK_SET );
 
271
        abyDELIM2_L2[11] = '\0';
 
272
 
 
273
        if (VSIFReadL( abyDELIM2_L2, 1, 11, fp ) == 11 &&
 
274
            abyDELIM2_L2[0] == 0x0E && abyDELIM2_L2[1] == 0xCA &&
 
275
            abyDELIM2_L2[2] == 0x14 && abyDELIM2_L2[3] == 0xBF)
 
276
        {
 
277
            int SFHL2 = atoi((const char*)(abyDELIM2_L2 + 4));
 
278
            if (SFHL2 > 0 && nFileSize > 11 + SFHL2 + 11 )
 
279
            {
 
280
                VSIFSeekL( fp, nFileSize - 11 - SFHL2 - 11 , SEEK_SET );
 
281
 
 
282
                if ( VSIFReadL( abyL1_DELIM1, 1, 11, fp ) == 11 &&
 
283
                     abyL1_DELIM1[7] == 0x0A && abyL1_DELIM1[8] == 0x6E &&
 
284
                     abyL1_DELIM1[9] == 0x1D && abyL1_DELIM1[10] == 0x97 &&
 
285
                     memcmp(abyL1_DELIM1, abyDELIM2_L2 + 4, 7) == 0 )
 
286
                {
 
287
                    if (SFHL2 == nHeaderLen)
 
288
                    {
 
289
                        CSLDestroy(psFile->papszMetadata);
 
290
                        psFile->papszMetadata = NULL;
 
291
 
 
292
                        if ( (int)VSIFReadL( pachHeader, 1, SFHL2, fp ) != SFHL2 )
 
293
                        {
 
294
                            VSIFCloseL(fp);
 
295
                            CPLFree(pachHeader);
 
296
                            CPLFree(psFile);
 
297
                            return NULL;
 
298
                        }
 
299
 
 
300
                        goto retry_read_header;
 
301
                    }
 
302
                }
 
303
            }
 
304
        }
242
305
    }
243
306
 
244
307
/* -------------------------------------------------------------------- */
248
311
 
249
312
    nOffset = nHeaderLenOffset + 6;
250
313
 
251
 
    nOffset = NITFCollectSegmentInfo( psFile, nOffset,"IM",6, 10, &nNextData );
 
314
    nOffset = NITFCollectSegmentInfo( psFile, nHeaderLen, nOffset,"IM",6, 10, &nNextData );
252
315
 
253
 
    nOffset = NITFCollectSegmentInfo( psFile, nOffset, "GR", 4, 6, &nNextData);
 
316
    if (nOffset != -1)
 
317
        nOffset = NITFCollectSegmentInfo( psFile, nHeaderLen, nOffset, "GR", 4, 6, &nNextData);
254
318
 
255
319
    /* LA Called NUMX in NITF 2.1 */
256
 
    nOffset = NITFCollectSegmentInfo( psFile, nOffset, "LA", 4, 3, &nNextData);
257
 
 
258
 
    nOffset = NITFCollectSegmentInfo( psFile, nOffset, "TX", 4, 5, &nNextData);
259
 
 
260
 
    nOffset = NITFCollectSegmentInfo( psFile, nOffset, "DE", 4, 9, &nNextData);
261
 
 
262
 
    nOffset = NITFCollectSegmentInfo( psFile, nOffset, "RE", 4, 7, &nNextData);
 
320
    if (nOffset != -1)
 
321
        nOffset = NITFCollectSegmentInfo( psFile, nHeaderLen, nOffset, "LA", 4, 3, &nNextData);
 
322
 
 
323
    if (nOffset != -1)
 
324
        nOffset = NITFCollectSegmentInfo( psFile, nHeaderLen, nOffset, "TX", 4, 5, &nNextData);
 
325
 
 
326
    if (nOffset != -1)
 
327
        nOffset = NITFCollectSegmentInfo( psFile, nHeaderLen, nOffset, "DE", 4, 9, &nNextData);
 
328
 
 
329
    if (nOffset != -1)
 
330
        nOffset = NITFCollectSegmentInfo( psFile, nHeaderLen, nOffset, "RE", 4, 7, &nNextData);
 
331
    else
 
332
    {
 
333
        NITFClose(psFile);
 
334
        return NULL;
 
335
    }
263
336
 
264
337
/* -------------------------------------------------------------------- */
265
338
/*      Is there User Define Header Data? (TREs)                        */
282
355
    }
283
356
    nOffset += 5;
284
357
 
285
 
    if( psFile->nTREBytes > 3 )
 
358
    if( psFile->nTREBytes == 3 )
 
359
    {
 
360
        nOffset += 3; /* UDHOFL */
 
361
        psFile->nTREBytes = 0;
 
362
    }
 
363
    else if( psFile->nTREBytes > 3 )
286
364
    {
287
365
        nOffset += 3; /* UDHOFL */
288
366
        psFile->nTREBytes -= 3;
374
452
 
375
453
        if( EQUAL(psSegInfo->szSegmentType,"IM"))
376
454
            NITFImageDeaccess( (NITFImage *) psSegInfo->hAccess );
 
455
        else if( EQUAL(psSegInfo->szSegmentType,"DE"))
 
456
            NITFDESDeaccess( (NITFDES *) psSegInfo->hAccess );
377
457
        else
378
458
        {
379
459
            CPLAssert( FALSE );
386
466
    CPLFree( psFile->pachHeader );
387
467
    CSLDestroy( psFile->papszMetadata );
388
468
    CPLFree( psFile->pachTRE );
 
469
 
 
470
    if (psFile->psNITFSpecNode)
 
471
        CPLDestroyXMLNode(psFile->psNITFSpecNode);
 
472
 
389
473
    CPLFree( psFile );
390
474
}
391
475
 
392
 
static void NITFGotoOffset(FILE* fp, GUIntBig nLocation)
 
476
static void NITFGotoOffset(VSILFILE* fp, GUIntBig nLocation)
393
477
{
394
478
    GUIntBig nCurrentLocation = VSIFTellL(fp);
395
479
    if (nLocation > nCurrentLocation)
427
511
                      char **papszOptions )
428
512
 
429
513
{
430
 
    FILE        *fp;
 
514
    VSILFILE    *fp;
431
515
    GUIntBig    nCur = 0;
432
516
    int         nOffset = 0, iBand, nIHSize, nNPPBH, nNPPBV;
433
517
    GIntBig     nImageSize;
435
519
    const char *pszIREP;
436
520
    const char *pszIC = CSLFetchNameValue(papszOptions,"IC");
437
521
    int nCLevel;
438
 
    const char *pszOpt;
 
522
    const char *pszNUMT;
439
523
    int nHL, nNUMT = 0;
440
524
    int nUDIDLOffset;
441
525
    const char *pszVersion;
442
526
    int iIM, nIM = 1;
443
527
    const char *pszNUMI;
 
528
    int iGS, nGS = 0; // number of graphic segment
 
529
    const char *pszNUMS; // graphic segment option string
444
530
 
445
531
    if (nBands <= 0 || nBands > 99999)
446
532
    {
459
545
    if( pszIREP == NULL )
460
546
        pszIREP = "MONO";
461
547
 
462
 
    pszOpt = CSLFetchNameValue( papszOptions, "NUMT" );
463
 
    if( pszOpt != NULL )
464
 
        nNUMT = atoi(pszOpt);
465
 
    
 
548
    pszNUMT = CSLFetchNameValue( papszOptions, "NUMT" );
 
549
    if( pszNUMT != NULL )
 
550
    {
 
551
        nNUMT = atoi(pszNUMT);
 
552
        if (nNUMT < 0 || nNUMT > 999)
 
553
        {
 
554
            CPLError( CE_Failure, CPLE_AppDefined, 
 
555
                    "Invalid NUMT value : %s", pszNUMT);
 
556
            return FALSE;
 
557
        }
 
558
    }
 
559
 
466
560
    pszNUMI = CSLFetchNameValue( papszOptions, "NUMI" );
467
561
    if (pszNUMI != NULL)
468
562
    {
481
575
        }
482
576
    }
483
577
    
 
578
    // Reads and validates graphics segment number option
 
579
    pszNUMS = CSLFetchNameValue(papszOptions, "NUMS");
 
580
    if (pszNUMS != NULL)
 
581
    {
 
582
        nGS = atoi(pszNUMS);
 
583
        if (nGS < 0 || nGS > 999)
 
584
        {
 
585
            CPLError(CE_Failure, CPLE_AppDefined, "Invalid NUMS value : %s",
 
586
                            pszNUMS);
 
587
            return FALSE;
 
588
        }
 
589
    }
 
590
 
 
591
 
 
592
 
484
593
/* -------------------------------------------------------------------- */
485
594
/*      Compute raw image size, blocking factors and so forth.          */
486
595
/* -------------------------------------------------------------------- */
518
627
            * ((GIntBig) nPixels *nLines)
519
628
            * nBands;
520
629
    }
 
630
    else if (EQUAL(pszIC, "NC") &&
 
631
             nPixels > 8192 && nNPPBH == nPixels)
 
632
    {
 
633
        /* See MIL-STD-2500-C, paragraph 5.4.2.2-d */
 
634
        nNBPR = 1;
 
635
        nNPPBH = 0;
 
636
        nNBPC = (nLines + nNPPBV - 1) / nNPPBV;
 
637
 
 
638
        if ( nNBPC > 9999 )
 
639
        {
 
640
            CPLError( CE_Failure, CPLE_AppDefined,
 
641
                      "Unable to create file %s,\n"
 
642
                      "Too many blocks : %d x %d",
 
643
                     pszFilename, nNBPR, nNBPC);
 
644
            return FALSE;
 
645
        }
 
646
 
 
647
        nImageSize =
 
648
            ((nBitsPerSample)/8)
 
649
            * ((GIntBig) nPixels * (nNBPC * nNPPBV))
 
650
            * nBands;
 
651
    }
 
652
    else if (EQUAL(pszIC, "NC") &&
 
653
             nLines > 8192 && nNPPBV == nLines)
 
654
    {
 
655
        /* See MIL-STD-2500-C, paragraph 5.4.2.2-d */
 
656
        nNBPC = 1;
 
657
        nNPPBV = 0;
 
658
        nNBPR = (nPixels + nNPPBH - 1) / nNPPBH;
 
659
 
 
660
        if ( nNBPR > 9999 )
 
661
        {
 
662
            CPLError( CE_Failure, CPLE_AppDefined,
 
663
                      "Unable to create file %s,\n"
 
664
                      "Too many blocks : %d x %d",
 
665
                     pszFilename, nNBPR, nNBPC);
 
666
            return FALSE;
 
667
        }
 
668
 
 
669
        nImageSize =
 
670
            ((nBitsPerSample)/8)
 
671
            * ((GIntBig) nLines * (nNBPR * nNPPBH))
 
672
            * nBands;
 
673
    }
521
674
    else
522
675
    {
523
676
        if( nNPPBH <= 0 || nNPPBV <= 0 ||
543
696
 
544
697
    if (EQUAL(pszIC, "NC"))
545
698
    {
546
 
        if ((double)nImageSize >= 1e10)
 
699
        if ((double)nImageSize >= 1e10 - 1)
547
700
        {
548
701
            CPLError( CE_Failure, CPLE_AppDefined, 
549
702
                    "Unable to create file %s,\n"
551
704
                    pszFilename, nImageSize );
552
705
            return FALSE;
553
706
        }
554
 
        if ((double)(nImageSize * nIM) >= 1e12)
 
707
        if ((double)(nImageSize * nIM) >= 1e12 - 1)
555
708
        {
556
709
            CPLError( CE_Failure, CPLE_AppDefined, 
557
710
                    "Unable to create file %s,\n"
659
812
        nHL += 6 + 10;
660
813
    }
661
814
 
662
 
    PLACE (nHL,     NUMS         ,"000"                           );
663
 
    PLACE (nHL + 3, NUMX         ,"000"                           );
664
 
    PLACE (nHL + 6, NUMT         ,CPLSPrintf("%03d",nNUMT)        );
665
 
 
666
 
    PLACE (nHL + 9, LTSHnLTn     ,""                              );
667
 
 
668
 
    nHL += 9 + (4+5) * nNUMT;
 
815
    // Creates Header entries for graphic segment
 
816
    //    NUMS: number of segment
 
817
    // For each segment:
 
818
    //    LSSH[i]: subheader length (4 byte), set to be 258, the size for
 
819
    //                          minimal amount of information.
 
820
    //    LS[i] data length (6 byte)
 
821
    PLACE (nHL,     NUMS         ,CPLSPrintf("%03d",nGS)        );
 
822
    nHL += 3; // Move three characters
 
823
    for (iGS = 0; iGS < nGS; iGS++)
 
824
    {
 
825
        PLACE (nHL, LSSHi ,CPLSPrintf("0000") );
 
826
        PLACE (nHL + 4, LSi ,CPLSPrintf("000000") );
 
827
        nHL += 4 + 6;
 
828
    }
 
829
 
 
830
    PLACE (nHL, NUMX         ,"000"                           );
 
831
    PLACE (nHL + 3, NUMT         ,CPLSPrintf("%03d",nNUMT)        );
 
832
 
 
833
    PLACE (nHL + 6, LTSHnLTn     ,""                              );
 
834
 
 
835
    nHL += 6 + (4+5) * nNUMT;
669
836
 
670
837
    PLACE (nHL, NUMDES       ,"000"                           );
671
838
    nHL += 3;
676
843
    PLACE (nHL, XHDL         ,"00000"                         );
677
844
    nHL += 5;
678
845
 
 
846
    if( CSLFetchNameValue(papszOptions,"FILE_TRE") != NULL )
 
847
    {
 
848
        NITFWriteTREsFromOptions(
 
849
            fp,
 
850
            nHL - 10,
 
851
            nHL,
 
852
            &nHL,
 
853
            papszOptions, "FILE_TRE=" );
 
854
    }
 
855
 
 
856
    if (nHL > 999999)
 
857
    {
 
858
        CPLError(CE_Failure, CPLE_AppDefined,
 
859
                 "Too big file header length : %d", nHL);
 
860
        VSIFCloseL( fp );
 
861
        return FALSE;
 
862
    }
 
863
 
679
864
    // update header length
680
865
    PLACE (354, HL           ,CPLSPrintf("%06d",nHL)          );
681
866
 
686
871
/* -------------------------------------------------------------------- */
687
872
  for(iIM=0;iIM<nIM;iIM++)
688
873
  {
 
874
    char** papszIREPBANDTokens = NULL;
 
875
    char** papszISUBCATTokens = NULL;
 
876
 
 
877
    if( CSLFetchNameValue(papszOptions,"IREPBAND") != NULL )
 
878
    {
 
879
        papszIREPBANDTokens = CSLTokenizeStringComplex(
 
880
            CSLFetchNameValue(papszOptions,"IREPBAND"), ",", 0, 0 );
 
881
        if( papszIREPBANDTokens != NULL && CSLCount( papszIREPBANDTokens ) != nBands)
 
882
        {
 
883
            CSLDestroy(  papszIREPBANDTokens );
 
884
            papszIREPBANDTokens = NULL;
 
885
        }
 
886
    }
 
887
    if( CSLFetchNameValue(papszOptions,"ISUBCAT") != NULL )
 
888
    {
 
889
        papszISUBCATTokens = CSLTokenizeStringComplex(
 
890
            CSLFetchNameValue(papszOptions,"ISUBCAT"), ",", 0, 0 );
 
891
        if( papszISUBCATTokens != NULL && CSLCount( papszISUBCATTokens ) != nBands)
 
892
        {
 
893
            CSLDestroy( papszISUBCATTokens );
 
894
            papszISUBCATTokens = NULL;
 
895
        }
 
896
    }
 
897
 
689
898
    VSIFSeekL(fp, nCur, SEEK_SET);
690
899
 
691
900
    PLACE (nCur+  0, IM           , "IM"                           );
734
943
        }
735
944
    }
736
945
 
737
 
    PLACE (nCur+nOffset, NICOM    , "0"                            );
 
946
    {
 
947
        const char* pszICOM = CSLFetchNameValue( papszOptions, "ICOM");
 
948
        if (pszICOM != NULL)
 
949
        {
 
950
            int nLenICOM = strlen(pszICOM);
 
951
            int nICOM = (79 + nLenICOM) / 80;
 
952
            if (nICOM > 9)
 
953
            {
 
954
                CPLError(CE_Warning, CPLE_NotSupported, "ICOM will be truncated");
 
955
                nICOM = 9;
 
956
            }
 
957
            PLACE (nCur+nOffset, NICOM    , CPLSPrintf("%01d",nICOM) );
 
958
            VSIFWriteL(pszICOM, 1, MIN(nICOM * 80, nLenICOM), fp);
 
959
            nOffset += nICOM * 80;
 
960
        }
 
961
        else
 
962
        {
 
963
            PLACE (nCur+nOffset, NICOM    , "0"                            );
 
964
        }
 
965
    }
 
966
 
738
967
    OVR( 2,nCur+nOffset+1, IC     , "NC"                           );
739
968
 
740
969
    if( pszIC[0] != 'N' )
763
992
    {
764
993
        const char *pszIREPBAND = "M";
765
994
 
766
 
        if( EQUAL(pszIREP,"RGB/LUT") )
 
995
        if( papszIREPBANDTokens != NULL )
 
996
        {
 
997
            if (strlen(papszIREPBANDTokens[iBand]) > 2)
 
998
            {
 
999
                papszIREPBANDTokens[iBand][2] = '\0';
 
1000
                CPLError(CE_Warning, CPLE_NotSupported,
 
1001
                         "Truncating IREPBAND[%d] to '%s'",
 
1002
                         iBand + 1, papszIREPBANDTokens[iBand]);
 
1003
            }
 
1004
            pszIREPBAND = papszIREPBANDTokens[iBand];
 
1005
        }
 
1006
        else if( EQUAL(pszIREP,"RGB/LUT") )
767
1007
            pszIREPBAND = "LU";
768
1008
        else if( EQUAL(pszIREP,"RGB") )
769
1009
        {
785
1025
        }
786
1026
 
787
1027
        PLACE(nCur+nOffset+ 0, IREPBANDn, pszIREPBAND                 );
788
 
//      PLACE(nCur+nOffset+ 2, ISUBCATn, ""                           );
 
1028
 
 
1029
        if( papszISUBCATTokens != NULL )
 
1030
        {
 
1031
            if (strlen(papszISUBCATTokens[iBand]) > 6)
 
1032
            {
 
1033
                papszISUBCATTokens[iBand][6] = '\0';
 
1034
                CPLError(CE_Warning, CPLE_NotSupported,
 
1035
                         "Truncating ISUBCAT[%d] to '%s'",
 
1036
                         iBand + 1, papszISUBCATTokens[iBand]);
 
1037
            }
 
1038
            PLACE(nCur+nOffset+ 2, ISUBCATn, papszISUBCATTokens[iBand] );
 
1039
        }
 
1040
//      else
 
1041
//          PLACE(nCur+nOffset+ 2, ISUBCATn, ""                           );
 
1042
 
789
1043
        PLACE(nCur+nOffset+ 8, IFCn  , "N"                            );
790
1044
//      PLACE(nCur+nOffset+ 9, IMFLTn, ""                             );
791
1045
 
820
1074
        }
821
1075
    }
822
1076
 
 
1077
    CSLDestroy(papszIREPBANDTokens);
 
1078
    CSLDestroy(papszISUBCATTokens);
 
1079
 
823
1080
/* -------------------------------------------------------------------- */
824
1081
/*      Remainder of image header info.                                 */
825
1082
/* -------------------------------------------------------------------- */
868
1125
            nCur + (GUIntBig)nUDIDLOffset, 
869
1126
            nCur + (GUIntBig)nOffset, 
870
1127
            &nOffset, 
871
 
            papszOptions );
 
1128
            papszOptions, "TRE=" );
872
1129
    }
873
1130
 
874
1131
/* -------------------------------------------------------------------- */
918
1175
 
919
1176
    /* According to the spec, CLEVEL 7 supports up to 10,737,418,330 bytes */
920
1177
    /* but we can support technically much more */
921
 
    if (EQUAL(pszIC, "NC") && GUINTBIG_TO_DOUBLE(nCur) >= 1e12)
 
1178
    if (EQUAL(pszIC, "NC") && GUINTBIG_TO_DOUBLE(nCur) >= 1e12 - 1)
922
1179
    {
923
1180
        CPLError(CE_Failure, CPLE_AppDefined,
924
1181
                 "Too big file : " CPL_FRMT_GUIB, nCur);
948
1205
/*                            NITFWriteTRE()                            */
949
1206
/************************************************************************/
950
1207
 
951
 
static int NITFWriteTRE( FILE* fp,
 
1208
static int NITFWriteTRE( VSILFILE* fp,
952
1209
                         vsi_l_offset nOffsetUDIDL, 
953
1210
                         vsi_l_offset nOffsetTREInHeader, 
954
1211
                         int  *pnOffset,
1004
1261
/************************************************************************/
1005
1262
 
1006
1263
static int NITFWriteTREsFromOptions(
1007
 
    FILE* fp,
 
1264
    VSILFILE* fp,
1008
1265
    vsi_l_offset nOffsetUDIDL, vsi_l_offset nOffsetTRE,
1009
1266
    int *pnOffset,
1010
 
    char **papszOptions )    
 
1267
    char **papszOptions, const char* pszTREPrefix )    
1011
1268
 
1012
1269
{
1013
1270
    int bIgnoreBLOCKA = 
1014
1271
        CSLFetchNameValue(papszOptions,"BLOCKA_BLOCK_COUNT") != NULL;
1015
1272
    int iOption;
 
1273
    int nTREPrefixLen = strlen(pszTREPrefix);
1016
1274
 
1017
1275
    if( papszOptions == NULL )
1018
1276
        return TRUE;
1025
1283
        int  nContentLength;
1026
1284
        const char* pszSpace;
1027
1285
 
1028
 
        if( !EQUALN(papszOptions[iOption],"TRE=",4) )
 
1286
        if( !EQUALN(papszOptions[iOption], pszTREPrefix, nTREPrefixLen) )
1029
1287
            continue;
1030
1288
 
1031
 
        if( EQUALN(papszOptions[iOption]+4,"BLOCKA=",7)
 
1289
        if( EQUALN(papszOptions[iOption]+nTREPrefixLen,"BLOCKA=",7)
1032
1290
            && bIgnoreBLOCKA )
1033
1291
            continue;
1034
1292
        
1035
1293
        /* We do no longer use CPLParseNameValue() as it removes leading spaces */
1036
1294
        /* from the value (see #3088) */
1037
 
        pszSpace = strchr(papszOptions[iOption]+4, '=');
 
1295
        pszSpace = strchr(papszOptions[iOption]+nTREPrefixLen, '=');
1038
1296
        if (pszSpace == NULL)
1039
1297
        {
1040
1298
            CPLError(CE_Failure, CPLE_AppDefined,
1041
 
                     "Could not parse creation options %s", papszOptions[iOption]+4);
 
1299
                     "Could not parse creation options %s", papszOptions[iOption]+nTREPrefixLen);
1042
1300
            return FALSE;
1043
1301
        }
1044
1302
        
1045
 
        pszTREName = CPLStrdup(papszOptions[iOption]+4);
1046
 
        pszTREName[pszSpace - (papszOptions[iOption]+4)] = '\0';
 
1303
        pszTREName = CPLStrdup(papszOptions[iOption]+nTREPrefixLen);
 
1304
        pszTREName[MIN(6, pszSpace - (papszOptions[iOption]+nTREPrefixLen))] = '\0';
1047
1305
        pszEscapedContents = pszSpace + 1;
1048
1306
 
1049
1307
        pszUnescapedContents = 
1073
1331
/*                          NITFWriteBLOCKA()                           */
1074
1332
/************************************************************************/
1075
1333
 
1076
 
static int NITFWriteBLOCKA( FILE* fp, vsi_l_offset nOffsetUDIDL, 
 
1334
static int NITFWriteBLOCKA( VSILFILE* fp, vsi_l_offset nOffsetUDIDL,
1077
1335
                            vsi_l_offset nOffsetTRE, 
1078
1336
                            int *pnOffset,
1079
1337
                            char **papszOptions )
1100
1358
/* ==================================================================== */
1101
1359
    for( iBlock = 1; iBlock <= nBlockCount; iBlock++ )
1102
1360
    {
1103
 
        char szBLOCKA[200];
 
1361
        char szBLOCKA[123];
1104
1362
        int iField;
1105
1363
 
1106
1364
/* -------------------------------------------------------------------- */
1120
1378
            if( pszValue == NULL )
1121
1379
                pszValue = "";
1122
1380
 
1123
 
            if (iStart + MAX( 0 , (size_t)iSize - strlen(pszValue) )
1124
 
                       + MIN( (size_t)iSize , strlen(pszValue) ) >
1125
 
                sizeof(szBLOCKA))
 
1381
            if (strlen(pszValue) > (size_t)iSize)
1126
1382
            {
1127
 
                CPLError(CE_Failure, CPLE_AppDefined, "Too much data for BLOCKA");
 
1383
                CPLError(CE_Failure, CPLE_AppDefined,
 
1384
                         "Too much data for %s. Got %d bytes, max allowed is %d",
 
1385
                         szFullFieldName, (int)strlen(pszValue), iSize);
1128
1386
                return FALSE;
1129
1387
            }
1130
1388
 
 
1389
            /* Right align value and left pad with spaces */
1131
1390
            memset( szBLOCKA + iStart, ' ', iSize );
1132
1391
            memcpy( szBLOCKA + iStart + MAX((size_t)0,iSize-strlen(pszValue)),
1133
 
                    pszValue, MIN((size_t)iSize,strlen(pszValue)) );
 
1392
                    pszValue, strlen(pszValue) );
1134
1393
        }
1135
1394
 
1136
1395
        // required field - semantics unknown. 
1155
1414
/************************************************************************/
1156
1415
 
1157
1416
static int 
1158
 
NITFCollectSegmentInfo( NITFFile *psFile, int nOffset, char *pszType,
 
1417
NITFCollectSegmentInfo( NITFFile *psFile, int nFileHeaderLen, int nOffset, const char szType[3],
1159
1418
                        int nHeaderLenSize, int nDataLenSize, GUIntBig *pnNextData )
1160
1419
 
1161
1420
{
1162
1421
    char szTemp[12];
1163
 
    char *pachSegDef;
1164
1422
    int  nCount, nSegDefSize, iSegment;
1165
1423
 
1166
1424
/* -------------------------------------------------------------------- */
1167
1425
/*      Get the segment count, and grow the segmentinfo array           */
1168
1426
/*      accordingly.                                                    */
1169
1427
/* -------------------------------------------------------------------- */
1170
 
    VSIFSeekL( psFile->fp, nOffset, SEEK_SET );
1171
 
    VSIFReadL( szTemp, 1, 3, psFile->fp );
1172
 
    szTemp[3] = '\0';
 
1428
    if ( nFileHeaderLen < nOffset + 3 )
 
1429
    {
 
1430
        CPLError(CE_Failure, CPLE_AppDefined, "Not enough bytes to read segment count");
 
1431
        return -1;
 
1432
    }
1173
1433
 
 
1434
    NITFGetField( szTemp, psFile->pachHeader, nOffset, 3 );
1174
1435
    nCount = atoi(szTemp);
1175
1436
 
1176
1437
    if( nCount <= 0 )
1177
1438
        return nOffset + 3;
1178
1439
 
 
1440
    nSegDefSize = nCount * (nHeaderLenSize + nDataLenSize);
 
1441
    if ( nFileHeaderLen < nOffset + 3 + nSegDefSize)
 
1442
    {
 
1443
        CPLError(CE_Failure, CPLE_AppDefined, "Not enough bytes to read segment info");
 
1444
        return -1;
 
1445
    }
 
1446
 
1179
1447
    if( psFile->pasSegmentInfo == NULL )
1180
1448
        psFile->pasSegmentInfo = (NITFSegmentInfo *)
1181
1449
            CPLMalloc( sizeof(NITFSegmentInfo) * nCount );
1186
1454
                        * (psFile->nSegmentCount+nCount) );
1187
1455
 
1188
1456
/* -------------------------------------------------------------------- */
1189
 
/*      Read the detailed information about the segments.               */
1190
 
/* -------------------------------------------------------------------- */
1191
 
    nSegDefSize = nCount * (nHeaderLenSize + nDataLenSize);
1192
 
    pachSegDef = (char *) CPLMalloc(nCount * (nHeaderLenSize + nDataLenSize));
1193
 
    
1194
 
    if((int)VSIFReadL( pachSegDef, 1, nSegDefSize, psFile->fp) != nSegDefSize)
1195
 
    {
1196
 
        CPLError(CE_Failure, CPLE_AppDefined, "Cannot read segment info");
1197
 
        CPLFree( pachSegDef );
1198
 
        return nOffset + 3;
1199
 
    }
1200
 
 
1201
 
/* -------------------------------------------------------------------- */
1202
1457
/*      Collect detailed about segment.                                 */
1203
1458
/* -------------------------------------------------------------------- */
1204
1459
    for( iSegment = 0; iSegment < nCount; iSegment++ )
1213
1468
        psInfo->nCCS_C = -1;
1214
1469
 
1215
1470
        psInfo->hAccess = NULL;
1216
 
        strcpy( psInfo->szSegmentType, pszType );
 
1471
        strcpy( psInfo->szSegmentType, szType );
1217
1472
        
1218
1473
        psInfo->nSegmentHeaderSize = 
1219
 
            atoi(NITFGetField(szTemp,pachSegDef, 
1220
 
                              iSegment * (nHeaderLenSize+nDataLenSize), 
 
1474
            atoi(NITFGetField(szTemp, psFile->pachHeader, 
 
1475
                              nOffset + 3 + iSegment * (nHeaderLenSize+nDataLenSize), 
1221
1476
                              nHeaderLenSize));
1222
1477
        if (strchr(szTemp, '-') != NULL) /* Avoid negative values being mapped to huge unsigned values */
1223
1478
        {
1224
 
            CPLError(CE_Failure, CPLE_AppDefined, "Invalid segment info");
1225
 
            break;
1226
 
        }
 
1479
            CPLError(CE_Failure, CPLE_AppDefined, "Invalid segment header size : %s", szTemp);
 
1480
            return -1;
 
1481
        }
 
1482
 
 
1483
        if (strcmp(szType, "DE") == 0 && psInfo->nSegmentHeaderSize == 207)
 
1484
        {
 
1485
            /* DMAAC A.TOC files have a wrong header size. It says 207 but it is 209 really */
 
1486
            psInfo->nSegmentHeaderSize = 209;
 
1487
        }
 
1488
 
1227
1489
        psInfo->nSegmentSize = 
1228
 
            CPLScanUIntBig(NITFGetField(szTemp,pachSegDef, 
1229
 
                              iSegment * (nHeaderLenSize+nDataLenSize) 
 
1490
            CPLScanUIntBig(NITFGetField(szTemp,psFile->pachHeader, 
 
1491
                              nOffset + 3 + iSegment * (nHeaderLenSize+nDataLenSize) 
1230
1492
                              + nHeaderLenSize,
1231
1493
                              nDataLenSize), nDataLenSize);
1232
1494
        if (strchr(szTemp, '-') != NULL) /* Avoid negative values being mapped to huge unsigned values */
1233
1495
        {
1234
 
            CPLError(CE_Failure, CPLE_AppDefined, "Invalid segment info");
1235
 
            break;
 
1496
            CPLError(CE_Failure, CPLE_AppDefined, "Invalid segment size : %s", szTemp);
 
1497
            return -1;
1236
1498
        }
1237
1499
 
1238
1500
        psInfo->nSegmentHeaderStart = *pnNextData;
1242
1504
        psFile->nSegmentCount++;
1243
1505
    }
1244
1506
 
1245
 
    CPLFree( pachSegDef );
1246
 
 
1247
1507
    return nOffset + nSegDefSize + 3;
1248
1508
}
1249
1509
 
1284
1544
                     nThisTRESize, szTemp);
1285
1545
            return NULL;
1286
1546
        }
 
1547
        if (nTREBytes - 11 < nThisTRESize)
 
1548
        {
 
1549
            NITFGetField(szTemp, pszTREData, 0, 6 );
 
1550
            if (EQUALN(szTemp, "RPFIMG",6))
 
1551
            {
 
1552
                /* See #3848 */
 
1553
                CPLDebug("NITF", "Adjusting RPFIMG TRE size from %d to %d, which is the remaining size", nThisTRESize, nTREBytes - 11);
 
1554
                nThisTRESize = nTREBytes - 11;
 
1555
            }
 
1556
            else
 
1557
            {
 
1558
                CPLError(CE_Failure, CPLE_AppDefined,
 
1559
                        "Cannot read %s TRE. Not enough bytes : remaining %d, expected %d",
 
1560
                        szTemp, nTREBytes - 11, nThisTRESize);
 
1561
                return NULL;
 
1562
            }
 
1563
        }
1287
1564
 
1288
1565
        if( EQUALN(pszTREData,pszTag,6) )
1289
1566
        {
1321
1598
                     nThisTRESize, szTemp);
1322
1599
            return NULL;
1323
1600
        }
 
1601
        if (nTREBytes - 11 < nThisTRESize)
 
1602
        {
 
1603
            NITFGetField(szTemp, pszTREData, 0, 6 );
 
1604
            if (EQUALN(szTemp, "RPFIMG",6))
 
1605
            {
 
1606
                /* See #3848 */
 
1607
                CPLDebug("NITF", "Adjusting RPFIMG TRE size from %d to %d, which is the remaining size", nThisTRESize, nTREBytes - 11);
 
1608
                nThisTRESize = nTREBytes - 11;
 
1609
            }
 
1610
            else
 
1611
            {
 
1612
                CPLError(CE_Failure, CPLE_AppDefined,
 
1613
                        "Cannot read %s TRE. Not enough bytes : remaining %d, expected %d",
 
1614
                        szTemp, nTREBytes - 11, nThisTRESize);
 
1615
                return NULL;
 
1616
            }
 
1617
        }
1324
1618
 
1325
1619
        if( EQUALN(pszTREData,pszTag,6) )
1326
1620
        {
1352
1646
 
1353
1647
{
1354
1648
    char szWork[400];
 
1649
    char* pszWork;
 
1650
 
 
1651
    if (nLength >= sizeof(szWork) - 1)
 
1652
        pszWork = (char*)CPLMalloc(nLength + 1);
 
1653
    else
 
1654
        pszWork = szWork;
1355
1655
 
1356
1656
    /* trim white space */
1357
1657
    while( nLength > 0 && pachHeader[nStart + nLength - 1] == ' ' )
1358
1658
        nLength--;
1359
1659
 
1360
 
    memcpy( szWork, pachHeader + nStart, nLength );
1361
 
    szWork[nLength] = '\0';
1362
 
 
1363
 
    *ppapszMetadata = CSLSetNameValue( *ppapszMetadata, pszName, szWork );
 
1660
    memcpy( pszWork, pachHeader + nStart, nLength );
 
1661
    pszWork[nLength] = '\0';
 
1662
 
 
1663
    *ppapszMetadata = CSLSetNameValue( *ppapszMetadata, pszName, pszWork );
 
1664
 
 
1665
    if (szWork != pszWork)
 
1666
        CPLFree(pszWork);
1364
1667
}
1365
1668
                          
1366
1669
/************************************************************************/
1644
1947
                {
1645
1948
                    psSegInfo->nCCS_R = psOtherSegInfo->nLOC_R + psSegInfo->nLOC_R;
1646
1949
                    psSegInfo->nCCS_C = psOtherSegInfo->nLOC_C + psSegInfo->nLOC_C;
1647
 
                    bMadeProgress = TRUE;
 
1950
                    if ( psSegInfo->nCCS_R != -1 )
 
1951
                        bMadeProgress = TRUE;
1648
1952
                }
1649
1953
                else
1650
1954
                {
1651
1955
                    bSuccess = FALSE;
1652
1956
                }
 
1957
                break;
1653
1958
            }
1654
1959
        }
1655
1960
 
1667
1972
    else
1668
1973
        return NITFReconcileAttachments( psFile );
1669
1974
}
 
1975
 
 
1976
/************************************************************************/
 
1977
/*                        NITFFindValFromEnd()                          */
 
1978
/************************************************************************/
 
1979
 
 
1980
static const char* NITFFindValFromEnd(char** papszMD,
 
1981
                                      int nMDSize,
 
1982
                                      const char* pszVar,
 
1983
                                      const char* pszDefault)
 
1984
{
 
1985
    int nVarLen = strlen(pszVar);
 
1986
    int nIter = nMDSize-1;
 
1987
    for(;nIter >= 0;nIter--)
 
1988
    {
 
1989
        if (strncmp(papszMD[nIter], pszVar, nVarLen) == 0 &&
 
1990
            papszMD[nIter][nVarLen] == '=')
 
1991
            return papszMD[nIter] + nVarLen + 1;
 
1992
    }
 
1993
    return NULL;
 
1994
}
 
1995
 
 
1996
/************************************************************************/
 
1997
/*                  NITFGenericMetadataReadTREInternal()                */
 
1998
/************************************************************************/
 
1999
 
 
2000
static char** NITFGenericMetadataReadTREInternal(char **papszMD,
 
2001
                                                 int* pnMDSize,
 
2002
                                                 int* pnMDAlloc,
 
2003
                                                 CPLXMLNode* psOutXMLNode,
 
2004
                                                 const char* pszTREName,
 
2005
                                                 const char *pachTRE,
 
2006
                                                 int nTRESize,
 
2007
                                                 CPLXMLNode* psTreNode,
 
2008
                                                 int *pnTreOffset,
 
2009
                                                 const char* pszMDPrefix,
 
2010
                                                 int *pbError)
 
2011
{
 
2012
    CPLXMLNode* psIter;
 
2013
    for(psIter = psTreNode->psChild;
 
2014
        psIter != NULL && *pbError == FALSE;
 
2015
        psIter = psIter->psNext)
 
2016
    {
 
2017
        if (psIter->eType == CXT_Element &&
 
2018
            psIter->pszValue != NULL &&
 
2019
            strcmp(psIter->pszValue, "field") == 0)
 
2020
        {
 
2021
            const char* pszName = CPLGetXMLValue(psIter, "name", NULL);
 
2022
            const char* pszLongName = CPLGetXMLValue(psIter, "longname", NULL);
 
2023
            const char* pszLength = CPLGetXMLValue(psIter, "length", NULL);
 
2024
            int nLength = -1;
 
2025
            if (pszLength != NULL)
 
2026
                nLength = atoi(pszLength);
 
2027
            else
 
2028
            {
 
2029
                const char* pszLengthVar = CPLGetXMLValue(psIter, "length_var", NULL);
 
2030
                if (pszLengthVar != NULL)
 
2031
                {
 
2032
                    char** papszMDIter = papszMD;
 
2033
                    while(papszMDIter != NULL && *papszMDIter != NULL)
 
2034
                    {
 
2035
                        if (strstr(*papszMDIter, pszLengthVar) != NULL)
 
2036
                        {
 
2037
                            const char* pszEqual = strchr(*papszMDIter, '=');
 
2038
                            if (pszEqual != NULL)
 
2039
                            {
 
2040
                                nLength = atoi(pszEqual + 1);
 
2041
                                break;
 
2042
                            }
 
2043
                        }
 
2044
                        papszMDIter ++;
 
2045
                    }
 
2046
                }
 
2047
            }
 
2048
            if (pszName != NULL && nLength > 0)
 
2049
            {
 
2050
                char* pszMDItemName;
 
2051
                char** papszTmp = NULL;
 
2052
 
 
2053
                if (*pnTreOffset + nLength > nTRESize)
 
2054
                {
 
2055
                    *pbError = TRUE;
 
2056
                    CPLError( CE_Warning, CPLE_AppDefined,
 
2057
                              "Not enough bytes when reading %s TRE "
 
2058
                              "(at least %d needed, only %d available)",
 
2059
                              pszTREName, *pnTreOffset + nLength, nTRESize );
 
2060
                    break;
 
2061
                }
 
2062
 
 
2063
                pszMDItemName = CPLStrdup(
 
2064
                            CPLSPrintf("%s%s", pszMDPrefix, pszName));
 
2065
 
 
2066
                NITFExtractMetadata( &papszTmp, pachTRE, *pnTreOffset,
 
2067
                                     nLength, pszMDItemName );
 
2068
                if (*pnMDSize + 1 >= *pnMDAlloc)
 
2069
                {
 
2070
                    *pnMDAlloc = (*pnMDAlloc * 4 / 3) + 32;
 
2071
                    papszMD = (char**)CPLRealloc(papszMD, *pnMDAlloc * sizeof(char**));
 
2072
                }
 
2073
                papszMD[*pnMDSize] = papszTmp[0];
 
2074
                papszMD[(*pnMDSize) + 1] = NULL;
 
2075
                (*pnMDSize) ++;
 
2076
                papszTmp[0] = NULL;
 
2077
                CPLFree(papszTmp);
 
2078
 
 
2079
                if (psOutXMLNode != NULL)
 
2080
                {
 
2081
                    const char* pszVal = strchr(papszMD[(*pnMDSize) - 1], '=') + 1;
 
2082
                    CPLXMLNode* psFieldNode;
 
2083
                    CPLXMLNode* psNameNode;
 
2084
                    CPLXMLNode* psValueNode;
 
2085
 
 
2086
                    CPLAssert(pszVal != NULL);
 
2087
                    psFieldNode =
 
2088
                        CPLCreateXMLNode(psOutXMLNode, CXT_Element, "field");
 
2089
                    psNameNode =
 
2090
                        CPLCreateXMLNode(psFieldNode, CXT_Attribute, "name");
 
2091
                    psValueNode =
 
2092
                        CPLCreateXMLNode(psFieldNode, CXT_Attribute, "value");
 
2093
                    CPLCreateXMLNode(psNameNode, CXT_Text,
 
2094
                       (pszName[0] || pszLongName == NULL) ? pszName : pszLongName);
 
2095
                    CPLCreateXMLNode(psValueNode, CXT_Text, pszVal);
 
2096
                }
 
2097
 
 
2098
                CPLFree(pszMDItemName);
 
2099
 
 
2100
                *pnTreOffset += nLength;
 
2101
            }
 
2102
            else if (nLength > 0)
 
2103
            {
 
2104
                *pnTreOffset += nLength;
 
2105
            }
 
2106
            else
 
2107
            {
 
2108
                *pbError = TRUE;
 
2109
                CPLError( CE_Warning, CPLE_AppDefined,
 
2110
                          "Invalid item construct in %s TRE in XML ressource",
 
2111
                          pszTREName );
 
2112
                break;
 
2113
            }
 
2114
        }
 
2115
        else if (psIter->eType == CXT_Element &&
 
2116
                 psIter->pszValue != NULL &&
 
2117
                 strcmp(psIter->pszValue, "loop") == 0)
 
2118
        {
 
2119
            const char* pszCounter = CPLGetXMLValue(psIter, "counter", NULL);
 
2120
            const char* pszIterations = CPLGetXMLValue(psIter, "iterations", NULL);
 
2121
            const char* pszFormula = CPLGetXMLValue(psIter, "formula", NULL);
 
2122
            const char* pszMDSubPrefix = CPLGetXMLValue(psIter, "md_prefix", NULL);
 
2123
            int nIterations = -1;
 
2124
 
 
2125
            if (pszCounter != NULL)
 
2126
            {
 
2127
                char* pszMDItemName = CPLStrdup(
 
2128
                            CPLSPrintf("%s%s", pszMDPrefix, pszCounter));
 
2129
                nIterations = atoi(NITFFindValFromEnd(papszMD, *pnMDSize, pszMDItemName, "-1"));
 
2130
                CPLFree(pszMDItemName);
 
2131
                if (nIterations < 0)
 
2132
                {
 
2133
                    CPLError( CE_Warning, CPLE_AppDefined,
 
2134
                            "Invalid loop construct in %s TRE in XML ressource : "
 
2135
                            "invalid 'counter' %s",
 
2136
                            pszTREName, pszCounter );
 
2137
                    *pbError = TRUE;
 
2138
                    break;
 
2139
                }
 
2140
            }
 
2141
            else if (pszIterations != NULL)
 
2142
            {
 
2143
                nIterations = atoi(pszIterations);
 
2144
            }
 
2145
            else if (pszFormula != NULL &&
 
2146
                     strcmp(pszFormula, "(NPART+1)*(NPART)/2") == 0)
 
2147
            {
 
2148
                char* pszMDItemName = CPLStrdup(
 
2149
                            CPLSPrintf("%s%s", pszMDPrefix, "NPART"));
 
2150
                int NPART = atoi(NITFFindValFromEnd(papszMD, *pnMDSize, pszMDItemName, "-1"));
 
2151
                CPLFree(pszMDItemName);
 
2152
                if (NPART < 0)
 
2153
                {
 
2154
                    CPLError( CE_Warning, CPLE_AppDefined,
 
2155
                            "Invalid loop construct in %s TRE in XML ressource : "
 
2156
                            "invalid 'counter' %s",
 
2157
                            pszTREName, "NPART" );
 
2158
                    *pbError = TRUE;
 
2159
                    break;
 
2160
                }
 
2161
                nIterations = NPART * (NPART + 1) / 2;
 
2162
            }
 
2163
            else if (pszFormula != NULL &&
 
2164
                     strcmp(pszFormula, "(NUMOPG+1)*(NUMOPG)/2") == 0)
 
2165
            {
 
2166
                char* pszMDItemName = CPLStrdup(
 
2167
                            CPLSPrintf("%s%s", pszMDPrefix, "NUMOPG"));
 
2168
                int NUMOPG = atoi(NITFFindValFromEnd(papszMD, *pnMDSize, pszMDItemName, "-1"));
 
2169
                CPLFree(pszMDItemName);
 
2170
                if (NUMOPG < 0)
 
2171
                {
 
2172
                    CPLError( CE_Warning, CPLE_AppDefined,
 
2173
                            "Invalid loop construct in %s TRE in XML ressource : "
 
2174
                            "invalid 'counter' %s",
 
2175
                            pszTREName, "NUMOPG" );
 
2176
                    *pbError = TRUE;
 
2177
                    break;
 
2178
                }
 
2179
                nIterations = NUMOPG * (NUMOPG + 1) / 2;
 
2180
            }
 
2181
            else if (pszFormula != NULL &&
 
2182
                     strcmp(pszFormula, "NPAR*NPARO") == 0)
 
2183
            {
 
2184
                char* pszMDNPARName = CPLStrdup(
 
2185
                            CPLSPrintf("%s%s", pszMDPrefix, "NPAR"));
 
2186
                int NPAR = atoi(NITFFindValFromEnd(papszMD, *pnMDSize, pszMDNPARName, "-1"));
 
2187
                char* pszMDNPAROName = CPLStrdup(
 
2188
                            CPLSPrintf("%s%s", pszMDPrefix, "NPARO"));
 
2189
                int NPARO= atoi(NITFFindValFromEnd(papszMD, *pnMDSize, pszMDNPAROName, "-1"));
 
2190
                CPLFree(pszMDNPARName);
 
2191
                CPLFree(pszMDNPAROName);
 
2192
                if (NPAR < 0)
 
2193
                {
 
2194
                    CPLError( CE_Warning, CPLE_AppDefined,
 
2195
                            "Invalid loop construct in %s TRE in XML ressource : "
 
2196
                            "invalid 'counter' %s",
 
2197
                            pszTREName, "NPAR" );
 
2198
                    *pbError = TRUE;
 
2199
                    break;
 
2200
                }
 
2201
                if (NPARO < 0)
 
2202
                {
 
2203
                    CPLError( CE_Warning, CPLE_AppDefined,
 
2204
                            "Invalid loop construct in %s TRE in XML ressource : "
 
2205
                            "invalid 'counter' %s",
 
2206
                            pszTREName, "NPAR0" );
 
2207
                    *pbError = TRUE;
 
2208
                    break;
 
2209
                }
 
2210
                nIterations = NPAR*NPARO;
 
2211
            }
 
2212
            else if (pszFormula != NULL &&
 
2213
                     strcmp(pszFormula, "NPLN-1") == 0)
 
2214
            {
 
2215
                char* pszMDItemName = CPLStrdup(
 
2216
                            CPLSPrintf("%s%s", pszMDPrefix, "NPLN"));
 
2217
                int NPLN = atoi(NITFFindValFromEnd(papszMD, *pnMDSize, pszMDItemName, "-1"));
 
2218
                CPLFree(pszMDItemName);
 
2219
                if (NPLN < 0)
 
2220
                {
 
2221
                    CPLError( CE_Warning, CPLE_AppDefined,
 
2222
                            "Invalid loop construct in %s TRE in XML ressource : "
 
2223
                            "invalid 'counter' %s",
 
2224
                            pszTREName, "NPLN" );
 
2225
                    *pbError = TRUE;
 
2226
                    break;
 
2227
                }
 
2228
                nIterations = NPLN-1;
 
2229
            }
 
2230
            else if (pszFormula != NULL &&
 
2231
                     strcmp(pszFormula, "NXPTS*NYPTS") == 0)
 
2232
            {
 
2233
                char* pszMDNPARName = CPLStrdup(
 
2234
                            CPLSPrintf("%s%s", pszMDPrefix, "NXPTS"));
 
2235
                int NXPTS = atoi(NITFFindValFromEnd(papszMD, *pnMDSize, pszMDNPARName, "-1"));
 
2236
                char* pszMDNPAROName = CPLStrdup(
 
2237
                            CPLSPrintf("%s%s", pszMDPrefix, "NYPTS"));
 
2238
                int NYPTS= atoi(NITFFindValFromEnd(papszMD, *pnMDSize, pszMDNPAROName, "-1"));
 
2239
                CPLFree(pszMDNPARName);
 
2240
                CPLFree(pszMDNPAROName);
 
2241
                if (NXPTS < 0)
 
2242
                {
 
2243
                    CPLError( CE_Warning, CPLE_AppDefined,
 
2244
                            "Invalid loop construct in %s TRE in XML ressource : "
 
2245
                            "invalid 'counter' %s",
 
2246
                            pszTREName, "NXPTS" );
 
2247
                    *pbError = TRUE;
 
2248
                    break;
 
2249
                }
 
2250
                if (NYPTS < 0)
 
2251
                {
 
2252
                    CPLError( CE_Warning, CPLE_AppDefined,
 
2253
                            "Invalid loop construct in %s TRE in XML ressource : "
 
2254
                            "invalid 'counter' %s",
 
2255
                            pszTREName, "NYPTS" );
 
2256
                    *pbError = TRUE;
 
2257
                    break;
 
2258
                }
 
2259
                nIterations = NXPTS*NYPTS;
 
2260
            }
 
2261
            else
 
2262
            {
 
2263
                CPLError( CE_Warning, CPLE_AppDefined,
 
2264
                          "Invalid loop construct in %s TRE in XML ressource : "
 
2265
                          "missing or invalid 'counter' or 'iterations' or 'formula'",
 
2266
                          pszTREName );
 
2267
                *pbError = TRUE;
 
2268
                break;
 
2269
            }
 
2270
 
 
2271
            if (nIterations > 0)
 
2272
            {
 
2273
                int iIter;
 
2274
                const char* pszPercent;
 
2275
                int bHasValidPercentD = FALSE;
 
2276
                CPLXMLNode* psRepeatedNode = NULL;
 
2277
                CPLXMLNode* psLastChild = NULL;
 
2278
 
 
2279
                /* Check that md_prefix has one and only %XXXXd pattern */
 
2280
                if (pszMDSubPrefix != NULL &&
 
2281
                    (pszPercent = strchr(pszMDSubPrefix, '%')) != NULL &&
 
2282
                    strchr(pszPercent+1,'%') == NULL)
 
2283
                {
 
2284
                    const char* pszIter = pszPercent + 1;
 
2285
                    while(*pszIter != '\0')
 
2286
                    {
 
2287
                        if (*pszIter >= '0' && *pszIter <= '9')
 
2288
                            pszIter ++;
 
2289
                        else if (*pszIter == 'd')
 
2290
                        {
 
2291
                            bHasValidPercentD = atoi(pszPercent + 1) <= 10;
 
2292
                            break;
 
2293
                        }
 
2294
                        else
 
2295
                            break;
 
2296
                    }
 
2297
                }
 
2298
 
 
2299
                if (psOutXMLNode != NULL)
 
2300
                {
 
2301
                    CPLXMLNode* psNumberNode;
 
2302
                    CPLXMLNode* psNameNode;
 
2303
                    const char* pszName = CPLGetXMLValue(psIter, "name", NULL);
 
2304
                    psRepeatedNode = CPLCreateXMLNode(psOutXMLNode, CXT_Element, "repeated");
 
2305
                    if (pszName)
 
2306
                    {
 
2307
                        psNameNode = CPLCreateXMLNode(psRepeatedNode, CXT_Attribute, "name");
 
2308
                        CPLCreateXMLNode(psNameNode, CXT_Text, pszName);
 
2309
                    }
 
2310
                    psNumberNode = CPLCreateXMLNode(psRepeatedNode, CXT_Attribute, "number");
 
2311
                    CPLCreateXMLNode(psNumberNode, CXT_Text, CPLSPrintf("%d", nIterations));
 
2312
 
 
2313
                    psLastChild = psRepeatedNode->psChild;
 
2314
                    while(psLastChild->psNext != NULL)
 
2315
                        psLastChild = psLastChild->psNext;
 
2316
                }
 
2317
 
 
2318
                for(iIter = 0; iIter < nIterations && *pbError == FALSE; iIter++)
 
2319
                {
 
2320
                    char* pszMDNewPrefix = NULL;
 
2321
                    CPLXMLNode* psGroupNode = NULL;
 
2322
                    if (pszMDSubPrefix != NULL)
 
2323
                    {
 
2324
                        if (bHasValidPercentD)
 
2325
                        {
 
2326
                            char* szTmp = (char*)CPLMalloc(
 
2327
                                            strlen(pszMDSubPrefix) + 10 + 1);
 
2328
                            sprintf(szTmp, pszMDSubPrefix, iIter + 1);
 
2329
                            pszMDNewPrefix = CPLStrdup(CPLSPrintf("%s%s",
 
2330
                                                       pszMDPrefix, szTmp));
 
2331
                            CPLFree(szTmp);
 
2332
                        }
 
2333
                        else
 
2334
                            pszMDNewPrefix = CPLStrdup(CPLSPrintf("%s%s%04d_",
 
2335
                                      pszMDPrefix, pszMDSubPrefix, iIter + 1));
 
2336
                    }
 
2337
                    else
 
2338
                        pszMDNewPrefix = CPLStrdup(CPLSPrintf("%s%04d_",
 
2339
                                                   pszMDPrefix, iIter + 1));
 
2340
 
 
2341
                    if (psRepeatedNode != NULL)
 
2342
                    {
 
2343
                        CPLXMLNode* psIndexNode;
 
2344
                        psGroupNode = CPLCreateXMLNode(NULL, CXT_Element, "group");
 
2345
                        CPLAssert(psLastChild->psNext == NULL);
 
2346
                        psLastChild->psNext = psGroupNode;
 
2347
                        psLastChild = psGroupNode;
 
2348
                        psIndexNode = CPLCreateXMLNode(psGroupNode, CXT_Attribute, "index");
 
2349
                        CPLCreateXMLNode(psIndexNode, CXT_Text, CPLSPrintf("%d", iIter));
 
2350
                    }
 
2351
 
 
2352
                    papszMD = NITFGenericMetadataReadTREInternal(papszMD,
 
2353
                                                                 pnMDSize,
 
2354
                                                                 pnMDAlloc,
 
2355
                                                                 psGroupNode,
 
2356
                                                                 pszTREName,
 
2357
                                                                 pachTRE,
 
2358
                                                                 nTRESize,
 
2359
                                                                 psIter,
 
2360
                                                                 pnTreOffset,
 
2361
                                                                 pszMDNewPrefix,
 
2362
                                                                 pbError);
 
2363
                    CPLFree(pszMDNewPrefix);
 
2364
                }
 
2365
            }
 
2366
        }
 
2367
        else if (psIter->eType == CXT_Element &&
 
2368
                 psIter->pszValue != NULL &&
 
2369
                 strcmp(psIter->pszValue, "if") == 0)
 
2370
        {
 
2371
            const char* pszCond = CPLGetXMLValue(psIter, "cond", NULL);
 
2372
            const char* pszEqual = NULL;
 
2373
            if (pszCond != NULL && strcmp(pszCond, "QSS!=U AND QOD!=Y") == 0)
 
2374
            {
 
2375
                char* pszQSSName = CPLStrdup(
 
2376
                            CPLSPrintf("%s%s", pszMDPrefix, "QSS"));
 
2377
                char* pszQODName = CPLStrdup(
 
2378
                            CPLSPrintf("%s%s", pszMDPrefix, "QOD"));
 
2379
                const char* pszQSSVal = NITFFindValFromEnd(papszMD, *pnMDSize, pszQSSName, NULL);
 
2380
                const char* pszQODVal = NITFFindValFromEnd(papszMD, *pnMDSize, pszQODName, NULL);
 
2381
                if (pszQSSVal == NULL)
 
2382
                {
 
2383
                    CPLDebug("NITF", "Cannot find if cond variable %s", "QSS");
 
2384
                }
 
2385
                else if (pszQODVal == NULL)
 
2386
                {
 
2387
                    CPLDebug("NITF", "Cannot find if cond variable %s", "QOD");
 
2388
                }
 
2389
                else if (strcmp(pszQSSVal, "U") != 0 && strcmp(pszQODVal, "Y") != 0)
 
2390
                {
 
2391
                    papszMD = NITFGenericMetadataReadTREInternal(papszMD,
 
2392
                                                                 pnMDSize,
 
2393
                                                                 pnMDAlloc,
 
2394
                                                                 psOutXMLNode,
 
2395
                                                                 pszTREName,
 
2396
                                                                 pachTRE,
 
2397
                                                                 nTRESize,
 
2398
                                                                 psIter,
 
2399
                                                                 pnTreOffset,
 
2400
                                                                 pszMDPrefix,
 
2401
                                                                 pbError);
 
2402
                }
 
2403
                CPLFree(pszQSSName);
 
2404
                CPLFree(pszQODName);
 
2405
            }
 
2406
            else if (pszCond != NULL && (pszEqual = strchr(pszCond, '=')) != NULL)
 
2407
            {
 
2408
                char* pszCondVar = (char*)CPLMalloc(pszEqual - pszCond + 1);
 
2409
                const char* pszCondExpectedVal = pszEqual + 1;
 
2410
                char* pszMDItemName;
 
2411
                const char* pszCondVal;
 
2412
                int bTestEqual = TRUE;
 
2413
                memcpy(pszCondVar, pszCond, pszEqual - pszCond);
 
2414
                if (pszEqual - pszCond > 1 && pszCondVar[pszEqual - pszCond - 1] == '!')
 
2415
                {
 
2416
                    bTestEqual = FALSE;
 
2417
                    pszCondVar[pszEqual - pszCond - 1] = '\0';
 
2418
                }
 
2419
                pszCondVar[pszEqual - pszCond] = '\0';
 
2420
                pszMDItemName = CPLStrdup(
 
2421
                            CPLSPrintf("%s%s", pszMDPrefix, pszCondVar));
 
2422
                pszCondVal = NITFFindValFromEnd(papszMD, *pnMDSize, pszMDItemName, NULL);
 
2423
                if (pszCondVal == NULL)
 
2424
                {
 
2425
                    CPLDebug("NITF", "Cannot find if cond variable %s",
 
2426
                             pszMDItemName);
 
2427
                }
 
2428
                else if ((bTestEqual && strcmp(pszCondVal, pszCondExpectedVal) == 0) ||
 
2429
                         (!bTestEqual && strcmp(pszCondVal, pszCondExpectedVal) != 0))
 
2430
                {
 
2431
                    papszMD = NITFGenericMetadataReadTREInternal(papszMD,
 
2432
                                                                 pnMDSize,
 
2433
                                                                 pnMDAlloc,
 
2434
                                                                 psOutXMLNode,
 
2435
                                                                 pszTREName,
 
2436
                                                                 pachTRE,
 
2437
                                                                 nTRESize,
 
2438
                                                                 psIter,
 
2439
                                                                 pnTreOffset,
 
2440
                                                                 pszMDPrefix,
 
2441
                                                                 pbError);
 
2442
                }
 
2443
                CPLFree(pszMDItemName);
 
2444
                CPLFree(pszCondVar);
 
2445
            }
 
2446
            else
 
2447
            {
 
2448
                CPLError( CE_Warning, CPLE_AppDefined,
 
2449
                          "Invalid if construct in %s TRE in XML ressource : "
 
2450
                          "missing or invalid 'cond' attribute",
 
2451
                          pszTREName );
 
2452
                *pbError = TRUE;
 
2453
                break;
 
2454
            }
 
2455
        }
 
2456
        else if (psIter->eType == CXT_Element &&
 
2457
                 psIter->pszValue != NULL &&
 
2458
                 strcmp(psIter->pszValue, "if_remaining_bytes") == 0)
 
2459
        {
 
2460
            if (*pnTreOffset < nTRESize)
 
2461
            {
 
2462
                papszMD = NITFGenericMetadataReadTREInternal(papszMD,
 
2463
                                                             pnMDSize,
 
2464
                                                             pnMDAlloc,
 
2465
                                                             psOutXMLNode,
 
2466
                                                             pszTREName,
 
2467
                                                             pachTRE,
 
2468
                                                             nTRESize,
 
2469
                                                             psIter,
 
2470
                                                             pnTreOffset,
 
2471
                                                             pszMDPrefix,
 
2472
                                                             pbError);
 
2473
        }
 
2474
        }
 
2475
        else
 
2476
        {
 
2477
            //CPLDebug("NITF", "Unknown element : %s", psIter->pszValue ? psIter->pszValue : "null");
 
2478
        }
 
2479
    }
 
2480
    return papszMD;
 
2481
}
 
2482
 
 
2483
/************************************************************************/
 
2484
/*                      NITFGenericMetadataReadTRE()                    */
 
2485
/************************************************************************/
 
2486
 
 
2487
static
 
2488
char **NITFGenericMetadataReadTRE(char **papszMD,
 
2489
                                  const char* pszTREName,
 
2490
                                  const char *pachTRE,
 
2491
                                  int nTRESize,
 
2492
                                  CPLXMLNode* psTreNode)
 
2493
{
 
2494
    int nTreLength, nTreMinLength = -1, nTreMaxLength = -1;
 
2495
    int bError = FALSE;
 
2496
    int nTreOffset = 0;
 
2497
    const char* pszMDPrefix;
 
2498
    int nMDSize, nMDAlloc;
 
2499
 
 
2500
    nTreLength = atoi(CPLGetXMLValue(psTreNode, "length", "-1"));
 
2501
    nTreMinLength = atoi(CPLGetXMLValue(psTreNode, "minlength", "-1"));
 
2502
    nTreMaxLength = atoi(CPLGetXMLValue(psTreNode, "maxlength", "-1"));
 
2503
 
 
2504
    if( (nTreLength > 0 && nTRESize != nTreLength) ||
 
2505
        (nTreMinLength > 0 && nTRESize < nTreMinLength) )
 
2506
    {
 
2507
        CPLError( CE_Warning, CPLE_AppDefined,
 
2508
                  "%s TRE wrong size, ignoring.", pszTREName );
 
2509
        return papszMD;
 
2510
    }
 
2511
 
 
2512
    pszMDPrefix = CPLGetXMLValue(psTreNode, "md_prefix", "");
 
2513
 
 
2514
    nMDSize = nMDAlloc = CSLCount(papszMD);
 
2515
 
 
2516
    papszMD = NITFGenericMetadataReadTREInternal(papszMD,
 
2517
                                                 &nMDSize,
 
2518
                                                 &nMDAlloc,
 
2519
                                                 NULL,
 
2520
                                                 pszTREName,
 
2521
                                                 pachTRE,
 
2522
                                                 nTRESize,
 
2523
                                                 psTreNode,
 
2524
                                                 &nTreOffset,
 
2525
                                                 pszMDPrefix,
 
2526
                                                 &bError);
 
2527
 
 
2528
    if (bError == FALSE && nTreLength > 0 && nTreOffset != nTreLength)
 
2529
    {
 
2530
        CPLError( CE_Warning, CPLE_AppDefined,
 
2531
                  "Inconsistant declaration of %s TRE",
 
2532
                  pszTREName );
 
2533
    }
 
2534
    if (nTreOffset < nTRESize)
 
2535
        CPLDebug("NITF", "%d remaining bytes at end of %s TRE",
 
2536
                 nTRESize -nTreOffset, pszTREName);
 
2537
 
 
2538
    return papszMD;
 
2539
}
 
2540
 
 
2541
 
 
2542
/************************************************************************/
 
2543
/*                           NITFLoadXMLSpec()                          */
 
2544
/************************************************************************/
 
2545
 
 
2546
#define NITF_SPEC_FILE "nitf_spec.xml"
 
2547
 
 
2548
static CPLXMLNode* NITFLoadXMLSpec(NITFFile* psFile)
 
2549
{
 
2550
 
 
2551
    if (psFile->psNITFSpecNode == NULL)
 
2552
    {
 
2553
        const char* pszXMLDescFilename = CPLFindFile("gdal", NITF_SPEC_FILE);
 
2554
        if (pszXMLDescFilename == NULL)
 
2555
        {
 
2556
            CPLDebug("NITF", "Cannot find XML file : %s", NITF_SPEC_FILE);
 
2557
            return NULL;
 
2558
        }
 
2559
        psFile->psNITFSpecNode = CPLParseXMLFile(pszXMLDescFilename);
 
2560
        if (psFile->psNITFSpecNode == NULL)
 
2561
        {
 
2562
            CPLDebug("NITF", "Invalid XML file : %s", pszXMLDescFilename);
 
2563
            return NULL;
 
2564
        }
 
2565
    }
 
2566
 
 
2567
    return psFile->psNITFSpecNode;
 
2568
}
 
2569
 
 
2570
/************************************************************************/
 
2571
/*                      NITFFindTREXMLDescFromName()                    */
 
2572
/************************************************************************/
 
2573
 
 
2574
static CPLXMLNode* NITFFindTREXMLDescFromName(NITFFile* psFile,
 
2575
                                              const char* pszTREName)
 
2576
{
 
2577
    CPLXMLNode* psTreeNode;
 
2578
    CPLXMLNode* psTresNode;
 
2579
    CPLXMLNode* psIter;
 
2580
 
 
2581
    psTreeNode = NITFLoadXMLSpec(psFile);
 
2582
    if (psTreeNode == NULL)
 
2583
        return NULL;
 
2584
 
 
2585
    psTresNode = CPLGetXMLNode(psTreeNode, "=tres");
 
2586
    if (psTresNode == NULL)
 
2587
    {
 
2588
        CPLDebug("NITF", "Cannot find <tres> root element");
 
2589
        return NULL;
 
2590
    }
 
2591
 
 
2592
    for(psIter = psTresNode->psChild;psIter != NULL;psIter = psIter->psNext)
 
2593
    {
 
2594
        if (psIter->eType == CXT_Element &&
 
2595
            psIter->pszValue != NULL &&
 
2596
            strcmp(psIter->pszValue, "tre") == 0)
 
2597
        {
 
2598
            const char* pszName = CPLGetXMLValue(psIter, "name", NULL);
 
2599
            if (pszName != NULL && strcmp(pszName, pszTREName) == 0)
 
2600
            {
 
2601
                return psIter;
 
2602
            }
 
2603
        }
 
2604
    }
 
2605
 
 
2606
    return NULL;
 
2607
}
 
2608
 
 
2609
/************************************************************************/
 
2610
/*                         NITFCreateXMLTre()                           */
 
2611
/************************************************************************/
 
2612
 
 
2613
CPLXMLNode* NITFCreateXMLTre(NITFFile* psFile,
 
2614
                             const char* pszTREName,
 
2615
                             const char *pachTRE,
 
2616
                             int nTRESize)
 
2617
{
 
2618
    int nTreLength, nTreMinLength = -1, nTreMaxLength = -1;
 
2619
    int bError = FALSE;
 
2620
    int nTreOffset = 0;
 
2621
    CPLXMLNode* psTreNode;
 
2622
    CPLXMLNode* psOutXMLNode = NULL;
 
2623
    int nMDSize = 0, nMDAlloc = 0;
 
2624
 
 
2625
    psTreNode = NITFFindTREXMLDescFromName(psFile, pszTREName);
 
2626
    if (psTreNode == NULL)
 
2627
    {
 
2628
        if (!(EQUALN(pszTREName, "RPF", 3) || strcmp(pszTREName, "XXXXXX") == 0))
 
2629
        {
 
2630
            CPLDebug("NITF", "Cannot find definition of TRE %s in %s",
 
2631
                    pszTREName, NITF_SPEC_FILE);
 
2632
        }
 
2633
        return NULL;
 
2634
    }
 
2635
 
 
2636
    nTreLength = atoi(CPLGetXMLValue(psTreNode, "length", "-1"));
 
2637
    nTreMinLength = atoi(CPLGetXMLValue(psTreNode, "minlength", "-1"));
 
2638
    nTreMaxLength = atoi(CPLGetXMLValue(psTreNode, "maxlength", "-1"));
 
2639
 
 
2640
    if( (nTreLength > 0 && nTRESize != nTreLength) ||
 
2641
        (nTreMinLength > 0 && nTRESize < nTreMinLength) )
 
2642
    {
 
2643
        CPLError( CE_Warning, CPLE_AppDefined,
 
2644
                  "%s TRE wrong size, ignoring.", pszTREName );
 
2645
        return NULL;
 
2646
    }
 
2647
 
 
2648
    psOutXMLNode = CPLCreateXMLNode(NULL, CXT_Element, "tre");
 
2649
    CPLCreateXMLNode(CPLCreateXMLNode(psOutXMLNode, CXT_Attribute, "name"),
 
2650
                     CXT_Text, pszTREName);
 
2651
 
 
2652
    CSLDestroy(NITFGenericMetadataReadTREInternal(NULL,
 
2653
                                                  &nMDSize,
 
2654
                                                  &nMDAlloc,
 
2655
                                                  psOutXMLNode,
 
2656
                                                  pszTREName,
 
2657
                                                  pachTRE,
 
2658
                                                  nTRESize,
 
2659
                                                  psTreNode,
 
2660
                                                  &nTreOffset,
 
2661
                                                  "",
 
2662
                                                  &bError));
 
2663
 
 
2664
    if (bError == FALSE && nTreLength > 0 && nTreOffset != nTreLength)
 
2665
    {
 
2666
        CPLError( CE_Warning, CPLE_AppDefined,
 
2667
                  "Inconsistant declaration of %s TRE",
 
2668
                  pszTREName );
 
2669
    }
 
2670
    if (nTreOffset < nTRESize)
 
2671
        CPLDebug("NITF", "%d remaining bytes at end of %s TRE",
 
2672
                 nTRESize -nTreOffset, pszTREName);
 
2673
 
 
2674
    return psOutXMLNode;
 
2675
}
 
2676
 
 
2677
/************************************************************************/
 
2678
/*                        NITFGenericMetadataRead()                     */
 
2679
/*                                                                      */
 
2680
/* Add metadata from TREs of file and image objects in the papszMD list */
 
2681
/* pszSpecificTRE can be NULL, in which case all TREs listed in         */
 
2682
/* data/nitf_resources.xml that have md_prefix defined will be looked   */
 
2683
/* for. If not NULL, only the specified one will be looked for.         */
 
2684
/************************************************************************/
 
2685
 
 
2686
char **NITFGenericMetadataRead( char **papszMD,
 
2687
                                NITFFile* psFile,
 
2688
                                NITFImage *psImage,
 
2689
                                const char* pszSpecificTREName)
 
2690
{
 
2691
    CPLXMLNode* psTreeNode = NULL;
 
2692
    CPLXMLNode* psTresNode = NULL;
 
2693
    CPLXMLNode* psIter = NULL;
 
2694
 
 
2695
    if (psFile == NULL && psImage == NULL)
 
2696
        return papszMD;
 
2697
 
 
2698
    psTreeNode = NITFLoadXMLSpec(psFile ? psFile : psImage->psFile);
 
2699
    if (psTreeNode == NULL)
 
2700
        return papszMD;
 
2701
 
 
2702
    psTresNode = CPLGetXMLNode(psTreeNode, "=tres");
 
2703
    if (psTresNode == NULL)
 
2704
    {
 
2705
        CPLDebug("NITF", "Cannot find <tres> root element");
 
2706
        return papszMD;
 
2707
    }
 
2708
 
 
2709
    for(psIter = psTresNode->psChild;psIter!=NULL;psIter = psIter->psNext)
 
2710
    {
 
2711
        if (psIter->eType == CXT_Element &&
 
2712
            psIter->pszValue != NULL &&
 
2713
            strcmp(psIter->pszValue, "tre") == 0)
 
2714
        {
 
2715
            const char* pszName = CPLGetXMLValue(psIter, "name", NULL);
 
2716
            const char* pszMDPrefix = CPLGetXMLValue(psIter, "md_prefix", NULL);
 
2717
            if (pszName != NULL && ((pszSpecificTREName == NULL && pszMDPrefix != NULL) ||
 
2718
                                    (pszSpecificTREName != NULL && strcmp(pszName, pszSpecificTREName) == 0)))
 
2719
            {
 
2720
                if (psFile != NULL)
 
2721
                {
 
2722
                    const char *pachTRE = NULL;
 
2723
                    int  nTRESize = 0;
 
2724
 
 
2725
                    pachTRE = NITFFindTRE( psFile->pachTRE, psFile->nTREBytes,
 
2726
                                           pszName, &nTRESize);
 
2727
                    if( pachTRE != NULL )
 
2728
                        papszMD = NITFGenericMetadataReadTRE(
 
2729
                                  papszMD, pszName, pachTRE, nTRESize, psIter);
 
2730
                }
 
2731
                if (psImage != NULL)
 
2732
                {
 
2733
                    const char *pachTRE = NULL;
 
2734
                    int  nTRESize = 0;
 
2735
 
 
2736
                    pachTRE = NITFFindTRE( psImage->pachTRE, psImage->nTREBytes,
 
2737
                                           pszName, &nTRESize);
 
2738
                    if( pachTRE != NULL )
 
2739
                       papszMD = NITFGenericMetadataReadTRE(
 
2740
                                  papszMD, pszName, pachTRE, nTRESize, psIter);
 
2741
                }
 
2742
                if (pszSpecificTREName)
 
2743
                    break;
 
2744
            }
 
2745
        }
 
2746
    }
 
2747
 
 
2748
    return papszMD;
 
2749
}