1 /******************************************************************************
2 * $Id: e00griddataset.cpp 27942 2014-11-11 00:57:41Z rouault $
3 *
4 * Project: E00 grid driver
5 * Purpose: GDALDataset driver for E00 grid dataset.
6 * Author: Even Rouault, <even dot rouault at mines dash paris dot org>
7 *
8 ******************************************************************************
9 * Copyright (c) 2011, Even Rouault <even dot rouault at mines-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 "cpl_vsi_virtual.h"
31 #include "cpl_string.h"
32 #include "ogr_spatialref.h"
33 #include "gdal_pam.h"
34
35 /* Private import of e00read.c */
36 #define E00ReadOpen GDALE00GRIDReadOpen
37 #define E00ReadCallbackOpen GDALE00GRIDReadCallbackOpen
38 #define E00ReadClose GDALE00GRIDReadClose
39 #define E00ReadNextLine GDALE00GRIDReadNextLine
40 #define E00ReadRewind GDALE00GRIDReadRewind
41 #include "e00read.c"
42
43 #define E00_INT_SIZE 10
44 #define E00_INT14_SIZE 14
45 #define E00_FLOAT_SIZE 14
46 #define E00_DOUBLE_SIZE 21
47 #define VALS_PER_LINE 5
48
49 CPL_CVSID("$Id: e00griddataset.cpp 27942 2014-11-11 00:57:41Z rouault $");
50
51 CPL_C_START
52 void GDALRegister_E00GRID(void);
53 CPL_C_END
54
55 /* g++ -fPIC -Wall -g frmts/e00grid/e00griddataset.cpp -shared -o gdal_E00GRID.so -Iport -Igcore -Iogr -L. -lgdal */
56
57 /* Test data ; (google for "EXP 0" "GRD 2")
58
59 ftp://msdis.missouri.edu/pub/dem/24k/county/
60 http://dusk.geo.orst.edu/djl/samoa/data/samoa_bathy.e00
61 http://dusk.geo.orst.edu/djl/samoa/FBNMS/RasterGrids-Metadata/ntae02_3m_utm.e00
62 http://www.navdat.org/coverages/elevation/iddem1.e00 (int32)
63 http://delta-vision.projects.atlas.ca.gov/lidar/bare_earth.grids/sac0165.e00
64 http://ag.arizona.edu/SRER/maps_e00/srer_dem.e00
65 http://ok.water.usgs.gov/projects/norlan/spatial/ntopo0408-10.e00 (compressed)
66 http://wrri.nmsu.edu/publish/techrpt/tr322/GIS/dem.e00 (compressed)
67 */
68
69 /************************************************************************/
70 /* ==================================================================== */
71 /* E00GRIDDataset */
72 /* ==================================================================== */
73 /************************************************************************/
74
75 class E00GRIDRasterBand;
76
77 class E00GRIDDataset : public GDALPamDataset
78 {
79 friend class E00GRIDRasterBand;
80
81 E00ReadPtr e00ReadPtr;
82 VSILFILE *fp;
83 vsi_l_offset nDataStart;
84 int nBytesEOL;
85
86 vsi_l_offset nPosBeforeReadLine;
87 vsi_l_offset* panOffsets;
88 int nLastYOff;
89 int nMaxYOffset;
90
91 double adfGeoTransform[6];
92 CPLString osProjection;
93
94 double dfNoData;
95
96 char** papszPrj;
97
98 const char* ReadLine();
99
100 int bHasReadMetadata;
101 void ReadMetadata();
102
103 int bHasStats;
104 double dfMin, dfMax, dfMean, dfStddev;
105
106 static const char* ReadNextLine(void * ptr);
107 static void Rewind(void* ptr);
108
109 public:
110 E00GRIDDataset();
111 virtual ~E00GRIDDataset();
112
113 virtual CPLErr GetGeoTransform( double * );
114 virtual const char* GetProjectionRef();
115
116 static GDALDataset *Open( GDALOpenInfo * );
117 static int Identify( GDALOpenInfo * );
118 };
119
120 /************************************************************************/
121 /* ==================================================================== */
122 /* E00GRIDRasterBand */
123 /* ==================================================================== */
124 /************************************************************************/
125
126 class E00GRIDRasterBand : public GDALPamRasterBand
127 {
128 friend class E00GRIDDataset;
129
130 public:
131
132 E00GRIDRasterBand( E00GRIDDataset *, int, GDALDataType );
133
134 virtual CPLErr IReadBlock( int, int, void * );
135
136 virtual double GetNoDataValue( int *pbSuccess = NULL );
137 virtual const char *GetUnitType();
138 virtual double GetMinimum( int *pbSuccess = NULL );
139 virtual double GetMaximum( int *pbSuccess = NULL );
140 virtual CPLErr GetStatistics( int bApproxOK, int bForce,
141 double *pdfMin, double *pdfMax,
142 double *pdfMean, double *padfStdDev );
143 };
144
145
146 /************************************************************************/
147 /* E00GRIDRasterBand() */
148 /************************************************************************/
149
E00GRIDRasterBand(E00GRIDDataset * poDS,int nBand,GDALDataType eDT)150 E00GRIDRasterBand::E00GRIDRasterBand( E00GRIDDataset *poDS, int nBand,
151 GDALDataType eDT )
152
153 {
154 this->poDS = poDS;
155 this->nBand = nBand;
156
157 eDataType = eDT;
158
159 nBlockXSize = poDS->GetRasterXSize();
160 nBlockYSize = 1;
161 }
162
163 /************************************************************************/
164 /* IReadBlock() */
165 /************************************************************************/
166
IReadBlock(CPL_UNUSED int nBlockXOff,int nBlockYOff,void * pImage)167 CPLErr E00GRIDRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff,
168 int nBlockYOff,
169 void * pImage )
170 {
171 E00GRIDDataset *poGDS = (E00GRIDDataset *) poDS;
172
173 char szVal[E00_FLOAT_SIZE+1];
174 szVal[E00_FLOAT_SIZE] = 0;
175
176 int i;
177 float* pafImage = (float*)pImage;
178 int* panImage = (int*)pImage;
179 const float fNoData = (const float)poGDS->dfNoData;
180
181 /* A new data line begins on a new text line. So if the xsize */
182 /* is not a multiple of VALS_PER_LINE, there are padding values */
183 /* that must be ignored */
184 const int nRoundedBlockXSize = ((nBlockXSize + VALS_PER_LINE - 1) /
185 VALS_PER_LINE) * VALS_PER_LINE;
186
187 if (poGDS->e00ReadPtr)
188 {
189 if (poGDS->nLastYOff < 0)
190 {
191 E00ReadRewind(poGDS->e00ReadPtr);
192 for(i=0;i<6;i++)
193 E00ReadNextLine(poGDS->e00ReadPtr);
194 }
195
196 if (nBlockYOff == poGDS->nLastYOff + 1)
197 {
198 }
199 else if (nBlockYOff <= poGDS->nMaxYOffset)
200 {
201 //CPLDebug("E00GRID", "Skip to %d from %d", nBlockYOff, poGDS->nLastYOff);
202 VSIFSeekL(poGDS->fp, poGDS->panOffsets[nBlockYOff], SEEK_SET);
203 poGDS->nPosBeforeReadLine = poGDS->panOffsets[nBlockYOff];
204 poGDS->e00ReadPtr->iInBufPtr = 0;
205 poGDS->e00ReadPtr->szInBuf[0] = '\0';
206 }
207 else if (nBlockYOff > poGDS->nLastYOff + 1)
208 {
209 //CPLDebug("E00GRID", "Forward skip to %d from %d", nBlockYOff, poGDS->nLastYOff);
210 for(i=poGDS->nLastYOff + 1; i < nBlockYOff;i++)
211 IReadBlock(0, i, pImage);
212 }
213
214 if (nBlockYOff > poGDS->nMaxYOffset)
215 {
216 poGDS->panOffsets[nBlockYOff] = poGDS->nPosBeforeReadLine +
217 poGDS->e00ReadPtr->iInBufPtr;
218 poGDS->nMaxYOffset = nBlockYOff;
219 }
220
221 const char* pszLine = NULL;
222 for(i=0;i<nBlockXSize;i++)
223 {
224 if ((i % VALS_PER_LINE) == 0)
225 {
226 pszLine = E00ReadNextLine(poGDS->e00ReadPtr);
227 if (pszLine == NULL || strlen(pszLine) < 5 * E00_FLOAT_SIZE)
228 return CE_Failure;
229 }
230 if (eDataType == GDT_Float32)
231 {
232 pafImage[i] = (float) CPLAtof(pszLine + (i%VALS_PER_LINE) * E00_FLOAT_SIZE);
233 /* Workaround single vs double precision problems */
234 if (fNoData != 0 && fabs((pafImage[i] - fNoData)/fNoData) < 1e-6)
235 pafImage[i] = fNoData;
236 }
237 else
238 {
239 panImage[i] = atoi(pszLine + (i%VALS_PER_LINE) * E00_FLOAT_SIZE);
240 }
241 }
242
243 poGDS->nLastYOff = nBlockYOff;
244
245 return CE_None;
246 }
247
248 vsi_l_offset nValsToSkip = (vsi_l_offset)nBlockYOff * nRoundedBlockXSize;
249 vsi_l_offset nLinesToSkip = nValsToSkip / VALS_PER_LINE;
250 int nBytesPerLine = VALS_PER_LINE * E00_FLOAT_SIZE + poGDS->nBytesEOL;
251 vsi_l_offset nPos = poGDS->nDataStart + nLinesToSkip * nBytesPerLine;
252 VSIFSeekL(poGDS->fp, nPos, SEEK_SET);
253
254 for(i=0;i<nBlockXSize;i++)
255 {
256 if (VSIFReadL(szVal, E00_FLOAT_SIZE, 1, poGDS->fp) != 1)
257 return CE_Failure;
258
259 if (eDataType == GDT_Float32)
260 {
261 pafImage[i] = (float) CPLAtof(szVal);
262 /* Workaround single vs double precision problems */
263 if (fNoData != 0 && fabs((pafImage[i] - fNoData)/fNoData) < 1e-6)
264 pafImage[i] = fNoData;
265 }
266 else
267 {
268 panImage[i] = atoi(szVal);
269 }
270
271 if (((i+1) % VALS_PER_LINE) == 0)
272 VSIFReadL(szVal, poGDS->nBytesEOL, 1, poGDS->fp);
273 }
274
275 return CE_None;
276 }
277
278 /************************************************************************/
279 /* GetNoDataValue() */
280 /************************************************************************/
281
GetNoDataValue(int * pbSuccess)282 double E00GRIDRasterBand::GetNoDataValue( int *pbSuccess )
283 {
284 E00GRIDDataset *poGDS = (E00GRIDDataset *) poDS;
285
286 if (pbSuccess)
287 *pbSuccess = TRUE;
288
289 if (eDataType == GDT_Float32)
290 return (double)(float) poGDS->dfNoData;
291 else
292 return (double)(int)poGDS->dfNoData;
293 }
294
295 /************************************************************************/
296 /* GetUnitType() */
297 /************************************************************************/
298
GetUnitType()299 const char * E00GRIDRasterBand::GetUnitType()
300 {
301 E00GRIDDataset *poGDS = (E00GRIDDataset *) poDS;
302
303 poGDS->ReadMetadata();
304
305 if (poGDS->papszPrj == NULL)
306 return GDALPamRasterBand::GetUnitType();
307
308 char** papszIter = poGDS->papszPrj;
309 const char* pszRet = "";
310 while(*papszIter)
311 {
312 if (EQUALN(*papszIter, "Zunits", 6))
313 {
314 char** papszTokens = CSLTokenizeString(*papszIter);
315 if (CSLCount(papszTokens) == 2)
316 {
317 if (EQUAL(papszTokens[1], "FEET"))
318 pszRet = "ft";
319 else if (EQUAL(papszTokens[1], "METERS"))
320 pszRet = "m";
321 }
322 CSLDestroy(papszTokens);
323 break;
324 }
325 papszIter ++;
326 }
327
328 return pszRet;
329 }
330
331 /************************************************************************/
332 /* GetMinimum() */
333 /************************************************************************/
334
GetMinimum(int * pbSuccess)335 double E00GRIDRasterBand::GetMinimum( int *pbSuccess )
336 {
337 E00GRIDDataset *poGDS = (E00GRIDDataset *) poDS;
338
339 poGDS->ReadMetadata();
340
341 if (poGDS->bHasStats)
342 {
343 if( pbSuccess != NULL )
344 *pbSuccess = TRUE;
345
346 return poGDS->dfMin;
347 }
348
349 return GDALPamRasterBand::GetMinimum( pbSuccess );
350 }
351
352 /************************************************************************/
353 /* GetMaximum() */
354 /************************************************************************/
355
GetMaximum(int * pbSuccess)356 double E00GRIDRasterBand::GetMaximum( int *pbSuccess )
357 {
358 E00GRIDDataset *poGDS = (E00GRIDDataset *) poDS;
359
360 poGDS->ReadMetadata();
361
362 if (poGDS->bHasStats)
363 {
364 if( pbSuccess != NULL )
365 *pbSuccess = TRUE;
366
367 return poGDS->dfMax;
368 }
369
370 return GDALPamRasterBand::GetMaximum( pbSuccess );
371 }
372
373 /************************************************************************/
374 /* GetStatistics() */
375 /************************************************************************/
376
GetStatistics(int bApproxOK,int bForce,double * pdfMin,double * pdfMax,double * pdfMean,double * pdfStdDev)377 CPLErr E00GRIDRasterBand::GetStatistics( int bApproxOK, int bForce,
378 double *pdfMin, double *pdfMax,
379 double *pdfMean, double *pdfStdDev )
380 {
381 E00GRIDDataset *poGDS = (E00GRIDDataset *) poDS;
382
383 poGDS->ReadMetadata();
384
385 if (poGDS->bHasStats)
386 {
387 if (pdfMin)
388 *pdfMin = poGDS->dfMin;
389 if (pdfMax)
390 *pdfMax = poGDS->dfMax;
391 if (pdfMean)
392 *pdfMean = poGDS->dfMean;
393 if (pdfStdDev)
394 *pdfStdDev = poGDS->dfStddev;
395 return CE_None;
396 }
397
398 return GDALPamRasterBand::GetStatistics(bApproxOK, bForce,
399 pdfMin, pdfMax,
400 pdfMean, pdfStdDev);
401 }
402
403 /************************************************************************/
404 /* E00GRIDDataset() */
405 /************************************************************************/
406
E00GRIDDataset()407 E00GRIDDataset::E00GRIDDataset()
408 {
409 e00ReadPtr = NULL;
410 fp = NULL;
411 nDataStart = 0;
412 nBytesEOL = 1;
413
414 nPosBeforeReadLine = 0;
415 panOffsets = NULL;
416 nLastYOff = -1;
417 nMaxYOffset = -1;
418
419 adfGeoTransform[0] = 0;
420 adfGeoTransform[1] = 1;
421 adfGeoTransform[2] = 0;
422 adfGeoTransform[3] = 0;
423 adfGeoTransform[4] = 0;
424 adfGeoTransform[5] = 1;
425
426 dfNoData = 0;
427
428 papszPrj = NULL;
429
430 bHasReadMetadata = FALSE;
431
432 bHasStats = FALSE;
433 dfMin = 0;
434 dfMax = 0;
435 dfMean = 0;
436 dfStddev = 0;
437 }
438
439 /************************************************************************/
440 /* ~E00GRIDDataset() */
441 /************************************************************************/
442
~E00GRIDDataset()443 E00GRIDDataset::~E00GRIDDataset()
444
445 {
446 FlushCache();
447 if (fp)
448 VSIFCloseL(fp);
449 CSLDestroy(papszPrj);
450 E00ReadClose(e00ReadPtr);
451 CPLFree(panOffsets);
452 }
453
454 /************************************************************************/
455 /* Identify() */
456 /************************************************************************/
457
Identify(GDALOpenInfo * poOpenInfo)458 int E00GRIDDataset::Identify( GDALOpenInfo * poOpenInfo )
459 {
460 if (poOpenInfo->nHeaderBytes == 0)
461 return FALSE;
462
463 if (!(EQUALN((const char*)poOpenInfo->pabyHeader, "EXP 0", 6) ||
464 EQUALN((const char*)poOpenInfo->pabyHeader, "EXP 1", 6)))
465 return FALSE;
466
467 /* FIXME: handle GRD 3 if that ever exists ? */
468 if (strstr((const char*)poOpenInfo->pabyHeader, "GRD 2") == NULL)
469 return FALSE;
470
471 return TRUE;
472 }
473
474 /************************************************************************/
475 /* ReadNextLine() */
476 /************************************************************************/
477
ReadNextLine(void * ptr)478 const char* E00GRIDDataset::ReadNextLine(void * ptr)
479 {
480 E00GRIDDataset* poDS = (E00GRIDDataset*) ptr;
481 poDS->nPosBeforeReadLine = VSIFTellL(poDS->fp);
482 return CPLReadLine2L(poDS->fp, 256, NULL);
483 }
484
485 /************************************************************************/
486 /* Rewind() */
487 /************************************************************************/
488
Rewind(void * ptr)489 void E00GRIDDataset::Rewind(void * ptr)
490 {
491 E00GRIDDataset* poDS = (E00GRIDDataset*) ptr;
492 VSIRewindL(poDS->fp);
493 }
494
495 /************************************************************************/
496 /* Open() */
497 /************************************************************************/
498
Open(GDALOpenInfo * poOpenInfo)499 GDALDataset *E00GRIDDataset::Open( GDALOpenInfo * poOpenInfo )
500
501 {
502 int i;
503 GDALDataType eDT = GDT_Float32;
504
505 if (!Identify(poOpenInfo))
506 return NULL;
507
508 /* -------------------------------------------------------------------- */
509 /* Find dataset characteristics */
510 /* -------------------------------------------------------------------- */
511 VSILFILE* fp = VSIFOpenL(poOpenInfo->pszFilename, "rb");
512 if (fp == NULL)
513 return NULL;
514
515 if (poOpenInfo->eAccess == GA_Update)
516 {
517 CPLError( CE_Failure, CPLE_NotSupported,
518 "The E00GRID driver does not support update access to existing"
519 " datasets.\n" );
520 VSIFCloseL(fp);
521 return NULL;
522 }
523
524 /* -------------------------------------------------------------------- */
525 /* Create a corresponding GDALDataset. */
526 /* -------------------------------------------------------------------- */
527 E00GRIDDataset *poDS;
528
529 poDS = new E00GRIDDataset();
530 if (strstr((const char*)poOpenInfo->pabyHeader, "\r\n") != NULL)
531 poDS->nBytesEOL = 2;
532 poDS->fp = fp;
533
534 const char* pszLine;
535 /* read EXP 0 or EXP 1 line */
536 pszLine = CPLReadLine2L(fp, 81, NULL);
537 if (pszLine == NULL)
538 {
539 CPLDebug("E00GRID", "Bad 1st line");
540 delete poDS;
541 return NULL;
542 }
543 int bCompressed = EQUALN(pszLine, "EXP 1", 6);
544
545 E00ReadPtr e00ReadPtr = NULL;
546 if (bCompressed)
547 {
548 VSIRewindL(fp);
549 e00ReadPtr = E00ReadCallbackOpen(poDS,
550 E00GRIDDataset::ReadNextLine,
551 E00GRIDDataset::Rewind);
552 if (e00ReadPtr == NULL)
553 {
554 delete poDS;
555 return NULL;
556 }
557 E00ReadNextLine(e00ReadPtr);
558 poDS->e00ReadPtr = e00ReadPtr;
559 }
560
561 /* skip GRD 2 line */
562 if (e00ReadPtr)
563 pszLine = E00ReadNextLine(e00ReadPtr);
564 else
565 pszLine = CPLReadLine2L(fp, 81, NULL);
566 if (pszLine == NULL || !EQUALN(pszLine, "GRD 2", 6))
567 {
568 CPLDebug("E00GRID", "Bad 2nd line");
569 delete poDS;
570 return NULL;
571 }
572
573 /* read ncols, nrows and nodata value */
574 if (e00ReadPtr)
575 pszLine = E00ReadNextLine(e00ReadPtr);
576 else
577 pszLine = CPLReadLine2L(fp, 81, NULL);
578 if (pszLine == NULL || strlen(pszLine) <
579 E00_INT_SIZE+E00_INT_SIZE+2+E00_DOUBLE_SIZE)
580 {
581 CPLDebug("E00GRID", "Bad 3rd line");
582 delete poDS;
583 return NULL;
584 }
585
586 int nRasterXSize = atoi(pszLine);
587 int nRasterYSize = atoi(pszLine + E00_INT_SIZE);
588
589 if (!GDALCheckDatasetDimensions(nRasterXSize, nRasterYSize))
590 {
591 delete poDS;
592 return NULL;
593 }
594
595 if (EQUALN(pszLine + E00_INT_SIZE + E00_INT_SIZE, " 1", 2))
596 eDT = GDT_Int32;
597 else if (EQUALN(pszLine + E00_INT_SIZE + E00_INT_SIZE, " 2", 2))
598 eDT = GDT_Float32;
599 else
600 {
601 CPLDebug("E00GRID", "Unknown data type : %s", pszLine);
602 }
603
604 double dfNoData = CPLAtof(pszLine + E00_INT_SIZE + E00_INT_SIZE + 2);
605
606 /* read pixel size */
607 if (e00ReadPtr)
608 pszLine = E00ReadNextLine(e00ReadPtr);
609 else
610 pszLine = CPLReadLine2L(fp, 81, NULL);
611 if (pszLine == NULL || strlen(pszLine) < 2*E00_DOUBLE_SIZE)
612 {
613 CPLDebug("E00GRID", "Bad 4th line");
614 delete poDS;
615 return NULL;
616 }
617 /*
618 double dfPixelX = CPLAtof(pszLine);
619 double dfPixelY = CPLAtof(pszLine + E00_DOUBLE_SIZE);
620 */
621
622 /* read xmin, ymin */
623 if (e00ReadPtr)
624 pszLine = E00ReadNextLine(e00ReadPtr);
625 else
626 pszLine = CPLReadLine2L(fp, 81, NULL);
627 if (pszLine == NULL || strlen(pszLine) < 2*E00_DOUBLE_SIZE)
628 {
629 CPLDebug("E00GRID", "Bad 5th line");
630 delete poDS;
631 return NULL;
632 }
633 double dfMinX = CPLAtof(pszLine);
634 double dfMinY = CPLAtof(pszLine + E00_DOUBLE_SIZE);
635
636 /* read xmax, ymax */
637 if (e00ReadPtr)
638 pszLine = E00ReadNextLine(e00ReadPtr);
639 else
640 pszLine = CPLReadLine2L(fp, 81, NULL);
641 if (pszLine == NULL || strlen(pszLine) < 2*E00_DOUBLE_SIZE)
642 {
643 CPLDebug("E00GRID", "Bad 6th line");
644 delete poDS;
645 return NULL;
646 }
647 double dfMaxX = CPLAtof(pszLine);
648 double dfMaxY = CPLAtof(pszLine + E00_DOUBLE_SIZE);
649
650 poDS->nRasterXSize = nRasterXSize;
651 poDS->nRasterYSize = nRasterYSize;
652 poDS->dfNoData = dfNoData;
653 poDS->adfGeoTransform[0] = dfMinX;
654 poDS->adfGeoTransform[1] = (dfMaxX - dfMinX) / nRasterXSize;
655 poDS->adfGeoTransform[2] = 0;
656 poDS->adfGeoTransform[3] = dfMaxY;
657 poDS->adfGeoTransform[4] = 0;
658 poDS->adfGeoTransform[5] = - (dfMaxY - dfMinY) / nRasterYSize;
659 poDS->nDataStart = VSIFTellL(fp);
660 if (bCompressed)
661 {
662 poDS->panOffsets = (vsi_l_offset*)
663 VSIMalloc2(sizeof(vsi_l_offset), nRasterYSize);
664 if (poDS->panOffsets == NULL)
665 {
666 delete poDS;
667 return NULL;
668 }
669 }
670 /* -------------------------------------------------------------------- */
671 /* Create band information objects. */
672 /* -------------------------------------------------------------------- */
673 poDS->nBands = 1;
674 for( i = 0; i < poDS->nBands; i++ )
675 poDS->SetBand( i+1, new E00GRIDRasterBand( poDS, i+1, eDT ) );
676
677 /* -------------------------------------------------------------------- */
678 /* Initialize any PAM information. */
679 /* -------------------------------------------------------------------- */
680 poDS->SetDescription( poOpenInfo->pszFilename );
681 poDS->TryLoadXML();
682
683 /* -------------------------------------------------------------------- */
684 /* Support overviews. */
685 /* -------------------------------------------------------------------- */
686 poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
687 return( poDS );
688 }
689
690 /************************************************************************/
691 /* GetGeoTransform() */
692 /************************************************************************/
693
GetGeoTransform(double * padfTransform)694 CPLErr E00GRIDDataset::GetGeoTransform( double * padfTransform )
695
696 {
697 memcpy(padfTransform, adfGeoTransform, 6 * sizeof(double));
698
699 return( CE_None );
700 }
701
702
703 /************************************************************************/
704 /* ReadLine() */
705 /************************************************************************/
706
ReadLine()707 const char* E00GRIDDataset::ReadLine()
708 {
709 if (e00ReadPtr)
710 return E00ReadNextLine(e00ReadPtr);
711 else
712 return CPLReadLine2L(fp, 81, NULL);
713 }
714
715 /************************************************************************/
716 /* GetProjectionRef() */
717 /************************************************************************/
718
GetProjectionRef()719 const char* E00GRIDDataset::GetProjectionRef()
720
721 {
722 ReadMetadata();
723 return osProjection.c_str();
724 }
725
726 /************************************************************************/
727 /* ReadMetadata() */
728 /************************************************************************/
729
ReadMetadata()730 void E00GRIDDataset::ReadMetadata()
731
732 {
733 if (bHasReadMetadata)
734 return;
735
736 bHasReadMetadata = TRUE;
737
738 if (e00ReadPtr == NULL)
739 {
740 int nRoundedBlockXSize = ((nRasterXSize + VALS_PER_LINE - 1) /
741 VALS_PER_LINE) * VALS_PER_LINE;
742 vsi_l_offset nValsToSkip =
743 (vsi_l_offset)nRasterYSize * nRoundedBlockXSize;
744 vsi_l_offset nLinesToSkip = nValsToSkip / VALS_PER_LINE;
745 int nBytesPerLine = VALS_PER_LINE * E00_FLOAT_SIZE + nBytesEOL;
746 vsi_l_offset nPos = nDataStart + nLinesToSkip * nBytesPerLine;
747 VSIFSeekL(fp, nPos, SEEK_SET);
748 }
749 else
750 {
751 nLastYOff = -1;
752
753 const unsigned int BUFFER_SIZE = 65536;
754 const unsigned int NEEDLE_SIZE = 3*5;
755 const unsigned int nToRead = BUFFER_SIZE - NEEDLE_SIZE;
756 char* pabyBuffer = (char*)CPLCalloc(1, BUFFER_SIZE+NEEDLE_SIZE);
757 int nRead;
758 int bEOGFound = FALSE;
759
760 VSIFSeekL(fp, 0, SEEK_END);
761 vsi_l_offset nEndPos = VSIFTellL(fp);
762 if (nEndPos > BUFFER_SIZE)
763 nEndPos -= BUFFER_SIZE;
764 else
765 nEndPos = 0;
766 VSIFSeekL(fp, nEndPos, SEEK_SET);
767
768 #define GOTO_NEXT_CHAR() \
769 i ++; \
770 if (pabyBuffer[i] == 13 || pabyBuffer[i] == 10) \
771 { \
772 i++; \
773 if (pabyBuffer[i] == 10) \
774 i++; \
775 } \
776
777 while ((nRead = VSIFReadL(pabyBuffer, 1, nToRead, fp)) != 0)
778 {
779 int i;
780 for(i = 0; i < nRead; i++)
781 {
782 if (pabyBuffer[i] == 'E')
783 {
784 GOTO_NEXT_CHAR();
785 if (pabyBuffer[i] == 'O')
786 {
787 GOTO_NEXT_CHAR();
788 if (pabyBuffer[i] == 'G')
789 {
790 GOTO_NEXT_CHAR();
791 if (pabyBuffer[i] == '~')
792 {
793 GOTO_NEXT_CHAR();
794 if (pabyBuffer[i] == '}')
795 {
796 bEOGFound = TRUE;
797 break;
798 }
799 }
800 }
801 }
802 }
803 }
804
805 if (bEOGFound)
806 {
807 VSIFSeekL(fp, VSIFTellL(fp) - nRead + i + 1, SEEK_SET);
808 e00ReadPtr->iInBufPtr = 0;
809 e00ReadPtr->szInBuf[0] = '\0';
810 break;
811 }
812
813 if (nEndPos == 0)
814 break;
815
816 if ((unsigned int)nRead == nToRead)
817 {
818 memmove(pabyBuffer + nToRead, pabyBuffer, NEEDLE_SIZE);
819 if (nEndPos >= (vsi_l_offset)nToRead)
820 nEndPos -= nToRead;
821 else
822 nEndPos = 0;
823 VSIFSeekL(fp, nEndPos, SEEK_SET);
824 }
825 else
826 break;
827 }
828 CPLFree(pabyBuffer);
829 if (!bEOGFound)
830 return;
831 }
832
833 const char* pszLine;
834 int bPRJFound = FALSE;
835 int bStatsFound = FALSE;
836 while((pszLine = ReadLine()) != NULL)
837 {
838 if (EQUALN(pszLine, "PRJ 2", 6))
839 {
840 bPRJFound = TRUE;
841 while((pszLine = ReadLine()) != NULL)
842 {
843 if (EQUAL(pszLine, "EOP"))
844 {
845 break;
846 }
847 papszPrj = CSLAddString(papszPrj, pszLine);
848 }
849
850 OGRSpatialReference oSRS;
851 if( oSRS.importFromESRI( papszPrj ) != OGRERR_NONE )
852 {
853 CPLError( CE_Warning, CPLE_AppDefined,
854 "Failed to parse PRJ section, ignoring." );
855 }
856 else
857 {
858 char* pszWKT = NULL;
859 if (oSRS.exportToWkt(&pszWKT) == OGRERR_NONE && pszWKT != NULL)
860 osProjection = pszWKT;
861 CPLFree(pszWKT);
862 }
863 if (bStatsFound)
864 break;
865 }
866 else if (strcmp(pszLine, "STDV 8-1 254-1 15 3 60-1 -1 -1-1 4-") == 0)
867 {
868 bStatsFound = TRUE;
869 pszLine = ReadLine();
870 if (pszLine)
871 {
872 CPLString osStats = pszLine;
873 pszLine = ReadLine();
874 if (pszLine)
875 {
876 osStats += pszLine;
877 char** papszTokens = CSLTokenizeString(osStats);
878 if (CSLCount(papszTokens) == 4)
879 {
880 dfMin = CPLAtof(papszTokens[0]);
881 dfMax = CPLAtof(papszTokens[1]);
882 dfMean = CPLAtof(papszTokens[2]);
883 dfStddev = CPLAtof(papszTokens[3]);
884 bHasStats = TRUE;
885 }
886 CSLDestroy(papszTokens);
887 }
888 }
889 if (bPRJFound)
890 break;
891 }
892 }
893 }
894
895 /************************************************************************/
896 /* GDALRegister_E00GRID() */
897 /************************************************************************/
898
GDALRegister_E00GRID()899 void GDALRegister_E00GRID()
900
901 {
902 GDALDriver *poDriver;
903
904 if( GDALGetDriverByName( "E00GRID" ) == NULL )
905 {
906 poDriver = new GDALDriver();
907
908 poDriver->SetDescription( "E00GRID" );
909 poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
910 poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
911 "Arc/Info Export E00 GRID" );
912 poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
913 "frmt_various.html#E00GRID" );
914 poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "e00" );
915
916
917 poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
918
919 poDriver->pfnOpen = E00GRIDDataset::Open;
920 poDriver->pfnIdentify = E00GRIDDataset::Identify;
921
922 GetGDALDriverManager()->RegisterDriver( poDriver );
923 }
924 }
925