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