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