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 36092 : 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 36092 : if (poOpenInfo->nHeaderBytes < 24)
108 29053 : return nullptr;
109 :
110 7039 : char *pachLeader = reinterpret_cast<char *>(poOpenInfo->pabyHeader);
111 7039 : if (pachLeader[5] != '1' && pachLeader[5] != '2' && pachLeader[5] != '3')
112 6715 : return nullptr;
113 :
114 324 : if (pachLeader[6] != 'L')
115 273 : return nullptr;
116 :
117 51 : if (pachLeader[8] != '1' && pachLeader[8] != ' ')
118 0 : return nullptr;
119 :
120 : /* -------------------------------------------------------------------- */
121 : /* Try opening the dataset. */
122 : /* -------------------------------------------------------------------- */
123 51 : 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 : ReportUpdateNotSupportedByDriver("SDTS");
138 0 : return nullptr;
139 : }
140 :
141 : /* -------------------------------------------------------------------- */
142 : /* Find the first raster layer. If there are none, abort */
143 : /* returning an error. */
144 : /* -------------------------------------------------------------------- */
145 2 : SDTSRasterReader *poRL = nullptr;
146 :
147 2 : for (int i = 0; i < poTransfer->GetLayerCount(); i++)
148 : {
149 2 : if (poTransfer->GetLayerType(i) == SLTRaster)
150 : {
151 2 : poRL = poTransfer->GetLayerRasterReader(i);
152 2 : break;
153 : }
154 : }
155 :
156 2 : if (poRL == nullptr)
157 : {
158 0 : delete poTransfer;
159 :
160 0 : CPLError(CE_Warning, CPLE_AppDefined,
161 : "%s is an SDTS transfer, but has no raster cell layers.\n"
162 : "Perhaps it is a vector transfer?\n",
163 : poOpenInfo->pszFilename);
164 0 : return nullptr;
165 : }
166 :
167 : /* -------------------------------------------------------------------- */
168 : /* Initialize a corresponding GDALDataset. */
169 : /* -------------------------------------------------------------------- */
170 2 : SDTSDataset *poDS = new SDTSDataset();
171 :
172 2 : poDS->poTransfer = poTransfer;
173 2 : poDS->poRL = poRL;
174 :
175 : /* -------------------------------------------------------------------- */
176 : /* Capture some information from the file that is of interest. */
177 : /* -------------------------------------------------------------------- */
178 2 : poDS->nRasterXSize = poRL->GetXSize();
179 2 : poDS->nRasterYSize = poRL->GetYSize();
180 :
181 : /* -------------------------------------------------------------------- */
182 : /* Create band information objects. */
183 : /* -------------------------------------------------------------------- */
184 2 : poDS->nBands = 1;
185 2 : poDS->papoBands = reinterpret_cast<GDALRasterBand **>(
186 2 : VSICalloc(sizeof(GDALRasterBand *), poDS->nBands));
187 :
188 4 : for (int i = 0; i < poDS->nBands; i++)
189 2 : poDS->SetBand(i + 1, new SDTSRasterBand(poDS, i + 1, poRL));
190 :
191 : /* -------------------------------------------------------------------- */
192 : /* Try to establish the projection string. For now we only */
193 : /* support UTM and GEO. */
194 : /* -------------------------------------------------------------------- */
195 2 : SDTS_XREF *poXREF = poTransfer->GetXREF();
196 :
197 2 : if (EQUAL(poXREF->pszSystemName, "UTM"))
198 : {
199 2 : poDS->m_oSRS.SetUTM(poXREF->nZone);
200 : }
201 0 : else if (EQUAL(poXREF->pszSystemName, "GEO"))
202 : {
203 : /* we set datum later */
204 : }
205 : else
206 0 : poDS->m_oSRS.SetLocalCS(poXREF->pszSystemName);
207 :
208 2 : if (poDS->m_oSRS.IsLocal())
209 : /* don't try to set datum. */;
210 2 : else if (EQUAL(poXREF->pszDatum, "NAS"))
211 2 : poDS->m_oSRS.SetWellKnownGeogCS("NAD27");
212 0 : else if (EQUAL(poXREF->pszDatum, "NAX"))
213 0 : poDS->m_oSRS.SetWellKnownGeogCS("NAD83");
214 0 : else if (EQUAL(poXREF->pszDatum, "WGC"))
215 0 : poDS->m_oSRS.SetWellKnownGeogCS("WGS72");
216 : else /* if( EQUAL(poXREF->pszDatum, "WGE") ) or default */
217 0 : poDS->m_oSRS.SetWellKnownGeogCS("WGS84");
218 :
219 : /* -------------------------------------------------------------------- */
220 : /* Get metadata from the IDEN file. */
221 : /* -------------------------------------------------------------------- */
222 : const char *pszIDENFilePath =
223 2 : poTransfer->GetCATD()->GetModuleFilePath("IDEN");
224 2 : if (pszIDENFilePath)
225 : {
226 4 : DDFModule oIDENFile;
227 2 : if (oIDENFile.Open(pszIDENFilePath))
228 : {
229 2 : DDFRecord *poRecord = nullptr;
230 :
231 2 : while ((poRecord = oIDENFile.ReadRecord()) != nullptr)
232 : {
233 :
234 2 : if (poRecord->GetStringSubfield("IDEN", 0, "MODN", 0) ==
235 : nullptr)
236 0 : continue;
237 :
238 : static const char *const fields[][2] = {
239 : {"TITL", "TITLE"},
240 : {"DAID", "DATASET_ID"},
241 : {"DAST", "DATA_STRUCTURE"},
242 : {"MPDT", "MAP_DATE"},
243 : {"DCDT", "DATASET_CREATION_DATE"}};
244 :
245 12 : for (int i = 0; i < static_cast<int>(sizeof(fields)) /
246 : static_cast<int>(sizeof(fields[0]));
247 : i++)
248 : {
249 : const char *pszFieldValue =
250 10 : poRecord->GetStringSubfield("IDEN", 0, fields[i][0], 0);
251 10 : if (pszFieldValue)
252 10 : poDS->SetMetadataItem(fields[i][1], pszFieldValue);
253 : }
254 :
255 2 : break;
256 : }
257 : }
258 : }
259 :
260 : /* -------------------------------------------------------------------- */
261 : /* Initialize any PAM information. */
262 : /* -------------------------------------------------------------------- */
263 2 : poDS->SetDescription(poOpenInfo->pszFilename);
264 2 : poDS->TryLoadXML();
265 :
266 : /* -------------------------------------------------------------------- */
267 : /* Check for external overviews. */
268 : /* -------------------------------------------------------------------- */
269 4 : poDS->oOvManager.Initialize(poDS, poOpenInfo->pszFilename,
270 2 : poOpenInfo->GetSiblingFiles());
271 :
272 2 : return poDS;
273 : }
274 :
275 : /************************************************************************/
276 : /* GetGeoTransform() */
277 : /************************************************************************/
278 :
279 1 : CPLErr SDTSDataset::GetGeoTransform(double *padfTransform)
280 :
281 : {
282 1 : if (poRL->GetTransform(padfTransform))
283 1 : return CE_None;
284 :
285 0 : return CE_Failure;
286 : }
287 :
288 : /************************************************************************/
289 : /* ==================================================================== */
290 : /* SDTSRasterBand */
291 : /* ==================================================================== */
292 : /************************************************************************/
293 :
294 : /************************************************************************/
295 : /* SDTSRasterBand() */
296 : /************************************************************************/
297 :
298 2 : SDTSRasterBand::SDTSRasterBand(SDTSDataset *poDSIn, int nBandIn,
299 2 : SDTSRasterReader *poRLIn)
300 2 : : poRL(poRLIn)
301 : {
302 2 : poDS = poDSIn;
303 2 : nBand = nBandIn;
304 :
305 2 : if (poRL->GetRasterType() == SDTS_RT_INT16)
306 2 : eDataType = GDT_Int16;
307 : else
308 0 : eDataType = GDT_Float32;
309 :
310 2 : nBlockXSize = poRL->GetBlockXSize();
311 2 : nBlockYSize = poRL->GetBlockYSize();
312 2 : }
313 :
314 : /************************************************************************/
315 : /* IReadBlock() */
316 : /************************************************************************/
317 :
318 25 : CPLErr SDTSRasterBand::IReadBlock(int nBlockXOff, int nBlockYOff, void *pImage)
319 :
320 : {
321 25 : if (poRL->GetBlock(nBlockXOff, nBlockYOff, pImage))
322 25 : return CE_None;
323 :
324 0 : return CE_Failure;
325 : }
326 :
327 : /************************************************************************/
328 : /* GetNoDataValue() */
329 : /************************************************************************/
330 :
331 0 : double SDTSRasterBand::GetNoDataValue(int *pbSuccess)
332 :
333 : {
334 0 : if (pbSuccess != nullptr)
335 0 : *pbSuccess = TRUE;
336 :
337 0 : return -32766.0;
338 : }
339 :
340 : /************************************************************************/
341 : /* GetUnitType() */
342 : /************************************************************************/
343 :
344 0 : const char *SDTSRasterBand::GetUnitType()
345 :
346 : {
347 0 : if (EQUAL(poRL->szUNITS, "FEET"))
348 0 : return "ft";
349 0 : else if (STARTS_WITH_CI(poRL->szUNITS, "MET"))
350 0 : return "m";
351 :
352 0 : return poRL->szUNITS;
353 : }
354 :
355 : /************************************************************************/
356 : /* GDALRegister_SDTS() */
357 : /************************************************************************/
358 :
359 1686 : void GDALRegister_SDTS()
360 :
361 : {
362 1686 : if (GDALGetDriverByName("SDTS") != nullptr)
363 302 : return;
364 :
365 1384 : GDALDriver *poDriver = new GDALDriver();
366 :
367 1384 : poDriver->SetDescription("SDTS");
368 1384 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
369 1384 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "SDTS Raster");
370 1384 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/sdts.html");
371 1384 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "ddf");
372 1384 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
373 :
374 1384 : poDriver->pfnOpen = SDTSDataset::Open;
375 :
376 1384 : GetGDALDriverManager()->RegisterDriver(poDriver);
377 : }
|