Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: ELAS Translator
4 : * Purpose: Complete implementation of ELAS translator module for GDAL.
5 : * Author: Frank Warmerdam, warmerdam@pobox.com
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 1999, Frank Warmerdam
9 : * Copyright (c) 2008-2011, Even Rouault <even dot rouault at spatialys.com>
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #include "gdal_frmts.h"
31 : #include "gdal_pam.h"
32 :
33 : #include <cmath>
34 : #include <algorithm>
35 : #include <limits>
36 :
37 : using std::fill;
38 :
39 : typedef struct ELASHeader
40 : {
41 : ELASHeader();
42 :
43 : GInt32 NBIH; /* bytes in header, normally 1024 */
44 : GInt32 NBPR; /* bytes per data record (all bands of scanline) */
45 : GInt32 IL; /* initial line - normally 1 */
46 : GInt32 LL; /* last line */
47 : GInt32 IE; /* initial element (pixel), normally 1 */
48 : GInt32 LE; /* last element (pixel) */
49 : GInt32 NC; /* number of channels (bands) */
50 : GUInt32 H4321; /* header record identifier - always 4321. */
51 : char YLabel[4]; /* Should be "NOR" for UTM */
52 : GInt32 YOffset; /* topleft pixel center northing */
53 : char XLabel[4]; /* Should be "EAS" for UTM */
54 : GInt32 XOffset; /* topleft pixel center easting */
55 : float YPixSize; /* height of pixel in georef units */
56 : float XPixSize; /* width of pixel in georef units */
57 : float Matrix[4]; /* 2x2 transformation matrix. Should be
58 : 1,0,0,1 for pixel/line, or
59 : 1,0,0,-1 for UTM */
60 : GByte IH19[4]; /* data type, and size flags */
61 : GInt32 IH20; /* number of secondary headers */
62 : char unused1[8];
63 : GInt32 LABL; /* used by LABL module */
64 : char HEAD; /* used by HEAD module */
65 : char Comment1[64];
66 : char Comment2[64];
67 : char Comment3[64];
68 : char Comment4[64];
69 : char Comment5[64];
70 : char Comment6[64];
71 : GUInt16 ColorTable[256]; /* RGB packed with 4 bits each */
72 : char unused2[32];
73 : } _ELASHeader;
74 :
75 48 : ELASHeader::ELASHeader()
76 : : NBIH(0), NBPR(0), IL(0), LL(0), IE(0), LE(0), NC(0), H4321(0), YOffset(0),
77 48 : XOffset(0), YPixSize(0.0), XPixSize(0.0), IH20(0), LABL(0), HEAD(0)
78 : {
79 48 : fill(YLabel, YLabel + CPL_ARRAYSIZE(YLabel), static_cast<char>(0));
80 48 : fill(XLabel, XLabel + CPL_ARRAYSIZE(XLabel), static_cast<char>(0));
81 48 : fill(Matrix, Matrix + CPL_ARRAYSIZE(Matrix), 0.f);
82 48 : fill(IH19, IH19 + CPL_ARRAYSIZE(IH19), static_cast<GByte>(0));
83 48 : fill(unused1, unused1 + CPL_ARRAYSIZE(unused1), static_cast<char>(0));
84 48 : fill(Comment1, Comment1 + CPL_ARRAYSIZE(Comment1), static_cast<char>(0));
85 48 : fill(Comment2, Comment2 + CPL_ARRAYSIZE(Comment2), static_cast<char>(0));
86 48 : fill(Comment3, Comment3 + CPL_ARRAYSIZE(Comment3), static_cast<char>(0));
87 48 : fill(Comment4, Comment4 + CPL_ARRAYSIZE(Comment4), static_cast<char>(0));
88 48 : fill(Comment5, Comment5 + CPL_ARRAYSIZE(Comment5), static_cast<char>(0));
89 48 : fill(Comment6, Comment6 + CPL_ARRAYSIZE(Comment6), static_cast<char>(0));
90 48 : fill(ColorTable, ColorTable + CPL_ARRAYSIZE(ColorTable),
91 48 : static_cast<GUInt16>(0));
92 48 : fill(unused2, unused2 + CPL_ARRAYSIZE(unused2), static_cast<char>(0));
93 48 : }
94 :
95 : /************************************************************************/
96 : /* ==================================================================== */
97 : /* ELASDataset */
98 : /* ==================================================================== */
99 : /************************************************************************/
100 :
101 : class ELASRasterBand;
102 :
103 : class ELASDataset final : public GDALPamDataset
104 : {
105 : friend class ELASRasterBand;
106 :
107 : VSILFILE *fp;
108 :
109 : ELASHeader sHeader;
110 : int bHeaderModified;
111 :
112 : GDALDataType eRasterDataType;
113 :
114 : int nLineOffset;
115 : int nBandOffset; // Within a line.
116 :
117 : double adfGeoTransform[6];
118 :
119 : public:
120 : ELASDataset();
121 : ~ELASDataset() override;
122 :
123 : CPLErr GetGeoTransform(double *) override;
124 : CPLErr SetGeoTransform(double *) override;
125 :
126 : static GDALDataset *Open(GDALOpenInfo *);
127 : static int Identify(GDALOpenInfo *);
128 : static GDALDataset *Create(const char *pszFilename, int nXSize, int nYSize,
129 : int nBandsIn, GDALDataType eType,
130 : char **papszParamList);
131 :
132 : CPLErr FlushCache(bool bAtClosing) override;
133 : };
134 :
135 : /************************************************************************/
136 : /* ==================================================================== */
137 : /* ELASRasterBand */
138 : /* ==================================================================== */
139 : /************************************************************************/
140 :
141 : class ELASRasterBand final : public GDALPamRasterBand
142 : {
143 : friend class ELASDataset;
144 :
145 : public:
146 : ELASRasterBand(ELASDataset *, int);
147 :
148 : // should override RasterIO eventually.
149 :
150 : CPLErr IReadBlock(int, int, void *) override;
151 : CPLErr IWriteBlock(int, int, void *) override;
152 : };
153 :
154 : /************************************************************************/
155 : /* ELASRasterBand() */
156 : /************************************************************************/
157 :
158 69 : ELASRasterBand::ELASRasterBand(ELASDataset *poDSIn, int nBandIn)
159 :
160 : {
161 69 : poDS = poDSIn;
162 69 : nBand = nBandIn;
163 :
164 69 : eAccess = poDSIn->eAccess;
165 :
166 69 : eDataType = poDSIn->eRasterDataType;
167 :
168 69 : nBlockXSize = poDS->GetRasterXSize();
169 69 : nBlockYSize = 1;
170 69 : }
171 :
172 : /************************************************************************/
173 : /* IReadBlock() */
174 : /************************************************************************/
175 :
176 60 : CPLErr ELASRasterBand::IReadBlock(CPL_UNUSED int nBlockXOff, int nBlockYOff,
177 : void *pImage)
178 : {
179 60 : CPLAssert(nBlockXOff == 0);
180 :
181 60 : ELASDataset *poGDS = (ELASDataset *)poDS;
182 :
183 : int nDataSize =
184 60 : GDALGetDataTypeSizeBytes(eDataType) * poGDS->GetRasterXSize();
185 60 : long nOffset =
186 60 : poGDS->nLineOffset * nBlockYOff + 1024 + (nBand - 1) * nDataSize;
187 :
188 : /* -------------------------------------------------------------------- */
189 : /* If we can't seek to the data, we will assume this is a newly */
190 : /* created file, and that the file hasn't been extended yet. */
191 : /* Just read as zeros. */
192 : /* -------------------------------------------------------------------- */
193 120 : if (VSIFSeekL(poGDS->fp, nOffset, SEEK_SET) != 0 ||
194 60 : VSIFReadL(pImage, 1, nDataSize, poGDS->fp) != (size_t)nDataSize)
195 : {
196 0 : CPLError(CE_Failure, CPLE_FileIO,
197 : "Seek or read of %d bytes at %ld failed.\n", nDataSize,
198 : nOffset);
199 0 : return CE_Failure;
200 : }
201 :
202 60 : return CE_None;
203 : }
204 :
205 : /************************************************************************/
206 : /* IWriteBlock() */
207 : /************************************************************************/
208 :
209 190 : CPLErr ELASRasterBand::IWriteBlock(CPL_UNUSED int nBlockXOff, int nBlockYOff,
210 : void *pImage)
211 : {
212 190 : CPLAssert(nBlockXOff == 0);
213 190 : CPLAssert(eAccess == GA_Update);
214 :
215 190 : ELASDataset *poGDS = (ELASDataset *)poDS;
216 :
217 : int nDataSize =
218 190 : GDALGetDataTypeSizeBytes(eDataType) * poGDS->GetRasterXSize();
219 190 : long nOffset =
220 190 : poGDS->nLineOffset * nBlockYOff + 1024 + (nBand - 1) * nDataSize;
221 :
222 380 : if (VSIFSeekL(poGDS->fp, nOffset, SEEK_SET) != 0 ||
223 190 : VSIFWriteL(pImage, 1, nDataSize, poGDS->fp) != (size_t)nDataSize)
224 : {
225 0 : CPLError(CE_Failure, CPLE_FileIO,
226 : "Seek or write of %d bytes at %ld failed.\n", nDataSize,
227 : nOffset);
228 0 : return CE_Failure;
229 : }
230 :
231 190 : return CE_None;
232 : }
233 :
234 : /************************************************************************/
235 : /* ==================================================================== */
236 : /* ELASDataset */
237 : /* ==================================================================== */
238 : /************************************************************************/
239 :
240 : /************************************************************************/
241 : /* ELASDataset() */
242 : /************************************************************************/
243 :
244 31 : ELASDataset::ELASDataset()
245 : : fp(nullptr), bHeaderModified(0), eRasterDataType(GDT_Unknown),
246 31 : nLineOffset(0), nBandOffset(0)
247 : {
248 31 : adfGeoTransform[0] = 0.0;
249 31 : adfGeoTransform[1] = 1.0;
250 31 : adfGeoTransform[2] = 0.0;
251 31 : adfGeoTransform[3] = 0.0;
252 31 : adfGeoTransform[4] = 0.0;
253 31 : adfGeoTransform[5] = 1.0;
254 31 : }
255 :
256 : /************************************************************************/
257 : /* ~ELASDataset() */
258 : /************************************************************************/
259 :
260 62 : ELASDataset::~ELASDataset()
261 :
262 : {
263 31 : ELASDataset::FlushCache(true);
264 :
265 31 : if (fp != nullptr)
266 : {
267 31 : CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
268 : }
269 62 : }
270 :
271 : /************************************************************************/
272 : /* FlushCache() */
273 : /* */
274 : /* We also write out the header, if it is modified. */
275 : /************************************************************************/
276 :
277 32 : CPLErr ELASDataset::FlushCache(bool bAtClosing)
278 :
279 : {
280 32 : CPLErr eErr = GDALDataset::FlushCache(bAtClosing);
281 :
282 32 : if (bHeaderModified)
283 : {
284 32 : if (VSIFSeekL(fp, 0, SEEK_SET) != 0 ||
285 16 : VSIFWriteL(&sHeader, 1024, 1, fp) != 1)
286 : {
287 0 : eErr = CE_Failure;
288 : }
289 16 : bHeaderModified = FALSE;
290 : }
291 32 : return eErr;
292 : }
293 :
294 : /************************************************************************/
295 : /* Identify() */
296 : /************************************************************************/
297 :
298 54034 : int ELASDataset::Identify(GDALOpenInfo *poOpenInfo)
299 :
300 : {
301 : /* -------------------------------------------------------------------- */
302 : /* First we check to see if the file has the expected header */
303 : /* bytes. */
304 : /* -------------------------------------------------------------------- */
305 54034 : if (poOpenInfo->nHeaderBytes < 256)
306 47813 : return FALSE;
307 :
308 6221 : if (CPL_MSBWORD32(*((GInt32 *)(poOpenInfo->pabyHeader + 0))) != 1024 ||
309 62 : CPL_MSBWORD32(*((GInt32 *)(poOpenInfo->pabyHeader + 28))) != 4321)
310 : {
311 6159 : return FALSE;
312 : }
313 :
314 62 : return TRUE;
315 : }
316 :
317 : /************************************************************************/
318 : /* Open() */
319 : /************************************************************************/
320 :
321 31 : GDALDataset *ELASDataset::Open(GDALOpenInfo *poOpenInfo)
322 :
323 : {
324 31 : if (!Identify(poOpenInfo) || poOpenInfo->fpL == nullptr)
325 0 : return nullptr;
326 :
327 : /* -------------------------------------------------------------------- */
328 : /* Create a corresponding GDALDataset. */
329 : /* -------------------------------------------------------------------- */
330 :
331 31 : ELASDataset *poDS = new ELASDataset();
332 31 : poDS->eAccess = poOpenInfo->eAccess;
333 31 : poDS->fp = poOpenInfo->fpL;
334 31 : poOpenInfo->fpL = nullptr;
335 :
336 : /* -------------------------------------------------------------------- */
337 : /* Read the header information. */
338 : /* -------------------------------------------------------------------- */
339 31 : poDS->bHeaderModified = FALSE;
340 31 : if (VSIFReadL(&(poDS->sHeader), 1024, 1, poDS->fp) != 1)
341 : {
342 0 : CPLError(CE_Failure, CPLE_FileIO,
343 : "Attempt to read 1024 byte header filed on file %s\n",
344 : poOpenInfo->pszFilename);
345 0 : delete poDS;
346 0 : return nullptr;
347 : }
348 :
349 : /* -------------------------------------------------------------------- */
350 : /* Extract information of interest from the header. */
351 : /* -------------------------------------------------------------------- */
352 31 : poDS->nLineOffset = CPL_MSBWORD32(poDS->sHeader.NBPR);
353 :
354 31 : int nStart = CPL_MSBWORD32(poDS->sHeader.IL);
355 31 : int nEnd = CPL_MSBWORD32(poDS->sHeader.LL);
356 31 : GIntBig nDiff = static_cast<GIntBig>(nEnd) - nStart + 1;
357 :
358 31 : if (nDiff <= 0 || nDiff > std::numeric_limits<int>::max())
359 : {
360 0 : delete poDS;
361 0 : return nullptr;
362 : }
363 31 : poDS->nRasterYSize = static_cast<int>(nDiff);
364 :
365 31 : nStart = CPL_MSBWORD32(poDS->sHeader.IE);
366 31 : nEnd = CPL_MSBWORD32(poDS->sHeader.LE);
367 31 : nDiff = static_cast<GIntBig>(nEnd) - nStart + 1;
368 31 : if (nDiff <= 0 || nDiff > std::numeric_limits<int>::max())
369 : {
370 0 : delete poDS;
371 0 : return nullptr;
372 : }
373 31 : poDS->nRasterXSize = static_cast<int>(nDiff);
374 :
375 31 : poDS->nBands = CPL_MSBWORD32(poDS->sHeader.NC);
376 :
377 62 : if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize) ||
378 31 : !GDALCheckBandCount(poDS->nBands, FALSE))
379 : {
380 0 : delete poDS;
381 0 : return nullptr;
382 : }
383 :
384 31 : const int nELASDataType = (poDS->sHeader.IH19[2] & 0x7e) >> 2;
385 31 : const int nBytesPerSample = poDS->sHeader.IH19[3];
386 :
387 31 : if (nELASDataType == 0 && nBytesPerSample == 1)
388 0 : poDS->eRasterDataType = GDT_Byte;
389 31 : else if (nELASDataType == 1 && nBytesPerSample == 1)
390 21 : poDS->eRasterDataType = GDT_Byte;
391 10 : else if (nELASDataType == 16 && nBytesPerSample == 4)
392 5 : poDS->eRasterDataType = GDT_Float32;
393 5 : else if (nELASDataType == 17 && nBytesPerSample == 8)
394 5 : poDS->eRasterDataType = GDT_Float64;
395 : else
396 : {
397 0 : delete poDS;
398 0 : CPLError(CE_Failure, CPLE_AppDefined,
399 : "Unrecognized image data type %d, with BytesPerSample=%d.\n",
400 : nELASDataType, nBytesPerSample);
401 0 : return nullptr;
402 : }
403 :
404 : /* -------------------------------------------------------------------- */
405 : /* Band offsets are always multiples of 256 within a multi-band */
406 : /* scanline of data. */
407 : /* -------------------------------------------------------------------- */
408 31 : if (GDALGetDataTypeSizeBytes(poDS->eRasterDataType) >
409 31 : (std::numeric_limits<int>::max() - 256) / poDS->nRasterXSize)
410 : {
411 0 : delete poDS;
412 0 : return nullptr;
413 : }
414 31 : poDS->nBandOffset =
415 31 : (poDS->nRasterXSize * GDALGetDataTypeSizeBytes(poDS->eRasterDataType));
416 :
417 31 : if (poDS->nBandOffset > 1000000)
418 : {
419 0 : VSIFSeekL(poDS->fp, 0, SEEK_END);
420 0 : if (VSIFTellL(poDS->fp) < static_cast<vsi_l_offset>(poDS->nBandOffset))
421 : {
422 0 : CPLError(CE_Failure, CPLE_FileIO, "File too short");
423 0 : delete poDS;
424 0 : return nullptr;
425 : }
426 : }
427 :
428 31 : if (poDS->nBandOffset % 256 != 0)
429 : {
430 31 : poDS->nBandOffset = poDS->nBandOffset - (poDS->nBandOffset % 256) + 256;
431 : }
432 :
433 : /* -------------------------------------------------------------------- */
434 : /* Create band information objects. */
435 : /* -------------------------------------------------------------------- */
436 : /* coverity[tainted_data] */
437 100 : for (int iBand = 0; iBand < poDS->nBands; iBand++)
438 : {
439 69 : poDS->SetBand(iBand + 1, new ELASRasterBand(poDS, iBand + 1));
440 : }
441 :
442 : /* -------------------------------------------------------------------- */
443 : /* Extract the projection coordinates, if present. */
444 : /* -------------------------------------------------------------------- */
445 31 : if (poDS->sHeader.XOffset != 0)
446 : {
447 12 : CPL_MSBPTR32(&(poDS->sHeader.XPixSize));
448 12 : CPL_MSBPTR32(&(poDS->sHeader.YPixSize));
449 :
450 12 : poDS->adfGeoTransform[0] = (GInt32)CPL_MSBWORD32(poDS->sHeader.XOffset);
451 12 : poDS->adfGeoTransform[1] = poDS->sHeader.XPixSize;
452 12 : poDS->adfGeoTransform[2] = 0.0;
453 12 : poDS->adfGeoTransform[3] = (GInt32)CPL_MSBWORD32(poDS->sHeader.YOffset);
454 12 : poDS->adfGeoTransform[4] = 0.0;
455 12 : poDS->adfGeoTransform[5] = -1.0 * std::abs(poDS->sHeader.YPixSize);
456 :
457 12 : CPL_MSBPTR32(&(poDS->sHeader.XPixSize));
458 12 : CPL_MSBPTR32(&(poDS->sHeader.YPixSize));
459 :
460 12 : poDS->adfGeoTransform[0] -= poDS->adfGeoTransform[1] * 0.5;
461 12 : poDS->adfGeoTransform[3] -= poDS->adfGeoTransform[5] * 0.5;
462 : }
463 : else
464 : {
465 19 : poDS->adfGeoTransform[0] = 0.0;
466 19 : poDS->adfGeoTransform[1] = 1.0;
467 19 : poDS->adfGeoTransform[2] = 0.0;
468 19 : poDS->adfGeoTransform[3] = 0.0;
469 19 : poDS->adfGeoTransform[4] = 0.0;
470 19 : poDS->adfGeoTransform[5] = 1.0;
471 : }
472 :
473 : /* -------------------------------------------------------------------- */
474 : /* Initialize any PAM information. */
475 : /* -------------------------------------------------------------------- */
476 31 : poDS->SetDescription(poOpenInfo->pszFilename);
477 31 : poDS->TryLoadXML();
478 :
479 : /* -------------------------------------------------------------------- */
480 : /* Check for external overviews. */
481 : /* -------------------------------------------------------------------- */
482 31 : poDS->oOvManager.Initialize(poDS, poOpenInfo->pszFilename,
483 : poOpenInfo->GetSiblingFiles());
484 :
485 31 : return poDS;
486 : }
487 :
488 : /************************************************************************/
489 : /* Create() */
490 : /* */
491 : /* Create a new GeoTIFF or TIFF file. */
492 : /************************************************************************/
493 :
494 61 : GDALDataset *ELASDataset::Create(const char *pszFilename, int nXSize,
495 : int nYSize, int nBandsIn, GDALDataType eType,
496 : char ** /* notdef: papszParamList */)
497 :
498 : {
499 : /* -------------------------------------------------------------------- */
500 : /* Verify input options. */
501 : /* -------------------------------------------------------------------- */
502 61 : if (nBandsIn <= 0)
503 : {
504 1 : CPLError(CE_Failure, CPLE_NotSupported,
505 : "ELAS driver does not support %d bands.\n", nBandsIn);
506 1 : return nullptr;
507 : }
508 :
509 60 : if (eType != GDT_Byte && eType != GDT_Float32 && eType != GDT_Float64)
510 : {
511 30 : CPLError(CE_Failure, CPLE_AppDefined,
512 : "Attempt to create an ELAS dataset with an illegal\n"
513 : "data type (%d).\n",
514 : eType);
515 :
516 30 : return nullptr;
517 : }
518 :
519 : /* -------------------------------------------------------------------- */
520 : /* Try to create the file. */
521 : /* -------------------------------------------------------------------- */
522 30 : FILE *fp = VSIFOpen(pszFilename, "w");
523 :
524 30 : if (fp == nullptr)
525 : {
526 13 : CPLError(CE_Failure, CPLE_OpenFailed,
527 : "Attempt to create file `%s' failed.\n", pszFilename);
528 13 : return nullptr;
529 : }
530 :
531 : /* -------------------------------------------------------------------- */
532 : /* How long will each band of a scanline be? */
533 : /* -------------------------------------------------------------------- */
534 17 : int nBandOffset = nXSize * GDALGetDataTypeSizeBytes(eType);
535 :
536 17 : if (nBandOffset % 256 != 0)
537 : {
538 17 : nBandOffset = nBandOffset - (nBandOffset % 256) + 256;
539 : }
540 :
541 : /* -------------------------------------------------------------------- */
542 : /* Setup header data block. */
543 : /* */
544 : /* Note that CPL_MSBWORD32() will swap little endian words to */
545 : /* big endian on little endian platforms. */
546 : /* -------------------------------------------------------------------- */
547 17 : ELASHeader sHeader;
548 :
549 17 : sHeader.NBIH = CPL_MSBWORD32(1024);
550 :
551 17 : sHeader.NBPR = CPL_MSBWORD32(nBandsIn * nBandOffset);
552 :
553 17 : sHeader.IL = CPL_MSBWORD32(1);
554 17 : sHeader.LL = CPL_MSBWORD32(nYSize);
555 :
556 17 : sHeader.IE = CPL_MSBWORD32(1);
557 17 : sHeader.LE = CPL_MSBWORD32(nXSize);
558 :
559 17 : sHeader.NC = CPL_MSBWORD32(nBandsIn);
560 :
561 17 : sHeader.H4321 = CPL_MSBWORD32(4321);
562 :
563 17 : sHeader.IH19[0] = 0x04;
564 17 : sHeader.IH19[1] = 0xd2;
565 17 : sHeader.IH19[3] = (GByte)(GDALGetDataTypeSizeBytes(eType));
566 :
567 17 : if (eType == GDT_Byte)
568 11 : sHeader.IH19[2] = 1 << 2;
569 6 : else if (eType == GDT_Float32)
570 3 : sHeader.IH19[2] = 16 << 2;
571 3 : else if (eType == GDT_Float64)
572 3 : sHeader.IH19[2] = 17 << 2;
573 :
574 : /* -------------------------------------------------------------------- */
575 : /* Write the header data. */
576 : /* -------------------------------------------------------------------- */
577 17 : CPL_IGNORE_RET_VAL(VSIFWrite(&sHeader, 1024, 1, fp));
578 :
579 : /* -------------------------------------------------------------------- */
580 : /* Now write out zero data for all the imagery. This is */
581 : /* inefficient, but simplifies IReadBlock() / IWriteBlock() logic. */
582 : /* -------------------------------------------------------------------- */
583 17 : GByte *pabyLine = (GByte *)CPLCalloc(nBandOffset, nBandsIn);
584 1007 : for (int iLine = 0; iLine < nYSize; iLine++)
585 : {
586 990 : if (VSIFWrite(pabyLine, 1, nBandOffset, fp) != (size_t)nBandOffset)
587 : {
588 0 : CPLError(CE_Failure, CPLE_FileIO,
589 : "Error writing ELAS image data ... likely insufficient"
590 : " disk space.\n");
591 0 : VSIFClose(fp);
592 0 : CPLFree(pabyLine);
593 0 : return nullptr;
594 : }
595 : }
596 :
597 17 : CPLFree(pabyLine);
598 :
599 17 : VSIFClose(fp);
600 :
601 : /* -------------------------------------------------------------------- */
602 : /* Try to return a regular handle on the file. */
603 : /* -------------------------------------------------------------------- */
604 17 : return (GDALDataset *)GDALOpen(pszFilename, GA_Update);
605 : }
606 :
607 : /************************************************************************/
608 : /* GetGeoTransform() */
609 : /************************************************************************/
610 :
611 9 : CPLErr ELASDataset::GetGeoTransform(double *padfTransform)
612 :
613 : {
614 9 : memcpy(padfTransform, adfGeoTransform, sizeof(double) * 6);
615 :
616 9 : return CE_None;
617 : }
618 :
619 : /************************************************************************/
620 : /* SetGeoTransform() */
621 : /************************************************************************/
622 :
623 16 : CPLErr ELASDataset::SetGeoTransform(double *padfTransform)
624 :
625 : {
626 : /* -------------------------------------------------------------------- */
627 : /* I don't think it supports rotation, but perhaps it is possible */
628 : /* for us to use the 2x2 transform matrix to accomplish some */
629 : /* sort of rotation. */
630 : /* -------------------------------------------------------------------- */
631 16 : if (padfTransform[2] != 0.0 || padfTransform[4] != 0.0)
632 : {
633 0 : CPLError(CE_Failure, CPLE_AppDefined,
634 : "Attempt to set rotated geotransform on ELAS file.\n"
635 : "ELAS does not support rotation.\n");
636 :
637 0 : return CE_Failure;
638 : }
639 :
640 : /* -------------------------------------------------------------------- */
641 : /* Remember the new transform, and update the header. */
642 : /* -------------------------------------------------------------------- */
643 16 : memcpy(adfGeoTransform, padfTransform, sizeof(double) * 6);
644 :
645 16 : bHeaderModified = TRUE;
646 :
647 16 : const int nXOff = (int)(adfGeoTransform[0] + adfGeoTransform[1] * 0.5);
648 16 : const int nYOff = (int)(adfGeoTransform[3] + adfGeoTransform[5] * 0.5);
649 :
650 16 : sHeader.XOffset = CPL_MSBWORD32(nXOff);
651 16 : sHeader.YOffset = CPL_MSBWORD32(nYOff);
652 :
653 16 : sHeader.XPixSize = static_cast<float>(std::abs(adfGeoTransform[1]));
654 16 : sHeader.YPixSize = static_cast<float>(std::abs(adfGeoTransform[5]));
655 :
656 16 : CPL_MSBPTR32(&(sHeader.XPixSize));
657 16 : CPL_MSBPTR32(&(sHeader.YPixSize));
658 :
659 16 : memcpy(sHeader.YLabel, "NOR ", 4);
660 16 : memcpy(sHeader.XLabel, "EAS ", 4);
661 :
662 16 : sHeader.Matrix[0] = 1.0;
663 16 : sHeader.Matrix[1] = 0.0;
664 16 : sHeader.Matrix[2] = 0.0;
665 16 : sHeader.Matrix[3] = -1.0;
666 :
667 16 : CPL_MSBPTR32(&(sHeader.Matrix[0]));
668 16 : CPL_MSBPTR32(&(sHeader.Matrix[1]));
669 16 : CPL_MSBPTR32(&(sHeader.Matrix[2]));
670 16 : CPL_MSBPTR32(&(sHeader.Matrix[3]));
671 :
672 16 : return CE_None;
673 : }
674 :
675 : /************************************************************************/
676 : /* GDALRegister_ELAS() */
677 : /************************************************************************/
678 :
679 1520 : void GDALRegister_ELAS()
680 :
681 : {
682 1520 : if (GDALGetDriverByName("ELAS") != nullptr)
683 301 : return;
684 :
685 1219 : GDALDriver *poDriver = new GDALDriver();
686 :
687 1219 : poDriver->SetDescription("ELAS");
688 1219 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
689 1219 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "ELAS");
690 1219 : poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES,
691 1219 : "Byte Float32 Float64");
692 :
693 1219 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
694 :
695 1219 : poDriver->pfnOpen = ELASDataset::Open;
696 1219 : poDriver->pfnIdentify = ELASDataset::Identify;
697 1219 : poDriver->pfnCreate = ELASDataset::Create;
698 :
699 1219 : GetGDALDriverManager()->RegisterDriver(poDriver);
700 : }
|