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