Coverage Report

Created: 2025-06-09 07:07

/src/gdal/frmts/gff/gff_dataset.cpp
Line
Count
Source (jump to first uncovered line)
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
GFFDataset::GFFDataset()
64
0
    : fp(nullptr), eDataType(GDT_Unknown), nEndianness(0), nVersionMajor(0),
65
0
      nVersionMinor(0), nLength(0), nBPP(0), nFrameCnt(0), nImageType(0),
66
0
      nRowMajor(0), nRgCnt(0), nAzCnt(0)
67
0
{
68
0
}
69
70
GFFDataset::~GFFDataset()
71
0
{
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
static unsigned long GFFSampleSize(GDALDataType eDataType)
91
0
{
92
    // Determine the number of bytes per sample.
93
0
    unsigned long nBytes = 1;
94
0
    switch (eDataType)
95
0
    {
96
0
        case GDT_CInt16:
97
0
            nBytes = 4;
98
0
            break;
99
0
        case GDT_CInt32:
100
0
        case GDT_CFloat32:
101
0
            nBytes = 8;
102
0
            break;
103
0
        default:
104
0
            nBytes = 1;
105
0
    }
106
107
0
    return nBytes;
108
0
}
109
110
/************************************************************************/
111
/*                           GFFRasterBand()                            */
112
/************************************************************************/
113
GFFRasterBand::GFFRasterBand(GFFDataset *poDSIn, int nBandIn,
114
                             GDALDataType eDataTypeIn)
115
0
    : nRasterBandMemory(GFFSampleSize(eDataTypeIn) * poDSIn->GetRasterXSize()),
116
0
      nSampleSize(static_cast<int>(GFFSampleSize(eDataTypeIn)))
117
0
{
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
CPLErr GFFRasterBand::IReadBlock(int /* nBlockXOff */, int nBlockYOff,
132
                                 void *pImage)
133
0
{
134
0
    GFFDataset *poGDS = cpl::down_cast<GFFDataset *>(poDS);
135
0
    long nOffset = poGDS->nLength;
136
137
0
    VSIFSeekL(poGDS->fp,
138
0
              nOffset + (poGDS->GetRasterXSize() * nBlockYOff * (nSampleSize)),
139
0
              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
0
}
157
158
/********************************************************************
159
 * ================================================================ *
160
 * Implementation of the GFFDataset Class                           *
161
 * ================================================================ *
162
 ********************************************************************/
163
164
/************************************************************************/
165
/*                              Identify()                              */
166
/************************************************************************/
167
int GFFDataset::Identify(GDALOpenInfo *poOpenInfo)
168
16.3k
{
169
16.3k
    if (poOpenInfo->nHeaderBytes < 7)
170
571
        return 0;
171
172
15.7k
    if (STARTS_WITH_CI((char *)poOpenInfo->pabyHeader, "GSATIMG"))
173
0
        return 1;
174
175
15.7k
    return 0;
176
15.7k
}
177
178
/************************************************************************/
179
/*                                Open()                                */
180
/************************************************************************/
181
182
GDALDataset *GFFDataset::Open(GDALOpenInfo *poOpenInfo)
183
16.3k
{
184
    /* Check that the dataset is indeed a GSAT File Format (GFF) file */
185
16.3k
    if (!GFFDataset::Identify(poOpenInfo) || poOpenInfo->fpL == nullptr)
186
16.3k
        return nullptr;
187
188
    /* -------------------------------------------------------------------- */
189
    /*      Confirm the requested access is supported.                      */
190
    /* -------------------------------------------------------------------- */
191
0
    if (poOpenInfo->eAccess == GA_Update)
192
0
    {
193
0
        ReportUpdateNotSupportedByDriver("GFF");
194
0
        return nullptr;
195
0
    }
196
197
0
    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
0
    {
234
0
        VSIFReadL(&poDS->nBPP, 4, 1, poDS->fp);
235
0
        CPL_LSBPTR32(&poDS->nBPP);
236
0
    }
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
0
    {
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
0
            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
0
    }
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
0
    {
280
0
        poDS->nRasterXSize = poDS->nRgCnt / (poDS->nImageType == 0 ? 1 : 2);
281
0
        poDS->nRasterYSize = poDS->nAzCnt;
282
0
    }
283
0
    else
284
0
    {
285
0
        poDS->nRasterXSize = poDS->nAzCnt / (poDS->nImageType == 0 ? 1 : 2);
286
0
        poDS->nRasterYSize = poDS->nRgCnt;
287
0
    }
288
289
0
    if (poDS->nRasterXSize <= 0 || poDS->nRasterYSize <= 0)
290
0
    {
291
0
        CPLError(CE_Failure, CPLE_AppDefined,
292
0
                 "Invalid raster dimensions : %d x %d", poDS->nRasterXSize,
293
0
                 poDS->nRasterYSize);
294
0
        delete poDS;
295
0
        return nullptr;
296
0
    }
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
0
}
313
314
/************************************************************************/
315
/*                          GDALRegister_GFF()                          */
316
/************************************************************************/
317
318
void GDALRegister_GFF()
319
2
{
320
2
    if (GDALGetDriverByName("GFF") != nullptr)
321
0
        return;
322
323
2
    GDALDriver *poDriver = new GDALDriver();
324
325
2
    poDriver->SetDescription("GFF");
326
2
    poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
327
2
    poDriver->SetMetadataItem(
328
2
        GDAL_DMD_LONGNAME,
329
2
        "Ground-based SAR Applications Testbed File Format (.gff)");
330
2
    poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/gff.html");
331
2
    poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "gff");
332
2
    poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
333
2
    poDriver->pfnOpen = GFFDataset::Open;
334
2
    GetGDALDriverManager()->RegisterDriver(poDriver);
335
2
}