Coverage Report

Created: 2026-06-30 08:33

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/frmts/gff/gff_dataset.cpp
Line
Count
Source
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
GFFDataset::GFFDataset()
64
119
    : fp(nullptr), eDataType(GDT_Unknown), nEndianness(0), nVersionMajor(0),
65
119
      nVersionMinor(0), nLength(0), nBPP(0), nFrameCnt(0), nImageType(0),
66
119
      nRowMajor(0), nRgCnt(0), nAzCnt(0)
67
119
{
68
119
}
69
70
GFFDataset::~GFFDataset()
71
119
{
72
119
    if (fp != nullptr)
73
119
        VSIFCloseL(fp);
74
119
}
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
204
{
92
    // Determine the number of bytes per sample.
93
204
    unsigned long nBytes = 1;
94
204
    switch (eDataType)
95
204
    {
96
110
        case GDT_CInt16:
97
110
            nBytes = 4;
98
110
            break;
99
0
        case GDT_CInt32:
100
74
        case GDT_CFloat32:
101
74
            nBytes = 8;
102
74
            break;
103
20
        default:
104
20
            nBytes = 1;
105
204
    }
106
107
204
    return nBytes;
108
204
}
109
110
/************************************************************************/
111
/*                           GFFRasterBand()                            */
112
/************************************************************************/
113
GFFRasterBand::GFFRasterBand(GFFDataset *poDSIn, int nBandIn,
114
                             GDALDataType eDataTypeIn)
115
102
    : nRasterBandMemory(GFFSampleSize(eDataTypeIn) * poDSIn->GetRasterXSize()),
116
102
      nSampleSize(static_cast<int>(GFFSampleSize(eDataTypeIn)))
117
102
{
118
102
    poDS = poDSIn;
119
102
    nBand = nBandIn;
120
121
102
    eDataType = eDataTypeIn;
122
123
102
    nBlockXSize = poDS->GetRasterXSize();
124
102
    nBlockYSize = 1;
125
102
}
126
127
/************************************************************************/
128
/*                             IReadBlock()                             */
129
/************************************************************************/
130
131
CPLErr GFFRasterBand::IReadBlock(int /* nBlockXOff */, int nBlockYOff,
132
                                 void *pImage)
133
2.78k
{
134
2.78k
    GFFDataset *poGDS = cpl::down_cast<GFFDataset *>(poDS);
135
2.78k
    long nOffset = poGDS->nLength;
136
137
2.78k
    VSIFSeekL(poGDS->fp,
138
2.78k
              nOffset + (static_cast<vsi_l_offset>(poGDS->GetRasterXSize()) *
139
2.78k
                         nBlockYOff * (nSampleSize)),
140
2.78k
              SEEK_SET);
141
142
    /* Ingest entire range line */
143
2.78k
    if (VSIFReadL(pImage, nRasterBandMemory, 1, poGDS->fp) != 1)
144
31
        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
2.75k
    return CE_None;
157
2.78k
}
158
159
/********************************************************************
160
 * ================================================================ *
161
 * Implementation of the GFFDataset Class                           *
162
 * ================================================================ *
163
 ********************************************************************/
164
165
/************************************************************************/
166
/*                              Identify()                              */
167
/************************************************************************/
168
int GFFDataset::Identify(GDALOpenInfo *poOpenInfo)
169
503k
{
170
503k
    if (poOpenInfo->nHeaderBytes < 7)
171
397k
        return 0;
172
173
106k
    if (STARTS_WITH_CI((char *)poOpenInfo->pabyHeader, "GSATIMG"))
174
119
        return 1;
175
176
106k
    return 0;
177
106k
}
178
179
/************************************************************************/
180
/*                                Open()                                */
181
/************************************************************************/
182
183
GDALDataset *GFFDataset::Open(GDALOpenInfo *poOpenInfo)
184
503k
{
185
    /* Check that the dataset is indeed a GSAT File Format (GFF) file */
186
503k
    if (!GFFDataset::Identify(poOpenInfo) || poOpenInfo->fpL == nullptr)
187
503k
        return nullptr;
188
189
    /* -------------------------------------------------------------------- */
190
    /*      Confirm the requested access is supported.                      */
191
    /* -------------------------------------------------------------------- */
192
119
    if (poOpenInfo->eAccess == GA_Update)
193
0
    {
194
0
        ReportUpdateNotSupportedByDriver("GFF");
195
0
        return nullptr;
196
0
    }
197
198
119
    GFFDataset *poDS = new GFFDataset();
199
200
119
    poDS->fp = poOpenInfo->fpL;
201
119
    poOpenInfo->fpL = nullptr;
202
203
    /* Check the endianness of the file */
204
119
    VSIFSeekL(poDS->fp, 54, SEEK_SET);
205
119
    VSIFReadL(&(poDS->nEndianness), 2, 1, poDS->fp);
206
207
119
    VSIFSeekL(poDS->fp, 8, SEEK_SET);
208
119
    VSIFReadL(&poDS->nVersionMinor, 2, 1, poDS->fp);
209
119
    CPL_LSBPTR16(&poDS->nVersionMinor);
210
119
    VSIFReadL(&poDS->nVersionMajor, 2, 1, poDS->fp);
211
119
    CPL_LSBPTR16(&poDS->nVersionMajor);
212
119
    VSIFReadL(&poDS->nLength, 4, 1, poDS->fp);
213
119
    CPL_LSBPTR32(&poDS->nLength);
214
215
119
    unsigned short nCreatorLength = 0;
216
119
    VSIFReadL(&nCreatorLength, 2, 1, poDS->fp);
217
119
    CPL_LSBPTR16(&nCreatorLength);
218
    /* Hack for now... I should properly load the date metadata, for
219
     * example
220
     */
221
119
    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
119
    {
235
119
        VSIFReadL(&poDS->nBPP, 4, 1, poDS->fp);
236
119
        CPL_LSBPTR32(&poDS->nBPP);
237
119
    }
238
119
    VSIFReadL(&poDS->nFrameCnt, 4, 1, poDS->fp);
239
119
    CPL_LSBPTR32(&poDS->nFrameCnt);
240
119
    VSIFReadL(&poDS->nImageType, 4, 1, poDS->fp);
241
119
    CPL_LSBPTR32(&poDS->nImageType);
242
119
    VSIFReadL(&poDS->nRowMajor, 4, 1, poDS->fp);
243
119
    CPL_LSBPTR32(&poDS->nRowMajor);
244
119
    VSIFReadL(&poDS->nRgCnt, 4, 1, poDS->fp);
245
119
    CPL_LSBPTR32(&poDS->nRgCnt);
246
119
    VSIFReadL(&poDS->nAzCnt, 4, 1, poDS->fp);
247
119
    CPL_LSBPTR32(&poDS->nAzCnt);
248
249
    /* We now have enough information to determine the number format */
250
119
    switch (poDS->nImageType)
251
119
    {
252
10
        case 0:
253
10
            poDS->eDataType = GDT_UInt8;
254
10
            break;
255
256
55
        case 1:
257
55
            if (poDS->nBPP == 4)
258
55
                poDS->eDataType = GDT_CInt16;
259
0
            else
260
0
                poDS->eDataType = GDT_CInt32;
261
55
            break;
262
263
39
        case 2:
264
39
            poDS->eDataType = GDT_CFloat32;
265
39
            break;
266
267
15
        default:
268
15
            CPLError(CE_Failure, CPLE_AppDefined, "Unknown image type found!");
269
15
            delete poDS;
270
15
            return nullptr;
271
119
    }
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
104
    if (poDS->nRowMajor)
280
67
    {
281
67
        poDS->nRasterXSize = poDS->nRgCnt / (poDS->nImageType == 0 ? 1 : 2);
282
67
        poDS->nRasterYSize = poDS->nAzCnt;
283
67
    }
284
37
    else
285
37
    {
286
37
        poDS->nRasterXSize = poDS->nAzCnt / (poDS->nImageType == 0 ? 1 : 2);
287
37
        poDS->nRasterYSize = poDS->nRgCnt;
288
37
    }
289
290
104
    if (poDS->nRasterXSize <= 0 || poDS->nRasterYSize <= 0)
291
2
    {
292
2
        CPLError(CE_Failure, CPLE_AppDefined,
293
2
                 "Invalid raster dimensions : %d x %d", poDS->nRasterXSize,
294
2
                 poDS->nRasterYSize);
295
2
        delete poDS;
296
2
        return nullptr;
297
2
    }
298
299
102
    poDS->SetBand(1, new GFFRasterBand(poDS, 1, poDS->eDataType));
300
301
    /* -------------------------------------------------------------------- */
302
    /*      Initialize any PAM information.                                 */
303
    /* -------------------------------------------------------------------- */
304
102
    poDS->SetDescription(poOpenInfo->pszFilename);
305
102
    poDS->TryLoadXML();
306
307
    /* -------------------------------------------------------------------- */
308
    /*      Support overviews.                                              */
309
    /* -------------------------------------------------------------------- */
310
102
    poDS->oOvManager.Initialize(poDS, poOpenInfo->pszFilename);
311
312
102
    return poDS;
313
104
}
314
315
/************************************************************************/
316
/*                          GDALRegister_GFF()                          */
317
/************************************************************************/
318
319
void GDALRegister_GFF()
320
22
{
321
22
    if (GDALGetDriverByName("GFF") != nullptr)
322
0
        return;
323
324
22
    GDALDriver *poDriver = new GDALDriver();
325
326
22
    poDriver->SetDescription("GFF");
327
22
    poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
328
22
    poDriver->SetMetadataItem(
329
22
        GDAL_DMD_LONGNAME,
330
22
        "Ground-based SAR Applications Testbed File Format (.gff)");
331
22
    poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/gff.html");
332
22
    poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "gff");
333
22
    poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
334
22
    poDriver->pfnOpen = GFFDataset::Open;
335
22
    GetGDALDriverManager()->RegisterDriver(poDriver);
336
22
}