Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: SDTS Translator
4 : * Purpose: GDALDataset driver for SDTS Raster translator.
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 : #include "ogr_spatialref.h"
33 : #include "sdts_al.h"
34 :
35 : /**
36 : \file sdtsdataset.cpp
37 :
38 : exclude
39 : */
40 :
41 : /************************************************************************/
42 : /* ==================================================================== */
43 : /* SDTSDataset */
44 : /* ==================================================================== */
45 : /************************************************************************/
46 :
47 : class SDTSRasterBand;
48 :
49 : class SDTSDataset final : public GDALPamDataset
50 : {
51 : friend class SDTSRasterBand;
52 :
53 : SDTSTransfer *poTransfer;
54 : SDTSRasterReader *poRL;
55 :
56 : OGRSpatialReference m_oSRS{};
57 :
58 : public:
59 : SDTSDataset();
60 : virtual ~SDTSDataset();
61 :
62 : static GDALDataset *Open(GDALOpenInfo *);
63 :
64 1 : const OGRSpatialReference *GetSpatialRef() const override
65 : {
66 1 : return &m_oSRS;
67 : }
68 :
69 : virtual CPLErr GetGeoTransform(double *) override;
70 : };
71 :
72 : class SDTSRasterBand final : public GDALPamRasterBand
73 : {
74 : friend class SDTSDataset;
75 :
76 : SDTSRasterReader *poRL;
77 :
78 : public:
79 : SDTSRasterBand(SDTSDataset *, int, SDTSRasterReader *);
80 :
81 : virtual CPLErr IReadBlock(int, int, void *) override;
82 :
83 : virtual double GetNoDataValue(int *pbSuccess) override;
84 : virtual const char *GetUnitType() override;
85 : };
86 :
87 : /************************************************************************/
88 : /* SDTSDataset() */
89 : /************************************************************************/
90 :
91 2 : SDTSDataset::SDTSDataset() : poTransfer(nullptr), poRL(nullptr)
92 : {
93 2 : m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
94 2 : }
95 :
96 : /************************************************************************/
97 : /* ~SDTSDataset() */
98 : /************************************************************************/
99 :
100 4 : SDTSDataset::~SDTSDataset()
101 :
102 : {
103 2 : FlushCache(true);
104 :
105 2 : if (poTransfer != nullptr)
106 2 : delete poTransfer;
107 :
108 2 : if (poRL != nullptr)
109 2 : delete poRL;
110 4 : }
111 :
112 : /************************************************************************/
113 : /* Open() */
114 : /************************************************************************/
115 :
116 33849 : GDALDataset *SDTSDataset::Open(GDALOpenInfo *poOpenInfo)
117 :
118 : {
119 : /* -------------------------------------------------------------------- */
120 : /* Before trying SDTSOpen() we first verify that the first */
121 : /* record is in fact a SDTS file descriptor record. */
122 : /* -------------------------------------------------------------------- */
123 33849 : if (poOpenInfo->nHeaderBytes < 24)
124 27264 : return nullptr;
125 :
126 6585 : char *pachLeader = reinterpret_cast<char *>(poOpenInfo->pabyHeader);
127 6585 : if (pachLeader[5] != '1' && pachLeader[5] != '2' && pachLeader[5] != '3')
128 6233 : return nullptr;
129 :
130 352 : if (pachLeader[6] != 'L')
131 301 : return nullptr;
132 :
133 51 : if (pachLeader[8] != '1' && pachLeader[8] != ' ')
134 0 : return nullptr;
135 :
136 : /* -------------------------------------------------------------------- */
137 : /* Try opening the dataset. */
138 : /* -------------------------------------------------------------------- */
139 51 : SDTSTransfer *poTransfer = new SDTSTransfer;
140 :
141 51 : if (!poTransfer->Open(poOpenInfo->pszFilename))
142 : {
143 49 : delete poTransfer;
144 49 : return nullptr;
145 : }
146 :
147 : /* -------------------------------------------------------------------- */
148 : /* Confirm the requested access is supported. */
149 : /* -------------------------------------------------------------------- */
150 2 : if (poOpenInfo->eAccess == GA_Update)
151 : {
152 0 : delete poTransfer;
153 0 : CPLError(CE_Failure, CPLE_NotSupported,
154 : "The SDTS driver does not support update access to existing"
155 : " datasets.\n");
156 0 : return nullptr;
157 : }
158 :
159 : /* -------------------------------------------------------------------- */
160 : /* Find the first raster layer. If there are none, abort */
161 : /* returning an error. */
162 : /* -------------------------------------------------------------------- */
163 2 : SDTSRasterReader *poRL = nullptr;
164 :
165 2 : for (int i = 0; i < poTransfer->GetLayerCount(); i++)
166 : {
167 2 : if (poTransfer->GetLayerType(i) == SLTRaster)
168 : {
169 2 : poRL = poTransfer->GetLayerRasterReader(i);
170 2 : break;
171 : }
172 : }
173 :
174 2 : if (poRL == nullptr)
175 : {
176 0 : delete poTransfer;
177 :
178 0 : CPLError(CE_Warning, CPLE_AppDefined,
179 : "%s is an SDTS transfer, but has no raster cell layers.\n"
180 : "Perhaps it is a vector transfer?\n",
181 : poOpenInfo->pszFilename);
182 0 : return nullptr;
183 : }
184 :
185 : /* -------------------------------------------------------------------- */
186 : /* Initialize a corresponding GDALDataset. */
187 : /* -------------------------------------------------------------------- */
188 2 : SDTSDataset *poDS = new SDTSDataset();
189 :
190 2 : poDS->poTransfer = poTransfer;
191 2 : poDS->poRL = poRL;
192 :
193 : /* -------------------------------------------------------------------- */
194 : /* Capture some information from the file that is of interest. */
195 : /* -------------------------------------------------------------------- */
196 2 : poDS->nRasterXSize = poRL->GetXSize();
197 2 : poDS->nRasterYSize = poRL->GetYSize();
198 :
199 : /* -------------------------------------------------------------------- */
200 : /* Create band information objects. */
201 : /* -------------------------------------------------------------------- */
202 2 : poDS->nBands = 1;
203 2 : poDS->papoBands = reinterpret_cast<GDALRasterBand **>(
204 2 : VSICalloc(sizeof(GDALRasterBand *), poDS->nBands));
205 :
206 4 : for (int i = 0; i < poDS->nBands; i++)
207 2 : poDS->SetBand(i + 1, new SDTSRasterBand(poDS, i + 1, poRL));
208 :
209 : /* -------------------------------------------------------------------- */
210 : /* Try to establish the projection string. For now we only */
211 : /* support UTM and GEO. */
212 : /* -------------------------------------------------------------------- */
213 2 : SDTS_XREF *poXREF = poTransfer->GetXREF();
214 :
215 2 : if (EQUAL(poXREF->pszSystemName, "UTM"))
216 : {
217 2 : poDS->m_oSRS.SetUTM(poXREF->nZone);
218 : }
219 0 : else if (EQUAL(poXREF->pszSystemName, "GEO"))
220 : {
221 : /* we set datum later */
222 : }
223 : else
224 0 : poDS->m_oSRS.SetLocalCS(poXREF->pszSystemName);
225 :
226 2 : if (poDS->m_oSRS.IsLocal())
227 : /* don't try to set datum. */;
228 2 : else if (EQUAL(poXREF->pszDatum, "NAS"))
229 2 : poDS->m_oSRS.SetWellKnownGeogCS("NAD27");
230 0 : else if (EQUAL(poXREF->pszDatum, "NAX"))
231 0 : poDS->m_oSRS.SetWellKnownGeogCS("NAD83");
232 0 : else if (EQUAL(poXREF->pszDatum, "WGC"))
233 0 : poDS->m_oSRS.SetWellKnownGeogCS("WGS72");
234 : else /* if( EQUAL(poXREF->pszDatum, "WGE") ) or default */
235 0 : poDS->m_oSRS.SetWellKnownGeogCS("WGS84");
236 :
237 : /* -------------------------------------------------------------------- */
238 : /* Get metadata from the IDEN file. */
239 : /* -------------------------------------------------------------------- */
240 : const char *pszIDENFilePath =
241 2 : poTransfer->GetCATD()->GetModuleFilePath("IDEN");
242 2 : if (pszIDENFilePath)
243 : {
244 4 : DDFModule oIDENFile;
245 2 : if (oIDENFile.Open(pszIDENFilePath))
246 : {
247 2 : DDFRecord *poRecord = nullptr;
248 :
249 2 : while ((poRecord = oIDENFile.ReadRecord()) != nullptr)
250 : {
251 :
252 2 : if (poRecord->GetStringSubfield("IDEN", 0, "MODN", 0) ==
253 : nullptr)
254 0 : continue;
255 :
256 : static const char *const fields[][2] = {
257 : {"TITL", "TITLE"},
258 : {"DAID", "DATASET_ID"},
259 : {"DAST", "DATA_STRUCTURE"},
260 : {"MPDT", "MAP_DATE"},
261 : {"DCDT", "DATASET_CREATION_DATE"}};
262 :
263 12 : for (int i = 0; i < static_cast<int>(sizeof(fields)) /
264 : static_cast<int>(sizeof(fields[0]));
265 : i++)
266 : {
267 : const char *pszFieldValue =
268 10 : poRecord->GetStringSubfield("IDEN", 0, fields[i][0], 0);
269 10 : if (pszFieldValue)
270 10 : poDS->SetMetadataItem(fields[i][1], pszFieldValue);
271 : }
272 :
273 2 : break;
274 : }
275 : }
276 : }
277 :
278 : /* -------------------------------------------------------------------- */
279 : /* Initialize any PAM information. */
280 : /* -------------------------------------------------------------------- */
281 2 : poDS->SetDescription(poOpenInfo->pszFilename);
282 2 : poDS->TryLoadXML();
283 :
284 : /* -------------------------------------------------------------------- */
285 : /* Check for external overviews. */
286 : /* -------------------------------------------------------------------- */
287 2 : poDS->oOvManager.Initialize(poDS, poOpenInfo->pszFilename,
288 : poOpenInfo->GetSiblingFiles());
289 :
290 2 : return poDS;
291 : }
292 :
293 : /************************************************************************/
294 : /* GetGeoTransform() */
295 : /************************************************************************/
296 :
297 1 : CPLErr SDTSDataset::GetGeoTransform(double *padfTransform)
298 :
299 : {
300 1 : if (poRL->GetTransform(padfTransform))
301 1 : return CE_None;
302 :
303 0 : return CE_Failure;
304 : }
305 :
306 : /************************************************************************/
307 : /* ==================================================================== */
308 : /* SDTSRasterBand */
309 : /* ==================================================================== */
310 : /************************************************************************/
311 :
312 : /************************************************************************/
313 : /* SDTSRasterBand() */
314 : /************************************************************************/
315 :
316 2 : SDTSRasterBand::SDTSRasterBand(SDTSDataset *poDSIn, int nBandIn,
317 2 : SDTSRasterReader *poRLIn)
318 2 : : poRL(poRLIn)
319 : {
320 2 : poDS = poDSIn;
321 2 : nBand = nBandIn;
322 :
323 2 : if (poRL->GetRasterType() == SDTS_RT_INT16)
324 2 : eDataType = GDT_Int16;
325 : else
326 0 : eDataType = GDT_Float32;
327 :
328 2 : nBlockXSize = poRL->GetBlockXSize();
329 2 : nBlockYSize = poRL->GetBlockYSize();
330 2 : }
331 :
332 : /************************************************************************/
333 : /* IReadBlock() */
334 : /************************************************************************/
335 :
336 25 : CPLErr SDTSRasterBand::IReadBlock(int nBlockXOff, int nBlockYOff, void *pImage)
337 :
338 : {
339 25 : if (poRL->GetBlock(nBlockXOff, nBlockYOff, pImage))
340 25 : return CE_None;
341 :
342 0 : return CE_Failure;
343 : }
344 :
345 : /************************************************************************/
346 : /* GetNoDataValue() */
347 : /************************************************************************/
348 :
349 0 : double SDTSRasterBand::GetNoDataValue(int *pbSuccess)
350 :
351 : {
352 0 : if (pbSuccess != nullptr)
353 0 : *pbSuccess = TRUE;
354 :
355 0 : return -32766.0;
356 : }
357 :
358 : /************************************************************************/
359 : /* GetUnitType() */
360 : /************************************************************************/
361 :
362 0 : const char *SDTSRasterBand::GetUnitType()
363 :
364 : {
365 0 : if (EQUAL(poRL->szUNITS, "FEET"))
366 0 : return "ft";
367 0 : else if (STARTS_WITH_CI(poRL->szUNITS, "MET"))
368 0 : return "m";
369 :
370 0 : return poRL->szUNITS;
371 : }
372 :
373 : /************************************************************************/
374 : /* GDALRegister_SDTS() */
375 : /************************************************************************/
376 :
377 1520 : void GDALRegister_SDTS()
378 :
379 : {
380 1520 : if (GDALGetDriverByName("SDTS") != nullptr)
381 301 : return;
382 :
383 1219 : GDALDriver *poDriver = new GDALDriver();
384 :
385 1219 : poDriver->SetDescription("SDTS");
386 1219 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
387 1219 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "SDTS Raster");
388 1219 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/sdts.html");
389 1219 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "ddf");
390 1219 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
391 :
392 1219 : poDriver->pfnOpen = SDTSDataset::Open;
393 :
394 1219 : GetGDALDriverManager()->RegisterDriver(poDriver);
395 : }
|