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 : * SPDX-License-Identifier: MIT
13 : ****************************************************************************/
14 :
15 : #include "cpl_conv.h"
16 : #include "cpl_port.h"
17 : #include "cpl_string.h"
18 : #include "cpl_vsi.h"
19 : #include "gdal_frmts.h"
20 : #include "gdal_pam.h"
21 : #include "gdal_priv.h"
22 :
23 : /*******************************************************************
24 : * Declaration of the GFFDataset class *
25 : *******************************************************************/
26 :
27 : class GFFRasterBand;
28 :
29 : class GFFDataset final : public GDALPamDataset
30 : {
31 : friend class GFFRasterBand;
32 : VSILFILE *fp;
33 : GDALDataType eDataType;
34 : unsigned int nEndianness;
35 : /* Some relevant headers */
36 : unsigned short nVersionMajor;
37 : unsigned short nVersionMinor;
38 : unsigned int nLength;
39 : // char *pszCreator;
40 : // TODO: Needs a better explanation.
41 : /* I am taking this at face value (are they insane?) */
42 : // float fBPP;
43 : unsigned int nBPP;
44 :
45 : /* Good information to know */
46 : unsigned int nFrameCnt;
47 : unsigned int nImageType;
48 : unsigned int nRowMajor;
49 : unsigned int nRgCnt;
50 : unsigned int nAzCnt;
51 : // long nScaleExponent;
52 : // long nScaleMantissa;
53 : // long nOffsetExponent;
54 : // long nOffsetMantissa;
55 : public:
56 : GFFDataset();
57 : ~GFFDataset();
58 :
59 : static GDALDataset *Open(GDALOpenInfo *);
60 : static int Identify(GDALOpenInfo *poOpenInfo);
61 : };
62 :
63 0 : GFFDataset::GFFDataset()
64 : : fp(nullptr), eDataType(GDT_Unknown), nEndianness(0), nVersionMajor(0),
65 : nVersionMinor(0), nLength(0), nBPP(0), nFrameCnt(0), nImageType(0),
66 0 : nRowMajor(0), nRgCnt(0), nAzCnt(0)
67 : {
68 0 : }
69 :
70 0 : GFFDataset::~GFFDataset()
71 : {
72 0 : if (fp != nullptr)
73 0 : VSIFCloseL(fp);
74 0 : }
75 :
76 : /*********************************************************************
77 : * Declaration and implementation of the GFFRasterBand Class *
78 : *********************************************************************/
79 :
80 : class GFFRasterBand final : public GDALPamRasterBand
81 : {
82 : long nRasterBandMemory;
83 : int nSampleSize;
84 :
85 : public:
86 : GFFRasterBand(GFFDataset *, int, GDALDataType);
87 : CPLErr IReadBlock(int, int, void *) override;
88 : };
89 :
90 0 : static unsigned long GFFSampleSize(GDALDataType eDataType)
91 : {
92 : // Determine the number of bytes per sample.
93 0 : unsigned long nBytes = 1;
94 0 : switch (eDataType)
95 : {
96 0 : case GDT_CInt16:
97 0 : nBytes = 4;
98 0 : break;
99 0 : case GDT_CInt32:
100 : case GDT_CFloat32:
101 0 : nBytes = 8;
102 0 : break;
103 0 : default:
104 0 : nBytes = 1;
105 : }
106 :
107 0 : return nBytes;
108 : }
109 :
110 : /************************************************************************/
111 : /* GFFRasterBand() */
112 : /************************************************************************/
113 0 : GFFRasterBand::GFFRasterBand(GFFDataset *poDSIn, int nBandIn,
114 0 : GDALDataType eDataTypeIn)
115 0 : : nRasterBandMemory(GFFSampleSize(eDataTypeIn) * poDSIn->GetRasterXSize()),
116 0 : nSampleSize(static_cast<int>(GFFSampleSize(eDataTypeIn)))
117 : {
118 0 : poDS = poDSIn;
119 0 : nBand = nBandIn;
120 :
121 0 : eDataType = eDataTypeIn;
122 :
123 0 : nBlockXSize = poDS->GetRasterXSize();
124 0 : nBlockYSize = 1;
125 0 : }
126 :
127 : /************************************************************************/
128 : /* IReadBlock() */
129 : /************************************************************************/
130 :
131 0 : CPLErr GFFRasterBand::IReadBlock(int /* nBlockXOff */, int nBlockYOff,
132 : void *pImage)
133 : {
134 0 : GFFDataset *poGDS = (GFFDataset *)poDS;
135 0 : long nOffset = poGDS->nLength;
136 :
137 0 : VSIFSeekL(poGDS->fp,
138 0 : nOffset + (poGDS->GetRasterXSize() * nBlockYOff * (nSampleSize)),
139 : SEEK_SET);
140 :
141 : /* Ingest entire range line */
142 0 : if (VSIFReadL(pImage, nRasterBandMemory, 1, poGDS->fp) != 1)
143 0 : return CE_Failure;
144 :
145 : #if defined(CPL_MSB)
146 : if (GDALDataTypeIsComplex(eDataType))
147 : {
148 : int nWordSize = GDALGetDataTypeSize(eDataType) / 16;
149 : GDALSwapWords(pImage, nWordSize, nBlockXSize, 2 * nWordSize);
150 : GDALSwapWords(((GByte *)pImage) + nWordSize, nWordSize, nBlockXSize,
151 : 2 * nWordSize);
152 : }
153 : #endif
154 :
155 0 : return CE_None;
156 : }
157 :
158 : /********************************************************************
159 : * ================================================================ *
160 : * Implementation of the GFFDataset Class *
161 : * ================================================================ *
162 : ********************************************************************/
163 :
164 : /************************************************************************/
165 : /* Identify() */
166 : /************************************************************************/
167 36424 : int GFFDataset::Identify(GDALOpenInfo *poOpenInfo)
168 : {
169 36424 : if (poOpenInfo->nHeaderBytes < 7)
170 29124 : return 0;
171 :
172 7300 : if (STARTS_WITH_CI((char *)poOpenInfo->pabyHeader, "GSATIMG"))
173 0 : return 1;
174 :
175 7300 : return 0;
176 : }
177 :
178 : /************************************************************************/
179 : /* Open() */
180 : /************************************************************************/
181 :
182 36423 : GDALDataset *GFFDataset::Open(GDALOpenInfo *poOpenInfo)
183 : {
184 : /* Check that the dataset is indeed a GSAT File Format (GFF) file */
185 36423 : if (!GFFDataset::Identify(poOpenInfo) || poOpenInfo->fpL == nullptr)
186 36423 : return nullptr;
187 :
188 : /* -------------------------------------------------------------------- */
189 : /* Confirm the requested access is supported. */
190 : /* -------------------------------------------------------------------- */
191 1 : if (poOpenInfo->eAccess == GA_Update)
192 : {
193 0 : ReportUpdateNotSupportedByDriver("GFF");
194 0 : return nullptr;
195 : }
196 :
197 1 : GFFDataset *poDS = new GFFDataset();
198 :
199 0 : poDS->fp = poOpenInfo->fpL;
200 0 : poOpenInfo->fpL = nullptr;
201 :
202 : /* Check the endianness of the file */
203 0 : VSIFSeekL(poDS->fp, 54, SEEK_SET);
204 0 : VSIFReadL(&(poDS->nEndianness), 2, 1, poDS->fp);
205 :
206 0 : VSIFSeekL(poDS->fp, 8, SEEK_SET);
207 0 : VSIFReadL(&poDS->nVersionMinor, 2, 1, poDS->fp);
208 0 : CPL_LSBPTR16(&poDS->nVersionMinor);
209 0 : VSIFReadL(&poDS->nVersionMajor, 2, 1, poDS->fp);
210 0 : CPL_LSBPTR16(&poDS->nVersionMajor);
211 0 : VSIFReadL(&poDS->nLength, 4, 1, poDS->fp);
212 0 : CPL_LSBPTR32(&poDS->nLength);
213 :
214 0 : unsigned short nCreatorLength = 0;
215 0 : VSIFReadL(&nCreatorLength, 2, 1, poDS->fp);
216 0 : CPL_LSBPTR16(&nCreatorLength);
217 : /* Hack for now... I should properly load the date metadata, for
218 : * example
219 : */
220 0 : VSIFSeekL(poDS->fp, 56, SEEK_SET);
221 :
222 : /* By looking at the Matlab code, one should write something like the
223 : * following test */
224 : /* but the results don't seem to be the ones really expected */
225 : /*if ((poDS->nVersionMajor == 1 && poDS->nVersionMinor > 7) ||
226 : (poDS->nVersionMajor > 1))
227 : {
228 : float fBPP;
229 : VSIFRead(&fBPP,4,1,poDS->fp);
230 : poDS->nBPP = fBPP;
231 : }
232 : else*/
233 : {
234 0 : VSIFReadL(&poDS->nBPP, 4, 1, poDS->fp);
235 0 : CPL_LSBPTR32(&poDS->nBPP);
236 : }
237 0 : VSIFReadL(&poDS->nFrameCnt, 4, 1, poDS->fp);
238 0 : CPL_LSBPTR32(&poDS->nFrameCnt);
239 0 : VSIFReadL(&poDS->nImageType, 4, 1, poDS->fp);
240 0 : CPL_LSBPTR32(&poDS->nImageType);
241 0 : VSIFReadL(&poDS->nRowMajor, 4, 1, poDS->fp);
242 0 : CPL_LSBPTR32(&poDS->nRowMajor);
243 0 : VSIFReadL(&poDS->nRgCnt, 4, 1, poDS->fp);
244 0 : CPL_LSBPTR32(&poDS->nRgCnt);
245 0 : VSIFReadL(&poDS->nAzCnt, 4, 1, poDS->fp);
246 0 : CPL_LSBPTR32(&poDS->nAzCnt);
247 :
248 : /* We now have enough information to determine the number format */
249 0 : switch (poDS->nImageType)
250 : {
251 0 : case 0:
252 0 : poDS->eDataType = GDT_Byte;
253 0 : break;
254 :
255 0 : case 1:
256 0 : if (poDS->nBPP == 4)
257 0 : poDS->eDataType = GDT_CInt16;
258 : else
259 0 : poDS->eDataType = GDT_CInt32;
260 0 : break;
261 :
262 0 : case 2:
263 0 : poDS->eDataType = GDT_CFloat32;
264 0 : break;
265 :
266 0 : default:
267 0 : CPLError(CE_Failure, CPLE_AppDefined, "Unknown image type found!");
268 0 : delete poDS;
269 0 : return nullptr;
270 : }
271 :
272 : /* Set raster width/height
273 : * Note that the images that are complex are listed as having twice the
274 : * number of X-direction values than there are actual pixels. This is
275 : * because whoever came up with the format was crazy (actually, my
276 : * hunch is that they designed it very much for Matlab)
277 : * */
278 0 : if (poDS->nRowMajor)
279 : {
280 0 : poDS->nRasterXSize = poDS->nRgCnt / (poDS->nImageType == 0 ? 1 : 2);
281 0 : poDS->nRasterYSize = poDS->nAzCnt;
282 : }
283 : else
284 : {
285 0 : poDS->nRasterXSize = poDS->nAzCnt / (poDS->nImageType == 0 ? 1 : 2);
286 0 : poDS->nRasterYSize = poDS->nRgCnt;
287 : }
288 :
289 0 : if (poDS->nRasterXSize <= 0 || poDS->nRasterYSize <= 0)
290 : {
291 0 : CPLError(CE_Failure, CPLE_AppDefined,
292 : "Invalid raster dimensions : %d x %d", poDS->nRasterXSize,
293 : poDS->nRasterYSize);
294 0 : delete poDS;
295 0 : return nullptr;
296 : }
297 :
298 0 : poDS->SetBand(1, new GFFRasterBand(poDS, 1, poDS->eDataType));
299 :
300 : /* -------------------------------------------------------------------- */
301 : /* Initialize any PAM information. */
302 : /* -------------------------------------------------------------------- */
303 0 : poDS->SetDescription(poOpenInfo->pszFilename);
304 0 : poDS->TryLoadXML();
305 :
306 : /* -------------------------------------------------------------------- */
307 : /* Support overviews. */
308 : /* -------------------------------------------------------------------- */
309 0 : poDS->oOvManager.Initialize(poDS, poOpenInfo->pszFilename);
310 :
311 0 : return poDS;
312 : }
313 :
314 : /************************************************************************/
315 : /* GDALRegister_GFF() */
316 : /************************************************************************/
317 :
318 1686 : void GDALRegister_GFF()
319 : {
320 1686 : if (GDALGetDriverByName("GFF") != nullptr)
321 302 : return;
322 :
323 1384 : GDALDriver *poDriver = new GDALDriver();
324 :
325 1384 : poDriver->SetDescription("GFF");
326 1384 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
327 1384 : poDriver->SetMetadataItem(
328 : GDAL_DMD_LONGNAME,
329 1384 : "Ground-based SAR Applications Testbed File Format (.gff)");
330 1384 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/gff.html");
331 1384 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "gff");
332 1384 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
333 1384 : poDriver->pfnOpen = GFFDataset::Open;
334 1384 : GetGDALDriverManager()->RegisterDriver(poDriver);
335 : }
|