Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: Ground-based SAR Applitcations Testbed File Format driver
4 : * Purpose: Support in GDAL for Sandia National Laboratory's GFF format
5 : * blame Tisham for putting me up to this
6 : * Author: Philippe Vachon <philippe@cowpig.ca>
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2007, Philippe Vachon
10 : * Copyright (c) 2008-2012, Even Rouault <even dot rouault at spatialys.com>
11 : *
12 : * Permission is hereby granted, free of charge, to any person obtaining a
13 : * copy of this software and associated documentation files (the "Software"),
14 : * to deal in the Software without restriction, including without limitation
15 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 : * and/or sell copies of the Software, and to permit persons to whom the
17 : * Software is furnished to do so, subject to the following conditions:
18 : *
19 : * The above copyright notice and this permission notice shall be included
20 : * in all copies or substantial portions of the Software.
21 : *
22 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 : * DEALINGS IN THE SOFTWARE.
29 : ****************************************************************************/
30 :
31 : #include "cpl_conv.h"
32 : #include "cpl_port.h"
33 : #include "cpl_string.h"
34 : #include "cpl_vsi.h"
35 : #include "gdal_frmts.h"
36 : #include "gdal_pam.h"
37 : #include "gdal_priv.h"
38 :
39 : /*******************************************************************
40 : * Declaration of the GFFDataset class *
41 : *******************************************************************/
42 :
43 : class GFFRasterBand;
44 :
45 : class GFFDataset final : public GDALPamDataset
46 : {
47 : friend class GFFRasterBand;
48 : VSILFILE *fp;
49 : GDALDataType eDataType;
50 : unsigned int nEndianness;
51 : /* Some relevant headers */
52 : unsigned short nVersionMajor;
53 : unsigned short nVersionMinor;
54 : unsigned int nLength;
55 : // char *pszCreator;
56 : // TODO: Needs a better explanation.
57 : /* I am taking this at face value (are they insane?) */
58 : // float fBPP;
59 : unsigned int nBPP;
60 :
61 : /* Good information to know */
62 : unsigned int nFrameCnt;
63 : unsigned int nImageType;
64 : unsigned int nRowMajor;
65 : unsigned int nRgCnt;
66 : unsigned int nAzCnt;
67 : // long nScaleExponent;
68 : // long nScaleMantissa;
69 : // long nOffsetExponent;
70 : // long nOffsetMantissa;
71 : public:
72 : GFFDataset();
73 : ~GFFDataset();
74 :
75 : static GDALDataset *Open(GDALOpenInfo *);
76 : static int Identify(GDALOpenInfo *poOpenInfo);
77 : };
78 :
79 0 : GFFDataset::GFFDataset()
80 : : fp(nullptr), eDataType(GDT_Unknown), nEndianness(0), nVersionMajor(0),
81 : nVersionMinor(0), nLength(0), nBPP(0), nFrameCnt(0), nImageType(0),
82 0 : nRowMajor(0), nRgCnt(0), nAzCnt(0)
83 : {
84 0 : }
85 :
86 0 : GFFDataset::~GFFDataset()
87 : {
88 0 : if (fp != nullptr)
89 0 : VSIFCloseL(fp);
90 0 : }
91 :
92 : /*********************************************************************
93 : * Declaration and implementation of the GFFRasterBand Class *
94 : *********************************************************************/
95 :
96 : class GFFRasterBand final : public GDALPamRasterBand
97 : {
98 : long nRasterBandMemory;
99 : int nSampleSize;
100 :
101 : public:
102 : GFFRasterBand(GFFDataset *, int, GDALDataType);
103 : CPLErr IReadBlock(int, int, void *) override;
104 : };
105 :
106 0 : static unsigned long GFFSampleSize(GDALDataType eDataType)
107 : {
108 : // Determine the number of bytes per sample.
109 0 : unsigned long nBytes = 1;
110 0 : switch (eDataType)
111 : {
112 0 : case GDT_CInt16:
113 0 : nBytes = 4;
114 0 : break;
115 0 : case GDT_CInt32:
116 : case GDT_CFloat32:
117 0 : nBytes = 8;
118 0 : break;
119 0 : default:
120 0 : nBytes = 1;
121 : }
122 :
123 0 : return nBytes;
124 : }
125 :
126 : /************************************************************************/
127 : /* GFFRasterBand() */
128 : /************************************************************************/
129 0 : GFFRasterBand::GFFRasterBand(GFFDataset *poDSIn, int nBandIn,
130 0 : GDALDataType eDataTypeIn)
131 0 : : nRasterBandMemory(GFFSampleSize(eDataTypeIn) * poDSIn->GetRasterXSize()),
132 0 : nSampleSize(static_cast<int>(GFFSampleSize(eDataTypeIn)))
133 : {
134 0 : poDS = poDSIn;
135 0 : nBand = nBandIn;
136 :
137 0 : eDataType = eDataTypeIn;
138 :
139 0 : nBlockXSize = poDS->GetRasterXSize();
140 0 : nBlockYSize = 1;
141 0 : }
142 :
143 : /************************************************************************/
144 : /* IReadBlock() */
145 : /************************************************************************/
146 :
147 0 : CPLErr GFFRasterBand::IReadBlock(int /* nBlockXOff */, int nBlockYOff,
148 : void *pImage)
149 : {
150 0 : GFFDataset *poGDS = (GFFDataset *)poDS;
151 0 : long nOffset = poGDS->nLength;
152 :
153 0 : VSIFSeekL(poGDS->fp,
154 0 : nOffset + (poGDS->GetRasterXSize() * nBlockYOff * (nSampleSize)),
155 : SEEK_SET);
156 :
157 : /* Ingest entire range line */
158 0 : if (VSIFReadL(pImage, nRasterBandMemory, 1, poGDS->fp) != 1)
159 0 : return CE_Failure;
160 :
161 : #if defined(CPL_MSB)
162 : if (GDALDataTypeIsComplex(eDataType))
163 : {
164 : int nWordSize = GDALGetDataTypeSize(eDataType) / 16;
165 : GDALSwapWords(pImage, nWordSize, nBlockXSize, 2 * nWordSize);
166 : GDALSwapWords(((GByte *)pImage) + nWordSize, nWordSize, nBlockXSize,
167 : 2 * nWordSize);
168 : }
169 : #endif
170 :
171 0 : return CE_None;
172 : }
173 :
174 : /********************************************************************
175 : * ================================================================ *
176 : * Implementation of the GFFDataset Class *
177 : * ================================================================ *
178 : ********************************************************************/
179 :
180 : /************************************************************************/
181 : /* Identify() */
182 : /************************************************************************/
183 34050 : int GFFDataset::Identify(GDALOpenInfo *poOpenInfo)
184 : {
185 34050 : if (poOpenInfo->nHeaderBytes < 7)
186 27218 : return 0;
187 :
188 6832 : if (STARTS_WITH_CI((char *)poOpenInfo->pabyHeader, "GSATIMG"))
189 0 : return 1;
190 :
191 6832 : return 0;
192 : }
193 :
194 : /************************************************************************/
195 : /* Open() */
196 : /************************************************************************/
197 :
198 34050 : GDALDataset *GFFDataset::Open(GDALOpenInfo *poOpenInfo)
199 : {
200 : /* Check that the dataset is indeed a GSAT File Format (GFF) file */
201 34050 : if (!GFFDataset::Identify(poOpenInfo) || poOpenInfo->fpL == nullptr)
202 34049 : return nullptr;
203 :
204 : /* -------------------------------------------------------------------- */
205 : /* Confirm the requested access is supported. */
206 : /* -------------------------------------------------------------------- */
207 0 : if (poOpenInfo->eAccess == GA_Update)
208 : {
209 0 : CPLError(CE_Failure, CPLE_NotSupported,
210 : "The GFF driver does not support update access to existing"
211 : " datasets.\n");
212 0 : return nullptr;
213 : }
214 :
215 0 : GFFDataset *poDS = new GFFDataset();
216 :
217 0 : poDS->fp = poOpenInfo->fpL;
218 0 : poOpenInfo->fpL = nullptr;
219 :
220 : /* Check the endianness of the file */
221 0 : VSIFSeekL(poDS->fp, 54, SEEK_SET);
222 0 : VSIFReadL(&(poDS->nEndianness), 2, 1, poDS->fp);
223 :
224 0 : VSIFSeekL(poDS->fp, 8, SEEK_SET);
225 0 : VSIFReadL(&poDS->nVersionMinor, 2, 1, poDS->fp);
226 0 : CPL_LSBPTR16(&poDS->nVersionMinor);
227 0 : VSIFReadL(&poDS->nVersionMajor, 2, 1, poDS->fp);
228 0 : CPL_LSBPTR16(&poDS->nVersionMajor);
229 0 : VSIFReadL(&poDS->nLength, 4, 1, poDS->fp);
230 0 : CPL_LSBPTR32(&poDS->nLength);
231 :
232 0 : unsigned short nCreatorLength = 0;
233 0 : VSIFReadL(&nCreatorLength, 2, 1, poDS->fp);
234 0 : CPL_LSBPTR16(&nCreatorLength);
235 : /* Hack for now... I should properly load the date metadata, for
236 : * example
237 : */
238 0 : VSIFSeekL(poDS->fp, 56, SEEK_SET);
239 :
240 : /* By looking at the Matlab code, one should write something like the
241 : * following test */
242 : /* but the results don't seem to be the ones really expected */
243 : /*if ((poDS->nVersionMajor == 1 && poDS->nVersionMinor > 7) ||
244 : (poDS->nVersionMajor > 1))
245 : {
246 : float fBPP;
247 : VSIFRead(&fBPP,4,1,poDS->fp);
248 : poDS->nBPP = fBPP;
249 : }
250 : else*/
251 : {
252 0 : VSIFReadL(&poDS->nBPP, 4, 1, poDS->fp);
253 0 : CPL_LSBPTR32(&poDS->nBPP);
254 : }
255 0 : VSIFReadL(&poDS->nFrameCnt, 4, 1, poDS->fp);
256 0 : CPL_LSBPTR32(&poDS->nFrameCnt);
257 0 : VSIFReadL(&poDS->nImageType, 4, 1, poDS->fp);
258 0 : CPL_LSBPTR32(&poDS->nImageType);
259 0 : VSIFReadL(&poDS->nRowMajor, 4, 1, poDS->fp);
260 0 : CPL_LSBPTR32(&poDS->nRowMajor);
261 0 : VSIFReadL(&poDS->nRgCnt, 4, 1, poDS->fp);
262 0 : CPL_LSBPTR32(&poDS->nRgCnt);
263 0 : VSIFReadL(&poDS->nAzCnt, 4, 1, poDS->fp);
264 0 : CPL_LSBPTR32(&poDS->nAzCnt);
265 :
266 : /* We now have enough information to determine the number format */
267 0 : switch (poDS->nImageType)
268 : {
269 0 : case 0:
270 0 : poDS->eDataType = GDT_Byte;
271 0 : break;
272 :
273 0 : case 1:
274 0 : if (poDS->nBPP == 4)
275 0 : poDS->eDataType = GDT_CInt16;
276 : else
277 0 : poDS->eDataType = GDT_CInt32;
278 0 : break;
279 :
280 0 : case 2:
281 0 : poDS->eDataType = GDT_CFloat32;
282 0 : break;
283 :
284 0 : default:
285 0 : CPLError(CE_Failure, CPLE_AppDefined, "Unknown image type found!");
286 0 : delete poDS;
287 0 : return nullptr;
288 : }
289 :
290 : /* Set raster width/height
291 : * Note that the images that are complex are listed as having twice the
292 : * number of X-direction values than there are actual pixels. This is
293 : * because whoever came up with the format was crazy (actually, my
294 : * hunch is that they designed it very much for Matlab)
295 : * */
296 0 : if (poDS->nRowMajor)
297 : {
298 0 : poDS->nRasterXSize = poDS->nRgCnt / (poDS->nImageType == 0 ? 1 : 2);
299 0 : poDS->nRasterYSize = poDS->nAzCnt;
300 : }
301 : else
302 : {
303 0 : poDS->nRasterXSize = poDS->nAzCnt / (poDS->nImageType == 0 ? 1 : 2);
304 0 : poDS->nRasterYSize = poDS->nRgCnt;
305 : }
306 :
307 0 : if (poDS->nRasterXSize <= 0 || poDS->nRasterYSize <= 0)
308 : {
309 0 : CPLError(CE_Failure, CPLE_AppDefined,
310 : "Invalid raster dimensions : %d x %d", poDS->nRasterXSize,
311 : poDS->nRasterYSize);
312 0 : delete poDS;
313 0 : return nullptr;
314 : }
315 :
316 0 : poDS->SetBand(1, new GFFRasterBand(poDS, 1, poDS->eDataType));
317 :
318 : /* -------------------------------------------------------------------- */
319 : /* Initialize any PAM information. */
320 : /* -------------------------------------------------------------------- */
321 0 : poDS->SetDescription(poOpenInfo->pszFilename);
322 0 : poDS->TryLoadXML();
323 :
324 : /* -------------------------------------------------------------------- */
325 : /* Support overviews. */
326 : /* -------------------------------------------------------------------- */
327 0 : poDS->oOvManager.Initialize(poDS, poOpenInfo->pszFilename);
328 :
329 0 : return poDS;
330 : }
331 :
332 : /************************************************************************/
333 : /* GDALRegister_GFF() */
334 : /************************************************************************/
335 :
336 1520 : void GDALRegister_GFF()
337 : {
338 1520 : if (GDALGetDriverByName("GFF") != nullptr)
339 301 : return;
340 :
341 1219 : GDALDriver *poDriver = new GDALDriver();
342 :
343 1219 : poDriver->SetDescription("GFF");
344 1219 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
345 1219 : poDriver->SetMetadataItem(
346 : GDAL_DMD_LONGNAME,
347 1219 : "Ground-based SAR Applications Testbed File Format (.gff)");
348 1219 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/gff.html");
349 1219 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "gff");
350 1219 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
351 1219 : poDriver->pfnOpen = GFFDataset::Open;
352 1219 : GetGDALDriverManager()->RegisterDriver(poDriver);
353 : }
|