Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GDAL
4 : * Purpose: Implementation for ELAS DIPEx format variant.
5 : * Author: Frank Warmerdam, warmerdam@pobox.com
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2006, 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 "cpl_string.h"
31 : #include "gdal_frmts.h"
32 : #include "ogr_spatialref.h"
33 : #include "rawdataset.h"
34 :
35 : #include <cmath>
36 : #include <algorithm>
37 :
38 : using std::fill;
39 :
40 : /************************************************************************/
41 : /* ==================================================================== */
42 : /* DIPExDataset */
43 : /* ==================================================================== */
44 : /************************************************************************/
45 :
46 : class DIPExDataset final : public GDALPamDataset
47 : {
48 : struct DIPExHeader
49 : {
50 : GInt32 NBIH = {0}; /* bytes in header, normally 1024 */
51 : GInt32 NBPR = {0}; /* bytes per data record (all bands of scanline) */
52 : GInt32 IL = {0}; /* initial line - normally 1 */
53 : GInt32 LL = {0}; /* last line */
54 : GInt32 IE = {0}; /* initial element (pixel), normally 1 */
55 : GInt32 LE = {0}; /* last element (pixel) */
56 : GInt32 NC = {0}; /* number of channels (bands) */
57 : GInt32 H4322 = {0}; /* header record identifier - always 4322. */
58 : char unused1[40] = {0};
59 : GByte IH19[4] = {0}; /* data type, and size flags */
60 : GInt32 IH20 = {0}; /* number of secondary headers */
61 : GInt32 SRID = {0};
62 : char unused2[12] = {0};
63 : double YOffset = {0};
64 : double XOffset = {0};
65 : double YPixSize = {0};
66 : double XPixSize = {0};
67 : double Matrix[4] = {0};
68 : char unused3[344] = {0};
69 : GUInt16 ColorTable[256] = {0}; /* RGB packed with 4 bits each */
70 : char unused4[32] = {0};
71 : };
72 :
73 : VSILFILE *fp;
74 : OGRSpatialReference m_oSRS{};
75 :
76 : DIPExHeader sHeader{};
77 :
78 : GDALDataType eRasterDataType;
79 :
80 : double adfGeoTransform[6];
81 :
82 : CPL_DISALLOW_COPY_ASSIGN(DIPExDataset)
83 :
84 : public:
85 : DIPExDataset();
86 : ~DIPExDataset() override;
87 :
88 : CPLErr GetGeoTransform(double *) override;
89 :
90 0 : const OGRSpatialReference *GetSpatialRef() const override
91 : {
92 0 : return m_oSRS.IsEmpty() ? nullptr : &m_oSRS;
93 : }
94 :
95 : static GDALDataset *Open(GDALOpenInfo *);
96 : };
97 :
98 : /************************************************************************/
99 : /* ==================================================================== */
100 : /* DIPExDataset */
101 : /* ==================================================================== */
102 : /************************************************************************/
103 :
104 : /************************************************************************/
105 : /* DIPExDataset() */
106 : /************************************************************************/
107 :
108 2 : DIPExDataset::DIPExDataset() : fp(nullptr), eRasterDataType(GDT_Unknown)
109 : {
110 2 : m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
111 2 : adfGeoTransform[0] = 0.0;
112 2 : adfGeoTransform[1] = 1.0;
113 2 : adfGeoTransform[2] = 0.0;
114 2 : adfGeoTransform[3] = 0.0;
115 2 : adfGeoTransform[4] = 0.0;
116 2 : adfGeoTransform[5] = 1.0;
117 2 : }
118 :
119 : /************************************************************************/
120 : /* ~DIPExDataset() */
121 : /************************************************************************/
122 :
123 4 : DIPExDataset::~DIPExDataset()
124 :
125 : {
126 2 : if (fp)
127 2 : CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
128 2 : fp = nullptr;
129 4 : }
130 :
131 : /************************************************************************/
132 : /* Open() */
133 : /************************************************************************/
134 :
135 29118 : GDALDataset *DIPExDataset::Open(GDALOpenInfo *poOpenInfo)
136 :
137 : {
138 : /* -------------------------------------------------------------------- */
139 : /* First we check to see if the file has the expected header */
140 : /* bytes. */
141 : /* -------------------------------------------------------------------- */
142 29118 : if (poOpenInfo->nHeaderBytes < 256 || poOpenInfo->fpL == nullptr)
143 26470 : return nullptr;
144 :
145 2648 : if (CPL_LSBWORD32(
146 : *(reinterpret_cast<GInt32 *>(poOpenInfo->pabyHeader + 0))) != 1024)
147 2646 : return nullptr;
148 :
149 2 : if (CPL_LSBWORD32(
150 : *(reinterpret_cast<GInt32 *>(poOpenInfo->pabyHeader + 28))) != 4322)
151 0 : return nullptr;
152 :
153 : /* -------------------------------------------------------------------- */
154 : /* Create a corresponding GDALDataset. */
155 : /* -------------------------------------------------------------------- */
156 4 : auto poDS = std::make_unique<DIPExDataset>();
157 :
158 2 : poDS->eAccess = poOpenInfo->eAccess;
159 2 : poDS->fp = poOpenInfo->fpL;
160 2 : poOpenInfo->fpL = nullptr;
161 :
162 : /* -------------------------------------------------------------------- */
163 : /* Read the header information. */
164 : /* -------------------------------------------------------------------- */
165 2 : if (VSIFReadL(&(poDS->sHeader), 1024, 1, poDS->fp) != 1)
166 : {
167 0 : CPLError(CE_Failure, CPLE_FileIO,
168 : "Attempt to read 1024 byte header filed on file %s\n",
169 : poOpenInfo->pszFilename);
170 0 : return nullptr;
171 : }
172 :
173 : // To avoid cppcheck warnings about unused members
174 2 : CPL_IGNORE_RET_VAL(poDS->sHeader.NBIH);
175 2 : CPL_IGNORE_RET_VAL(poDS->sHeader.H4322);
176 2 : CPL_IGNORE_RET_VAL(poDS->sHeader.unused1);
177 2 : CPL_IGNORE_RET_VAL(poDS->sHeader.IH20);
178 2 : CPL_IGNORE_RET_VAL(poDS->sHeader.unused2);
179 2 : CPL_IGNORE_RET_VAL(poDS->sHeader.Matrix);
180 2 : CPL_IGNORE_RET_VAL(poDS->sHeader.unused3);
181 2 : CPL_IGNORE_RET_VAL(poDS->sHeader.ColorTable);
182 2 : CPL_IGNORE_RET_VAL(poDS->sHeader.unused4);
183 :
184 : /* -------------------------------------------------------------------- */
185 : /* Extract information of interest from the header. */
186 : /* -------------------------------------------------------------------- */
187 2 : const int nLineOffset = CPL_LSBWORD32(poDS->sHeader.NBPR);
188 :
189 2 : int nStart = CPL_LSBWORD32(poDS->sHeader.IL);
190 2 : int nEnd = CPL_LSBWORD32(poDS->sHeader.LL);
191 2 : GIntBig nDiff = static_cast<GIntBig>(nEnd) - nStart + 1;
192 2 : if (nDiff <= 0 || nDiff > INT_MAX)
193 : {
194 0 : return nullptr;
195 : }
196 2 : poDS->nRasterYSize = static_cast<int>(nDiff);
197 :
198 2 : nStart = CPL_LSBWORD32(poDS->sHeader.IE);
199 2 : nEnd = CPL_LSBWORD32(poDS->sHeader.LE);
200 2 : nDiff = static_cast<GIntBig>(nEnd) - nStart + 1;
201 2 : if (nDiff <= 0 || nDiff > INT_MAX)
202 : {
203 0 : return nullptr;
204 : }
205 2 : poDS->nRasterXSize = static_cast<int>(nDiff);
206 :
207 2 : const int nBands = CPL_LSBWORD32(poDS->sHeader.NC);
208 :
209 4 : if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize) ||
210 2 : !GDALCheckBandCount(nBands, FALSE))
211 : {
212 0 : return nullptr;
213 : }
214 :
215 2 : const int nDIPExDataType = (poDS->sHeader.IH19[1] & 0x7e) >> 2;
216 2 : const int nBytesPerSample = poDS->sHeader.IH19[0];
217 :
218 2 : if (nDIPExDataType == 0 && nBytesPerSample == 1)
219 2 : poDS->eRasterDataType = GDT_Byte;
220 0 : else if (nDIPExDataType == 1 && nBytesPerSample == 1)
221 0 : poDS->eRasterDataType = GDT_Byte;
222 0 : else if (nDIPExDataType == 16 && nBytesPerSample == 4)
223 0 : poDS->eRasterDataType = GDT_Float32;
224 0 : else if (nDIPExDataType == 17 && nBytesPerSample == 8)
225 0 : poDS->eRasterDataType = GDT_Float64;
226 : else
227 : {
228 0 : CPLError(CE_Failure, CPLE_AppDefined,
229 : "Unrecognized image data type %d, with BytesPerSample=%d.",
230 : nDIPExDataType, nBytesPerSample);
231 0 : return nullptr;
232 : }
233 :
234 2 : if (nLineOffset <= 0 || nLineOffset > INT_MAX / nBands)
235 : {
236 0 : CPLError(CE_Failure, CPLE_AppDefined,
237 : "Invalid values: nLineOffset = %d, nBands = %d.", nLineOffset,
238 : nBands);
239 0 : return nullptr;
240 : }
241 :
242 : /* -------------------------------------------------------------------- */
243 : /* Create band information objects. */
244 : /* -------------------------------------------------------------------- */
245 2 : CPLErrorReset();
246 4 : for (int iBand = 0; iBand < nBands; iBand++)
247 : {
248 : auto poBand = RawRasterBand::Create(
249 4 : poDS.get(), iBand + 1, poDS->fp, 1024 + iBand * nLineOffset,
250 2 : nBytesPerSample, nLineOffset * nBands, poDS->eRasterDataType,
251 : RawRasterBand::ByteOrder::ORDER_LITTLE_ENDIAN,
252 2 : RawRasterBand::OwnFP::NO);
253 2 : if (!poBand)
254 0 : return nullptr;
255 2 : poDS->SetBand(iBand + 1, std::move(poBand));
256 : }
257 :
258 : /* -------------------------------------------------------------------- */
259 : /* Extract the projection coordinates, if present. */
260 : /* -------------------------------------------------------------------- */
261 2 : CPL_LSBPTR64(&(poDS->sHeader.XPixSize));
262 2 : CPL_LSBPTR64(&(poDS->sHeader.YPixSize));
263 2 : CPL_LSBPTR64(&(poDS->sHeader.XOffset));
264 2 : CPL_LSBPTR64(&(poDS->sHeader.YOffset));
265 :
266 2 : if (poDS->sHeader.XOffset != 0)
267 : {
268 0 : poDS->adfGeoTransform[0] = poDS->sHeader.XOffset;
269 0 : poDS->adfGeoTransform[1] = poDS->sHeader.XPixSize;
270 0 : poDS->adfGeoTransform[2] = 0.0;
271 0 : poDS->adfGeoTransform[3] = poDS->sHeader.YOffset;
272 0 : poDS->adfGeoTransform[4] = 0.0;
273 0 : poDS->adfGeoTransform[5] = -1.0 * std::abs(poDS->sHeader.YPixSize);
274 :
275 0 : poDS->adfGeoTransform[0] -= poDS->adfGeoTransform[1] * 0.5;
276 0 : poDS->adfGeoTransform[3] -= poDS->adfGeoTransform[5] * 0.5;
277 : }
278 : else
279 : {
280 2 : poDS->adfGeoTransform[0] = 0.0;
281 2 : poDS->adfGeoTransform[1] = 1.0;
282 2 : poDS->adfGeoTransform[2] = 0.0;
283 2 : poDS->adfGeoTransform[3] = 0.0;
284 2 : poDS->adfGeoTransform[4] = 0.0;
285 2 : poDS->adfGeoTransform[5] = 1.0;
286 : }
287 :
288 : /* -------------------------------------------------------------------- */
289 : /* Look for SRID. */
290 : /* -------------------------------------------------------------------- */
291 2 : CPL_LSBPTR32(&(poDS->sHeader.SRID));
292 :
293 2 : if (poDS->sHeader.SRID > 0 && poDS->sHeader.SRID < 33000)
294 : {
295 4 : OGRSpatialReference oSR;
296 2 : oSR.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
297 2 : if (oSR.importFromEPSG(poDS->sHeader.SRID) == OGRERR_NONE)
298 : {
299 2 : poDS->m_oSRS = std::move(oSR);
300 : }
301 : }
302 :
303 : /* -------------------------------------------------------------------- */
304 : /* Initialize any PAM information. */
305 : /* -------------------------------------------------------------------- */
306 2 : poDS->SetDescription(poOpenInfo->pszFilename);
307 2 : poDS->TryLoadXML();
308 :
309 : /* -------------------------------------------------------------------- */
310 : /* Check for external overviews. */
311 : /* -------------------------------------------------------------------- */
312 2 : poDS->oOvManager.Initialize(poDS.get(), poOpenInfo->pszFilename,
313 : poOpenInfo->GetSiblingFiles());
314 :
315 2 : return poDS.release();
316 : }
317 :
318 : /************************************************************************/
319 : /* GetGeoTransform() */
320 : /************************************************************************/
321 :
322 0 : CPLErr DIPExDataset::GetGeoTransform(double *padfTransform)
323 :
324 : {
325 0 : memcpy(padfTransform, adfGeoTransform, sizeof(double) * 6);
326 :
327 0 : return CE_None;
328 : }
329 :
330 : /************************************************************************/
331 : /* GDALRegister_DIPEx() */
332 : /************************************************************************/
333 :
334 1511 : void GDALRegister_DIPEx()
335 :
336 : {
337 1511 : if (GDALGetDriverByName("DIPEx") != nullptr)
338 295 : return;
339 :
340 1216 : GDALDriver *poDriver = new GDALDriver();
341 :
342 1216 : poDriver->SetDescription("DIPEx");
343 1216 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
344 1216 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "DIPEx");
345 1216 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
346 :
347 1216 : poDriver->pfnOpen = DIPExDataset::Open;
348 :
349 1216 : GetGDALDriverManager()->RegisterDriver(poDriver);
350 : }
|