30
30
* DEALINGS IN THE SOFTWARE.
31
31
****************************************************************************/
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"
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 $");
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 );
47
static CPLErr NITFSetColorInterpretation( NITFImage *psImage,
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 );
56
/************************************************************************/
57
/* ==================================================================== */
59
/* ==================================================================== */
60
/************************************************************************/
63
class NITFWrapperRasterBand;
65
class NITFDataset : public GDALPamDataset
67
friend class NITFRasterBand;
68
friend class NITFWrapperRasterBand;
73
GDALPamDataset *poJ2KDataset;
76
GDALPamDataset *poJPEGDataset;
79
double adfGeoTransform[6];
85
char *pszGCPProjection;
87
GDALMultiDomainMetadata oSpecialMD;
89
void InitializeCGMMetadata();
90
void InitializeTextMetadata();
91
void InitializeTREMetadata();
93
GIntBig *panJPEGBlockOffset;
97
int ScanJPEGQLevel( GUIntBig *pnDataStart );
98
CPLErr ScanJPEGBlocks( void );
99
CPLErr ReadJPEGBlock( int, int );
100
void CheckGeoSDEInfo();
103
CPLString osNITFFilename;
109
virtual CPLErr AdviseRead( int nXOff, int nYOff, int nXSize, int nYSize,
110
int nBufXSize, int nBufYSize,
112
int nBandCount, int *panBandList,
113
char **papszOptions );
115
virtual CPLErr IRasterIO( GDALRWFlag, int, int, int, int,
116
void *, int, int, GDALDataType,
117
int, int *, int, int, int );
119
virtual const char *GetProjectionRef(void);
120
virtual CPLErr SetProjection( const char * );
121
virtual CPLErr GetGeoTransform( double * );
122
virtual CPLErr SetGeoTransform( double * );
124
virtual int GetGCPCount();
125
virtual const char *GetGCPProjection();
126
virtual const GDAL_GCP *GetGCPs();
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 * );
135
static int Identify( GDALOpenInfo * );
136
static GDALDataset *Open( GDALOpenInfo *, GDALDataset *poWritableJ2KDataset);
137
static GDALDataset *Open( GDALOpenInfo * );
139
NITFCreateCopy( const char *pszFilename, GDALDataset *poSrcDS,
140
int bStrict, char **papszOptions,
141
GDALProgressFunc pfnProgress, void * pProgressData );
145
/************************************************************************/
146
/* NITFMakeColorTable() */
147
/************************************************************************/
149
static GDALColorTable* NITFMakeColorTable(NITFImage* psImage, NITFBandInfo *psBandInfo)
151
GDALColorTable* poColorTable = NULL;
153
if( psBandInfo->nSignificantLUTEntries > 0 )
157
poColorTable = new GDALColorTable();
159
for( iColor = 0; iColor < psBandInfo->nSignificantLUTEntries; iColor++)
161
GDALColorEntry sEntry;
163
sEntry.c1 = psBandInfo->pabyLUT[ 0 + iColor];
164
sEntry.c2 = psBandInfo->pabyLUT[256 + iColor];
165
sEntry.c3 = psBandInfo->pabyLUT[512 + iColor];
168
poColorTable->SetColorEntry( iColor, &sEntry );
171
if (psImage->bNoDataSet)
173
GDALColorEntry sEntry;
174
sEntry.c1 = sEntry.c2 = sEntry.c3 = sEntry.c4 = 0;
175
poColorTable->SetColorEntry( psImage->nNoDataValue, &sEntry );
179
/* -------------------------------------------------------------------- */
180
/* We create a color table for 1 bit data too... */
181
/* -------------------------------------------------------------------- */
182
if( poColorTable == NULL && psImage->nBitsPerSample == 1 )
184
GDALColorEntry sEntry;
186
poColorTable = new GDALColorTable();
192
poColorTable->SetColorEntry( 0, &sEntry );
198
poColorTable->SetColorEntry( 1, &sEntry );
204
/************************************************************************/
205
/* ==================================================================== */
207
/* ==================================================================== */
208
/************************************************************************/
210
class NITFRasterBand : public GDALPamRasterBand
212
friend class NITFDataset;
216
GDALColorTable *poColorTable;
221
NITFRasterBand( NITFDataset *, int );
224
virtual CPLErr IReadBlock( int, int, void * );
225
virtual CPLErr IWriteBlock( int, int, void * );
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 );
233
void Unpack(GByte* pData);
236
/************************************************************************/
237
/* NITFRasterBand() */
238
/************************************************************************/
240
NITFRasterBand::NITFRasterBand( NITFDataset *poDS, int nBand )
243
NITFBandInfo *psBandInfo = poDS->psImage->pasBandInfo + nBand - 1;
248
this->eAccess = poDS->eAccess;
249
this->psImage = poDS->psImage;
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 */
280
eDataType = GDT_Unknown;
281
CPLError( CE_Warning, CPLE_AppDefined,
282
"Unsupported combination of PVTYPE(%s) and NBPP(%d).",
283
psImage->szPVType, psImage->nBitsPerSample );
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") )
295
nBlockXSize = psImage->nBlockWidth;
300
nBlockXSize = psImage->nBlockWidth;
301
nBlockYSize = psImage->nBlockHeight;
304
/* -------------------------------------------------------------------- */
305
/* Do we have a color table? */
306
/* -------------------------------------------------------------------- */
307
poColorTable = NITFMakeColorTable(psImage,
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" );
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];
326
/************************************************************************/
327
/* ~NITFRasterBand() */
328
/************************************************************************/
330
NITFRasterBand::~NITFRasterBand()
333
if( poColorTable != NULL )
336
delete[] pUnpackData;
339
/************************************************************************/
341
/************************************************************************/
343
CPLErr NITFRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
348
NITFDataset *poGDS = (NITFDataset *) poDS;
350
/* -------------------------------------------------------------------- */
351
/* Special case for JPEG blocks. */
352
/* -------------------------------------------------------------------- */
353
if( EQUAL(psImage->szIC,"C3") || EQUAL(psImage->szIC,"M3") )
355
CPLErr eErr = poGDS->ReadJPEGBlock( nBlockXOff, nBlockYOff );
356
int nBlockBandSize = psImage->nBlockWidth*psImage->nBlockHeight*
357
(GDALGetDataTypeSize(eDataType)/8);
359
if( eErr != CE_None )
363
poGDS->pabyJPEGBlock + (nBand - 1) * nBlockBandSize,
369
/* -------------------------------------------------------------------- */
370
/* Read the line/block */
371
/* -------------------------------------------------------------------- */
372
if( nBlockYSize == 1 )
375
NITFReadImageLine(psImage, nBlockYOff, nBand, pImage);
380
NITFReadImageBlock(psImage, nBlockXOff, nBlockYOff, nBand, pImage);
383
if( nBlockResult == BLKREAD_OK )
385
if( psImage->nBitsPerSample % 8 )
386
Unpack((GByte*)pImage);
391
if( nBlockResult == BLKREAD_FAIL )
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 */
398
/* -------------------------------------------------------------------- */
399
if( psImage->bNoDataSet )
400
memset( pImage, psImage->nNoDataValue,
401
psImage->nWordSize*psImage->nBlockWidth*psImage->nBlockHeight);
404
psImage->nWordSize*psImage->nBlockWidth*psImage->nBlockHeight);
409
/************************************************************************/
411
/************************************************************************/
413
CPLErr NITFRasterBand::IWriteBlock( int nBlockXOff, int nBlockYOff,
419
/* -------------------------------------------------------------------- */
420
/* Write the line/block */
421
/* -------------------------------------------------------------------- */
422
if( nBlockYSize == 1 )
425
NITFWriteImageLine(psImage, nBlockYOff, nBand, pImage);
430
NITFWriteImageBlock(psImage, nBlockXOff, nBlockYOff, nBand,pImage);
433
if( nBlockResult == BLKREAD_OK )
439
/************************************************************************/
440
/* GetNoDataValue() */
441
/************************************************************************/
443
double NITFRasterBand::GetNoDataValue( int *pbSuccess )
446
if( pbSuccess != NULL )
447
*pbSuccess = psImage->bNoDataSet;
449
if( psImage->bNoDataSet )
450
return psImage->nNoDataValue;
452
return GDALPamRasterBand::GetNoDataValue( pbSuccess );
455
/************************************************************************/
456
/* GetColorInterpretation() */
457
/************************************************************************/
459
GDALColorInterp NITFRasterBand::GetColorInterpretation()
462
NITFBandInfo *psBandInfo = psImage->pasBandInfo + nBand - 1;
464
if( poColorTable != NULL )
465
return GCI_PaletteIndex;
467
if( EQUAL(psBandInfo->szIREPBAND,"R") )
469
if( EQUAL(psBandInfo->szIREPBAND,"G") )
470
return GCI_GreenBand;
471
if( EQUAL(psBandInfo->szIREPBAND,"B") )
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;
482
return GCI_Undefined;
485
/************************************************************************/
486
/* NITFSetColorInterpretation() */
487
/************************************************************************/
489
static CPLErr NITFSetColorInterpretation( NITFImage *psImage,
491
GDALColorInterp eInterp )
494
NITFBandInfo *psBandInfo = psImage->pasBandInfo + nBand - 1;
495
const char *pszREP = NULL;
498
if( eInterp == GCI_RedBand )
500
else if( eInterp == GCI_GreenBand )
502
else if( eInterp == GCI_BlueBand )
504
else if( eInterp == GCI_GrayIndex )
506
else if( eInterp == GCI_YCbCr_YBand )
508
else if( eInterp == GCI_YCbCr_CbBand )
510
else if( eInterp == GCI_YCbCr_CrBand )
512
else if( eInterp == GCI_Undefined )
517
CPLError( CE_Failure, CPLE_NotSupported,
518
"Requested color interpretation (%s) not supported in NITF.",
519
GDALGetColorInterpretationName( eInterp ) );
523
/* -------------------------------------------------------------------- */
524
/* Where does this go in the file? */
525
/* -------------------------------------------------------------------- */
526
strcpy( psBandInfo->szIREPBAND, pszREP );
527
nOffset = NITFIHFieldOffset( psImage, "IREPBAND" );
530
nOffset += (nBand - 1) * 13;
532
/* -------------------------------------------------------------------- */
533
/* write it (space padded). */
534
/* -------------------------------------------------------------------- */
536
strcpy( szPadded, pszREP );
537
strcat( szPadded, " " );
541
if( VSIFSeekL( psImage->psFile->fp, nOffset, SEEK_SET ) != 0
542
|| VSIFWriteL( (void *) szPadded, 1, 2, psImage->psFile->fp ) != 2 )
544
CPLError( CE_Failure, CPLE_AppDefined,
545
"IO failure writing new IREPBAND value to NITF file." );
553
/************************************************************************/
554
/* SetColorInterpretation() */
555
/************************************************************************/
557
CPLErr NITFRasterBand::SetColorInterpretation( GDALColorInterp eInterp )
560
return NITFSetColorInterpretation( psImage, nBand, eInterp );
563
/************************************************************************/
564
/* GetColorTable() */
565
/************************************************************************/
567
GDALColorTable *NITFRasterBand::GetColorTable()
573
/************************************************************************/
574
/* SetColorTable() */
575
/************************************************************************/
577
CPLErr NITFRasterBand::SetColorTable( GDALColorTable *poNewCT )
580
if( poNewCT == NULL )
583
GByte abyNITFLUT[768];
585
int nCount = MIN(256,poNewCT->GetColorEntryCount());
587
memset( abyNITFLUT, 0, 768 );
588
for( i = 0; i < nCount; i++ )
590
GDALColorEntry sEntry;
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;
598
if( NITFWriteLUT( psImage, nBand, nCount, abyNITFLUT ) )
604
/************************************************************************/
606
/************************************************************************/
608
void NITFRasterBand::Unpack( GByte* pData )
610
long n = nBlockXSize*nBlockYSize;
613
switch (psImage->nBitsPerSample)
617
// unpack 1-bit in-place in reverse
618
for (i = n; --i >= 0; )
619
pData[i] = (pData[i>>3] & (0x80 >> (i&7))) != 0;
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;
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;
643
// unpacks 8 pixels (3 bytes) at time
644
for (i = 0, k = 0; i < n; i += 8, k += 3)
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);
656
memcpy(pData, pUnpackData, n);
661
// unpacks 8 pixels (5 bytes) at time
662
for (i = 0, k = 0; i < n; i += 8, k += 5)
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);
674
memcpy(pData, pUnpackData, n);
679
// unpacks 4 pixels (3 bytes) at time
680
for (i = 0, k = 0; i < n; i += 4, k += 3)
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);
688
memcpy(pData, pUnpackData, n);
693
// unpacks 8 pixels (7 bytes) at time
694
for (i = 0, k = 0; i < n; i += 8, k += 7)
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);
706
memcpy(pData, pUnpackData, n);
711
GByte* pabyImage = (GByte *)pData;
712
GUInt16* panImage = (GUInt16*)pData;
713
for (i = n; --i >= 0; )
715
long iOffset = i*3 / 2;
717
panImage[i] = pabyImage[iOffset] + (pabyImage[iOffset+1] & 0xf0) * 16;
719
panImage[i] = (pabyImage[iOffset] & 0x0f) * 16
720
+ (pabyImage[iOffset+1] & 0xf0) / 16
721
+ (pabyImage[iOffset+1] & 0x0f) * 256;
729
/************************************************************************/
730
/* ==================================================================== */
731
/* NITFWrapperRasterBand */
732
/* ==================================================================== */
733
/************************************************************************/
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 */
743
class NITFWrapperRasterBand : public GDALProxyRasterBand
745
GDALRasterBand* poBaseBand;
746
GDALColorTable* poColorTable;
747
GDALColorInterp eInterp;
750
/* Pure virtual method of the GDALProxyRasterBand */
751
virtual GDALRasterBand* RefUnderlyingRasterBand();
754
NITFWrapperRasterBand( NITFDataset * poDS,
755
GDALRasterBand* poBaseBand,
757
~NITFWrapperRasterBand();
759
/* Methods from GDALRasterBand we want to override */
760
virtual GDALColorInterp GetColorInterpretation();
761
virtual CPLErr SetColorInterpretation( GDALColorInterp );
763
virtual GDALColorTable *GetColorTable();
765
/* Specific method */
766
void SetColorTableFromNITFBandInfo();
769
/************************************************************************/
770
/* NITFWrapperRasterBand() */
771
/************************************************************************/
773
NITFWrapperRasterBand::NITFWrapperRasterBand( NITFDataset * poDS,
774
GDALRasterBand* poBaseBand,
779
this->poBaseBand = poBaseBand;
780
eDataType = poBaseBand->GetRasterDataType();
781
poBaseBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
783
eInterp = poBaseBand->GetColorInterpretation();
786
/************************************************************************/
787
/* ~NITFWrapperRasterBand() */
788
/************************************************************************/
790
NITFWrapperRasterBand::~NITFWrapperRasterBand()
792
if( poColorTable != NULL )
796
/************************************************************************/
797
/* RefUnderlyingRasterBand() */
798
/************************************************************************/
800
/* We don't need ref-counting. Just return the base band */
801
GDALRasterBand* NITFWrapperRasterBand::RefUnderlyingRasterBand()
806
/************************************************************************/
807
/* GetColorTable() */
808
/************************************************************************/
810
GDALColorTable *NITFWrapperRasterBand::GetColorTable()
815
/************************************************************************/
816
/* SetColorTableFromNITFBandInfo() */
817
/************************************************************************/
819
void NITFWrapperRasterBand::SetColorTableFromNITFBandInfo()
821
NITFDataset* poGDS = (NITFDataset* )poDS;
822
poColorTable = NITFMakeColorTable(poGDS->psImage,
823
poGDS->psImage->pasBandInfo + nBand - 1);
826
/************************************************************************/
827
/* GetColorInterpretation() */
828
/************************************************************************/
830
GDALColorInterp NITFWrapperRasterBand::GetColorInterpretation()
835
/************************************************************************/
836
/* SetColorInterpretation() */
837
/************************************************************************/
839
CPLErr NITFWrapperRasterBand::SetColorInterpretation( GDALColorInterp eInterp)
841
this->eInterp = eInterp;
52
static void SetBandMetadata( NITFImage *psImage, GDALRasterBand *poBand, int nBand );
845
55
/************************************************************************/
846
56
/* ==================================================================== */
985
246
GDALPamDataset::FlushCache();
251
/************************************************************************/
252
/* ExtractEsriMD() */
254
/* Extracts ESRI-specific required meta data from metadata */
255
/* string list papszStrList. */
256
/************************************************************************/
258
static char **ExtractEsriMD( char **papszMD )
260
char **papszEsriMD = NULL;
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";
281
const char *pCCImageSegment = CSLFetchNameValue( papszMD, "NITF_IID1" );
282
std::string ccSegment("false");
284
if( ( pCCImageSegment != NULL ) && ( strlen(pCCImageSegment) <= 10 ) )
287
strncpy( szField, pCCImageSegment, strlen(pCCImageSegment) );
288
szField[strlen(pCCImageSegment)] = '\0';
290
// Trim white off tag.
291
while( ( strlen(szField) > 0 ) && ( szField[strlen(szField)-1] == ' ' ) )
292
szField[strlen(szField)-1] = '\0';
294
if ((strlen(szField) == 2) && (EQUALN(szField, "CC", 2))) ccSegment.assign("true");
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" );
307
// Get ESRI_MD_DATA_TYPE.
308
const char *pDataType = NULL;
309
const char *pImgSegFieldICAT = CSLFetchNameValue( papszMD, "NITF_ICAT" );
311
if( ( pImgSegFieldICAT != NULL ) && ( EQUALN(pImgSegFieldICAT, "DTEM", 4) ) )
312
pDataType = "Elevation";
314
pDataType = "Generic";
316
if( pAngleToNorth == NULL )
317
pAngleToNorth = CSLFetchNameValue( papszMD, "NITF_USE00A_ANGLE_TO_NORTH" );
319
// Percent cloud cover == 999 means that the information is not available.
320
if( (pPercentCloudCover != NULL) && (EQUALN(pPercentCloudCover, "999", 3)) )
321
pPercentCloudCover = NULL;
323
pAngleToNorth = CSLFetchNameValue( papszMD, "NITF_USE00A_ANGLE_TO_NORTH" );
325
if( pSunAzimuth == NULL )
326
pSunAzimuth = CSLFetchNameValue( papszMD, "NITF_USE00A_SUN_AZ" );
328
if( pSunElevation == NULL )
329
pSunElevation = CSLFetchNameValue( papszMD, "NITF_USE00A_SUN_EL" );
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 );
345
return (papszEsriMD);
348
/************************************************************************/
349
/* SetBandMetadata() */
350
/************************************************************************/
352
static void SetBandMetadata( NITFImage *psImage, GDALRasterBand *poBand, int nBand )
354
if( (psImage != NULL) && (poBand != NULL) && (nBand > 0) )
356
NITFBandInfo *psBandInfo = psImage->pasBandInfo + nBand - 1;
358
if( psBandInfo != NULL )
360
// Set metadata BandName, WavelengthMax and WavelengthMin.
362
if ( psBandInfo->szIREPBAND != NULL )
364
if( EQUAL(psBandInfo->szIREPBAND,"B") )
366
poBand->SetMetadataItem( "BandName", "Blue" );
367
poBand->SetMetadataItem( "WavelengthMax", psBandInfo->szISUBCAT );
368
poBand->SetMetadataItem( "WavelengthMin", psBandInfo->szISUBCAT );
370
else if( EQUAL(psBandInfo->szIREPBAND,"G") )
372
poBand->SetMetadataItem( "BandName", "Green" );
373
poBand->SetMetadataItem( "WavelengthMax", psBandInfo->szISUBCAT );
374
poBand->SetMetadataItem( "WavelengthMin", psBandInfo->szISUBCAT );
376
else if( EQUAL(psBandInfo->szIREPBAND,"R") )
378
poBand->SetMetadataItem( "BandName", "Red" );
379
poBand->SetMetadataItem( "WavelengthMax", psBandInfo->szISUBCAT );
380
poBand->SetMetadataItem( "WavelengthMin", psBandInfo->szISUBCAT );
382
else if( EQUAL(psBandInfo->szIREPBAND,"N") )
384
poBand->SetMetadataItem( "BandName", "NearInfrared" );
385
poBand->SetMetadataItem( "WavelengthMax", psBandInfo->szISUBCAT );
386
poBand->SetMetadataItem( "WavelengthMin", psBandInfo->szISUBCAT );
388
else if( ( EQUAL(psBandInfo->szIREPBAND,"M") ) || ( ( psImage->szIREP != NULL ) && ( EQUAL(psImage->szIREP,"MONO") ) ) )
390
poBand->SetMetadataItem( "BandName", "Panchromatic" );
394
if( ( psImage->szICAT != NULL ) && ( EQUAL(psImage->szICAT,"IR") ) )
396
poBand->SetMetadataItem( "BandName", "Infrared" );
397
poBand->SetMetadataItem( "WavelengthMax", psBandInfo->szISUBCAT );
398
poBand->SetMetadataItem( "WavelengthMin", psBandInfo->szISUBCAT );
406
#endif /* def ESRI_BUILD */
988
408
/************************************************************************/
990
410
/************************************************************************/
2544
2079
return CE_None;
2083
/************************************************************************/
2084
/* InitializeNITFDESMetadata() */
2085
/************************************************************************/
2087
void NITFDataset::InitializeNITFDESMetadata()
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);
2096
char **ppszDESMetadataList = oSpecialMD.GetMetadata( pszDESMetadataDomain );
2098
if( ppszDESMetadataList != NULL ) return;
2100
char **ppszDESsList = this->GetMetadata( pszDESsDomain );
2102
if( ppszDESsList == NULL ) return;
2104
bool foundXmlDataContent = false;
2105
char *pachNITFDES = NULL;
2107
// Set metadata "NITF_DES_XML_DATA_CONTENT_DESDATA".
2108
// NOTE: There should only be one instance of XML_DATA_CONTENT DES.
2110
while( ((pachNITFDES = *ppszDESsList) != NULL) && (!foundXmlDataContent) )
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.
2116
const char* pszSpace = strchr(pachNITFDES, ' ');
2118
char* pszData = NULL;
2122
pszData = CPLStrdup( pszSpace+1 );
2123
nDataLen = CPLBase64DecodeInPlace((GByte*)pszData);
2124
pszData[nDataLen] = 0;
2127
if ( nDataLen > 2 + sizeXmlDataContent && EQUALN(pszData, "DE", 2) )
2129
// Check to see if this is a XML_DATA_CONTENT DES.
2130
if ( EQUALN(pszData + 2, pszXmlDataContent, sizeXmlDataContent) &&
2131
nDataLen > idxXmlDataContentDESDATA )
2133
foundXmlDataContent = true;
2135
// Get the value of the DESDATA field and set metadata "NITF_DES_XML_DATA_CONTENT_DESDATA".
2136
const char* pszXML = pszData + idxXmlDataContentDESDATA;
2138
// Set the metadata.
2139
oSpecialMD.SetMetadataItem( pszMDXmlDataContentDESDATA, pszXML, pszDESMetadataDomain );
2151
/************************************************************************/
2152
/* InitializeNITFDESs() */
2153
/************************************************************************/
2155
void NITFDataset::InitializeNITFDESs()
2157
static const char *pszDESsDomain = "NITF_DES";
2159
char **ppszDESsList = oSpecialMD.GetMetadata( pszDESsDomain );
2161
if( ppszDESsList != NULL ) return;
2163
/* -------------------------------------------------------------------- */
2164
/* Go through all the segments and process all DES segments. */
2165
/* -------------------------------------------------------------------- */
2167
char *pachDESData = NULL;
2168
int nDESDataSize = 0;
2169
std::string encodedDESData("");
2170
CPLStringList aosList;
2172
for( int iSegment = 0; iSegment < psFile->nSegmentCount; iSegment++ )
2174
NITFSegmentInfo *psSegInfo = psFile->pasSegmentInfo + iSegment;
2176
if( EQUAL(psSegInfo->szSegmentType,"DE") )
2178
nDESDataSize = psSegInfo->nSegmentHeaderSize + psSegInfo->nSegmentSize;
2179
pachDESData = (char*) VSIMalloc( nDESDataSize + 1 );
2181
if (pachDESData == NULL)
2183
CPLError( CE_Failure, CPLE_OutOfMemory, "Cannot allocate memory for DES segment" );
2187
if( VSIFSeekL( psFile->fp, psSegInfo->nSegmentHeaderStart,
2189
|| (int)VSIFReadL( pachDESData, 1, nDESDataSize,
2190
psFile->fp ) != nDESDataSize )
2192
CPLError( CE_Failure, CPLE_FileIO,
2193
"Failed to read %d byte DES subheader from " CPL_FRMT_GUIB ".",
2195
psSegInfo->nSegmentHeaderStart );
2196
CPLFree( pachDESData );
2200
pachDESData[nDESDataSize] = '\0';
2202
/* -------------------------------------------------------------------- */
2203
/* Accumulate all the DES segments. */
2204
/* -------------------------------------------------------------------- */
2206
char* pszBase64 = CPLBase64Encode( nDESDataSize, (const GByte *)pachDESData );
2207
encodedDESData = pszBase64;
2210
CPLFree( pachDESData );
2213
if( encodedDESData.empty() )
2215
CPLError(CE_Failure, CPLE_AppDefined, "Failed to encode DES subheader data!");
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.
2224
sprintf(buffer, "%d", nDESDataSize);
2226
std::string desSubheaderStr(buffer);
2227
desSubheaderStr.append(" ");
2228
desSubheaderStr.append(encodedDESData);
2230
aosList.AddString(desSubheaderStr.c_str() );
2234
if (aosList.size() > 0)
2235
oSpecialMD.SetMetadata( aosList.List(), pszDESsDomain );
2238
/************************************************************************/
2239
/* InitializeNITFTREs() */
2240
/************************************************************************/
2242
void NITFDataset::InitializeNITFTREs()
2244
static const char *pszFileHeaderTREsDomain = "NITF_FILE_HEADER_TRES";
2245
static const char *pszImageSegmentTREsDomain = "NITF_IMAGE_SEGMENT_TRES";
2247
char **ppszFileHeaderTREsList = oSpecialMD.GetMetadata( pszFileHeaderTREsDomain );
2248
char **ppszImageSegmentTREsList = oSpecialMD.GetMetadata( pszImageSegmentTREsDomain );
2250
if( (ppszFileHeaderTREsList != NULL) && (ppszImageSegmentTREsList != NULL ) ) return;
2252
/* -------------------------------------------------------------------- */
2253
/* Loop over TRE sources (file and image). */
2254
/* -------------------------------------------------------------------- */
2256
for( int nTRESrc = 0; nTRESrc < 2; nTRESrc++ )
2259
char *pszTREData = NULL;
2260
const char *pszTREsDomain = NULL;
2261
CPLStringList aosList;
2263
/* -------------------------------------------------------------------- */
2264
/* Extract file header or image segment TREs. */
2265
/* -------------------------------------------------------------------- */
2269
if( ppszFileHeaderTREsList != NULL ) continue;
2271
nTREBytes = psFile->nTREBytes;
2272
pszTREData = psFile->pachTRE;
2273
pszTREsDomain = pszFileHeaderTREsDomain;
2277
if( ppszImageSegmentTREsList != NULL ) continue;
2281
nTREBytes = psImage->nTREBytes;
2282
pszTREData = psImage->pachTRE;
2283
pszTREsDomain = pszImageSegmentTREsDomain;
2292
/* -------------------------------------------------------------------- */
2293
/* Loop over TREs. */
2294
/* -------------------------------------------------------------------- */
2296
while( nTREBytes >= 11 )
2300
char *pszEscapedData = NULL;
2301
int nThisTRESize = atoi(NITFGetField(szTemp, pszTREData, 6, 5 ));
2303
if (nThisTRESize < 0)
2305
NITFGetField(szTemp, pszTREData, 0, 6 );
2306
CPLError(CE_Failure, CPLE_AppDefined, "Invalid size (%d) for TRE %s",
2307
nThisTRESize, szTemp);
2311
if (nThisTRESize > nTREBytes - 11)
2313
CPLError(CE_Failure, CPLE_AppDefined, "Not enough bytes in TRE");
2317
strncpy( szTag, pszTREData, 6 );
2320
// trim white off tag.
2321
while( strlen(szTag) > 0 && szTag[strlen(szTag)-1] == ' ' )
2322
szTag[strlen(szTag)-1] = '\0';
2325
pszEscapedData = CPLEscapeString( pszTREData + 6,
2327
CPLES_BackslashQuotable );
2329
char * pszLine = (char *) CPLMalloc( strlen(szTag)+strlen(pszEscapedData)+2 );
2330
sprintf( pszLine, "%s=%s", szTag, pszEscapedData );
2331
aosList.AddString(pszLine);
2335
CPLFree( pszEscapedData );
2336
pszEscapedData = NULL;
2338
nTREBytes -= (nThisTRESize + 11);
2339
pszTREData += (nThisTRESize + 11);
2342
if (aosList.size() > 0)
2343
oSpecialMD.SetMetadata( aosList.List(), pszTREsDomain );
2348
/************************************************************************/
2349
/* InitializeNITFMetadata() */
2350
/************************************************************************/
2352
void NITFDataset::InitializeNITFMetadata()
2355
static const char *pszDomainName = "NITF_METADATA";
2356
static const char *pszTagNITFFileHeader = "NITFFileHeader";
2357
static const char *pszTagNITFImageSubheader = "NITFImageSubheader";
2359
if( oSpecialMD.GetMetadata( pszDomainName ) != NULL )
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).
2366
int nHeaderLenOffset = 0;
2368
// Get the NITF file header length.
2370
if( psFile->pachHeader != NULL )
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;
2380
if( nHeaderLenOffset > 0 )
2382
char *pszFieldHL = psFile->pachHeader + nHeaderLenOffset;
2384
memcpy(fieldHL, pszFieldHL, 6);
2386
nHeaderLen = atoi(fieldHL);
2389
if( nHeaderLen <= 0 )
2391
CPLError(CE_Failure, CPLE_AppDefined, "Zero length NITF file header!");
2395
char *encodedHeader = CPLBase64Encode(nHeaderLen,
2396
(GByte*)psFile->pachHeader);
2398
if (encodedHeader == NULL || strlen(encodedHeader) == 0 )
2400
CPLError(CE_Failure, CPLE_AppDefined,
2401
"Failed to encode NITF file header!");
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.
2409
std::string nitfFileheaderStr(fieldHL);
2410
nitfFileheaderStr.append(" ");
2411
nitfFileheaderStr.append(encodedHeader);
2413
CPLFree( encodedHeader );
2415
oSpecialMD.SetMetadataItem( pszTagNITFFileHeader, nitfFileheaderStr.c_str(), pszDomainName );
2417
// Get the image subheader length.
2419
int nImageSubheaderLen = 0;
2421
for( int i = 0; i < psFile->nSegmentCount; ++i )
2423
if (strncmp(psFile->pasSegmentInfo[i].szSegmentType, "IM", 2) == 0)
2425
nImageSubheaderLen = psFile->pasSegmentInfo[i].nSegmentHeaderSize;
2430
if( nImageSubheaderLen < 0 )
2432
CPLError(CE_Failure, CPLE_AppDefined, "Invalid length NITF image subheader!");
2436
if( nImageSubheaderLen > 0 )
2438
char *encodedImageSubheader = CPLBase64Encode(nImageSubheaderLen,(GByte*) psImage->pachHeader);
2440
if( encodedImageSubheader == NULL || strlen(encodedImageSubheader) ==0 )
2442
CPLError(CE_Failure, CPLE_AppDefined,
2443
"Failed to encode image subheader!");
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.
2452
sprintf(buffer, "%d", nImageSubheaderLen);
2454
std::string imageSubheaderStr(buffer);
2455
imageSubheaderStr.append(" ");
2456
imageSubheaderStr.append(encodedImageSubheader);
2458
CPLFree( encodedImageSubheader );
2460
oSpecialMD.SetMetadataItem( pszTagNITFImageSubheader, imageSubheaderStr.c_str(), pszDomainName );
2547
2464
/************************************************************************/
2548
2465
/* InitializeCGMMetadata() */
2549
2466
/************************************************************************/
3971
4585
VSIFCloseL( fpVSIL );
4588
/************************************************************************/
4589
/* NITFWriteCGMSegments() */
4590
/************************************************************************/
4591
static int NITFWriteCGMSegments( const char *pszFilename, char **papszList)
4593
char errorMessage[255] = "";
4595
// size of each Cgm header entry (LS (4) + LSSH (6))
4596
const int nCgmHdrEntrySz = 10;
4598
if (papszList == NULL)
4602
const char *pszNUMS;
4603
pszNUMS = CSLFetchNameValue(papszList, "SEGMENT_COUNT");
4604
if (pszNUMS != NULL)
4606
nNUMS = atoi(pszNUMS);
4609
/* -------------------------------------------------------------------- */
4610
/* Open the target file. */
4611
/* -------------------------------------------------------------------- */
4612
VSILFILE *fpVSIL = VSIFOpenL(pszFilename, "r+b");
4617
// Calculates the offset for NUMS so we can update header data
4618
char achNUMI[4]; // 3 digits plus null character
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);
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
4631
int nNumSOffset = nNumIOffset + 3+ nIM * (6 + 10);
4633
/* -------------------------------------------------------------------- */
4634
/* Confirm that the NUMS in the file header already matches the */
4635
/* number of graphic segments we want to write */
4636
/* -------------------------------------------------------------------- */
4639
VSIFSeekL( fpVSIL, nNumSOffset, SEEK_SET );
4640
VSIFReadL( achNUMS, 1, 3, fpVSIL );
4643
if( atoi(achNUMS) != nNUMS )
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." );
4650
VSIFCloseL( fpVSIL );
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);
4659
/* -------------------------------------------------------------------- */
4660
/* Assume no extended data such as SXSHDL, SXSHD */
4661
/* -------------------------------------------------------------------- */
4663
/* ==================================================================== */
4664
/* Write the Graphics segments at the end of the file. */
4665
/* ==================================================================== */
4667
#define PLACE(location,name,text) strncpy(location,text,strlen(text))
4669
for (int i = 0; i < nNUMS; i++)
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));
4685
if (pszSlocRow == NULL)
4687
sprintf(errorMessage, "NITF graphic segment writing error: SLOC_ROW for segment %d is not defined",i);
4690
if (pszSlocCol == NULL)
4692
sprintf(errorMessage, "NITF graphic segment writing error: SLOC_COL for segment %d is not defined",i);
4695
if (pszSdlvl == NULL)
4697
sprintf(errorMessage, "NITF graphic segment writing error: SDLVL for segment %d is not defined", i);
4700
if (pszSalvl == NULL)
4702
sprintf(errorMessage, "NITF graphic segment writing error: SALVLfor segment %d is not defined", i);
4705
if (pszData == NULL)
4707
sprintf(errorMessage, "NITF graphic segment writing error: DATA for segment %d is not defined", i);
4711
int nSlocCol = atoi(pszSlocRow);
4712
int nSlocRow = atoi(pszSlocCol);
4713
int nSdlvl = atoi(pszSdlvl);
4714
int nSalvl = atoi(pszSalvl);
4716
// Create a buffer for graphics segment header, 258 is the size of
4717
// the header that we will be writing.
4720
memset(achGSH, ' ', sizeof(achGSH));
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" );
4740
// Move to the end of the file
4741
VSIFSeekL(fpVSIL, 0, SEEK_END );
4742
VSIFWriteL(achGSH, 1, sizeof(achGSH), fpVSIL);
4744
/* -------------------------------------- ------------------------------ */
4745
/* Prepare and write CGM segment data. */
4746
/* -------------------------------------------------------------------- */
4748
char *pszCgmToWrite = CPLUnescapeString(pszData, &nCGMSize,
4749
CPLES_BackslashQuotable);
4751
if (nCGMSize > 999998)
4753
CPLError(CE_Warning, CPLE_NotSupported,
4754
"Length of SEGMENT_%d_DATA is %d, which is greater than 999998. Truncating...",
4759
VSIFWriteL(pszCgmToWrite, 1, nCGMSize, fpVSIL);
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 );
4766
CPLFree(pszCgmToWrite);
4771
/* -------------------------------------------------------------------- */
4772
/* Write out the graphic segment info. */
4773
/* -------------------------------------------------------------------- */
4775
VSIFSeekL(fpVSIL, nNumSOffset + 3, SEEK_SET );
4776
VSIFWriteL(pachLS, 1, nNUMS * nCgmHdrEntrySz, fpVSIL);
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)
4787
CPLError(CE_Failure, CPLE_AppDefined,
4788
"Too big file : " CPL_FRMT_GUIB ". Truncating to 999999999998",
4790
nFileLen = (GUIntBig) (1e12 - 2);
4792
CPLString osLen = CPLString().Printf("%012" CPL_FRMT_GB_WITHOUT_PREFIX "u",
4794
VSIFWriteL((void *) osLen.c_str(), 1, 12, fpVSIL);
4800
if (strlen(errorMessage) != 0)
4802
CPLError(CE_Failure, CPLE_AppDefined, "%s", errorMessage);
3974
4809
/************************************************************************/
3975
4810
/* NITFWriteTextSegments() */
3976
4811
/************************************************************************/
4054
4914
if( !EQUALN(papszList[iOpt],"DATA_",5) )
4917
const char *pszHeaderBuffer = NULL;
4919
/* -------------------------------------------------------------------- */
4920
/* Locate corresponding header data in the buffer */
4921
/* -------------------------------------------------------------------- */
4923
for( int iOpt2 = 0; papszList != NULL && papszList[iOpt2] != NULL; iOpt2++ ) {
4924
if( !EQUALN(papszList[iOpt2],"HEADER_",7) )
4927
char *pszHeaderKey, *pszDataKey;
4928
CPLParseNameValue( papszList[iOpt2], &pszHeaderKey );
4929
CPLParseNameValue( papszList[iOpt], &pszDataKey );
4931
char *pszHeaderId, *pszDataId; //point to header and data number
4932
pszHeaderId = pszHeaderKey + 7;
4933
pszDataId = pszDataKey + 5;
4935
bool bIsSameId = strcmp(pszHeaderId, pszDataId) == 0;
4936
CPLFree(pszHeaderKey);
4937
CPLFree(pszDataKey);
4939
// if ID matches, read the header information and exit the loop
4941
pszHeaderBuffer = CPLParseNameValue( papszList[iOpt2], NULL);
4057
4946
/* -------------------------------------------------------------------- */
4058
4947
/* Prepare and write text header. */
4059
4948
/* -------------------------------------------------------------------- */
4060
VSIFSeekL( fpVSIL, 0, SEEK_END );
4062
4949
char achTSH[282];
4064
4950
memset( achTSH, ' ', sizeof(achTSH) );
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 );
4953
if (pszHeaderBuffer!= NULL) {
4954
memcpy( achTSH, pszHeaderBuffer, MIN(strlen(pszHeaderBuffer), sizeof(achTSH)) );
4956
// Take care NITF2.0 date format changes
4957
char chTimeZone = achTSH[20];
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
4964
// The date value taken from default NITF file date
4965
char achNewDate[]="20021216151629";
4969
// Offset to the year
4970
strncpy(achYear,achOrigDate+12, 2);
4972
nYear = atoi(achYear);
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);
4981
strncpy(achNewDate+6, achOrigDate,8); // copy cover DDhhmmss
4982
strncpy(achNewDate+2, achOrigDate+12,2); // copy over years
4984
// Perform month conversion
4985
char *pszOrigMonth = achOrigDate+9;
4986
char *pszNewMonth = achNewDate+4;
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);
5000
PLACE( achTSH+ 12, TXTDT , achNewDate );
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" );
4074
5014
VSIFWriteL( achTSH, 1, sizeof(achTSH), fpVSIL );
4420
5370
const char* pszName;
5371
const char* pszDescription;
4421
5372
} NITFFieldDescription;
4423
5374
/* Keep in sync with NITFCreate */
4424
5375
static const NITFFieldDescription asFieldDescription [] =
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)" } ,
4476
5428
/* Keep in sync with NITFWriteBLOCKA */