/src/gdal/frmts/raw/gscdataset.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /****************************************************************************** |
2 | | * |
3 | | * Project: GSC Geogrid format driver. |
4 | | * Purpose: Implements support for reading and writing GSC Geogrid format. |
5 | | * Author: Frank Warmerdam <warmerdam@pobox.com> |
6 | | * |
7 | | ****************************************************************************** |
8 | | * Copyright (c) 2002, Frank Warmerdam <warmerdam@pobox.com> |
9 | | * Copyright (c) 2009-2011, Even Rouault <even dot rouault at spatialys.com> |
10 | | * |
11 | | * SPDX-License-Identifier: MIT |
12 | | ****************************************************************************/ |
13 | | |
14 | | #include "cpl_string.h" |
15 | | #include "gdal_frmts.h" |
16 | | #include "rawdataset.h" |
17 | | |
18 | | #include <algorithm> |
19 | | |
20 | | /************************************************************************/ |
21 | | /* ==================================================================== */ |
22 | | /* GSCDataset */ |
23 | | /* ==================================================================== */ |
24 | | /************************************************************************/ |
25 | | |
26 | | class GSCDataset final : public RawDataset |
27 | | { |
28 | | VSILFILE *fpImage = nullptr; // image data file. |
29 | | |
30 | | GDALGeoTransform m_gt{}; |
31 | | |
32 | | CPL_DISALLOW_COPY_ASSIGN(GSCDataset) |
33 | | |
34 | | CPLErr Close() override; |
35 | | |
36 | | public: |
37 | 0 | GSCDataset() = default; |
38 | | ~GSCDataset(); |
39 | | |
40 | | CPLErr GetGeoTransform(GDALGeoTransform >) const override; |
41 | | |
42 | | static GDALDataset *Open(GDALOpenInfo *); |
43 | | }; |
44 | | |
45 | | /************************************************************************/ |
46 | | /* ~GSCDataset() */ |
47 | | /************************************************************************/ |
48 | | |
49 | | GSCDataset::~GSCDataset() |
50 | | |
51 | 0 | { |
52 | 0 | GSCDataset::Close(); |
53 | 0 | } |
54 | | |
55 | | /************************************************************************/ |
56 | | /* Close() */ |
57 | | /************************************************************************/ |
58 | | |
59 | | CPLErr GSCDataset::Close() |
60 | 0 | { |
61 | 0 | CPLErr eErr = CE_None; |
62 | 0 | if (nOpenFlags != OPEN_FLAGS_CLOSED) |
63 | 0 | { |
64 | 0 | if (GSCDataset::FlushCache(true) != CE_None) |
65 | 0 | eErr = CE_Failure; |
66 | |
|
67 | 0 | if (fpImage) |
68 | 0 | { |
69 | 0 | if (VSIFCloseL(fpImage) != 0) |
70 | 0 | { |
71 | 0 | CPLError(CE_Failure, CPLE_FileIO, "I/O error"); |
72 | 0 | eErr = CE_Failure; |
73 | 0 | } |
74 | 0 | } |
75 | |
|
76 | 0 | if (GDALPamDataset::Close() != CE_None) |
77 | 0 | eErr = CE_Failure; |
78 | 0 | } |
79 | 0 | return eErr; |
80 | 0 | } |
81 | | |
82 | | /************************************************************************/ |
83 | | /* GetGeoTransform() */ |
84 | | /************************************************************************/ |
85 | | |
86 | | CPLErr GSCDataset::GetGeoTransform(GDALGeoTransform >) const |
87 | | |
88 | 0 | { |
89 | 0 | gt = m_gt; |
90 | |
|
91 | 0 | return CE_None; |
92 | 0 | } |
93 | | |
94 | | /************************************************************************/ |
95 | | /* Open() */ |
96 | | /************************************************************************/ |
97 | | |
98 | | GDALDataset *GSCDataset::Open(GDALOpenInfo *poOpenInfo) |
99 | | |
100 | 548k | { |
101 | | |
102 | | /* -------------------------------------------------------------------- */ |
103 | | /* Does this plausible look like a GSC Geogrid file? */ |
104 | | /* -------------------------------------------------------------------- */ |
105 | 548k | if (poOpenInfo->nHeaderBytes < 20) |
106 | 477k | return nullptr; |
107 | | |
108 | 71.7k | if (poOpenInfo->pabyHeader[12] != 0x02 || |
109 | 71.7k | poOpenInfo->pabyHeader[13] != 0x00 || |
110 | 71.7k | poOpenInfo->pabyHeader[14] != 0x00 || |
111 | 71.7k | poOpenInfo->pabyHeader[15] != 0x00) |
112 | 71.6k | return nullptr; |
113 | | |
114 | 77 | int nRecordLen = |
115 | 77 | CPL_LSBWORD32(reinterpret_cast<GInt32 *>(poOpenInfo->pabyHeader)[0]); |
116 | 77 | const int nPixels = |
117 | 77 | CPL_LSBWORD32(reinterpret_cast<GInt32 *>(poOpenInfo->pabyHeader)[1]); |
118 | 77 | const int nLines = |
119 | 77 | CPL_LSBWORD32(reinterpret_cast<GInt32 *>(poOpenInfo->pabyHeader)[2]); |
120 | | |
121 | 77 | if (nPixels < 1 || nLines < 1 || nPixels > 100000 || nLines > 100000) |
122 | 73 | return nullptr; |
123 | | |
124 | 4 | if (nRecordLen != nPixels * 4) |
125 | 4 | return nullptr; |
126 | | |
127 | | /* -------------------------------------------------------------------- */ |
128 | | /* Confirm the requested access is supported. */ |
129 | | /* -------------------------------------------------------------------- */ |
130 | 0 | if (poOpenInfo->eAccess == GA_Update) |
131 | 0 | { |
132 | 0 | ReportUpdateNotSupportedByDriver("GSC"); |
133 | 0 | return nullptr; |
134 | 0 | } |
135 | | |
136 | 0 | nRecordLen += 8; // For record length markers. |
137 | | |
138 | | /* -------------------------------------------------------------------- */ |
139 | | /* Create a corresponding GDALDataset. */ |
140 | | /* -------------------------------------------------------------------- */ |
141 | 0 | auto poDS = std::make_unique<GSCDataset>(); |
142 | |
|
143 | 0 | poDS->nRasterXSize = nPixels; |
144 | 0 | poDS->nRasterYSize = nLines; |
145 | 0 | std::swap(poDS->fpImage, poOpenInfo->fpL); |
146 | | |
147 | | /* -------------------------------------------------------------------- */ |
148 | | /* Read the header information in the second record. */ |
149 | | /* -------------------------------------------------------------------- */ |
150 | 0 | float afHeaderInfo[8] = {0.0}; |
151 | |
|
152 | 0 | if (VSIFSeekL(poDS->fpImage, nRecordLen + 12, SEEK_SET) != 0 || |
153 | 0 | VSIFReadL(afHeaderInfo, sizeof(float), 8, poDS->fpImage) != 8) |
154 | 0 | { |
155 | 0 | CPLError( |
156 | 0 | CE_Failure, CPLE_FileIO, |
157 | 0 | "Failure reading second record of GSC file with %d record length.", |
158 | 0 | nRecordLen); |
159 | 0 | return nullptr; |
160 | 0 | } |
161 | | |
162 | 0 | for (int i = 0; i < 8; i++) |
163 | 0 | { |
164 | 0 | CPL_LSBPTR32(afHeaderInfo + i); |
165 | 0 | } |
166 | |
|
167 | 0 | poDS->m_gt[0] = afHeaderInfo[2]; |
168 | 0 | poDS->m_gt[1] = afHeaderInfo[0]; |
169 | 0 | poDS->m_gt[2] = 0.0; |
170 | 0 | poDS->m_gt[3] = afHeaderInfo[5]; |
171 | 0 | poDS->m_gt[4] = 0.0; |
172 | 0 | poDS->m_gt[5] = -afHeaderInfo[1]; |
173 | | |
174 | | /* -------------------------------------------------------------------- */ |
175 | | /* Create band information objects. */ |
176 | | /* -------------------------------------------------------------------- */ |
177 | 0 | auto poBand = RawRasterBand::Create( |
178 | 0 | poDS.get(), 1, poDS->fpImage, nRecordLen * 2 + 4, sizeof(float), |
179 | 0 | nRecordLen, GDT_Float32, RawRasterBand::ByteOrder::ORDER_LITTLE_ENDIAN, |
180 | 0 | RawRasterBand::OwnFP::NO); |
181 | 0 | if (!poBand) |
182 | 0 | return nullptr; |
183 | 0 | poBand->SetNoDataValue(-1.0000000150474662199e+30); |
184 | 0 | poDS->SetBand(1, std::move(poBand)); |
185 | | |
186 | | /* -------------------------------------------------------------------- */ |
187 | | /* Initialize any PAM information. */ |
188 | | /* -------------------------------------------------------------------- */ |
189 | 0 | poDS->SetDescription(poOpenInfo->pszFilename); |
190 | 0 | poDS->TryLoadXML(); |
191 | | |
192 | | /* -------------------------------------------------------------------- */ |
193 | | /* Check for overviews. */ |
194 | | /* -------------------------------------------------------------------- */ |
195 | 0 | poDS->oOvManager.Initialize(poDS.get(), poOpenInfo->pszFilename); |
196 | |
|
197 | 0 | return poDS.release(); |
198 | 0 | } |
199 | | |
200 | | /************************************************************************/ |
201 | | /* GDALRegister_GSC() */ |
202 | | /************************************************************************/ |
203 | | |
204 | | void GDALRegister_GSC() |
205 | | |
206 | 22 | { |
207 | 22 | if (GDALGetDriverByName("GSC") != nullptr) |
208 | 0 | return; |
209 | | |
210 | 22 | GDALDriver *poDriver = new GDALDriver(); |
211 | | |
212 | 22 | poDriver->SetDescription("GSC"); |
213 | 22 | poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES"); |
214 | 22 | poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "GSC Geogrid"); |
215 | 22 | poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/gsc.html"); |
216 | 22 | poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES"); |
217 | | |
218 | 22 | poDriver->pfnOpen = GSCDataset::Open; |
219 | | |
220 | 22 | GetGDALDriverManager()->RegisterDriver(poDriver); |
221 | 22 | } |