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