1 : /******************************************************************************
2 : * $Id: nitfdes.c 19385 2010-04-11 18:05:19Z rouault $
3 : *
4 : * Project: NITF Read/Write Library
5 : * Purpose: Module responsible for implementation of DE segments.
6 : * Author: Even Rouault, <even dot rouault at mines dash paris dot org>
7 : *
8 : **********************************************************************
9 : * Copyright (c) 2010, Even Rouault <even dot rouault at mines dash paris dot org>
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #include "gdal.h"
31 : #include "nitflib.h"
32 : #include "cpl_vsi.h"
33 : #include "cpl_conv.h"
34 : #include "cpl_string.h"
35 :
36 : CPL_CVSID("$Id: nitfdes.c 19385 2010-04-11 18:05:19Z rouault $");
37 :
38 : /************************************************************************/
39 : /* NITFDESAccess() */
40 : /************************************************************************/
41 :
42 : NITFDES *NITFDESAccess( NITFFile *psFile, int iSegment )
43 :
44 1 : {
45 : NITFDES *psDES;
46 : char *pachHeader;
47 : NITFSegmentInfo *psSegInfo;
48 : char szDESID[26];
49 : char szTemp[128];
50 : int nOffset;
51 : int bHasDESOFLW;
52 : int nDESSHL;
53 :
54 : /* -------------------------------------------------------------------- */
55 : /* Verify segment, and return existing DES accessor if there */
56 : /* is one. */
57 : /* -------------------------------------------------------------------- */
58 1 : if( iSegment < 0 || iSegment >= psFile->nSegmentCount )
59 0 : return NULL;
60 :
61 1 : psSegInfo = psFile->pasSegmentInfo + iSegment;
62 :
63 1 : if( !EQUAL(psSegInfo->szSegmentType,"DE") )
64 0 : return NULL;
65 :
66 1 : if( psSegInfo->hAccess != NULL )
67 0 : return (NITFDES *) psSegInfo->hAccess;
68 :
69 : /* -------------------------------------------------------------------- */
70 : /* Read the DES subheader. */
71 : /* -------------------------------------------------------------------- */
72 1 : if (psSegInfo->nSegmentHeaderSize < 200)
73 : {
74 0 : CPLError(CE_Failure, CPLE_AppDefined,
75 : "DES header too small");
76 0 : return NULL;
77 : }
78 :
79 1 : pachHeader = (char*) VSIMalloc(psSegInfo->nSegmentHeaderSize);
80 1 : if (pachHeader == NULL)
81 : {
82 0 : CPLError(CE_Failure, CPLE_OutOfMemory,
83 : "Cannot allocate memory for segment header");
84 0 : return NULL;
85 : }
86 :
87 1 : retry:
88 1 : if( VSIFSeekL( psFile->fp, psSegInfo->nSegmentHeaderStart,
89 : SEEK_SET ) != 0
90 : || VSIFReadL( pachHeader, 1, psSegInfo->nSegmentHeaderSize,
91 : psFile->fp ) != psSegInfo->nSegmentHeaderSize )
92 : {
93 0 : CPLError( CE_Failure, CPLE_FileIO,
94 : "Failed to read %u byte DES subheader from " CPL_FRMT_GUIB ".",
95 : psSegInfo->nSegmentHeaderSize,
96 : psSegInfo->nSegmentHeaderStart );
97 0 : CPLFree(pachHeader);
98 0 : return NULL;
99 : }
100 :
101 1 : if (!EQUALN(pachHeader, "DE", 2))
102 : {
103 0 : if (EQUALN(pachHeader + 4, "DERegistered", 12))
104 : {
105 : /* BAO_46_Ed1/rpf/conc/concz10/000fz010.ona and cie are buggy */
106 0 : CPLDebug("NITF", "Patching nSegmentHeaderStart and nSegmentStart for DE segment %d", iSegment);
107 0 : psSegInfo->nSegmentHeaderStart += 4;
108 0 : psSegInfo->nSegmentStart += 4;
109 0 : goto retry;
110 : }
111 :
112 0 : CPLError(CE_Failure, CPLE_AppDefined,
113 : "Invalid segment prefix for DE segment %d", iSegment);
114 :
115 0 : CPLFree(pachHeader);
116 0 : return NULL;
117 : }
118 :
119 : /* -------------------------------------------------------------------- */
120 : /* Initialize DES object. */
121 : /* -------------------------------------------------------------------- */
122 1 : psDES = (NITFDES *) CPLCalloc(sizeof(NITFDES),1);
123 :
124 1 : psDES->psFile = psFile;
125 1 : psDES->iSegment = iSegment;
126 1 : psDES->pachHeader = pachHeader;
127 :
128 1 : psSegInfo->hAccess = psDES;
129 :
130 : /* -------------------------------------------------------------------- */
131 : /* Collect a variety of information as metadata. */
132 : /* -------------------------------------------------------------------- */
133 : #define GetMD( length, name ) \
134 : do { NITFExtractMetadata( &(psDES->papszMetadata), pachHeader, \
135 : nOffset, length, \
136 : "NITF_" #name ); \
137 : nOffset += length; } while(0)
138 :
139 1 : nOffset = 2;
140 1 : GetMD( 25, DESID );
141 1 : GetMD( 2, DESVER );
142 1 : GetMD( 1, DECLAS );
143 1 : GetMD( 2, DESCLSY );
144 1 : GetMD( 11, DESCODE );
145 1 : GetMD( 2, DESCTLH );
146 1 : GetMD( 20, DESREL );
147 1 : GetMD( 2, DESDCTP );
148 1 : GetMD( 8, DESDCDT );
149 1 : GetMD( 4, DESDCXM );
150 1 : GetMD( 1, DESDG );
151 1 : GetMD( 8, DESDGDT );
152 1 : GetMD( 43, DESCLTX );
153 1 : GetMD( 1, DESCATP );
154 1 : GetMD( 40, DESCAUT );
155 1 : GetMD( 1, DESCRSN );
156 1 : GetMD( 8, DESSRDT );
157 1 : GetMD( 15, DESCTLN );
158 :
159 : /* Load DESID */
160 1 : NITFGetField( szDESID, pachHeader, 2, 25);
161 :
162 : /* For NITF < 02.10, we cannot rely on DESID=TRE_OVERFLOW to detect */
163 : /* if DESOFLW and DESITEM are present. So if the next 4 bytes are non */
164 : /* numeric, we'll assume that DESOFLW is there */
165 1 : bHasDESOFLW = EQUALN(szDESID, "TRE_OVERFLOW", strlen("TRE_OVERFLOW")) ||
166 : (!((pachHeader[nOffset+0] >= '0' && pachHeader[nOffset+0] <= '9') &&
167 : (pachHeader[nOffset+1] >= '0' && pachHeader[nOffset+1] <= '9') &&
168 : (pachHeader[nOffset+2] >= '0' && pachHeader[nOffset+2] <= '9') &&
169 : (pachHeader[nOffset+3] >= '0' && pachHeader[nOffset+3] <= '9')));
170 :
171 1 : if (bHasDESOFLW)
172 : {
173 1 : if ((int)psSegInfo->nSegmentHeaderSize < nOffset + 6 + 3 )
174 : {
175 0 : CPLError(CE_Failure, CPLE_AppDefined,
176 : "DES header too small");
177 0 : NITFDESDeaccess(psDES);
178 0 : return NULL;
179 : }
180 1 : GetMD( 6, DESOFLW );
181 1 : GetMD( 3, DESITEM );
182 : }
183 :
184 1 : if ((int)psSegInfo->nSegmentHeaderSize < nOffset + 4 )
185 : {
186 0 : CPLError(CE_Failure, CPLE_AppDefined,
187 : "DES header too small");
188 0 : NITFDESDeaccess(psDES);
189 0 : return NULL;
190 : }
191 :
192 1 : nDESSHL = atoi(NITFGetField( szTemp, pachHeader, nOffset, 4));
193 1 : nOffset += 4;
194 :
195 1 : if (nDESSHL < 0)
196 : {
197 0 : CPLError(CE_Failure, CPLE_AppDefined,
198 : "Invalid value for DESSHL");
199 0 : NITFDESDeaccess(psDES);
200 0 : return NULL;
201 : }
202 1 : if ( (int)psSegInfo->nSegmentHeaderSize < nOffset + nDESSHL)
203 : {
204 0 : CPLError(CE_Failure, CPLE_AppDefined,
205 : "DES header too small");
206 0 : NITFDESDeaccess(psDES);
207 0 : return NULL;
208 : }
209 :
210 1 : if (EQUALN(szDESID, "CSSHPA DES", strlen("CSSHPA DES")))
211 : {
212 0 : if ( nDESSHL != 62 && nDESSHL != 80)
213 : {
214 0 : CPLError(CE_Failure, CPLE_AppDefined,
215 : "Invalid DESSHL for CSSHPA DES");
216 0 : NITFDESDeaccess(psDES);
217 0 : return NULL;
218 : }
219 :
220 0 : GetMD( 25, SHAPE_USE );
221 0 : GetMD( 10, SHAPE_CLASS );
222 0 : if (nDESSHL == 80)
223 0 : GetMD( 18, CC_SOURCE );
224 0 : GetMD( 3, SHAPE1_NAME );
225 0 : GetMD( 6, SHAPE1_START );
226 0 : GetMD( 3, SHAPE2_NAME );
227 0 : GetMD( 6, SHAPE2_START );
228 0 : GetMD( 3, SHAPE3_NAME );
229 0 : GetMD( 6, SHAPE3_START );
230 : }
231 1 : else if (nDESSHL > 0)
232 0 : GetMD( nDESSHL, DESSHF );
233 :
234 1 : if ((int)psSegInfo->nSegmentHeaderSize > nOffset)
235 : {
236 : char* pszEscapedDESDATA =
237 : CPLEscapeString( pachHeader + nOffset,
238 : (int)psSegInfo->nSegmentHeaderSize - nOffset,
239 0 : CPLES_BackslashQuotable );
240 0 : psDES->papszMetadata = CSLSetNameValue( psDES->papszMetadata,
241 : "NITF_DESDATA",
242 : pszEscapedDESDATA );
243 0 : CPLFree(pszEscapedDESDATA);
244 : }
245 :
246 1 : return psDES;
247 : }
248 :
249 : /************************************************************************/
250 : /* NITFDESDeaccess() */
251 : /************************************************************************/
252 :
253 : void NITFDESDeaccess( NITFDES *psDES )
254 :
255 1 : {
256 1 : CPLAssert( psDES->psFile->pasSegmentInfo[psDES->iSegment].hAccess
257 : == psDES );
258 :
259 1 : psDES->psFile->pasSegmentInfo[psDES->iSegment].hAccess = NULL;
260 :
261 1 : CPLFree( psDES->pachHeader );
262 1 : CSLDestroy( psDES->papszMetadata );
263 :
264 1 : CPLFree( psDES );
265 1 : }
266 :
267 : /************************************************************************/
268 : /* NITFDESGetTRE() */
269 : /************************************************************************/
270 :
271 : /**
272 : * Return the TRE located at nOffset.
273 : *
274 : * @param psDES descriptor of the DE segment
275 : * @param nOffset offset of the TRE relative to the beginning of the segment data
276 : * @param szTREName will be filled with the TRE name
277 : * @param ppabyTREData will be allocated by the function and filled with the TRE content (in raw form)
278 : * @param pnFoundTRESize will be filled with the TRE size (excluding the first 11 bytes)
279 : * @return TRUE if a TRE was found
280 : */
281 :
282 : int NITFDESGetTRE( NITFDES* psDES,
283 : int nOffset,
284 : char szTREName[7],
285 : char** ppabyTREData,
286 : int* pnFoundTRESize)
287 5 : {
288 : char szTREHeader[12];
289 : char szTRETempName[7];
290 : NITFSegmentInfo* psSegInfo;
291 : FILE* fp;
292 : int nTRESize;
293 :
294 5 : memset(szTREName, '\0', 7);
295 5 : if (ppabyTREData)
296 5 : *ppabyTREData = NULL;
297 5 : if (pnFoundTRESize)
298 5 : *pnFoundTRESize = 0;
299 :
300 5 : if (nOffset < 0)
301 0 : return FALSE;
302 :
303 5 : if (psDES == NULL)
304 0 : return FALSE;
305 :
306 5 : if (CSLFetchNameValue(psDES->papszMetadata, "NITF_DESOFLW") == NULL)
307 0 : return FALSE;
308 :
309 5 : psSegInfo = psDES->psFile->pasSegmentInfo + psDES->iSegment;
310 5 : fp = psDES->psFile->fp;
311 :
312 5 : if (nOffset >= psSegInfo->nSegmentSize)
313 1 : return FALSE;
314 :
315 4 : VSIFSeekL(fp, psSegInfo->nSegmentStart + nOffset, SEEK_SET);
316 :
317 4 : if (VSIFReadL(szTREHeader, 1, 11, fp) != 11)
318 : {
319 : /* Some files have a nSegmentSize larger than what is is in reality */
320 : /* So exit silently if we're at end of file */
321 0 : VSIFSeekL(fp, 0, SEEK_END);
322 0 : if (VSIFTellL(fp) == psSegInfo->nSegmentStart + nOffset)
323 0 : return FALSE;
324 :
325 0 : CPLError(CE_Failure, CPLE_FileIO,
326 : "Cannot get 11 bytes at offset " CPL_FRMT_GUIB ".",
327 : psSegInfo->nSegmentStart + nOffset );
328 0 : return FALSE;
329 : }
330 4 : szTREHeader[11] = '\0';
331 :
332 4 : memcpy(szTRETempName, szTREHeader, 6);
333 4 : szTRETempName[6] = '\0';
334 :
335 4 : nTRESize = atoi(szTREHeader + 6);
336 4 : if (nTRESize < 0)
337 : {
338 0 : CPLError(CE_Failure, CPLE_AppDefined,
339 : "Invalid size (%d) for TRE %s",
340 : nTRESize, szTRETempName);
341 0 : return FALSE;
342 : }
343 4 : if (nOffset + 11 + nTRESize > psSegInfo->nSegmentSize)
344 : {
345 0 : CPLError(CE_Failure, CPLE_AppDefined,
346 : "Cannot read %s TRE. Not enough bytes : remaining %d, expected %d",
347 : szTRETempName,
348 : (int)(psSegInfo->nSegmentSize - (nOffset + 11)), nTRESize);
349 0 : return FALSE;
350 : }
351 :
352 4 : if (ppabyTREData)
353 : {
354 : /* Allocate one extra byte for the NULL terminating character */
355 4 : *ppabyTREData = (char*) VSIMalloc(nTRESize + 1);
356 4 : if (*ppabyTREData == NULL)
357 : {
358 0 : CPLError(CE_Failure, CPLE_OutOfMemory,
359 : "Cannot allocate %d bytes for TRE %s",
360 : nTRESize, szTRETempName);
361 0 : return FALSE;
362 : }
363 4 : (*ppabyTREData)[nTRESize] = '\0';
364 :
365 4 : if ((int)VSIFReadL(*ppabyTREData, 1, nTRESize, fp) != nTRESize)
366 : {
367 0 : CPLError(CE_Failure, CPLE_FileIO,
368 : "Cannot get %d bytes at offset " CPL_FRMT_GUIB ".",
369 : nTRESize, VSIFTellL(fp) );
370 0 : VSIFree(*ppabyTREData);
371 0 : *ppabyTREData = NULL;
372 0 : return FALSE;
373 : }
374 : }
375 :
376 4 : strcpy(szTREName, szTRETempName);
377 4 : if (pnFoundTRESize)
378 4 : *pnFoundTRESize = nTRESize;
379 :
380 4 : return TRUE;
381 : }
382 :
383 : /************************************************************************/
384 : /* NITFDESFreeTREData() */
385 : /************************************************************************/
386 :
387 : void NITFDESFreeTREData( char* pabyTREData )
388 4 : {
389 4 : VSIFree(pabyTREData);
390 4 : }
391 :
392 :
393 : /************************************************************************/
394 : /* NITFDESExtractShapefile() */
395 : /************************************************************************/
396 :
397 : int NITFDESExtractShapefile(NITFDES* psDES, const char* pszRadixFileName)
398 0 : {
399 : NITFSegmentInfo* psSegInfo;
400 : const char* apszExt[3];
401 : int anOffset[4];
402 : int iShpFile;
403 : char* pszFilename;
404 :
405 0 : if ( CSLFetchNameValue(psDES->papszMetadata, "NITF_SHAPE_USE") == NULL )
406 0 : return FALSE;
407 :
408 0 : psSegInfo = psDES->psFile->pasSegmentInfo + psDES->iSegment;
409 :
410 0 : apszExt[0] = CSLFetchNameValue(psDES->papszMetadata, "NITF_SHAPE1_NAME");
411 0 : anOffset[0] = atoi(CSLFetchNameValue(psDES->papszMetadata, "NITF_SHAPE1_START"));
412 0 : apszExt[1] = CSLFetchNameValue(psDES->papszMetadata, "NITF_SHAPE2_NAME");
413 0 : anOffset[1] = atoi(CSLFetchNameValue(psDES->papszMetadata, "NITF_SHAPE2_START"));
414 0 : apszExt[2] = CSLFetchNameValue(psDES->papszMetadata, "NITF_SHAPE3_NAME");
415 0 : anOffset[2] = atoi(CSLFetchNameValue(psDES->papszMetadata, "NITF_SHAPE3_START"));
416 0 : anOffset[3] = (int) psSegInfo->nSegmentSize;
417 :
418 0 : for(iShpFile = 0; iShpFile < 3; iShpFile ++)
419 : {
420 0 : if (!EQUAL(apszExt[iShpFile], "SHP") &&
421 : !EQUAL(apszExt[iShpFile], "SHX") &&
422 : !EQUAL(apszExt[iShpFile], "DBF"))
423 0 : return FALSE;
424 :
425 0 : if (anOffset[iShpFile] < 0 ||
426 : anOffset[iShpFile] >= anOffset[iShpFile+1])
427 0 : return FALSE;
428 : }
429 :
430 0 : pszFilename = (char*) VSIMalloc(strlen(pszRadixFileName) + 4 + 1);
431 0 : if (pszFilename == NULL)
432 0 : return FALSE;
433 :
434 0 : for(iShpFile = 0; iShpFile < 3; iShpFile ++)
435 : {
436 : FILE* fp;
437 : GByte* pabyBuffer;
438 0 : int nSize = anOffset[iShpFile+1] - anOffset[iShpFile];
439 :
440 0 : pabyBuffer = (GByte*) VSIMalloc(nSize);
441 0 : if (pabyBuffer == NULL)
442 : {
443 0 : VSIFree(pszFilename);
444 0 : return FALSE;
445 : }
446 :
447 0 : VSIFSeekL(psDES->psFile->fp, psSegInfo->nSegmentStart + anOffset[iShpFile], SEEK_SET);
448 0 : if (VSIFReadL(pabyBuffer, 1, nSize, psDES->psFile->fp) != nSize)
449 : {
450 0 : VSIFree(pabyBuffer);
451 0 : VSIFree(pszFilename);
452 0 : return FALSE;
453 : }
454 :
455 0 : sprintf(pszFilename, "%s.%s", pszRadixFileName, apszExt[iShpFile]);
456 0 : fp = VSIFOpenL(pszFilename, "wb");
457 0 : if (fp == NULL)
458 : {
459 0 : VSIFree(pabyBuffer);
460 0 : VSIFree(pszFilename);
461 0 : return FALSE;
462 : }
463 :
464 0 : VSIFWriteL(pabyBuffer, 1, nSize, fp);
465 0 : VSIFCloseL(fp);
466 0 : VSIFree(pabyBuffer);
467 : }
468 :
469 0 : VSIFree(pszFilename);
470 :
471 0 : return TRUE;
472 : }
|