1 : /******************************************************************************
2 : * $Id: nitfdes.c 23033 2011-09-03 18:46:11Z 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 23033 2011-09-03 18:46:11Z rouault $");
37 :
38 : /************************************************************************/
39 : /* NITFDESAccess() */
40 : /************************************************************************/
41 :
42 4 : NITFDES *NITFDESAccess( NITFFile *psFile, int iSegment )
43 :
44 : {
45 : NITFDES *psDES;
46 : char *pachHeader;
47 : NITFSegmentInfo *psSegInfo;
48 : char szDESID[26];
49 : int nOffset;
50 : int bHasDESOFLW;
51 : int nDESSHL;
52 :
53 : /* -------------------------------------------------------------------- */
54 : /* Verify segment, and return existing DES accessor if there */
55 : /* is one. */
56 : /* -------------------------------------------------------------------- */
57 4 : if( iSegment < 0 || iSegment >= psFile->nSegmentCount )
58 0 : return NULL;
59 :
60 4 : psSegInfo = psFile->pasSegmentInfo + iSegment;
61 :
62 4 : if( !EQUAL(psSegInfo->szSegmentType,"DE") )
63 0 : return NULL;
64 :
65 4 : if( psSegInfo->hAccess != NULL )
66 0 : return (NITFDES *) psSegInfo->hAccess;
67 :
68 : /* -------------------------------------------------------------------- */
69 : /* Read the DES subheader. */
70 : /* -------------------------------------------------------------------- */
71 4 : if (psSegInfo->nSegmentHeaderSize < 200)
72 : {
73 0 : CPLError(CE_Failure, CPLE_AppDefined,
74 : "DES header too small");
75 0 : return NULL;
76 : }
77 :
78 4 : pachHeader = (char*) VSIMalloc(psSegInfo->nSegmentHeaderSize);
79 4 : if (pachHeader == NULL)
80 : {
81 0 : CPLError(CE_Failure, CPLE_OutOfMemory,
82 : "Cannot allocate memory for segment header");
83 0 : return NULL;
84 : }
85 :
86 : retry:
87 8 : if( VSIFSeekL( psFile->fp, psSegInfo->nSegmentHeaderStart,
88 : SEEK_SET ) != 0
89 8 : || VSIFReadL( pachHeader, 1, psSegInfo->nSegmentHeaderSize,
90 8 : psFile->fp ) != psSegInfo->nSegmentHeaderSize )
91 : {
92 0 : CPLError( CE_Failure, CPLE_FileIO,
93 : "Failed to read %u byte DES subheader from " CPL_FRMT_GUIB ".",
94 : psSegInfo->nSegmentHeaderSize,
95 : psSegInfo->nSegmentHeaderStart );
96 0 : CPLFree(pachHeader);
97 0 : return NULL;
98 : }
99 :
100 4 : if (!EQUALN(pachHeader, "DE", 2))
101 : {
102 0 : if (EQUALN(pachHeader + 4, "DERegistered", 12))
103 : {
104 : /* BAO_46_Ed1/rpf/conc/concz10/000fz010.ona and cie are buggy */
105 0 : CPLDebug("NITF", "Patching nSegmentHeaderStart and nSegmentStart for DE segment %d", iSegment);
106 0 : psSegInfo->nSegmentHeaderStart += 4;
107 0 : psSegInfo->nSegmentStart += 4;
108 0 : goto retry;
109 : }
110 :
111 0 : CPLError(CE_Failure, CPLE_AppDefined,
112 : "Invalid segment prefix for DE segment %d", iSegment);
113 :
114 0 : CPLFree(pachHeader);
115 0 : return NULL;
116 : }
117 :
118 : /* -------------------------------------------------------------------- */
119 : /* Initialize DES object. */
120 : /* -------------------------------------------------------------------- */
121 4 : psDES = (NITFDES *) CPLCalloc(sizeof(NITFDES),1);
122 :
123 4 : psDES->psFile = psFile;
124 4 : psDES->iSegment = iSegment;
125 4 : psDES->pachHeader = pachHeader;
126 :
127 4 : psSegInfo->hAccess = psDES;
128 :
129 : /* -------------------------------------------------------------------- */
130 : /* Collect a variety of information as metadata. */
131 : /* -------------------------------------------------------------------- */
132 : #define GetMD( length, name ) \
133 : do { NITFExtractMetadata( &(psDES->papszMetadata), pachHeader, \
134 : nOffset, length, \
135 : "NITF_" #name ); \
136 : nOffset += length; } while(0)
137 :
138 4 : nOffset = 2;
139 4 : GetMD( 25, DESID );
140 4 : GetMD( 2, DESVER );
141 4 : GetMD( 1, DECLAS );
142 4 : GetMD( 2, DESCLSY );
143 4 : GetMD( 11, DESCODE );
144 4 : GetMD( 2, DESCTLH );
145 4 : GetMD( 20, DESREL );
146 4 : GetMD( 2, DESDCTP );
147 4 : GetMD( 8, DESDCDT );
148 4 : GetMD( 4, DESDCXM );
149 4 : GetMD( 1, DESDG );
150 4 : GetMD( 8, DESDGDT );
151 4 : GetMD( 43, DESCLTX );
152 4 : GetMD( 1, DESCATP );
153 4 : GetMD( 40, DESCAUT );
154 4 : GetMD( 1, DESCRSN );
155 4 : GetMD( 8, DESSRDT );
156 4 : GetMD( 15, DESCTLN );
157 :
158 : /* Load DESID */
159 4 : NITFGetField( szDESID, pachHeader, 2, 25);
160 :
161 : /* For NITF < 02.10, we cannot rely on DESID=TRE_OVERFLOW to detect */
162 : /* if DESOFLW and DESITEM are present. So if the next 4 bytes are non */
163 : /* numeric, we'll assume that DESOFLW is there */
164 20 : bHasDESOFLW = EQUALN(szDESID, "TRE_OVERFLOW", strlen("TRE_OVERFLOW")) ||
165 4 : (!((pachHeader[nOffset+0] >= '0' && pachHeader[nOffset+0] <= '9') &&
166 4 : (pachHeader[nOffset+1] >= '0' && pachHeader[nOffset+1] <= '9') &&
167 4 : (pachHeader[nOffset+2] >= '0' && pachHeader[nOffset+2] <= '9') &&
168 4 : (pachHeader[nOffset+3] >= '0' && pachHeader[nOffset+3] <= '9')));
169 :
170 4 : if (bHasDESOFLW)
171 : {
172 2 : if ((int)psSegInfo->nSegmentHeaderSize < nOffset + 6 + 3 )
173 : {
174 0 : CPLError(CE_Failure, CPLE_AppDefined,
175 : "DES header too small");
176 0 : NITFDESDeaccess(psDES);
177 0 : return NULL;
178 : }
179 2 : GetMD( 6, DESOFLW );
180 2 : GetMD( 3, DESITEM );
181 : }
182 :
183 4 : if ((int)psSegInfo->nSegmentHeaderSize < nOffset + 4 )
184 : {
185 0 : CPLError(CE_Failure, CPLE_AppDefined,
186 : "DES header too small");
187 0 : NITFDESDeaccess(psDES);
188 0 : return NULL;
189 : }
190 :
191 4 : GetMD( 4, DESSHL );
192 4 : nDESSHL = atoi(CSLFetchNameValue( psDES->papszMetadata, "NITF_DESSHL" ) );
193 :
194 4 : if (nDESSHL < 0)
195 : {
196 0 : CPLError(CE_Failure, CPLE_AppDefined,
197 : "Invalid value for DESSHL");
198 0 : NITFDESDeaccess(psDES);
199 0 : return NULL;
200 : }
201 4 : if ( (int)psSegInfo->nSegmentHeaderSize < nOffset + nDESSHL)
202 : {
203 0 : CPLError(CE_Failure, CPLE_AppDefined,
204 : "DES header too small");
205 0 : NITFDESDeaccess(psDES);
206 0 : return NULL;
207 : }
208 :
209 4 : if (EQUALN(szDESID, "CSSHPA DES", strlen("CSSHPA DES")))
210 : {
211 0 : if ( nDESSHL != 62 && nDESSHL != 80)
212 : {
213 0 : CPLError(CE_Failure, CPLE_AppDefined,
214 : "Invalid DESSHL for CSSHPA DES");
215 0 : NITFDESDeaccess(psDES);
216 0 : return NULL;
217 : }
218 :
219 0 : GetMD( 25, SHAPE_USE );
220 0 : GetMD( 10, SHAPE_CLASS );
221 0 : if (nDESSHL == 80)
222 0 : GetMD( 18, CC_SOURCE );
223 0 : GetMD( 3, SHAPE1_NAME );
224 0 : GetMD( 6, SHAPE1_START );
225 0 : GetMD( 3, SHAPE2_NAME );
226 0 : GetMD( 6, SHAPE2_START );
227 0 : GetMD( 3, SHAPE3_NAME );
228 0 : GetMD( 6, SHAPE3_START );
229 : }
230 4 : else if (EQUALN(szDESID, "XML_DATA_CONTENT", strlen("XML_DATA_CONTENT")))
231 : {
232 : /* TODO : handle nDESSHL = 0005 and 0283 */
233 2 : if (nDESSHL >= 5)
234 : {
235 2 : GetMD( 5, DESCRC );
236 2 : if (nDESSHL >= 283)
237 : {
238 2 : GetMD( 8, DESSHFT );
239 2 : GetMD( 20, DESSHDT );
240 2 : GetMD( 40, DESSHRP );
241 2 : GetMD( 60, DESSHSI );
242 2 : GetMD( 10, DESSHSV );
243 2 : GetMD( 20, DESSHSD );
244 2 : GetMD( 120, DESSHTN );
245 2 : if (nDESSHL >= 773)
246 : {
247 2 : GetMD( 125, DESSHLPG );
248 2 : GetMD( 25, DESSHLPT );
249 2 : GetMD( 20, DESSHLI );
250 2 : GetMD( 120, DESSHLIN );
251 2 : GetMD( 200, DESSHABS );
252 : }
253 : }
254 : }
255 : }
256 2 : else if (EQUALN(szDESID, "CSATTA DES", strlen("CSATTA DES")) && nDESSHL == 52)
257 : {
258 0 : GetMD( 12, ATT_TYPE );
259 0 : GetMD( 14, DT_ATT );
260 0 : GetMD( 8, DATE_ATT );
261 0 : GetMD( 13, T0_ATT );
262 0 : GetMD( 5, NUM_ATT );
263 : }
264 2 : else if (nDESSHL > 0)
265 0 : GetMD( nDESSHL, DESSHF );
266 :
267 4 : if ((int)psSegInfo->nSegmentHeaderSize > nOffset)
268 : {
269 : char* pszEscapedDESDATA =
270 0 : CPLEscapeString( pachHeader + nOffset,
271 : (int)psSegInfo->nSegmentHeaderSize - nOffset,
272 0 : CPLES_BackslashQuotable );
273 0 : psDES->papszMetadata = CSLSetNameValue( psDES->papszMetadata,
274 : "NITF_DESDATA",
275 : pszEscapedDESDATA );
276 0 : CPLFree(pszEscapedDESDATA);
277 : }
278 : else
279 : {
280 4 : char* pachData = (char*)VSIMalloc((size_t)psSegInfo->nSegmentSize);
281 4 : if (pachData == NULL )
282 : {
283 0 : CPLDebug("NITF", "Cannot allocate " CPL_FRMT_GUIB " bytes DES data",
284 : psSegInfo->nSegmentSize);
285 : }
286 8 : else if( VSIFSeekL( psFile->fp, psSegInfo->nSegmentStart,
287 : SEEK_SET ) != 0
288 4 : || VSIFReadL( pachData, 1, (size_t)psSegInfo->nSegmentSize,
289 4 : psFile->fp ) != psSegInfo->nSegmentSize )
290 : {
291 0 : CPLDebug("NITF",
292 : "Failed to read " CPL_FRMT_GUIB" bytes DES data from " CPL_FRMT_GUIB ".",
293 : psSegInfo->nSegmentSize,
294 : psSegInfo->nSegmentStart );
295 : }
296 : else
297 : {
298 : char* pszEscapedDESDATA =
299 4 : CPLEscapeString( pachData,
300 : (int)psSegInfo->nSegmentSize,
301 4 : CPLES_BackslashQuotable );
302 4 : psDES->papszMetadata = CSLSetNameValue( psDES->papszMetadata,
303 : "NITF_DESDATA",
304 : pszEscapedDESDATA );
305 4 : CPLFree(pszEscapedDESDATA);
306 : }
307 :
308 : #ifdef notdef
309 : /* Disabled because might generate a huge amount of elements */
310 : if (EQUALN(szDESID, "CSATTA DES", strlen("CSATTA DES")))
311 : {
312 : int nNumAtt = atoi(CSLFetchNameValueDef(psDES->papszMetadata, "NITF_NUM_ATT", "0"));
313 : if (nNumAtt * 8 * 4 == psSegInfo->nSegmentSize)
314 : {
315 : int nMDSize = CSLCount(psDES->papszMetadata);
316 : char** papszMD = (char**)VSIRealloc(psDES->papszMetadata, (nMDSize + nNumAtt * 4 + 1) * sizeof(char*));
317 : if (papszMD)
318 : {
319 : int i, j;
320 : const GByte* pachDataIter = pachData;
321 :
322 : psDES->papszMetadata = papszMD;
323 : for(i=0;i<nNumAtt;i++)
324 : {
325 : char szAttrNameValue[64+1+256+1];
326 : double dfVal;
327 : for(j=0;j<4;j++)
328 : {
329 : memcpy(&dfVal, pachDataIter, 8);
330 : CPL_MSBPTR64(&dfVal);
331 : pachDataIter += 8;
332 : sprintf(szAttrNameValue, "NITF_ATT_Q%d_%d=%.16g", j+1, i, dfVal);
333 : papszMD[nMDSize + i * 4 + j] = CPLStrdup(szAttrNameValue);
334 : }
335 : }
336 : papszMD[nMDSize + nNumAtt * 4] = NULL;
337 : }
338 : }
339 : }
340 : #endif
341 :
342 4 : CPLFree(pachData);
343 : }
344 :
345 4 : return psDES;
346 : }
347 :
348 : /************************************************************************/
349 : /* NITFDESDeaccess() */
350 : /************************************************************************/
351 :
352 4 : void NITFDESDeaccess( NITFDES *psDES )
353 :
354 : {
355 4 : CPLAssert( psDES->psFile->pasSegmentInfo[psDES->iSegment].hAccess
356 : == psDES );
357 :
358 4 : psDES->psFile->pasSegmentInfo[psDES->iSegment].hAccess = NULL;
359 :
360 4 : CPLFree( psDES->pachHeader );
361 4 : CSLDestroy( psDES->papszMetadata );
362 :
363 4 : CPLFree( psDES );
364 4 : }
365 :
366 : /************************************************************************/
367 : /* NITFDESGetTRE() */
368 : /************************************************************************/
369 :
370 : /**
371 : * Return the TRE located at nOffset.
372 : *
373 : * @param psDES descriptor of the DE segment
374 : * @param nOffset offset of the TRE relative to the beginning of the segment data
375 : * @param szTREName will be filled with the TRE name
376 : * @param ppabyTREData will be allocated by the function and filled with the TRE content (in raw form)
377 : * @param pnFoundTRESize will be filled with the TRE size (excluding the first 11 bytes)
378 : * @return TRUE if a TRE was found
379 : */
380 :
381 12 : int NITFDESGetTRE( NITFDES* psDES,
382 : int nOffset,
383 : char szTREName[7],
384 : char** ppabyTREData,
385 : int* pnFoundTRESize)
386 : {
387 : char szTREHeader[12];
388 : char szTRETempName[7];
389 : NITFSegmentInfo* psSegInfo;
390 : VSILFILE* fp;
391 : int nTRESize;
392 :
393 12 : memset(szTREName, '\0', 7);
394 12 : if (ppabyTREData)
395 12 : *ppabyTREData = NULL;
396 12 : if (pnFoundTRESize)
397 12 : *pnFoundTRESize = 0;
398 :
399 12 : if (nOffset < 0)
400 0 : return FALSE;
401 :
402 12 : if (psDES == NULL)
403 0 : return FALSE;
404 :
405 12 : if (CSLFetchNameValue(psDES->papszMetadata, "NITF_DESOFLW") == NULL)
406 2 : return FALSE;
407 :
408 10 : psSegInfo = psDES->psFile->pasSegmentInfo + psDES->iSegment;
409 10 : fp = psDES->psFile->fp;
410 :
411 10 : if (nOffset >= psSegInfo->nSegmentSize)
412 2 : return FALSE;
413 :
414 8 : VSIFSeekL(fp, psSegInfo->nSegmentStart + nOffset, SEEK_SET);
415 :
416 8 : if (VSIFReadL(szTREHeader, 1, 11, fp) != 11)
417 : {
418 : /* Some files have a nSegmentSize larger than what is is in reality */
419 : /* So exit silently if we're at end of file */
420 0 : VSIFSeekL(fp, 0, SEEK_END);
421 0 : if (VSIFTellL(fp) == psSegInfo->nSegmentStart + nOffset)
422 0 : return FALSE;
423 :
424 0 : CPLError(CE_Failure, CPLE_FileIO,
425 : "Cannot get 11 bytes at offset " CPL_FRMT_GUIB ".",
426 : psSegInfo->nSegmentStart + nOffset );
427 0 : return FALSE;
428 : }
429 8 : szTREHeader[11] = '\0';
430 :
431 8 : memcpy(szTRETempName, szTREHeader, 6);
432 8 : szTRETempName[6] = '\0';
433 :
434 8 : nTRESize = atoi(szTREHeader + 6);
435 8 : if (nTRESize < 0)
436 : {
437 0 : CPLError(CE_Failure, CPLE_AppDefined,
438 : "Invalid size (%d) for TRE %s",
439 : nTRESize, szTRETempName);
440 0 : return FALSE;
441 : }
442 8 : if (nOffset + 11 + nTRESize > psSegInfo->nSegmentSize)
443 : {
444 0 : CPLError(CE_Failure, CPLE_AppDefined,
445 : "Cannot read %s TRE. Not enough bytes : remaining %d, expected %d",
446 : szTRETempName,
447 : (int)(psSegInfo->nSegmentSize - (nOffset + 11)), nTRESize);
448 0 : return FALSE;
449 : }
450 :
451 8 : if (ppabyTREData)
452 : {
453 : /* Allocate one extra byte for the NULL terminating character */
454 8 : *ppabyTREData = (char*) VSIMalloc(nTRESize + 1);
455 8 : if (*ppabyTREData == NULL)
456 : {
457 0 : CPLError(CE_Failure, CPLE_OutOfMemory,
458 : "Cannot allocate %d bytes for TRE %s",
459 : nTRESize, szTRETempName);
460 0 : return FALSE;
461 : }
462 8 : (*ppabyTREData)[nTRESize] = '\0';
463 :
464 8 : if ((int)VSIFReadL(*ppabyTREData, 1, nTRESize, fp) != nTRESize)
465 : {
466 0 : CPLError(CE_Failure, CPLE_FileIO,
467 : "Cannot get %d bytes at offset " CPL_FRMT_GUIB ".",
468 : nTRESize, VSIFTellL(fp) );
469 0 : VSIFree(*ppabyTREData);
470 0 : *ppabyTREData = NULL;
471 0 : return FALSE;
472 : }
473 : }
474 :
475 8 : strcpy(szTREName, szTRETempName);
476 8 : if (pnFoundTRESize)
477 8 : *pnFoundTRESize = nTRESize;
478 :
479 8 : return TRUE;
480 : }
481 :
482 : /************************************************************************/
483 : /* NITFDESFreeTREData() */
484 : /************************************************************************/
485 :
486 8 : void NITFDESFreeTREData( char* pabyTREData )
487 : {
488 8 : VSIFree(pabyTREData);
489 8 : }
490 :
491 :
492 : /************************************************************************/
493 : /* NITFDESExtractShapefile() */
494 : /************************************************************************/
495 :
496 0 : int NITFDESExtractShapefile(NITFDES* psDES, const char* pszRadixFileName)
497 : {
498 : NITFSegmentInfo* psSegInfo;
499 : const char* apszExt[3];
500 : int anOffset[4];
501 : int iShpFile;
502 : char* pszFilename;
503 :
504 0 : if ( CSLFetchNameValue(psDES->papszMetadata, "NITF_SHAPE_USE") == NULL )
505 0 : return FALSE;
506 :
507 0 : psSegInfo = psDES->psFile->pasSegmentInfo + psDES->iSegment;
508 :
509 0 : apszExt[0] = CSLFetchNameValue(psDES->papszMetadata, "NITF_SHAPE1_NAME");
510 0 : anOffset[0] = atoi(CSLFetchNameValue(psDES->papszMetadata, "NITF_SHAPE1_START"));
511 0 : apszExt[1] = CSLFetchNameValue(psDES->papszMetadata, "NITF_SHAPE2_NAME");
512 0 : anOffset[1] = atoi(CSLFetchNameValue(psDES->papszMetadata, "NITF_SHAPE2_START"));
513 0 : apszExt[2] = CSLFetchNameValue(psDES->papszMetadata, "NITF_SHAPE3_NAME");
514 0 : anOffset[2] = atoi(CSLFetchNameValue(psDES->papszMetadata, "NITF_SHAPE3_START"));
515 0 : anOffset[3] = (int) psSegInfo->nSegmentSize;
516 :
517 0 : for(iShpFile = 0; iShpFile < 3; iShpFile ++)
518 : {
519 0 : if (!EQUAL(apszExt[iShpFile], "SHP") &&
520 0 : !EQUAL(apszExt[iShpFile], "SHX") &&
521 0 : !EQUAL(apszExt[iShpFile], "DBF"))
522 0 : return FALSE;
523 :
524 0 : if (anOffset[iShpFile] < 0 ||
525 0 : anOffset[iShpFile] >= anOffset[iShpFile+1])
526 0 : return FALSE;
527 : }
528 :
529 0 : pszFilename = (char*) VSIMalloc(strlen(pszRadixFileName) + 4 + 1);
530 0 : if (pszFilename == NULL)
531 0 : return FALSE;
532 :
533 0 : for(iShpFile = 0; iShpFile < 3; iShpFile ++)
534 : {
535 : VSILFILE* fp;
536 : GByte* pabyBuffer;
537 0 : int nSize = anOffset[iShpFile+1] - anOffset[iShpFile];
538 :
539 0 : pabyBuffer = (GByte*) VSIMalloc(nSize);
540 0 : if (pabyBuffer == NULL)
541 : {
542 0 : VSIFree(pszFilename);
543 0 : return FALSE;
544 : }
545 :
546 0 : VSIFSeekL(psDES->psFile->fp, psSegInfo->nSegmentStart + anOffset[iShpFile], SEEK_SET);
547 0 : if (VSIFReadL(pabyBuffer, 1, nSize, psDES->psFile->fp) != nSize)
548 : {
549 0 : VSIFree(pabyBuffer);
550 0 : VSIFree(pszFilename);
551 0 : return FALSE;
552 : }
553 :
554 0 : sprintf(pszFilename, "%s.%s", pszRadixFileName, apszExt[iShpFile]);
555 0 : fp = VSIFOpenL(pszFilename, "wb");
556 0 : if (fp == NULL)
557 : {
558 0 : VSIFree(pabyBuffer);
559 0 : VSIFree(pszFilename);
560 0 : return FALSE;
561 : }
562 :
563 0 : VSIFWriteL(pabyBuffer, 1, nSize, fp);
564 0 : VSIFCloseL(fp);
565 0 : VSIFree(pabyBuffer);
566 : }
567 :
568 0 : VSIFree(pszFilename);
569 :
570 0 : return TRUE;
571 : }
|