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