Coverage Report

Created: 2025-06-09 07:43

/src/gdal/frmts/raw/krodataset.cpp
Line
Count
Source (jump to first uncovered line)
1
/******************************************************************************
2
 *
3
 * Project:  KRO format reader/writer
4
 * Purpose:  Implementation of KOLOR Raw Format
5
 * Author:   Even Rouault, <even dot rouault at spatialys.com>
6
 * Financial Support: SITES (http://www.sites.fr)
7
 *
8
 ******************************************************************************
9
 * Copyright (c) 2014, 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
// http://www.autopano.net/wiki-en/Format_KRO
21
22
/************************************************************************/
23
/* ==================================================================== */
24
/*                                KRODataset                            */
25
/* ==================================================================== */
26
/************************************************************************/
27
28
class KRODataset final : public RawDataset
29
{
30
    VSILFILE *fpImage = nullptr;  // image data file.
31
32
    CPL_DISALLOW_COPY_ASSIGN(KRODataset)
33
34
    CPLErr Close() override;
35
36
  public:
37
0
    KRODataset() = default;
38
    ~KRODataset();
39
40
    static GDALDataset *Open(GDALOpenInfo *);
41
    static GDALDataset *Create(const char *pszFilename, int nXSize, int nYSize,
42
                               int nBandsIn, GDALDataType eType,
43
                               char **papszOptions);
44
    static int Identify(GDALOpenInfo *);
45
};
46
47
/************************************************************************/
48
/* ==================================================================== */
49
/*                                  KRODataset                          */
50
/* ==================================================================== */
51
/************************************************************************/
52
53
/************************************************************************/
54
/*                             ~KRODataset()                            */
55
/************************************************************************/
56
57
KRODataset::~KRODataset()
58
59
0
{
60
0
    KRODataset::Close();
61
0
}
62
63
/************************************************************************/
64
/*                              Close()                                 */
65
/************************************************************************/
66
67
CPLErr KRODataset::Close()
68
0
{
69
0
    CPLErr eErr = CE_None;
70
0
    if (nOpenFlags != OPEN_FLAGS_CLOSED)
71
0
    {
72
0
        if (KRODataset::FlushCache(true) != CE_None)
73
0
            eErr = CE_Failure;
74
75
0
        if (fpImage)
76
0
        {
77
0
            if (VSIFCloseL(fpImage) != 0)
78
0
            {
79
0
                CPLError(CE_Failure, CPLE_FileIO, "I/O error");
80
0
                eErr = CE_Failure;
81
0
            }
82
0
        }
83
84
0
        if (GDALPamDataset::Close() != CE_None)
85
0
            eErr = CE_Failure;
86
0
    }
87
0
    return eErr;
88
0
}
89
90
/************************************************************************/
91
/*                              Identify()                              */
92
/************************************************************************/
93
94
int KRODataset::Identify(GDALOpenInfo *poOpenInfo)
95
96
177k
{
97
177k
    if (poOpenInfo->nHeaderBytes < 20)
98
173k
        return FALSE;
99
100
3.49k
    if (!STARTS_WITH_CI(reinterpret_cast<char *>(poOpenInfo->pabyHeader),
101
3.49k
                        "KRO\x01"))
102
3.49k
        return FALSE;
103
104
0
    return TRUE;
105
3.49k
}
106
107
/************************************************************************/
108
/*                                Open()                                */
109
/************************************************************************/
110
111
GDALDataset *KRODataset::Open(GDALOpenInfo *poOpenInfo)
112
113
0
{
114
0
    if (!Identify(poOpenInfo) || poOpenInfo->fpL == nullptr)
115
0
        return nullptr;
116
117
    /* -------------------------------------------------------------------- */
118
    /*      Create a corresponding GDALDataset.                             */
119
    /* -------------------------------------------------------------------- */
120
0
    auto poDS = std::make_unique<KRODataset>();
121
0
    poDS->eAccess = poOpenInfo->eAccess;
122
0
    std::swap(poDS->fpImage, poOpenInfo->fpL);
123
124
    /* -------------------------------------------------------------------- */
125
    /*      Read the file header.                                           */
126
    /* -------------------------------------------------------------------- */
127
0
    char achHeader[20] = {'\0'};
128
0
    CPL_IGNORE_RET_VAL(VSIFReadL(achHeader, 1, 20, poDS->fpImage));
129
130
0
    int nXSize;
131
0
    memcpy(&nXSize, achHeader + 4, 4);
132
0
    CPL_MSBPTR32(&nXSize);
133
134
0
    int nYSize = 0;
135
0
    memcpy(&nYSize, achHeader + 8, 4);
136
0
    CPL_MSBPTR32(&nYSize);
137
138
0
    int nDepth = 0;
139
0
    memcpy(&nDepth, achHeader + 12, 4);
140
0
    CPL_MSBPTR32(&nDepth);
141
142
0
    int nComp = 0;
143
0
    memcpy(&nComp, achHeader + 16, 4);
144
0
    CPL_MSBPTR32(&nComp);
145
146
0
    if (!GDALCheckDatasetDimensions(nXSize, nYSize) ||
147
0
        !GDALCheckBandCount(nComp, FALSE))
148
0
    {
149
0
        return nullptr;
150
0
    }
151
152
0
    poDS->nRasterXSize = nXSize;
153
0
    poDS->nRasterYSize = nYSize;
154
155
0
    GDALDataType eDT = GDT_Unknown;
156
0
    if (nDepth == 8)
157
0
    {
158
0
        eDT = GDT_Byte;
159
0
    }
160
0
    else if (nDepth == 16)
161
0
    {
162
0
        eDT = GDT_UInt16;
163
0
    }
164
0
    else if (nDepth == 32)
165
0
    {
166
0
        eDT = GDT_Float32;
167
0
    }
168
0
    else
169
0
    {
170
0
        CPLError(CE_Failure, CPLE_AppDefined, "Unhandled depth : %d", nDepth);
171
0
        return nullptr;
172
0
    }
173
174
0
    const int nDataTypeSize = nDepth / 8;
175
176
0
    if (nComp == 0 || nDataTypeSize == 0 ||
177
0
        poDS->nRasterXSize > INT_MAX / (nComp * nDataTypeSize))
178
0
    {
179
0
        CPLError(CE_Failure, CPLE_AppDefined,
180
0
                 "Too large width / number of bands");
181
0
        return nullptr;
182
0
    }
183
184
0
    vsi_l_offset nExpectedSize = static_cast<vsi_l_offset>(poDS->nRasterXSize) *
185
0
                                     poDS->nRasterYSize * nComp *
186
0
                                     nDataTypeSize +
187
0
                                 20;
188
0
    VSIFSeekL(poDS->fpImage, 0, SEEK_END);
189
0
    if (VSIFTellL(poDS->fpImage) < nExpectedSize)
190
0
    {
191
0
        CPLError(CE_Failure, CPLE_FileIO, "File too short");
192
0
        return nullptr;
193
0
    }
194
195
    /* -------------------------------------------------------------------- */
196
    /*      Create bands.                                                   */
197
    /* -------------------------------------------------------------------- */
198
0
    for (int iBand = 0; iBand < nComp; iBand++)
199
0
    {
200
0
        auto poBand = RawRasterBand::Create(
201
0
            poDS.get(), iBand + 1, poDS->fpImage, 20 + nDataTypeSize * iBand,
202
0
            nComp * nDataTypeSize, poDS->nRasterXSize * nComp * nDataTypeSize,
203
0
            eDT, RawRasterBand::ByteOrder::ORDER_BIG_ENDIAN,
204
0
            RawRasterBand::OwnFP::NO);
205
0
        if (!poBand)
206
0
            return nullptr;
207
0
        if (nComp == 3 || nComp == 4)
208
0
        {
209
0
            poBand->SetColorInterpretation(
210
0
                static_cast<GDALColorInterp>(GCI_RedBand + iBand));
211
0
        }
212
0
        poDS->SetBand(iBand + 1, std::move(poBand));
213
0
    }
214
215
0
    if (nComp > 1)
216
0
        poDS->SetMetadataItem("INTERLEAVE", "PIXEL", "IMAGE_STRUCTURE");
217
218
    /* -------------------------------------------------------------------- */
219
    /*      Initialize any PAM information.                                 */
220
    /* -------------------------------------------------------------------- */
221
0
    poDS->SetDescription(poOpenInfo->pszFilename);
222
0
    poDS->TryLoadXML();
223
224
    /* -------------------------------------------------------------------- */
225
    /*      Check for overviews.                                            */
226
    /* -------------------------------------------------------------------- */
227
0
    poDS->oOvManager.Initialize(poDS.get(), poOpenInfo->pszFilename);
228
229
0
    return poDS.release();
230
0
}
231
232
/************************************************************************/
233
/*                               Create()                               */
234
/************************************************************************/
235
236
GDALDataset *KRODataset::Create(const char *pszFilename, int nXSize, int nYSize,
237
                                int nBandsIn, GDALDataType eType,
238
                                char ** /* papszOptions */)
239
0
{
240
0
    if (eType != GDT_Byte && eType != GDT_UInt16 && eType != GDT_Float32)
241
0
    {
242
0
        CPLError(CE_Failure, CPLE_AppDefined,
243
0
                 "Attempt to create KRO file with unsupported data type '%s'.",
244
0
                 GDALGetDataTypeName(eType));
245
0
        return nullptr;
246
0
    }
247
0
    if (nXSize == 0 || nYSize == 0 || nBandsIn == 0)
248
0
    {
249
0
        return nullptr;
250
0
    }
251
252
    /* -------------------------------------------------------------------- */
253
    /*      Try to create file.                                             */
254
    /* -------------------------------------------------------------------- */
255
0
    VSILFILE *fp = VSIFOpenL(pszFilename, "wb");
256
0
    if (fp == nullptr)
257
0
    {
258
0
        CPLError(CE_Failure, CPLE_OpenFailed,
259
0
                 "Attempt to create file `%s' failed.", pszFilename);
260
0
        return nullptr;
261
0
    }
262
263
0
    size_t nRet = VSIFWriteL("KRO\01", 4, 1, fp);
264
265
    /* -------------------------------------------------------------------- */
266
    /*      Create a file level header.                                     */
267
    /* -------------------------------------------------------------------- */
268
0
    int nTmp = nXSize;
269
0
    CPL_MSBPTR32(&nTmp);
270
0
    nRet += VSIFWriteL(&nTmp, 4, 1, fp);
271
272
0
    nTmp = nYSize;
273
0
    CPL_MSBPTR32(&nTmp);
274
0
    nRet += VSIFWriteL(&nTmp, 4, 1, fp);
275
276
0
    nTmp = GDALGetDataTypeSizeBits(eType);
277
0
    CPL_MSBPTR32(&nTmp);
278
0
    nRet += VSIFWriteL(&nTmp, 4, 1, fp);
279
280
0
    nTmp = nBandsIn;
281
0
    CPL_MSBPTR32(&nTmp);
282
0
    nRet += VSIFWriteL(&nTmp, 4, 1, fp);
283
284
    /* -------------------------------------------------------------------- */
285
    /*      Zero out image data                                             */
286
    /* -------------------------------------------------------------------- */
287
288
0
    CPL_IGNORE_RET_VAL(VSIFSeekL(fp,
289
0
                                 static_cast<vsi_l_offset>(nXSize) * nYSize *
290
0
                                         GDALGetDataTypeSizeBytes(eType) *
291
0
                                         nBandsIn -
292
0
                                     1,
293
0
                                 SEEK_CUR));
294
0
    GByte byNul = 0;
295
0
    nRet += VSIFWriteL(&byNul, 1, 1, fp);
296
0
    if (VSIFCloseL(fp) != 0)
297
0
    {
298
0
        CPLError(CE_Failure, CPLE_FileIO, "I/O error");
299
0
        return nullptr;
300
0
    }
301
302
0
    if (nRet != 6)
303
0
        return nullptr;
304
305
0
    return GDALDataset::FromHandle(GDALOpen(pszFilename, GA_Update));
306
0
}
307
308
/************************************************************************/
309
/*                         GDALRegister_KRO()                           */
310
/************************************************************************/
311
312
void GDALRegister_KRO()
313
314
2
{
315
2
    if (GDALGetDriverByName("KRO") != nullptr)
316
0
        return;
317
318
2
    GDALDriver *poDriver = new GDALDriver();
319
320
2
    poDriver->SetDescription("KRO");
321
2
    poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
322
2
    poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "KOLOR Raw");
323
2
    poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "kro");
324
2
    poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
325
2
    poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES,
326
2
                              "Byte UInt16 Float32");
327
328
2
    poDriver->pfnIdentify = KRODataset::Identify;
329
2
    poDriver->pfnOpen = KRODataset::Open;
330
2
    poDriver->pfnCreate = KRODataset::Create;
331
332
2
    GetGDALDriverManager()->RegisterDriver(poDriver);
333
2
}