Coverage Report

Created: 2025-07-23 09:13

/src/gdal/frmts/raw/gscdataset.cpp
Line
Count
Source (jump to first uncovered line)
1
/******************************************************************************
2
 *
3
 * Project:  GSC Geogrid format driver.
4
 * Purpose:  Implements support for reading and writing GSC Geogrid format.
5
 * Author:   Frank Warmerdam <warmerdam@pobox.com>
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 2002, Frank Warmerdam <warmerdam@pobox.com>
9
 * Copyright (c) 2009-2011, Even Rouault <even dot rouault at spatialys.com>
10
 *
11
 * SPDX-License-Identifier: MIT
12
 ****************************************************************************/
13
14
#include "cpl_string.h"
15
#include "gdal_frmts.h"
16
#include "rawdataset.h"
17
18
#include <algorithm>
19
20
/************************************************************************/
21
/* ==================================================================== */
22
/*                              GSCDataset                              */
23
/* ==================================================================== */
24
/************************************************************************/
25
26
class GSCDataset final : public RawDataset
27
{
28
    VSILFILE *fpImage = nullptr;  // image data file.
29
30
    GDALGeoTransform m_gt{};
31
32
    CPL_DISALLOW_COPY_ASSIGN(GSCDataset)
33
34
    CPLErr Close() override;
35
36
  public:
37
0
    GSCDataset() = default;
38
    ~GSCDataset();
39
40
    CPLErr GetGeoTransform(GDALGeoTransform &gt) const override;
41
42
    static GDALDataset *Open(GDALOpenInfo *);
43
};
44
45
/************************************************************************/
46
/*                            ~GSCDataset()                             */
47
/************************************************************************/
48
49
GSCDataset::~GSCDataset()
50
51
0
{
52
0
    GSCDataset::Close();
53
0
}
54
55
/************************************************************************/
56
/*                              Close()                                 */
57
/************************************************************************/
58
59
CPLErr GSCDataset::Close()
60
0
{
61
0
    CPLErr eErr = CE_None;
62
0
    if (nOpenFlags != OPEN_FLAGS_CLOSED)
63
0
    {
64
0
        if (GSCDataset::FlushCache(true) != CE_None)
65
0
            eErr = CE_Failure;
66
67
0
        if (fpImage)
68
0
        {
69
0
            if (VSIFCloseL(fpImage) != 0)
70
0
            {
71
0
                CPLError(CE_Failure, CPLE_FileIO, "I/O error");
72
0
                eErr = CE_Failure;
73
0
            }
74
0
        }
75
76
0
        if (GDALPamDataset::Close() != CE_None)
77
0
            eErr = CE_Failure;
78
0
    }
79
0
    return eErr;
80
0
}
81
82
/************************************************************************/
83
/*                          GetGeoTransform()                           */
84
/************************************************************************/
85
86
CPLErr GSCDataset::GetGeoTransform(GDALGeoTransform &gt) const
87
88
0
{
89
0
    gt = m_gt;
90
91
0
    return CE_None;
92
0
}
93
94
/************************************************************************/
95
/*                                Open()                                */
96
/************************************************************************/
97
98
GDALDataset *GSCDataset::Open(GDALOpenInfo *poOpenInfo)
99
100
548k
{
101
102
    /* -------------------------------------------------------------------- */
103
    /*      Does this plausible look like a GSC Geogrid file?               */
104
    /* -------------------------------------------------------------------- */
105
548k
    if (poOpenInfo->nHeaderBytes < 20)
106
477k
        return nullptr;
107
108
71.7k
    if (poOpenInfo->pabyHeader[12] != 0x02 ||
109
71.7k
        poOpenInfo->pabyHeader[13] != 0x00 ||
110
71.7k
        poOpenInfo->pabyHeader[14] != 0x00 ||
111
71.7k
        poOpenInfo->pabyHeader[15] != 0x00)
112
71.6k
        return nullptr;
113
114
77
    int nRecordLen =
115
77
        CPL_LSBWORD32(reinterpret_cast<GInt32 *>(poOpenInfo->pabyHeader)[0]);
116
77
    const int nPixels =
117
77
        CPL_LSBWORD32(reinterpret_cast<GInt32 *>(poOpenInfo->pabyHeader)[1]);
118
77
    const int nLines =
119
77
        CPL_LSBWORD32(reinterpret_cast<GInt32 *>(poOpenInfo->pabyHeader)[2]);
120
121
77
    if (nPixels < 1 || nLines < 1 || nPixels > 100000 || nLines > 100000)
122
73
        return nullptr;
123
124
4
    if (nRecordLen != nPixels * 4)
125
4
        return nullptr;
126
127
    /* -------------------------------------------------------------------- */
128
    /*      Confirm the requested access is supported.                      */
129
    /* -------------------------------------------------------------------- */
130
0
    if (poOpenInfo->eAccess == GA_Update)
131
0
    {
132
0
        ReportUpdateNotSupportedByDriver("GSC");
133
0
        return nullptr;
134
0
    }
135
136
0
    nRecordLen += 8;  // For record length markers.
137
138
    /* -------------------------------------------------------------------- */
139
    /*      Create a corresponding GDALDataset.                             */
140
    /* -------------------------------------------------------------------- */
141
0
    auto poDS = std::make_unique<GSCDataset>();
142
143
0
    poDS->nRasterXSize = nPixels;
144
0
    poDS->nRasterYSize = nLines;
145
0
    std::swap(poDS->fpImage, poOpenInfo->fpL);
146
147
    /* -------------------------------------------------------------------- */
148
    /*      Read the header information in the second record.               */
149
    /* -------------------------------------------------------------------- */
150
0
    float afHeaderInfo[8] = {0.0};
151
152
0
    if (VSIFSeekL(poDS->fpImage, nRecordLen + 12, SEEK_SET) != 0 ||
153
0
        VSIFReadL(afHeaderInfo, sizeof(float), 8, poDS->fpImage) != 8)
154
0
    {
155
0
        CPLError(
156
0
            CE_Failure, CPLE_FileIO,
157
0
            "Failure reading second record of GSC file with %d record length.",
158
0
            nRecordLen);
159
0
        return nullptr;
160
0
    }
161
162
0
    for (int i = 0; i < 8; i++)
163
0
    {
164
0
        CPL_LSBPTR32(afHeaderInfo + i);
165
0
    }
166
167
0
    poDS->m_gt[0] = afHeaderInfo[2];
168
0
    poDS->m_gt[1] = afHeaderInfo[0];
169
0
    poDS->m_gt[2] = 0.0;
170
0
    poDS->m_gt[3] = afHeaderInfo[5];
171
0
    poDS->m_gt[4] = 0.0;
172
0
    poDS->m_gt[5] = -afHeaderInfo[1];
173
174
    /* -------------------------------------------------------------------- */
175
    /*      Create band information objects.                                */
176
    /* -------------------------------------------------------------------- */
177
0
    auto poBand = RawRasterBand::Create(
178
0
        poDS.get(), 1, poDS->fpImage, nRecordLen * 2 + 4, sizeof(float),
179
0
        nRecordLen, GDT_Float32, RawRasterBand::ByteOrder::ORDER_LITTLE_ENDIAN,
180
0
        RawRasterBand::OwnFP::NO);
181
0
    if (!poBand)
182
0
        return nullptr;
183
0
    poBand->SetNoDataValue(-1.0000000150474662199e+30);
184
0
    poDS->SetBand(1, std::move(poBand));
185
186
    /* -------------------------------------------------------------------- */
187
    /*      Initialize any PAM information.                                 */
188
    /* -------------------------------------------------------------------- */
189
0
    poDS->SetDescription(poOpenInfo->pszFilename);
190
0
    poDS->TryLoadXML();
191
192
    /* -------------------------------------------------------------------- */
193
    /*      Check for overviews.                                            */
194
    /* -------------------------------------------------------------------- */
195
0
    poDS->oOvManager.Initialize(poDS.get(), poOpenInfo->pszFilename);
196
197
0
    return poDS.release();
198
0
}
199
200
/************************************************************************/
201
/*                          GDALRegister_GSC()                          */
202
/************************************************************************/
203
204
void GDALRegister_GSC()
205
206
22
{
207
22
    if (GDALGetDriverByName("GSC") != nullptr)
208
0
        return;
209
210
22
    GDALDriver *poDriver = new GDALDriver();
211
212
22
    poDriver->SetDescription("GSC");
213
22
    poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
214
22
    poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "GSC Geogrid");
215
22
    poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/gsc.html");
216
22
    poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
217
218
22
    poDriver->pfnOpen = GSCDataset::Open;
219
220
22
    GetGDALDriverManager()->RegisterDriver(poDriver);
221
22
}