Coverage Report

Created: 2025-11-15 08:43

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/frmts/derived/deriveddataset.cpp
Line
Count
Source
1
/******************************************************************************
2
 *
3
 * Project:  GDAL
4
 * Purpose:  Implementation of derived subdatasets
5
 * Author:   Julien Michel <julien dot michel at cnes dot fr>
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 2016 Julien Michel <julien dot michel at cnes dot fr>
9
 *
10
 * SPDX-License-Identifier: MIT
11
 *****************************************************************************/
12
#include "../vrt/vrtdataset.h"
13
#include "gdal_frmts.h"
14
#include "gdal_pam.h"
15
#include "gdal_priv.h"
16
#include "derivedlist.h"
17
18
class DerivedDataset final : public VRTDataset
19
{
20
  public:
21
    DerivedDataset(int nXSize, int nYSize);
22
23
    ~DerivedDataset() override;
24
25
    static int Identify(GDALOpenInfo *);
26
    static GDALDataset *Open(GDALOpenInfo *);
27
};
28
29
DerivedDataset::DerivedDataset(int nXSize, int nYSize)
30
0
    : VRTDataset(nXSize, nYSize)
31
0
{
32
0
    poDriver = nullptr;
33
0
    SetWritable(FALSE);
34
0
}
35
36
0
DerivedDataset::~DerivedDataset() = default;
37
38
int DerivedDataset::Identify(GDALOpenInfo *poOpenInfo)
39
680k
{
40
    /* Try to open original dataset */
41
680k
    CPLString filename(poOpenInfo->pszFilename);
42
43
    /* DERIVED_SUBDATASET should be first domain */
44
680k
    const size_t dsds_pos = filename.find("DERIVED_SUBDATASET:");
45
46
680k
    if (dsds_pos != 0)
47
680k
    {
48
        /* Unable to Open in this case */
49
680k
        return FALSE;
50
680k
    }
51
52
0
    return TRUE;
53
680k
}
54
55
GDALDataset *DerivedDataset::Open(GDALOpenInfo *poOpenInfo)
56
0
{
57
    /* Try to open original dataset */
58
0
    CPLString filename(poOpenInfo->pszFilename);
59
60
    /* DERIVED_SUBDATASET should be first domain */
61
0
    const size_t dsds_pos = filename.find("DERIVED_SUBDATASET:");
62
0
    const size_t nPrefixLen = strlen("DERIVED_SUBDATASET:");
63
64
0
    if (dsds_pos != 0)
65
0
    {
66
        /* Unable to Open in this case */
67
0
        return nullptr;
68
0
    }
69
70
    /* Next, we need to now which derived dataset to compute */
71
0
    const size_t alg_pos = filename.find(":", nPrefixLen + 1);
72
0
    if (alg_pos == std::string::npos)
73
0
    {
74
        /* Unable to Open if we do not find the name of the derived dataset */
75
0
        return nullptr;
76
0
    }
77
78
0
    CPLString odDerivedName = filename.substr(nPrefixLen, alg_pos - nPrefixLen);
79
80
0
    CPLDebug("DerivedDataset::Open", "Derived dataset requested: %s",
81
0
             odDerivedName.c_str());
82
83
0
    CPLString pixelFunctionName = "";
84
0
    bool datasetFound = false;
85
86
0
    unsigned int nbSupportedDerivedDS(0);
87
0
    GDALDataType type = GDT_Float64;
88
89
0
    const DerivedDatasetDescription *poDDSDesc =
90
0
        GDALGetDerivedDatasetDescriptions(&nbSupportedDerivedDS);
91
92
0
    for (unsigned int derivedId = 0; derivedId < nbSupportedDerivedDS;
93
0
         ++derivedId)
94
0
    {
95
0
        if (odDerivedName == poDDSDesc[derivedId].pszDatasetName)
96
0
        {
97
0
            datasetFound = true;
98
0
            pixelFunctionName = poDDSDesc[derivedId].pszPixelFunction;
99
0
            type =
100
0
                GDALGetDataTypeByName(poDDSDesc[derivedId].pszOutputPixelType);
101
0
        }
102
0
    }
103
104
0
    if (!datasetFound)
105
0
    {
106
0
        return nullptr;
107
0
    }
108
109
0
    CPLString odFilename =
110
0
        filename.substr(alg_pos + 1, filename.size() - alg_pos);
111
112
0
    auto poTmpDS = std::unique_ptr<GDALDataset>(
113
0
        GDALDataset::Open(odFilename, GDAL_OF_RASTER | GDAL_OF_VERBOSE_ERROR));
114
115
0
    if (poTmpDS == nullptr)
116
0
        return nullptr;
117
118
0
    int nbBands = poTmpDS->GetRasterCount();
119
120
0
    if (nbBands == 0)
121
0
    {
122
0
        return nullptr;
123
0
    }
124
125
0
    int nRows = poTmpDS->GetRasterYSize();
126
0
    int nCols = poTmpDS->GetRasterXSize();
127
128
0
    DerivedDataset *poDS = new DerivedDataset(nCols, nRows);
129
130
    // Transfer metadata
131
0
    poDS->SetMetadata(poTmpDS->GetMetadata());
132
133
0
    char **papszRPC = poTmpDS->GetMetadata("RPC");
134
0
    if (papszRPC)
135
0
    {
136
0
        poDS->SetMetadata(papszRPC, "RPC");
137
0
    }
138
139
    // Transfer projection
140
0
    poDS->SetProjection(poTmpDS->GetProjectionRef());
141
142
    // Transfer geotransform
143
0
    GDALGeoTransform gt;
144
0
    if (poTmpDS->GetGeoTransform(gt) == CE_None)
145
0
    {
146
0
        poDS->SetGeoTransform(gt);
147
0
    }
148
149
    // Transfer GCPs
150
0
    const char *gcpProjection = poTmpDS->GetGCPProjection();
151
0
    int nbGcps = poTmpDS->GetGCPCount();
152
0
    poDS->SetGCPs(nbGcps, poTmpDS->GetGCPs(), gcpProjection);
153
154
    // Map bands
155
0
    for (int nBand = 1; nBand <= nbBands; ++nBand)
156
0
    {
157
0
        VRTDerivedRasterBand *poBand =
158
0
            new VRTDerivedRasterBand(poDS, nBand, type, nCols, nRows);
159
0
        poDS->SetBand(nBand, poBand);
160
161
0
        poBand->SetPixelFunctionName(pixelFunctionName);
162
0
        poBand->SetSourceTransferType(
163
0
            poTmpDS->GetRasterBand(nBand)->GetRasterDataType());
164
165
0
        poBand->AddComplexSource(odFilename, nBand, 0, 0, nCols, nRows, 0, 0,
166
0
                                 nCols, nRows);
167
0
    }
168
169
    // If dataset is a real file, initialize overview manager
170
0
    VSIStatBufL sStat;
171
0
    if (VSIStatL(odFilename, &sStat) == 0)
172
0
    {
173
0
        CPLString path = CPLGetPathSafe(odFilename);
174
0
        CPLString ovrFileName = "DERIVED_DATASET_" + odDerivedName + "_" +
175
0
                                CPLGetFilename(odFilename);
176
0
        CPLString ovrFilePath = CPLFormFilenameSafe(path, ovrFileName, nullptr);
177
178
0
        poDS->oOvManager.Initialize(poDS, ovrFilePath);
179
0
    }
180
181
0
    return poDS;
182
0
}
183
184
void GDALRegister_Derived()
185
22
{
186
22
    if (GDALGetDriverByName("DERIVED") != nullptr)
187
0
        return;
188
189
22
    GDALDriver *poDriver = new GDALDriver();
190
191
22
    poDriver->SetDescription("DERIVED");
192
22
#ifdef GDAL_DCAP_RASTER
193
22
    poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
194
22
#endif
195
22
    poDriver->SetMetadataItem(GDAL_DMD_LONGNAME,
196
22
                              "Derived datasets using VRT pixel functions");
197
22
    poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC,
198
22
                              "drivers/raster/derived.html");
199
22
    poDriver->SetMetadataItem(GDAL_DMD_SUBDATASETS, "NO");
200
201
22
    poDriver->pfnOpen = DerivedDataset::Open;
202
22
    poDriver->pfnIdentify = DerivedDataset::Identify;
203
204
22
    GetGDALDriverManager()->RegisterDriver(poDriver);
205
22
}