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

« back to all changes in this revision

Viewing changes to frmts/nitf/nitfdataset.cpp

  • 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: nitfdataset.cpp 19906 2010-06-23 20:51:56Z rouault $
 
2
 * $Id: nitfdataset.cpp 23491 2011-12-07 20:48:18Z rouault $
3
3
 *
4
4
 * Project:  NITF Read/Write Translator
5
 
 * Purpose:  GDALDataset/GDALRasterBand implementation on top of "nitflib".
 
5
 * Purpose:  NITFDataset and driver related implementations.
6
6
 * Author:   Frank Warmerdam, warmerdam@pobox.com
7
7
 *
8
8
 ******************************************************************************
30
30
 * DEALINGS IN THE SOFTWARE.
31
31
 ****************************************************************************/
32
32
 
33
 
#include "gdal_pam.h"
34
 
#include "nitflib.h"
35
 
#include "ogr_spatialref.h"
 
33
#include "nitfdataset.h"
36
34
#include "cpl_string.h"
37
35
#include "cpl_csv.h"
38
 
#include "gdal_proxy.h"
39
36
 
40
 
CPL_CVSID("$Id: nitfdataset.cpp 19906 2010-06-23 20:51:56Z rouault $");
 
37
CPL_CVSID("$Id: nitfdataset.cpp 23491 2011-12-07 20:48:18Z rouault $");
41
38
 
42
39
static void NITFPatchImageLength( const char *pszFilename,
43
40
                                  GUIntBig nImageOffset, 
44
41
                                  GIntBig nPixelCount, const char *pszIC );
 
42
static int NITFWriteCGMSegments( const char *pszFilename, char **papszList );
45
43
static void NITFWriteTextSegments( const char *pszFilename, char **papszList );
46
44
 
47
 
static CPLErr NITFSetColorInterpretation( NITFImage *psImage, 
48
 
                                          int nBand,
49
 
                                          GDALColorInterp eInterp );
50
45
#ifdef JPEG_SUPPORTED
51
 
static int NITFWriteJPEGImage( GDALDataset *, FILE *, vsi_l_offset, char **,
 
46
static int NITFWriteJPEGImage( GDALDataset *, VSILFILE *, vsi_l_offset, char **,
52
47
                               GDALProgressFunc pfnProgress, 
53
48
                               void * pProgressData );
54
49
#endif
55
50
 
56
 
/************************************************************************/
57
 
/* ==================================================================== */
58
 
/*                              NITFDataset                             */
59
 
/* ==================================================================== */
60
 
/************************************************************************/
61
 
 
62
 
class NITFRasterBand;
63
 
class NITFWrapperRasterBand;
64
 
 
65
 
class NITFDataset : public GDALPamDataset
66
 
{
67
 
    friend class NITFRasterBand;
68
 
    friend class NITFWrapperRasterBand;
69
 
 
70
 
    NITFFile    *psFile;
71
 
    NITFImage   *psImage;
72
 
 
73
 
    GDALPamDataset *poJ2KDataset;
74
 
    int         bJP2Writing;
75
 
 
76
 
    GDALPamDataset *poJPEGDataset;
77
 
 
78
 
    int         bGotGeoTransform;
79
 
    double      adfGeoTransform[6];
80
 
 
81
 
    char        *pszProjection;
82
 
 
83
 
    int         nGCPCount;
84
 
    GDAL_GCP    *pasGCPList;
85
 
    char        *pszGCPProjection;
86
 
 
87
 
    GDALMultiDomainMetadata oSpecialMD;
88
 
 
89
 
    void         InitializeCGMMetadata();
90
 
    void         InitializeTextMetadata();
91
 
    void         InitializeTREMetadata();
92
 
 
93
 
    GIntBig     *panJPEGBlockOffset;
94
 
    GByte       *pabyJPEGBlock;
95
 
    int          nQLevel;
96
 
 
97
 
    int          ScanJPEGQLevel( GUIntBig *pnDataStart );
98
 
    CPLErr       ScanJPEGBlocks( void );
99
 
    CPLErr       ReadJPEGBlock( int, int );
100
 
    void         CheckGeoSDEInfo();
101
 
 
102
 
    int          nIMIndex;
103
 
    CPLString    osNITFFilename;
104
 
 
105
 
  public:
106
 
                 NITFDataset();
107
 
                 ~NITFDataset();
108
 
 
109
 
    virtual CPLErr AdviseRead( int nXOff, int nYOff, int nXSize, int nYSize,
110
 
                               int nBufXSize, int nBufYSize, 
111
 
                               GDALDataType eDT, 
112
 
                               int nBandCount, int *panBandList,
113
 
                               char **papszOptions );
114
 
 
115
 
    virtual CPLErr IRasterIO( GDALRWFlag, int, int, int, int,
116
 
                              void *, int, int, GDALDataType,
117
 
                              int, int *, int, int, int );
118
 
 
119
 
    virtual const char *GetProjectionRef(void);
120
 
    virtual CPLErr SetProjection( const char * );
121
 
    virtual CPLErr GetGeoTransform( double * );
122
 
    virtual CPLErr SetGeoTransform( double * );
123
 
 
124
 
    virtual int    GetGCPCount();
125
 
    virtual const char *GetGCPProjection();
126
 
    virtual const GDAL_GCP *GetGCPs();
127
 
 
128
 
    virtual char      **GetMetadata( const char * pszDomain = "" );
129
 
    virtual const char *GetMetadataItem( const char * pszName,
130
 
                                         const char * pszDomain = "" );
131
 
    virtual void   FlushCache();
132
 
    virtual CPLErr IBuildOverviews( const char *, int, int *,
133
 
                                    int, int *, GDALProgressFunc, void * );
134
 
 
135
 
    static int          Identify( GDALOpenInfo * );
136
 
    static GDALDataset *Open( GDALOpenInfo *, GDALDataset *poWritableJ2KDataset);
137
 
    static GDALDataset *Open( GDALOpenInfo * );
138
 
    static GDALDataset *
139
 
    NITFCreateCopy( const char *pszFilename, GDALDataset *poSrcDS,
140
 
                    int bStrict, char **papszOptions, 
141
 
                    GDALProgressFunc pfnProgress, void * pProgressData );
142
 
 
143
 
};
144
 
 
145
 
/************************************************************************/
146
 
/*                       NITFMakeColorTable()                           */
147
 
/************************************************************************/
148
 
 
149
 
static GDALColorTable* NITFMakeColorTable(NITFImage* psImage, NITFBandInfo *psBandInfo)
150
 
{
151
 
    GDALColorTable* poColorTable = NULL;
152
 
 
153
 
    if( psBandInfo->nSignificantLUTEntries > 0 )
154
 
    {
155
 
        int  iColor;
156
 
 
157
 
        poColorTable = new GDALColorTable();
158
 
 
159
 
        for( iColor = 0; iColor < psBandInfo->nSignificantLUTEntries; iColor++)
160
 
        {
161
 
            GDALColorEntry sEntry;
162
 
 
163
 
            sEntry.c1 = psBandInfo->pabyLUT[  0 + iColor];
164
 
            sEntry.c2 = psBandInfo->pabyLUT[256 + iColor];
165
 
            sEntry.c3 = psBandInfo->pabyLUT[512 + iColor];
166
 
            sEntry.c4 = 255;
167
 
 
168
 
            poColorTable->SetColorEntry( iColor, &sEntry );
169
 
        }
170
 
 
171
 
        if (psImage->bNoDataSet)
172
 
        {
173
 
            GDALColorEntry sEntry;
174
 
            sEntry.c1 = sEntry.c2 = sEntry.c3 = sEntry.c4 = 0;
175
 
            poColorTable->SetColorEntry( psImage->nNoDataValue, &sEntry );
176
 
        }
177
 
    }
178
 
 
179
 
/* -------------------------------------------------------------------- */
180
 
/*      We create a color table for 1 bit data too...                   */
181
 
/* -------------------------------------------------------------------- */
182
 
    if( poColorTable == NULL && psImage->nBitsPerSample == 1 )
183
 
    {
184
 
        GDALColorEntry sEntry;
185
 
 
186
 
        poColorTable = new GDALColorTable();
187
 
 
188
 
        sEntry.c1 = 0;
189
 
        sEntry.c2 = 0;
190
 
        sEntry.c3 = 0;
191
 
        sEntry.c4 = 255;
192
 
        poColorTable->SetColorEntry( 0, &sEntry );
193
 
 
194
 
        sEntry.c1 = 255;
195
 
        sEntry.c2 = 255;
196
 
        sEntry.c3 = 255;
197
 
        sEntry.c4 = 255;
198
 
        poColorTable->SetColorEntry( 1, &sEntry );
199
 
    }
200
 
    
201
 
    return poColorTable;
202
 
}
203
 
 
204
 
/************************************************************************/
205
 
/* ==================================================================== */
206
 
/*                            NITFRasterBand                             */
207
 
/* ==================================================================== */
208
 
/************************************************************************/
209
 
 
210
 
class NITFRasterBand : public GDALPamRasterBand
211
 
{
212
 
    friend class NITFDataset;
213
 
 
214
 
    NITFImage   *psImage;
215
 
 
216
 
    GDALColorTable *poColorTable;
217
 
 
218
 
    GByte       *pUnpackData;
219
 
 
220
 
  public:
221
 
                   NITFRasterBand( NITFDataset *, int );
222
 
                  ~NITFRasterBand();
223
 
 
224
 
    virtual CPLErr IReadBlock( int, int, void * );
225
 
    virtual CPLErr IWriteBlock( int, int, void * );
226
 
 
227
 
    virtual GDALColorInterp GetColorInterpretation();
228
 
    virtual CPLErr SetColorInterpretation( GDALColorInterp );
229
 
    virtual GDALColorTable *GetColorTable();
230
 
    virtual CPLErr SetColorTable( GDALColorTable * ); 
231
 
    virtual double GetNoDataValue( int *pbSuccess = NULL );
232
 
 
233
 
    void Unpack(GByte* pData);
234
 
};
235
 
 
236
 
/************************************************************************/
237
 
/*                           NITFRasterBand()                           */
238
 
/************************************************************************/
239
 
 
240
 
NITFRasterBand::NITFRasterBand( NITFDataset *poDS, int nBand )
241
 
 
242
 
{
243
 
    NITFBandInfo *psBandInfo = poDS->psImage->pasBandInfo + nBand - 1;
244
 
 
245
 
    this->poDS = poDS;
246
 
    this->nBand = nBand;
247
 
 
248
 
    this->eAccess = poDS->eAccess;
249
 
    this->psImage = poDS->psImage;
250
 
 
251
 
/* -------------------------------------------------------------------- */
252
 
/*      Translate data type(s).                                         */
253
 
/* -------------------------------------------------------------------- */
254
 
    if( psImage->nBitsPerSample <= 8 )
255
 
        eDataType = GDT_Byte;
256
 
    else if( psImage->nBitsPerSample == 16 
257
 
             && EQUAL(psImage->szPVType,"SI") )
258
 
        eDataType = GDT_Int16;
259
 
    else if( psImage->nBitsPerSample == 16 )
260
 
        eDataType = GDT_UInt16;
261
 
    else if( psImage->nBitsPerSample == 12 )
262
 
        eDataType = GDT_UInt16;
263
 
    else if( psImage->nBitsPerSample == 32 
264
 
             && EQUAL(psImage->szPVType,"SI") )
265
 
        eDataType = GDT_Int32;
266
 
    else if( psImage->nBitsPerSample == 32 
267
 
             && EQUAL(psImage->szPVType,"R") )
268
 
        eDataType = GDT_Float32;
269
 
    else if( psImage->nBitsPerSample == 32 )
270
 
        eDataType = GDT_UInt32;
271
 
    else if( psImage->nBitsPerSample == 64 
272
 
             && EQUAL(psImage->szPVType,"R") )
273
 
        eDataType = GDT_Float64;
274
 
    else if( psImage->nBitsPerSample == 64
275
 
              && EQUAL(psImage->szPVType,"C") )
276
 
        eDataType = GDT_CFloat32;
277
 
    /* ERO : note I'm not sure if CFloat64 can be transmitted as NBPP is only 2 characters */
278
 
    else
279
 
    {
280
 
        eDataType = GDT_Unknown;
281
 
        CPLError( CE_Warning, CPLE_AppDefined, 
282
 
                  "Unsupported combination of PVTYPE(%s) and NBPP(%d).",
283
 
                  psImage->szPVType, psImage->nBitsPerSample );
284
 
    }
285
 
 
286
 
/* -------------------------------------------------------------------- */
287
 
/*      Work out block size. If the image is all one big block we       */
288
 
/*      handle via the scanline access API.                             */
289
 
/* -------------------------------------------------------------------- */
290
 
    if( psImage->nBlocksPerRow == 1 
291
 
        && psImage->nBlocksPerColumn == 1
292
 
        && psImage->nBitsPerSample >= 8
293
 
        && EQUAL(psImage->szIC,"NC") )
294
 
    {
295
 
        nBlockXSize = psImage->nBlockWidth;
296
 
        nBlockYSize = 1;
297
 
    }
298
 
    else
299
 
    {
300
 
        nBlockXSize = psImage->nBlockWidth;
301
 
        nBlockYSize = psImage->nBlockHeight;
302
 
    }
303
 
 
304
 
/* -------------------------------------------------------------------- */
305
 
/*      Do we have a color table?                                       */
306
 
/* -------------------------------------------------------------------- */
307
 
    poColorTable = NITFMakeColorTable(psImage,
308
 
                                      psBandInfo);
309
 
 
310
 
    if( psImage->nBitsPerSample == 1 
311
 
    ||  psImage->nBitsPerSample == 3
312
 
    ||  psImage->nBitsPerSample == 5
313
 
    ||  psImage->nBitsPerSample == 6
314
 
    ||  psImage->nBitsPerSample == 7
315
 
    ||  psImage->nBitsPerSample == 12 )
316
 
        SetMetadataItem( "NBITS", CPLString().Printf("%d", psImage->nBitsPerSample), "IMAGE_STRUCTURE" );
317
 
 
318
 
    pUnpackData = 0;
319
 
    if (psImage->nBitsPerSample == 3
320
 
    ||  psImage->nBitsPerSample == 5
321
 
    ||  psImage->nBitsPerSample == 6
322
 
    ||  psImage->nBitsPerSample == 7)
323
 
      pUnpackData = new GByte[((nBlockXSize*nBlockYSize+7)/8)*8];
324
 
}
325
 
 
326
 
/************************************************************************/
327
 
/*                          ~NITFRasterBand()                           */
328
 
/************************************************************************/
329
 
 
330
 
NITFRasterBand::~NITFRasterBand()
331
 
 
332
 
{
333
 
    if( poColorTable != NULL )
334
 
        delete poColorTable;
335
 
 
336
 
    delete[] pUnpackData;
337
 
}
338
 
 
339
 
/************************************************************************/
340
 
/*                             IReadBlock()                             */
341
 
/************************************************************************/
342
 
 
343
 
CPLErr NITFRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
344
 
                                   void * pImage )
345
 
 
346
 
{
347
 
    int  nBlockResult;
348
 
    NITFDataset *poGDS = (NITFDataset *) poDS;
349
 
 
350
 
/* -------------------------------------------------------------------- */
351
 
/*      Special case for JPEG blocks.                                   */
352
 
/* -------------------------------------------------------------------- */
353
 
    if( EQUAL(psImage->szIC,"C3") || EQUAL(psImage->szIC,"M3") )
354
 
    {
355
 
        CPLErr eErr = poGDS->ReadJPEGBlock( nBlockXOff, nBlockYOff );
356
 
        int nBlockBandSize = psImage->nBlockWidth*psImage->nBlockHeight*
357
 
                             (GDALGetDataTypeSize(eDataType)/8);
358
 
 
359
 
        if( eErr != CE_None )
360
 
            return eErr;
361
 
 
362
 
        memcpy( pImage, 
363
 
                poGDS->pabyJPEGBlock + (nBand - 1) * nBlockBandSize, 
364
 
                nBlockBandSize );
365
 
 
366
 
        return eErr;
367
 
    }
368
 
 
369
 
/* -------------------------------------------------------------------- */
370
 
/*      Read the line/block                                             */
371
 
/* -------------------------------------------------------------------- */
372
 
    if( nBlockYSize == 1 )
373
 
    {
374
 
        nBlockResult = 
375
 
            NITFReadImageLine(psImage, nBlockYOff, nBand, pImage);
376
 
    }
377
 
    else
378
 
    {
379
 
        nBlockResult = 
380
 
            NITFReadImageBlock(psImage, nBlockXOff, nBlockYOff, nBand, pImage);
381
 
    }
382
 
 
383
 
    if( nBlockResult == BLKREAD_OK )
384
 
    {
385
 
        if( psImage->nBitsPerSample % 8 )
386
 
            Unpack((GByte*)pImage);
387
 
 
388
 
        return CE_None;
389
 
    }
390
 
 
391
 
    if( nBlockResult == BLKREAD_FAIL )
392
 
        return CE_Failure;
393
 
 
394
 
/* -------------------------------------------------------------------- */
395
 
/*      If we got a null/missing block, try to fill it in with the      */
396
 
/*      nodata value.  It seems this only really works properly for     */
397
 
/*      8bit.                                                           */
398
 
/* -------------------------------------------------------------------- */
399
 
    if( psImage->bNoDataSet )
400
 
        memset( pImage, psImage->nNoDataValue, 
401
 
                psImage->nWordSize*psImage->nBlockWidth*psImage->nBlockHeight);
402
 
    else
403
 
        memset( pImage, 0, 
404
 
                psImage->nWordSize*psImage->nBlockWidth*psImage->nBlockHeight);
405
 
 
406
 
    return CE_None;
407
 
}
408
 
 
409
 
/************************************************************************/
410
 
/*                            IWriteBlock()                             */
411
 
/************************************************************************/
412
 
 
413
 
CPLErr NITFRasterBand::IWriteBlock( int nBlockXOff, int nBlockYOff,
414
 
                                    void * pImage )
415
 
    
416
 
{
417
 
    int  nBlockResult;
418
 
 
419
 
/* -------------------------------------------------------------------- */
420
 
/*      Write the line/block                                            */
421
 
/* -------------------------------------------------------------------- */
422
 
    if( nBlockYSize == 1 )
423
 
    {
424
 
        nBlockResult = 
425
 
            NITFWriteImageLine(psImage, nBlockYOff, nBand, pImage);
426
 
    }
427
 
    else
428
 
    {
429
 
        nBlockResult = 
430
 
            NITFWriteImageBlock(psImage, nBlockXOff, nBlockYOff, nBand,pImage);
431
 
    }
432
 
 
433
 
    if( nBlockResult == BLKREAD_OK )
434
 
        return CE_None;
435
 
    else
436
 
        return CE_Failure;
437
 
}
438
 
 
439
 
/************************************************************************/
440
 
/*                           GetNoDataValue()                           */
441
 
/************************************************************************/
442
 
 
443
 
double NITFRasterBand::GetNoDataValue( int *pbSuccess )
444
 
 
445
 
{
446
 
    if( pbSuccess != NULL )
447
 
        *pbSuccess = psImage->bNoDataSet;
448
 
 
449
 
    if( psImage->bNoDataSet )
450
 
        return psImage->nNoDataValue;
451
 
    else
452
 
        return GDALPamRasterBand::GetNoDataValue( pbSuccess );
453
 
}
454
 
 
455
 
/************************************************************************/
456
 
/*                       GetColorInterpretation()                       */
457
 
/************************************************************************/
458
 
 
459
 
GDALColorInterp NITFRasterBand::GetColorInterpretation()
460
 
 
461
 
{
462
 
    NITFBandInfo *psBandInfo = psImage->pasBandInfo + nBand - 1;
463
 
 
464
 
    if( poColorTable != NULL )
465
 
        return GCI_PaletteIndex;
466
 
    
467
 
    if( EQUAL(psBandInfo->szIREPBAND,"R") )
468
 
        return GCI_RedBand;
469
 
    if( EQUAL(psBandInfo->szIREPBAND,"G") )
470
 
        return GCI_GreenBand;
471
 
    if( EQUAL(psBandInfo->szIREPBAND,"B") )
472
 
        return GCI_BlueBand;
473
 
    if( EQUAL(psBandInfo->szIREPBAND,"M") )
474
 
        return GCI_GrayIndex;
475
 
    if( EQUAL(psBandInfo->szIREPBAND,"Y") )
476
 
        return GCI_YCbCr_YBand;
477
 
    if( EQUAL(psBandInfo->szIREPBAND,"Cb") )
478
 
        return GCI_YCbCr_CbBand;
479
 
    if( EQUAL(psBandInfo->szIREPBAND,"Cr") )
480
 
        return GCI_YCbCr_CrBand;
481
 
 
482
 
    return GCI_Undefined;
483
 
}
484
 
 
485
 
/************************************************************************/
486
 
/*                     NITFSetColorInterpretation()                     */
487
 
/************************************************************************/
488
 
 
489
 
static CPLErr NITFSetColorInterpretation( NITFImage *psImage, 
490
 
                                          int nBand,
491
 
                                          GDALColorInterp eInterp )
492
 
 
493
 
{
494
 
    NITFBandInfo *psBandInfo = psImage->pasBandInfo + nBand - 1;
495
 
    const char *pszREP = NULL;
496
 
    GUIntBig nOffset;
497
 
 
498
 
    if( eInterp == GCI_RedBand )
499
 
        pszREP = "R";
500
 
    else if( eInterp == GCI_GreenBand )
501
 
        pszREP = "G";
502
 
    else if( eInterp == GCI_BlueBand )
503
 
        pszREP = "B";
504
 
    else if( eInterp == GCI_GrayIndex )
505
 
        pszREP = "M";
506
 
    else if( eInterp == GCI_YCbCr_YBand )
507
 
        pszREP = "Y";
508
 
    else if( eInterp == GCI_YCbCr_CbBand )
509
 
        pszREP = "Cb";
510
 
    else if( eInterp == GCI_YCbCr_CrBand )
511
 
        pszREP = "Cr";
512
 
    else if( eInterp == GCI_Undefined )
513
 
        return CE_None;
514
 
 
515
 
    if( pszREP == NULL )
516
 
    {
517
 
        CPLError( CE_Failure, CPLE_NotSupported, 
518
 
                  "Requested color interpretation (%s) not supported in NITF.",
519
 
                  GDALGetColorInterpretationName( eInterp ) );
520
 
        return CE_Failure;
521
 
    }
522
 
 
523
 
/* -------------------------------------------------------------------- */
524
 
/*      Where does this go in the file?                                 */
525
 
/* -------------------------------------------------------------------- */
526
 
    strcpy( psBandInfo->szIREPBAND, pszREP );
527
 
    nOffset = NITFIHFieldOffset( psImage, "IREPBAND" );
528
 
 
529
 
    if( nOffset != 0 )
530
 
        nOffset += (nBand - 1) * 13;
531
 
    
532
 
/* -------------------------------------------------------------------- */
533
 
/*      write it (space padded).                                        */
534
 
/* -------------------------------------------------------------------- */
535
 
    char szPadded[4];
536
 
    strcpy( szPadded, pszREP );
537
 
    strcat( szPadded, " " );
538
 
    
539
 
    if( nOffset != 0 )
540
 
    {
541
 
        if( VSIFSeekL( psImage->psFile->fp, nOffset, SEEK_SET ) != 0 
542
 
            || VSIFWriteL( (void *) szPadded, 1, 2, psImage->psFile->fp ) != 2 )
543
 
        {
544
 
            CPLError( CE_Failure, CPLE_AppDefined, 
545
 
                      "IO failure writing new IREPBAND value to NITF file." );
546
 
            return CE_Failure;
547
 
        }
548
 
    }
549
 
    
550
 
    return CE_None;
551
 
}
552
 
 
553
 
/************************************************************************/
554
 
/*                       SetColorInterpretation()                       */
555
 
/************************************************************************/
556
 
 
557
 
CPLErr NITFRasterBand::SetColorInterpretation( GDALColorInterp eInterp )
558
 
 
559
 
{
560
 
    return NITFSetColorInterpretation( psImage, nBand, eInterp );
561
 
}
562
 
 
563
 
/************************************************************************/
564
 
/*                           GetColorTable()                            */
565
 
/************************************************************************/
566
 
 
567
 
GDALColorTable *NITFRasterBand::GetColorTable()
568
 
 
569
 
{
570
 
    return poColorTable;
571
 
}
572
 
 
573
 
/************************************************************************/
574
 
/*                           SetColorTable()                            */
575
 
/************************************************************************/
576
 
 
577
 
CPLErr NITFRasterBand::SetColorTable( GDALColorTable *poNewCT )
578
 
 
579
 
{
580
 
    if( poNewCT == NULL )
581
 
        return CE_Failure;
582
 
 
583
 
    GByte abyNITFLUT[768];
584
 
    int   i;
585
 
    int   nCount = MIN(256,poNewCT->GetColorEntryCount());
586
 
 
587
 
    memset( abyNITFLUT, 0, 768 );
588
 
    for( i = 0; i < nCount; i++ )
589
 
    {
590
 
        GDALColorEntry sEntry;
591
 
 
592
 
        poNewCT->GetColorEntryAsRGB( i, &sEntry );
593
 
        abyNITFLUT[i    ] = (GByte) sEntry.c1;
594
 
        abyNITFLUT[i+256] = (GByte) sEntry.c2;
595
 
        abyNITFLUT[i+512] = (GByte) sEntry.c3;
596
 
    }
597
 
 
598
 
    if( NITFWriteLUT( psImage, nBand, nCount, abyNITFLUT ) )
599
 
        return CE_None;
600
 
    else
601
 
        return CE_Failure;
602
 
}
603
 
 
604
 
/************************************************************************/
605
 
/*                           Unpack()                                   */
606
 
/************************************************************************/
607
 
 
608
 
void NITFRasterBand::Unpack( GByte* pData )
609
 
{
610
 
  long n = nBlockXSize*nBlockYSize;
611
 
  long i;
612
 
  long k;
613
 
  switch (psImage->nBitsPerSample)
614
 
  {
615
 
    case 1:
616
 
    {
617
 
      // unpack 1-bit in-place in reverse
618
 
      for (i = n; --i >= 0; )
619
 
        pData[i] = (pData[i>>3] & (0x80 >> (i&7))) != 0;
620
 
       
621
 
      break;
622
 
    }
623
 
    case 2:
624
 
    {
625
 
      static const int s_Shift2[] = {6, 4, 2, 0};
626
 
      // unpack 2-bit in-place in reverse
627
 
      for (i = n; --i >= 0; )
628
 
        pData[i] = (pData[i>>2] >> (GByte)s_Shift2[i&3]) & 0x03;
629
 
       
630
 
      break;
631
 
    }
632
 
    case 4:
633
 
    {
634
 
      static const int s_Shift4[] = {4, 0};
635
 
      // unpack 4-bit in-place in reverse
636
 
      for (i = n; --i >= 0; )
637
 
        pData[i] = (pData[i>>1] >> (GByte)s_Shift4[i&1]) & 0x07;
638
 
       
639
 
      break;
640
 
    }
641
 
    case 3:
642
 
    {
643
 
      // unpacks 8 pixels (3 bytes) at time
644
 
      for (i = 0, k = 0; i < n; i += 8, k += 3)
645
 
      {
646
 
        pUnpackData[i+0] = ((pData[k+0] >> 5));
647
 
        pUnpackData[i+1] = ((pData[k+0] >> 2) & 0x07);
648
 
        pUnpackData[i+2] = ((pData[k+0] << 1) & 0x07) | (pData[k+1] >> 7);
649
 
        pUnpackData[i+3] = ((pData[k+1] >> 4) & 0x07);
650
 
        pUnpackData[i+4] = ((pData[k+1] >> 1) & 0x07);
651
 
        pUnpackData[i+5] = ((pData[k+1] << 2) & 0x07) | (pData[k+2] >> 6);
652
 
        pUnpackData[i+6] = ((pData[k+2] >> 3) & 0x07);
653
 
        pUnpackData[i+7] = ((pData[k+2]) & 0x7);
654
 
      }
655
 
 
656
 
      memcpy(pData, pUnpackData, n);
657
 
      break;
658
 
    }
659
 
    case 5:
660
 
    {
661
 
      // unpacks 8 pixels (5 bytes) at time
662
 
      for (i = 0, k = 0; i < n; i += 8, k += 5)
663
 
      {
664
 
        pUnpackData[i+0] = ((pData[k+0] >> 3));
665
 
        pUnpackData[i+1] = ((pData[k+0] << 2) & 0x1f) | (pData[k+1] >> 6);
666
 
        pUnpackData[i+2] = ((pData[k+1] >> 1) & 0x1f);
667
 
        pUnpackData[i+3] = ((pData[k+1] << 4) & 0x1f) | (pData[k+2] >> 4);
668
 
        pUnpackData[i+4] = ((pData[k+2] << 1) & 0x1f) | (pData[k+3] >> 7);
669
 
        pUnpackData[i+5] = ((pData[k+3] >> 2) & 0x1f);
670
 
        pUnpackData[i+6] = ((pData[k+3] << 3) & 0x1f) | (pData[k+4] >> 5);
671
 
        pUnpackData[i+7] = ((pData[k+4]) & 0x1f);
672
 
      }
673
 
 
674
 
      memcpy(pData, pUnpackData, n);
675
 
      break;
676
 
    }
677
 
    case 6:
678
 
    {
679
 
      // unpacks 4 pixels (3 bytes) at time
680
 
      for (i = 0, k = 0; i < n; i += 4, k += 3)
681
 
      {
682
 
        pUnpackData[i+0] = ((pData[k+0] >> 2));
683
 
        pUnpackData[i+1] = ((pData[k+0] << 4) & 0x3f) | (pData[k+1] >> 4);
684
 
        pUnpackData[i+2] = ((pData[k+1] << 2) & 0x3f) | (pData[k+2] >> 6);
685
 
        pUnpackData[i+3] = ((pData[k+2]) & 0x3f);
686
 
      }
687
 
 
688
 
      memcpy(pData, pUnpackData, n);
689
 
      break;
690
 
    }
691
 
    case 7:
692
 
    {
693
 
      // unpacks 8 pixels (7 bytes) at time
694
 
      for (i = 0, k = 0; i < n; i += 8, k += 7)
695
 
      {
696
 
        pUnpackData[i+0] = ((pData[k+0] >> 1));
697
 
        pUnpackData[i+1] = ((pData[k+0] << 6) & 0x7f) | (pData[k+1] >> 2);
698
 
        pUnpackData[i+2] = ((pData[k+1] << 5) & 0x7f) | (pData[k+2] >> 3) ;
699
 
        pUnpackData[i+3] = ((pData[k+2] << 4) & 0x7f) | (pData[k+3] >> 4);
700
 
        pUnpackData[i+4] = ((pData[k+3] << 3) & 0x7f) | (pData[k+4] >> 5);
701
 
        pUnpackData[i+5] = ((pData[k+4] << 2) & 0x7f) | (pData[k+5] >> 6);
702
 
        pUnpackData[i+6] = ((pData[k+5] << 1) & 0x7f) | (pData[k+6] >> 7);
703
 
        pUnpackData[i+7] = ((pData[k+6]) & 0x7f);
704
 
      }
705
 
 
706
 
      memcpy(pData, pUnpackData, n);
707
 
      break;
708
 
    }
709
 
    case 12:
710
 
    {
711
 
      GByte*   pabyImage = (GByte  *)pData;
712
 
      GUInt16* panImage  = (GUInt16*)pData;
713
 
      for (i = n; --i >= 0; )
714
 
      {
715
 
        long iOffset = i*3 / 2;
716
 
        if (i % 2 == 0)
717
 
          panImage[i] = pabyImage[iOffset] + (pabyImage[iOffset+1] & 0xf0) * 16;
718
 
        else
719
 
          panImage[i] = (pabyImage[iOffset]   & 0x0f) * 16
720
 
                      + (pabyImage[iOffset+1] & 0xf0) / 16
721
 
                      + (pabyImage[iOffset+1] & 0x0f) * 256;
722
 
      }
723
 
 
724
 
      break;
725
 
    }
726
 
  }
727
 
}
728
 
 
729
 
/************************************************************************/
730
 
/* ==================================================================== */
731
 
/*                       NITFWrapperRasterBand                          */
732
 
/* ==================================================================== */
733
 
/************************************************************************/
734
 
 
735
 
/* This class is used to wrap bands from JPEG or JPEG2000 datasets in */
736
 
/* bands of the NITF dataset. Previously a trick was applied in the */
737
 
/* relevant drivers to define a SetColorInterpretation() method and */
738
 
/* to make sure they keep the proper pointer to their "natural" dataset */
739
 
/* This trick is no longer necessary with the NITFWrapperRasterBand */
740
 
/* We just override the few specific methods where we want that */
741
 
/* the NITFWrapperRasterBand behaviour differs from the JPEG/JPEG2000 one */
742
 
 
743
 
class NITFWrapperRasterBand : public GDALProxyRasterBand
744
 
{
745
 
  GDALRasterBand* poBaseBand;
746
 
  GDALColorTable* poColorTable;
747
 
  GDALColorInterp eInterp;
748
 
 
749
 
  protected:
750
 
    /* Pure virtual method of the GDALProxyRasterBand */
751
 
    virtual GDALRasterBand* RefUnderlyingRasterBand();
752
 
 
753
 
  public:
754
 
                   NITFWrapperRasterBand( NITFDataset * poDS,
755
 
                                          GDALRasterBand* poBaseBand,
756
 
                                          int nBand);
757
 
                  ~NITFWrapperRasterBand();
758
 
    
759
 
    /* Methods from GDALRasterBand we want to override */
760
 
    virtual GDALColorInterp GetColorInterpretation();
761
 
    virtual CPLErr          SetColorInterpretation( GDALColorInterp );
762
 
    
763
 
    virtual GDALColorTable *GetColorTable();
764
 
 
765
 
    /* Specific method */
766
 
    void                    SetColorTableFromNITFBandInfo(); 
767
 
};
768
 
 
769
 
/************************************************************************/
770
 
/*                      NITFWrapperRasterBand()                         */
771
 
/************************************************************************/
772
 
 
773
 
NITFWrapperRasterBand::NITFWrapperRasterBand( NITFDataset * poDS,
774
 
                                              GDALRasterBand* poBaseBand,
775
 
                                              int nBand)
776
 
{
777
 
    this->poDS = poDS;
778
 
    this->nBand = nBand;
779
 
    this->poBaseBand = poBaseBand;
780
 
    eDataType = poBaseBand->GetRasterDataType();
781
 
    poBaseBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
782
 
    poColorTable = NULL;
783
 
    eInterp = poBaseBand->GetColorInterpretation();
784
 
}
785
 
 
786
 
/************************************************************************/
787
 
/*                      ~NITFWrapperRasterBand()                        */
788
 
/************************************************************************/
789
 
 
790
 
NITFWrapperRasterBand::~NITFWrapperRasterBand()
791
 
{
792
 
    if( poColorTable != NULL )
793
 
        delete poColorTable;
794
 
}
795
 
 
796
 
/************************************************************************/
797
 
/*                     RefUnderlyingRasterBand()                        */
798
 
/************************************************************************/
799
 
 
800
 
/* We don't need ref-counting. Just return the base band */
801
 
GDALRasterBand* NITFWrapperRasterBand::RefUnderlyingRasterBand()
802
 
{
803
 
        return poBaseBand;
804
 
}
805
 
 
806
 
/************************************************************************/
807
 
/*                            GetColorTable()                           */
808
 
/************************************************************************/
809
 
 
810
 
GDALColorTable *NITFWrapperRasterBand::GetColorTable()
811
 
{
812
 
    return poColorTable;
813
 
}
814
 
 
815
 
/************************************************************************/
816
 
/*                 SetColorTableFromNITFBandInfo()                      */
817
 
/************************************************************************/
818
 
 
819
 
void NITFWrapperRasterBand::SetColorTableFromNITFBandInfo()
820
 
{
821
 
    NITFDataset* poGDS = (NITFDataset* )poDS;
822
 
    poColorTable = NITFMakeColorTable(poGDS->psImage,
823
 
                                      poGDS->psImage->pasBandInfo + nBand - 1);
824
 
}
825
 
 
826
 
/************************************************************************/
827
 
/*                        GetColorInterpretation()                      */
828
 
/************************************************************************/
829
 
 
830
 
GDALColorInterp NITFWrapperRasterBand::GetColorInterpretation()
831
 
{
832
 
    return eInterp;
833
 
}
834
 
 
835
 
/************************************************************************/
836
 
/*                        SetColorInterpretation()                      */
837
 
/************************************************************************/
838
 
 
839
 
CPLErr NITFWrapperRasterBand::SetColorInterpretation( GDALColorInterp eInterp)
840
 
{
841
 
    this->eInterp = eInterp;
842
 
    return CE_None;
843
 
}
 
51
#ifdef ESRI_BUILD
 
52
static void SetBandMetadata( NITFImage *psImage, GDALRasterBand *poBand, int nBand );
 
53
#endif
844
54
 
845
55
/************************************************************************/
846
56
/* ==================================================================== */
879
89
    adfGeoTransform[5] = 1.0;
880
90
    
881
91
    poDriver = (GDALDriver*) GDALGetDriverByName("NITF");
 
92
 
 
93
    papszTextMDToWrite = NULL;
 
94
    papszCgmMDToWrite = NULL;
 
95
    
 
96
    bInLoadXML = FALSE;
882
97
}
883
98
 
884
99
/************************************************************************/
888
103
NITFDataset::~NITFDataset()
889
104
 
890
105
{
 
106
    CloseDependentDatasets();
 
107
 
 
108
/* -------------------------------------------------------------------- */
 
109
/*      Free datastructures.                                            */
 
110
/* -------------------------------------------------------------------- */
 
111
    CPLFree( pszProjection );
 
112
 
 
113
    GDALDeinitGCPs( nGCPCount, pasGCPList );
 
114
    CPLFree( pasGCPList );
 
115
    CPLFree( pszGCPProjection );
 
116
 
 
117
    CPLFree( panJPEGBlockOffset );
 
118
    CPLFree( pabyJPEGBlock );
 
119
}
 
120
 
 
121
/************************************************************************/
 
122
/*                        CloseDependentDatasets()                      */
 
123
/************************************************************************/
 
124
 
 
125
int NITFDataset::CloseDependentDatasets()
 
126
{
891
127
    FlushCache();
892
128
 
 
129
    int bHasDroppedRef = GDALPamDataset::CloseDependentDatasets();
 
130
 
893
131
/* -------------------------------------------------------------------- */
894
132
/*      If we have been writing to a JPEG2000 file, check if the        */
895
133
/*      color interpretations were set.  If so, apply the settings      */
921
159
    }
922
160
 
923
161
/* -------------------------------------------------------------------- */
924
 
/*      Free datastructures.                                            */
925
 
/* -------------------------------------------------------------------- */
926
 
    CPLFree( pszProjection );
927
 
 
928
 
    GDALDeinitGCPs( nGCPCount, pasGCPList );
929
 
    CPLFree( pasGCPList );
930
 
 
931
 
/* -------------------------------------------------------------------- */
932
162
/*      If we have a jpeg2000 output file, make sure it gets closed     */
933
163
/*      and flushed out.                                                */
934
164
/* -------------------------------------------------------------------- */
935
165
    if( poJ2KDataset != NULL )
936
166
    {
937
167
        GDALClose( (GDALDatasetH) poJ2KDataset );
 
168
        poJ2KDataset = NULL;
 
169
        bHasDroppedRef = TRUE;
938
170
    }
939
171
 
940
172
/* -------------------------------------------------------------------- */
950
182
                              "C8" );
951
183
    }
952
184
 
 
185
    bJP2Writing = FALSE;
 
186
 
953
187
/* -------------------------------------------------------------------- */
954
188
/*      If we have a jpeg output file, make sure it gets closed         */
955
189
/*      and flushed out.                                                */
957
191
    if( poJPEGDataset != NULL )
958
192
    {
959
193
        GDALClose( (GDALDatasetH) poJPEGDataset );
960
 
    }
961
 
 
962
 
    CPLFree( panJPEGBlockOffset );
963
 
    CPLFree( pabyJPEGBlock );
 
194
        poJPEGDataset = NULL;
 
195
        bHasDroppedRef = TRUE;
 
196
    }
 
197
 
 
198
/* -------------------------------------------------------------------- */
 
199
/*      If the dataset was opened by Create(), we may need to write     */
 
200
/*      the CGM and TEXT segments                                       */
 
201
/* -------------------------------------------------------------------- */
 
202
    NITFWriteCGMSegments( GetDescription(), papszCgmMDToWrite );
 
203
    NITFWriteTextSegments( GetDescription(), papszTextMDToWrite );
 
204
 
 
205
    CSLDestroy(papszTextMDToWrite);
 
206
    papszTextMDToWrite = NULL;
 
207
    CSLDestroy(papszCgmMDToWrite);
 
208
    papszCgmMDToWrite = NULL;
 
209
 
 
210
/* -------------------------------------------------------------------- */
 
211
/*      Destroy the raster bands if they exist.                         */
 
212
/* We must do it now since the rasterbands can be NITFWrapperRasterBand */
 
213
/* that derive from the GDALProxyRasterBand object, which keeps         */
 
214
/* a reference on the JPEG/JP2K dataset, so any later call to           */
 
215
/* FlushCache() would result in FlushCache() being called on a          */
 
216
/* already destroyed object                                             */
 
217
/* -------------------------------------------------------------------- */
 
218
    for( int iBand = 0; iBand < nBands; iBand++ )
 
219
    {
 
220
       delete papoBands[iBand];
 
221
    }
 
222
    nBands = 0;
 
223
 
 
224
    return bHasDroppedRef;
964
225
}
965
226
 
966
227
/************************************************************************/
985
246
    GDALPamDataset::FlushCache();
986
247
}
987
248
 
 
249
#ifdef ESRI_BUILD
 
250
 
 
251
/************************************************************************/
 
252
/*                           ExtractEsriMD()                            */
 
253
/*                                                                      */
 
254
/*      Extracts ESRI-specific required meta data from metadata         */
 
255
/*      string list papszStrList.                                       */
 
256
/************************************************************************/
 
257
 
 
258
static char **ExtractEsriMD( char **papszMD )
 
259
{
 
260
    char **papszEsriMD = NULL;
 
261
 
 
262
    if( papszMD )
 
263
    {
 
264
        // These are the current generic ESRI metadata.
 
265
        const char *const pEsriMDAcquisitionDate   = "ESRI_MD_ACQUISITION_DATE";
 
266
        const char *const pEsriMDAngleToNorth      = "ESRI_MD_ANGLE_TO_NORTH";
 
267
        const char *const pEsriMDCircularError     = "ESRI_MD_CE";
 
268
        const char *const pEsriMDDataType          = "ESRI_MD_DATA_TYPE";
 
269
        const char *const pEsriMDIsCloudCover      = "ESRI_MD_ISCLOUDCOVER";
 
270
        const char *const pEsriMDLinearError       = "ESRI_MD_LE";
 
271
        const char *const pEsriMDOffNaDir          = "ESRI_MD_OFF_NADIR";
 
272
        const char *const pEsriMDPercentCloudCover = "ESRI_MD_PERCENT_CLOUD_COVER";
 
273
        const char *const pEsriMDProductName       = "ESRI_MD_PRODUCT_NAME";
 
274
        const char *const pEsriMDSensorAzimuth     = "ESRI_MD_SENSOR_AZIMUTH";
 
275
        const char *const pEsriMDSensorElevation   = "ESRI_MD_SENSOR_ELEVATION";
 
276
        const char *const pEsriMDSensorName        = "ESRI_MD_SENSOR_NAME";
 
277
        const char *const pEsriMDSunAzimuth        = "ESRI_MD_SUN_AZIMUTH";
 
278
        const char *const pEsriMDSunElevation      = "ESRI_MD_SUN_ELEVATION";
 
279
 
 
280
        char         szField[11];
 
281
        const char  *pCCImageSegment = CSLFetchNameValue( papszMD, "NITF_IID1" );
 
282
        std::string  ccSegment("false");
 
283
 
 
284
        if( ( pCCImageSegment != NULL ) && ( strlen(pCCImageSegment) <= 10 ) )
 
285
        {
 
286
            szField[0] = '\0';
 
287
            strncpy( szField, pCCImageSegment, strlen(pCCImageSegment) );
 
288
            szField[strlen(pCCImageSegment)] = '\0';
 
289
 
 
290
            // Trim white off tag.
 
291
            while( ( strlen(szField) > 0 ) && ( szField[strlen(szField)-1] == ' ' ) )
 
292
                szField[strlen(szField)-1] = '\0';
 
293
 
 
294
            if ((strlen(szField) == 2) && (EQUALN(szField, "CC", 2))) ccSegment.assign("true");
 
295
        }
 
296
 
 
297
        const char *pAcquisitionDate   = CSLFetchNameValue( papszMD, "NITF_FDT" );
 
298
        const char *pAngleToNorth      = CSLFetchNameValue( papszMD, "NITF_CSEXRA_ANGLE_TO_NORTH" );
 
299
        const char *pCircularError     = CSLFetchNameValue( papszMD, "NITF_CSEXRA_CIRCL_ERR" );      // Unit in feet.
 
300
        const char *pLinearError       = CSLFetchNameValue( papszMD, "NITF_CSEXRA_LINEAR_ERR" );     // Unit in feet.
 
301
        const char *pPercentCloudCover = CSLFetchNameValue( papszMD, "NITF_PIAIMC_CLOUDCVR" );
 
302
        const char *pProductName       = CSLFetchNameValue( papszMD, "NITF_CSDIDA_PRODUCT_ID" );
 
303
        const char *pSensorName        = CSLFetchNameValue( papszMD, "NITF_PIAIMC_SENSNAME" );
 
304
        const char *pSunAzimuth        = CSLFetchNameValue( papszMD, "NITF_CSEXRA_SUN_AZIMUTH" );
 
305
        const char *pSunElevation      = CSLFetchNameValue( papszMD, "NITF_CSEXRA_SUN_ELEVATION" );
 
306
 
 
307
        // Get ESRI_MD_DATA_TYPE.
 
308
        const char *pDataType        = NULL;
 
309
        const char *pImgSegFieldICAT = CSLFetchNameValue( papszMD, "NITF_ICAT" );
 
310
 
 
311
        if( ( pImgSegFieldICAT != NULL ) && ( EQUALN(pImgSegFieldICAT, "DTEM", 4) ) )
 
312
            pDataType = "Elevation";
 
313
        else
 
314
            pDataType = "Generic";
 
315
 
 
316
        if( pAngleToNorth == NULL )
 
317
            pAngleToNorth = CSLFetchNameValue( papszMD, "NITF_USE00A_ANGLE_TO_NORTH" );
 
318
 
 
319
        // Percent cloud cover == 999 means that the information is not available.
 
320
        if( (pPercentCloudCover != NULL) &&  (EQUALN(pPercentCloudCover, "999", 3)) )
 
321
            pPercentCloudCover = NULL;
 
322
 
 
323
        pAngleToNorth = CSLFetchNameValue( papszMD, "NITF_USE00A_ANGLE_TO_NORTH" );
 
324
 
 
325
        if( pSunAzimuth == NULL )
 
326
            pSunAzimuth = CSLFetchNameValue( papszMD, "NITF_USE00A_SUN_AZ" );
 
327
 
 
328
        if( pSunElevation == NULL )
 
329
            pSunElevation = CSLFetchNameValue( papszMD, "NITF_USE00A_SUN_EL" );
 
330
 
 
331
        // CSLAddNameValue will not add the key/value pair if the value is NULL.
 
332
        papszEsriMD = CSLAddNameValue( papszEsriMD, pEsriMDAcquisitionDate,   pAcquisitionDate );
 
333
        papszEsriMD = CSLAddNameValue( papszEsriMD, pEsriMDAngleToNorth,      pAngleToNorth );
 
334
        papszEsriMD = CSLAddNameValue( papszEsriMD, pEsriMDCircularError,     pCircularError );
 
335
        papszEsriMD = CSLAddNameValue( papszEsriMD, pEsriMDDataType,          pDataType );
 
336
        papszEsriMD = CSLAddNameValue( papszEsriMD, pEsriMDIsCloudCover,      ccSegment.c_str() );
 
337
        papszEsriMD = CSLAddNameValue( papszEsriMD, pEsriMDLinearError,       pLinearError );
 
338
        papszEsriMD = CSLAddNameValue( papszEsriMD, pEsriMDProductName,       pProductName );
 
339
        papszEsriMD = CSLAddNameValue( papszEsriMD, pEsriMDPercentCloudCover, pPercentCloudCover );
 
340
        papszEsriMD = CSLAddNameValue( papszEsriMD, pEsriMDSensorName,        pSensorName );
 
341
        papszEsriMD = CSLAddNameValue( papszEsriMD, pEsriMDSunAzimuth,        pSunAzimuth );
 
342
        papszEsriMD = CSLAddNameValue( papszEsriMD, pEsriMDSunElevation,      pSunElevation );
 
343
    }
 
344
 
 
345
    return (papszEsriMD);
 
346
}
 
347
 
 
348
/************************************************************************/
 
349
/*                          SetBandMetadata()                           */
 
350
/************************************************************************/
 
351
 
 
352
static void SetBandMetadata( NITFImage *psImage, GDALRasterBand *poBand, int nBand )
 
353
{
 
354
    if( (psImage != NULL) && (poBand != NULL) && (nBand > 0) )
 
355
    {
 
356
        NITFBandInfo *psBandInfo = psImage->pasBandInfo + nBand - 1;
 
357
 
 
358
        if( psBandInfo != NULL )
 
359
        {
 
360
            // Set metadata BandName, WavelengthMax and WavelengthMin.
 
361
 
 
362
            if ( psBandInfo->szIREPBAND != NULL )
 
363
            {
 
364
                if( EQUAL(psBandInfo->szIREPBAND,"B") )
 
365
                {
 
366
                    poBand->SetMetadataItem( "BandName", "Blue" );
 
367
                    poBand->SetMetadataItem( "WavelengthMax", psBandInfo->szISUBCAT );
 
368
                    poBand->SetMetadataItem( "WavelengthMin", psBandInfo->szISUBCAT );
 
369
                }
 
370
                else if( EQUAL(psBandInfo->szIREPBAND,"G") )
 
371
                {
 
372
                    poBand->SetMetadataItem( "BandName", "Green" );
 
373
                    poBand->SetMetadataItem( "WavelengthMax", psBandInfo->szISUBCAT );
 
374
                    poBand->SetMetadataItem( "WavelengthMin", psBandInfo->szISUBCAT );
 
375
                }
 
376
                else if( EQUAL(psBandInfo->szIREPBAND,"R") )
 
377
                {
 
378
                    poBand->SetMetadataItem( "BandName", "Red" );
 
379
                    poBand->SetMetadataItem( "WavelengthMax", psBandInfo->szISUBCAT );
 
380
                    poBand->SetMetadataItem( "WavelengthMin", psBandInfo->szISUBCAT );
 
381
                }
 
382
                else if( EQUAL(psBandInfo->szIREPBAND,"N") )
 
383
                {
 
384
                    poBand->SetMetadataItem( "BandName", "NearInfrared" );
 
385
                    poBand->SetMetadataItem( "WavelengthMax", psBandInfo->szISUBCAT );
 
386
                    poBand->SetMetadataItem( "WavelengthMin", psBandInfo->szISUBCAT );
 
387
                }
 
388
                else if( ( EQUAL(psBandInfo->szIREPBAND,"M") ) || ( ( psImage->szIREP != NULL ) && ( EQUAL(psImage->szIREP,"MONO") ) ) )
 
389
                {
 
390
                    poBand->SetMetadataItem( "BandName", "Panchromatic" );
 
391
                }
 
392
                else
 
393
                {
 
394
                    if( ( psImage->szICAT != NULL ) && ( EQUAL(psImage->szICAT,"IR") ) )
 
395
                    {
 
396
                        poBand->SetMetadataItem( "BandName", "Infrared" );
 
397
                        poBand->SetMetadataItem( "WavelengthMax", psBandInfo->szISUBCAT );
 
398
                        poBand->SetMetadataItem( "WavelengthMin", psBandInfo->szISUBCAT );
 
399
                    }
 
400
                }
 
401
            }
 
402
        }
 
403
    }
 
404
}
 
405
 
 
406
#endif /* def ESRI_BUILD */
 
407
 
988
408
/************************************************************************/
989
409
/*                              Identify()                              */
990
410
/************************************************************************/
1001
421
        return TRUE;
1002
422
 
1003
423
/* -------------------------------------------------------------------- */
 
424
/*      Avoid that on Windows, JPEG_SUBFILE:x,y,z,data/../tmp/foo.ntf   */
 
425
/*      to be recognized by the NITF driver, because                    */
 
426
/*      'JPEG_SUBFILE:x,y,z,data' is considered as a (valid) directory  */
 
427
/*      and thus the whole filename is evaluated as tmp/foo.ntf         */
 
428
/* -------------------------------------------------------------------- */
 
429
    if( EQUALN(pszFilename,"JPEG_SUBFILE:",13) )
 
430
        return FALSE;
 
431
        
 
432
/* -------------------------------------------------------------------- */
1004
433
/*      First we check to see if the file has the expected header       */
1005
434
/*      bytes.                                                          */    
1006
435
/* -------------------------------------------------------------------- */
1029
458
 
1030
459
GDALDataset *NITFDataset::Open( GDALOpenInfo * poOpenInfo )
1031
460
{
1032
 
    return Open(poOpenInfo, NULL);
 
461
    return OpenInternal(poOpenInfo, NULL, FALSE);
1033
462
}
1034
463
 
1035
 
GDALDataset *NITFDataset::Open( GDALOpenInfo * poOpenInfo, GDALDataset *poWritableJ2KDataset)
 
464
GDALDataset *NITFDataset::OpenInternal( GDALOpenInfo * poOpenInfo,
 
465
                                GDALDataset *poWritableJ2KDataset,
 
466
                                int bOpenForCreate)
1036
467
 
1037
468
{
1038
469
    int nIMIndex = -1;
1067
498
        return NULL;
1068
499
    }
1069
500
 
1070
 
    NITFCollectAttachments( psFile );
1071
 
    NITFReconcileAttachments( psFile );
 
501
    if (!bOpenForCreate)
 
502
    {
 
503
        NITFCollectAttachments( psFile );
 
504
        NITFReconcileAttachments( psFile );
 
505
    }
1072
506
 
1073
507
/* -------------------------------------------------------------------- */
1074
508
/*      Is there an image to operate on?                                */
1135
569
        poDS->nRasterXSize = 1;
1136
570
        poDS->nRasterYSize = 1;
1137
571
    }
 
572
        
 
573
    /* Can be set to NO to avoid opening the underlying JPEG2000/JPEG */
 
574
    /* stream. Might speed up operations when just metadata is needed */
 
575
    int bOpenUnderlyingDS = CSLTestBoolean(
 
576
            CPLGetConfigOption("NITF_OPEN_UNDERLYING_DS", "YES"));
1138
577
 
1139
578
/* -------------------------------------------------------------------- */
1140
579
/*      If the image is JPEG2000 (C8) compressed, we will need to       */
1148
587
    if( psImage )
1149
588
        nUsableBands = psImage->nBands;
1150
589
 
1151
 
    if( psImage != NULL && EQUAL(psImage->szIC,"C8") )
 
590
    if( bOpenUnderlyingDS && psImage != NULL && EQUAL(psImage->szIC,"C8") )
1152
591
    {
1153
592
        CPLString osDSName;
1154
593
 
1165
604
        }
1166
605
        else
1167
606
        {
1168
 
            poDS->poJ2KDataset = (GDALPamDataset *) 
1169
 
                GDALOpen( osDSName, GA_ReadOnly );
1170
 
                
 
607
            /* We explicitely list the allowed drivers to avoid hostile content */
 
608
            /* to be opened by a random driver, and also to make sure that */
 
609
            /* a future new JPEG2000 compatible driver derives from GDALPamDataset */
 
610
            static const char * const apszDrivers[] = { "JP2KAK", "JP2ECW", "JP2MRSID",
 
611
                                                        "JPEG2000", "JP2OPENJPEG", NULL };
 
612
            poDS->poJ2KDataset = (GDALPamDataset *)
 
613
                GDALOpenInternal( osDSName, GA_ReadOnly, apszDrivers);
 
614
 
1171
615
            if( poDS->poJ2KDataset == NULL )
1172
616
            {
1173
 
                CPLError( CE_Failure, CPLE_AppDefined, 
1174
 
                          "Unable to open JPEG2000 image within NITF file.\n"
1175
 
                          "Is the JP2KAK driver available?" );
 
617
                int bFoundJPEG2000Driver = FALSE;
 
618
                for(int iDriver=0;apszDrivers[iDriver]!=NULL;iDriver++)
 
619
                {
 
620
                    if (GDALGetDriverByName(apszDrivers[iDriver]) != NULL)
 
621
                        bFoundJPEG2000Driver = TRUE;
 
622
                }
 
623
 
 
624
                CPLError( CE_Failure, CPLE_AppDefined,
 
625
                        "Unable to open JPEG2000 image within NITF file.\n%s\n%s",
 
626
                         (!bFoundJPEG2000Driver) ?
 
627
                            "No JPEG2000 capable driver (JP2KAK, JP2ECW, JP2MRSID, JP2OPENJPEG, etc...) is available." :
 
628
                            "One or several JPEG2000 capable drivers are available but the datastream could not be opened successfully.",
 
629
                         "You can define the NITF_OPEN_UNDERLYING_DS configuration option to NO, in order to just get the metadata.");
1176
630
                delete poDS;
1177
631
                return NULL;
1178
632
            }
1179
 
            
 
633
 
1180
634
            poDS->poJ2KDataset->SetPamFlags( 
1181
635
                poDS->poJ2KDataset->GetPamFlags() | GPF_NOSAVE );
1182
636
        }
1230
684
/*      If the image is JPEG (C3) compressed, we will need to open      */
1231
685
/*      the image data as a JPEG dataset.                               */
1232
686
/* -------------------------------------------------------------------- */
1233
 
    else if( psImage != NULL
 
687
    else if( bOpenUnderlyingDS && psImage != NULL
1234
688
             && EQUAL(psImage->szIC,"C3") 
1235
689
             && psImage->nBlocksPerRow == 1
1236
690
             && psImage->nBlocksPerColumn == 1 )
1253
707
        poDS->poJPEGDataset = (GDALPamDataset*) GDALOpen(osDSName,GA_ReadOnly);
1254
708
        if( poDS->poJPEGDataset == NULL )
1255
709
        {
1256
 
            CPLError( CE_Failure, CPLE_AppDefined, 
1257
 
                      "Unable to open JPEG image within NITF file.\n"
1258
 
                      "Is the JPEG driver available?" );
 
710
            int bFoundJPEGDriver = GDALGetDriverByName("JPEG") != NULL;
 
711
            CPLError( CE_Failure, CPLE_AppDefined,
 
712
                    "Unable to open JPEG image within NITF file.\n%s\n%s",
 
713
                     (!bFoundJPEGDriver) ?
 
714
                        "The JPEG driver is not available." :
 
715
                        "The JPEG driver is available but the datastream could not be opened successfully.",
 
716
                     "You can define the NITF_OPEN_UNDERLYING_DS configuration option to NO, in order to just get the metadata.");
1259
717
            delete poDS;
1260
718
            return NULL;
1261
719
        }
1298
756
        {
1299
757
            GDALRasterBand* poBaseBand =
1300
758
                poBaseDS->GetRasterBand(iBand+1);
 
759
 
 
760
#ifdef ESRI_BUILD
 
761
            SetBandMetadata( psImage, poBaseBand, iBand+1 );
 
762
#endif
 
763
 
1301
764
            NITFWrapperRasterBand* poBand =
1302
765
                new NITFWrapperRasterBand(poDS, poBaseBand, iBand+1 );
1303
766
                
1339
802
                delete poDS;
1340
803
                return NULL;
1341
804
            }
 
805
 
 
806
#ifdef ESRI_BUILD
 
807
            SetBandMetadata( psImage, poBand, iBand+1 );
 
808
#endif
 
809
 
1342
810
            poDS->SetBand( iBand+1, poBand );
1343
811
        }
1344
812
    }
1346
814
/* -------------------------------------------------------------------- */
1347
815
/*      Report problems with odd bit sizes.                             */
1348
816
/* -------------------------------------------------------------------- */
1349
 
    if( psImage != NULL 
1350
 
        && psImage->nBitsPerSample != 1
1351
 
        && psImage->nBitsPerSample != 12
1352
 
        && (psImage->nBitsPerSample < 8 || psImage->nBitsPerSample % 8 != 0) 
 
817
    if( poOpenInfo->eAccess == GA_Update &&
 
818
        psImage != NULL 
 
819
        && (psImage->nBitsPerSample % 8 != 0) 
1353
820
        && poDS->poJPEGDataset == NULL
1354
821
        && poDS->poJ2KDataset == NULL )
1355
822
    {
1356
823
        CPLError( CE_Warning, CPLE_AppDefined, 
1357
 
                  "Image with %d bits per sample will not be interpreted properly.", 
 
824
                  "Image with %d bits per sample cannot be opened in update mode.", 
1358
825
                  psImage->nBitsPerSample );
 
826
        delete poDS;
 
827
        return NULL;
1359
828
    }
1360
829
 
1361
830
/* -------------------------------------------------------------------- */
1426
895
                              poDS->adfGeoTransform ) )
1427
896
    {
1428
897
        const char *pszHDR;
1429
 
        FILE *fpHDR;
 
898
        VSILFILE *fpHDR;
1430
899
        char **papszLines;
1431
900
        int isNorth;
1432
901
        int zone;
1439
908
        
1440
909
        fpHDR = VSIFOpenL( pszHDR, "rt" );
1441
910
 
1442
 
#ifndef WIN32
1443
 
        if( fpHDR == NULL )
 
911
        if( fpHDR == NULL && VSIIsCaseSensitiveFS(pszHDR) )
1444
912
        {
1445
913
            pszHDR = CPLResetExtension( pszFilename, "HDR" );
1446
914
            fpHDR = VSIFOpenL( pszHDR, "rt" );
1447
915
        }
1448
 
#endif
1449
916
    
1450
917
        if( fpHDR != NULL )
1451
918
        {
1458
925
                    isNorth=1;
1459
926
                else if (psImage->chICORDS =='S')
1460
927
                    isNorth=0;
1461
 
                else
 
928
                else if (psImage->chICORDS == 'G' || psImage->chICORDS == 'D' || psImage->chICORDS == 'C')
1462
929
                {
1463
930
                    if (psImage->dfLLY+psImage->dfLRY+psImage->dfULY+psImage->dfURY < 0)
1464
931
                        isNorth=0;
1465
932
                    else
1466
933
                        isNorth=1;
1467
934
                }
 
935
                else if (psImage->chICORDS == 'U')
 
936
                {
 
937
                    isNorth = psImage->nZone >= 0;
 
938
                }
 
939
                else
 
940
                {
 
941
                    isNorth = 1; /* arbitrarly suppose we are in northern hemisphere */
 
942
 
 
943
                    /* unless we have other information to determine the hemisphere */
 
944
                    char** papszUSE00A_MD = NITFReadSTDIDC( psImage );
 
945
                    if( papszUSE00A_MD != NULL )
 
946
                    {
 
947
                        const char* pszLocation = CSLFetchNameValue(papszUSE00A_MD, "NITF_STDIDC_LOCATION");
 
948
                        if (pszLocation && strlen(pszLocation) == 11)
 
949
                        {
 
950
                            isNorth = (pszLocation[4] == 'N');
 
951
                        }
 
952
                        CSLDestroy( papszUSE00A_MD );
 
953
                    }
 
954
                    else
 
955
                    {
 
956
                        NITFRPC00BInfo sRPCInfo;
 
957
                        if( NITFReadRPC00B( psImage, &sRPCInfo ) && sRPCInfo.SUCCESS )
 
958
                        {
 
959
                            isNorth = (sRPCInfo.LAT_OFF >= 0);
 
960
                        }
 
961
                    }
 
962
                }
 
963
 
1468
964
                if( (EQUALN(papszLines[7],
1469
965
                            "Selected Projection: Universal Transverse Mercator",50)) &&
1470
966
                    (EQUALN(papszLines[8],"Zone: ",6)) &&
1473
969
                    CPLFree( poDS->pszProjection );
1474
970
                    poDS->pszProjection = NULL;
1475
971
                    zone=atoi(&(papszLines[8][6]));
 
972
                    oSRSWork.Clear();
1476
973
                    oSRSWork.SetUTM( zone, isNorth );
1477
974
                    oSRSWork.SetWellKnownGeogCS( "WGS84" );
1478
975
                    oSRSWork.exportToWkt( &(poDS->pszProjection) );
1517
1014
 
1518
1015
        oSRS_WGS84.SetWellKnownGeogCS( "WGS84" );
1519
1016
 
 
1017
        CPLPushErrorHandler( CPLQuietErrorHandler );
1520
1018
        OGRCoordinateTransformationH hCT =
1521
1019
            (OGRCoordinateTransformationH)OGRCreateCoordinateTransformation(&oSRS_WGS84, &oSRS_AEQD);
 
1020
        CPLPopErrorHandler();
1522
1021
        if (hCT)
1523
1022
        {
1524
1023
            double dfULX_AEQD = psImage->dfULX;
1565
1064
            // natural coordinate system of the image is.  This is 
1566
1065
            // primarily used by ArcGIS (#3337)
1567
1066
 
 
1067
            CPLErrorReset();
 
1068
 
 
1069
            CPLError( CE_Warning, CPLE_AppDefined,
 
1070
                      "Failed to instantiate coordinate system transformer, likely PROJ.DLL/libproj.so is not available.  Returning image corners as lat/long GCPs as a fallback." );
 
1071
 
1568
1072
            char *pszAEQD = NULL;
1569
1073
            oSRS_AEQD.exportToWkt( &(pszAEQD) );
1570
1074
            poDS->SetMetadataItem( "GCPPROJECTIONX", pszAEQD, "IMAGE_STRUCTURE" );
1573
1077
    }
1574
1078
 
1575
1079
/* -------------------------------------------------------------------- */
 
1080
/*      Do we have RPCs?                                                */
 
1081
/* -------------------------------------------------------------------- */
 
1082
    int            bHasRPC00 = FALSE;
 
1083
    NITFRPC00BInfo sRPCInfo;
 
1084
    memset(&sRPCInfo, 0, sizeof(sRPCInfo)); /* To avoid warnings from not clever compilers */
 
1085
 
 
1086
    if( psImage && NITFReadRPC00B( psImage, &sRPCInfo ) && sRPCInfo.SUCCESS )
 
1087
        bHasRPC00 = TRUE;
 
1088
        
 
1089
/* -------------------------------------------------------------------- */
1576
1090
/*      Do we have IGEOLO data that can be treated as a                 */
1577
1091
/*      geotransform?  Our approach should support images in an         */
1578
1092
/*      affine rotated frame of reference.                              */
1587
1101
        psGCPs = (GDAL_GCP *) CPLMalloc(sizeof(GDAL_GCP) * nGCPCount);
1588
1102
        GDALInitGCPs( nGCPCount, psGCPs );
1589
1103
 
1590
 
        psGCPs[0].dfGCPPixel    = 0.0;
1591
 
        psGCPs[0].dfGCPLine             = 0.0;
 
1104
        if( psImage->bIsBoxCenterOfPixel ) 
 
1105
        {
 
1106
            psGCPs[0].dfGCPPixel        = 0.5;
 
1107
            psGCPs[0].dfGCPLine         = 0.5;
 
1108
            psGCPs[1].dfGCPPixel = poDS->nRasterXSize-0.5;
 
1109
            psGCPs[1].dfGCPLine = 0.5;
 
1110
            psGCPs[2].dfGCPPixel = poDS->nRasterXSize-0.5;
 
1111
            psGCPs[2].dfGCPLine = poDS->nRasterYSize-0.5;
 
1112
            psGCPs[3].dfGCPPixel = 0.5;
 
1113
            psGCPs[3].dfGCPLine = poDS->nRasterYSize-0.5;
 
1114
        }
 
1115
        else
 
1116
        {
 
1117
            psGCPs[0].dfGCPPixel        = 0.0;
 
1118
            psGCPs[0].dfGCPLine         = 0.0;
 
1119
            psGCPs[1].dfGCPPixel = poDS->nRasterXSize;
 
1120
            psGCPs[1].dfGCPLine = 0.0;
 
1121
            psGCPs[2].dfGCPPixel = poDS->nRasterXSize;
 
1122
            psGCPs[2].dfGCPLine = poDS->nRasterYSize;
 
1123
            psGCPs[3].dfGCPPixel = 0.0;
 
1124
            psGCPs[3].dfGCPLine = poDS->nRasterYSize;
 
1125
        }
 
1126
 
1592
1127
        psGCPs[0].dfGCPX                = psImage->dfULX;
1593
1128
        psGCPs[0].dfGCPY                = psImage->dfULY;
1594
1129
 
1595
 
        psGCPs[1].dfGCPPixel = poDS->nRasterXSize;
1596
 
        psGCPs[1].dfGCPLine = 0.0;
1597
1130
        psGCPs[1].dfGCPX                = psImage->dfURX;
1598
1131
        psGCPs[1].dfGCPY                = psImage->dfURY;
1599
1132
 
1600
 
        psGCPs[2].dfGCPPixel = poDS->nRasterXSize;
1601
 
        psGCPs[2].dfGCPLine = poDS->nRasterYSize;
1602
1133
        psGCPs[2].dfGCPX                = psImage->dfLRX;
1603
1134
        psGCPs[2].dfGCPY                = psImage->dfLRY;
1604
1135
 
1605
 
        psGCPs[3].dfGCPPixel = 0.0;
1606
 
        psGCPs[3].dfGCPLine = poDS->nRasterYSize;
1607
1136
        psGCPs[3].dfGCPX                = psImage->dfLLX;
1608
1137
        psGCPs[3].dfGCPY                = psImage->dfLLY;
 
1138
 
 
1139
/* -------------------------------------------------------------------- */
 
1140
/*      ESRI desires to use the RPCs to produce a denser and more       */
 
1141
/*      accurate set of GCPs in this case.  Details are unclear at      */
 
1142
/*      this time.                                                      */
 
1143
/* -------------------------------------------------------------------- */
 
1144
#ifdef ESRI_BUILD
 
1145
        if( bHasRPC00
 
1146
            &&  ( (psImage->chICORDS == 'G') || (psImage->chICORDS == 'C') ) )
 
1147
        {
 
1148
            if( nGCPCount == 4 )
 
1149
                NITFDensifyGCPs( &psGCPs, &nGCPCount );
 
1150
 
 
1151
            NITFUpdateGCPsWithRPC( &sRPCInfo, psGCPs, &nGCPCount );
 
1152
        }
 
1153
#endif /* def ESRI_BUILD */
1609
1154
    }
1610
1155
 
1611
1156
/* -------------------------------------------------------------------- */
1629
1174
    else if( (psImage->dfULX != 0 || psImage->dfURX != 0 
1630
1175
              || psImage->dfLRX != 0 || psImage->dfLLX != 0)
1631
1176
             && psImage->chICORDS != ' ' && 
1632
 
             ( poDS->bGotGeoTransform == FALSE ) )
 
1177
             ( poDS->bGotGeoTransform == FALSE ) &&
 
1178
             nGCPCount >= 4 )
1633
1179
    {
1634
1180
        CPLDebug( "GDAL", 
1635
1181
                  "NITFDataset::Open() wasn't able to derive a first order\n"
1636
1182
                  "geotransform.  It will be returned as GCPs.");
1637
1183
 
1638
 
        poDS->nGCPCount = 4;
1639
 
        poDS->pasGCPList = (GDAL_GCP *) CPLCalloc(sizeof(GDAL_GCP),
1640
 
                                                  poDS->nGCPCount);
1641
 
        GDALInitGCPs( 4, poDS->pasGCPList );
1642
 
 
1643
 
        poDS->pasGCPList[0].dfGCPX = psImage->dfULX;
1644
 
        poDS->pasGCPList[0].dfGCPY = psImage->dfULY;
1645
 
        poDS->pasGCPList[0].dfGCPPixel = 0;
1646
 
        poDS->pasGCPList[0].dfGCPLine = 0;
 
1184
        poDS->nGCPCount = nGCPCount;
 
1185
        poDS->pasGCPList = psGCPs;
 
1186
 
 
1187
        psGCPs = NULL;
 
1188
        nGCPCount = 0;
 
1189
 
1647
1190
        CPLFree( poDS->pasGCPList[0].pszId );
1648
1191
        poDS->pasGCPList[0].pszId = CPLStrdup( "UpperLeft" );
1649
1192
 
1650
 
        poDS->pasGCPList[1].dfGCPX = psImage->dfURX;
1651
 
        poDS->pasGCPList[1].dfGCPY = psImage->dfURY;
1652
 
        poDS->pasGCPList[1].dfGCPPixel = poDS->nRasterXSize;
1653
 
        poDS->pasGCPList[1].dfGCPLine = 0;
1654
1193
        CPLFree( poDS->pasGCPList[1].pszId );
1655
1194
        poDS->pasGCPList[1].pszId = CPLStrdup( "UpperRight" );
1656
1195
 
1657
 
        poDS->pasGCPList[2].dfGCPX = psImage->dfLLX;
1658
 
        poDS->pasGCPList[2].dfGCPY = psImage->dfLLY;
1659
 
        poDS->pasGCPList[2].dfGCPPixel = 0;
1660
 
        poDS->pasGCPList[2].dfGCPLine = poDS->nRasterYSize;
1661
1196
        CPLFree( poDS->pasGCPList[2].pszId );
1662
 
        poDS->pasGCPList[2].pszId = CPLStrdup( "LowerLeft" );
 
1197
        poDS->pasGCPList[2].pszId = CPLStrdup( "LowerRight" );
1663
1198
 
1664
 
        poDS->pasGCPList[3].dfGCPX = psImage->dfLRX;
1665
 
        poDS->pasGCPList[3].dfGCPY = psImage->dfLRY;
1666
 
        poDS->pasGCPList[3].dfGCPPixel = poDS->nRasterXSize;
1667
 
        poDS->pasGCPList[3].dfGCPLine = poDS->nRasterYSize;
1668
1199
        CPLFree( poDS->pasGCPList[3].pszId );
1669
 
        poDS->pasGCPList[3].pszId = CPLStrdup( "LowerRight" );
 
1200
        poDS->pasGCPList[3].pszId = CPLStrdup( "LowerLeft" );
1670
1201
 
1671
1202
        poDS->pszGCPProjection = CPLStrdup( poDS->pszProjection );
1672
1203
    }
1673
1204
 
1674
1205
    // This cleans up the original copy of the GCPs used to test if 
1675
 
    // this IGEOLO could be used for a geotransform.
 
1206
    // this IGEOLO could be used for a geotransform if we did not
 
1207
    // steal the to use as primary gcps.
1676
1208
    if( nGCPCount > 0 )
1677
1209
    {
1678
1210
        GDALDeinitGCPs( nGCPCount, psGCPs );
1690
1222
/*      Do we have metadata.                                            */
1691
1223
/* -------------------------------------------------------------------- */
1692
1224
    char **papszMergedMD;
1693
 
    char **papszUSE00A_MD;
 
1225
    char **papszTRE_MD;
1694
1226
 
1695
1227
    // File and Image level metadata.
1696
1228
    papszMergedMD = CSLDuplicate( poDS->psFile->papszMetadata );
1745
1277
                                 psImage->szIMAG );
1746
1278
        }
1747
1279
 
1748
 
        // USE00A 
1749
 
        papszUSE00A_MD = NITFReadUSE00A( psImage );
1750
 
        if( papszUSE00A_MD != NULL )
1751
 
        {
1752
 
            papszMergedMD = CSLInsertStrings( papszMergedMD, 
1753
 
                                              CSLCount( papszUSE00A_MD ),
1754
 
                                              papszUSE00A_MD );
1755
 
            CSLDestroy( papszUSE00A_MD );
1756
 
        }
1757
 
        
 
1280
        papszMergedMD = NITFGenericMetadataRead(papszMergedMD, psFile, psImage, NULL);
 
1281
 
1758
1282
        // BLOCKA 
1759
 
        papszUSE00A_MD = NITFReadBLOCKA( psImage );
1760
 
        if( papszUSE00A_MD != NULL )
1761
 
        {
1762
 
            papszMergedMD = CSLInsertStrings( papszMergedMD, 
1763
 
                                              CSLCount( papszUSE00A_MD ),
1764
 
                                              papszUSE00A_MD );
1765
 
            CSLDestroy( papszUSE00A_MD );
1766
 
        }
1767
 
        
1768
 
        papszUSE00A_MD = NITFReadSTDIDC( psImage );
1769
 
        if( papszUSE00A_MD != NULL )
1770
 
        {
1771
 
            papszMergedMD = CSLInsertStrings( papszMergedMD, 
1772
 
                                              CSLCount( papszUSE00A_MD ),
1773
 
                                              papszUSE00A_MD );
1774
 
            CSLDestroy( papszUSE00A_MD );
1775
 
        }
1776
 
    }
1777
 
        
 
1283
        papszTRE_MD = NITFReadBLOCKA( psImage );
 
1284
        if( papszTRE_MD != NULL )
 
1285
        {
 
1286
            papszMergedMD = CSLInsertStrings( papszMergedMD, 
 
1287
                                              CSLCount( papszTRE_MD ),
 
1288
                                              papszTRE_MD );
 
1289
            CSLDestroy( papszTRE_MD );
 
1290
        }
 
1291
    }
 
1292
        
 
1293
#ifdef ESRI_BUILD
 
1294
    // Extract ESRI generic metadata.
 
1295
    char **papszESRI_MD = ExtractEsriMD( papszMergedMD );
 
1296
    if( papszESRI_MD != NULL )
 
1297
    {
 
1298
        papszMergedMD = CSLInsertStrings( papszMergedMD, 
 
1299
                                          CSLCount( papszESRI_MD ),
 
1300
                                          papszESRI_MD );
 
1301
        CSLDestroy( papszESRI_MD );
 
1302
    }
 
1303
#endif
 
1304
 
1778
1305
    poDS->SetMetadata( papszMergedMD );
1779
1306
    CSLDestroy( papszMergedMD );
1780
1307
 
1805
1332
/* -------------------------------------------------------------------- */
1806
1333
/*      Do we have RPC info.                                            */
1807
1334
/* -------------------------------------------------------------------- */
1808
 
    NITFRPC00BInfo sRPCInfo;
1809
 
 
1810
 
    if( psImage
1811
 
        && NITFReadRPC00B( psImage, &sRPCInfo ) && sRPCInfo.SUCCESS )
 
1335
    if( psImage && bHasRPC00 )
1812
1336
    {
1813
1337
        char szValue[1280];
1814
1338
        int  i;
2022
1546
        poDS->SetPhysicalFilename( pszFilename );
2023
1547
    }
2024
1548
 
 
1549
    poDS->bInLoadXML = TRUE;
2025
1550
    poDS->TryLoadXML();
 
1551
    poDS->bInLoadXML = FALSE;
 
1552
 
 
1553
/* -------------------------------------------------------------------- */
 
1554
/*      Do we have a special overview file?  If not, do we have         */
 
1555
/*      RSets that should be treated as an overview file?               */
 
1556
/* -------------------------------------------------------------------- */
 
1557
    const char *pszOverviewFile = 
 
1558
        poDS->GetMetadataItem( "OVERVIEW_FILE", "OVERVIEWS" );
 
1559
 
 
1560
    if( pszOverviewFile == NULL )
 
1561
    {
 
1562
        if( poDS->CheckForRSets(pszFilename) )
 
1563
            pszOverviewFile = poDS->osRSetVRT;
 
1564
    }        
2026
1565
 
2027
1566
/* -------------------------------------------------------------------- */
2028
1567
/*      If we have jpeg or jpeg2000 bands we may need to set the        */
2032
1571
    if( poDS->poJPEGDataset )
2033
1572
        poSubDS = poDS->poJPEGDataset;
2034
1573
 
2035
 
    const char *pszOverviewFile = 
2036
 
        poDS->GetMetadataItem( "OVERVIEW_FILE", "OVERVIEWS" );
2037
 
 
2038
1574
    if( poSubDS && pszOverviewFile != NULL )
2039
1575
    {
2040
1576
        poSubDS->SetMetadataItem( "OVERVIEW_FILE", 
2170
1706
    const char *pszGEOPSB , *pszPRJPSB, *pszMAPLOB;
2171
1707
    OGRSpatialReference oSRS;
2172
1708
    char szName[81];
 
1709
    int nGEOPSBSize, nPRJPSBSize, nMAPLOBSize;
2173
1710
 
2174
 
    pszGEOPSB = NITFFindTRE( psFile->pachTRE, psFile->nTREBytes,"GEOPSB",NULL);
2175
 
    pszPRJPSB = NITFFindTRE( psFile->pachTRE, psFile->nTREBytes,"PRJPSB",NULL);
2176
 
    pszMAPLOB = NITFFindTRE(psImage->pachTRE,psImage->nTREBytes,"MAPLOB",NULL);
 
1711
    pszGEOPSB = NITFFindTRE( psFile->pachTRE, psFile->nTREBytes,"GEOPSB",&nGEOPSBSize);
 
1712
    pszPRJPSB = NITFFindTRE( psFile->pachTRE, psFile->nTREBytes,"PRJPSB",&nPRJPSBSize);
 
1713
    pszMAPLOB = NITFFindTRE(psImage->pachTRE,psImage->nTREBytes,"MAPLOB",&nMAPLOBSize);
2177
1714
 
2178
1715
    if( pszGEOPSB == NULL || pszPRJPSB == NULL || pszMAPLOB == NULL )
2179
1716
        return;
2181
1718
/* -------------------------------------------------------------------- */
2182
1719
/*      Collect projection parameters.                                  */
2183
1720
/* -------------------------------------------------------------------- */
2184
 
    int nRemainingBytesPRJPSB = psFile->nTREBytes - (pszPRJPSB - psFile->pachTRE);
2185
1721
 
2186
1722
    char szParm[16];
2187
 
    if (nRemainingBytesPRJPSB < 82 + 1)
 
1723
    if (nPRJPSBSize < 82 + 1)
2188
1724
    {
2189
1725
        CPLError(CE_Failure, CPLE_AppDefined,
2190
1726
                 "Cannot read PRJPSB TRE. Not enough bytes");
2195
1731
    double adfParm[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
2196
1732
    double dfFN;
2197
1733
    double dfFE;
2198
 
    if (nRemainingBytesPRJPSB < 83+15*nParmCount+15+15)
 
1734
    if (nPRJPSBSize < 83+15*nParmCount+15+15)
2199
1735
    {
2200
1736
        CPLError(CE_Failure, CPLE_AppDefined,
2201
1737
                 "Cannot read PRJPSB TRE. Not enough bytes");
2294
1830
/* -------------------------------------------------------------------- */
2295
1831
/*      Try to apply the datum.                                         */
2296
1832
/* -------------------------------------------------------------------- */
2297
 
    int nRemainingBytesGEOPSB = psFile->nTREBytes - (pszGEOPSB - psFile->pachTRE);
2298
 
    if (nRemainingBytesGEOPSB < 86 + 4)
 
1833
    if (nGEOPSBSize < 86 + 4)
2299
1834
    {
2300
1835
        CPLError(CE_Failure, CPLE_AppDefined,
2301
1836
                 "Cannot read GEOPSB TRE. Not enough bytes");
2309
1844
    double adfGT[6];
2310
1845
    double dfMeterPerUnit = 1.0;
2311
1846
 
2312
 
    int nRemainingBytesMAPLOB = psImage->nTREBytes - (pszMAPLOB - psImage->pachTRE);
2313
 
    if (nRemainingBytesMAPLOB < 28 + 15)
 
1847
    if (nMAPLOBSize < 28 + 15)
2314
1848
    {
2315
1849
        CPLError(CE_Failure, CPLE_AppDefined,
2316
1850
                 "Cannot read MAPLOB TRE. Not enough bytes");
2352
1886
    oSRS.exportToWkt( &pszProjection );
2353
1887
 
2354
1888
    memcpy( adfGeoTransform, adfGT, sizeof(double)*6 );
 
1889
    bGotGeoTransform = TRUE;
2355
1890
}
2356
1891
 
2357
1892
/************************************************************************/
2544
2079
    return CE_None;
2545
2080
}
2546
2081
 
 
2082
#ifdef ESRI_BUILD
 
2083
/************************************************************************/
 
2084
/*                       InitializeNITFDESMetadata()                    */
 
2085
/************************************************************************/
 
2086
 
 
2087
void NITFDataset::InitializeNITFDESMetadata()
 
2088
{
 
2089
    static const char   *pszDESMetadataDomain       = "NITF_DES_METADATA";
 
2090
    static const char   *pszDESsDomain              = "NITF_DES";
 
2091
    static const char   *pszMDXmlDataContentDESDATA = "NITF_DES_XML_DATA_CONTENT_DESDATA";
 
2092
    static const char   *pszXmlDataContent          = "XML_DATA_CONTENT";
 
2093
    static const int     idxXmlDataContentDESDATA   = 973;
 
2094
    static const int     sizeXmlDataContent         = (int)strlen(pszXmlDataContent);
 
2095
 
 
2096
    char **ppszDESMetadataList = oSpecialMD.GetMetadata( pszDESMetadataDomain );
 
2097
 
 
2098
    if( ppszDESMetadataList != NULL ) return;
 
2099
 
 
2100
    char **ppszDESsList = this->GetMetadata( pszDESsDomain );
 
2101
 
 
2102
    if( ppszDESsList == NULL ) return;
 
2103
 
 
2104
    bool          foundXmlDataContent = false;
 
2105
    char         *pachNITFDES         = NULL;
 
2106
 
 
2107
    // Set metadata "NITF_DES_XML_DATA_CONTENT_DESDATA".
 
2108
    // NOTE: There should only be one instance of XML_DATA_CONTENT DES.
 
2109
 
 
2110
    while( ((pachNITFDES = *ppszDESsList) != NULL) && (!foundXmlDataContent) )
 
2111
    {
 
2112
        // The data stream has been Base64 encoded, need to decode it.
 
2113
        // NOTE: The actual length of the DES data stream is appended at the beginning of the encoded
 
2114
        //       data and is separated by a space.
 
2115
 
 
2116
        const char* pszSpace = strchr(pachNITFDES, ' ');
 
2117
 
 
2118
        char* pszData = NULL;
 
2119
        int   nDataLen = 0;
 
2120
        if( pszSpace )
 
2121
        {
 
2122
            pszData = CPLStrdup( pszSpace+1 );
 
2123
            nDataLen = CPLBase64DecodeInPlace((GByte*)pszData);
 
2124
            pszData[nDataLen] = 0;
 
2125
        }
 
2126
 
 
2127
        if ( nDataLen > 2 + sizeXmlDataContent && EQUALN(pszData, "DE", 2) )
 
2128
        {
 
2129
            // Check to see if this is a XML_DATA_CONTENT DES.
 
2130
            if ( EQUALN(pszData + 2, pszXmlDataContent, sizeXmlDataContent) &&
 
2131
                 nDataLen > idxXmlDataContentDESDATA )
 
2132
            {
 
2133
                foundXmlDataContent = true;
 
2134
 
 
2135
                // Get the value of the DESDATA field and set metadata "NITF_DES_XML_DATA_CONTENT_DESDATA".
 
2136
                const char* pszXML = pszData + idxXmlDataContentDESDATA;
 
2137
 
 
2138
                // Set the metadata.
 
2139
                oSpecialMD.SetMetadataItem( pszMDXmlDataContentDESDATA, pszXML, pszDESMetadataDomain );
 
2140
            }
 
2141
        }
 
2142
 
 
2143
        CPLFree(pszData);
 
2144
 
 
2145
        pachNITFDES   = NULL;
 
2146
        ppszDESsList += 1;
 
2147
    }
 
2148
}
 
2149
 
 
2150
 
 
2151
/************************************************************************/
 
2152
/*                       InitializeNITFDESs()                           */
 
2153
/************************************************************************/
 
2154
 
 
2155
void NITFDataset::InitializeNITFDESs()
 
2156
{
 
2157
    static const char *pszDESsDomain = "NITF_DES";
 
2158
 
 
2159
    char **ppszDESsList = oSpecialMD.GetMetadata( pszDESsDomain );
 
2160
 
 
2161
    if( ppszDESsList != NULL ) return;
 
2162
 
 
2163
/* -------------------------------------------------------------------- */
 
2164
/*  Go through all the segments and process all DES segments.           */
 
2165
/* -------------------------------------------------------------------- */
 
2166
 
 
2167
    char               *pachDESData  = NULL;
 
2168
    int                 nDESDataSize = 0;
 
2169
    std::string         encodedDESData("");
 
2170
    CPLStringList       aosList;
 
2171
 
 
2172
    for( int iSegment = 0; iSegment < psFile->nSegmentCount; iSegment++ )
 
2173
    {
 
2174
        NITFSegmentInfo *psSegInfo = psFile->pasSegmentInfo + iSegment;
 
2175
 
 
2176
        if( EQUAL(psSegInfo->szSegmentType,"DE") )
 
2177
        {
 
2178
            nDESDataSize = psSegInfo->nSegmentHeaderSize + psSegInfo->nSegmentSize;
 
2179
            pachDESData  = (char*) VSIMalloc( nDESDataSize + 1 );
 
2180
 
 
2181
            if (pachDESData == NULL)
 
2182
            {
 
2183
                CPLError( CE_Failure, CPLE_OutOfMemory, "Cannot allocate memory for DES segment" );
 
2184
                return;
 
2185
            }
 
2186
 
 
2187
            if( VSIFSeekL( psFile->fp, psSegInfo->nSegmentHeaderStart,
 
2188
                          SEEK_SET ) != 0
 
2189
                || (int)VSIFReadL( pachDESData, 1, nDESDataSize,
 
2190
                             psFile->fp ) != nDESDataSize )
 
2191
            {
 
2192
                CPLError( CE_Failure, CPLE_FileIO,
 
2193
                          "Failed to read %d byte DES subheader from " CPL_FRMT_GUIB ".",
 
2194
                          nDESDataSize,
 
2195
                          psSegInfo->nSegmentHeaderStart );
 
2196
                CPLFree( pachDESData );
 
2197
                return;
 
2198
            }
 
2199
 
 
2200
            pachDESData[nDESDataSize] = '\0';
 
2201
 
 
2202
/* -------------------------------------------------------------------- */
 
2203
/*          Accumulate all the DES segments.                            */
 
2204
/* -------------------------------------------------------------------- */
 
2205
 
 
2206
            char* pszBase64 = CPLBase64Encode( nDESDataSize, (const GByte *)pachDESData );
 
2207
            encodedDESData = pszBase64;
 
2208
            CPLFree(pszBase64);
 
2209
 
 
2210
            CPLFree( pachDESData );
 
2211
            pachDESData = NULL;
 
2212
 
 
2213
            if( encodedDESData.empty() )
 
2214
            {
 
2215
                CPLError(CE_Failure, CPLE_AppDefined, "Failed to encode DES subheader data!");
 
2216
                return;
 
2217
            }
 
2218
 
 
2219
            // The length of the DES subheader data plus a space is append to the beginning of the encoded
 
2220
            // string so that we can recover the actual length of the image subheader when we decode it.
 
2221
 
 
2222
            char buffer[20];
 
2223
 
 
2224
            sprintf(buffer, "%d", nDESDataSize);
 
2225
 
 
2226
            std::string desSubheaderStr(buffer);
 
2227
            desSubheaderStr.append(" ");
 
2228
            desSubheaderStr.append(encodedDESData);
 
2229
 
 
2230
            aosList.AddString(desSubheaderStr.c_str() );
 
2231
        }
 
2232
    }
 
2233
 
 
2234
    if (aosList.size() > 0)
 
2235
        oSpecialMD.SetMetadata( aosList.List(), pszDESsDomain );
 
2236
}
 
2237
 
 
2238
/************************************************************************/
 
2239
/*                       InitializeNITFTREs()                           */
 
2240
/************************************************************************/
 
2241
 
 
2242
void NITFDataset::InitializeNITFTREs()
 
2243
{
 
2244
    static const char *pszFileHeaderTREsDomain   = "NITF_FILE_HEADER_TRES";
 
2245
    static const char *pszImageSegmentTREsDomain = "NITF_IMAGE_SEGMENT_TRES";
 
2246
 
 
2247
    char **ppszFileHeaderTREsList   = oSpecialMD.GetMetadata( pszFileHeaderTREsDomain );
 
2248
    char **ppszImageSegmentTREsList = oSpecialMD.GetMetadata( pszImageSegmentTREsDomain );
 
2249
 
 
2250
    if( (ppszFileHeaderTREsList != NULL) && (ppszImageSegmentTREsList != NULL ) ) return;
 
2251
 
 
2252
/* -------------------------------------------------------------------- */
 
2253
/*      Loop over TRE sources (file and image).                         */
 
2254
/* -------------------------------------------------------------------- */
 
2255
 
 
2256
    for( int nTRESrc = 0; nTRESrc < 2; nTRESrc++ )
 
2257
    {
 
2258
        int                 nTREBytes  = 0;
 
2259
        char               *pszTREData = NULL;
 
2260
        const char         *pszTREsDomain = NULL;
 
2261
        CPLStringList       aosList;
 
2262
 
 
2263
/* -------------------------------------------------------------------- */
 
2264
/*      Extract file header or image segment TREs.                      */
 
2265
/* -------------------------------------------------------------------- */
 
2266
 
 
2267
        if( nTRESrc == 0 )
 
2268
        {
 
2269
            if( ppszFileHeaderTREsList != NULL ) continue;
 
2270
 
 
2271
            nTREBytes     = psFile->nTREBytes;
 
2272
            pszTREData    = psFile->pachTRE;
 
2273
            pszTREsDomain = pszFileHeaderTREsDomain;
 
2274
        }
 
2275
        else
 
2276
        {
 
2277
            if( ppszImageSegmentTREsList != NULL ) continue;
 
2278
 
 
2279
            if( psImage )
 
2280
            {
 
2281
                nTREBytes     = psImage->nTREBytes;
 
2282
                pszTREData    = psImage->pachTRE;
 
2283
                pszTREsDomain = pszImageSegmentTREsDomain;
 
2284
            }
 
2285
            else
 
2286
            {
 
2287
                nTREBytes  = 0;
 
2288
                pszTREData = NULL;
 
2289
            }
 
2290
        }
 
2291
 
 
2292
/* -------------------------------------------------------------------- */
 
2293
/*      Loop over TREs.                                                 */
 
2294
/* -------------------------------------------------------------------- */
 
2295
 
 
2296
        while( nTREBytes >= 11 )
 
2297
        {
 
2298
            char szTemp[100];
 
2299
            char szTag[7];
 
2300
            char *pszEscapedData = NULL;
 
2301
            int nThisTRESize = atoi(NITFGetField(szTemp, pszTREData, 6, 5 ));
 
2302
 
 
2303
            if (nThisTRESize < 0)
 
2304
            {
 
2305
                NITFGetField(szTemp, pszTREData, 0, 6 );
 
2306
                CPLError(CE_Failure, CPLE_AppDefined, "Invalid size (%d) for TRE %s",
 
2307
                        nThisTRESize, szTemp);
 
2308
                return;
 
2309
            }
 
2310
 
 
2311
            if (nThisTRESize > nTREBytes - 11)
 
2312
            {
 
2313
                CPLError(CE_Failure, CPLE_AppDefined, "Not enough bytes in TRE");
 
2314
                return;
 
2315
            }
 
2316
 
 
2317
            strncpy( szTag, pszTREData, 6 );
 
2318
            szTag[6] = '\0';
 
2319
 
 
2320
            // trim white off tag.
 
2321
            while( strlen(szTag) > 0 && szTag[strlen(szTag)-1] == ' ' )
 
2322
                szTag[strlen(szTag)-1] = '\0';
 
2323
 
 
2324
            // escape data.
 
2325
            pszEscapedData = CPLEscapeString( pszTREData + 6,
 
2326
                                              nThisTRESize + 5,
 
2327
                                              CPLES_BackslashQuotable );
 
2328
 
 
2329
            char * pszLine = (char *) CPLMalloc( strlen(szTag)+strlen(pszEscapedData)+2 );
 
2330
            sprintf( pszLine, "%s=%s", szTag, pszEscapedData );
 
2331
            aosList.AddString(pszLine);
 
2332
            CPLFree(pszLine);
 
2333
            pszLine        = NULL;
 
2334
 
 
2335
            CPLFree( pszEscapedData );
 
2336
            pszEscapedData = NULL;
 
2337
 
 
2338
            nTREBytes  -= (nThisTRESize + 11);
 
2339
            pszTREData += (nThisTRESize + 11);
 
2340
        }
 
2341
 
 
2342
        if (aosList.size() > 0)
 
2343
            oSpecialMD.SetMetadata( aosList.List(), pszTREsDomain );
 
2344
    }
 
2345
}
 
2346
#endif
 
2347
 
 
2348
/************************************************************************/
 
2349
/*                       InitializeNITFMetadata()                        */
 
2350
/************************************************************************/
 
2351
 
 
2352
void NITFDataset::InitializeNITFMetadata()
 
2353
 
 
2354
{
 
2355
    static const char *pszDomainName            = "NITF_METADATA";
 
2356
    static const char *pszTagNITFFileHeader     = "NITFFileHeader";
 
2357
    static const char *pszTagNITFImageSubheader = "NITFImageSubheader";
 
2358
 
 
2359
    if( oSpecialMD.GetMetadata( pszDomainName ) != NULL )
 
2360
        return;
 
2361
 
 
2362
    // nHeaderLenOffset is the number of bytes to skip from the beginning of the NITF file header
 
2363
    // in order to get to the field HL (NITF file header length).
 
2364
 
 
2365
    int nHeaderLen       = 0;
 
2366
    int nHeaderLenOffset = 0;
 
2367
 
 
2368
    // Get the NITF file header length.
 
2369
 
 
2370
    if( psFile->pachHeader != NULL )
 
2371
    {
 
2372
        if ( (strncmp(psFile->pachHeader, "NITF02.10", 9) == 0) || (strncmp(psFile->pachHeader, "NSIF01.00", 9) == 0) )
 
2373
            nHeaderLenOffset = 354;
 
2374
        else if ( (strncmp(psFile->pachHeader, "NITF01.10", 9) == 0) || (strncmp(psFile->pachHeader, "NITF02.00", 9) == 0) )
 
2375
            nHeaderLenOffset = ( strncmp((psFile->pachHeader+280), "999998", 6 ) == 0 ) ? 394 : 354;
 
2376
    }
 
2377
 
 
2378
    char fieldHL[7];
 
2379
 
 
2380
    if( nHeaderLenOffset > 0 )
 
2381
    {
 
2382
        char *pszFieldHL = psFile->pachHeader + nHeaderLenOffset;
 
2383
 
 
2384
        memcpy(fieldHL, pszFieldHL, 6);
 
2385
        fieldHL[6] = '\0';
 
2386
        nHeaderLen = atoi(fieldHL);
 
2387
    }
 
2388
 
 
2389
    if( nHeaderLen <= 0 )
 
2390
    {
 
2391
        CPLError(CE_Failure, CPLE_AppDefined, "Zero length NITF file header!");
 
2392
        return;
 
2393
    }
 
2394
 
 
2395
    char *encodedHeader = CPLBase64Encode(nHeaderLen, 
 
2396
                                          (GByte*)psFile->pachHeader);
 
2397
 
 
2398
    if (encodedHeader == NULL || strlen(encodedHeader) == 0 )
 
2399
    {
 
2400
        CPLError(CE_Failure, CPLE_AppDefined, 
 
2401
                 "Failed to encode NITF file header!");
 
2402
        return;
 
2403
    }
 
2404
 
 
2405
    // The length of the NITF file header plus a space is append to the beginning of the encoded string so
 
2406
    // that we can recover the length of the NITF file header when we decode it without having to pull it
 
2407
    // out the HL field again.
 
2408
 
 
2409
    std::string nitfFileheaderStr(fieldHL);
 
2410
    nitfFileheaderStr.append(" ");
 
2411
    nitfFileheaderStr.append(encodedHeader);
 
2412
 
 
2413
    CPLFree( encodedHeader );
 
2414
 
 
2415
    oSpecialMD.SetMetadataItem( pszTagNITFFileHeader, nitfFileheaderStr.c_str(), pszDomainName );
 
2416
 
 
2417
    // Get the image subheader length.
 
2418
 
 
2419
    int nImageSubheaderLen = 0;
 
2420
    
 
2421
    for( int i = 0; i < psFile->nSegmentCount; ++i )
 
2422
    {
 
2423
        if (strncmp(psFile->pasSegmentInfo[i].szSegmentType, "IM", 2) == 0)
 
2424
        {
 
2425
            nImageSubheaderLen = psFile->pasSegmentInfo[i].nSegmentHeaderSize;
 
2426
            break;
 
2427
        }
 
2428
    }
 
2429
 
 
2430
    if( nImageSubheaderLen < 0 )
 
2431
    {
 
2432
        CPLError(CE_Failure, CPLE_AppDefined, "Invalid length NITF image subheader!");
 
2433
        return;
 
2434
    }
 
2435
 
 
2436
    if( nImageSubheaderLen > 0 )
 
2437
    {
 
2438
        char *encodedImageSubheader = CPLBase64Encode(nImageSubheaderLen,(GByte*) psImage->pachHeader);
 
2439
    
 
2440
        if( encodedImageSubheader == NULL || strlen(encodedImageSubheader) ==0 )
 
2441
        {
 
2442
            CPLError(CE_Failure, CPLE_AppDefined, 
 
2443
                     "Failed to encode image subheader!");
 
2444
            return;
 
2445
        }
 
2446
 
 
2447
        // The length of the image subheader plus a space is append to the beginning of the encoded string so
 
2448
        // that we can recover the actual length of the image subheader when we decode it.
 
2449
      
 
2450
        char buffer[20];
 
2451
 
 
2452
        sprintf(buffer, "%d", nImageSubheaderLen);
 
2453
 
 
2454
        std::string imageSubheaderStr(buffer);
 
2455
        imageSubheaderStr.append(" ");
 
2456
        imageSubheaderStr.append(encodedImageSubheader);
 
2457
 
 
2458
        CPLFree( encodedImageSubheader );
 
2459
 
 
2460
        oSpecialMD.SetMetadataItem( pszTagNITFImageSubheader, imageSubheaderStr.c_str(), pszDomainName );
 
2461
    }
 
2462
}
 
2463
 
2547
2464
/************************************************************************/
2548
2465
/*                       InitializeCGMMetadata()                        */
2549
2466
/************************************************************************/
2604
2521
/* -------------------------------------------------------------------- */
2605
2522
        char *pabyCGMData, *pszEscapedCGMData;
2606
2523
 
2607
 
        pabyCGMData = (char *) CPLCalloc(1,(size_t)psSegment->nSegmentSize);
 
2524
        pabyCGMData = (char *) VSICalloc(1,(size_t)psSegment->nSegmentSize);
 
2525
        if (pabyCGMData == NULL)
 
2526
        {
 
2527
            CPLError( CE_Failure, CPLE_OutOfMemory, "Out of memory");
 
2528
            CSLDestroy( papszCGMMetadata );
 
2529
            return;
 
2530
        }
2608
2531
        if( VSIFSeekL( psFile->fp, psSegment->nSegmentStart, 
2609
2532
                       SEEK_SET ) != 0 
2610
2533
            || VSIFReadL( pabyCGMData, 1, (size_t)psSegment->nSegmentSize, 
2614
2537
                      "Failed to read " CPL_FRMT_GUIB " bytes of graphic data at " CPL_FRMT_GUIB ".", 
2615
2538
                      psSegment->nSegmentSize,
2616
2539
                      psSegment->nSegmentStart );
 
2540
            CPLFree(pabyCGMData);
 
2541
            CSLDestroy( papszCGMMetadata );
2617
2542
            return;
2618
2543
        }
2619
2544
 
2620
2545
        pszEscapedCGMData = CPLEscapeString( pabyCGMData, 
2621
2546
                                             (int)psSegment->nSegmentSize, 
2622
2547
                                             CPLES_BackslashQuotable );
 
2548
        if (pszEscapedCGMData == NULL)
 
2549
        {
 
2550
            CPLError( CE_Failure, CPLE_OutOfMemory, "Out of memory");
 
2551
            CPLFree(pabyCGMData);
 
2552
            CSLDestroy( papszCGMMetadata );
 
2553
            return;
 
2554
        }
2623
2555
 
2624
2556
        papszCGMMetadata = 
2625
2557
            CSLSetNameValue( papszCGMMetadata, 
2658
2590
    int iText = 0;
2659
2591
 
2660
2592
/* ==================================================================== */
2661
 
/*      Process all graphics segments.                                  */
 
2593
/*      Process all text segments.                                  */
2662
2594
/* ==================================================================== */
2663
2595
    for( iSegment = 0; iSegment < psFile->nSegmentCount; iSegment++ )
2664
2596
    {
2668
2600
            continue;
2669
2601
 
2670
2602
/* -------------------------------------------------------------------- */
 
2603
/*      Load the text header                                            */
 
2604
/* -------------------------------------------------------------------- */
 
2605
 
 
2606
        /* Allocate one extra byte for the NULL terminating character */
 
2607
        char *pabyHeaderData = (char *) CPLCalloc(1,
 
2608
                (size_t) psSegment->nSegmentHeaderSize + 1);
 
2609
        if (VSIFSeekL(psFile->fp, psSegment->nSegmentHeaderStart,
 
2610
                      SEEK_SET) != 0 ||
 
2611
            VSIFReadL(pabyHeaderData, 1, (size_t) psSegment->nSegmentHeaderSize,
 
2612
                      psFile->fp) != psSegment->nSegmentHeaderSize)
 
2613
        {
 
2614
            CPLError( CE_Warning, CPLE_FileIO,
 
2615
                      "Failed to read %d bytes of text header data at " CPL_FRMT_GUIB ".",
 
2616
                      psSegment->nSegmentHeaderSize,
 
2617
                      psSegment->nSegmentHeaderStart);
 
2618
            CPLFree(pabyHeaderData);
 
2619
            return;
 
2620
        }
 
2621
 
 
2622
        oSpecialMD.SetMetadataItem( CPLString().Printf("HEADER_%d", iText),
 
2623
                                    pabyHeaderData, "TEXT");
 
2624
        CPLFree(pabyHeaderData);
 
2625
 
 
2626
/* -------------------------------------------------------------------- */
2671
2627
/*      Load the raw TEXT data itself.                                  */
2672
2628
/* -------------------------------------------------------------------- */
2673
2629
        char *pabyTextData;
2674
2630
 
2675
2631
        /* Allocate one extra byte for the NULL terminating character */
2676
 
        pabyTextData = (char *) CPLCalloc(1,(size_t)psSegment->nSegmentSize+1);
 
2632
        pabyTextData = (char *) VSICalloc(1,(size_t)psSegment->nSegmentSize+1);
 
2633
        if (pabyTextData == NULL)
 
2634
        {
 
2635
            CPLError( CE_Failure, CPLE_OutOfMemory, "Out of memory");
 
2636
            return;
 
2637
        }
2677
2638
        if( VSIFSeekL( psFile->fp, psSegment->nSegmentStart, 
2678
2639
                       SEEK_SET ) != 0 
2679
2640
            || VSIFReadL( pabyTextData, 1, (size_t)psSegment->nSegmentSize, 
2683
2644
                      "Failed to read " CPL_FRMT_GUIB " bytes of text data at " CPL_FRMT_GUIB ".", 
2684
2645
                      psSegment->nSegmentSize,
2685
2646
                      psSegment->nSegmentStart );
 
2647
            CPLFree( pabyTextData );
2686
2648
            return;
2687
2649
        }
2688
2650
 
2704
2666
    if( oSpecialMD.GetMetadata( "TRE" ) != NULL )
2705
2667
        return;
2706
2668
 
 
2669
    CPLXMLNode* psTresNode = CPLCreateXMLNode(NULL, CXT_Element, "tres");
 
2670
 
2707
2671
/* -------------------------------------------------------------------- */
2708
2672
/*      Loop over TRE sources (file and image).                         */
2709
2673
/* -------------------------------------------------------------------- */
2763
2727
            // trim white off tag. 
2764
2728
            while( strlen(szTag) > 0 && szTag[strlen(szTag)-1] == ' ' )
2765
2729
                szTag[strlen(szTag)-1] = '\0';
2766
 
            
 
2730
 
 
2731
            CPLXMLNode* psTreNode = NITFCreateXMLTre(psFile, szTag, pszTREData + 11,nThisTRESize);
 
2732
            if (psTreNode)
 
2733
            {
 
2734
                CPLCreateXMLNode(CPLCreateXMLNode(psTreNode, CXT_Attribute, "location"),
 
2735
                                 CXT_Text, nTRESrc == 0 ? "file" : "image");
 
2736
                CPLAddXMLChild(psTresNode, psTreNode);
 
2737
            }
 
2738
 
2767
2739
            // escape data. 
2768
2740
            pszEscapedData = CPLEscapeString( pszTREData + 11,
2769
2741
                                              nThisTRESize,
2770
2742
                                              CPLES_BackslashQuotable );
 
2743
            if (pszEscapedData == NULL)
 
2744
            {
 
2745
                CPLError( CE_Failure, CPLE_OutOfMemory, "Out of memory");
 
2746
                return;
 
2747
            }
2771
2748
 
2772
 
            oSpecialMD.SetMetadataItem( szTag, pszEscapedData, "TRE" );
 
2749
            char szUniqueTag[32];
 
2750
            strcpy(szUniqueTag, szTag);
 
2751
            int nCountUnique = 2;
 
2752
            while(oSpecialMD.GetMetadataItem( szUniqueTag, "TRE") != NULL)
 
2753
            {
 
2754
                sprintf(szUniqueTag, "%s_%d", szTag, nCountUnique);
 
2755
                nCountUnique ++;
 
2756
            }
 
2757
            oSpecialMD.SetMetadataItem( szUniqueTag, pszEscapedData, "TRE" );
2773
2758
            CPLFree( pszEscapedData );
2774
2759
            
2775
2760
            nTREBytes -= (nThisTRESize + 11);
2776
2761
            pszTREData += (nThisTRESize + 11);
2777
2762
        }
2778
2763
    }
 
2764
 
 
2765
/* -------------------------------------------------------------------- */
 
2766
/*      Loop over TRE in DES                                            */
 
2767
/* -------------------------------------------------------------------- */
 
2768
    int iSegment;
 
2769
    for( iSegment = 0; iSegment < psFile->nSegmentCount; iSegment++ )
 
2770
    {
 
2771
        NITFSegmentInfo *psSegInfo = psFile->pasSegmentInfo + iSegment;
 
2772
        NITFDES *psDES;
 
2773
        int nOffset = 0;
 
2774
        char szTREName[7];
 
2775
        int nThisTRESize;
 
2776
 
 
2777
        if( !EQUAL(psSegInfo->szSegmentType,"DE") )
 
2778
            continue;
 
2779
 
 
2780
        psDES = NITFDESAccess( psFile, iSegment );
 
2781
        if( psDES == NULL )
 
2782
            continue;
 
2783
 
 
2784
        char* pabyTREData = NULL;
 
2785
        nOffset = 0;
 
2786
        while (NITFDESGetTRE( psDES, nOffset, szTREName, &pabyTREData, &nThisTRESize))
 
2787
        {
 
2788
            char* pszEscapedData = CPLEscapeString( pabyTREData, nThisTRESize,
 
2789
                                                CPLES_BackslashQuotable );
 
2790
            if (pszEscapedData == NULL)
 
2791
            {
 
2792
                CPLError( CE_Failure, CPLE_OutOfMemory, "Out of memory");
 
2793
                NITFDESFreeTREData(pabyTREData);
 
2794
                NITFDESDeaccess(psDES);
 
2795
                return;
 
2796
            }
 
2797
 
 
2798
            // trim white off tag. 
 
2799
            while( strlen(szTREName) > 0 && szTREName[strlen(szTREName)-1] == ' ' )
 
2800
                szTREName[strlen(szTREName)-1] = '\0';
 
2801
 
 
2802
            CPLXMLNode* psTreNode = NITFCreateXMLTre(psFile, szTREName, pabyTREData,nThisTRESize);
 
2803
            if (psTreNode)
 
2804
            {
 
2805
                const char* pszDESID = CSLFetchNameValue(psDES->papszMetadata, "NITF_DESID");
 
2806
                CPLCreateXMLNode(CPLCreateXMLNode(psTreNode, CXT_Attribute, "location"),
 
2807
                                 CXT_Text, pszDESID ? CPLSPrintf("des %s", pszDESID) : "des");
 
2808
                CPLAddXMLChild(psTresNode, psTreNode);
 
2809
            }
 
2810
 
 
2811
            char szUniqueTag[32];
 
2812
            strcpy(szUniqueTag, szTREName);
 
2813
            int nCountUnique = 2;
 
2814
            while(oSpecialMD.GetMetadataItem( szUniqueTag, "TRE") != NULL)
 
2815
            {
 
2816
                sprintf(szUniqueTag, "%s_%d", szTREName, nCountUnique);
 
2817
                nCountUnique ++;
 
2818
            }
 
2819
            oSpecialMD.SetMetadataItem( szUniqueTag, pszEscapedData, "TRE" );
 
2820
 
 
2821
            CPLFree(pszEscapedData);
 
2822
 
 
2823
            nOffset += 11 + nThisTRESize;
 
2824
 
 
2825
            NITFDESFreeTREData(pabyTREData);
 
2826
        }
 
2827
 
 
2828
        NITFDESDeaccess(psDES);
 
2829
    }
 
2830
 
 
2831
    if (psTresNode->psChild != NULL)
 
2832
    {
 
2833
        char* pszXML = CPLSerializeXMLTree(psTresNode);
 
2834
        char* apszMD[2];
 
2835
        apszMD[0] = pszXML;
 
2836
        apszMD[1] = NULL;
 
2837
        oSpecialMD.SetMetadata( apszMD, "xml:TRE" );
 
2838
        CPLFree(pszXML);
 
2839
    }
 
2840
    CPLDestroyXMLNode(psTresNode);
2779
2841
}
2780
2842
 
2781
2843
/************************************************************************/
2785
2847
char **NITFDataset::GetMetadata( const char * pszDomain )
2786
2848
 
2787
2849
{
 
2850
    if( pszDomain != NULL && EQUAL(pszDomain,"NITF_METADATA") )
 
2851
    {
 
2852
        // InitializeNITFMetadata retrieves the NITF file header and all image segment file headers. (NOTE: The returned strings are base64-encoded).
 
2853
 
 
2854
        InitializeNITFMetadata();
 
2855
        return oSpecialMD.GetMetadata( pszDomain );
 
2856
    }
 
2857
 
 
2858
#ifdef ESRI_BUILD
 
2859
    if( pszDomain != NULL && EQUAL(pszDomain,"NITF_DES") )
 
2860
    {
 
2861
        // InitializeNITFDESs retrieves all the DES file headers (NOTE: The returned strings are base64-encoded).
 
2862
 
 
2863
        InitializeNITFDESs();
 
2864
        return oSpecialMD.GetMetadata( pszDomain );
 
2865
    }
 
2866
 
 
2867
    if( pszDomain != NULL && EQUAL(pszDomain,"NITF_DES_METADATA") )
 
2868
    {
 
2869
        // InitializeNITFDESs retrieves all the DES file headers (NOTE: The returned strings are base64-encoded).
 
2870
 
 
2871
        InitializeNITFDESMetadata();
 
2872
        return oSpecialMD.GetMetadata( pszDomain );
 
2873
    }
 
2874
 
 
2875
    if( pszDomain != NULL && EQUAL(pszDomain,"NITF_FILE_HEADER_TRES") )
 
2876
    {
 
2877
        // InitializeNITFTREs retrieves all the TREs that are resides in the NITF file header and all the
 
2878
        // TREs that are resides in the current image segment.
 
2879
        // NOTE: the returned strings are backslash-escaped
 
2880
 
 
2881
        InitializeNITFTREs();
 
2882
        return oSpecialMD.GetMetadata( pszDomain );
 
2883
    }
 
2884
 
 
2885
    if( pszDomain != NULL && EQUAL(pszDomain,"NITF_IMAGE_SEGMENT_TRES") )
 
2886
    {
 
2887
        // InitializeNITFTREs retrieves all the TREs that are resides in the NITF file header and all the
 
2888
        // TREs that are resides in the current image segment.
 
2889
        // NOTE: the returned strings are backslash-escaped
 
2890
 
 
2891
        InitializeNITFTREs();
 
2892
        return oSpecialMD.GetMetadata( pszDomain );
 
2893
    }
 
2894
#endif
 
2895
 
2788
2896
    if( pszDomain != NULL && EQUAL(pszDomain,"CGM") )
2789
2897
    {
2790
2898
        InitializeCGMMetadata();
2803
2911
        return oSpecialMD.GetMetadata( pszDomain );
2804
2912
    }
2805
2913
 
 
2914
    if( pszDomain != NULL && EQUAL(pszDomain,"xml:TRE") )
 
2915
    {
 
2916
        InitializeTREMetadata();
 
2917
        return oSpecialMD.GetMetadata( pszDomain );
 
2918
    }
 
2919
 
2806
2920
    return GDALPamDataset::GetMetadata( pszDomain );
2807
2921
}
2808
2922
 
2814
2928
                                         const char * pszDomain )
2815
2929
 
2816
2930
{
 
2931
    if( pszDomain != NULL && EQUAL(pszDomain,"NITF_METADATA") )
 
2932
    {
 
2933
        // InitializeNITFMetadata retrieves the NITF file header and all image segment file headers. (NOTE: The returned strings are base64-encoded).
 
2934
 
 
2935
        InitializeNITFMetadata();
 
2936
        return oSpecialMD.GetMetadataItem( pszName, pszDomain );
 
2937
    }
 
2938
 
 
2939
#ifdef ESRI_BUILD
 
2940
    if( pszDomain != NULL && EQUAL(pszDomain,"NITF_DES_METADATA") )
 
2941
    {
 
2942
        // InitializeNITFDESs retrieves all the DES file headers (NOTE: The returned strings are base64-encoded).
 
2943
 
 
2944
        InitializeNITFDESMetadata();
 
2945
        return oSpecialMD.GetMetadataItem( pszName, pszDomain );
 
2946
    }
 
2947
 
 
2948
    if( pszDomain != NULL && EQUAL(pszDomain,"NITF_FILE_HEADER_TRES") )
 
2949
    {
 
2950
        // InitializeNITFTREs retrieves all the TREs that are resides in the NITF file header and all the
 
2951
        // TREs that are resides in the current image segment.
 
2952
        // NOTE: the returned strings are backslash-escaped
 
2953
 
 
2954
        InitializeNITFTREs();
 
2955
        return oSpecialMD.GetMetadataItem( pszName, pszDomain );
 
2956
    }
 
2957
 
 
2958
    if( pszDomain != NULL && EQUAL(pszDomain,"NITF_IMAGE_SEGMENT_TRES") )
 
2959
    {
 
2960
        // InitializeNITFTREs retrieves all the TREs that are resides in the NITF file header and all the
 
2961
        // TREs that are resides in the current image segment.
 
2962
        // NOTE: the returned strings are backslash-escaped
 
2963
 
 
2964
        InitializeNITFTREs();
 
2965
        return oSpecialMD.GetMetadataItem( pszName, pszDomain );
 
2966
    }
 
2967
#endif
 
2968
 
2817
2969
    if( pszDomain != NULL && EQUAL(pszDomain,"CGM") )
2818
2970
    {
2819
2971
        InitializeCGMMetadata();
2832
2984
        return oSpecialMD.GetMetadataItem( pszName, pszDomain );
2833
2985
    }
2834
2986
 
 
2987
    if( pszDomain != NULL && EQUAL(pszDomain,"OVERVIEWS") 
 
2988
        && osRSetVRT.size() > 0 )
 
2989
        return osRSetVRT;
 
2990
 
2835
2991
    return GDALPamDataset::GetMetadataItem( pszName, pszDomain );
2836
2992
}
2837
2993
 
2870
3026
}
2871
3027
 
2872
3028
/************************************************************************/
 
3029
/*                           CheckForRSets()                            */
 
3030
/*                                                                      */
 
3031
/*      Check for reduced resolution images in .r<n> files and if       */
 
3032
/*      found return filename for a virtual file wrapping them as an    */
 
3033
/*      overview file. (#3457)                                          */
 
3034
/************************************************************************/
 
3035
 
 
3036
int NITFDataset::CheckForRSets( const char *pszNITFFilename )
 
3037
 
 
3038
{
 
3039
    bool isR0File = EQUAL(CPLGetExtension(pszNITFFilename),"r0");
 
3040
 
 
3041
/* -------------------------------------------------------------------- */
 
3042
/*      Check to see if we have RSets.                                  */
 
3043
/* -------------------------------------------------------------------- */
 
3044
    std::vector<CPLString> aosRSetFilenames;
 
3045
    int i;
 
3046
 
 
3047
    for( i = 1; i <= 5; i++ )
 
3048
    {
 
3049
        CPLString osTarget;
 
3050
        VSIStatBufL sStat;
 
3051
 
 
3052
        if ( isR0File )
 
3053
        {
 
3054
          osTarget = pszNITFFilename;
 
3055
          osTarget[osTarget.size()-1] = (char) ('0' + i );
 
3056
        }
 
3057
        else
 
3058
          osTarget.Printf( "%s.r%d", pszNITFFilename, i );
 
3059
 
 
3060
        if( VSIStatL( osTarget, &sStat ) != 0 )
 
3061
            break;
 
3062
 
 
3063
        aosRSetFilenames.push_back( osTarget );
 
3064
    }
 
3065
   
 
3066
    if( aosRSetFilenames.size() == 0 )
 
3067
        return FALSE;
 
3068
    
 
3069
/* -------------------------------------------------------------------- */
 
3070
/*      We do, so try to create a wrapping VRT file.                    */
 
3071
/* -------------------------------------------------------------------- */
 
3072
    CPLString osFragment;
 
3073
    int iBand;
 
3074
 
 
3075
    osRSetVRT.Printf( "<VRTDataset rasterXSize=\"%d\" rasterYSize=\"%d\">\n",
 
3076
                  GetRasterXSize()/2, GetRasterYSize()/2 );
 
3077
 
 
3078
    for( iBand = 0; iBand < GetRasterCount(); iBand++ )
 
3079
    {
 
3080
        GDALRasterBand *poBand = GetRasterBand(iBand+1);
 
3081
 
 
3082
        osRSetVRT += osFragment.
 
3083
            Printf( "  <VRTRasterBand dataType=\"%s\" band=\"%d\">\n", 
 
3084
                    GDALGetDataTypeName( poBand->GetRasterDataType() ),
 
3085
                    iBand+1 );
 
3086
 
 
3087
        for( i = 0; i < (int) aosRSetFilenames.size(); i++ )
 
3088
        {
 
3089
            char* pszEscaped = CPLEscapeString(aosRSetFilenames[i].c_str(), -1, CPLES_XML);
 
3090
            if( i == 0 )
 
3091
                osRSetVRT += osFragment.Printf(
 
3092
                    "    <SimpleSource><SourceFilename>%s</SourceFilename><SourceBand>%d</SourceBand></SimpleSource>\n", 
 
3093
                    pszEscaped, iBand+1 );
 
3094
            else
 
3095
                osRSetVRT += osFragment.Printf(
 
3096
                    "    <Overview><SourceFilename>%s</SourceFilename><SourceBand>%d</SourceBand></Overview>\n", 
 
3097
                    pszEscaped, iBand+1 );
 
3098
            CPLFree(pszEscaped);
 
3099
        }
 
3100
        osRSetVRT += osFragment.
 
3101
            Printf( "  </VRTRasterBand>\n" );
 
3102
    }
 
3103
 
 
3104
    osRSetVRT += "</VRTDataset>\n";
 
3105
 
 
3106
    return TRUE;
 
3107
}
 
3108
 
 
3109
/************************************************************************/
2873
3110
/*                          IBuildOverviews()                           */
2874
3111
/************************************************************************/
2875
3112
 
2881
3118
    
2882
3119
{
2883
3120
/* -------------------------------------------------------------------- */
 
3121
/*      If we have been using RSets we will need to clear them first.   */
 
3122
/* -------------------------------------------------------------------- */
 
3123
    if( osRSetVRT.size() > 0 )
 
3124
    {
 
3125
        oOvManager.CleanOverviews();
 
3126
        osRSetVRT = "";
 
3127
    }
 
3128
 
 
3129
/* -------------------------------------------------------------------- */
2884
3130
/*      If we have an underlying JPEG2000 dataset (hopefully via        */
2885
3131
/*      JP2KAK) we will try and build zero overviews as a way of        */
2886
3132
/*      tricking it into clearing existing overviews-from-jpeg2000.     */
2997
3243
/*      Allocate offset array                                           */
2998
3244
/* -------------------------------------------------------------------- */
2999
3245
    panJPEGBlockOffset = (GIntBig *) 
3000
 
        CPLCalloc(sizeof(GIntBig),
 
3246
        VSICalloc(sizeof(GIntBig),
3001
3247
                  psImage->nBlocksPerRow*psImage->nBlocksPerColumn);
 
3248
    if (panJPEGBlockOffset == NULL)
 
3249
    {
 
3250
        CPLError( CE_Failure, CPLE_OutOfMemory, "Out of memory");
 
3251
        return CE_Failure;
 
3252
    }
3002
3253
    panJPEGBlockOffset[0] = nJPEGStart;
3003
3254
 
3004
3255
    if ( psImage->nBlocksPerRow * psImage->nBlocksPerColumn == 1)
3112
3363
/*      the whole file. We just use the psImage->panBlockStart table    */
3113
3364
/* -------------------------------------------------------------------- */
3114
3365
            panJPEGBlockOffset = (GIntBig *) 
3115
 
                CPLCalloc(sizeof(GIntBig),
 
3366
                VSICalloc(sizeof(GIntBig),
3116
3367
                        psImage->nBlocksPerRow*psImage->nBlocksPerColumn);
 
3368
            if (panJPEGBlockOffset == NULL)
 
3369
            {
 
3370
                CPLError( CE_Failure, CPLE_OutOfMemory, "Out of memory");
 
3371
                return CE_Failure;
 
3372
            }
3117
3373
            int i;
3118
3374
            for (i=0;i< psImage->nBlocksPerRow*psImage->nBlocksPerColumn;i++)
3119
3375
            {
3152
3408
    {
3153
3409
        /* Allocate enough memory to hold 12bit JPEG data */
3154
3410
        pabyJPEGBlock = (GByte *) 
3155
 
            CPLCalloc(psImage->nBands,
 
3411
            VSICalloc(psImage->nBands,
3156
3412
                      psImage->nBlockWidth * psImage->nBlockHeight * 2);
 
3413
        if (pabyJPEGBlock == NULL)
 
3414
        {
 
3415
            CPLError( CE_Failure, CPLE_OutOfMemory, "Out of memory");
 
3416
            return CE_Failure;
 
3417
        }
3157
3418
    }
3158
3419
 
3159
3420
 
3222
3483
}
3223
3484
 
3224
3485
/************************************************************************/
 
3486
/*                            GetFileList()                             */
 
3487
/************************************************************************/
 
3488
 
 
3489
char **NITFDataset::GetFileList()
 
3490
 
 
3491
{
 
3492
    char **papszFileList = GDALPamDataset::GetFileList();
 
3493
 
 
3494
/* -------------------------------------------------------------------- */
 
3495
/*      Check for .imd file.                                            */
 
3496
/* -------------------------------------------------------------------- */
 
3497
    papszFileList = AddFile( papszFileList, "IMD", "imd" );
 
3498
 
 
3499
/* -------------------------------------------------------------------- */
 
3500
/*      Check for .rpb file.                                            */
 
3501
/* -------------------------------------------------------------------- */
 
3502
    papszFileList = AddFile( papszFileList, "RPB", "rpb" );
 
3503
 
 
3504
/* -------------------------------------------------------------------- */
 
3505
/*      Check for other files.                                          */
 
3506
/* -------------------------------------------------------------------- */
 
3507
    papszFileList = AddFile( papszFileList, "ATT", "att" );
 
3508
    papszFileList = AddFile( papszFileList, "EPH", "eph" );
 
3509
    papszFileList = AddFile( papszFileList, "GEO", "geo" );
 
3510
    papszFileList = AddFile( papszFileList, "XML", "xml" );
 
3511
 
 
3512
    return papszFileList;
 
3513
}
 
3514
 
 
3515
/************************************************************************/
 
3516
/*                              AddFile()                               */
 
3517
/*                                                                      */
 
3518
/*      Helper method for GetFileList()                                 */
 
3519
/************************************************************************/
 
3520
char **NITFDataset::AddFile(char **papszFileList, const char* EXTENSION, const char* extension)
 
3521
{
 
3522
    VSIStatBufL sStatBuf;
 
3523
    CPLString osTarget = CPLResetExtension( osNITFFilename, EXTENSION );
 
3524
    if( VSIStatL( osTarget, &sStatBuf ) == 0 )
 
3525
        papszFileList = CSLAddString( papszFileList, osTarget );
 
3526
    else
 
3527
    {
 
3528
        osTarget = CPLResetExtension( osNITFFilename, extension );
 
3529
        if( VSIStatL( osTarget, &sStatBuf ) == 0 )
 
3530
            papszFileList = CSLAddString( papszFileList, osTarget );
 
3531
    }
 
3532
 
 
3533
    return papszFileList;
 
3534
}
 
3535
 
 
3536
/************************************************************************/
3225
3537
/*                         GDALToNITFDataType()                         */
3226
3538
/************************************************************************/
3227
3539
 
3298
3610
    return papszJP2Options;
3299
3611
}
3300
3612
 
 
3613
 
 
3614
 
 
3615
/************************************************************************/
 
3616
/*              NITFExtractTEXTAndCGMCreationOption()                   */
 
3617
/************************************************************************/
 
3618
 
 
3619
static char** NITFExtractTEXTAndCGMCreationOption( GDALDataset* poSrcDS,
 
3620
                                                   char **papszOptions,
 
3621
                                                   char ***ppapszTextMD,
 
3622
                                                   char ***ppapszCgmMD )
 
3623
{
 
3624
    char** papszFullOptions = CSLDuplicate(papszOptions);
 
3625
 
 
3626
/* -------------------------------------------------------------------- */
 
3627
/*      Prepare for text segments.                                      */
 
3628
/* -------------------------------------------------------------------- */
 
3629
    int iOpt, nNUMT = 0;
 
3630
    char **papszTextMD = CSLFetchNameValueMultiple (papszOptions, "TEXT");
 
3631
    // Notice: CSLFetchNameValueMultiple remove the leading "TEXT=" when
 
3632
    // returning the list, which is what we want.
 
3633
 
 
3634
    // Use TEXT information from original image if no creation option is passed in.
 
3635
    if (poSrcDS != NULL && papszTextMD == NULL)
 
3636
    {
 
3637
        // Read CGM adata from original image, duplicate the list becuase
 
3638
        // we frees papszCgmMD at end of the function.
 
3639
        papszTextMD = CSLDuplicate( poSrcDS->GetMetadata( "TEXT" ));
 
3640
    }
 
3641
 
 
3642
    for( iOpt = 0; 
 
3643
         papszTextMD != NULL && papszTextMD[iOpt] != NULL; 
 
3644
         iOpt++ )
 
3645
    {
 
3646
        if( !EQUALN(papszTextMD[iOpt],"DATA_",5) )
 
3647
            continue;
 
3648
 
 
3649
        nNUMT++;
 
3650
    }
 
3651
 
 
3652
    if( nNUMT > 0 )
 
3653
    {
 
3654
        papszFullOptions = CSLAddString( papszFullOptions, 
 
3655
                                         CPLString().Printf( "NUMT=%d", 
 
3656
                                                             nNUMT ) );
 
3657
    }
 
3658
 
 
3659
/* -------------------------------------------------------------------- */
 
3660
/*      Prepare for CGM segments.                                       */
 
3661
/* -------------------------------------------------------------------- */
 
3662
    const char *pszNUMS; // graphic segment option string
 
3663
    int nNUMS = 0;
 
3664
 
 
3665
    char **papszCgmMD = CSLFetchNameValueMultiple (papszOptions, "CGM");
 
3666
    // Notice: CSLFetchNameValueMultiple remove the leading "CGM=" when
 
3667
    // returning the list, which is what we want.
 
3668
 
 
3669
    // Use CGM information from original image if no creation option is passed in.
 
3670
    if (poSrcDS != NULL && papszCgmMD == NULL)
 
3671
    {
 
3672
        // Read CGM adata from original image, duplicate the list becuase
 
3673
        // we frees papszCgmMD at end of the function.
 
3674
        papszCgmMD = CSLDuplicate( poSrcDS->GetMetadata( "CGM" ));
 
3675
    }
 
3676
 
 
3677
    // Set NUMS based on the number of segments
 
3678
    if (papszCgmMD != NULL)
 
3679
    {
 
3680
        pszNUMS = CSLFetchNameValue(papszCgmMD, "SEGMENT_COUNT");
 
3681
 
 
3682
        if (pszNUMS != NULL) {
 
3683
            nNUMS = atoi(pszNUMS);
 
3684
        }
 
3685
        papszFullOptions = CSLAddString(papszFullOptions,
 
3686
                                        CPLString().Printf("NUMS=%d", nNUMS));
 
3687
    }
 
3688
 
 
3689
    *ppapszTextMD = papszTextMD;
 
3690
    *ppapszCgmMD = papszCgmMD;
 
3691
 
 
3692
    return papszFullOptions;
 
3693
}
 
3694
 
3301
3695
/************************************************************************/
3302
3696
/*                         NITFDatasetCreate()                          */
3303
3697
/************************************************************************/
3304
3698
 
3305
 
static GDALDataset *
3306
 
NITFDatasetCreate( const char *pszFilename, int nXSize, int nYSize, int nBands,
3307
 
                   GDALDataType eType, char **papszOptions )
 
3699
GDALDataset *
 
3700
NITFDataset::NITFDatasetCreate( const char *pszFilename, int nXSize, int nYSize, int nBands,
 
3701
                                GDALDataType eType, char **papszOptions )
3308
3702
 
3309
3703
{
3310
3704
    const char *pszPVType = GDALToNITFDataType( eType );
3344
3738
        return NULL;
3345
3739
    }
3346
3740
 
 
3741
    const char* pszSDE_TRE = CSLFetchNameValue(papszOptions, "SDE_TRE");
 
3742
    if (pszSDE_TRE != NULL)
 
3743
    {
 
3744
        CPLError( CE_Warning, CPLE_AppDefined,
 
3745
                  "SDE_TRE creation option ignored by Create() method (only valid in CreateCopy())" );
 
3746
    }
 
3747
    
 
3748
 
 
3749
/* -------------------------------------------------------------------- */
 
3750
/*      Prepare for text and CGM segments.                              */
 
3751
/* -------------------------------------------------------------------- */
 
3752
    char **papszTextMD = NULL;
 
3753
    char **papszCgmMD = NULL;
 
3754
    char **papszFullOptions = NITFExtractTEXTAndCGMCreationOption( NULL,
 
3755
                                                          papszOptions,
 
3756
                                                          &papszTextMD,
 
3757
                                                          &papszCgmMD );
 
3758
 
3347
3759
/* -------------------------------------------------------------------- */
3348
3760
/*      Create the file.                                                */
3349
3761
/* -------------------------------------------------------------------- */
3350
3762
 
3351
3763
    if( !NITFCreate( pszFilename, nXSize, nYSize, nBands, 
3352
3764
                     GDALGetDataTypeSize( eType ), pszPVType, 
3353
 
                     papszOptions ) )
 
3765
                     papszFullOptions ) )
 
3766
    {
 
3767
        CSLDestroy(papszTextMD);
 
3768
        CSLDestroy(papszCgmMD);
 
3769
        CSLDestroy(papszFullOptions);
3354
3770
        return NULL;
 
3771
    }
 
3772
 
 
3773
    CSLDestroy(papszFullOptions);
 
3774
    papszFullOptions = NULL;
3355
3775
 
3356
3776
/* -------------------------------------------------------------------- */
3357
3777
/*      Various special hacks related to JPEG2000 encoded files.        */
3360
3780
    if( poJ2KDriver )
3361
3781
    {
3362
3782
        NITFFile *psFile = NITFOpen( pszFilename, TRUE );
 
3783
        if (psFile == NULL)
 
3784
        {
 
3785
            CSLDestroy(papszTextMD);
 
3786
            CSLDestroy(papszCgmMD);
 
3787
            return NULL;
 
3788
        }
3363
3789
        GUIntBig nImageOffset = psFile->pasSegmentInfo[0].nSegmentStart;
3364
3790
 
3365
3791
        CPLString osDSName;
3366
3792
 
3367
 
        osDSName.Printf("J2K_SUBFILE:" CPL_FRMT_GUIB ",%d,%s", nImageOffset, -1, pszFilename);
 
3793
        osDSName.Printf("/vsisubfile/" CPL_FRMT_GUIB "_%d,%s", nImageOffset, -1, pszFilename);
3368
3794
 
3369
3795
        NITFClose( psFile );
3370
3796
 
3375
3801
        CSLDestroy(papszJP2Options);
3376
3802
 
3377
3803
        if( poWritableJ2KDataset == NULL )
 
3804
        {
 
3805
            CSLDestroy(papszTextMD);
 
3806
            CSLDestroy(papszCgmMD);
3378
3807
            return NULL;
 
3808
        }
3379
3809
    }
3380
3810
 
3381
3811
/* -------------------------------------------------------------------- */
3382
3812
/*      Open the dataset in update mode.                                */
3383
3813
/* -------------------------------------------------------------------- */
3384
3814
    GDALOpenInfo oOpenInfo( pszFilename, GA_Update );
3385
 
    return NITFDataset::Open(&oOpenInfo, poWritableJ2KDataset);
 
3815
    NITFDataset* poDS = (NITFDataset*)
 
3816
            NITFDataset::OpenInternal(&oOpenInfo, poWritableJ2KDataset, TRUE);
 
3817
    if (poDS)
 
3818
    {
 
3819
        poDS->papszTextMDToWrite = papszTextMD;
 
3820
        poDS->papszCgmMDToWrite = papszCgmMD;
 
3821
    }
 
3822
    else
 
3823
    {
 
3824
        CSLDestroy(papszTextMD);
 
3825
        CSLDestroy(papszCgmMD);
 
3826
    }
 
3827
    return poDS;
3386
3828
}
3387
3829
 
3388
3830
/************************************************************************/
3398
3840
{
3399
3841
    GDALDataType eType;
3400
3842
    GDALRasterBand *poBand1;
3401
 
    char  **papszFullOptions = CSLDuplicate( papszOptions );
3402
3843
    int   bJPEG2000 = FALSE;
3403
3844
    int   bJPEG = FALSE;
3404
3845
    NITFDataset *poDstDS = NULL;
3409
3850
    {
3410
3851
        CPLError( CE_Failure, CPLE_NotSupported,
3411
3852
                  "Unable to export files with zero bands." );
3412
 
        CSLDestroy(papszFullOptions);
3413
3853
        return NULL;
3414
3854
    }
3415
3855
 
3416
3856
    poBand1 = poSrcDS->GetRasterBand(1);
3417
3857
    if( poBand1 == NULL )
3418
3858
    {
3419
 
        CSLDestroy(papszFullOptions);
3420
3859
        return NULL;
3421
3860
    }
3422
3861
 
3432
3871
        {
3433
3872
            poJ2KDriver = 
3434
3873
                GetGDALDriverManager()->GetDriverByName( "JP2ECW" );
3435
 
            if( poJ2KDriver == NULL )
 
3874
            if( poJ2KDriver == NULL || 
 
3875
                poJ2KDriver->GetMetadataItem( GDAL_DCAP_CREATECOPY, NULL ) == NULL )
3436
3876
            {
3437
3877
                /* Try with Jasper as an alternate driver */
3438
3878
                poJ2KDriver = 
3440
3880
            }
3441
3881
            if( poJ2KDriver == NULL )
3442
3882
            {
 
3883
                /* Try with JP2KAK as an alternate driver */
 
3884
                poJ2KDriver = 
 
3885
                    GetGDALDriverManager()->GetDriverByName( "JP2KAK" );
 
3886
            }
 
3887
            if( poJ2KDriver == NULL )
 
3888
            {
3443
3889
                CPLError( 
3444
3890
                    CE_Failure, CPLE_AppDefined, 
3445
3891
                    "Unable to write JPEG2000 compressed NITF file.\n"
3446
3892
                    "No 'subfile' JPEG2000 write supporting drivers are\n"
3447
3893
                    "configured." );
3448
 
                CSLDestroy(papszFullOptions);
3449
3894
                return NULL;
3450
3895
            }
3451
3896
            bJPEG2000 = TRUE;
3458
3903
                CE_Failure, CPLE_AppDefined, 
3459
3904
                "Unable to write JPEG compressed NITF file.\n"
3460
3905
                "Libjpeg is not configured into build." );
3461
 
            CSLDestroy(papszFullOptions);
3462
3906
            return NULL;
3463
3907
#endif
3464
3908
        }
3467
3911
            CPLError( CE_Failure, CPLE_AppDefined, 
3468
3912
                      "Only IC=NC (uncompressed), IC=C3/M3 (JPEG) and IC=C8 (JPEG2000)\n"
3469
3913
                      "allowed with NITF CreateCopy method." );
3470
 
            CSLDestroy(papszFullOptions);
3471
3914
            return NULL;
3472
3915
        }
3473
3916
    }
3482
3925
        eType = GDT_CFloat32;
3483
3926
 
3484
3927
/* -------------------------------------------------------------------- */
 
3928
/*      Prepare for text and CGM segments.                              */
 
3929
/* -------------------------------------------------------------------- */
 
3930
    char **papszTextMD = NULL;
 
3931
    char **papszCgmMD = NULL;
 
3932
    char **papszFullOptions = NITFExtractTEXTAndCGMCreationOption( poSrcDS,
 
3933
                                                         papszOptions,
 
3934
                                                         &papszTextMD,
 
3935
                                                         &papszCgmMD );
 
3936
 
 
3937
/* -------------------------------------------------------------------- */
3485
3938
/*      Copy over other source metadata items as creation options       */
3486
3939
/*      that seem useful.                                               */
3487
3940
/* -------------------------------------------------------------------- */
3512
3965
    {
3513
3966
        CPLString osTRE;
3514
3967
 
 
3968
        if (EQUALN(papszSrcMD[iMD], "RPFHDR", 6) ||
 
3969
            EQUALN(papszSrcMD[iMD], "RPFIMG", 6) ||
 
3970
            EQUALN(papszSrcMD[iMD], "RPFDES", 6))
 
3971
        {
 
3972
            /* Do not copy RPF TRE. They contain absolute offsets */
 
3973
            /* No chance that they make sense in the new NITF file */
 
3974
            continue;
 
3975
        }
 
3976
 
3515
3977
        osTRE = "TRE=";
3516
3978
        osTRE += papszSrcMD[iMD];
3517
3979
 
3519
3981
    }
3520
3982
 
3521
3983
/* -------------------------------------------------------------------- */
3522
 
/*      Prepare for text segments.                                      */
3523
 
/* -------------------------------------------------------------------- */
3524
 
    int iOpt, nNUMT = 0;
3525
 
    char **papszTextMD = poSrcDS->GetMetadata( "TEXT" );
3526
 
 
3527
 
    for( iOpt = 0; 
3528
 
         papszTextMD != NULL && papszTextMD[iOpt] != NULL; 
3529
 
         iOpt++ )
3530
 
    {
3531
 
        if( !EQUALN(papszTextMD[iOpt],"DATA_",5) )
3532
 
            continue;
3533
 
 
3534
 
        nNUMT++;
3535
 
    }
3536
 
 
3537
 
    if( nNUMT > 0 )
3538
 
    {
3539
 
        papszFullOptions = CSLAddString( papszFullOptions, 
3540
 
                                         CPLString().Printf( "NUMT=%d", 
3541
 
                                                             nNUMT ) );
3542
 
    }
3543
 
 
3544
 
/* -------------------------------------------------------------------- */
3545
3984
/*      Set if we can set IREP.                                         */
3546
3985
/* -------------------------------------------------------------------- */
3547
3986
    if( CSLFetchNameValue(papszFullOptions,"IREP") == NULL )
3600
4039
            if (bStrict)
3601
4040
            {
3602
4041
                CSLDestroy(papszFullOptions);
 
4042
                CSLDestroy(papszCgmMD);
 
4043
                CSLDestroy(papszTextMD);
3603
4044
                return NULL;
3604
4045
            }
3605
4046
        }
3606
4047
 
3607
4048
        const char* pszICORDS = CSLFetchNameValue(papszFullOptions, "ICORDS");
3608
4049
 
 
4050
/* -------------------------------------------------------------------- */
 
4051
/*      Should we write DIGEST Spatial Data Extension TRE ?             */
 
4052
/* -------------------------------------------------------------------- */
 
4053
        const char* pszSDE_TRE = CSLFetchNameValue(papszFullOptions, "SDE_TRE");
 
4054
        int bSDE_TRE = pszSDE_TRE && CSLTestBoolean(pszSDE_TRE);
 
4055
        if (bSDE_TRE)
 
4056
        {
 
4057
            if( oSRS.IsGeographic() && oSRS.GetPrimeMeridian() == 0.0
 
4058
                && poSrcDS->GetGeoTransform( adfGeoTransform ) == CE_None &&
 
4059
                adfGeoTransform[2] == 0.0 && adfGeoTransform[4] == 0.0 &&
 
4060
                adfGeoTransform[5] < 0.0)
 
4061
            {
 
4062
                /* Override ICORDS to G if necessary */
 
4063
                if (pszICORDS != NULL && EQUAL(pszICORDS, "D"))
 
4064
                {
 
4065
                    papszFullOptions =
 
4066
                        CSLSetNameValue( papszFullOptions, "ICORDS", "G" );
 
4067
                    CPLError(CE_Warning, CPLE_AppDefined,
 
4068
                             "Forcing ICORDS=G when writing GEOLOB");
 
4069
                }
 
4070
                else
 
4071
                {
 
4072
                    /* Code a bit below will complain with other ICORDS value */
 
4073
                }
 
4074
 
 
4075
                if (CSLPartialFindString(papszFullOptions, "TRE=GEOLOB=") != - 1)
 
4076
                {
 
4077
                    CPLDebug("NITF", "GEOLOB TRE was explicitely defined before. "
 
4078
                             "Overriding it with current georefencing info.");
 
4079
                }
 
4080
 
 
4081
                /* Structure of SDE TRE documented here */
 
4082
                /*http://www.gwg.nga.mil/ntb/baseline/docs/digest/part2_annex_d.pdf */
 
4083
 
 
4084
/* -------------------------------------------------------------------- */
 
4085
/*      Write GEOLOB TRE                                                */
 
4086
/* -------------------------------------------------------------------- */
 
4087
                char szGEOLOB[48+1];
 
4088
                char* pszGEOLOB = szGEOLOB;
 
4089
                double dfARV = 360.0 / adfGeoTransform[1];
 
4090
                double dfBRV = 360.0 / -adfGeoTransform[5];
 
4091
                double dfLSO = adfGeoTransform[0];
 
4092
                double dfPSO = adfGeoTransform[3];
 
4093
                sprintf(pszGEOLOB, "%09d", (int)(dfARV + 0.5)); pszGEOLOB += 9;
 
4094
                sprintf(pszGEOLOB, "%09d", (int)(dfBRV + 0.5)); pszGEOLOB += 9;
 
4095
                sprintf(pszGEOLOB, "%#+015.10f", dfLSO); pszGEOLOB += 15;
 
4096
                sprintf(pszGEOLOB, "%#+015.10f", dfPSO); pszGEOLOB += 15;
 
4097
                CPLAssert(pszGEOLOB == szGEOLOB + 48);
 
4098
 
 
4099
                CPLString osGEOLOB("TRE=GEOLOB=");
 
4100
                osGEOLOB += szGEOLOB;
 
4101
                papszFullOptions = CSLAddString( papszFullOptions, osGEOLOB ) ;
 
4102
 
 
4103
/* -------------------------------------------------------------------- */
 
4104
/*      Write GEOPSB TRE if not already explicitely provided            */
 
4105
/* -------------------------------------------------------------------- */
 
4106
                if (CSLPartialFindString(papszFullOptions, "FILE_TRE=GEOPSB=") == -1 &&
 
4107
                    CSLPartialFindString(papszFullOptions, "TRE=GEOPSB=") == -1)
 
4108
                {
 
4109
                    char szGEOPSB[443+1];
 
4110
                    memset(szGEOPSB, ' ', 443);
 
4111
                    szGEOPSB[443] = 0;
 
4112
    #define WRITE_STR_NOSZ(dst, src) memcpy(dst, src, strlen(src))
 
4113
                    char* pszGEOPSB = szGEOPSB;
 
4114
                    WRITE_STR_NOSZ(pszGEOPSB, "GEO"); pszGEOPSB += 3;
 
4115
                    WRITE_STR_NOSZ(pszGEOPSB, "DEG"); pszGEOPSB += 3;
 
4116
                    WRITE_STR_NOSZ(pszGEOPSB, "World Geodetic System 1984"); pszGEOPSB += 80;
 
4117
                    WRITE_STR_NOSZ(pszGEOPSB, "WGE"); pszGEOPSB += 4;
 
4118
                    WRITE_STR_NOSZ(pszGEOPSB, "World Geodetic System 1984"); pszGEOPSB += 80;
 
4119
                    WRITE_STR_NOSZ(pszGEOPSB, "WE"); pszGEOPSB += 3;
 
4120
                    WRITE_STR_NOSZ(pszGEOPSB, "Geodetic"); pszGEOPSB += 80; /* DVR */
 
4121
                    WRITE_STR_NOSZ(pszGEOPSB, "GEOD"); pszGEOPSB += 4; /* VDCDVR */
 
4122
                    WRITE_STR_NOSZ(pszGEOPSB, "Mean Sea"); pszGEOPSB += 80; /* SDA */
 
4123
                    WRITE_STR_NOSZ(pszGEOPSB, "MSL"); pszGEOPSB += 4; /* VDCSDA */
 
4124
                    WRITE_STR_NOSZ(pszGEOPSB, "000000000000000"); pszGEOPSB += 15; /* ZOR */
 
4125
                    pszGEOPSB += 3; /* GRD */
 
4126
                    pszGEOPSB += 80; /* GRN */
 
4127
                    WRITE_STR_NOSZ(pszGEOPSB, "0000"); pszGEOPSB += 4; /* ZNA */
 
4128
                    CPLAssert(pszGEOPSB == szGEOPSB + 443);
 
4129
 
 
4130
                    CPLString osGEOPSB("FILE_TRE=GEOPSB=");
 
4131
                    osGEOPSB += szGEOPSB;
 
4132
                    papszFullOptions = CSLAddString( papszFullOptions, osGEOPSB ) ;
 
4133
                }
 
4134
                else
 
4135
                {
 
4136
                    CPLDebug("NITF", "GEOPSB TRE was explicitely defined before. Keeping it.");
 
4137
                }
 
4138
 
 
4139
            }
 
4140
            else
 
4141
            {
 
4142
                CPLError((bStrict) ? CE_Failure : CE_Warning, CPLE_NotSupported,
 
4143
                    "Georeferencing info isn't compatible with writing a GEOLOB TRE (only geographic SRS handled for now)");
 
4144
                if (bStrict)
 
4145
                {
 
4146
                    CSLDestroy(papszFullOptions);
 
4147
                    return NULL;
 
4148
                }
 
4149
            }
 
4150
        }
 
4151
 
3609
4152
        if( oSRS.IsGeographic() && oSRS.GetPrimeMeridian() == 0.0 
3610
4153
            && poSrcDS->GetGeoTransform( adfGeoTransform ) == CE_None )
3611
4154
        {
3654
4197
            if (bStrict)
3655
4198
            {
3656
4199
                CSLDestroy(papszFullOptions);
 
4200
                CSLDestroy(papszCgmMD);
 
4201
                CSLDestroy(papszTextMD);
3657
4202
                return NULL;
3658
4203
            }
3659
4204
        }
3669
4214
    if( pszPVType == NULL )
3670
4215
    {
3671
4216
        CSLDestroy(papszFullOptions);
 
4217
        CSLDestroy(papszCgmMD);
 
4218
        CSLDestroy(papszTextMD);
3672
4219
        return NULL;
3673
4220
    }
3674
4221
 
3677
4224
                papszFullOptions ))
3678
4225
    {
3679
4226
        CSLDestroy( papszFullOptions );
 
4227
        CSLDestroy(papszCgmMD);
 
4228
        CSLDestroy(papszTextMD);
3680
4229
        return NULL;
3681
4230
    }
3682
4231
 
3690
4239
    if( bJPEG2000 )
3691
4240
    {
3692
4241
        NITFFile *psFile = NITFOpen( pszFilename, TRUE );
 
4242
        if (psFile == NULL)
 
4243
        {
 
4244
            CSLDestroy(papszCgmMD);
 
4245
            CSLDestroy(papszTextMD);
 
4246
            return NULL;
 
4247
        }
 
4248
 
3693
4249
        GDALDataset *poJ2KDataset = NULL;
3694
4250
        GUIntBig nImageOffset = psFile->pasSegmentInfo[0].nSegmentStart;
3695
4251
        CPLString osDSName;
3696
4252
 
3697
 
        if (EQUAL(poJ2KDriver->GetDescription(), "JP2ECW"))
3698
 
        {
3699
 
            osDSName.Printf( "J2K_SUBFILE:" CPL_FRMT_GUIB ",%d,%s", nImageOffset, -1,
3700
 
                             pszFilename );
3701
 
        }
3702
 
        else
3703
 
        {
3704
 
            /* Jasper case */
3705
 
            osDSName.Printf( "/vsisubfile/" CPL_FRMT_GUIB "_%d,%s", nImageOffset, -1,
3706
 
                             pszFilename );
3707
 
        }
 
4253
        NITFClose( psFile );
 
4254
 
 
4255
        osDSName.Printf( "/vsisubfile/" CPL_FRMT_GUIB "_%d,%s", 
 
4256
                         nImageOffset, -1,
 
4257
                         pszFilename );
3708
4258
                             
3709
 
        NITFClose( psFile );
3710
 
 
3711
4259
        if (EQUAL(poJ2KDriver->GetDescription(), "JP2ECW"))
3712
4260
        {
3713
4261
            char** papszJP2Options = NITFJP2Options(papszOptions);
3727
4275
                                         pfnProgress, pProgressData );
3728
4276
        }
3729
4277
        if( poJ2KDataset == NULL )
 
4278
        {
 
4279
            CSLDestroy(papszCgmMD);
 
4280
            CSLDestroy(papszTextMD);
3730
4281
            return NULL;
 
4282
        }
3731
4283
 
3732
4284
        delete poJ2KDataset;
3733
4285
 
3737
4289
            poSrcDS->GetRasterCount();
3738
4290
 
3739
4291
        NITFPatchImageLength( pszFilename, nImageOffset, nPixelCount, "C8" );
 
4292
        NITFWriteCGMSegments( pszFilename, papszCgmMD );
3740
4293
        NITFWriteTextSegments( pszFilename, papszTextMD );
3741
4294
 
3742
4295
        GDALOpenInfo oOpenInfo( pszFilename, GA_Update );
3743
4296
        poDstDS = (NITFDataset *) Open( &oOpenInfo );
3744
4297
 
3745
4298
        if( poDstDS == NULL )
 
4299
        {
 
4300
            CSLDestroy(papszCgmMD);
 
4301
            CSLDestroy(papszTextMD);
3746
4302
            return NULL;
 
4303
        }
3747
4304
    }
3748
4305
 
3749
4306
/* ==================================================================== */
3753
4310
    {
3754
4311
#ifdef JPEG_SUPPORTED
3755
4312
        NITFFile *psFile = NITFOpen( pszFilename, TRUE );
 
4313
        if (psFile == NULL)
 
4314
        {
 
4315
            CSLDestroy(papszCgmMD);
 
4316
            CSLDestroy(papszTextMD);
 
4317
            return NULL;
 
4318
        }
3756
4319
        GUIntBig nImageOffset = psFile->pasSegmentInfo[0].nSegmentStart;
3757
4320
        int bSuccess;
3758
4321
        
3764
4327
        if( !bSuccess )
3765
4328
        {
3766
4329
            NITFClose( psFile );
 
4330
            CSLDestroy(papszCgmMD);
 
4331
            CSLDestroy(papszTextMD);
3767
4332
            return NULL;
3768
4333
        }
3769
4334
 
3776
4341
 
3777
4342
        NITFPatchImageLength( pszFilename, nImageOffset,
3778
4343
                              nPixelCount, pszIC );
 
4344
 
 
4345
        NITFWriteCGMSegments( pszFilename, papszCgmMD );
3779
4346
        NITFWriteTextSegments( pszFilename, papszTextMD );
3780
4347
        
3781
4348
        GDALOpenInfo oOpenInfo( pszFilename, GA_Update );
3782
4349
        poDstDS = (NITFDataset *) Open( &oOpenInfo );
3783
4350
 
3784
4351
        if( poDstDS == NULL )
 
4352
        {
 
4353
            CSLDestroy(papszCgmMD);
 
4354
            CSLDestroy(papszTextMD);
3785
4355
            return NULL;
 
4356
        }
3786
4357
#endif /* def JPEG_SUPPORTED */
3787
4358
    }
3788
4359
 
3791
4362
/* ==================================================================== */
3792
4363
    else
3793
4364
    {
 
4365
        NITFWriteCGMSegments( pszFilename, papszCgmMD );
3794
4366
        NITFWriteTextSegments( pszFilename, papszTextMD );
3795
4367
 
3796
4368
        GDALOpenInfo oOpenInfo( pszFilename, GA_Update );
3797
4369
        poDstDS = (NITFDataset *) Open( &oOpenInfo );
3798
4370
        if( poDstDS == NULL )
 
4371
        {
 
4372
            CSLDestroy(papszCgmMD);
 
4373
            CSLDestroy(papszTextMD);
3799
4374
            return NULL;
 
4375
        }
3800
4376
        
3801
4377
        void  *pData = VSIMalloc2(nXSize, (GDALGetDataTypeSize(eType) / 8));
3802
4378
        if (pData == NULL)
3803
4379
        {
3804
4380
            delete poDstDS;
 
4381
            CSLDestroy(papszCgmMD);
 
4382
            CSLDestroy(papszTextMD);
3805
4383
            return NULL;
3806
4384
        }
3807
4385
        
3853
4431
        if ( eErr != CE_None )
3854
4432
        {
3855
4433
            delete poDstDS;
 
4434
            CSLDestroy(papszCgmMD);
 
4435
            CSLDestroy(papszTextMD);
3856
4436
            return NULL;
3857
4437
        }
3858
4438
    }
3868
4448
 
3869
4449
    poDstDS->CloneInfo( poSrcDS, GCIF_PAM_DEFAULT );
3870
4450
 
 
4451
    CSLDestroy(papszCgmMD);
 
4452
    CSLDestroy(papszTextMD);
 
4453
 
3871
4454
    return poDstDS;
3872
4455
}
3873
4456
 
3885
4468
                                  const char *pszIC )
3886
4469
 
3887
4470
{
3888
 
    FILE *fpVSIL = VSIFOpenL( pszFilename, "r+b" );
 
4471
    VSILFILE *fpVSIL = VSIFOpenL( pszFilename, "r+b" );
3889
4472
    if( fpVSIL == NULL )
3890
4473
        return;
3891
4474
    
3895
4478
/* -------------------------------------------------------------------- */
3896
4479
/*      Update total file length.                                       */
3897
4480
/* -------------------------------------------------------------------- */
3898
 
    if (nFileLen >= (GUIntBig)1e12)
 
4481
    if (nFileLen >= (GUIntBig)(1e12 - 1))
3899
4482
    {
3900
4483
        CPLError(CE_Failure, CPLE_AppDefined,
3901
 
                 "Too big file : " CPL_FRMT_GUIB ". Truncating to 999999999999",
 
4484
                 "Too big file : " CPL_FRMT_GUIB ". Truncating to 999999999998",
3902
4485
                 nFileLen);
3903
 
        nFileLen = (GUIntBig)(1e12 - 1);
 
4486
        nFileLen = (GUIntBig)(1e12 - 2);
3904
4487
    }
3905
4488
    VSIFSeekL( fpVSIL, 342, SEEK_SET );
3906
4489
    CPLString osLen = CPLString().Printf("%012" CPL_FRMT_GB_WITHOUT_PREFIX "u",nFileLen);
3910
4493
/*      Update the image data length.                                   */
3911
4494
/* -------------------------------------------------------------------- */
3912
4495
    GUIntBig nImageSize = nFileLen-nImageOffset;
3913
 
    if (GUINTBIG_TO_DOUBLE(nImageSize) >= 1e10)
 
4496
    if (GUINTBIG_TO_DOUBLE(nImageSize) >= 1e10 - 1)
3914
4497
    {
3915
4498
        CPLError(CE_Failure, CPLE_AppDefined,
3916
 
                 "Too big image size : " CPL_FRMT_GUIB". Truncating to 9999999999",
 
4499
                 "Too big image size : " CPL_FRMT_GUIB". Truncating to 9999999998",
3917
4500
                 nImageSize);
3918
 
        nImageSize = (GUIntBig)(1e10 - 1);
 
4501
        nImageSize = (GUIntBig)(1e10 - 2);
3919
4502
    }
3920
4503
    VSIFSeekL( fpVSIL, 369, SEEK_SET );
3921
4504
    osLen = CPLString().Printf("%010" CPL_FRMT_GB_WITHOUT_PREFIX "u",nImageSize);
3922
4505
    VSIFWriteL( (void *) osLen.c_str(), 1, 10, fpVSIL );
3923
4506
 
3924
4507
/* -------------------------------------------------------------------- */
3925
 
/*      Update COMRAT, the compression rate variable.  It is a bit      */
3926
 
/*      hard to know right here whether we have an IGEOLO segment,      */
3927
 
/*      so the COMRAT will either be at offset 778 or 838.              */
 
4508
/*      Update COMRAT, the compression rate variable.  We have to       */
 
4509
/*      take into account the presence of graphic and text segments,    */
 
4510
/*      the optional presence of IGEOLO and ICOM to find its position.  */
3928
4511
/* -------------------------------------------------------------------- */
3929
4512
    char szICBuf[2];
3930
 
    VSIFSeekL( fpVSIL, 779-2, SEEK_SET );
 
4513
    char achNUM[4]; // buffer for segment size.  3 digits plus null character
 
4514
    achNUM[3] = '\0';
 
4515
 
 
4516
    // get number of graphic and text segment so we can calculate offset for
 
4517
    // image IC.
 
4518
    int nNumIOffset = 360;
 
4519
    VSIFSeekL( fpVSIL, nNumIOffset, SEEK_SET );
 
4520
    VSIFReadL( achNUM, 1, 3, fpVSIL );
 
4521
    int nIM = atoi(achNUM); // number of image segment
 
4522
 
 
4523
    int nNumSOffset = nNumIOffset + 3 + nIM * 16;
 
4524
    VSIFSeekL( fpVSIL,  nNumSOffset, SEEK_SET );
 
4525
    VSIFReadL( achNUM, 1, 3, fpVSIL );
 
4526
    int nGS = atoi(achNUM); // number of graphic segment
 
4527
 
 
4528
    int nNumTOffset = nNumSOffset + 3 + 10 * nGS + 3;
 
4529
    VSIFSeekL( fpVSIL, nNumTOffset, SEEK_SET );
 
4530
    VSIFReadL( achNUM, 1, 3, fpVSIL );
 
4531
    int nTS = atoi(achNUM); // number of text segment
 
4532
 
 
4533
    int nAdditionalOffset = nGS * 10 + nTS * 9;
 
4534
 
 
4535
    /* Read ICORDS */
 
4536
    VSIFSeekL( fpVSIL, 775 + nAdditionalOffset , SEEK_SET );
 
4537
    char chICORDS;
 
4538
    VSIFReadL( &chICORDS, 1, 1, fpVSIL );
 
4539
    if (chICORDS != ' ')
 
4540
        VSIFSeekL( fpVSIL, 60, SEEK_CUR); /* skip IGEOLO */
 
4541
 
 
4542
    /* Read NICOM */
 
4543
    char achNICOM[2];
 
4544
    VSIFReadL( achNICOM, 1, 1, fpVSIL );
 
4545
    achNICOM[1] = 0;
 
4546
    int nNICOM = atoi(achNICOM);
 
4547
    VSIFSeekL( fpVSIL, nNICOM * 80, SEEK_CUR); /* skip comments */
 
4548
 
 
4549
    /* Read IC */
3931
4550
    VSIFReadL( szICBuf, 2, 1, fpVSIL );
3932
 
    if( !EQUALN(szICBuf,pszIC,2) )
3933
 
    {
3934
 
        VSIFSeekL( fpVSIL, 839-2, SEEK_SET );
3935
 
        VSIFReadL( szICBuf, 2, 1, fpVSIL );
3936
 
    }
3937
 
    
 
4551
 
3938
4552
    /* The following line works around a "feature" of *BSD libc (at least PC-BSD 7.1) */
3939
4553
    /* that makes the position of the file offset unreliable when executing a */
3940
4554
    /* "seek, read and write" sequence. After the read(), the file offset seen by */
3970
4584
    
3971
4585
    VSIFCloseL( fpVSIL );
3972
4586
}
3973
 
        
 
4587
 
 
4588
/************************************************************************/
 
4589
/*                       NITFWriteCGMSegments()                        */
 
4590
/************************************************************************/
 
4591
static int NITFWriteCGMSegments( const char *pszFilename, char **papszList)
 
4592
{
 
4593
    char errorMessage[255] = "";
 
4594
 
 
4595
    // size of each Cgm header entry (LS (4) + LSSH (6))
 
4596
    const int nCgmHdrEntrySz = 10;
 
4597
    
 
4598
    if (papszList == NULL)
 
4599
        return TRUE;
 
4600
 
 
4601
    int nNUMS = 0;
 
4602
    const char *pszNUMS;
 
4603
    pszNUMS = CSLFetchNameValue(papszList, "SEGMENT_COUNT");
 
4604
    if (pszNUMS != NULL)
 
4605
    {
 
4606
        nNUMS = atoi(pszNUMS);
 
4607
    }
 
4608
 
 
4609
    /* -------------------------------------------------------------------- */
 
4610
    /*      Open the target file.                                           */
 
4611
    /* -------------------------------------------------------------------- */
 
4612
    VSILFILE *fpVSIL = VSIFOpenL(pszFilename, "r+b");
 
4613
 
 
4614
    if (fpVSIL == NULL)
 
4615
        return FALSE;
 
4616
 
 
4617
    // Calculates the offset for NUMS so we can update header data
 
4618
    char achNUMI[4]; // 3 digits plus null character
 
4619
    achNUMI[3] = '\0';
 
4620
 
 
4621
    // NUMI offset is at a fixed offset 363
 
4622
    int nNumIOffset = 360;
 
4623
    VSIFSeekL(fpVSIL, nNumIOffset, SEEK_SET );
 
4624
    VSIFReadL(achNUMI, 1, 3, fpVSIL);
 
4625
    int nIM = atoi(achNUMI);
 
4626
 
 
4627
    // 6 for size of LISH and 10 for size of LI
 
4628
    // NUMS offset is NumI offset plus the size of NumI + size taken up each
 
4629
    // the header data multiply by the number of data
 
4630
 
 
4631
    int nNumSOffset = nNumIOffset + 3+ nIM * (6 + 10);
 
4632
 
 
4633
    /* -------------------------------------------------------------------- */
 
4634
    /*      Confirm that the NUMS in the file header already matches the    */
 
4635
    /*      number of graphic segments we want to write                     */
 
4636
    /* -------------------------------------------------------------------- */
 
4637
    char achNUMS[4];
 
4638
 
 
4639
    VSIFSeekL( fpVSIL, nNumSOffset, SEEK_SET );
 
4640
    VSIFReadL( achNUMS, 1, 3, fpVSIL );
 
4641
    achNUMS[3] = '\0';
 
4642
 
 
4643
    if( atoi(achNUMS) != nNUMS )
 
4644
    {
 
4645
        CPLError( CE_Failure, CPLE_AppDefined,
 
4646
                  "It appears an attempt was made to add or update graphic\n"
 
4647
                  "segments on an NITF file with existing segments.  This\n"
 
4648
                  "is not currently supported by the GDAL NITF driver." );
 
4649
 
 
4650
        VSIFCloseL( fpVSIL );
 
4651
        return FALSE;
 
4652
    }
 
4653
 
 
4654
 
 
4655
    // allocate space for graphic header.
 
4656
    // Size of LS = 4, size of LSSH = 6, and 1 for null character
 
4657
    char *pachLS = (char *) CPLCalloc(nNUMS * nCgmHdrEntrySz + 1, 1);
 
4658
 
 
4659
    /* -------------------------------------------------------------------- */
 
4660
    /*  Assume no extended data such as SXSHDL, SXSHD                                           */
 
4661
    /* -------------------------------------------------------------------- */
 
4662
 
 
4663
    /* ==================================================================== */
 
4664
    /*      Write the Graphics segments at the end of the file.             */
 
4665
    /* ==================================================================== */
 
4666
 
 
4667
    #define PLACE(location,name,text)  strncpy(location,text,strlen(text))
 
4668
 
 
4669
    for (int i = 0; i < nNUMS; i++)
 
4670
    {
 
4671
 
 
4672
        // Get all the fields for current CGM segment
 
4673
        const char *pszSlocRow = CSLFetchNameValue(papszList,
 
4674
                        CPLString().Printf("SEGMENT_%d_SLOC_ROW", i));
 
4675
        const char *pszSlocCol = CSLFetchNameValue(papszList,
 
4676
                        CPLString().Printf("SEGMENT_%d_SLOC_COL", i));
 
4677
        const char *pszSdlvl = CSLFetchNameValue(papszList,
 
4678
                        CPLString().Printf("SEGMENT_%d_SDLVL", i));
 
4679
        const char *pszSalvl = CSLFetchNameValue(papszList,
 
4680
                        CPLString().Printf("SEGMENT_%d_SALVL", i));
 
4681
        const char *pszData = CSLFetchNameValue(papszList,
 
4682
                        CPLString().Printf("SEGMENT_%d_DATA", i));
 
4683
 
 
4684
        // Error checking
 
4685
        if (pszSlocRow == NULL)
 
4686
        {
 
4687
            sprintf(errorMessage, "NITF graphic segment writing error: SLOC_ROW for segment %d is not defined",i);
 
4688
            break;
 
4689
        }
 
4690
        if (pszSlocCol == NULL)
 
4691
        {
 
4692
            sprintf(errorMessage, "NITF graphic segment writing error: SLOC_COL for segment %d is not defined",i);
 
4693
            break;
 
4694
        }
 
4695
        if (pszSdlvl == NULL)
 
4696
        {
 
4697
            sprintf(errorMessage, "NITF graphic segment writing error: SDLVL for segment %d is not defined", i);
 
4698
            break;
 
4699
        }
 
4700
        if (pszSalvl == NULL)
 
4701
        {
 
4702
            sprintf(errorMessage, "NITF graphic segment writing error: SALVLfor segment %d is not defined", i);
 
4703
            break;
 
4704
        }
 
4705
        if (pszData == NULL)
 
4706
        {
 
4707
            sprintf(errorMessage, "NITF graphic segment writing error: DATA for segment %d is not defined", i);
 
4708
            break;
 
4709
        }
 
4710
 
 
4711
        int nSlocCol = atoi(pszSlocRow);
 
4712
        int nSlocRow = atoi(pszSlocCol);
 
4713
        int nSdlvl = atoi(pszSdlvl);
 
4714
        int nSalvl = atoi(pszSalvl);
 
4715
 
 
4716
        // Create a buffer for graphics segment header, 258 is the size of
 
4717
        // the header that we will be writing.
 
4718
        char achGSH[258];
 
4719
 
 
4720
        memset(achGSH, ' ', sizeof(achGSH));
 
4721
 
 
4722
 
 
4723
        PLACE( achGSH+ 0, SY , "SY" );
 
4724
        PLACE( achGSH+ 2, SID ,CPLSPrintf("%010d", i) );
 
4725
        PLACE( achGSH+ 12, SNAME , "DEFAULT NAME        " );
 
4726
        PLACE( achGSH+32, SSCLAS , "U" );
 
4727
        PLACE( achGSH+33, SSCLASY , "0" );
 
4728
        PLACE( achGSH+199, ENCRYP , "0" );
 
4729
        PLACE( achGSH+200, SFMT , "C" );
 
4730
        PLACE( achGSH+201, SSTRUCT , "0000000000000" );
 
4731
        PLACE( achGSH+214, SDLVL , CPLSPrintf("%03d",nSdlvl)); // size3
 
4732
        PLACE( achGSH+217, SALVL , CPLSPrintf("%03d",nSalvl)); // size3
 
4733
        PLACE( achGSH+220, SLOC , CPLSPrintf("%05d%05d",nSlocRow,nSlocCol) ); // size 10
 
4734
        PLACE( achGSH+230, SBAND1 , "0000000000" );
 
4735
        PLACE( achGSH+240, SCOLOR, "C" );
 
4736
        PLACE( achGSH+241, SBAND2, "0000000000" );
 
4737
        PLACE( achGSH+251, SRES2, "00" );
 
4738
        PLACE( achGSH+253, SXSHDL, "00000" );
 
4739
 
 
4740
        // Move to the end of the file
 
4741
        VSIFSeekL(fpVSIL, 0, SEEK_END );
 
4742
        VSIFWriteL(achGSH, 1, sizeof(achGSH), fpVSIL);
 
4743
 
 
4744
        /* -------------------------------------- ------------------------------ */
 
4745
        /*      Prepare and write CGM segment data.                            */
 
4746
        /* -------------------------------------------------------------------- */
 
4747
        int nCGMSize = 0;
 
4748
        char *pszCgmToWrite = CPLUnescapeString(pszData, &nCGMSize,
 
4749
                        CPLES_BackslashQuotable);
 
4750
 
 
4751
        if (nCGMSize > 999998)
 
4752
        {
 
4753
            CPLError(CE_Warning, CPLE_NotSupported,
 
4754
                     "Length of SEGMENT_%d_DATA is %d, which is greater than 999998. Truncating...",
 
4755
                     i + 1, nCGMSize);
 
4756
            nCGMSize = 999998;
 
4757
        }
 
4758
 
 
4759
        VSIFWriteL(pszCgmToWrite, 1, nCGMSize, fpVSIL);
 
4760
 
 
4761
        /* -------------------------------------------------------------------- */
 
4762
        /*      Update the subheader and data size info in the file header.     */
 
4763
        /* -------------------------------------------------------------------- */
 
4764
        sprintf( pachLS + nCgmHdrEntrySz * i, "%04d%06d",(int) sizeof(achGSH), nCGMSize );
 
4765
 
 
4766
        CPLFree(pszCgmToWrite);
 
4767
 
 
4768
    } // End For
 
4769
 
 
4770
 
 
4771
    /* -------------------------------------------------------------------- */
 
4772
    /*      Write out the graphic segment info.                             */
 
4773
    /* -------------------------------------------------------------------- */
 
4774
 
 
4775
    VSIFSeekL(fpVSIL, nNumSOffset + 3, SEEK_SET );
 
4776
    VSIFWriteL(pachLS, 1, nNUMS * nCgmHdrEntrySz, fpVSIL);
 
4777
 
 
4778
    /* -------------------------------------------------------------------- */
 
4779
    /*      Update total file length.                                       */
 
4780
    /* -------------------------------------------------------------------- */
 
4781
    VSIFSeekL(fpVSIL, 0, SEEK_END );
 
4782
    GUIntBig nFileLen = VSIFTellL(fpVSIL);
 
4783
    // Offset to file length entry
 
4784
    VSIFSeekL(fpVSIL, 342, SEEK_SET );
 
4785
    if (GUINTBIG_TO_DOUBLE(nFileLen) >= 1e12 - 1)
 
4786
    {
 
4787
        CPLError(CE_Failure, CPLE_AppDefined,
 
4788
                        "Too big file : " CPL_FRMT_GUIB ". Truncating to 999999999998",
 
4789
                        nFileLen);
 
4790
        nFileLen = (GUIntBig) (1e12 - 2);
 
4791
    }
 
4792
    CPLString osLen = CPLString().Printf("%012" CPL_FRMT_GB_WITHOUT_PREFIX "u",
 
4793
                    nFileLen);
 
4794
    VSIFWriteL((void *) osLen.c_str(), 1, 12, fpVSIL);
 
4795
 
 
4796
    VSIFCloseL(fpVSIL);
 
4797
 
 
4798
    CPLFree(pachLS);
 
4799
 
 
4800
    if (strlen(errorMessage) != 0)
 
4801
    {
 
4802
        CPLError(CE_Failure, CPLE_AppDefined, "%s", errorMessage);
 
4803
        return FALSE;
 
4804
    }
 
4805
 
 
4806
    return TRUE;
 
4807
}
 
4808
 
3974
4809
/************************************************************************/
3975
4810
/*                       NITFWriteTextSegments()                        */
3976
4811
/************************************************************************/
3997
4832
/* -------------------------------------------------------------------- */
3998
4833
/*      Open the target file.                                           */
3999
4834
/* -------------------------------------------------------------------- */
4000
 
    FILE *fpVSIL = VSIFOpenL( pszFilename, "r+b" );
 
4835
    VSILFILE *fpVSIL = VSIFOpenL( pszFilename, "r+b" );
4001
4836
 
4002
4837
    if( fpVSIL == NULL )
4003
4838
        return;
4004
 
    
4005
 
/* -------------------------------------------------------------------- */
4006
 
/*      Confirm that the NUMT in the file header already matches the    */
4007
 
/*      number of text segements we want to write, and that the         */
4008
 
/*      segment header/data size info is blank.                         */
4009
 
/* -------------------------------------------------------------------- */
 
4839
 
 
4840
    // Get number of text field.  Since there there could be multiple images
 
4841
    // or graphic segment, the  offset need to be calculated dynamically.
 
4842
 
 
4843
    char achNUMI[4]; // 3 digits plus null character
 
4844
    achNUMI[3] = '\0';
 
4845
    // NUMI offset is at a fixed offset 363
 
4846
    int nNumIOffset = 360;
 
4847
    VSIFSeekL( fpVSIL, nNumIOffset, SEEK_SET );
 
4848
    VSIFReadL( achNUMI, 1, 3, fpVSIL );
 
4849
    int nIM = atoi(achNUMI);
 
4850
 
 
4851
    char achNUMG[4]; // 3 digits plus null character
 
4852
    achNUMG[3] = '\0';
 
4853
 
 
4854
    // 3 for size of NUMI.  6 and 10 are the field size for LISH and LI
 
4855
    int nNumGOffset = nNumIOffset + 3 + nIM * (6 + 10);
 
4856
    VSIFSeekL( fpVSIL, nNumGOffset, SEEK_SET );
 
4857
    VSIFReadL( achNUMG, 1, 3, fpVSIL );
 
4858
    int nGS = atoi(achNUMG);
 
4859
 
 
4860
    // NUMT offset
 
4861
    // 3 for size of NUMG.  4 and 6 are filed size of LSSH and LS.
 
4862
    // the last + 3 is for NUMX field, which is not used
 
4863
    int nNumTOffset = nNumGOffset + 3 + nGS * (4 + 6) + 3;
 
4864
 
 
4865
    /* -------------------------------------------------------------------- */
 
4866
    /*      Confirm that the NUMT in the file header already matches the    */
 
4867
    /*      number of text segements we want to write, and that the         */
 
4868
    /*      segment header/data size info is blank.                         */
 
4869
    /* -------------------------------------------------------------------- */
4010
4870
    char achNUMT[4];
4011
4871
    char *pachLT = (char *) CPLCalloc(nNUMT * 9 + 1, 1);
4012
4872
 
4013
 
    VSIFSeekL( fpVSIL, 385, SEEK_SET );
 
4873
    VSIFSeekL( fpVSIL, nNumTOffset, SEEK_SET );
4014
4874
    VSIFReadL( achNUMT, 1, 3, fpVSIL );
4015
4875
    achNUMT[3] = '\0';
4016
4876
 
4054
4914
        if( !EQUALN(papszList[iOpt],"DATA_",5) )
4055
4915
            continue;
4056
4916
 
 
4917
        const char *pszHeaderBuffer = NULL;
 
4918
 
 
4919
/* -------------------------------------------------------------------- */
 
4920
/*      Locate corresponding header data in the buffer                  */
 
4921
/* -------------------------------------------------------------------- */
 
4922
 
 
4923
        for( int iOpt2 = 0; papszList != NULL && papszList[iOpt2] != NULL; iOpt2++ ) {
 
4924
            if( !EQUALN(papszList[iOpt2],"HEADER_",7) )
 
4925
                continue;
 
4926
 
 
4927
            char *pszHeaderKey, *pszDataKey;
 
4928
            CPLParseNameValue( papszList[iOpt2], &pszHeaderKey );
 
4929
            CPLParseNameValue( papszList[iOpt], &pszDataKey );
 
4930
 
 
4931
            char *pszHeaderId, *pszDataId; //point to header and data number
 
4932
            pszHeaderId = pszHeaderKey + 7;
 
4933
            pszDataId = pszDataKey + 5;
 
4934
 
 
4935
            bool bIsSameId = strcmp(pszHeaderId, pszDataId) == 0;
 
4936
            CPLFree(pszHeaderKey);
 
4937
            CPLFree(pszDataKey);
 
4938
 
 
4939
            // if ID matches, read the header information and exit the loop
 
4940
            if (bIsSameId) {
 
4941
                pszHeaderBuffer = CPLParseNameValue( papszList[iOpt2], NULL);
 
4942
                break;
 
4943
            }
 
4944
        }
 
4945
 
4057
4946
/* -------------------------------------------------------------------- */
4058
4947
/*      Prepare and write text header.                                  */
4059
4948
/* -------------------------------------------------------------------- */
4060
 
        VSIFSeekL( fpVSIL, 0, SEEK_END );
4061
 
 
4062
4949
        char achTSH[282];
4063
 
 
4064
4950
        memset( achTSH, ' ', sizeof(achTSH) );
4065
 
 
4066
 
        PLACE( achTSH+  0, TE            , "TE"                              );
4067
 
        PLACE( achTSH+  9, TXTALVL       , "000"                             );
4068
 
        PLACE( achTSH+ 12, TXTDT         , "00000000000000"                  );
4069
 
        PLACE( achTSH+106, TSCLAS        , "U"                               );
4070
 
        PLACE( achTSH+273, ENCRYP        , "0"                               );
4071
 
        PLACE( achTSH+274, TXTFMT        , "STA"                             );
4072
 
        PLACE( achTSH+277, TXSHDL        , "00000"                           );
 
4951
        VSIFSeekL( fpVSIL, 0, SEEK_END );
 
4952
 
 
4953
        if (pszHeaderBuffer!= NULL) {
 
4954
            memcpy( achTSH, pszHeaderBuffer, MIN(strlen(pszHeaderBuffer), sizeof(achTSH)) );
 
4955
 
 
4956
            // Take care NITF2.0 date format changes
 
4957
            char chTimeZone = achTSH[20];
 
4958
 
 
4959
            // Check for Zulu time zone character.  IpachLTf that exist, then
 
4960
            // it's NITF2.0 format.
 
4961
            if (chTimeZone == 'Z') {
 
4962
                char *achOrigDate=achTSH+12;  // original date string
 
4963
 
 
4964
                // The date value taken from default NITF file date
 
4965
                char achNewDate[]="20021216151629";
 
4966
                char achYear[3];
 
4967
                int nYear;
 
4968
 
 
4969
                // Offset to the year
 
4970
                strncpy(achYear,achOrigDate+12, 2);
 
4971
                achYear[2] = '\0';
 
4972
                nYear = atoi(achYear);
 
4973
 
 
4974
                // Set century.
 
4975
                // Since NITF2.0 does not track the century, we are going to
 
4976
                // assume any year number greater then 94 (the year NITF2.0
 
4977
                // spec published), will be 1900s, otherwise, it's 2000s.
 
4978
                if (nYear > 94) strncpy(achNewDate,"19",2);
 
4979
                else strncpy(achNewDate,"20",2);
 
4980
 
 
4981
                strncpy(achNewDate+6, achOrigDate,8); // copy cover DDhhmmss
 
4982
                strncpy(achNewDate+2, achOrigDate+12,2); // copy over years
 
4983
 
 
4984
                // Perform month conversion
 
4985
                char *pszOrigMonth = achOrigDate+9;
 
4986
                char *pszNewMonth = achNewDate+4;
 
4987
 
 
4988
                if (strncmp(pszOrigMonth,"JAN",3) == 0) strncpy(pszNewMonth,"01",2);
 
4989
                else if (strncmp(pszOrigMonth,"FEB",3) == 0) strncpy(pszNewMonth,"02",2);
 
4990
                else if (strncmp(pszOrigMonth,"MAR",3) == 0) strncpy(pszNewMonth,"03",2);
 
4991
                else if (strncmp(pszOrigMonth,"APR",3) == 0) strncpy(pszNewMonth,"04",2);
 
4992
                else if (strncmp(pszOrigMonth,"MAY",3) == 0) strncpy(pszNewMonth,"05",2);
 
4993
                else if (strncmp(pszOrigMonth,"JUN",3) == 0) strncpy(pszNewMonth,"07",2);
 
4994
                else if (strncmp(pszOrigMonth,"AUG",3) == 0) strncpy(pszNewMonth,"08",2);
 
4995
                else if (strncmp(pszOrigMonth,"SEP",3) == 0) strncpy(pszNewMonth,"09",2);
 
4996
                else if (strncmp(pszOrigMonth,"OCT",3) == 0) strncpy(pszNewMonth,"10",2);
 
4997
                else if (strncmp(pszOrigMonth,"NOV",3) == 0) strncpy(pszNewMonth,"11",2);
 
4998
                else if (strncmp(pszOrigMonth,"DEC",3) == 0) strncpy(pszNewMonth,"12",2);
 
4999
 
 
5000
                PLACE( achTSH+ 12, TXTDT         , achNewDate                   );
 
5001
 
 
5002
            }
 
5003
        } else { // Use default value if header information is not found
 
5004
            PLACE( achTSH+  0, TE            , "TE"                          );
 
5005
            PLACE( achTSH+  9, TXTALVL       , "000"                         );
 
5006
            PLACE( achTSH+ 12, TXTDT         , "20021216151629"              );
 
5007
            PLACE( achTSH+106, TSCLAS        , "U"                           );
 
5008
            PLACE( achTSH+273, ENCRYP        , "0"                           );
 
5009
            PLACE( achTSH+274, TXTFMT        , "STA"                         );
 
5010
            PLACE( achTSH+277, TXSHDL        , "00000"                       );
 
5011
        }
 
5012
 
4073
5013
 
4074
5014
        VSIFWriteL( achTSH, 1, sizeof(achTSH), fpVSIL );
4075
5015
 
4077
5017
/*      Prepare and write text segment data.                            */
4078
5018
/* -------------------------------------------------------------------- */
4079
5019
        pszTextToWrite = CPLParseNameValue( papszList[iOpt], NULL );
 
5020
        
 
5021
        int nTextLength = (int) strlen(pszTextToWrite);
 
5022
        if (nTextLength > 99998)
 
5023
        {
 
5024
            CPLError(CE_Warning, CPLE_NotSupported,
 
5025
                     "Length of DATA_%d is %d, which is greater than 99998. Truncating...",
 
5026
                     iTextSeg + 1, nTextLength);
 
5027
            nTextLength = 99998;
 
5028
        }
4080
5029
 
4081
 
        VSIFWriteL( pszTextToWrite, 1, strlen(pszTextToWrite), fpVSIL );
 
5030
        VSIFWriteL( pszTextToWrite, 1, nTextLength, fpVSIL );
4082
5031
        
4083
5032
/* -------------------------------------------------------------------- */
4084
5033
/*      Update the subheader and data size info in the file header.     */
4085
5034
/* -------------------------------------------------------------------- */
4086
5035
        sprintf( pachLT + 9*iTextSeg+0, "%04d%05d",
4087
 
                 (int) sizeof(achTSH), (int) strlen(pszTextToWrite) );
 
5036
                 (int) sizeof(achTSH), nTextLength );
4088
5037
 
4089
5038
        iTextSeg++;
4090
5039
    }
4092
5041
/* -------------------------------------------------------------------- */
4093
5042
/*      Write out the text segment info.                                */
4094
5043
/* -------------------------------------------------------------------- */
4095
 
    VSIFSeekL( fpVSIL, 388, SEEK_SET );
 
5044
 
 
5045
    VSIFSeekL( fpVSIL, nNumTOffset + 3, SEEK_SET );
4096
5046
    VSIFWriteL( pachLT, 1, nNUMT * 9, fpVSIL );
4097
5047
 
4098
5048
/* -------------------------------------------------------------------- */
4102
5052
    GUIntBig nFileLen = VSIFTellL( fpVSIL );
4103
5053
 
4104
5054
    VSIFSeekL( fpVSIL, 342, SEEK_SET );
4105
 
    if (GUINTBIG_TO_DOUBLE(nFileLen) >= 1e12)
 
5055
    if (GUINTBIG_TO_DOUBLE(nFileLen) >= 1e12 - 1)
4106
5056
    {
4107
5057
        CPLError(CE_Failure, CPLE_AppDefined,
4108
 
                 "Too big file : " CPL_FRMT_GUIB ". Truncating to 999999999999",
 
5058
                 "Too big file : " CPL_FRMT_GUIB ". Truncating to 999999999998",
4109
5059
                 nFileLen);
4110
 
        nFileLen = (GUIntBig)(1e12 - 1);
 
5060
        nFileLen = (GUIntBig)(1e12 - 2);
4111
5061
    }
4112
5062
    CPLString osLen = CPLString().Printf("%012" CPL_FRMT_GB_WITHOUT_PREFIX "u",nFileLen);
4113
5063
    VSIFWriteL( (void *) osLen.c_str(), 1, 12, fpVSIL );
4123
5073
#ifdef JPEG_SUPPORTED
4124
5074
 
4125
5075
int 
4126
 
NITFWriteJPEGBlock( GDALDataset *poSrcDS, FILE *fp,
 
5076
NITFWriteJPEGBlock( GDALDataset *poSrcDS, VSILFILE *fp,
4127
5077
                    int nBlockXOff, int nBlockYOff,
4128
5078
                    int nBlockXSize, int nBlockYSize,
4129
5079
                    int bProgressive, int nQuality,
4131
5081
                    GDALProgressFunc pfnProgress, void * pProgressData );
4132
5082
 
4133
5083
static int 
4134
 
NITFWriteJPEGImage( GDALDataset *poSrcDS, FILE *fp, vsi_l_offset nStartOffset, 
 
5084
NITFWriteJPEGImage( GDALDataset *poSrcDS, VSILFILE *fp, vsi_l_offset nStartOffset,
4135
5085
                    char **papszOptions,
4136
5086
                    GDALProgressFunc pfnProgress, void * pProgressData )
4137
5087
{
4264
5214
    nOffset ++;
4265
5215
 
4266
5216
    /* Number of image blocks per row */
4267
 
    nUInt16 = nNBPR;
 
5217
    nUInt16 = (GUInt16) nNBPR;
4268
5218
    CPL_MSBPTR16(&nUInt16);
4269
5219
    memcpy(abyAPP6 + nOffset, &nUInt16, sizeof(nUInt16));
4270
5220
    nOffset += sizeof(nUInt16);
4271
5221
 
4272
5222
    /* Number of image blocks per column */
4273
 
    nUInt16 = nNBPC;
 
5223
    nUInt16 = (GUInt16) nNBPC;
4274
5224
    CPL_MSBPTR16(&nUInt16);
4275
5225
    memcpy(abyAPP6 + nOffset, &nUInt16, sizeof(nUInt16));
4276
5226
    nOffset += sizeof(nUInt16);
4418
5368
{
4419
5369
    int         nMaxLen;
4420
5370
    const char* pszName;
 
5371
    const char* pszDescription;
4421
5372
} NITFFieldDescription;
4422
5373
 
4423
5374
/* Keep in sync with NITFCreate */
4424
5375
static const NITFFieldDescription asFieldDescription [] =
4425
5376
{
4426
 
    { 2, "CLEVEL" } ,
4427
 
    { 10, "OSTAID" } ,
4428
 
    { 14, "FDT" } ,
4429
 
    { 80, "FTITLE" } ,
4430
 
    { 1, "FSCLAS" } ,
4431
 
    { 2, "FSCLSY" } ,
4432
 
    { 11, "FSCODE" } ,
4433
 
    { 2, "FSCTLH" } ,
4434
 
    { 20, "FSREL" } ,
4435
 
    { 2, "FSDCTP" } ,
4436
 
    { 8, "FSDCDT" } ,
4437
 
    { 4, "FSDCXM" } ,
4438
 
    { 1, "FSDG" } ,
4439
 
    { 8, "FSDGDT" } ,
4440
 
    { 43, "FSCLTX" } ,
4441
 
    { 1, "FSCATP" } ,
4442
 
    { 40, "FSCAUT" } ,
4443
 
    { 1, "FSCRSN" } ,
4444
 
    { 8, "FSSRDT" } ,
4445
 
    { 15, "FSCTLN" } ,
4446
 
    { 5, "FSCOP" } ,
4447
 
    { 5, "FSCPYS" } ,
4448
 
    { 24, "ONAME" } ,
4449
 
    { 18, "OPHONE" } ,
4450
 
    { 10, "IID1" } ,
4451
 
    { 14, "IDATIM" } ,
4452
 
    { 17, "TGTID" } ,
4453
 
    { 80, "IID2" } ,
4454
 
    {  1, "ISCLAS" } ,
4455
 
    {  2, "ISCLSY" } ,
4456
 
    { 11, "ISCODE" } ,
4457
 
    {  2, "ISCTLH" } ,
4458
 
    { 20, "ISREL" } ,
4459
 
    {  2, "ISDCTP" } ,
4460
 
    {  8, "ISDCDT" } ,
4461
 
    {  4, "ISDCXM" } ,
4462
 
    {  1, "ISDG" } ,
4463
 
    {  8, "ISDGDT" } ,
4464
 
    { 43, "ISCLTX" } ,
4465
 
    {  1, "ISCATP" } ,
4466
 
    { 40, "ISCAUT" } ,
4467
 
    {  1, "ISCRSN" } ,
4468
 
    {  8, "ISSRDT" } ,
4469
 
    { 15, "ISCTLN" } ,
4470
 
    { 42, "ISORCE" } ,
4471
 
    {  8, "ICAT" } ,
4472
 
    {  2, "ABPP" } ,
4473
 
    {  1, "PJUST" } ,
 
5377
    { 2, "CLEVEL", "Complexity level" } ,
 
5378
    { 10, "OSTAID", "Originating Station ID" } ,
 
5379
    { 14, "FDT", "File Date and Time" } ,
 
5380
    { 80, "FTITLE", "File Title" } ,
 
5381
    { 1, "FSCLAS", "File Security Classification" } ,
 
5382
    { 2, "FSCLSY", "File Classification Security System" } ,
 
5383
    { 11, "FSCODE", "File Codewords" } ,
 
5384
    { 2, "FSCTLH", "File Control and Handling" } ,
 
5385
    { 20, "FSREL", "File Releasing Instructions" } ,
 
5386
    { 2, "FSDCTP", "File Declassification Type" } ,
 
5387
    { 8, "FSDCDT", "File Declassification Date" } ,
 
5388
    { 4, "FSDCXM", "File Declassification Exemption" } ,
 
5389
    { 1, "FSDG", "File Downgrade" } ,
 
5390
    { 8, "FSDGDT", "File Downgrade Date" } ,
 
5391
    { 43, "FSCLTX", "File Classification Text" } ,
 
5392
    { 1, "FSCATP", "File Classification Authority Type" } ,
 
5393
    { 40, "FSCAUT", "File Classification Authority" } ,
 
5394
    { 1, "FSCRSN", "File Classification Reason" } ,
 
5395
    { 8, "FSSRDT", "File Security Source Date" } ,
 
5396
    { 15, "FSCTLN", "File Security Control Number" } ,
 
5397
    { 5, "FSCOP", "File Copy Number" } ,
 
5398
    { 5, "FSCPYS", "File Number of Copies" } ,
 
5399
    { 24, "ONAME", "Originator Name" } ,
 
5400
    { 18, "OPHONE", "Originator Phone Number" } ,
 
5401
    { 10, "IID1", "Image Identifier 1" } ,
 
5402
    { 14, "IDATIM", "Image Date and Time" } ,
 
5403
    { 17, "TGTID", "Target Identifier" } ,
 
5404
    { 80, "IID2", "Image Identifier 2" } ,
 
5405
    {  1, "ISCLAS", "Image Security Classification" } ,
 
5406
    {  2, "ISCLSY", "Image Classification Security System" } ,
 
5407
    { 11, "ISCODE", "Image Codewords" } ,
 
5408
    {  2, "ISCTLH", "Image Control and Handling" } ,
 
5409
    { 20, "ISREL", "Image Releasing Instructions" } ,
 
5410
    {  2, "ISDCTP", "Image Declassification Type" } ,
 
5411
    {  8, "ISDCDT", "Image Declassification Date" } ,
 
5412
    {  4, "ISDCXM", "Image Declassification Exemption" } ,
 
5413
    {  1, "ISDG", "Image Downgrade" } ,
 
5414
    {  8, "ISDGDT", "Image Downgrade Date" } ,
 
5415
    { 43, "ISCLTX", "Image Classification Text" } ,
 
5416
    {  1, "ISCATP", "Image Classification Authority Type" } ,
 
5417
    { 40, "ISCAUT", "Image Classification Authority" } ,
 
5418
    {  1, "ISCRSN", "Image Classification Reason" } ,
 
5419
    {  8, "ISSRDT", "Image Security Source Date" } ,
 
5420
    { 15, "ISCTLN", "Image Security Control Number" } ,
 
5421
    { 42, "ISORCE", "Image Source" } ,
 
5422
    {  8, "ICAT", "Image Category" } ,
 
5423
    {  2, "ABPP", "Actual Bits-Per-Pixel Per Band" } ,
 
5424
    {  1, "PJUST", "Pixel Justification" } ,
 
5425
    {780, "ICOM", "Image Comments (up to 9x80 characters)" } ,
4474
5426
};
4475
5427
 
4476
5428
/* Keep in sync with NITFWriteBLOCKA */
4537
5489
"       <Value>NSIF01.00</Value>"
4538
5490
"   </Option>"
4539
5491
"   <Option name='IREP' type='string' description='Set to RGB/LUT to reserve space for a color table for each output band. (Only needed for Create() method, not CreateCopy())'/>"
 
5492
"   <Option name='IREPBAND' type='string' description='Comma separated list of band IREPBANDs in band order'/>"
 
5493
"   <Option name='ISUBCAT' type='string' description='Comma separated list of band ISUBCATs in band order'/>" 
4540
5494
"   <Option name='LUT_SIZE' type='integer' description='Set to control the size of pseudocolor tables for RGB/LUT bands' default='256'/>"
4541
5495
"   <Option name='BLOCKXSIZE' type='int' description='Set the block width'/>"
4542
5496
"   <Option name='BLOCKYSIZE' type='int' description='Set the block height'/>"
4543
 
"   <Option name='BLOCKSIZE' type='int' description='Set the block with and height. Overridden by BLOCKXSIZE and BLOCKYSIZE'/>";
 
5497
"   <Option name='BLOCKSIZE' type='int' description='Set the block with and height. Overridden by BLOCKXSIZE and BLOCKYSIZE'/>"
 
5498
"   <Option name='TEXT' type='string' description='TEXT options as text-option-name=text-option-content'/>"
 
5499
"   <Option name='CGM' type='string' description='CGM options in cgm-option-name=cgm-option-content'/>";
4544
5500
 
4545
5501
        for(i=0;i<sizeof(asFieldDescription) / sizeof(asFieldDescription[0]); i++)
4546
5502
        {
4547
 
            char szFieldDescription[128];
4548
 
            sprintf(szFieldDescription, "   <Option name='%s' type='string' maxsize='%d'/>",
4549
 
                    asFieldDescription[i].pszName, asFieldDescription[i].nMaxLen);
4550
 
            osCreationOptions += szFieldDescription;
 
5503
            osCreationOptions += CPLString().Printf("   <Option name='%s' type='string' description='%s' maxsize='%d'/>",
 
5504
                    asFieldDescription[i].pszName, asFieldDescription[i].pszDescription, asFieldDescription[i].nMaxLen);
4551
5505
        }
4552
5506
 
4553
5507
        osCreationOptions +=
4554
5508
"   <Option name='TRE' type='string' description='Under the format TRE=tre-name,tre-contents'/>"
 
5509
"   <Option name='FILE_TRE' type='string' description='Under the format FILE_TRE=tre-name,tre-contents'/>"
4555
5510
"   <Option name='BLOCKA_BLOCK_COUNT' type='int'/>";
4556
5511
 
4557
5512
        for(i=0; apszFieldsBLOCKA[i] != NULL; i+=3)
4561
5516
                    apszFieldsBLOCKA[i], atoi(apszFieldsBLOCKA[i+2]));
4562
5517
            osCreationOptions += szFieldDescription;
4563
5518
        }
4564
 
 
 
5519
        osCreationOptions +=
 
5520
"   <Option name='SDE_TRE' type='boolean' description='Write GEOLOB and GEOPSB TREs (only geographic SRS for now)' default='NO'/>";
4565
5521
        osCreationOptions += "</CreationOptionList>";
4566
5522
 
4567
5523
        poDriver = new GDALDriver();
4572
5528
        
4573
5529
        poDriver->pfnIdentify = NITFDataset::Identify;
4574
5530
        poDriver->pfnOpen = NITFDataset::Open;
4575
 
        poDriver->pfnCreate = NITFDatasetCreate;
 
5531
        poDriver->pfnCreate = NITFDataset::NITFDatasetCreate;
4576
5532
        poDriver->pfnCreateCopy = NITFDataset::NITFCreateCopy;
4577
5533
 
4578
5534
        poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, "frmt_nitf.html" );