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 35861 : int GFFDataset::Identify(GDALOpenInfo *poOpenInfo)
168 : {
169 35861 : if (poOpenInfo->nHeaderBytes < 7)
170 28596 : return 0;
171 :
172 7265 : if (STARTS_WITH_CI((char *)poOpenInfo->pabyHeader, "GSATIMG"))
173 0 : return 1;
174 :
175 7265 : return 0;
176 : }
177 :
178 : /************************************************************************/
179 : /* Open() */
180 : /************************************************************************/
181 :
182 35861 : GDALDataset *GFFDataset::Open(GDALOpenInfo *poOpenInfo)
183 : {
184 : /* Check that the dataset is indeed a GSAT File Format (GFF) file */
185 35861 : if (!GFFDataset::Identify(poOpenInfo) || poOpenInfo->fpL == nullptr)
186 35859 : return nullptr;
187 :
188 : /* -------------------------------------------------------------------- */
189 : /* Confirm the requested access is supported. */
190 : /* -------------------------------------------------------------------- */
191 0 : if (poOpenInfo->eAccess == GA_Update)
192 : {
193 0 : CPLError(CE_Failure, CPLE_NotSupported,
194 : "The GFF driver does not support update access to existing"
195 : " datasets.\n");
196 0 : return nullptr;
197 : }
198 :
199 0 : GFFDataset *poDS = new GFFDataset();
200 :
201 0 : poDS->fp = poOpenInfo->fpL;
202 0 : poOpenInfo->fpL = nullptr;
203 :
204 : /* Check the endianness of the file */
205 0 : VSIFSeekL(poDS->fp, 54, SEEK_SET);
206 0 : VSIFReadL(&(poDS->nEndianness), 2, 1, poDS->fp);
207 :
208 0 : VSIFSeekL(poDS->fp, 8, SEEK_SET);
209 0 : VSIFReadL(&poDS->nVersionMinor, 2, 1, poDS->fp);
210 0 : CPL_LSBPTR16(&poDS->nVersionMinor);
211 0 : VSIFReadL(&poDS->nVersionMajor, 2, 1, poDS->fp);
212 0 : CPL_LSBPTR16(&poDS->nVersionMajor);
213 0 : VSIFReadL(&poDS->nLength, 4, 1, poDS->fp);
214 0 : CPL_LSBPTR32(&poDS->nLength);
215 :
216 0 : unsigned short nCreatorLength = 0;
217 0 : VSIFReadL(&nCreatorLength, 2, 1, poDS->fp);
218 0 : CPL_LSBPTR16(&nCreatorLength);
219 : /* Hack for now... I should properly load the date metadata, for
220 : * example
221 : */
222 0 : VSIFSeekL(poDS->fp, 56, SEEK_SET);
223 :
224 : /* By looking at the Matlab code, one should write something like the
225 : * following test */
226 : /* but the results don't seem to be the ones really expected */
227 : /*if ((poDS->nVersionMajor == 1 && poDS->nVersionMinor > 7) ||
228 : (poDS->nVersionMajor > 1))
229 : {
230 : float fBPP;
231 : VSIFRead(&fBPP,4,1,poDS->fp);
232 : poDS->nBPP = fBPP;
233 : }
234 : else*/
235 : {
236 0 : VSIFReadL(&poDS->nBPP, 4, 1, poDS->fp);
237 0 : CPL_LSBPTR32(&poDS->nBPP);
238 : }
239 0 : VSIFReadL(&poDS->nFrameCnt, 4, 1, poDS->fp);
240 0 : CPL_LSBPTR32(&poDS->nFrameCnt);
241 0 : VSIFReadL(&poDS->nImageType, 4, 1, poDS->fp);
242 0 : CPL_LSBPTR32(&poDS->nImageType);
243 0 : VSIFReadL(&poDS->nRowMajor, 4, 1, poDS->fp);
244 0 : CPL_LSBPTR32(&poDS->nRowMajor);
245 0 : VSIFReadL(&poDS->nRgCnt, 4, 1, poDS->fp);
246 0 : CPL_LSBPTR32(&poDS->nRgCnt);
247 0 : VSIFReadL(&poDS->nAzCnt, 4, 1, poDS->fp);
248 0 : CPL_LSBPTR32(&poDS->nAzCnt);
249 :
250 : /* We now have enough information to determine the number format */
251 0 : switch (poDS->nImageType)
252 : {
253 0 : case 0:
254 0 : poDS->eDataType = GDT_Byte;
255 0 : break;
256 :
257 0 : case 1:
258 0 : if (poDS->nBPP == 4)
259 0 : poDS->eDataType = GDT_CInt16;
260 : else
261 0 : poDS->eDataType = GDT_CInt32;
262 0 : break;
263 :
264 0 : case 2:
265 0 : poDS->eDataType = GDT_CFloat32;
266 0 : break;
267 :
268 0 : default:
269 0 : CPLError(CE_Failure, CPLE_AppDefined, "Unknown image type found!");
270 0 : delete poDS;
271 0 : return nullptr;
272 : }
273 :
274 : /* Set raster width/height
275 : * Note that the images that are complex are listed as having twice the
276 : * number of X-direction values than there are actual pixels. This is
277 : * because whoever came up with the format was crazy (actually, my
278 : * hunch is that they designed it very much for Matlab)
279 : * */
280 0 : if (poDS->nRowMajor)
281 : {
282 0 : poDS->nRasterXSize = poDS->nRgCnt / (poDS->nImageType == 0 ? 1 : 2);
283 0 : poDS->nRasterYSize = poDS->nAzCnt;
284 : }
285 : else
286 : {
287 0 : poDS->nRasterXSize = poDS->nAzCnt / (poDS->nImageType == 0 ? 1 : 2);
288 0 : poDS->nRasterYSize = poDS->nRgCnt;
289 : }
290 :
291 0 : if (poDS->nRasterXSize <= 0 || poDS->nRasterYSize <= 0)
292 : {
293 0 : CPLError(CE_Failure, CPLE_AppDefined,
294 : "Invalid raster dimensions : %d x %d", poDS->nRasterXSize,
295 : poDS->nRasterYSize);
296 0 : delete poDS;
297 0 : return nullptr;
298 : }
299 :
300 0 : poDS->SetBand(1, new GFFRasterBand(poDS, 1, poDS->eDataType));
301 :
302 : /* -------------------------------------------------------------------- */
303 : /* Initialize any PAM information. */
304 : /* -------------------------------------------------------------------- */
305 0 : poDS->SetDescription(poOpenInfo->pszFilename);
306 0 : poDS->TryLoadXML();
307 :
308 : /* -------------------------------------------------------------------- */
309 : /* Support overviews. */
310 : /* -------------------------------------------------------------------- */
311 0 : poDS->oOvManager.Initialize(poDS, poOpenInfo->pszFilename);
312 :
313 0 : return poDS;
314 : }
315 :
316 : /************************************************************************/
317 : /* GDALRegister_GFF() */
318 : /************************************************************************/
319 :
320 1595 : void GDALRegister_GFF()
321 : {
322 1595 : if (GDALGetDriverByName("GFF") != nullptr)
323 302 : return;
324 :
325 1293 : GDALDriver *poDriver = new GDALDriver();
326 :
327 1293 : poDriver->SetDescription("GFF");
328 1293 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
329 1293 : poDriver->SetMetadataItem(
330 : GDAL_DMD_LONGNAME,
331 1293 : "Ground-based SAR Applications Testbed File Format (.gff)");
332 1293 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/gff.html");
333 1293 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "gff");
334 1293 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
335 1293 : poDriver->pfnOpen = GFFDataset::Open;
336 1293 : GetGDALDriverManager()->RegisterDriver(poDriver);
337 : }
|