1 : /******************************************************************************
2 : * $Id: gff_dataset.cpp 18244 2009-12-10 17:08:59Z warmerdam $
3 : *
4 : * Project: Ground-based SAR Applitcations Testbed File Format driver
5 : * Purpose: Support in GDAL for Sandia National Laboratory's GFF format
6 : * blame Tisham for putting me up to this
7 : * Author: Philippe Vachon <philippe@cowpig.ca>
8 : *
9 : ******************************************************************************
10 : * Copyright (c) 2007, Philippe Vachon
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 "gdal_priv.h"
32 : #include "gdal_pam.h"
33 : #include "cpl_port.h"
34 : #include "cpl_conv.h"
35 : #include "cpl_vsi.h"
36 : #include "cpl_string.h"
37 :
38 : CPL_CVSID("$Id: gff_dataset.cpp 18244 2009-12-10 17:08:59Z warmerdam $");
39 :
40 : /*******************************************************************
41 : * Declaration of the GFFDataset class *
42 : *******************************************************************/
43 :
44 : class GFFRasterBand;
45 :
46 : class GFFDataset : public GDALPamDataset
47 : {
48 : friend class GFFRasterBand;
49 : FILE *fp;
50 : GDALDataType eDataType;
51 : unsigned int nEndianess;
52 : /* Some relevant headers */
53 : unsigned short nVersionMajor;
54 : unsigned short nVersionMinor;
55 : unsigned int nLength;
56 : char *pszCreator;
57 : /* I am taking this at face value (are they freakin' 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 1 : GFFDataset::GFFDataset()
80 : {
81 1 : fp = NULL;
82 1 : }
83 :
84 1 : GFFDataset::~GFFDataset()
85 : {
86 1 : if (fp != NULL)
87 1 : VSIFCloseL(fp);
88 1 : }
89 :
90 : /*********************************************************************
91 : * Declaration and implementation of the GFFRasterBand Class *
92 : *********************************************************************/
93 :
94 1 : class GFFRasterBand : public GDALPamRasterBand {
95 : long nRasterBandMemory;
96 : int nSampleSize;
97 : public:
98 : GFFRasterBand( GFFDataset *, int, GDALDataType );
99 : virtual CPLErr IReadBlock( int, int, void * );
100 : };
101 :
102 : /************************************************************************/
103 : /* GFFRasterBand() */
104 : /************************************************************************/
105 : GFFRasterBand::GFFRasterBand( GFFDataset *poDS, int nBand,
106 1 : GDALDataType eDataType )
107 : {
108 : unsigned long nBytes;
109 1 : this->poDS = poDS;
110 1 : this->nBand = nBand;
111 :
112 1 : this->eDataType = eDataType;
113 :
114 1 : nBlockXSize = poDS->GetRasterXSize();
115 1 : nBlockYSize = 1;
116 :
117 : /* Determine the number of bytes per sample */
118 1 : switch (eDataType) {
119 : case GDT_CInt16:
120 0 : nBytes = 4;
121 0 : break;
122 : case GDT_CInt32:
123 : case GDT_CFloat32:
124 1 : nBytes = 8;
125 1 : break;
126 : default:
127 0 : nBytes = 1;
128 : }
129 :
130 1 : nRasterBandMemory = nBytes * poDS->GetRasterXSize();
131 1 : nSampleSize = nBytes;
132 :
133 1 : }
134 :
135 : /************************************************************************/
136 : /* IReadBlock() */
137 : /************************************************************************/
138 :
139 : CPLErr GFFRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
140 2 : void *pImage )
141 : {
142 2 : GFFDataset *poGDS = (GFFDataset *)poDS;
143 2 : long nOffset = poGDS->nLength;
144 :
145 2 : VSIFSeekL(poGDS->fp, nOffset + (poGDS->GetRasterXSize() * nBlockYOff * (nSampleSize)),SEEK_SET);
146 :
147 : /* Ingest entire range line */
148 2 : if (VSIFReadL(pImage,nRasterBandMemory,1,poGDS->fp) != 1)
149 1 : return CE_Failure;
150 :
151 : #if defined(CPL_MSB)
152 : if( GDALDataTypeIsComplex( eDataType ) )
153 : {
154 : int nWordSize;
155 :
156 : nWordSize = GDALGetDataTypeSize(eDataType)/16;
157 : GDALSwapWords( pImage, nWordSize, nBlockXSize, 2*nWordSize );
158 : GDALSwapWords( ((GByte *) pImage)+nWordSize,
159 : nWordSize, nBlockXSize, 2*nWordSize );
160 : }
161 : #endif
162 :
163 1 : return CE_None;
164 :
165 : }
166 :
167 : /********************************************************************
168 : * ================================================================ *
169 : * Implementation of the GFFDataset Class *
170 : * ================================================================ *
171 : ********************************************************************/
172 :
173 : /************************************************************************/
174 : /* Identify() */
175 : /************************************************************************/
176 11372 : int GFFDataset::Identify( GDALOpenInfo *poOpenInfo )
177 : {
178 11372 : if(poOpenInfo->nHeaderBytes < 7)
179 9835 : return 0;
180 :
181 1537 : if (EQUALN((char *)poOpenInfo->pabyHeader,"GSATIMG",7))
182 1 : return 1;
183 :
184 1536 : return 0;
185 : }
186 :
187 : /************************************************************************/
188 : /* Open() */
189 : /************************************************************************/
190 :
191 11372 : GDALDataset *GFFDataset::Open( GDALOpenInfo *poOpenInfo )
192 : {
193 11372 : unsigned short nCreatorLength = 0;
194 :
195 : /* Check that the dataset is indeed a GSAT File Format (GFF) file */
196 11372 : if (!GFFDataset::Identify(poOpenInfo))
197 11371 : return NULL;
198 :
199 : /* -------------------------------------------------------------------- */
200 : /* Confirm the requested access is supported. */
201 : /* -------------------------------------------------------------------- */
202 1 : if( poOpenInfo->eAccess == GA_Update )
203 : {
204 : CPLError( CE_Failure, CPLE_NotSupported,
205 : "The GFF driver does not support update access to existing"
206 0 : " datasets.\n" );
207 0 : return NULL;
208 : }
209 :
210 : GFFDataset *poDS;
211 1 : poDS = new GFFDataset();
212 :
213 1 : poDS->fp = VSIFOpenL( poOpenInfo->pszFilename, "r" );
214 1 : if( poDS->fp == NULL )
215 : {
216 0 : delete poDS;
217 0 : return NULL;
218 : }
219 :
220 : /* Check the endianess of the file */
221 1 : VSIFSeekL(poDS->fp,54,SEEK_SET);
222 1 : VSIFReadL(&(poDS->nEndianess),2,1,poDS->fp);
223 :
224 : #if defined(CPL_LSB)
225 1 : int bSwap = 0;
226 : #else
227 : int bSwap = 1;
228 : #endif
229 :
230 1 : VSIFSeekL(poDS->fp,8,SEEK_SET);
231 1 : VSIFReadL(&poDS->nVersionMinor,2,1,poDS->fp);
232 1 : if (bSwap) CPL_SWAP16PTR(&poDS->nVersionMinor);
233 1 : VSIFReadL(&poDS->nVersionMajor,2,1,poDS->fp);
234 1 : if (bSwap) CPL_SWAP16PTR(&poDS->nVersionMajor);
235 1 : VSIFReadL(&poDS->nLength,4,1,poDS->fp);
236 1 : if (bSwap) CPL_SWAP32PTR(&poDS->nLength);
237 1 : VSIFReadL(&nCreatorLength,2,1,poDS->fp);
238 1 : if (bSwap) CPL_SWAP16PTR(&nCreatorLength);
239 : /* Hack for now... I should properly load the date metadata, for
240 : * example
241 : */
242 1 : VSIFSeekL(poDS->fp,56,SEEK_SET);
243 :
244 : /* By looking at the Matlab code, one should write something like the following test */
245 : /* but the results don't seem to be the ones really expected */
246 : /*if ((poDS->nVersionMajor == 1 && poDS->nVersionMinor > 7) || (poDS->nVersionMajor > 1))
247 : {
248 : float fBPP;
249 : VSIFRead(&fBPP,4,1,poDS->fp);
250 : poDS->nBPP = fBPP;
251 : }
252 : else*/
253 : {
254 1 : VSIFReadL(&poDS->nBPP,4,1,poDS->fp);
255 1 : if (bSwap) CPL_SWAP32PTR(&poDS->nBPP);
256 : }
257 1 : VSIFReadL(&poDS->nFrameCnt,4,1,poDS->fp);
258 1 : if (bSwap) CPL_SWAP32PTR(&poDS->nFrameCnt);
259 1 : VSIFReadL(&poDS->nImageType,4,1,poDS->fp);
260 1 : if (bSwap) CPL_SWAP32PTR(&poDS->nImageType);
261 1 : VSIFReadL(&poDS->nRowMajor,4,1,poDS->fp);
262 1 : if (bSwap) CPL_SWAP32PTR(&poDS->nRowMajor);
263 1 : VSIFReadL(&poDS->nRgCnt,4,1,poDS->fp);
264 1 : if (bSwap) CPL_SWAP32PTR(&poDS->nRgCnt);
265 1 : VSIFReadL(&poDS->nAzCnt,4,1,poDS->fp);
266 1 : if (bSwap) CPL_SWAP32PTR(&poDS->nAzCnt);
267 :
268 : /* We now have enough information to determine the number format */
269 1 : switch (poDS->nImageType) {
270 : case 0:
271 0 : poDS->eDataType = GDT_Byte;
272 0 : break;
273 :
274 : case 1:
275 1 : if (poDS->nBPP == 4)
276 0 : poDS->eDataType = GDT_CInt16;
277 : else
278 1 : poDS->eDataType = GDT_CInt32;
279 1 : break;
280 :
281 : case 2:
282 0 : poDS->eDataType = GDT_CFloat32;
283 0 : break;
284 :
285 : default:
286 0 : CPLError(CE_Failure, CPLE_AppDefined, "Unknown image type found!");
287 0 : delete poDS;
288 0 : return NULL;
289 : }
290 :
291 : /* Set raster width/height
292 : * Note that the images that are complex are listed as having twice the
293 : * number of X-direction values than there are actual pixels. This is
294 : * because whoever came up with the format was crazy (actually, my
295 : * hunch is that they designed it very much for Matlab)
296 : * */
297 1 : if (poDS->nRowMajor) {
298 0 : poDS->nRasterXSize = poDS->nRgCnt/(poDS->nImageType == 0 ? 1 : 2);
299 0 : poDS->nRasterYSize = poDS->nAzCnt;
300 : }
301 : else {
302 1 : poDS->nRasterXSize = poDS->nAzCnt/(poDS->nImageType == 0 ? 1 : 2);
303 1 : poDS->nRasterYSize = poDS->nRgCnt;
304 : }
305 :
306 1 : if (poDS->nRasterXSize <= 0 || poDS->nRasterYSize <= 0)
307 : {
308 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid raster dimensions : %d x %d",
309 0 : poDS->nRasterXSize, poDS->nRasterYSize);
310 0 : delete poDS;
311 0 : return NULL;
312 : }
313 :
314 1 : poDS->SetBand(1, new GFFRasterBand(poDS, 1, poDS->eDataType));
315 :
316 : /* -------------------------------------------------------------------- */
317 : /* Initialize any PAM information. */
318 : /* -------------------------------------------------------------------- */
319 1 : poDS->SetDescription( poOpenInfo->pszFilename );
320 1 : poDS->TryLoadXML();
321 :
322 : /* -------------------------------------------------------------------- */
323 : /* Support overviews. */
324 : /* -------------------------------------------------------------------- */
325 1 : poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
326 :
327 1 : return poDS;
328 : }
329 :
330 : /************************************************************************/
331 : /* GDALRegister_GFF() */
332 : /************************************************************************/
333 :
334 409 : void GDALRegister_GFF(void)
335 : {
336 : GDALDriver *poDriver;
337 409 : if ( GDALGetDriverByName("GFF") == NULL ) {
338 392 : poDriver = new GDALDriver();
339 392 : poDriver->SetDescription("GFF");
340 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME,
341 392 : "Ground-based SAR Applications Testbed File Format (.gff)");
342 392 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "frmt_various.html#GFF");
343 392 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "gff");
344 392 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
345 392 : poDriver->pfnOpen = GFFDataset::Open;
346 392 : GetGDALDriverManager()->RegisterDriver(poDriver);
347 : }
348 409 : }
|