1 : /******************************************************************************
2 : * $Id: gsagdataset.cpp 16925 2009-05-03 14:16:49Z rouault $
3 : *
4 : * Project: GDAL
5 : * Purpose: Implements the Golden Software ASCII Grid Format.
6 : * Author: Kevin Locke, kwl7@cornell.edu
7 : * (Based largely on aaigriddataset.cpp by Frank Warmerdam)
8 : *
9 : ******************************************************************************
10 : * Copyright (c) 2006, Kevin Locke <kwl7@cornell.edu>
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 "cpl_conv.h"
32 :
33 : #include <sstream>
34 : #include <float.h>
35 : #include <limits.h>
36 : #include <assert.h>
37 :
38 : #include "gdal_pam.h"
39 :
40 : #ifndef DBL_MAX
41 : # ifdef __DBL_MAX__
42 : # define DBL_MAX __DBL_MAX__
43 : # else
44 : # define DBL_MAX 1.7976931348623157E+308
45 : # endif /* __DBL_MAX__ */
46 : #endif /* DBL_MAX */
47 :
48 : #ifndef INT_MAX
49 : # define INT_MAX 2147483647
50 : #endif /* INT_MAX */
51 :
52 : CPL_CVSID("$Id: gsagdataset.cpp 16925 2009-05-03 14:16:49Z rouault $");
53 :
54 : CPL_C_START
55 : void GDALRegister_GSAG(void);
56 : CPL_C_END
57 :
58 : /************************************************************************/
59 : /* ==================================================================== */
60 : /* GSAGDataset */
61 : /* ==================================================================== */
62 : /************************************************************************/
63 :
64 : class GSAGRasterBand;
65 :
66 : class GSAGDataset : public GDALPamDataset
67 : {
68 : friend class GSAGRasterBand;
69 :
70 : static const double dfNODATA_VALUE;
71 : static const int nFIELD_PRECISION;
72 : static const size_t nMAX_HEADER_SIZE;
73 :
74 : static CPLErr ShiftFileContents( FILE *, vsi_l_offset, int, const char * );
75 :
76 : FILE *fp;
77 : size_t nMinMaxZOffset;
78 : char szEOL[3];
79 :
80 : CPLErr UpdateHeader();
81 :
82 : public:
83 : GSAGDataset( const char *pszEOL = "\x0D\x0A" );
84 : ~GSAGDataset();
85 :
86 : static GDALDataset *Open( GDALOpenInfo * );
87 : static GDALDataset *CreateCopy( const char *pszFilename,
88 : GDALDataset *poSrcDS,
89 : int bStrict, char **papszOptions,
90 : GDALProgressFunc pfnProgress,
91 : void *pProgressData );
92 : static CPLErr Delete( const char *pszFilename );
93 :
94 : CPLErr GetGeoTransform( double *padfGeoTransform );
95 : CPLErr SetGeoTransform( double *padfGeoTransform );
96 : };
97 :
98 : /* NOTE: This is not mentioned in the spec, but Surfer 8 uses this value */
99 : const double GSAGDataset::dfNODATA_VALUE = 1.70141E+38;
100 :
101 : const int GSAGDataset::nFIELD_PRECISION = 14;
102 : const size_t GSAGDataset::nMAX_HEADER_SIZE = 200;
103 :
104 : /************************************************************************/
105 : /* ==================================================================== */
106 : /* GSAGRasterBand */
107 : /* ==================================================================== */
108 : /************************************************************************/
109 :
110 : class GSAGRasterBand : public GDALPamRasterBand
111 : {
112 : friend class GSAGDataset;
113 :
114 : double dfMinX;
115 : double dfMaxX;
116 : double dfMinY;
117 : double dfMaxY;
118 : double dfMinZ;
119 : double dfMaxZ;
120 :
121 : vsi_l_offset *panLineOffset;
122 : int nLastReadLine;
123 :
124 : double *padfRowMinZ;
125 : double *padfRowMaxZ;
126 : int nMinZRow;
127 : int nMaxZRow;
128 :
129 : CPLErr ScanForMinMaxZ();
130 :
131 : public:
132 :
133 : GSAGRasterBand( GSAGDataset *, int, vsi_l_offset );
134 : ~GSAGRasterBand();
135 :
136 : CPLErr IReadBlock( int, int, void * );
137 : CPLErr IWriteBlock( int, int, void * );
138 :
139 : double GetNoDataValue( int *pbSuccess = NULL );
140 : double GetMinimum( int *pbSuccess = NULL );
141 : double GetMaximum( int *pbSuccess = NULL );
142 : };
143 :
144 : /************************************************************************/
145 : /* AlmostEqual() */
146 : /* This function is needed because in release mode "1.70141E+38" is not */
147 : /* parsed as 1.70141E+38 in the last bit of the mantissa. */
148 : /* See http://gcc.gnu.org/ml/gcc/2003-08/msg01195.html for some */
149 : /* explanation. */
150 : /************************************************************************/
151 :
152 400 : bool AlmostEqual( double dfVal1, double dfVal2 )
153 :
154 : {
155 400 : const double dfTOLERANCE = 0.0000000001;
156 400 : if( dfVal1 == 0.0 || dfVal2 == 0.0 )
157 0 : return fabs(dfVal1 - dfVal2) < dfTOLERANCE;
158 400 : return fabs((dfVal1 - dfVal2)/dfVal1) < dfTOLERANCE;
159 : }
160 :
161 : /************************************************************************/
162 : /* GSAGRasterBand() */
163 : /************************************************************************/
164 :
165 15 : GSAGRasterBand::GSAGRasterBand( GSAGDataset *poDS, int nBand,
166 : vsi_l_offset nDataStart ) :
167 : padfRowMinZ(NULL),
168 : padfRowMaxZ(NULL),
169 : nMinZRow(-1),
170 15 : nMaxZRow(-1)
171 :
172 : {
173 15 : this->poDS = poDS;
174 15 : nBand = nBand;
175 :
176 15 : eDataType = GDT_Float64;
177 :
178 15 : nBlockXSize = poDS->GetRasterXSize();
179 15 : nBlockYSize = 1;
180 :
181 : panLineOffset =
182 15 : (vsi_l_offset *)VSICalloc( poDS->nRasterYSize+1, sizeof(vsi_l_offset) );
183 15 : if( panLineOffset == NULL )
184 : {
185 : CPLError(CE_Failure, CPLE_OutOfMemory,
186 : "GSAGRasterBand::GSAGRasterBand : Out of memory allocating %d * %d bytes",
187 0 : (int) poDS->nRasterYSize+1, (int) sizeof(vsi_l_offset) );
188 0 : return;
189 : }
190 :
191 15 : panLineOffset[poDS->nRasterYSize-1] = nDataStart;
192 15 : nLastReadLine = poDS->nRasterYSize;
193 0 : }
194 :
195 : /************************************************************************/
196 : /* ~GSAGRasterBand() */
197 : /************************************************************************/
198 :
199 30 : GSAGRasterBand::~GSAGRasterBand()
200 : {
201 15 : CPLFree( panLineOffset );
202 15 : if( padfRowMinZ != NULL )
203 0 : CPLFree( padfRowMinZ );
204 15 : if( padfRowMaxZ != NULL )
205 0 : CPLFree( padfRowMaxZ );
206 30 : }
207 :
208 : /************************************************************************/
209 : /* ScanForMinMaxZ() */
210 : /************************************************************************/
211 :
212 0 : CPLErr GSAGRasterBand::ScanForMinMaxZ()
213 :
214 : {
215 0 : double *padfRowValues = (double *)VSIMalloc2( nBlockXSize, sizeof(double) );
216 0 : if( padfRowValues == NULL )
217 : {
218 : CPLError( CE_Failure, CPLE_OutOfMemory,
219 0 : "Unable to allocate memory for grid row values.\n" );
220 0 : return CE_Failure;
221 : }
222 :
223 0 : double dfNewMinZ = DBL_MAX;
224 0 : double dfNewMaxZ = -DBL_MAX;
225 0 : int nNewMinZRow = 0;
226 0 : int nNewMaxZRow = 0;
227 :
228 : /* Since we have to scan, lets calc. statistics too */
229 0 : double dfSum = 0.0;
230 0 : double dfSum2 = 0.0;
231 0 : unsigned long nValuesRead = 0;
232 0 : for( int iRow=0; iRow<nRasterYSize; iRow++ )
233 : {
234 0 : CPLErr eErr = IReadBlock( 0, iRow, padfRowValues );
235 0 : if( eErr != CE_None )
236 : {
237 0 : VSIFree( padfRowValues );
238 0 : return eErr;
239 : }
240 :
241 0 : padfRowMinZ[iRow] = DBL_MAX;
242 0 : padfRowMaxZ[iRow] = -DBL_MAX;
243 0 : for( int iCell=0; iCell<nRasterXSize; iCell++ )
244 : {
245 0 : if( AlmostEqual(padfRowValues[iCell], GSAGDataset::dfNODATA_VALUE) )
246 0 : continue;
247 :
248 0 : if( padfRowValues[iCell] < padfRowMinZ[iRow] )
249 0 : padfRowMinZ[iRow] = padfRowValues[iCell];
250 :
251 0 : if( padfRowValues[iCell] > padfRowMaxZ[iRow] )
252 0 : padfRowMaxZ[iRow] = padfRowValues[iCell];
253 :
254 0 : dfSum += padfRowValues[iCell];
255 0 : dfSum2 += padfRowValues[iCell] * padfRowValues[iCell];
256 0 : nValuesRead++;
257 : }
258 :
259 0 : if( padfRowMinZ[iRow] < dfNewMinZ )
260 : {
261 0 : dfNewMinZ = padfRowMinZ[iRow];
262 0 : nNewMinZRow = iRow;
263 : }
264 :
265 0 : if( padfRowMaxZ[iRow] > dfNewMaxZ )
266 : {
267 0 : dfNewMaxZ = padfRowMaxZ[iRow];
268 0 : nNewMaxZRow = iRow;
269 : }
270 : }
271 :
272 0 : VSIFree( padfRowValues );
273 :
274 0 : if( nValuesRead == 0 )
275 : {
276 0 : dfMinZ = 0.0;
277 0 : dfMaxZ = 0.0;
278 0 : nMinZRow = 0;
279 0 : nMaxZRow = 0;
280 0 : return CE_None;
281 : }
282 :
283 0 : dfMinZ = dfNewMinZ;
284 0 : dfMaxZ = dfNewMaxZ;
285 0 : nMinZRow = nNewMinZRow;
286 0 : nMaxZRow = nNewMaxZRow;
287 :
288 0 : double dfMean = dfSum / nValuesRead;
289 0 : double dfStdDev = sqrt((dfSum2 / nValuesRead) - (dfMean * dfMean));
290 0 : SetStatistics( dfMinZ, dfMaxZ, dfMean, dfStdDev );
291 :
292 0 : return CE_None;
293 : }
294 :
295 : /************************************************************************/
296 : /* IReadBlock() */
297 : /************************************************************************/
298 :
299 156 : CPLErr GSAGRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
300 : void * pImage )
301 : {
302 : static size_t nMaxLineSize = 128;
303 156 : double *pdfImage = (double *)pImage;
304 156 : GSAGDataset *poGDS = (GSAGDataset *)poDS;
305 :
306 156 : assert( poGDS != NULL );
307 :
308 156 : if( nBlockYOff < 0 || nBlockYOff > nRasterYSize - 1 || nBlockXOff != 0 )
309 0 : return CE_Failure;
310 :
311 156 : if( panLineOffset[nBlockYOff] == 0 )
312 : {
313 : // Discover the last read block
314 80 : for ( int iFoundLine = nLastReadLine - 1; iFoundLine > nBlockYOff; iFoundLine--)
315 : {
316 76 : IReadBlock( nBlockXOff, iFoundLine, NULL);
317 : }
318 : }
319 :
320 156 : if( panLineOffset[nBlockYOff] == 0 )
321 0 : return CE_Failure;
322 156 : if( VSIFSeekL( poGDS->fp, panLineOffset[nBlockYOff], SEEK_SET ) != 0 )
323 : {
324 : CPLError( CE_Failure, CPLE_FileIO,
325 : "Can't seek to offset %ld to read grid row %d.",
326 0 : (long) panLineOffset[nBlockYOff], nBlockYOff );
327 0 : return CE_Failure;
328 : }
329 :
330 : size_t nLineBufSize;
331 156 : char *szLineBuf = NULL;
332 : size_t nCharsRead;
333 156 : size_t nCharsExamined = 0;
334 : /* If we know the offsets, we can just read line directly */
335 232 : if( (nBlockYOff > 0) && ( panLineOffset[nBlockYOff-1] != 0 ) )
336 : {
337 76 : assert(panLineOffset[nBlockYOff-1] > panLineOffset[nBlockYOff]);
338 76 : nLineBufSize = panLineOffset[nBlockYOff-1]
339 76 : - panLineOffset[nBlockYOff] + 1;
340 : }
341 : else
342 : {
343 80 : nLineBufSize = nMaxLineSize;
344 : }
345 :
346 156 : szLineBuf = (char *)VSIMalloc( nLineBufSize );
347 156 : if( szLineBuf == NULL )
348 : {
349 : CPLError( CE_Failure, CPLE_OutOfMemory,
350 0 : "Unable to read block, unable to allocate line buffer.\n" );
351 0 : return CE_Failure;
352 : }
353 :
354 156 : nCharsRead = VSIFReadL( szLineBuf, 1, nLineBufSize - 1, poGDS->fp );
355 156 : if( nCharsRead == 0 )
356 : {
357 0 : VSIFree( szLineBuf );
358 : CPLError( CE_Failure, CPLE_FileIO,
359 : "Can't read grid row %d at offset %ld.\n",
360 0 : nBlockYOff, (long) panLineOffset[nBlockYOff] );
361 0 : return CE_Failure;
362 : }
363 156 : szLineBuf[nCharsRead] = '\0';
364 :
365 156 : char *szStart = szLineBuf;
366 156 : char *szEnd = szStart;
367 3276 : for( int iCell=0; iCell<nBlockXSize; szStart = szEnd )
368 : {
369 3120 : double dfValue = CPLStrtod( szStart, &szEnd );
370 3120 : if( szStart == szEnd )
371 : {
372 : /* No number found */
373 :
374 : /* Check if this was an expected failure */
375 0 : while( isspace( (unsigned char)*szStart ) )
376 0 : szStart++;
377 :
378 : /* Found sign at end of input, seek back to re-read it */
379 0 : if ( (*szStart == '-' || *szStart == '+') && *(szStart+1) == '\0' )
380 : {
381 0 : if( VSIFSeekL( poGDS->fp,
382 : VSIFTellL( poGDS->fp)-1,
383 : SEEK_SET ) != 0 )
384 : {
385 0 : VSIFree( szLineBuf );
386 : CPLError( CE_Failure, CPLE_FileIO,
387 : "Unable to seek in grid row %d "
388 : "(offset %ld, seek %d).\n",
389 : nBlockYOff,
390 : (long) VSIFTellL(poGDS->fp),
391 0 : -1 );
392 :
393 0 : return CE_Failure;
394 : }
395 : }
396 0 : else if( *szStart != '\0' )
397 : {
398 0 : szEnd = szStart;
399 0 : while( !isspace( (unsigned char)*szEnd ) && *szEnd != '\0' )
400 0 : szEnd++;
401 0 : char cOldEnd = *szEnd;
402 0 : *szEnd = '\0';
403 :
404 : CPLError( CE_Warning, CPLE_FileIO,
405 : "Unexpected value in grid row %d (expected floating "
406 : "point value, found \"%s\").\n",
407 0 : nBlockYOff, szStart );
408 :
409 0 : *szEnd = cOldEnd;
410 :
411 0 : szEnd = szStart;
412 0 : while( !isdigit( *szEnd ) && *szEnd != '.' && *szEnd != '\0' )
413 0 : szEnd++;
414 :
415 0 : continue;
416 : }
417 0 : else if( static_cast<size_t>(szStart - szLineBuf) != nCharsRead )
418 : {
419 : CPLError( CE_Warning, CPLE_FileIO,
420 : "Unexpected ASCII null-character in grid row %d at "
421 : "offset %ld.\n",
422 : nBlockYOff,
423 0 : (long) (szStart - szLineBuf) );
424 :
425 0 : while( *szStart == '\0' &&
426 : static_cast<size_t>(szStart - szLineBuf) < nCharsRead )
427 0 : szStart++;
428 :
429 0 : szEnd = szStart;
430 0 : continue;
431 : }
432 :
433 0 : nCharsExamined += szStart - szLineBuf;
434 0 : nCharsRead = VSIFReadL( szLineBuf, 1, nLineBufSize - 1, poGDS->fp );
435 0 : if( nCharsRead == 0 )
436 : {
437 0 : VSIFree( szLineBuf );
438 : CPLError( CE_Failure, CPLE_FileIO,
439 : "Can't read portion of grid row %d at offset %ld.",
440 0 : nBlockYOff, (long) panLineOffset[nBlockYOff] );
441 0 : return CE_Failure;
442 : }
443 0 : szLineBuf[nCharsRead] = '\0';
444 0 : szStart = szEnd = szLineBuf;
445 0 : continue;
446 : }
447 3120 : else if( *szEnd == '\0'
448 : || (*szEnd == '.' && *(szEnd+1) == '\0')
449 : || (*szEnd == '-' && *(szEnd+1) == '\0')
450 : || (*szEnd == '+' && *(szEnd+1) == '\0')
451 : || (*szEnd == 'E' && *(szEnd+1) == '\0')
452 : || (*szEnd == 'E' && *(szEnd+1) == '-' && *(szEnd+2) == '\0')
453 : || (*szEnd == 'E' && *(szEnd+1) == '+' && *(szEnd+2) == '\0')
454 : || (*szEnd == 'e' && *(szEnd+1) == '\0')
455 : || (*szEnd == 'e' && *(szEnd+1) == '-' && *(szEnd+2) == '\0')
456 : || (*szEnd == 'e' && *(szEnd+1) == '+' && *(szEnd+2) == '\0'))
457 : {
458 : /* Number was interrupted by a nul character */
459 0 : while( *szEnd != '\0' )
460 0 : szEnd++;
461 :
462 0 : if( static_cast<size_t>(szEnd - szLineBuf) != nCharsRead )
463 : {
464 : CPLError( CE_Warning, CPLE_FileIO,
465 : "Unexpected ASCII null-character in grid row %d at "
466 : "offset %ld.\n",
467 : nBlockYOff,
468 0 : (long) (szStart - szLineBuf) );
469 :
470 0 : while( *szEnd == '\0' &&
471 : static_cast<size_t>(szStart - szLineBuf) < nCharsRead )
472 0 : szEnd++;
473 :
474 0 : continue;
475 : }
476 :
477 : /* End of buffer, could be interrupting a number */
478 0 : if( VSIFSeekL( poGDS->fp, szStart - szEnd, SEEK_CUR ) != 0 )
479 : {
480 0 : VSIFree( szLineBuf );
481 : CPLError( CE_Failure, CPLE_FileIO,
482 : "Unable to seek in grid row %d (offset %ld, seek %d)"
483 : ".\n", nBlockYOff,
484 : (long) VSIFTellL(poGDS->fp),
485 0 : (int) (szStart - szEnd) );
486 :
487 0 : return CE_Failure;
488 : }
489 0 : nCharsExamined += szStart - szLineBuf;
490 0 : nCharsRead = VSIFReadL( szLineBuf, 1, nLineBufSize - 1, poGDS->fp );
491 0 : szLineBuf[nCharsRead] = '\0';
492 :
493 0 : if( nCharsRead == 0 )
494 : {
495 0 : VSIFree( szLineBuf );
496 : CPLError( CE_Failure, CPLE_FileIO,
497 : "Can't read portion of grid row %d at offset %ld.",
498 0 : nBlockYOff, (long) panLineOffset[nBlockYOff] );
499 0 : return CE_Failure;
500 : }
501 0 : else if( nCharsRead > static_cast<size_t>(szEnd - szStart) )
502 : {
503 : /* Read new data, this was not really the end */
504 0 : szEnd = szStart = szLineBuf;
505 0 : continue;
506 : }
507 :
508 : /* This is really the last value and has no tailing newline */
509 0 : szStart = szLineBuf;
510 0 : szEnd = szLineBuf + nCharsRead;
511 : }
512 :
513 3120 : if( pdfImage != NULL )
514 : {
515 1600 : *(pdfImage+iCell) = dfValue;
516 : }
517 :
518 3120 : iCell++;
519 : }
520 :
521 468 : while( *szEnd == ' ' )
522 156 : szEnd++;
523 :
524 156 : if( *szEnd != '\0' && *szEnd != poGDS->szEOL[0] )
525 : CPLDebug( "GSAG", "Grid row %d does not end with a newline. "
526 0 : "Possible skew.\n", nBlockYOff );
527 :
528 986 : while( isspace( (unsigned char)*szEnd ) )
529 674 : szEnd++;
530 :
531 156 : nCharsExamined += szEnd - szLineBuf;
532 :
533 156 : if( nCharsExamined >= nMaxLineSize )
534 0 : nMaxLineSize = nCharsExamined + 1;
535 :
536 156 : if( nBlockYOff > 0 )
537 152 : panLineOffset[nBlockYOff - 1] =
538 152 : panLineOffset[nBlockYOff] + nCharsExamined;
539 :
540 156 : nLastReadLine = nBlockYOff;
541 :
542 156 : VSIFree( szLineBuf );
543 :
544 156 : return CE_None;
545 : }
546 :
547 : /************************************************************************/
548 : /* IWriteBlock() */
549 : /************************************************************************/
550 :
551 0 : CPLErr GSAGRasterBand::IWriteBlock( int nBlockXOff, int nBlockYOff,
552 : void * pImage )
553 :
554 : {
555 0 : if( eAccess == GA_ReadOnly )
556 : {
557 : CPLError( CE_Failure, CPLE_NoWriteAccess,
558 0 : "Unable to write block, dataset opened read only.\n" );
559 0 : return CE_Failure;
560 : }
561 :
562 0 : if( nBlockYOff < 0 || nBlockYOff > nRasterYSize - 1 || nBlockXOff != 0 )
563 0 : return CE_Failure;
564 :
565 0 : GSAGDataset *poGDS = (GSAGDataset *)poDS;
566 0 : assert( poGDS != NULL );
567 :
568 0 : if( padfRowMinZ == NULL || padfRowMaxZ == NULL
569 : || nMinZRow < 0 || nMaxZRow < 0 )
570 : {
571 0 : padfRowMinZ = (double *)VSIMalloc2( nRasterYSize,sizeof(double) );
572 0 : if( padfRowMinZ == NULL )
573 : {
574 : CPLError( CE_Failure, CPLE_OutOfMemory,
575 0 : "Unable to allocate space for row minimums array.\n" );
576 0 : return CE_Failure;
577 : }
578 :
579 0 : padfRowMaxZ = (double *)VSIMalloc2( nRasterYSize,sizeof(double) );
580 0 : if( padfRowMaxZ == NULL )
581 : {
582 0 : VSIFree( padfRowMinZ );
583 0 : padfRowMinZ = NULL;
584 : CPLError( CE_Failure, CPLE_OutOfMemory,
585 0 : "Unable to allocate space for row maximums array.\n" );
586 0 : return CE_Failure;
587 : }
588 :
589 0 : CPLErr eErr = ScanForMinMaxZ();
590 0 : if( eErr != CE_None )
591 0 : return eErr;
592 : }
593 :
594 0 : if( panLineOffset[nBlockYOff+1] == 0 )
595 0 : IReadBlock( nBlockXOff, nBlockYOff, NULL );
596 :
597 0 : if( panLineOffset[nBlockYOff+1] == 0 || panLineOffset[nBlockYOff] == 0 )
598 0 : return CE_Failure;
599 :
600 0 : std::ostringstream ssOutBuf;
601 0 : ssOutBuf.precision( GSAGDataset::nFIELD_PRECISION );
602 0 : ssOutBuf.setf( std::ios::uppercase );
603 :
604 0 : double *pdfImage = (double *)pImage;
605 0 : padfRowMinZ[nBlockYOff] = DBL_MAX;
606 0 : padfRowMaxZ[nBlockYOff] = -DBL_MAX;
607 0 : for( int iCell=0; iCell<nBlockXSize; )
608 : {
609 0 : for( int iCol=0; iCol<10 && iCell<nBlockXSize; iCol++, iCell++ )
610 : {
611 0 : if( AlmostEqual( pdfImage[iCell], GSAGDataset::dfNODATA_VALUE ) )
612 : {
613 0 : if( pdfImage[iCell] < padfRowMinZ[nBlockYOff] )
614 0 : padfRowMinZ[nBlockYOff] = pdfImage[iCell];
615 :
616 0 : if( pdfImage[iCell] > padfRowMaxZ[nBlockYOff] )
617 0 : padfRowMaxZ[nBlockYOff] = pdfImage[iCell];
618 : }
619 :
620 0 : ssOutBuf << pdfImage[iCell] << " ";
621 : }
622 0 : ssOutBuf << poGDS->szEOL;
623 : }
624 0 : ssOutBuf << poGDS->szEOL;
625 :
626 0 : CPLString sOut = ssOutBuf.str();
627 0 : if( sOut.length() != panLineOffset[nBlockYOff+1]-panLineOffset[nBlockYOff] )
628 : {
629 0 : int nShiftSize = sOut.length() - (panLineOffset[nBlockYOff+1]
630 0 : - panLineOffset[nBlockYOff]);
631 0 : if( nBlockYOff != poGDS->nRasterYSize
632 : && GSAGDataset::ShiftFileContents( poGDS->fp,
633 : panLineOffset[nBlockYOff+1],
634 : nShiftSize,
635 : poGDS->szEOL ) != CE_None )
636 : {
637 : CPLError( CE_Failure, CPLE_FileIO,
638 : "Failure writing block, "
639 0 : "unable to shift file contents.\n" );
640 0 : return CE_Failure;
641 : }
642 :
643 0 : for( size_t iLine=nBlockYOff+1;
644 : iLine < static_cast<unsigned>(poGDS->nRasterYSize+1)
645 0 : && panLineOffset[iLine] != 0; iLine++ )
646 0 : panLineOffset[iLine] += nShiftSize;
647 : }
648 :
649 0 : if( VSIFSeekL( poGDS->fp, panLineOffset[nBlockYOff], SEEK_SET ) != 0 )
650 : {
651 0 : CPLError( CE_Failure, CPLE_FileIO, "Unable to seek to grid line.\n" );
652 0 : return CE_Failure;
653 : }
654 :
655 0 : if( VSIFWriteL( sOut.c_str(), 1, sOut.length(),
656 : poGDS->fp ) != sOut.length() )
657 : {
658 0 : CPLError( CE_Failure, CPLE_FileIO, "Unable to write grid block.\n" );
659 0 : return CE_Failure;
660 : }
661 :
662 : /* Update header as needed */
663 0 : bool bHeaderNeedsUpdate = false;
664 0 : if( nMinZRow == nBlockYOff && padfRowMinZ[nBlockYOff] > dfMinZ )
665 : {
666 0 : double dfNewMinZ = -DBL_MAX;
667 0 : for( int iRow=0; iRow<nRasterYSize; iRow++ )
668 : {
669 0 : if( padfRowMinZ[iRow] < dfNewMinZ )
670 : {
671 0 : dfNewMinZ = padfRowMinZ[iRow];
672 0 : nMinZRow = iRow;
673 : }
674 : }
675 :
676 0 : if( dfNewMinZ != dfMinZ )
677 : {
678 0 : dfMinZ = dfNewMinZ;
679 0 : bHeaderNeedsUpdate = true;
680 : }
681 : }
682 :
683 0 : if( nMaxZRow == nBlockYOff && padfRowMaxZ[nBlockYOff] < dfMaxZ )
684 : {
685 0 : double dfNewMaxZ = -DBL_MAX;
686 0 : for( int iRow=0; iRow<nRasterYSize; iRow++ )
687 : {
688 0 : if( padfRowMaxZ[iRow] > dfNewMaxZ )
689 : {
690 0 : dfNewMaxZ = padfRowMaxZ[iRow];
691 0 : nMaxZRow = iRow;
692 : }
693 : }
694 :
695 0 : if( dfNewMaxZ != dfMaxZ )
696 : {
697 0 : dfMaxZ = dfNewMaxZ;
698 0 : bHeaderNeedsUpdate = true;
699 : }
700 : }
701 :
702 0 : if( padfRowMinZ[nBlockYOff] < dfMinZ || padfRowMaxZ[nBlockYOff] > dfMaxZ )
703 : {
704 0 : if( padfRowMinZ[nBlockYOff] < dfMinZ )
705 : {
706 0 : dfMinZ = padfRowMinZ[nBlockYOff];
707 0 : nMinZRow = nBlockYOff;
708 : }
709 :
710 0 : if( padfRowMaxZ[nBlockYOff] > dfMaxZ )
711 : {
712 0 : dfMaxZ = padfRowMaxZ[nBlockYOff];
713 0 : nMaxZRow = nBlockYOff;
714 : }
715 :
716 0 : bHeaderNeedsUpdate = true;
717 : }
718 :
719 0 : if( bHeaderNeedsUpdate && dfMaxZ > dfMinZ )
720 : {
721 0 : CPLErr eErr = poGDS->UpdateHeader();
722 0 : return eErr;
723 : }
724 :
725 0 : return CE_None;
726 : }
727 :
728 : /************************************************************************/
729 : /* GetNoDataValue() */
730 : /************************************************************************/
731 :
732 4 : double GSAGRasterBand::GetNoDataValue( int * pbSuccess )
733 : {
734 4 : if( pbSuccess )
735 4 : *pbSuccess = TRUE;
736 :
737 4 : return GSAGDataset::dfNODATA_VALUE;
738 : }
739 :
740 : /************************************************************************/
741 : /* GetMinimum() */
742 : /************************************************************************/
743 :
744 0 : double GSAGRasterBand::GetMinimum( int *pbSuccess )
745 : {
746 0 : if( pbSuccess )
747 0 : *pbSuccess = TRUE;
748 :
749 0 : return dfMinZ;
750 : }
751 :
752 : /************************************************************************/
753 : /* GetMaximum() */
754 : /************************************************************************/
755 :
756 0 : double GSAGRasterBand::GetMaximum( int *pbSuccess )
757 : {
758 0 : if( pbSuccess )
759 0 : *pbSuccess = TRUE;
760 :
761 0 : return dfMaxZ;
762 : }
763 :
764 : /************************************************************************/
765 : /* ==================================================================== */
766 : /* GSAGDataset */
767 : /* ==================================================================== */
768 : /************************************************************************/
769 :
770 : /************************************************************************/
771 : /* GSAGDataset() */
772 : /************************************************************************/
773 :
774 15 : GSAGDataset::GSAGDataset( const char *pszEOL )
775 :
776 : {
777 15 : if( pszEOL == NULL || EQUAL(pszEOL, "") )
778 : {
779 0 : CPLDebug( "GSAG", "GSAGDataset() created with invalid EOL string.\n" );
780 0 : this->szEOL[0] = '\x0D';
781 0 : this->szEOL[1] = '\x0A';
782 0 : this->szEOL[2] = '\0';
783 : }
784 : else
785 : {
786 15 : strncpy(this->szEOL, pszEOL, sizeof(this->szEOL));
787 15 : this->szEOL[sizeof(this->szEOL) - 1] = '\0';
788 : }
789 15 : }
790 :
791 : /************************************************************************/
792 : /* ~GSAGDataset() */
793 : /************************************************************************/
794 :
795 30 : GSAGDataset::~GSAGDataset()
796 :
797 : {
798 15 : FlushCache();
799 15 : if( fp != NULL )
800 15 : VSIFCloseL( fp );
801 30 : }
802 :
803 : /************************************************************************/
804 : /* Open() */
805 : /************************************************************************/
806 :
807 8827 : GDALDataset *GSAGDataset::Open( GDALOpenInfo * poOpenInfo )
808 :
809 : {
810 : /* Check for signature */
811 8842 : if( poOpenInfo->nHeaderBytes < 5
812 : || !EQUALN((const char *) poOpenInfo->pabyHeader,"DSAA",4)
813 15 : || ( poOpenInfo->pabyHeader[4] != '\x0D'
814 0 : && poOpenInfo->pabyHeader[4] != '\x0A' ))
815 : {
816 8812 : return NULL;
817 : }
818 :
819 : /* Identify the end of line marker (should be \x0D\x0A, but try some others)
820 : * (note that '\x0D' == '\r' and '\x0A' == '\n' on most systems) */
821 : char szEOL[3];
822 15 : szEOL[0] = poOpenInfo->pabyHeader[4];
823 15 : szEOL[1] = poOpenInfo->pabyHeader[5];
824 15 : szEOL[2] = '\0';
825 15 : if( szEOL[1] != '\x0D' && szEOL[1] != '\x0A' )
826 0 : szEOL[1] = '\0';
827 :
828 : /* -------------------------------------------------------------------- */
829 : /* Create a corresponding GDALDataset. */
830 : /* -------------------------------------------------------------------- */
831 15 : GSAGDataset *poDS = new GSAGDataset( szEOL );
832 :
833 : /* -------------------------------------------------------------------- */
834 : /* Open file with large file API. */
835 : /* -------------------------------------------------------------------- */
836 :
837 15 : poDS->eAccess = poOpenInfo->eAccess;
838 15 : if( poOpenInfo->eAccess == GA_ReadOnly )
839 3 : poDS->fp = VSIFOpenL( poOpenInfo->pszFilename, "rb" );
840 : else
841 12 : poDS->fp = VSIFOpenL( poOpenInfo->pszFilename, "r+b" );
842 :
843 15 : if( poDS->fp == NULL )
844 : {
845 : CPLError( CE_Failure, CPLE_OpenFailed,
846 : "VSIFOpenL(%s) failed unexpectedly.",
847 0 : poOpenInfo->pszFilename );
848 0 : delete poDS;
849 0 : return NULL;
850 : }
851 :
852 : /* -------------------------------------------------------------------- */
853 : /* Read the header. */
854 : /* -------------------------------------------------------------------- */
855 : char *pabyHeader;
856 15 : bool bMustFreeHeader = false;
857 15 : if( poOpenInfo->nHeaderBytes >= static_cast<int>(nMAX_HEADER_SIZE) )
858 : {
859 15 : pabyHeader = (char *)poOpenInfo->pabyHeader;
860 : }
861 : else
862 : {
863 0 : bMustFreeHeader = true;
864 0 : pabyHeader = (char *)VSIMalloc( nMAX_HEADER_SIZE );
865 0 : if( pabyHeader == NULL )
866 : {
867 : CPLError( CE_Failure, CPLE_OutOfMemory,
868 0 : "Unable to open dataset, unable to header buffer.\n" );
869 0 : return NULL;
870 : }
871 :
872 0 : size_t nRead = VSIFReadL( pabyHeader, 1, nMAX_HEADER_SIZE-1, poDS->fp );
873 0 : pabyHeader[nRead] = '\0';
874 : }
875 :
876 15 : const char *szErrorMsg = NULL;
877 15 : const char *szStart = pabyHeader + 5;
878 : char *szEnd;
879 : double dfTemp;
880 : double dfMinX;
881 : double dfMaxX;
882 : double dfMinY;
883 : double dfMaxY;
884 : double dfMinZ;
885 : double dfMaxZ;
886 :
887 : /* Parse number of X axis grid rows */
888 15 : long nTemp = strtol( szStart, &szEnd, 10 );
889 15 : if( szStart == szEnd || nTemp < 0l )
890 : {
891 0 : szErrorMsg = "Unable to parse the number of X axis grid columns.\n";
892 0 : goto error;
893 : }
894 : else if( nTemp > INT_MAX )
895 : {
896 : CPLError( CE_Warning, CPLE_AppDefined,
897 : "Number of X axis grid columns not representable.\n" );
898 : poDS->nRasterXSize = INT_MAX;
899 : }
900 15 : else if ( nTemp == 0 )
901 : {
902 0 : szErrorMsg = "Number of X axis grid columns is zero, which is invalid.\n";
903 0 : goto error;
904 : }
905 : else
906 : {
907 15 : poDS->nRasterXSize = static_cast<int>(nTemp);
908 : }
909 15 : szStart = szEnd;
910 :
911 : /* Parse number of Y axis grid rows */
912 15 : nTemp = strtol( szStart, &szEnd, 10 );
913 15 : if( szStart == szEnd || nTemp < 0l )
914 : {
915 0 : szErrorMsg = "Unable to parse the number of Y axis grid rows.\n";
916 0 : goto error;
917 : }
918 : else if( nTemp > INT_MAX )
919 : {
920 : CPLError( CE_Warning, CPLE_AppDefined,
921 : "Number of Y axis grid rows not representable.\n" );
922 : poDS->nRasterYSize = INT_MAX;
923 : }
924 15 : else if ( nTemp == 0)
925 : {
926 0 : szErrorMsg = "Number of Y axis grid rows is zero, which is invalid.\n";
927 0 : goto error;
928 : }
929 : else
930 : {
931 15 : poDS->nRasterYSize = static_cast<int>(nTemp);
932 : }
933 15 : szStart = szEnd;
934 :
935 : /* Parse the minimum X value of the grid */
936 15 : dfTemp = CPLStrtod( szStart, &szEnd );
937 15 : if( szStart == szEnd )
938 : {
939 0 : szErrorMsg = "Unable to parse the minimum X value.\n";
940 0 : goto error;
941 : }
942 : else
943 : {
944 15 : dfMinX = dfTemp;
945 : }
946 15 : szStart = szEnd;
947 :
948 : /* Parse the maximum X value of the grid */
949 15 : dfTemp = CPLStrtod( szStart, &szEnd );
950 15 : if( szStart == szEnd )
951 : {
952 0 : szErrorMsg = "Unable to parse the maximum X value.\n";
953 0 : goto error;
954 : }
955 : else
956 : {
957 15 : dfMaxX = dfTemp;
958 : }
959 15 : szStart = szEnd;
960 :
961 : /* Parse the minimum Y value of the grid */
962 15 : dfTemp = CPLStrtod( szStart, &szEnd );
963 15 : if( szStart == szEnd )
964 : {
965 0 : szErrorMsg = "Unable to parse the minimum Y value.\n";
966 0 : goto error;
967 : }
968 : else
969 : {
970 15 : dfMinY = dfTemp;
971 : }
972 15 : szStart = szEnd;
973 :
974 : /* Parse the maximum Y value of the grid */
975 15 : dfTemp = CPLStrtod( szStart, &szEnd );
976 15 : if( szStart == szEnd )
977 : {
978 0 : szErrorMsg = "Unable to parse the maximum Y value.\n";
979 0 : goto error;
980 : }
981 : else
982 : {
983 15 : dfMaxY = dfTemp;
984 : }
985 15 : szStart = szEnd;
986 :
987 : /* Parse the minimum Z value of the grid */
988 60 : while( isspace( (unsigned char)*szStart ) )
989 30 : szStart++;
990 15 : poDS->nMinMaxZOffset = szStart - pabyHeader;
991 :
992 15 : dfTemp = CPLStrtod( szStart, &szEnd );
993 15 : if( szStart == szEnd )
994 : {
995 0 : szErrorMsg = "Unable to parse the minimum Z value.\n";
996 0 : goto error;
997 : }
998 : else
999 : {
1000 15 : dfMinZ = dfTemp;
1001 : }
1002 15 : szStart = szEnd;
1003 :
1004 : /* Parse the maximum Z value of the grid */
1005 15 : dfTemp = CPLStrtod( szStart, &szEnd );
1006 15 : if( szStart == szEnd )
1007 : {
1008 0 : szErrorMsg = "Unable to parse the maximum Z value.\n";
1009 0 : goto error;
1010 : }
1011 : else
1012 : {
1013 15 : dfMaxZ = dfTemp;
1014 : }
1015 :
1016 60 : while( isspace((unsigned char)*szEnd) )
1017 30 : szEnd++;
1018 :
1019 : /* -------------------------------------------------------------------- */
1020 : /* Create band information objects. */
1021 : /* -------------------------------------------------------------------- */
1022 : {
1023 15 : GSAGRasterBand *poBand = new GSAGRasterBand( poDS, 1, szEnd-pabyHeader );
1024 15 : if( poBand->panLineOffset == NULL )
1025 : {
1026 0 : delete poBand;
1027 0 : goto error;
1028 : }
1029 :
1030 15 : poBand->dfMinX = dfMinX;
1031 15 : poBand->dfMaxX = dfMaxX;
1032 15 : poBand->dfMinY = dfMinY;
1033 15 : poBand->dfMaxY = dfMaxY;
1034 15 : poBand->dfMinZ = dfMinZ;
1035 15 : poBand->dfMaxZ = dfMaxZ;
1036 :
1037 15 : poDS->SetBand( 1, poBand );
1038 : }
1039 :
1040 15 : if( bMustFreeHeader )
1041 : {
1042 0 : CPLFree( pabyHeader );
1043 : }
1044 :
1045 : /* -------------------------------------------------------------------- */
1046 : /* Initialize any PAM information. */
1047 : /* -------------------------------------------------------------------- */
1048 15 : poDS->SetDescription( poOpenInfo->pszFilename );
1049 15 : poDS->TryLoadXML();
1050 :
1051 15 : return( poDS );
1052 :
1053 : error:
1054 0 : if ( bMustFreeHeader )
1055 : {
1056 0 : CPLFree( pabyHeader );
1057 : }
1058 :
1059 0 : delete poDS;
1060 :
1061 0 : if (szErrorMsg)
1062 0 : CPLError( CE_Failure, CPLE_AppDefined, "%s", szErrorMsg );
1063 0 : return NULL;
1064 : }
1065 :
1066 : /************************************************************************/
1067 : /* GetGeoTransform() */
1068 : /************************************************************************/
1069 :
1070 4 : CPLErr GSAGDataset::GetGeoTransform( double *padfGeoTransform )
1071 : {
1072 4 : if( padfGeoTransform == NULL )
1073 0 : return CE_Failure;
1074 :
1075 4 : GSAGRasterBand *poGRB = (GSAGRasterBand *)GetRasterBand( 1 );
1076 :
1077 4 : if( poGRB == NULL )
1078 : {
1079 0 : padfGeoTransform[0] = 0;
1080 0 : padfGeoTransform[1] = 1;
1081 0 : padfGeoTransform[2] = 0;
1082 0 : padfGeoTransform[3] = 0;
1083 0 : padfGeoTransform[4] = 0;
1084 0 : padfGeoTransform[5] = 1;
1085 0 : return CE_Failure;
1086 : }
1087 :
1088 : /* check if we have a PAM GeoTransform stored */
1089 4 : CPLPushErrorHandler( CPLQuietErrorHandler );
1090 4 : CPLErr eErr = GDALPamDataset::GetGeoTransform( padfGeoTransform );
1091 4 : CPLPopErrorHandler();
1092 :
1093 4 : if( eErr == CE_None )
1094 0 : return CE_None;
1095 :
1096 : /* calculate pixel size first */
1097 4 : padfGeoTransform[1] = (poGRB->dfMaxX - poGRB->dfMinX)/(nRasterXSize - 1);
1098 4 : padfGeoTransform[5] = (poGRB->dfMinY - poGRB->dfMaxY)/(nRasterYSize - 1);
1099 :
1100 : /* then calculate image origin */
1101 4 : padfGeoTransform[0] = poGRB->dfMinX - padfGeoTransform[1] / 2;
1102 4 : padfGeoTransform[3] = poGRB->dfMaxY - padfGeoTransform[5] / 2;
1103 :
1104 : /* tilt/rotation does not supported by the GS grids */
1105 4 : padfGeoTransform[4] = 0.0;
1106 4 : padfGeoTransform[2] = 0.0;
1107 :
1108 4 : return CE_None;
1109 : }
1110 :
1111 : /************************************************************************/
1112 : /* SetGeoTransform() */
1113 : /************************************************************************/
1114 :
1115 0 : CPLErr GSAGDataset::SetGeoTransform( double *padfGeoTransform )
1116 : {
1117 0 : if( eAccess == GA_ReadOnly )
1118 : {
1119 : CPLError( CE_Failure, CPLE_NoWriteAccess,
1120 0 : "Unable to set GeoTransform, dataset opened read only.\n" );
1121 0 : return CE_Failure;
1122 : }
1123 :
1124 0 : GSAGRasterBand *poGRB = (GSAGRasterBand *)GetRasterBand( 1 );
1125 :
1126 0 : if( poGRB == NULL || padfGeoTransform == NULL)
1127 0 : return CE_Failure;
1128 :
1129 : /* non-zero transform 2 or 4 or negative 1 or 5 not supported natively */
1130 0 : CPLErr eErr = CE_None;
1131 : /*if( padfGeoTransform[2] != 0.0 || padfGeoTransform[4] != 0.0
1132 : || padfGeoTransform[1] < 0.0 || padfGeoTransform[5] < 0.0 )
1133 : eErr = GDALPamDataset::SetGeoTransform( padfGeoTransform );*/
1134 :
1135 0 : if( eErr != CE_None )
1136 0 : return eErr;
1137 :
1138 0 : double dfOldMinX = poGRB->dfMinX;
1139 0 : double dfOldMaxX = poGRB->dfMaxX;
1140 0 : double dfOldMinY = poGRB->dfMinY;
1141 0 : double dfOldMaxY = poGRB->dfMaxY;
1142 :
1143 0 : poGRB->dfMinX = padfGeoTransform[0] + padfGeoTransform[1] / 2;
1144 : poGRB->dfMaxX =
1145 0 : padfGeoTransform[1] * (nRasterXSize - 0.5) + padfGeoTransform[0];
1146 : poGRB->dfMinY =
1147 0 : padfGeoTransform[5] * (nRasterYSize - 0.5) + padfGeoTransform[3];
1148 0 : poGRB->dfMaxY = padfGeoTransform[3] + padfGeoTransform[5] / 2;
1149 :
1150 0 : eErr = UpdateHeader();
1151 :
1152 0 : if( eErr != CE_None )
1153 : {
1154 0 : poGRB->dfMinX = dfOldMinX;
1155 0 : poGRB->dfMaxX = dfOldMaxX;
1156 0 : poGRB->dfMinY = dfOldMinY;
1157 0 : poGRB->dfMaxY = dfOldMaxY;
1158 : }
1159 :
1160 0 : return eErr;
1161 : }
1162 :
1163 : /************************************************************************/
1164 : /* ShiftFileContents() */
1165 : /************************************************************************/
1166 12 : CPLErr GSAGDataset::ShiftFileContents( FILE *fp, vsi_l_offset nShiftStart,
1167 : int nShiftSize, const char *pszEOL )
1168 : {
1169 : /* nothing to do for zero-shift */
1170 12 : if( nShiftSize == 0 )
1171 0 : return CE_None;
1172 :
1173 : /* make sure start location is sane */
1174 12 : if( nShiftStart < 0
1175 : || (nShiftSize < 0
1176 : && nShiftStart < static_cast<vsi_l_offset>(-nShiftSize)) )
1177 0 : nShiftStart = (nShiftSize > 0) ? 0 : -nShiftSize;
1178 :
1179 : /* get offset at end of file */
1180 12 : if( VSIFSeekL( fp, 0, SEEK_END ) != 0 )
1181 : {
1182 : CPLError( CE_Failure, CPLE_FileIO,
1183 0 : "Unable to seek to end of grid file.\n" );
1184 0 : return CE_Failure;
1185 : }
1186 :
1187 12 : vsi_l_offset nOldEnd = VSIFTellL( fp );
1188 :
1189 : /* If shifting past end, just zero-pad as necessary */
1190 12 : if( nShiftStart >= nOldEnd )
1191 : {
1192 0 : if( nShiftSize < 0 )
1193 : {
1194 0 : if( nShiftStart + nShiftSize >= nOldEnd )
1195 0 : return CE_None;
1196 :
1197 0 : if( VSIFSeekL( fp, nShiftStart + nShiftSize, SEEK_SET ) != 0 )
1198 : {
1199 : CPLError( CE_Failure, CPLE_FileIO,
1200 0 : "Unable to seek near end of file.\n" );
1201 0 : return CE_Failure;
1202 : }
1203 :
1204 : /* ftruncate()? */
1205 0 : for( vsi_l_offset nPos = nShiftStart + nShiftSize;
1206 : nPos > nOldEnd; nPos++ )
1207 : {
1208 0 : if( VSIFWriteL( (void *)" ", 1, 1, fp ) != 1 )
1209 : {
1210 : CPLError( CE_Failure, CPLE_FileIO,
1211 : "Unable to write padding to grid file "
1212 0 : "(Out of space?).\n" );
1213 0 : return CE_Failure;
1214 : }
1215 : }
1216 :
1217 0 : return CE_None;
1218 : }
1219 : else
1220 : {
1221 0 : for( vsi_l_offset nPos = nOldEnd;
1222 : nPos < nShiftStart + nShiftSize; nPos++ )
1223 : {
1224 0 : if( VSIFWriteL( (void *)" ", 1, 1, fp ) != 1 )
1225 : {
1226 : CPLError( CE_Failure, CPLE_FileIO,
1227 : "Unable to write padding to grid file "
1228 0 : "(Out of space?).\n" );
1229 0 : return CE_Failure;
1230 : }
1231 : }
1232 0 : return CE_None;
1233 : }
1234 : }
1235 :
1236 : /* prepare buffer for real shifting */
1237 12 : size_t nBufferSize = (1024 >= abs(nShiftSize)*2) ? 1024 : abs(nShiftSize)*2;
1238 12 : char *pabyBuffer = (char *)VSIMalloc( nBufferSize );
1239 12 : if( pabyBuffer == NULL)
1240 : {
1241 : CPLError( CE_Failure, CPLE_OutOfMemory,
1242 0 : "Unable to allocate space for shift buffer.\n" );
1243 0 : return CE_Failure;
1244 : }
1245 :
1246 12 : if( VSIFSeekL( fp, nShiftStart, SEEK_SET ) != 0 )
1247 : {
1248 0 : VSIFree( pabyBuffer );
1249 : CPLError( CE_Failure, CPLE_FileIO,
1250 0 : "Unable to seek to start of shift in grid file.\n" );
1251 0 : return CE_Failure;
1252 : }
1253 :
1254 : size_t nRead;
1255 12 : size_t nOverlap = (nShiftSize > 0) ? nShiftSize : 0;
1256 : /* If there is overlap, fill buffer with the overlap to start */
1257 12 : if( nOverlap > 0)
1258 : {
1259 0 : nRead = VSIFReadL( (void *)pabyBuffer, 1, nOverlap, fp );
1260 0 : if( nRead < nOverlap && !VSIFEofL( fp ) )
1261 : {
1262 0 : VSIFree( pabyBuffer );
1263 : CPLError( CE_Failure, CPLE_FileIO,
1264 0 : "Error reading grid file.\n" );
1265 0 : return CE_Failure;
1266 : }
1267 :
1268 : /* overwrite the new space with ' ' */
1269 0 : if( VSIFSeekL( fp, nShiftStart, SEEK_SET ) != 0 )
1270 : {
1271 0 : VSIFree( pabyBuffer );
1272 : CPLError( CE_Failure, CPLE_FileIO,
1273 0 : "Unable to seek to start of shift in grid file.\n" );
1274 0 : return CE_Failure;
1275 : }
1276 :
1277 0 : for( int iFill=0; iFill<nShiftSize; iFill++ )
1278 : {
1279 0 : if( VSIFWriteL( (void *)" ", 1, 1, fp ) != 1 )
1280 : {
1281 0 : VSIFree( pabyBuffer );
1282 : CPLError( CE_Failure, CPLE_FileIO,
1283 : "Unable to write padding to grid file "
1284 0 : "(Out of space?).\n" );
1285 0 : return CE_Failure;
1286 : }
1287 : }
1288 :
1289 : /* if we have already read the entire file, finish it off */
1290 0 : if( VSIFTellL( fp ) >= nOldEnd )
1291 : {
1292 0 : if( VSIFWriteL( (void *)pabyBuffer, 1, nRead, fp ) != nRead )
1293 : {
1294 0 : VSIFree( pabyBuffer );
1295 : CPLError( CE_Failure, CPLE_FileIO,
1296 0 : "Unable to write to grid file (Out of space?).\n" );
1297 0 : return CE_Failure;
1298 : }
1299 :
1300 0 : VSIFree( pabyBuffer );
1301 0 : return CE_None;
1302 : }
1303 : }
1304 :
1305 : /* iterate over the remainder of the file and shift as requested */
1306 12 : bool bEOF = false;
1307 37 : while( !bEOF )
1308 : {
1309 : nRead = VSIFReadL( (void *)(pabyBuffer+nOverlap), 1,
1310 13 : nBufferSize - nOverlap, fp );
1311 :
1312 13 : bEOF = VSIFEofL( fp );
1313 :
1314 13 : if( nRead == 0 && !bEOF )
1315 : {
1316 0 : VSIFree( pabyBuffer );
1317 : CPLError( CE_Failure, CPLE_FileIO,
1318 0 : "Unable to read from grid file (possible corruption).\n");
1319 0 : return CE_Failure;
1320 : }
1321 :
1322 : /* FIXME: Should use SEEK_CUR, review integer promotions... */
1323 13 : if( VSIFSeekL( fp, VSIFTellL(fp)-nRead+nShiftSize-nOverlap,
1324 : SEEK_SET ) != 0 )
1325 : {
1326 0 : VSIFree( pabyBuffer );
1327 : CPLError( CE_Failure, CPLE_FileIO,
1328 0 : "Unable to seek in grid file (possible corruption).\n" );
1329 0 : return CE_Failure;
1330 : }
1331 :
1332 13 : size_t nWritten = VSIFWriteL( (void *)pabyBuffer, 1, nRead, fp );
1333 13 : if( nWritten != nRead )
1334 : {
1335 0 : VSIFree( pabyBuffer );
1336 : CPLError( CE_Failure, CPLE_FileIO,
1337 0 : "Unable to write to grid file (out of space?).\n" );
1338 0 : return CE_Failure;
1339 : }
1340 :
1341 : /* shift overlapped contents to the front of the buffer if necessary */
1342 13 : if( nOverlap > 0)
1343 0 : memmove(pabyBuffer, pabyBuffer+nRead, nOverlap);
1344 : }
1345 :
1346 : /* write the remainder of the buffer or overwrite leftovers and finish */
1347 12 : if( nShiftSize > 0 )
1348 : {
1349 0 : size_t nTailSize = nOverlap;
1350 0 : while( nTailSize > 0 && isspace( (unsigned char)pabyBuffer[nTailSize-1] ) )
1351 0 : nTailSize--;
1352 :
1353 0 : if( VSIFWriteL( (void *)pabyBuffer, 1, nTailSize, fp ) != nTailSize )
1354 : {
1355 0 : VSIFree( pabyBuffer );
1356 : CPLError( CE_Failure, CPLE_FileIO,
1357 0 : "Unable to write to grid file (out of space?).\n" );
1358 0 : return CE_Failure;
1359 : }
1360 :
1361 0 : if( VSIFWriteL( (void *)pszEOL, 1, strlen(pszEOL), fp )
1362 : != strlen(pszEOL) )
1363 : {
1364 0 : VSIFree( pabyBuffer );
1365 : CPLError( CE_Failure, CPLE_FileIO,
1366 0 : "Unable to write to grid file (out of space?).\n" );
1367 0 : return CE_Failure;
1368 : }
1369 : }
1370 : else
1371 : {
1372 : /* FIXME: ftruncate()? */
1373 : /* FIXME: Should use SEEK_CUR, review integer promotions... */
1374 12 : if( VSIFSeekL( fp, VSIFTellL(fp)-strlen(pszEOL), SEEK_SET ) != 0 )
1375 : {
1376 0 : VSIFree( pabyBuffer );
1377 : CPLError( CE_Failure, CPLE_FileIO,
1378 0 : "Unable to seek in grid file.\n" );
1379 0 : return CE_Failure;
1380 : }
1381 :
1382 301 : for( int iPadding=0; iPadding<-nShiftSize; iPadding++ )
1383 : {
1384 289 : if( VSIFWriteL( (void *)" ", 1, 1, fp ) != 1 )
1385 : {
1386 0 : VSIFree( pabyBuffer );
1387 : CPLError( CE_Failure, CPLE_FileIO,
1388 0 : "Error writing to grid file.\n" );
1389 0 : return CE_Failure;
1390 : }
1391 : }
1392 :
1393 12 : if( VSIFWriteL( (void *)pszEOL, 1, strlen(pszEOL), fp )
1394 : != strlen(pszEOL) )
1395 : {
1396 0 : VSIFree( pabyBuffer );
1397 : CPLError( CE_Failure, CPLE_FileIO,
1398 0 : "Unable to write to grid file (out of space?).\n" );
1399 0 : return CE_Failure;
1400 : }
1401 : }
1402 :
1403 12 : VSIFree( pabyBuffer );
1404 12 : return CE_None;
1405 : }
1406 :
1407 : /************************************************************************/
1408 : /* UpdateHeader() */
1409 : /************************************************************************/
1410 :
1411 0 : CPLErr GSAGDataset::UpdateHeader()
1412 :
1413 : {
1414 0 : GSAGRasterBand *poBand = (GSAGRasterBand *)GetRasterBand( 1 );
1415 0 : if( poBand == NULL )
1416 : {
1417 0 : CPLError( CE_Failure, CPLE_FileIO, "Unable to open raster band.\n" );
1418 0 : return CE_Failure;
1419 : }
1420 :
1421 0 : std::ostringstream ssOutBuf;
1422 0 : ssOutBuf.precision( nFIELD_PRECISION );
1423 0 : ssOutBuf.setf( std::ios::uppercase );
1424 :
1425 : /* signature */
1426 0 : ssOutBuf << "DSAA" << szEOL;
1427 :
1428 : /* columns rows */
1429 0 : ssOutBuf << nRasterXSize << " " << nRasterYSize << szEOL;
1430 :
1431 : /* x range */
1432 0 : ssOutBuf << poBand->dfMinX << " " << poBand->dfMaxX << szEOL;
1433 :
1434 : /* y range */
1435 0 : ssOutBuf << poBand->dfMinY << " " << poBand->dfMaxY << szEOL;
1436 :
1437 : /* z range */
1438 0 : ssOutBuf << poBand->dfMinZ << " " << poBand->dfMaxZ << szEOL;
1439 :
1440 0 : CPLString sOut = ssOutBuf.str();
1441 0 : if( sOut.length() != poBand->panLineOffset[0] )
1442 : {
1443 0 : int nShiftSize = sOut.length() - poBand->panLineOffset[0];
1444 0 : if( ShiftFileContents( fp, poBand->panLineOffset[0], nShiftSize,
1445 : szEOL ) != CE_None )
1446 : {
1447 : CPLError( CE_Failure, CPLE_FileIO,
1448 : "Unable to update grid header, "
1449 0 : "failure shifting file contents.\n" );
1450 0 : return CE_Failure;
1451 : }
1452 :
1453 0 : for( size_t iLine=0;
1454 : iLine < static_cast<unsigned>(nRasterYSize+1)
1455 0 : && poBand->panLineOffset[iLine] != 0;
1456 : iLine++ )
1457 0 : poBand->panLineOffset[iLine] += nShiftSize;
1458 : }
1459 :
1460 0 : if( VSIFSeekL( fp, 0, SEEK_SET ) != 0 )
1461 : {
1462 : CPLError( CE_Failure, CPLE_FileIO,
1463 0 : "Unable to seek to start of grid file.\n" );
1464 0 : return CE_Failure;
1465 : }
1466 :
1467 0 : if( VSIFWriteL( sOut.c_str(), 1, sOut.length(), fp ) != sOut.length() )
1468 : {
1469 : CPLError( CE_Failure, CPLE_FileIO,
1470 0 : "Unable to update file header. Disk full?\n" );
1471 0 : return CE_Failure;
1472 : }
1473 :
1474 0 : return CE_None;
1475 : }
1476 :
1477 : /************************************************************************/
1478 : /* CreateCopy() */
1479 : /************************************************************************/
1480 :
1481 17 : GDALDataset *GSAGDataset::CreateCopy( const char *pszFilename,
1482 : GDALDataset *poSrcDS,
1483 : int bStrict, char **papszOptions,
1484 : GDALProgressFunc pfnProgress,
1485 : void *pProgressData )
1486 : {
1487 17 : if( pfnProgress == NULL )
1488 0 : pfnProgress = GDALDummyProgress;
1489 :
1490 17 : int nBands = poSrcDS->GetRasterCount();
1491 17 : if (nBands == 0)
1492 : {
1493 : CPLError( CE_Failure, CPLE_NotSupported,
1494 1 : "GSAG driver does not support source dataset with zero band.\n");
1495 1 : return NULL;
1496 : }
1497 16 : else if (nBands > 1)
1498 : {
1499 4 : if( bStrict )
1500 : {
1501 : CPLError( CE_Failure, CPLE_NotSupported,
1502 : "Unable to create copy, Golden Software ASCII Grid "
1503 4 : "format only supports one raster band.\n" );
1504 4 : return NULL;
1505 : }
1506 : else
1507 : CPLError( CE_Warning, CPLE_NotSupported,
1508 : "Golden Software ASCII Grid format only supports one "
1509 0 : "raster band, first band will be copied.\n" );
1510 : }
1511 :
1512 12 : if( !pfnProgress( 0.0, NULL, pProgressData ) )
1513 : {
1514 0 : CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated\n" );
1515 0 : return NULL;
1516 : }
1517 :
1518 12 : FILE *fp = VSIFOpenL( pszFilename, "w+b" );
1519 :
1520 12 : if( fp == NULL )
1521 : {
1522 : CPLError( CE_Failure, CPLE_OpenFailed,
1523 : "Attempt to create file '%s' failed.\n",
1524 0 : pszFilename );
1525 0 : return NULL;
1526 : }
1527 :
1528 12 : int nXSize = poSrcDS->GetRasterXSize();
1529 12 : int nYSize = poSrcDS->GetRasterYSize();
1530 : double adfGeoTransform[6];
1531 :
1532 12 : poSrcDS->GetGeoTransform( adfGeoTransform );
1533 :
1534 12 : std::ostringstream ssHeader;
1535 12 : ssHeader.precision( nFIELD_PRECISION );
1536 12 : ssHeader.setf( std::ios::uppercase );
1537 :
1538 12 : ssHeader << "DSAA\x0D\x0A";
1539 :
1540 12 : ssHeader << nXSize << " " << nYSize << "\x0D\x0A";
1541 :
1542 12 : ssHeader << adfGeoTransform[0] + adfGeoTransform[1] / 2 << " "
1543 24 : << adfGeoTransform[1] * (nXSize - 0.5) + adfGeoTransform[0]
1544 36 : << "\x0D\x0A";
1545 :
1546 24 : ssHeader << adfGeoTransform[5] * (nYSize - 0.5) + adfGeoTransform[3] << " "
1547 12 : << adfGeoTransform[3] + adfGeoTransform[5] / 2
1548 36 : << "\x0D\x0A";
1549 :
1550 12 : if( VSIFWriteL( (void *)ssHeader.str().c_str(), 1, ssHeader.str().length(),
1551 : fp ) != ssHeader.str().length() )
1552 : {
1553 0 : VSIFCloseL( fp );
1554 : CPLError( CE_Failure, CPLE_FileIO,
1555 0 : "Unable to create copy, writing header failed.\n" );
1556 0 : return NULL;
1557 : }
1558 :
1559 : /* Save the location and write placeholders for the min/max Z value */
1560 12 : vsi_l_offset nRangeStart = VSIFTellL( fp );
1561 12 : const char *szDummyRange = "0.0000000000001 0.0000000000001\x0D\x0A";
1562 12 : size_t nDummyRangeLen = strlen( szDummyRange );
1563 12 : if( VSIFWriteL( (void *)szDummyRange, 1, nDummyRangeLen,
1564 : fp ) != nDummyRangeLen )
1565 : {
1566 0 : VSIFCloseL( fp );
1567 : CPLError( CE_Failure, CPLE_FileIO,
1568 0 : "Unable to create copy, writing header failed.\n" );
1569 0 : return NULL;
1570 : }
1571 :
1572 : /* -------------------------------------------------------------------- */
1573 : /* Copy band data. */
1574 : /* -------------------------------------------------------------------- */
1575 12 : double *pdfData = (double *)VSIMalloc2( nXSize, sizeof( double ) );
1576 12 : if( pdfData == NULL )
1577 : {
1578 0 : VSIFCloseL( fp );
1579 : CPLError( CE_Failure, CPLE_OutOfMemory,
1580 0 : "Unable to create copy, unable to allocate line buffer.\n" );
1581 0 : return NULL;
1582 : }
1583 :
1584 12 : GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand(1);
1585 : int bSrcHasNDValue;
1586 12 : double dfSrcNoDataValue = poSrcBand->GetNoDataValue( &bSrcHasNDValue );
1587 12 : double dfMin = DBL_MAX;
1588 12 : double dfMax = -DBL_MAX;
1589 142 : for( int iRow=0; iRow<nYSize; iRow++ )
1590 : {
1591 : CPLErr eErr = poSrcBand->RasterIO( GF_Read, 0, nYSize-iRow-1,
1592 : nXSize, 1, pdfData,
1593 130 : nXSize, 1, GDT_Float64, 0, 0 );
1594 :
1595 130 : if( eErr != CE_None )
1596 : {
1597 0 : VSIFCloseL( fp );
1598 0 : VSIFree( pdfData );
1599 0 : return NULL;
1600 : }
1601 :
1602 410 : for( int iCol=0; iCol<nXSize; )
1603 : {
1604 150 : for( int iCount=0;
1605 : iCount<10 && iCol<nXSize;
1606 : iCount++, iCol++ )
1607 : {
1608 1500 : double dfValue = pdfData[iCol];
1609 :
1610 1500 : if( bSrcHasNDValue && AlmostEqual( dfValue, dfSrcNoDataValue ) )
1611 : {
1612 0 : dfValue = dfNODATA_VALUE;
1613 : }
1614 : else
1615 : {
1616 1500 : if( dfValue > dfMax )
1617 14 : dfMax = dfValue;
1618 :
1619 1500 : if( dfValue < dfMin )
1620 19 : dfMin = dfValue;
1621 : }
1622 :
1623 1500 : std::ostringstream ssOut;
1624 1500 : ssOut.precision(nFIELD_PRECISION);
1625 1500 : ssOut.setf( std::ios::uppercase );
1626 1500 : ssOut << dfValue << " ";
1627 1500 : CPLString sOut = ssOut.str();
1628 :
1629 1500 : if( VSIFWriteL( sOut.c_str(), 1, sOut.length(), fp )
1630 : != sOut.length() )
1631 : {
1632 0 : VSIFCloseL( fp );
1633 0 : VSIFree( pdfData );
1634 : CPLError( CE_Failure, CPLE_FileIO,
1635 0 : "Unable to write grid cell. Disk full?\n" );
1636 0 : return NULL;
1637 : }
1638 : }
1639 :
1640 150 : if( VSIFWriteL( (void *)"\x0D\x0A", 1, 2, fp ) != 2 )
1641 : {
1642 0 : VSIFCloseL( fp );
1643 0 : VSIFree( pdfData );
1644 : CPLError( CE_Failure, CPLE_FileIO,
1645 0 : "Unable to finish write of grid line. Disk full?\n" );
1646 0 : return NULL;
1647 : }
1648 : }
1649 :
1650 130 : if( VSIFWriteL( (void *)"\x0D\x0A", 1, 2, fp ) != 2 )
1651 : {
1652 0 : VSIFCloseL( fp );
1653 0 : VSIFree( pdfData );
1654 : CPLError( CE_Failure, CPLE_FileIO,
1655 0 : "Unable to finish write of grid row. Disk full?\n" );
1656 0 : return NULL;
1657 : }
1658 :
1659 130 : if( !pfnProgress( static_cast<double>(iRow)/nYSize,
1660 : NULL, pProgressData ) )
1661 : {
1662 0 : VSIFCloseL( fp );
1663 0 : VSIFree( pdfData );
1664 0 : CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
1665 0 : return NULL;
1666 : }
1667 : }
1668 :
1669 12 : VSIFree( pdfData );
1670 :
1671 : /* write out the min and max values */
1672 12 : std::ostringstream ssRange;
1673 12 : ssRange.precision( nFIELD_PRECISION );
1674 12 : ssRange.setf( std::ios::uppercase );
1675 12 : ssRange << dfMin << " " << dfMax << "\x0D\x0A";
1676 12 : if( ssRange.str().length() != nDummyRangeLen )
1677 : {
1678 12 : int nShiftSize = ssRange.str().length() - nDummyRangeLen;
1679 12 : if( ShiftFileContents( fp, nRangeStart + nDummyRangeLen,
1680 : nShiftSize, "\x0D\x0A" ) != CE_None )
1681 : {
1682 0 : VSIFCloseL( fp );
1683 : CPLError( CE_Failure, CPLE_FileIO,
1684 0 : "Unable to shift file contents.\n" );
1685 0 : return NULL;
1686 : }
1687 : }
1688 :
1689 12 : if( VSIFSeekL( fp, nRangeStart, SEEK_SET ) != 0 )
1690 : {
1691 0 : VSIFCloseL( fp );
1692 : CPLError( CE_Failure, CPLE_FileIO,
1693 0 : "Unable to seek to start of grid file copy.\n" );
1694 0 : return NULL;
1695 : }
1696 :
1697 12 : if( VSIFWriteL( (void *)ssRange.str().c_str(), 1, ssRange.str().length(),
1698 : fp ) != ssRange.str().length() )
1699 : {
1700 0 : VSIFCloseL( fp );
1701 : CPLError( CE_Failure, CPLE_FileIO,
1702 0 : "Unable to write range information.\n" );
1703 0 : return NULL;
1704 : }
1705 :
1706 12 : VSIFCloseL( fp );
1707 :
1708 : GDALPamDataset *poDstDS = (GDALPamDataset *)GDALOpen( pszFilename,
1709 12 : GA_Update );
1710 12 : if( poDstDS == NULL )
1711 : {
1712 0 : VSIUnlink( pszFilename );
1713 : CPLError( CE_Failure, CPLE_FileIO,
1714 0 : "Unable to open copy of dataset.\n" );
1715 0 : return NULL;
1716 : }
1717 :
1718 12 : GDALRasterBand *poDstBand = poDstDS->GetRasterBand(1);
1719 12 : if( poDstBand == NULL )
1720 : {
1721 0 : VSIUnlink( pszFilename );
1722 0 : delete poDstDS;
1723 : CPLError( CE_Failure, CPLE_FileIO,
1724 0 : "Unable to open copy of raster band?\n" );
1725 0 : return NULL;
1726 : }
1727 :
1728 : /* -------------------------------------------------------------------- */
1729 : /* Attempt to copy metadata. */
1730 : /* -------------------------------------------------------------------- */
1731 12 : if( !bStrict )
1732 1 : CPLPushErrorHandler( CPLQuietErrorHandler );
1733 :
1734 : /* non-zero transform 2 or 4 or negative 1 or 5 not supported natively */
1735 : /*if( adfGeoTransform[2] != 0.0 || adfGeoTransform[4] != 0.0
1736 : || adfGeoTransform[1] < 0.0 || adfGeoTransform[5] < 0.0 )
1737 : poDstDS->GDALPamDataset::SetGeoTransform( adfGeoTransform );*/
1738 :
1739 12 : const char *szProjectionRef = poSrcDS->GetProjectionRef();
1740 12 : if( *szProjectionRef != '\0' )
1741 11 : poDstDS->SetProjection( szProjectionRef );
1742 :
1743 12 : char **pszMetadata = poSrcDS->GetMetadata();
1744 12 : if( pszMetadata != NULL )
1745 11 : poDstDS->SetMetadata( pszMetadata );
1746 :
1747 : /* FIXME: Should the dataset description be copied as well, or is it
1748 : * always the file name? */
1749 12 : poDstBand->SetDescription( poSrcBand->GetDescription() );
1750 :
1751 : int bSuccess;
1752 12 : double dfOffset = poSrcBand->GetOffset( &bSuccess );
1753 12 : if( bSuccess && dfOffset != 0.0 )
1754 0 : poDstBand->SetOffset( dfOffset );
1755 :
1756 12 : double dfScale = poSrcBand->GetScale( &bSuccess );
1757 12 : if( bSuccess && dfScale != 1.0 )
1758 0 : poDstBand->SetScale( dfScale );
1759 :
1760 12 : GDALColorInterp oColorInterp = poSrcBand->GetColorInterpretation();
1761 12 : if( oColorInterp != GCI_Undefined )
1762 11 : poDstBand->SetColorInterpretation( oColorInterp );
1763 :
1764 12 : char **pszCatNames = poSrcBand->GetCategoryNames();
1765 12 : if( pszCatNames != NULL)
1766 0 : poDstBand->SetCategoryNames( pszCatNames );
1767 :
1768 12 : GDALColorTable *poColorTable = poSrcBand->GetColorTable();
1769 12 : if( poColorTable != NULL )
1770 0 : poDstBand->SetColorTable( poColorTable );
1771 :
1772 12 : if( !bStrict )
1773 1 : CPLPopErrorHandler();
1774 :
1775 12 : return poDstDS;
1776 : }
1777 :
1778 : /************************************************************************/
1779 : /* Delete() */
1780 : /************************************************************************/
1781 :
1782 1 : CPLErr GSAGDataset::Delete( const char *pszFilename )
1783 :
1784 : {
1785 : VSIStatBufL sStat;
1786 :
1787 1 : if( VSIStatL( pszFilename, &sStat ) != 0 )
1788 : {
1789 : CPLError( CE_Failure, CPLE_FileIO,
1790 0 : "Unable to stat() %s.\n", pszFilename );
1791 0 : return CE_Failure;
1792 : }
1793 :
1794 1 : if( !VSI_ISREG( sStat.st_mode ) )
1795 : {
1796 : CPLError( CE_Failure, CPLE_FileIO,
1797 0 : "%s is not a regular file, not removed.\n", pszFilename );
1798 0 : return CE_Failure;
1799 : }
1800 :
1801 1 : if( VSIUnlink( pszFilename ) != 0 )
1802 : {
1803 : CPLError( CE_Failure, CPLE_FileIO,
1804 0 : "Error unlinking %s.\n", pszFilename );
1805 0 : return CE_Failure;
1806 : }
1807 :
1808 1 : return CE_None;
1809 : }
1810 :
1811 : /************************************************************************/
1812 : /* GDALRegister_GSAG() */
1813 : /************************************************************************/
1814 :
1815 338 : void GDALRegister_GSAG()
1816 :
1817 : {
1818 : GDALDriver *poDriver;
1819 :
1820 338 : if( GDALGetDriverByName( "GSAG" ) == NULL )
1821 : {
1822 336 : poDriver = new GDALDriver();
1823 :
1824 336 : poDriver->SetDescription( "GSAG" );
1825 : poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
1826 336 : "Golden Software ASCII Grid (.grd)" );
1827 : poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
1828 336 : "frmt_various.html#GSAG" );
1829 336 : poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "grd" );
1830 : poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES,
1831 : "Byte Int16 UInt16 Int32 UInt32 "
1832 336 : "Float32 Float64" );
1833 :
1834 336 : poDriver->pfnOpen = GSAGDataset::Open;
1835 336 : poDriver->pfnCreateCopy = GSAGDataset::CreateCopy;
1836 336 : poDriver->pfnDelete = GSAGDataset::Delete;
1837 :
1838 336 : GetGDALDriverManager()->RegisterDriver( poDriver );
1839 : }
1840 338 : }
|