Coverage Report

Created: 2026-11-12 08:28

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