1 : /******************************************************************************
2 : * $Id: nitffile.c 19365 2010-04-10 19:23:30Z rouault $
3 : *
4 : * Project: NITF Read/Write Library
5 : * Purpose: Module responsible for opening NITF file, populating NITFFile
6 : * structure, and instantiating segment specific access objects.
7 : * Author: Frank Warmerdam, warmerdam@pobox.com
8 : *
9 : **********************************************************************
10 : * Copyright (c) 2002, Frank Warmerdam
11 : *
12 : * Permission is hereby granted, free of charge, to any person obtaining a
13 : * copy of this software and associated documentation files (the "Software"),
14 : * to deal in the Software without restriction, including without limitation
15 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 : * and/or sell copies of the Software, and to permit persons to whom the
17 : * Software is furnished to do so, subject to the following conditions:
18 : *
19 : * The above copyright notice and this permission notice shall be included
20 : * in all copies or substantial portions of the Software.
21 : *
22 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 : * DEALINGS IN THE SOFTWARE.
29 : ****************************************************************************/
30 :
31 : #include "nitflib.h"
32 : #include "cpl_vsi.h"
33 : #include "cpl_conv.h"
34 : #include "cpl_string.h"
35 :
36 : CPL_CVSID("$Id: nitffile.c 19365 2010-04-10 19:23:30Z rouault $");
37 :
38 : static int NITFWriteBLOCKA( FILE* fp, vsi_l_offset nOffsetUDIDL,
39 : vsi_l_offset nOffsetTRE,
40 : int *pnOffset,
41 : char **papszOptions );
42 : static int NITFWriteTREsFromOptions(
43 : FILE* fp,
44 : vsi_l_offset nOffsetUDIDL, vsi_l_offset nOffsetTRE,
45 : int *pnOffset,
46 : char **papszOptions,
47 : const char* pszTREPrefix);
48 :
49 : static int
50 : NITFCollectSegmentInfo( NITFFile *psFile, int nFileHeaderLenSize, int nOffset,
51 : const char szType[3],
52 : int nHeaderLenSize, int nDataLenSize,
53 : GUIntBig *pnNextData );
54 :
55 : /************************************************************************/
56 : /* NITFOpen() */
57 : /************************************************************************/
58 :
59 : NITFFile *NITFOpen( const char *pszFilename, int bUpdatable )
60 :
61 546 : {
62 : FILE *fp;
63 : char *pachHeader;
64 : NITFFile *psFile;
65 : int nHeaderLen, nOffset, nHeaderLenOffset;
66 : GUIntBig nNextData;
67 : char szTemp[128], achFSDWNG[6];
68 : GIntBig currentPos;
69 546 : int bTriedStreamingFileHeader = FALSE;
70 :
71 : /* -------------------------------------------------------------------- */
72 : /* Open the file. */
73 : /* -------------------------------------------------------------------- */
74 546 : if( bUpdatable )
75 196 : fp = VSIFOpenL( pszFilename, "r+b" );
76 : else
77 350 : fp = VSIFOpenL( pszFilename, "rb" );
78 :
79 546 : if( fp == NULL )
80 : {
81 0 : CPLError( CE_Failure, CPLE_OpenFailed,
82 : "Failed to open file %s.",
83 : pszFilename );
84 0 : return NULL;
85 : }
86 :
87 : /* -------------------------------------------------------------------- */
88 : /* Check file type. */
89 : /* -------------------------------------------------------------------- */
90 546 : VSIFReadL( szTemp, 1, 9, fp );
91 :
92 546 : if( !EQUALN(szTemp,"NITF",4) && !EQUALN(szTemp,"NSIF",4) )
93 : {
94 0 : CPLError( CE_Failure, CPLE_AppDefined,
95 : "The file %s is not an NITF file.",
96 : pszFilename );
97 0 : VSIFCloseL(fp);
98 0 : return NULL;
99 : }
100 :
101 : /* -------------------------------------------------------------------- */
102 : /* Read the FSDWNG field. */
103 : /* -------------------------------------------------------------------- */
104 546 : if( VSIFSeekL( fp, 280, SEEK_SET ) != 0
105 : || VSIFReadL( achFSDWNG, 1, 6, fp ) != 6 )
106 : {
107 1 : CPLError( CE_Failure, CPLE_NotSupported,
108 : "Unable to read FSDWNG field from NITF file. File is either corrupt\n"
109 : "or empty." );
110 1 : VSIFCloseL(fp);
111 1 : return NULL;
112 : }
113 :
114 : /* -------------------------------------------------------------------- */
115 : /* Get header length. */
116 : /* -------------------------------------------------------------------- */
117 554 : if( EQUALN(szTemp,"NITF01.",7) || EQUALN(achFSDWNG,"999998",6) )
118 9 : nHeaderLenOffset = 394;
119 : else
120 536 : nHeaderLenOffset = 354;
121 :
122 545 : if( VSIFSeekL( fp, nHeaderLenOffset, SEEK_SET ) != 0
123 : || VSIFReadL( szTemp, 1, 6, fp ) != 6 )
124 : {
125 2 : CPLError( CE_Failure, CPLE_NotSupported,
126 : "Unable to read header length from NITF file. File is either corrupt\n"
127 : "or empty." );
128 2 : VSIFCloseL(fp);
129 2 : return NULL;
130 : }
131 :
132 543 : szTemp[6] = '\0';
133 543 : nHeaderLen = atoi(szTemp);
134 :
135 543 : VSIFSeekL( fp, nHeaderLen, SEEK_SET );
136 543 : currentPos = VSIFTellL( fp ) ;
137 543 : if( nHeaderLen < nHeaderLenOffset || nHeaderLen > currentPos )
138 : {
139 1 : CPLError( CE_Failure, CPLE_NotSupported,
140 : "NITF Header Length (%d) seems to be corrupt.",
141 : nHeaderLen );
142 1 : VSIFCloseL(fp);
143 1 : return NULL;
144 : }
145 :
146 : /* -------------------------------------------------------------------- */
147 : /* Read the whole file header. */
148 : /* -------------------------------------------------------------------- */
149 542 : pachHeader = (char *) VSIMalloc(nHeaderLen);
150 542 : if (pachHeader == NULL)
151 : {
152 0 : CPLError( CE_Failure, CPLE_OutOfMemory,
153 : "Cannot allocate memory for NITF header");
154 0 : VSIFCloseL(fp);
155 0 : return NULL;
156 : }
157 542 : VSIFSeekL( fp, 0, SEEK_SET );
158 542 : if ((int)VSIFReadL( pachHeader, 1, nHeaderLen, fp ) != nHeaderLen)
159 : {
160 1 : CPLError( CE_Failure, CPLE_OutOfMemory,
161 : "Cannot read %d bytes for NITF header", (nHeaderLen));
162 1 : VSIFCloseL(fp);
163 1 : CPLFree(pachHeader);
164 1 : return NULL;
165 : }
166 :
167 : /* -------------------------------------------------------------------- */
168 : /* Create and initialize info structure about file. */
169 : /* -------------------------------------------------------------------- */
170 541 : psFile = (NITFFile *) CPLCalloc(sizeof(NITFFile),1);
171 541 : psFile->fp = fp;
172 541 : psFile->pachHeader = pachHeader;
173 :
174 542 : retry_read_header:
175 : /* -------------------------------------------------------------------- */
176 : /* Get version. */
177 : /* -------------------------------------------------------------------- */
178 542 : NITFGetField( psFile->szVersion, pachHeader, 0, 9 );
179 :
180 : /* -------------------------------------------------------------------- */
181 : /* Collect a variety of information as metadata. */
182 : /* -------------------------------------------------------------------- */
183 : #define GetMD( target, hdr, start, length, name ) \
184 : NITFExtractMetadata( &(target->papszMetadata), hdr, \
185 : start, length, \
186 : "NITF_" #name );
187 :
188 1045 : if( EQUAL(psFile->szVersion,"NITF02.10")
189 : || EQUAL(psFile->szVersion,"NSIF01.00") )
190 : {
191 : char szWork[100];
192 :
193 503 : GetMD( psFile, pachHeader, 0, 9, FHDR );
194 503 : GetMD( psFile, pachHeader, 9, 2, CLEVEL );
195 503 : GetMD( psFile, pachHeader, 11, 4, STYPE );
196 503 : GetMD( psFile, pachHeader, 15, 10, OSTAID );
197 503 : GetMD( psFile, pachHeader, 25, 14, FDT );
198 503 : GetMD( psFile, pachHeader, 39, 80, FTITLE );
199 503 : GetMD( psFile, pachHeader, 119, 1, FSCLAS );
200 503 : GetMD( psFile, pachHeader, 120, 2, FSCLSY );
201 503 : GetMD( psFile, pachHeader, 122, 11, FSCODE );
202 503 : GetMD( psFile, pachHeader, 133, 2, FSCTLH );
203 503 : GetMD( psFile, pachHeader, 135, 20, FSREL );
204 503 : GetMD( psFile, pachHeader, 155, 2, FSDCTP );
205 503 : GetMD( psFile, pachHeader, 157, 8, FSDCDT );
206 503 : GetMD( psFile, pachHeader, 165, 4, FSDCXM );
207 503 : GetMD( psFile, pachHeader, 169, 1, FSDG );
208 503 : GetMD( psFile, pachHeader, 170, 8, FSDGDT );
209 503 : GetMD( psFile, pachHeader, 178, 43, FSCLTX );
210 503 : GetMD( psFile, pachHeader, 221, 1, FSCATP );
211 503 : GetMD( psFile, pachHeader, 222, 40, FSCAUT );
212 503 : GetMD( psFile, pachHeader, 262, 1, FSCRSN );
213 503 : GetMD( psFile, pachHeader, 263, 8, FSSRDT );
214 503 : GetMD( psFile, pachHeader, 271, 15, FSCTLN );
215 503 : GetMD( psFile, pachHeader, 286, 5, FSCOP );
216 503 : GetMD( psFile, pachHeader, 291, 5, FSCPYS );
217 503 : GetMD( psFile, pachHeader, 296, 1, ENCRYP );
218 503 : sprintf( szWork, "%3d,%3d,%3d",
219 : ((GByte *)pachHeader)[297],
220 : ((GByte *)pachHeader)[298],
221 : ((GByte *)pachHeader)[299] );
222 503 : GetMD( psFile, szWork, 0, 11, FBKGC );
223 503 : GetMD( psFile, pachHeader, 300, 24, ONAME );
224 503 : GetMD( psFile, pachHeader, 324, 18, OPHONE );
225 503 : NITFGetField(szTemp, pachHeader, 342, 12);
226 : }
227 39 : else if( EQUAL(psFile->szVersion,"NITF02.00") )
228 : {
229 33 : int nCOff = 0;
230 :
231 33 : GetMD( psFile, pachHeader, 0, 9, FHDR );
232 33 : GetMD( psFile, pachHeader, 9, 2, CLEVEL );
233 33 : GetMD( psFile, pachHeader, 11, 4, STYPE );
234 33 : GetMD( psFile, pachHeader, 15, 10, OSTAID );
235 33 : GetMD( psFile, pachHeader, 25, 14, FDT );
236 33 : GetMD( psFile, pachHeader, 39, 80, FTITLE );
237 33 : GetMD( psFile, pachHeader, 119, 1, FSCLAS );
238 33 : GetMD( psFile, pachHeader, 120, 40, FSCODE );
239 33 : GetMD( psFile, pachHeader, 160, 40, FSCTLH );
240 33 : GetMD( psFile, pachHeader, 200, 40, FSREL );
241 33 : GetMD( psFile, pachHeader, 240, 20, FSCAUT );
242 33 : GetMD( psFile, pachHeader, 260, 20, FSCTLN );
243 33 : GetMD( psFile, pachHeader, 280, 6, FSDWNG );
244 33 : if( EQUALN(pachHeader+280,"999998",6) )
245 : {
246 2 : GetMD( psFile, pachHeader, 286, 40, FSDEVT );
247 2 : nCOff += 40;
248 : }
249 33 : GetMD( psFile, pachHeader, 286+nCOff, 5, FSCOP );
250 33 : GetMD( psFile, pachHeader, 291+nCOff, 5, FSCPYS );
251 33 : GetMD( psFile, pachHeader, 296+nCOff, 1, ENCRYP );
252 33 : GetMD( psFile, pachHeader, 297+nCOff, 27, ONAME );
253 33 : GetMD( psFile, pachHeader, 324+nCOff, 18, OPHONE );
254 33 : NITFGetField(szTemp, pachHeader, 342+nCOff, 12);
255 : }
256 :
257 542 : if (!bTriedStreamingFileHeader &&
258 : EQUAL(szTemp, "999999999999"))
259 : {
260 : GUIntBig nFileSize;
261 : GByte abyDELIM2_L2[12];
262 : GByte abyL1_DELIM1[11];
263 :
264 1 : bTriedStreamingFileHeader = TRUE;
265 1 : CPLDebug("NITF", "Total file unknown. Trying to get a STREAMING_FILE_HEADER");
266 :
267 1 : VSIFSeekL( fp, 0, SEEK_END );
268 1 : nFileSize = VSIFTellL(fp);
269 :
270 1 : VSIFSeekL( fp, nFileSize - 11, SEEK_SET );
271 1 : abyDELIM2_L2[11] = '\0';
272 :
273 1 : if (VSIFReadL( abyDELIM2_L2, 1, 11, fp ) == 11 &&
274 : abyDELIM2_L2[0] == 0x0E && abyDELIM2_L2[1] == 0xCA &&
275 : abyDELIM2_L2[2] == 0x14 && abyDELIM2_L2[3] == 0xBF)
276 : {
277 1 : int SFHL2 = atoi((const char*)(abyDELIM2_L2 + 4));
278 1 : if (SFHL2 > 0 && nFileSize > 11 + SFHL2 + 11 )
279 : {
280 1 : VSIFSeekL( fp, nFileSize - 11 - SFHL2 - 11 , SEEK_SET );
281 :
282 1 : if ( VSIFReadL( abyL1_DELIM1, 1, 11, fp ) == 11 &&
283 : abyL1_DELIM1[7] == 0x0A && abyL1_DELIM1[8] == 0x6E &&
284 : abyL1_DELIM1[9] == 0x1D && abyL1_DELIM1[10] == 0x97 &&
285 : memcmp(abyL1_DELIM1, abyDELIM2_L2 + 4, 7) == 0 )
286 : {
287 1 : if (SFHL2 == nHeaderLen)
288 : {
289 1 : CSLDestroy(psFile->papszMetadata);
290 1 : psFile->papszMetadata = NULL;
291 :
292 1 : if ( (int)VSIFReadL( pachHeader, 1, SFHL2, fp ) != SFHL2 )
293 : {
294 0 : VSIFCloseL(fp);
295 0 : CPLFree(pachHeader);
296 0 : CPLFree(psFile);
297 0 : return NULL;
298 : }
299 :
300 1 : goto retry_read_header;
301 : }
302 : }
303 : }
304 : }
305 : }
306 :
307 : /* -------------------------------------------------------------------- */
308 : /* Collect segment info for the types we care about. */
309 : /* -------------------------------------------------------------------- */
310 541 : nNextData = nHeaderLen;
311 :
312 541 : nOffset = nHeaderLenOffset + 6;
313 :
314 541 : nOffset = NITFCollectSegmentInfo( psFile, nHeaderLen, nOffset,"IM",6, 10, &nNextData );
315 :
316 541 : if (nOffset != -1)
317 537 : nOffset = NITFCollectSegmentInfo( psFile, nHeaderLen, nOffset, "GR", 4, 6, &nNextData);
318 :
319 : /* LA Called NUMX in NITF 2.1 */
320 541 : if (nOffset != -1)
321 537 : nOffset = NITFCollectSegmentInfo( psFile, nHeaderLen, nOffset, "LA", 4, 3, &nNextData);
322 :
323 541 : if (nOffset != -1)
324 537 : nOffset = NITFCollectSegmentInfo( psFile, nHeaderLen, nOffset, "TX", 4, 5, &nNextData);
325 :
326 541 : if (nOffset != -1)
327 537 : nOffset = NITFCollectSegmentInfo( psFile, nHeaderLen, nOffset, "DE", 4, 9, &nNextData);
328 :
329 541 : if (nOffset != -1)
330 537 : nOffset = NITFCollectSegmentInfo( psFile, nHeaderLen, nOffset, "RE", 4, 7, &nNextData);
331 : else
332 : {
333 4 : NITFClose(psFile);
334 4 : return NULL;
335 : }
336 :
337 : /* -------------------------------------------------------------------- */
338 : /* Is there User Define Header Data? (TREs) */
339 : /* -------------------------------------------------------------------- */
340 537 : if (nHeaderLen < nOffset + 5)
341 : {
342 1 : CPLError(CE_Failure, CPLE_AppDefined, "NITF header too small");
343 1 : NITFClose(psFile);
344 1 : return NULL;
345 : }
346 :
347 536 : psFile->nTREBytes =
348 : atoi(NITFGetField( szTemp, pachHeader, nOffset, 5 ));
349 536 : if (psFile->nTREBytes < 0)
350 : {
351 1 : CPLError(CE_Failure, CPLE_AppDefined,
352 : "Invalid TRE size : %d", psFile->nTREBytes);
353 1 : NITFClose(psFile);
354 1 : return NULL;
355 : }
356 535 : nOffset += 5;
357 :
358 535 : if( psFile->nTREBytes > 3 )
359 : {
360 27 : nOffset += 3; /* UDHOFL */
361 27 : psFile->nTREBytes -= 3;
362 :
363 27 : if (nHeaderLen < nOffset + psFile->nTREBytes)
364 : {
365 0 : CPLError(CE_Failure, CPLE_AppDefined, "NITF header too small");
366 0 : NITFClose(psFile);
367 0 : return NULL;
368 : }
369 :
370 27 : psFile->pachTRE = (char *) VSIMalloc(psFile->nTREBytes);
371 27 : if (psFile->pachTRE == NULL)
372 : {
373 0 : CPLError(CE_Failure, CPLE_OutOfMemory,
374 : "Cannot allocate %d bytes", psFile->nTREBytes);
375 0 : NITFClose(psFile);
376 0 : return NULL;
377 : }
378 27 : memcpy( psFile->pachTRE, pachHeader + nOffset,
379 : psFile->nTREBytes );
380 : }
381 :
382 : /* -------------------------------------------------------------------- */
383 : /* Is there Extended Header Data? (More TREs) */
384 : /* -------------------------------------------------------------------- */
385 535 : if( nHeaderLen > nOffset + 8 )
386 : {
387 : int nXHDL =
388 37 : atoi(NITFGetField( szTemp, pachHeader, nOffset, 5 ));
389 37 : if (nXHDL < 0)
390 : {
391 1 : CPLError(CE_Failure, CPLE_AppDefined,
392 : "Invalid XHDL value : %d", nXHDL);
393 1 : NITFClose(psFile);
394 1 : return NULL;
395 : }
396 :
397 36 : nOffset += 5; /* XHDL */
398 :
399 36 : if( nXHDL > 3 )
400 : {
401 : char* pachNewTRE;
402 :
403 9 : nOffset += 3; /* XHDLOFL */
404 9 : nXHDL -= 3;
405 :
406 9 : if (nHeaderLen < nOffset + nXHDL)
407 : {
408 1 : CPLError(CE_Failure, CPLE_AppDefined, "NITF header too small");
409 1 : NITFClose(psFile);
410 1 : return NULL;
411 : }
412 :
413 8 : pachNewTRE = (char *)
414 : VSIRealloc( psFile->pachTRE,
415 : psFile->nTREBytes + nXHDL );
416 8 : if (pachNewTRE == NULL)
417 : {
418 0 : CPLError(CE_Failure, CPLE_OutOfMemory,
419 : "Cannot allocate %d bytes", psFile->nTREBytes + nXHDL);
420 0 : NITFClose(psFile);
421 0 : return NULL;
422 : }
423 8 : psFile->pachTRE = pachNewTRE;
424 8 : memcpy( psFile->pachTRE, pachHeader + nOffset, nXHDL );
425 8 : psFile->nTREBytes += nXHDL;
426 : }
427 : }
428 :
429 533 : return psFile;
430 : }
431 :
432 : /************************************************************************/
433 : /* NITFClose() */
434 : /************************************************************************/
435 :
436 : void NITFClose( NITFFile *psFile )
437 :
438 541 : {
439 : int iSegment;
440 :
441 6822 : for( iSegment = 0; iSegment < psFile->nSegmentCount; iSegment++ )
442 : {
443 6281 : NITFSegmentInfo *psSegInfo = psFile->pasSegmentInfo + iSegment;
444 :
445 6281 : if( psSegInfo->hAccess == NULL )
446 1747 : continue;
447 :
448 4534 : if( EQUAL(psSegInfo->szSegmentType,"IM"))
449 4534 : NITFImageDeaccess( (NITFImage *) psSegInfo->hAccess );
450 0 : else if( EQUAL(psSegInfo->szSegmentType,"DE"))
451 0 : NITFDESDeaccess( (NITFDES *) psSegInfo->hAccess );
452 : else
453 : {
454 0 : CPLAssert( FALSE );
455 : }
456 : }
457 :
458 541 : CPLFree( psFile->pasSegmentInfo );
459 541 : if( psFile->fp != NULL )
460 541 : VSIFCloseL( psFile->fp );
461 541 : CPLFree( psFile->pachHeader );
462 541 : CSLDestroy( psFile->papszMetadata );
463 541 : CPLFree( psFile->pachTRE );
464 541 : CPLFree( psFile );
465 541 : }
466 :
467 : static void NITFGotoOffset(FILE* fp, GUIntBig nLocation)
468 284350 : {
469 284350 : GUIntBig nCurrentLocation = VSIFTellL(fp);
470 284350 : if (nLocation > nCurrentLocation)
471 : {
472 : GUIntBig nFileSize;
473 : int iFill;
474 173227 : char cSpace = ' ';
475 :
476 173227 : VSIFSeekL(fp, 0, SEEK_END);
477 173227 : nFileSize = VSIFTellL(fp);
478 173227 : if (nLocation > nFileSize)
479 : {
480 1309863 : for(iFill = 0; iFill < nLocation - nFileSize; iFill++)
481 1138862 : VSIFWriteL(&cSpace, 1, 1, fp);
482 : }
483 : else
484 2226 : VSIFSeekL(fp, nLocation, SEEK_SET);
485 : }
486 111123 : else if (nLocation < nCurrentLocation)
487 : {
488 2593 : VSIFSeekL(fp, nLocation, SEEK_SET);
489 : }
490 :
491 284350 : }
492 :
493 : /************************************************************************/
494 : /* NITFCreate() */
495 : /* */
496 : /* Create a new uncompressed NITF file. */
497 : /************************************************************************/
498 :
499 : int NITFCreate( const char *pszFilename,
500 : int nPixels, int nLines, int nBands,
501 : int nBitsPerSample, const char *pszPVType,
502 : char **papszOptions )
503 :
504 196 : {
505 : FILE *fp;
506 196 : GUIntBig nCur = 0;
507 196 : int nOffset = 0, iBand, nIHSize, nNPPBH, nNPPBV;
508 : GIntBig nImageSize;
509 : int nNBPR, nNBPC;
510 : const char *pszIREP;
511 196 : const char *pszIC = CSLFetchNameValue(papszOptions,"IC");
512 : int nCLevel;
513 : const char *pszNUMT;
514 196 : int nHL, nNUMT = 0;
515 : int nUDIDLOffset;
516 : const char *pszVersion;
517 196 : int iIM, nIM = 1;
518 : const char *pszNUMI;
519 196 : int iGS, nGS = 0; // number of graphic segment
520 : const char *pszNUMS; // graphic segment option string
521 :
522 196 : if (nBands <= 0 || nBands > 99999)
523 : {
524 2 : CPLError(CE_Failure, CPLE_NotSupported,
525 : "Invalid band number : %d", nBands);
526 2 : return FALSE;
527 : }
528 :
529 194 : if( pszIC == NULL )
530 187 : pszIC = "NC";
531 :
532 : /* -------------------------------------------------------------------- */
533 : /* Fetch some parameter overrides. */
534 : /* -------------------------------------------------------------------- */
535 194 : pszIREP = CSLFetchNameValue( papszOptions, "IREP" );
536 194 : if( pszIREP == NULL )
537 155 : pszIREP = "MONO";
538 :
539 194 : pszNUMT = CSLFetchNameValue( papszOptions, "NUMT" );
540 194 : if( pszNUMT != NULL )
541 : {
542 5 : nNUMT = atoi(pszNUMT);
543 5 : if (nNUMT < 0 || nNUMT > 999)
544 : {
545 1 : CPLError( CE_Failure, CPLE_AppDefined,
546 : "Invalid NUMT value : %s", pszNUMT);
547 1 : return FALSE;
548 : }
549 : }
550 :
551 193 : pszNUMI = CSLFetchNameValue( papszOptions, "NUMI" );
552 193 : if (pszNUMI != NULL)
553 : {
554 4 : nIM = atoi(pszNUMI);
555 4 : if (nIM < 1 || nIM > 999)
556 : {
557 1 : CPLError( CE_Failure, CPLE_AppDefined,
558 : "Invalid NUMI value : %s", pszNUMI);
559 1 : return FALSE;
560 : }
561 3 : if (nIM != 1 && !EQUAL(pszIC, "NC"))
562 : {
563 1 : CPLError( CE_Failure, CPLE_AppDefined,
564 : "Unable to create file with multiple images and compression at the same time");
565 1 : return FALSE;
566 : }
567 : }
568 :
569 : // Reads and validates graphics segment number option
570 191 : pszNUMS = CSLFetchNameValue(papszOptions, "NUMS");
571 191 : if (pszNUMS != NULL)
572 : {
573 9 : nGS = atoi(pszNUMS);
574 9 : if (nGS < 0 || nGS > 999)
575 : {
576 1 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid NUMS value : %s",
577 : pszNUMS);
578 1 : return FALSE;
579 : }
580 : }
581 :
582 :
583 :
584 : /* -------------------------------------------------------------------- */
585 : /* Compute raw image size, blocking factors and so forth. */
586 : /* -------------------------------------------------------------------- */
587 190 : nNPPBH = nPixels;
588 190 : nNPPBV = nLines;
589 :
590 190 : if( CSLFetchNameValue( papszOptions, "BLOCKSIZE" ) != NULL )
591 4 : nNPPBH = nNPPBV = atoi(CSLFetchNameValue( papszOptions, "BLOCKSIZE" ));
592 :
593 190 : if( CSLFetchNameValue( papszOptions, "BLOCKXSIZE" ) != NULL )
594 3 : nNPPBH = atoi(CSLFetchNameValue( papszOptions, "BLOCKXSIZE" ));
595 :
596 190 : if( CSLFetchNameValue( papszOptions, "BLOCKYSIZE" ) != NULL )
597 2 : nNPPBV = atoi(CSLFetchNameValue( papszOptions, "BLOCKYSIZE" ));
598 :
599 190 : if( CSLFetchNameValue( papszOptions, "NPPBH" ) != NULL )
600 0 : nNPPBH = atoi(CSLFetchNameValue( papszOptions, "NPPBH" ));
601 :
602 190 : if( CSLFetchNameValue( papszOptions, "NPPBV" ) != NULL )
603 0 : nNPPBV = atoi(CSLFetchNameValue( papszOptions, "NPPBV" ));
604 :
605 :
606 193 : if (EQUAL(pszIC, "NC") &&
607 : (nPixels > 8192 || nLines > 8192) &&
608 : nNPPBH == nPixels && nNPPBV == nLines)
609 : {
610 : /* See MIL-STD-2500-C, paragraph 5.4.2.2-d (#3263) */
611 3 : nNBPR = 1;
612 3 : nNBPC = 1;
613 3 : nNPPBH = 0;
614 3 : nNPPBV = 0;
615 :
616 3 : nImageSize =
617 : ((nBitsPerSample)/8)
618 : * ((GIntBig) nPixels *nLines)
619 : * nBands;
620 : }
621 : else
622 : {
623 187 : if( nNPPBH <= 0 || nNPPBV <= 0 ||
624 : nNPPBH > 9999 || nNPPBV > 9999 )
625 0 : nNPPBH = nNPPBV = 256;
626 :
627 187 : nNBPR = (nPixels + nNPPBH - 1) / nNPPBH;
628 187 : nNBPC = (nLines + nNPPBV - 1) / nNPPBV;
629 187 : if ( nNBPR > 9999 || nNBPC > 9999 )
630 : {
631 1 : CPLError( CE_Failure, CPLE_AppDefined,
632 : "Unable to create file %s,\n"
633 : "Too many blocks : %d x %d",
634 : pszFilename, nNBPR, nNBPC);
635 1 : return FALSE;
636 : }
637 :
638 186 : nImageSize =
639 : ((nBitsPerSample)/8)
640 : * ((GIntBig) nNBPR * nNBPC)
641 : * nNPPBH * nNPPBV * nBands;
642 : }
643 :
644 189 : if (EQUAL(pszIC, "NC"))
645 : {
646 184 : if ((double)nImageSize >= 1e10 - 1)
647 : {
648 1 : CPLError( CE_Failure, CPLE_AppDefined,
649 : "Unable to create file %s,\n"
650 : "Too big image size : " CPL_FRMT_GUIB,
651 : pszFilename, nImageSize );
652 1 : return FALSE;
653 : }
654 183 : if ((double)(nImageSize * nIM) >= 1e12 - 1)
655 : {
656 1 : CPLError( CE_Failure, CPLE_AppDefined,
657 : "Unable to create file %s,\n"
658 : "Too big file size : " CPL_FRMT_GUIB,
659 : pszFilename, nImageSize * nIM );
660 1 : return FALSE;
661 : }
662 : }
663 :
664 : /* -------------------------------------------------------------------- */
665 : /* Open new file. */
666 : /* -------------------------------------------------------------------- */
667 187 : fp = VSIFOpenL( pszFilename, "wb+" );
668 187 : if( fp == NULL )
669 : {
670 1 : CPLError( CE_Failure, CPLE_OpenFailed,
671 : "Unable to create file %s,\n"
672 : "check path and permissions.",
673 : pszFilename );
674 1 : return FALSE;
675 : }
676 :
677 :
678 : /* -------------------------------------------------------------------- */
679 : /* Work out the version we are producing. For now we really */
680 : /* only support creating NITF02.10 or the nato analog */
681 : /* NSIF01.00. */
682 : /* -------------------------------------------------------------------- */
683 186 : pszVersion = CSLFetchNameValue( papszOptions, "FHDR" );
684 186 : if( pszVersion == NULL )
685 180 : pszVersion = "NITF02.10";
686 6 : else if( !EQUAL(pszVersion,"NITF02.10")
687 : && !EQUAL(pszVersion,"NSIF01.00") )
688 : {
689 1 : CPLError( CE_Warning, CPLE_AppDefined,
690 : "FHDR=%s not supported, switching to NITF02.10.",
691 : pszVersion );
692 1 : pszVersion = "NITF02.10";
693 : }
694 :
695 : /* -------------------------------------------------------------------- */
696 : /* Prepare the file header. */
697 : /* -------------------------------------------------------------------- */
698 :
699 : #define PLACE(location,name,text) { \
700 : const char* _text = text; \
701 : NITFGotoOffset(fp, location); \
702 : VSIFWriteL(_text, 1, strlen(_text), fp); }
703 :
704 : #define OVR(width,location,name,text) { \
705 : const char* _text = text; \
706 : const char *pszParmValue; \
707 : pszParmValue = CSLFetchNameValue( papszOptions, #name ); \
708 : if( pszParmValue == NULL ) \
709 : pszParmValue = _text; \
710 : NITFGotoOffset(fp, location); \
711 : VSIFWriteL(pszParmValue, 1, MIN(width,strlen(pszParmValue)), fp); }
712 :
713 : #define WRITE_BYTE(location, val) { \
714 : char cVal = val; \
715 : NITFGotoOffset(fp, location); \
716 : VSIFWriteL(&cVal, 1, 1, fp); }
717 :
718 186 : VSIFSeekL(fp, 0, SEEK_SET);
719 :
720 186 : PLACE ( 0, FDHR_FVER, pszVersion );
721 186 : OVR( 2, 9, CLEVEL, "03" ); /* Patched at the end */
722 186 : PLACE ( 11, STYPE ,"BF01" );
723 186 : OVR(10, 15, OSTAID ,"GDAL" );
724 186 : OVR(14, 25, FDT ,"20021216151629" );
725 186 : OVR(80, 39, FTITLE ,"" );
726 186 : OVR( 1,119, FSCLAS ,"U" );
727 186 : OVR( 2,120, FSCLSY ,"" );
728 186 : OVR(11,122, FSCODE ,"" );
729 186 : OVR( 2,133, FSCTLH ,"" );
730 186 : OVR(20,135, FSREL ,"" );
731 186 : OVR( 2,155, FSDCTP ,"" );
732 186 : OVR( 8,157, FSDCDT ,"" );
733 186 : OVR( 4,165, FSDCXM ,"" );
734 186 : OVR( 1,169, FSDG ,"" );
735 186 : OVR( 8,170, FSDGDT ,"" );
736 186 : OVR(43,178, FSCLTX ,"" );
737 186 : OVR( 1,221, FSCATP ,"" );
738 186 : OVR(40,222, FSCAUT ,"" );
739 186 : OVR( 1,262, FSCRSN ,"" );
740 186 : OVR( 8,263, FSSRDT ,"" );
741 186 : OVR(15,271, FSCTLN ,"" );
742 186 : OVR( 5,286, FSCOP ,"00000" );
743 186 : OVR( 5,291, FSCPYS ,"00000" );
744 186 : PLACE (296, ENCRYP ,"0" );
745 186 : WRITE_BYTE(297, 0x00); /* FBKGC */
746 186 : WRITE_BYTE(298, 0x00);
747 186 : WRITE_BYTE(299, 0x00);
748 186 : OVR(24,300, ONAME ,"" );
749 186 : OVR(18,324, OPHONE ,"" );
750 186 : PLACE (342, FL ,"????????????" );
751 186 : PLACE (354, HL ,"??????" );
752 186 : PLACE (360, NUMI ,CPLSPrintf("%03d", nIM) );
753 :
754 186 : nHL = 363;
755 1370 : for(iIM=0;iIM<nIM;iIM++)
756 : {
757 1184 : PLACE (nHL, LISHi ,"??????" );
758 1184 : PLACE (nHL + 6, LIi ,CPLSPrintf("%010" CPL_FRMT_GB_WITHOUT_PREFIX "d", nImageSize) );
759 1184 : nHL += 6 + 10;
760 : }
761 :
762 : // Creates Header entries for graphic segment
763 : // NUMS: number of segment
764 : // For each segment:
765 : // LSSH[i]: subheader length (4 byte), set to be 258, the size for
766 : // minimal amount of information.
767 : // LS[i] data length (6 byte)
768 186 : PLACE (nHL, NUMS ,CPLSPrintf("%03d",nGS) );
769 186 : nHL += 3; // Move three characters
770 190 : for (iGS = 0; iGS < nGS; iGS++)
771 : {
772 4 : PLACE (nHL, LSSHi ,CPLSPrintf("0000") );
773 4 : PLACE (nHL + 4, LSi ,CPLSPrintf("000000") );
774 4 : nHL += 4 + 6;
775 : }
776 :
777 186 : PLACE (nHL, NUMX ,"000" );
778 186 : PLACE (nHL + 3, NUMT ,CPLSPrintf("%03d",nNUMT) );
779 :
780 186 : PLACE (nHL + 6, LTSHnLTn ,"" );
781 :
782 186 : nHL += 6 + (4+5) * nNUMT;
783 :
784 186 : PLACE (nHL, NUMDES ,"000" );
785 186 : nHL += 3;
786 186 : PLACE (nHL, NUMRES ,"000" );
787 186 : nHL += 3;
788 186 : PLACE (nHL, UDHDL ,"00000" );
789 186 : nHL += 5;
790 186 : PLACE (nHL, XHDL ,"00000" );
791 186 : nHL += 5;
792 :
793 186 : if( CSLFetchNameValue(papszOptions,"FILE_TRE") != NULL )
794 : {
795 3 : NITFWriteTREsFromOptions(
796 : fp,
797 : nHL - 10,
798 : nHL,
799 : &nHL,
800 : papszOptions, "FILE_TRE=" );
801 : }
802 :
803 186 : if (nHL > 999999)
804 : {
805 0 : CPLError(CE_Failure, CPLE_AppDefined,
806 : "Too big file header length : %d", nHL);
807 0 : VSIFCloseL( fp );
808 0 : return FALSE;
809 : }
810 :
811 : // update header length
812 186 : PLACE (354, HL ,CPLSPrintf("%06d",nHL) );
813 :
814 186 : nCur = nHL;
815 :
816 : /* -------------------------------------------------------------------- */
817 : /* Prepare the image header. */
818 : /* -------------------------------------------------------------------- */
819 1370 : for(iIM=0;iIM<nIM;iIM++)
820 : {
821 1184 : VSIFSeekL(fp, nCur, SEEK_SET);
822 :
823 1184 : PLACE (nCur+ 0, IM , "IM" );
824 1184 : OVR(10,nCur+ 2, IID1 , "Missing" );
825 1184 : OVR(14,nCur+ 12, IDATIM , "20021216151629" );
826 1184 : OVR(17,nCur+ 26, TGTID , "" );
827 1184 : OVR(80,nCur+ 43, IID2 , "" );
828 1184 : OVR( 1,nCur+123, ISCLAS , "U" );
829 1184 : OVR( 2,nCur+124, ISCLSY , "" );
830 1184 : OVR(11,nCur+126, ISCODE , "" );
831 1184 : OVR( 2,nCur+137, ISCTLH , "" );
832 1184 : OVR(20,nCur+139, ISREL , "" );
833 1184 : OVR( 2,nCur+159, ISDCTP , "" );
834 1184 : OVR( 8,nCur+161, ISDCDT , "" );
835 1184 : OVR( 4,nCur+169, ISDCXM , "" );
836 1184 : OVR( 1,nCur+173, ISDG , "" );
837 1184 : OVR( 8,nCur+174, ISDGDT , "" );
838 1184 : OVR(43,nCur+182, ISCLTX , "" );
839 1184 : OVR( 1,nCur+225, ISCATP , "" );
840 1184 : OVR(40,nCur+226, ISCAUT , "" );
841 1184 : OVR( 1,nCur+266, ISCRSN , "" );
842 1184 : OVR( 8,nCur+267, ISSRDT , "" );
843 1184 : OVR(15,nCur+275, ISCTLN , "" );
844 1184 : PLACE (nCur+290, ENCRYP , "0" );
845 1184 : OVR(42,nCur+291, ISORCE , "Unknown" );
846 1184 : PLACE (nCur+333, NROWS , CPLSPrintf("%08d", nLines) );
847 1184 : PLACE (nCur+341, NCOLS , CPLSPrintf("%08d", nPixels) );
848 1184 : PLACE (nCur+349, PVTYPE , pszPVType );
849 1184 : PLACE (nCur+352, IREP , pszIREP );
850 1184 : OVR( 8,nCur+360, ICAT , "VIS" );
851 1184 : OVR( 2,nCur+368, ABPP , CPLSPrintf("%02d",nBitsPerSample) );
852 1184 : OVR( 1,nCur+370, PJUST , "R" );
853 1184 : OVR( 1,nCur+371, ICORDS , " " );
854 :
855 1184 : nOffset = 372;
856 :
857 : {
858 : const char *pszParmValue;
859 1184 : pszParmValue = CSLFetchNameValue( papszOptions, "ICORDS" );
860 1184 : if( pszParmValue == NULL )
861 1145 : pszParmValue = " ";
862 1184 : if( *pszParmValue != ' ' )
863 : {
864 39 : OVR(60,nCur+nOffset, IGEOLO, "" );
865 39 : nOffset += 60;
866 : }
867 : }
868 :
869 : {
870 1184 : const char* pszICOM = CSLFetchNameValue( papszOptions, "ICOM");
871 1184 : if (pszICOM != NULL)
872 : {
873 1 : int nLenICOM = strlen(pszICOM);
874 1 : int nICOM = (79 + nLenICOM) / 80;
875 1 : if (nICOM > 9)
876 : {
877 0 : CPLError(CE_Warning, CPLE_NotSupported, "ICOM will be truncated");
878 0 : nICOM = 9;
879 : }
880 1 : PLACE (nCur+nOffset, NICOM , CPLSPrintf("%01d",nICOM) );
881 1 : VSIFWriteL(pszICOM, 1, MIN(nICOM * 80, nLenICOM), fp);
882 1 : nOffset += nICOM * 80;
883 : }
884 : else
885 : {
886 1183 : PLACE (nCur+nOffset, NICOM , "0" );
887 : }
888 : }
889 :
890 1184 : OVR( 2,nCur+nOffset+1, IC , "NC" );
891 :
892 1184 : if( pszIC[0] != 'N' )
893 : {
894 5 : OVR( 4,nCur+nOffset+3, COMRAT , " " );
895 5 : nOffset += 4;
896 : }
897 :
898 1184 : if (nBands <= 9)
899 : {
900 1181 : PLACE (nCur+nOffset+3, NBANDS , CPLSPrintf("%d",nBands) );
901 : }
902 : else
903 : {
904 3 : PLACE (nCur+nOffset+3, NBANDS , "0" );
905 3 : PLACE (nCur+nOffset+4, XBANDS , CPLSPrintf("%05d",nBands) );
906 3 : nOffset += 5;
907 : }
908 :
909 1184 : nOffset += 4;
910 :
911 : /* -------------------------------------------------------------------- */
912 : /* Per band info */
913 : /* -------------------------------------------------------------------- */
914 72450 : for( iBand = 0; iBand < nBands; iBand++ )
915 : {
916 71266 : const char *pszIREPBAND = "M";
917 :
918 71266 : if( EQUAL(pszIREP,"RGB/LUT") )
919 5 : pszIREPBAND = "LU";
920 71261 : else if( EQUAL(pszIREP,"RGB") )
921 : {
922 13 : if( iBand == 0 )
923 4 : pszIREPBAND = "R";
924 9 : else if( iBand == 1 )
925 4 : pszIREPBAND = "G";
926 5 : else if( iBand == 2 )
927 4 : pszIREPBAND = "B";
928 : }
929 71248 : else if( EQUALN(pszIREP,"YCbCr",5) )
930 : {
931 9 : if( iBand == 0 )
932 3 : pszIREPBAND = "Y";
933 6 : else if( iBand == 1 )
934 3 : pszIREPBAND = "Cb";
935 3 : else if( iBand == 2 )
936 3 : pszIREPBAND = "Cr";
937 : }
938 :
939 71266 : PLACE(nCur+nOffset+ 0, IREPBANDn, pszIREPBAND );
940 : // PLACE(nCur+nOffset+ 2, ISUBCATn, "" );
941 71266 : PLACE(nCur+nOffset+ 8, IFCn , "N" );
942 : // PLACE(nCur+nOffset+ 9, IMFLTn, "" );
943 :
944 71266 : if( !EQUAL(pszIREP,"RGB/LUT") )
945 : {
946 71261 : PLACE(nCur+nOffset+12, NLUTSn, "0" );
947 71261 : nOffset += 13;
948 : }
949 : else
950 : {
951 5 : int iC, nCount=256;
952 :
953 5 : if( CSLFetchNameValue(papszOptions,"LUT_SIZE") != NULL )
954 5 : nCount = atoi(CSLFetchNameValue(papszOptions,"LUT_SIZE"));
955 :
956 5 : if (!(nCount >= 0 && nCount <= 99999))
957 : {
958 1 : CPLError(CE_Warning, CPLE_AppDefined,
959 : "Invalid LUT value : %d. Defaulting to 256", nCount);
960 1 : nCount = 256;
961 : }
962 5 : PLACE(nCur+nOffset+12, NLUTSn, "3" );
963 5 : PLACE(nCur+nOffset+13, NELUTn, CPLSPrintf("%05d",nCount) );
964 :
965 1030 : for( iC = 0; iC < nCount; iC++ )
966 : {
967 1025 : WRITE_BYTE(nCur+nOffset+18+iC+ 0, (char) iC);
968 1025 : WRITE_BYTE(nCur+nOffset+18+iC+nCount*1, (char) iC);
969 1025 : WRITE_BYTE(nCur+nOffset+18+iC+nCount*2, (char) iC);
970 : }
971 5 : nOffset += 18 + nCount*3;
972 : }
973 : }
974 :
975 : /* -------------------------------------------------------------------- */
976 : /* Remainder of image header info. */
977 : /* -------------------------------------------------------------------- */
978 1184 : PLACE(nCur+nOffset+ 0, ISYNC , "0" );
979 :
980 : /* RGB JPEG compressed NITF requires IMODE=P (see #3345) */
981 1187 : if (nBands >= 3 && (EQUAL(pszIC, "C3") || EQUAL(pszIC, "M3")))
982 : {
983 3 : PLACE(nCur+nOffset+ 1, IMODE , "P" );
984 : }
985 : else
986 : {
987 1181 : PLACE(nCur+nOffset+ 1, IMODE , "B" );
988 : }
989 1184 : PLACE(nCur+nOffset+ 2, NBPR , CPLSPrintf("%04d",nNBPR) );
990 1184 : PLACE(nCur+nOffset+ 6, NBPC , CPLSPrintf("%04d",nNBPC) );
991 1184 : PLACE(nCur+nOffset+ 10, NPPBH , CPLSPrintf("%04d",nNPPBH) );
992 1184 : PLACE(nCur+nOffset+ 14, NPPBV , CPLSPrintf("%04d",nNPPBV) );
993 1184 : PLACE(nCur+nOffset+ 18, NBPP , CPLSPrintf("%02d",nBitsPerSample) );
994 1184 : PLACE(nCur+nOffset+ 20, IDLVL , "001" );
995 1184 : PLACE(nCur+nOffset+ 23, IALVL , "000" );
996 1184 : PLACE(nCur+nOffset+ 26, ILOC , "0000000000" );
997 1184 : PLACE(nCur+nOffset+ 36, IMAG , "1.0 " );
998 1184 : PLACE(nCur+nOffset+ 40, UDIDL , "00000" );
999 1184 : PLACE(nCur+nOffset+ 45, IXSHDL, "00000" );
1000 :
1001 1184 : nUDIDLOffset = nOffset + 40;
1002 1184 : nOffset += 50;
1003 :
1004 : /* -------------------------------------------------------------------- */
1005 : /* Add BLOCKA TRE if requested. */
1006 : /* -------------------------------------------------------------------- */
1007 1184 : if( CSLFetchNameValue(papszOptions,"BLOCKA_BLOCK_COUNT") != NULL )
1008 : {
1009 3 : NITFWriteBLOCKA( fp,
1010 : nCur + (GUIntBig)nUDIDLOffset,
1011 : nCur + (GUIntBig)nOffset,
1012 : &nOffset,
1013 : papszOptions );
1014 : }
1015 :
1016 1184 : if( CSLFetchNameValue(papszOptions,"TRE") != NULL )
1017 : {
1018 13 : NITFWriteTREsFromOptions(
1019 : fp,
1020 : nCur + (GUIntBig)nUDIDLOffset,
1021 : nCur + (GUIntBig)nOffset,
1022 : &nOffset,
1023 : papszOptions, "TRE=" );
1024 : }
1025 :
1026 : /* -------------------------------------------------------------------- */
1027 : /* Update the image header length in the file header. */
1028 : /* -------------------------------------------------------------------- */
1029 1184 : nIHSize = nOffset;
1030 :
1031 1184 : if (nIHSize > 999999)
1032 : {
1033 0 : CPLError(CE_Failure, CPLE_AppDefined,
1034 : "Too big image header length : %d", nIHSize);
1035 0 : VSIFCloseL( fp );
1036 0 : return FALSE;
1037 : }
1038 :
1039 1184 : PLACE( 363 + iIM * 16, LISH1, CPLSPrintf("%06d",nIHSize) );
1040 :
1041 1184 : nCur += nIHSize + nImageSize;
1042 : }
1043 :
1044 : /* -------------------------------------------------------------------- */
1045 : /* Compute and update CLEVEL ("complexity" level). */
1046 : /* See: http://164.214.2.51/ntb/baseline/docs/2500b/2500b_not2.pdf */
1047 : /* page 96u */
1048 : /* -------------------------------------------------------------------- */
1049 186 : nCLevel = 3;
1050 186 : if (nBands > 9 || nIM > 20 || nPixels > 2048 || nLines > 2048 ||
1051 : nNPPBH > 2048 || nNPPBV > 2048 || nCur > 52428799 )
1052 : {
1053 6 : nCLevel = 5;
1054 : }
1055 186 : if (nPixels > 8192 || nLines > 8192 ||
1056 : nNPPBH > 8192 || nNPPBV > 8192 || nCur > 1073741833)
1057 : {
1058 2 : nCLevel = 6;
1059 : }
1060 186 : if (nBands > 256 || nPixels > 65536 || nLines > 65536 ||
1061 : nCur > 2147483647)
1062 : {
1063 2 : nCLevel = 7;
1064 : }
1065 186 : OVR( 2, 9, CLEVEL, CPLSPrintf("%02d", nCLevel) );
1066 :
1067 : /* -------------------------------------------------------------------- */
1068 : /* Update total file length */
1069 : /* -------------------------------------------------------------------- */
1070 :
1071 : /* According to the spec, CLEVEL 7 supports up to 10,737,418,330 bytes */
1072 : /* but we can support technically much more */
1073 186 : if (EQUAL(pszIC, "NC") && GUINTBIG_TO_DOUBLE(nCur) >= 1e12 - 1)
1074 : {
1075 0 : CPLError(CE_Failure, CPLE_AppDefined,
1076 : "Too big file : " CPL_FRMT_GUIB, nCur);
1077 0 : VSIFCloseL( fp );
1078 0 : return FALSE;
1079 : }
1080 :
1081 186 : PLACE( 342, FL,
1082 : CPLSPrintf( "%012" CPL_FRMT_GB_WITHOUT_PREFIX "d", nCur) );
1083 :
1084 : /* -------------------------------------------------------------------- */
1085 : /* Grow file to full required size by writing one byte at the end. */
1086 : /* -------------------------------------------------------------------- */
1087 186 : if( EQUAL(pszIC,"NC") )
1088 : {
1089 181 : char cNul = 0;
1090 181 : VSIFSeekL( fp, nCur-1, SEEK_SET );
1091 181 : VSIFWriteL( &cNul, 1, 1, fp );
1092 : }
1093 :
1094 186 : VSIFCloseL( fp );
1095 :
1096 186 : return TRUE;
1097 : }
1098 :
1099 : /************************************************************************/
1100 : /* NITFWriteTRE() */
1101 : /************************************************************************/
1102 :
1103 : static int NITFWriteTRE( FILE* fp,
1104 : vsi_l_offset nOffsetUDIDL,
1105 : vsi_l_offset nOffsetTREInHeader,
1106 : int *pnOffset,
1107 : const char *pszTREName, char *pabyTREData, int nTREDataSize )
1108 :
1109 19 : {
1110 : char szTemp[12];
1111 : int nOldOffset;
1112 :
1113 : /* -------------------------------------------------------------------- */
1114 : /* Update IXSHDL. */
1115 : /* -------------------------------------------------------------------- */
1116 19 : VSIFSeekL(fp, nOffsetUDIDL + 5, SEEK_SET);
1117 19 : VSIFReadL(szTemp, 1, 5, fp);
1118 19 : szTemp[5] = 0;
1119 19 : nOldOffset = atoi(szTemp);
1120 :
1121 19 : if( nOldOffset == 0 )
1122 : {
1123 16 : nOldOffset = 3;
1124 16 : PLACE(nOffsetUDIDL+10, IXSOFL, "000" );
1125 16 : *pnOffset += 3;
1126 : }
1127 :
1128 19 : if (nOldOffset + 11 + nTREDataSize > 99999 || nTREDataSize > 99999)
1129 : {
1130 2 : CPLError(CE_Failure, CPLE_AppDefined, "Too big TRE to be written");
1131 2 : return FALSE;
1132 : }
1133 :
1134 17 : sprintf( szTemp, "%05d", nOldOffset + 11 + nTREDataSize );
1135 17 : PLACE( nOffsetUDIDL + 5, IXSHDL, szTemp );
1136 :
1137 : /* -------------------------------------------------------------------- */
1138 : /* Create TRE prefix. */
1139 : /* -------------------------------------------------------------------- */
1140 17 : sprintf( szTemp, "%-6s%05d",
1141 : pszTREName, nTREDataSize );
1142 17 : VSIFSeekL(fp, nOffsetTREInHeader + nOldOffset, SEEK_SET);
1143 17 : VSIFWriteL(szTemp, 11, 1, fp);
1144 17 : VSIFWriteL(pabyTREData, nTREDataSize, 1, fp);
1145 :
1146 : /* -------------------------------------------------------------------- */
1147 : /* Increment values. */
1148 : /* -------------------------------------------------------------------- */
1149 17 : *pnOffset += nTREDataSize + 11;
1150 :
1151 17 : return TRUE;
1152 : }
1153 :
1154 : /************************************************************************/
1155 : /* NITFWriteTREsFromOptions() */
1156 : /************************************************************************/
1157 :
1158 : static int NITFWriteTREsFromOptions(
1159 : FILE* fp,
1160 : vsi_l_offset nOffsetUDIDL, vsi_l_offset nOffsetTRE,
1161 : int *pnOffset,
1162 : char **papszOptions, const char* pszTREPrefix )
1163 :
1164 16 : {
1165 : int bIgnoreBLOCKA =
1166 16 : CSLFetchNameValue(papszOptions,"BLOCKA_BLOCK_COUNT") != NULL;
1167 : int iOption;
1168 16 : int nTREPrefixLen = strlen(pszTREPrefix);
1169 :
1170 16 : if( papszOptions == NULL )
1171 0 : return TRUE;
1172 :
1173 50 : for( iOption = 0; papszOptions[iOption] != NULL; iOption++ )
1174 : {
1175 : const char *pszEscapedContents;
1176 : char *pszUnescapedContents;
1177 : char *pszTREName;
1178 : int nContentLength;
1179 : const char* pszSpace;
1180 :
1181 37 : if( !EQUALN(papszOptions[iOption], pszTREPrefix, nTREPrefixLen) )
1182 18 : continue;
1183 :
1184 19 : if( EQUALN(papszOptions[iOption]+nTREPrefixLen,"BLOCKA=",7)
1185 : && bIgnoreBLOCKA )
1186 1 : continue;
1187 :
1188 : /* We do no longer use CPLParseNameValue() as it removes leading spaces */
1189 : /* from the value (see #3088) */
1190 18 : pszSpace = strchr(papszOptions[iOption]+nTREPrefixLen, '=');
1191 18 : if (pszSpace == NULL)
1192 : {
1193 1 : CPLError(CE_Failure, CPLE_AppDefined,
1194 : "Could not parse creation options %s", papszOptions[iOption]+nTREPrefixLen);
1195 1 : return FALSE;
1196 : }
1197 :
1198 17 : pszTREName = CPLStrdup(papszOptions[iOption]+nTREPrefixLen);
1199 17 : pszTREName[pszSpace - (papszOptions[iOption]+nTREPrefixLen)] = '\0';
1200 17 : pszEscapedContents = pszSpace + 1;
1201 :
1202 17 : pszUnescapedContents =
1203 : CPLUnescapeString( pszEscapedContents, &nContentLength,
1204 : CPLES_BackslashQuotable );
1205 :
1206 17 : if( !NITFWriteTRE( fp,
1207 : nOffsetUDIDL, nOffsetTRE,
1208 : pnOffset,
1209 : pszTREName, pszUnescapedContents,
1210 : nContentLength ) )
1211 : {
1212 2 : CPLFree( pszTREName );
1213 2 : CPLFree( pszUnescapedContents );
1214 2 : return FALSE;
1215 : }
1216 :
1217 15 : CPLFree( pszTREName );
1218 15 : CPLFree( pszUnescapedContents );
1219 :
1220 : }
1221 :
1222 13 : return TRUE;
1223 : }
1224 :
1225 : /************************************************************************/
1226 : /* NITFWriteBLOCKA() */
1227 : /************************************************************************/
1228 :
1229 : static int NITFWriteBLOCKA( FILE* fp, vsi_l_offset nOffsetUDIDL,
1230 : vsi_l_offset nOffsetTRE,
1231 : int *pnOffset,
1232 : char **papszOptions )
1233 :
1234 3 : {
1235 : static const char *apszFields[] = {
1236 : "BLOCK_INSTANCE", "0", "2",
1237 : "N_GRAY", "2", "5",
1238 : "L_LINES", "7", "5",
1239 : "LAYOVER_ANGLE", "12", "3",
1240 : "SHADOW_ANGLE", "15", "3",
1241 : "BLANKS", "18", "16",
1242 : "FRLC_LOC", "34", "21",
1243 : "LRLC_LOC", "55", "21",
1244 : "LRFC_LOC", "76", "21",
1245 : "FRFC_LOC", "97", "21",
1246 : NULL, NULL, NULL };
1247 : int nBlockCount =
1248 3 : atoi(CSLFetchNameValue( papszOptions, "BLOCKA_BLOCK_COUNT" ));
1249 : int iBlock;
1250 :
1251 : /* ==================================================================== */
1252 : /* Loop over all the blocks we have metadata for. */
1253 : /* ==================================================================== */
1254 5 : for( iBlock = 1; iBlock <= nBlockCount; iBlock++ )
1255 : {
1256 : char szBLOCKA[123];
1257 : int iField;
1258 :
1259 : /* -------------------------------------------------------------------- */
1260 : /* Write all fields. */
1261 : /* -------------------------------------------------------------------- */
1262 32 : for( iField = 0; apszFields[iField*3] != NULL; iField++ )
1263 : {
1264 : char szFullFieldName[64];
1265 30 : int iStart = atoi(apszFields[iField*3+1]);
1266 30 : int iSize = atoi(apszFields[iField*3+2]);
1267 : const char *pszValue;
1268 :
1269 30 : sprintf( szFullFieldName, "BLOCKA_%s_%02d",
1270 : apszFields[iField*3 + 0], iBlock );
1271 :
1272 30 : pszValue = CSLFetchNameValue( papszOptions, szFullFieldName );
1273 30 : if( pszValue == NULL )
1274 14 : pszValue = "";
1275 :
1276 30 : if (strlen(pszValue) > (size_t)iSize)
1277 : {
1278 1 : CPLError(CE_Failure, CPLE_AppDefined,
1279 : "Too much data for %s. Got %d bytes, max allowed is %d",
1280 : szFullFieldName, (int)strlen(pszValue), iSize);
1281 1 : return FALSE;
1282 : }
1283 :
1284 : /* Right align value and left pad with spaces */
1285 29 : memset( szBLOCKA + iStart, ' ', iSize );
1286 29 : memcpy( szBLOCKA + iStart + MAX((size_t)0,iSize-strlen(pszValue)),
1287 : pszValue, strlen(pszValue) );
1288 : }
1289 :
1290 : // required field - semantics unknown.
1291 2 : memcpy( szBLOCKA + 118, "010.0", 5);
1292 :
1293 2 : if( !NITFWriteTRE( fp,
1294 : nOffsetUDIDL, nOffsetTRE,
1295 : pnOffset,
1296 : "BLOCKA", szBLOCKA, 123 ) )
1297 0 : return FALSE;
1298 : }
1299 :
1300 2 : return TRUE;
1301 : }
1302 :
1303 : /************************************************************************/
1304 : /* NITFCollectSegmentInfo() */
1305 : /* */
1306 : /* Collect the information about a set of segments of a */
1307 : /* particular type from the NITF file header, and add them to */
1308 : /* the segment list in the NITFFile object. */
1309 : /************************************************************************/
1310 :
1311 : static int
1312 : NITFCollectSegmentInfo( NITFFile *psFile, int nFileHeaderLen, int nOffset, const char szType[3],
1313 : int nHeaderLenSize, int nDataLenSize, GUIntBig *pnNextData )
1314 :
1315 3226 : {
1316 : char szTemp[12];
1317 : int nCount, nSegDefSize, iSegment;
1318 :
1319 : /* -------------------------------------------------------------------- */
1320 : /* Get the segment count, and grow the segmentinfo array */
1321 : /* accordingly. */
1322 : /* -------------------------------------------------------------------- */
1323 3226 : if ( nFileHeaderLen < nOffset + 3 )
1324 : {
1325 1 : CPLError(CE_Failure, CPLE_AppDefined, "Not enough bytes to read segment count");
1326 1 : return -1;
1327 : }
1328 :
1329 3225 : NITFGetField( szTemp, psFile->pachHeader, nOffset, 3 );
1330 3225 : nCount = atoi(szTemp);
1331 :
1332 3225 : if( nCount <= 0 )
1333 2635 : return nOffset + 3;
1334 :
1335 590 : nSegDefSize = nCount * (nHeaderLenSize + nDataLenSize);
1336 590 : if ( nFileHeaderLen < nOffset + 3 + nSegDefSize)
1337 : {
1338 1 : CPLError(CE_Failure, CPLE_AppDefined, "Not enough bytes to read segment info");
1339 1 : return -1;
1340 : }
1341 :
1342 589 : if( psFile->pasSegmentInfo == NULL )
1343 539 : psFile->pasSegmentInfo = (NITFSegmentInfo *)
1344 : CPLMalloc( sizeof(NITFSegmentInfo) * nCount );
1345 : else
1346 50 : psFile->pasSegmentInfo = (NITFSegmentInfo *)
1347 : CPLRealloc( psFile->pasSegmentInfo,
1348 : sizeof(NITFSegmentInfo)
1349 : * (psFile->nSegmentCount+nCount) );
1350 :
1351 : /* -------------------------------------------------------------------- */
1352 : /* Collect detailed about segment. */
1353 : /* -------------------------------------------------------------------- */
1354 6870 : for( iSegment = 0; iSegment < nCount; iSegment++ )
1355 : {
1356 6283 : NITFSegmentInfo *psInfo = psFile->pasSegmentInfo+psFile->nSegmentCount;
1357 :
1358 6283 : psInfo->nDLVL = -1;
1359 6283 : psInfo->nALVL = -1;
1360 6283 : psInfo->nLOC_R = -1;
1361 6283 : psInfo->nLOC_C = -1;
1362 6283 : psInfo->nCCS_R = -1;
1363 6283 : psInfo->nCCS_C = -1;
1364 :
1365 6283 : psInfo->hAccess = NULL;
1366 6283 : strcpy( psInfo->szSegmentType, szType );
1367 :
1368 6283 : psInfo->nSegmentHeaderSize =
1369 : atoi(NITFGetField(szTemp, psFile->pachHeader,
1370 : nOffset + 3 + iSegment * (nHeaderLenSize+nDataLenSize),
1371 : nHeaderLenSize));
1372 6283 : if (strchr(szTemp, '-') != NULL) /* Avoid negative values being mapped to huge unsigned values */
1373 : {
1374 1 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid segment header size : %s", szTemp);
1375 1 : return -1;
1376 : }
1377 :
1378 6282 : if (strcmp(szType, "DE") == 0 && psInfo->nSegmentHeaderSize == 207)
1379 : {
1380 : /* DMAAC A.TOC files have a wrong header size. It says 207 but it is 209 really */
1381 0 : psInfo->nSegmentHeaderSize = 209;
1382 : }
1383 :
1384 6282 : psInfo->nSegmentSize =
1385 : CPLScanUIntBig(NITFGetField(szTemp,psFile->pachHeader,
1386 : nOffset + 3 + iSegment * (nHeaderLenSize+nDataLenSize)
1387 : + nHeaderLenSize,
1388 : nDataLenSize), nDataLenSize);
1389 6282 : if (strchr(szTemp, '-') != NULL) /* Avoid negative values being mapped to huge unsigned values */
1390 : {
1391 1 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid segment size : %s", szTemp);
1392 1 : return -1;
1393 : }
1394 :
1395 6281 : psInfo->nSegmentHeaderStart = *pnNextData;
1396 6281 : psInfo->nSegmentStart = *pnNextData + psInfo->nSegmentHeaderSize;
1397 :
1398 6281 : *pnNextData += (psInfo->nSegmentHeaderSize+psInfo->nSegmentSize);
1399 6281 : psFile->nSegmentCount++;
1400 : }
1401 :
1402 587 : return nOffset + nSegDefSize + 3;
1403 : }
1404 :
1405 : /************************************************************************/
1406 : /* NITFGetField() */
1407 : /* */
1408 : /* Copy a field from a passed in header buffer into a temporary */
1409 : /* buffer and zero terminate it. */
1410 : /************************************************************************/
1411 :
1412 : char *NITFGetField( char *pszTarget, const char *pszSource,
1413 : int nStart, int nLength )
1414 :
1415 798825 : {
1416 798825 : memcpy( pszTarget, pszSource + nStart, nLength );
1417 798825 : pszTarget[nLength] = '\0';
1418 :
1419 798825 : return pszTarget;
1420 : }
1421 :
1422 : /************************************************************************/
1423 : /* NITFFindTRE() */
1424 : /************************************************************************/
1425 :
1426 : const char *NITFFindTRE( const char *pszTREData, int nTREBytes,
1427 : const char *pszTag, int *pnFoundTRESize )
1428 :
1429 18150 : {
1430 : char szTemp[100];
1431 :
1432 73487 : while( nTREBytes >= 11 )
1433 : {
1434 37292 : int nThisTRESize = atoi(NITFGetField(szTemp, pszTREData, 6, 5 ));
1435 37292 : if (nThisTRESize < 0)
1436 : {
1437 20 : NITFGetField(szTemp, pszTREData, 0, 6 );
1438 20 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid size (%d) for TRE %s",
1439 : nThisTRESize, szTemp);
1440 20 : return NULL;
1441 : }
1442 37272 : if (nTREBytes - 11 < nThisTRESize)
1443 : {
1444 20 : NITFGetField(szTemp, pszTREData, 0, 6 );
1445 20 : CPLError(CE_Failure, CPLE_AppDefined,
1446 : "Cannot read %s TRE. Not enough bytes : remaining %d, expected %d",
1447 : szTemp, nTREBytes - 11, nThisTRESize);
1448 20 : return NULL;
1449 : }
1450 :
1451 37252 : if( EQUALN(pszTREData,pszTag,6) )
1452 : {
1453 65 : if( pnFoundTRESize != NULL )
1454 65 : *pnFoundTRESize = nThisTRESize;
1455 :
1456 65 : return pszTREData + 11;
1457 : }
1458 :
1459 37187 : nTREBytes -= (nThisTRESize + 11);
1460 37187 : pszTREData += (nThisTRESize + 11);
1461 : }
1462 :
1463 18045 : return NULL;
1464 : }
1465 :
1466 : /************************************************************************/
1467 : /* NITFFindTREByIndex() */
1468 : /************************************************************************/
1469 :
1470 : const char *NITFFindTREByIndex( const char *pszTREData, int nTREBytes,
1471 : const char *pszTag, int nTreIndex,
1472 : int *pnFoundTRESize )
1473 :
1474 520 : {
1475 : char szTemp[100];
1476 :
1477 1123 : while( nTREBytes >= 11 )
1478 : {
1479 101 : int nThisTRESize = atoi(NITFGetField(szTemp, pszTREData, 6, 5 ));
1480 101 : if (nThisTRESize < 0)
1481 : {
1482 2 : NITFGetField(szTemp, pszTREData, 0, 6 );
1483 2 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid size (%d) for TRE %s",
1484 : nThisTRESize, szTemp);
1485 2 : return NULL;
1486 : }
1487 99 : if (nTREBytes - 11 < nThisTRESize)
1488 : {
1489 2 : NITFGetField(szTemp, pszTREData, 0, 6 );
1490 2 : CPLError(CE_Failure, CPLE_AppDefined,
1491 : "Cannot read %s TRE. Not enough bytes : remaining %d, expected %d",
1492 : szTemp, nTREBytes - 11, nThisTRESize);
1493 2 : return NULL;
1494 : }
1495 :
1496 97 : if( EQUALN(pszTREData,pszTag,6) )
1497 : {
1498 28 : if ( nTreIndex <= 0)
1499 : {
1500 14 : if( pnFoundTRESize != NULL )
1501 14 : *pnFoundTRESize = nThisTRESize;
1502 :
1503 14 : return pszTREData + 11;
1504 : }
1505 :
1506 : /* Found a prevoius one - skip it ... */
1507 14 : nTreIndex--;
1508 : }
1509 :
1510 83 : nTREBytes -= (nThisTRESize + 11);
1511 83 : pszTREData += (nThisTRESize + 11);
1512 : }
1513 :
1514 502 : return NULL;
1515 : }
1516 :
1517 : /************************************************************************/
1518 : /* NITFExtractMetadata() */
1519 : /************************************************************************/
1520 :
1521 : void NITFExtractMetadata( char ***ppapszMetadata, const char *pachHeader,
1522 : int nStart, int nLength, const char *pszName )
1523 :
1524 137256 : {
1525 : char szWork[400];
1526 :
1527 : /* trim white space */
1528 1840757 : while( nLength > 0 && pachHeader[nStart + nLength - 1] == ' ' )
1529 1566245 : nLength--;
1530 :
1531 137256 : memcpy( szWork, pachHeader + nStart, nLength );
1532 137256 : szWork[nLength] = '\0';
1533 :
1534 137256 : *ppapszMetadata = CSLSetNameValue( *ppapszMetadata, pszName, szWork );
1535 137256 : }
1536 :
1537 : /************************************************************************/
1538 : /* NITF_WGS84_Geocentric_Latitude_To_Geodetic_Latitude() */
1539 : /* */
1540 : /* The input is a geocentric latitude in degrees. The output */
1541 : /* is a geodetic latitude in degrees. */
1542 : /************************************************************************/
1543 :
1544 : /*
1545 : * "The angle L' is called "geocentric latitude" and is defined as the
1546 : * angle between the equatorial plane and the radius from the geocenter.
1547 : *
1548 : * The angle L is called "geodetic latitude" and is defined as the angle
1549 : * between the equatorial plane and the normal to the surface of the
1550 : * ellipsoid. The word "latitude" usually means geodetic latitude. This
1551 : * is the basis for most of the maps and charts we use. The normal to the
1552 : * surface is the direction that a plumb bob would hang were it not for
1553 : * local anomalies in the earth's gravitational field."
1554 : */
1555 :
1556 : double NITF_WGS84_Geocentric_Latitude_To_Geodetic_Latitude( double dfLat )
1557 :
1558 0 : {
1559 : /* WGS84 Ellipsoid */
1560 0 : double a = 6378137.0;
1561 0 : double b = 6356752.3142;
1562 0 : double dfPI = 3.14159265358979323;
1563 :
1564 : /* convert to radians */
1565 0 : dfLat = dfLat * dfPI / 180.0;
1566 :
1567 : /* convert to geodetic */
1568 0 : dfLat = atan( ((a*a)/(b*b)) * tan(dfLat) );
1569 :
1570 : /* convert back to degrees */
1571 0 : dfLat = dfLat * 180.0 / dfPI;
1572 :
1573 0 : return dfLat;
1574 : }
1575 :
1576 :
1577 : /************************************************************************/
1578 : /* NITFGetSeriesInfo() */
1579 : /************************************************************************/
1580 :
1581 : static const NITFSeries nitfSeries[] =
1582 : {
1583 : { "GN", "GNC", "1:5M", "Global Navigation Chart", "CADRG"},
1584 : { "JN", "JNC", "1:2M", "Jet Navigation Chart", "CADRG"},
1585 : { "OH", "VHRC", "1:1M", "VFR Helicopter Route Chart", "CADRG"},
1586 : { "ON", "ONC", "1:1M", "Operational Navigation Chart", "CADRG"},
1587 : { "OW", "WAC", "1:1M", "High Flying Chart - Host Nation", "CADRG"},
1588 : { "TP", "TPC", "1:500K", "Tactical Pilotage Chart", "CADRG"},
1589 : { "LF", "LFC-FR (Day)", "1:500K", "Low Flying Chart (Day) - Host Nation", "CADRG"},
1590 : { "L1", "LFC-1", "1:500K", "Low Flying Chart (TED #1)", "CADRG"},
1591 : { "L2", "LFC-2", "1:500K", "Low Flying Chart (TED #2)", "CADRG"},
1592 : { "L3", "LFC-3", "1:500K", "Low Flying Chart (TED #3)", "CADRG"},
1593 : { "L4", "LFC-4", "1:500K", "Low Flying Chart (TED #4)", "CADRG"},
1594 : { "L5", "LFC-5", "1:500K", "Low Flying Chart (TED #5)", "CADRG"},
1595 : { "LN", "LN (Night)", "1:500K", "Low Flying Chart (Night) - Host Nation", "CADRG"},
1596 : { "JG", "JOG", "1:250K", "Joint Operation Graphic", "CADRG"},
1597 : { "JA", "JOG-A", "1:250K", "Joint Operation Graphic - Air", "CADRG"},
1598 : { "JR", "JOG-R", "1:250K", "Joint Operation Graphic - Radar", "CADRG"},
1599 : { "JO", "OPG", "1:250K", "Operational Planning Graphic", "CADRG"},
1600 : { "VT", "VTAC", "1:250K", "VFR Terminal Area Chart", "CADRG"},
1601 : { "F1", "TFC-1", "1:250K", "Transit Flying Chart (TED #1)", "CADRG"},
1602 : { "F2", "TFC-2", "1:250K", "Transit Flying Chart (TED #2)", "CADRG"},
1603 : { "F3", "TFC-3", "1:250K", "Transit Flying Chart (TED #3)", "CADRG"},
1604 : { "F4", "TFC-4", "1:250K", "Transit Flying Chart (TED #4)", "CADRG"},
1605 : { "F5", "TFC-5", "1:250K", "Transit Flying Chart (TED #5)", "CADRG"},
1606 : { "AT", "ATC", "1:200K", "Series 200 Air Target Chart", "CADRG"},
1607 : { "VH", "HRC", "1:125K", "Helicopter Route Chart", "CADRG"},
1608 : { "TN", "TFC (Night)", "1:250K", "Transit Flying Charget (Night) - Host Nation", "CADRG"},
1609 : { "TR", "TLM 200", "1:200K", "Topographic Line Map 1:200,000 scale", "CADRG"},
1610 : { "TC", "TLM 100", "1:100K", "Topographic Line Map 1:100,000 scale", "CADRG"},
1611 : { "RV", "Riverine", "1:50K", "Riverine Map 1:50,000 scale", "CADRG"},
1612 : { "TL", "TLM 50", "1:50K", "Topographic Line Map 1:50,000 scale", "CADRG"},
1613 : { "UL", "TLM 50 - Other", "1:50K", "Topographic Line Map (other 1:50,000 scale)", "CADRG"},
1614 : { "TT", "TLM 25", "1:25K", "Topographic Line Map 1:25,000 scale", "CADRG"},
1615 : { "TQ", "TLM 24", "1:24K", "Topographic Line Map 1:24,000 scale", "CADRG"},
1616 : { "HA", "HA", "Various", "Harbor and Approach Charts", "CADRG"},
1617 : { "CO", "CO", "Various", "Coastal Charts", "CADRG"},
1618 : { "OA", "OPAREA", "Various", "Naval Range Operation Area Chart", "CADRG"},
1619 : { "CG", "CG", "Various", "City Graphics", "CADRG"},
1620 : { "C1", "CG", "1:10000", "City Graphics", "CADRG"},
1621 : { "C2", "CG", "1:10560", "City Graphics", "CADRG"},
1622 : { "C3", "CG", "1:11000", "City Graphics", "CADRG"},
1623 : { "C4", "CG", "1:11800", "City Graphics", "CADRG"},
1624 : { "C5", "CG", "1:12000", "City Graphics", "CADRG"},
1625 : { "C6", "CG", "1:12500", "City Graphics", "CADRG"},
1626 : { "C7", "CG", "1:12800", "City Graphics", "CADRG"},
1627 : { "C8", "CG", "1:14000", "City Graphics", "CADRG"},
1628 : { "C9", "CG", "1:14700", "City Graphics", "CADRG"},
1629 : { "CA", "CG", "1:15000", "City Graphics", "CADRG"},
1630 : { "CB", "CG", "1:15500", "City Graphics", "CADRG"},
1631 : { "CC", "CG", "1:16000", "City Graphics", "CADRG"},
1632 : { "CD", "CG", "1:16666", "City Graphics", "CADRG"},
1633 : { "CE", "CG", "1:17000", "City Graphics", "CADRG"},
1634 : { "CF", "CG", "1:17500", "City Graphics", "CADRG"},
1635 : { "CH", "CG", "1:18000", "City Graphics", "CADRG"},
1636 : { "CJ", "CG", "1:20000", "City Graphics", "CADRG"},
1637 : { "CK", "CG", "1:21000", "City Graphics", "CADRG"},
1638 : { "CL", "CG", "1:21120", "City Graphics", "CADRG"},
1639 : { "CN", "CG", "1:22000", "City Graphics", "CADRG"},
1640 : { "CP", "CG", "1:23000", "City Graphics", "CADRG"},
1641 : { "CQ", "CG", "1:25000", "City Graphics", "CADRG"},
1642 : { "CR", "CG", "1:26000", "City Graphics", "CADRG"},
1643 : { "CS", "CG", "1:35000", "City Graphics", "CADRG"},
1644 : { "CT", "CG", "1:36000", "City Graphics", "CADRG"},
1645 : { "CM", "CM", "Various", "Combat Charts", "CADRG"},
1646 : { "A1", "CM", "1:10K", "Combat Charts (1:10K)", "CADRG"},
1647 : { "A2", "CM", "1:25K", "Combat Charts (1:25K)", "CADRG"},
1648 : { "A3", "CM", "1:50K", "Combat Charts (1:50K)", "CADRG"},
1649 : { "A4", "CM", "1:100K", "Combat Charts (1:100K)", "CADRG"},
1650 : { "MI", "MIM", "1:50K", "Military Installation Maps", "CADRG"},
1651 : { "M1", "MIM", "Various", "Military Installation Maps (TED #1)", "CADRG"},
1652 : { "M2", "MIM", "Various", "Military Installation Maps (TED #2)", "CADRG"},
1653 : { "VN", "VNC", "1:500K", "Visual Navigation Charts", "CADRG"},
1654 : { "MM", "", "Various", "(Miscellaneous Maps & Charts)", "CADRG"},
1655 :
1656 : { "I1", "", "10m", "Imagery, 10 meter resolution", "CIB"},
1657 : { "I2", "", "5m", "Imagery, 5 meter resolution", "CIB"},
1658 : { "I3", "", "2m", "Imagery, 2 meter resolution", "CIB"},
1659 : { "I4", "", "1m", "Imagery, 1 meter resolution", "CIB"},
1660 : { "I5", "", ".5m", "Imagery, .5 (half) meter resolution", "CIB"},
1661 : { "IV", "", "Various > 10m", "Imagery, greater than 10 meter resolution", "CIB"},
1662 :
1663 : { "D1", "", "100m", "Elevation Data from DTED level 1", "CDTED"},
1664 : { "D2", "", "30m", "Elevation Data from DTED level 2", "CDTED"},
1665 : };
1666 :
1667 : /* See 24111CN1.pdf paragraph 5.1.4 */
1668 : const NITFSeries* NITFGetSeriesInfo(const char* pszFilename)
1669 517 : {
1670 : int i;
1671 517 : char seriesCode[3] = {0,0,0};
1672 517 : if (pszFilename == NULL) return NULL;
1673 3363 : for (i=strlen(pszFilename)-1;i>=0;i--)
1674 : {
1675 3313 : if (pszFilename[i] == '.')
1676 : {
1677 472 : if (i < (int)strlen(pszFilename) - 3)
1678 : {
1679 467 : seriesCode[0] = pszFilename[i+1];
1680 467 : seriesCode[1] = pszFilename[i+2];
1681 35511 : for(i=0;i<sizeof(nitfSeries) / sizeof(nitfSeries[0]); i++)
1682 : {
1683 35074 : if (EQUAL(seriesCode, nitfSeries[i].code))
1684 : {
1685 30 : return &nitfSeries[i];
1686 : }
1687 : }
1688 437 : return NULL;
1689 : }
1690 : }
1691 : }
1692 50 : return NULL;
1693 : }
1694 :
1695 : /************************************************************************/
1696 : /* NITFCollectAttachments() */
1697 : /* */
1698 : /* Collect attachment, display level and location info into the */
1699 : /* segmentinfo structures. */
1700 : /************************************************************************/
1701 :
1702 : int NITFCollectAttachments( NITFFile *psFile )
1703 :
1704 376 : {
1705 : int iSegment;
1706 :
1707 : /* ==================================================================== */
1708 : /* Loop over all segments. */
1709 : /* ==================================================================== */
1710 5476 : for( iSegment = 0; iSegment < psFile->nSegmentCount; iSegment++ )
1711 : {
1712 5119 : NITFSegmentInfo *psSegInfo = psFile->pasSegmentInfo + iSegment;
1713 :
1714 : /* -------------------------------------------------------------------- */
1715 : /* For image segments, we use the normal image access stuff. */
1716 : /* -------------------------------------------------------------------- */
1717 5119 : if( EQUAL(psSegInfo->szSegmentType,"IM") )
1718 : {
1719 4401 : NITFImage *psImage = NITFImageAccess( psFile, iSegment );
1720 4401 : if (psImage == NULL)
1721 19 : return FALSE;
1722 :
1723 4382 : psSegInfo->nDLVL = psImage->nIDLVL;
1724 4382 : psSegInfo->nALVL = psImage->nIALVL;
1725 4382 : psSegInfo->nLOC_R = psImage->nILOCRow;
1726 4382 : psSegInfo->nLOC_C = psImage->nILOCColumn;
1727 : }
1728 : /* -------------------------------------------------------------------- */
1729 : /* For graphic file we need to process the header. */
1730 : /* -------------------------------------------------------------------- */
1731 718 : else if( EQUAL(psSegInfo->szSegmentType,"SY")
1732 : || EQUAL(psSegInfo->szSegmentType,"GR") )
1733 : {
1734 : char achSubheader[298];
1735 : int nSTYPEOffset;
1736 : char szTemp[100];
1737 :
1738 : /* -------------------------------------------------------------------- */
1739 : /* Load the graphic subheader. */
1740 : /* -------------------------------------------------------------------- */
1741 361 : if( VSIFSeekL( psFile->fp, psSegInfo->nSegmentHeaderStart,
1742 : SEEK_SET ) != 0
1743 : || VSIFReadL( achSubheader, 1, sizeof(achSubheader),
1744 : psFile->fp ) < 258 )
1745 : {
1746 1 : CPLError( CE_Warning, CPLE_FileIO,
1747 : "Failed to read graphic subheader at " CPL_FRMT_GUIB ".",
1748 : psSegInfo->nSegmentHeaderStart );
1749 1 : continue;
1750 : }
1751 :
1752 : // NITF 2.0. (also works for NITF 2.1)
1753 360 : nSTYPEOffset = 200;
1754 360 : if( EQUALN(achSubheader+193,"999998",6) )
1755 318 : nSTYPEOffset += 40;
1756 :
1757 : /* -------------------------------------------------------------------- */
1758 : /* Report some standard info. */
1759 : /* -------------------------------------------------------------------- */
1760 360 : psSegInfo->nDLVL = atoi(NITFGetField(szTemp,achSubheader,
1761 : nSTYPEOffset + 14, 3));
1762 360 : psSegInfo->nALVL = atoi(NITFGetField(szTemp,achSubheader,
1763 : nSTYPEOffset + 17, 3));
1764 360 : psSegInfo->nLOC_R = atoi(NITFGetField(szTemp,achSubheader,
1765 : nSTYPEOffset + 20, 5));
1766 360 : psSegInfo->nLOC_C = atoi(NITFGetField(szTemp,achSubheader,
1767 : nSTYPEOffset + 25, 5));
1768 : }
1769 : }
1770 :
1771 357 : return TRUE;
1772 : }
1773 :
1774 : /************************************************************************/
1775 : /* NITFReconcileAttachments() */
1776 : /* */
1777 : /* Generate the CCS location information for all the segments */
1778 : /* if possible. */
1779 : /************************************************************************/
1780 :
1781 : int NITFReconcileAttachments( NITFFile *psFile )
1782 :
1783 384 : {
1784 : int iSegment;
1785 384 : int bSuccess = TRUE;
1786 384 : int bMadeProgress = FALSE;
1787 :
1788 5615 : for( iSegment = 0; iSegment < psFile->nSegmentCount; iSegment++ )
1789 : {
1790 5231 : NITFSegmentInfo *psSegInfo = psFile->pasSegmentInfo + iSegment;
1791 : int iOther;
1792 :
1793 : // already processed?
1794 5231 : if( psSegInfo->nCCS_R != -1 )
1795 48 : continue;
1796 :
1797 : // unattached segments are straight forward.
1798 5183 : if( psSegInfo->nALVL < 1 )
1799 : {
1800 5020 : psSegInfo->nCCS_R = psSegInfo->nLOC_R;
1801 5020 : psSegInfo->nCCS_C = psSegInfo->nLOC_C;
1802 5020 : if( psSegInfo->nCCS_R != -1 )
1803 4603 : bMadeProgress = TRUE;
1804 5020 : continue;
1805 : }
1806 :
1807 : // Loc for segment to which we are attached.
1808 610 : for( iOther = 0; iOther < psFile->nSegmentCount; iOther++ )
1809 : {
1810 586 : NITFSegmentInfo *psOtherSegInfo = psFile->pasSegmentInfo + iOther;
1811 :
1812 586 : if( psSegInfo->nALVL == psOtherSegInfo->nDLVL )
1813 : {
1814 139 : if( psOtherSegInfo->nCCS_R != -1 )
1815 : {
1816 131 : psSegInfo->nCCS_R = psOtherSegInfo->nLOC_R + psSegInfo->nLOC_R;
1817 131 : psSegInfo->nCCS_C = psOtherSegInfo->nLOC_C + psSegInfo->nLOC_C;
1818 131 : if ( psSegInfo->nCCS_R != -1 )
1819 131 : bMadeProgress = TRUE;
1820 : }
1821 : else
1822 : {
1823 8 : bSuccess = FALSE;
1824 : }
1825 139 : break;
1826 : }
1827 : }
1828 :
1829 163 : if( iOther == psFile->nSegmentCount )
1830 24 : bSuccess = FALSE;
1831 : }
1832 :
1833 : /* -------------------------------------------------------------------- */
1834 : /* If succeeded or made no progress then return our success */
1835 : /* flag. Otherwise make another pass, hopefully filling in */
1836 : /* more values. */
1837 : /* -------------------------------------------------------------------- */
1838 384 : if( bSuccess || !bMadeProgress )
1839 376 : return bSuccess;
1840 : else
1841 8 : return NITFReconcileAttachments( psFile );
1842 : }
|