Coverage Report

Created: 2026-02-14 09:00

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
3
    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
3
{
61
3
    KRODataset::Close();
62
3
}
63
64
/************************************************************************/
65
/*                               Close()                                */
66
/************************************************************************/
67
68
CPLErr KRODataset::Close(GDALProgressFunc, void *)
69
3
{
70
3
    CPLErr eErr = CE_None;
71
3
    if (nOpenFlags != OPEN_FLAGS_CLOSED)
72
3
    {
73
3
        if (KRODataset::FlushCache(true) != CE_None)
74
0
            eErr = CE_Failure;
75
76
3
        if (fpImage)
77
3
        {
78
3
            if (VSIFCloseL(fpImage) != 0)
79
0
            {
80
0
                CPLError(CE_Failure, CPLE_FileIO, "I/O error");
81
0
                eErr = CE_Failure;
82
0
            }
83
3
        }
84
85
3
        if (GDALPamDataset::Close() != CE_None)
86
0
            eErr = CE_Failure;
87
3
    }
88
3
    return eErr;
89
3
}
90
91
/************************************************************************/
92
/*                              Identify()                              */
93
/************************************************************************/
94
95
int KRODataset::Identify(GDALOpenInfo *poOpenInfo)
96
97
328k
{
98
328k
    if (poOpenInfo->nHeaderBytes < 20)
99
267k
        return FALSE;
100
101
60.8k
    if (!STARTS_WITH_CI(reinterpret_cast<char *>(poOpenInfo->pabyHeader),
102
60.8k
                        "KRO\x01"))
103
60.8k
        return FALSE;
104
105
6
    return TRUE;
106
60.8k
}
107
108
/************************************************************************/
109
/*                                Open()                                */
110
/************************************************************************/
111
112
GDALDataset *KRODataset::Open(GDALOpenInfo *poOpenInfo)
113
114
3
{
115
3
    if (!Identify(poOpenInfo) || poOpenInfo->fpL == nullptr)
116
0
        return nullptr;
117
118
    /* -------------------------------------------------------------------- */
119
    /*      Create a corresponding GDALDataset.                             */
120
    /* -------------------------------------------------------------------- */
121
3
    auto poDS = std::make_unique<KRODataset>();
122
3
    poDS->eAccess = poOpenInfo->eAccess;
123
3
    std::swap(poDS->fpImage, poOpenInfo->fpL);
124
125
    /* -------------------------------------------------------------------- */
126
    /*      Read the file header.                                           */
127
    /* -------------------------------------------------------------------- */
128
3
    char achHeader[20] = {'\0'};
129
3
    CPL_IGNORE_RET_VAL(VSIFReadL(achHeader, 1, 20, poDS->fpImage));
130
131
3
    int nXSize;
132
3
    memcpy(&nXSize, achHeader + 4, 4);
133
3
    CPL_MSBPTR32(&nXSize);
134
135
3
    int nYSize = 0;
136
3
    memcpy(&nYSize, achHeader + 8, 4);
137
3
    CPL_MSBPTR32(&nYSize);
138
139
3
    int nDepth = 0;
140
3
    memcpy(&nDepth, achHeader + 12, 4);
141
3
    CPL_MSBPTR32(&nDepth);
142
143
3
    int nComp = 0;
144
3
    memcpy(&nComp, achHeader + 16, 4);
145
3
    CPL_MSBPTR32(&nComp);
146
147
3
    if (!GDALCheckDatasetDimensions(nXSize, nYSize) ||
148
3
        !GDALCheckBandCount(nComp, FALSE))
149
2
    {
150
2
        return nullptr;
151
2
    }
152
153
1
    poDS->nRasterXSize = nXSize;
154
1
    poDS->nRasterYSize = nYSize;
155
156
1
    GDALDataType eDT = GDT_Unknown;
157
1
    if (nDepth == 8)
158
0
    {
159
0
        eDT = GDT_UInt8;
160
0
    }
161
1
    else if (nDepth == 16)
162
0
    {
163
0
        eDT = GDT_UInt16;
164
0
    }
165
1
    else if (nDepth == 32)
166
0
    {
167
0
        eDT = GDT_Float32;
168
0
    }
169
1
    else
170
1
    {
171
1
        CPLError(CE_Failure, CPLE_AppDefined, "Unhandled depth : %d", nDepth);
172
1
        return nullptr;
173
1
    }
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("INTERLEAVE", "PIXEL", "IMAGE_STRUCTURE");
218
219
    /* -------------------------------------------------------------------- */
220
    /*      Initialize any PAM information.                                 */
221
    /* -------------------------------------------------------------------- */
222
0
    poDS->SetDescription(poOpenInfo->pszFilename);
223
0
    poDS->TryLoadXML();
224
225
    /* -------------------------------------------------------------------- */
226
    /*      Check for overviews.                                            */
227
    /* -------------------------------------------------------------------- */
228
0
    poDS->oOvManager.Initialize(poDS.get(), poOpenInfo->pszFilename);
229
230
0
    return poDS.release();
231
0
}
232
233
/************************************************************************/
234
/*                               Create()                               */
235
/************************************************************************/
236
237
GDALDataset *KRODataset::Create(const char *pszFilename, int nXSize, int nYSize,
238
                                int nBandsIn, GDALDataType eType,
239
                                CSLConstList /* papszOptions */)
240
0
{
241
0
    if (eType != GDT_UInt8 && eType != GDT_UInt16 && eType != GDT_Float32)
242
0
    {
243
0
        CPLError(CE_Failure, CPLE_AppDefined,
244
0
                 "Attempt to create KRO file with unsupported data type '%s'.",
245
0
                 GDALGetDataTypeName(eType));
246
0
        return nullptr;
247
0
    }
248
0
    if (nXSize == 0 || nYSize == 0 || nBandsIn == 0)
249
0
    {
250
0
        return nullptr;
251
0
    }
252
253
    /* -------------------------------------------------------------------- */
254
    /*      Try to create file.                                             */
255
    /* -------------------------------------------------------------------- */
256
0
    VSILFILE *fp = VSIFOpenL(pszFilename, "wb");
257
0
    if (fp == nullptr)
258
0
    {
259
0
        CPLError(CE_Failure, CPLE_OpenFailed,
260
0
                 "Attempt to create file `%s' failed.", pszFilename);
261
0
        return nullptr;
262
0
    }
263
264
0
    size_t nRet = VSIFWriteL("KRO\01", 4, 1, fp);
265
266
    /* -------------------------------------------------------------------- */
267
    /*      Create a file level header.                                     */
268
    /* -------------------------------------------------------------------- */
269
0
    int nTmp = nXSize;
270
0
    CPL_MSBPTR32(&nTmp);
271
0
    nRet += VSIFWriteL(&nTmp, 4, 1, fp);
272
273
0
    nTmp = nYSize;
274
0
    CPL_MSBPTR32(&nTmp);
275
0
    nRet += VSIFWriteL(&nTmp, 4, 1, fp);
276
277
0
    nTmp = GDALGetDataTypeSizeBits(eType);
278
0
    CPL_MSBPTR32(&nTmp);
279
0
    nRet += VSIFWriteL(&nTmp, 4, 1, fp);
280
281
0
    nTmp = nBandsIn;
282
0
    CPL_MSBPTR32(&nTmp);
283
0
    nRet += VSIFWriteL(&nTmp, 4, 1, fp);
284
285
    /* -------------------------------------------------------------------- */
286
    /*      Zero out image data                                             */
287
    /* -------------------------------------------------------------------- */
288
289
0
    CPL_IGNORE_RET_VAL(VSIFSeekL(fp,
290
0
                                 static_cast<vsi_l_offset>(nXSize) * nYSize *
291
0
                                         GDALGetDataTypeSizeBytes(eType) *
292
0
                                         nBandsIn -
293
0
                                     1,
294
0
                                 SEEK_CUR));
295
0
    GByte byNul = 0;
296
0
    nRet += VSIFWriteL(&byNul, 1, 1, fp);
297
0
    if (VSIFCloseL(fp) != 0)
298
0
    {
299
0
        CPLError(CE_Failure, CPLE_FileIO, "I/O error");
300
0
        return nullptr;
301
0
    }
302
303
0
    if (nRet != 6)
304
0
        return nullptr;
305
306
0
    return GDALDataset::FromHandle(GDALOpen(pszFilename, GA_Update));
307
0
}
308
309
/************************************************************************/
310
/*                          GDALRegister_KRO()                          */
311
/************************************************************************/
312
313
void GDALRegister_KRO()
314
315
22
{
316
22
    if (GDALGetDriverByName("KRO") != nullptr)
317
0
        return;
318
319
22
    GDALDriver *poDriver = new GDALDriver();
320
321
22
    poDriver->SetDescription("KRO");
322
22
    poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
323
22
    poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "KOLOR Raw");
324
22
    poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "kro");
325
22
    poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
326
22
    poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES,
327
22
                              "Byte UInt16 Float32");
328
329
22
    poDriver->pfnIdentify = KRODataset::Identify;
330
22
    poDriver->pfnOpen = KRODataset::Open;
331
22
    poDriver->pfnCreate = KRODataset::Create;
332
333
22
    GetGDALDriverManager()->RegisterDriver(poDriver);
334
22
}