Coverage Report

Created: 2025-06-13 06:29

/src/gdal/gcore/gdalsubdatasetinfo.cpp
Line
Count
Source (jump to first uncovered line)
1
/***************************************************************************
2
  gdal_subdatasetinfo.cpp - GDALSubdatasetInfo
3
4
 ---------------------
5
 begin                : 21.7.2023
6
 copyright            : (C) 2023 by Alessndro Pasotti
7
 email                : elpaso@itopen.it
8
 ***************************************************************************
9
 *                                                                         *
10
 * SPDX-License-Identifier: MIT
11
 *                                                                         *
12
 ***************************************************************************/
13
#include "gdalsubdatasetinfo.h"
14
#include "gdal_priv.h"
15
#include <algorithm>
16
#include <stdexcept>
17
18
/************************************************************************/
19
/*                     Subdataset informational functions               */
20
/************************************************************************/
21
22
GDALSubdatasetInfoH GDALGetSubdatasetInfo(const char *pszFileName)
23
0
{
24
    // Iterate all drivers
25
0
    GDALDriverManager *poDM_ = GetGDALDriverManager();
26
0
    const int nDriverCount = poDM_->GetDriverCount();
27
0
    for (int iDriver = 0; iDriver < nDriverCount; ++iDriver)
28
0
    {
29
0
        GDALDriver *poDriver = poDM_->GetDriver(iDriver);
30
0
        if (!poDriver->pfnGetSubdatasetInfoFunc)
31
0
        {
32
0
            continue;
33
0
        }
34
0
        const char *pszDMDSubdatasets =
35
0
            GDALGetMetadataItem(poDriver, GDAL_DMD_SUBDATASETS, nullptr);
36
0
        if (!pszDMDSubdatasets || !CPLTestBool(pszDMDSubdatasets))
37
0
        {
38
0
            continue;
39
0
        }
40
41
0
        GDALSubdatasetInfo *poGetSubdatasetInfo =
42
0
            poDriver->pfnGetSubdatasetInfoFunc(pszFileName);
43
44
0
        if (!poGetSubdatasetInfo)
45
0
        {
46
0
            continue;
47
0
        }
48
49
0
        return static_cast<GDALSubdatasetInfoH>(poGetSubdatasetInfo);
50
0
    }
51
0
    return nullptr;
52
0
}
53
54
/************************************************************************/
55
/*                       GDALDestroySubdatasetInfo()                    */
56
/************************************************************************/
57
58
/**
59
 * \brief Destroys subdataset info.
60
 *
61
 * This function is the same as the C++ method GDALSubdatasetInfo::~GDALSubdatasetInfo()
62
 */
63
void GDALDestroySubdatasetInfo(GDALSubdatasetInfoH hInfo)
64
65
0
{
66
0
    delete hInfo;
67
0
}
68
69
char *GDALSubdatasetInfoGetPathComponent(GDALSubdatasetInfoH hInfo)
70
0
{
71
0
    return CPLStrdup(hInfo->GetPathComponent().c_str());
72
0
}
73
74
char *GDALSubdatasetInfoGetSubdatasetComponent(GDALSubdatasetInfoH hInfo)
75
0
{
76
0
    return CPLStrdup(hInfo->GetSubdatasetComponent().c_str());
77
0
}
78
79
char *GDALSubdatasetInfoModifyPathComponent(GDALSubdatasetInfoH hInfo,
80
                                            const char *pszNewFileName)
81
0
{
82
0
    return CPLStrdup(hInfo->ModifyPathComponent(pszNewFileName).c_str());
83
0
}
84
85
GDALSubdatasetInfo::GDALSubdatasetInfo(const std::string &fileName)
86
0
    : m_fileName(fileName), m_pathComponent(), m_cleanedPathComponent(),
87
0
      m_subdatasetComponent(), m_driverPrefixComponent()
88
0
{
89
0
}
90
91
0
GDALSubdatasetInfo::~GDALSubdatasetInfo() = default;
92
93
std::string GDALSubdatasetInfo::GetPathComponent() const
94
0
{
95
0
    init();
96
0
    return m_cleanedPathComponent;
97
0
}
98
99
std::string
100
GDALSubdatasetInfo::ModifyPathComponent(const std::string &newPathName) const
101
0
{
102
0
    init();
103
104
0
    std::string replaced{m_fileName};
105
106
0
    try
107
0
    {
108
0
        auto newPathName_{newPathName};
109
0
        if (m_isQuoted)
110
0
        {
111
0
            if (newPathName_.length() >= 2 && newPathName_.at(0) != '"' &&
112
0
                newPathName_.at(newPathName_.length() - 1) != '"')
113
0
            {
114
0
                newPathName_ = quote(newPathName_);
115
0
            }
116
0
        }
117
0
        replaced.replace(replaced.find(m_pathComponent),
118
0
                         m_pathComponent.length(), newPathName_);
119
0
    }
120
0
    catch (const std::out_of_range &)
121
0
    {
122
0
        return "";
123
0
    }
124
125
0
    return replaced;
126
0
}
127
128
std::string GDALSubdatasetInfo::GetSubdatasetComponent() const
129
0
{
130
0
    init();
131
0
    return m_subdatasetComponent;
132
0
}
133
134
//! @cond Doxygen_Suppress
135
std::string GDALSubdatasetInfo::unquote(const std::string &path)
136
0
{
137
0
    if (path.length() >= 2)
138
0
    {
139
0
        std::string cleanedPath{path};
140
0
        if (cleanedPath.at(0) == '"' &&
141
0
            cleanedPath.at(cleanedPath.length() - 1) == '"')
142
0
        {
143
0
            cleanedPath = cleanedPath.substr(1, cleanedPath.length() - 2);
144
0
            while (cleanedPath.find(R"(\")") != std::string::npos)
145
0
            {
146
0
                const auto pos{cleanedPath.find(R"(\")")};
147
0
                if (pos == 0 || cleanedPath.at(pos - 1) != '\\')
148
0
                {
149
0
                    cleanedPath.erase(pos, 1);
150
0
                }
151
0
            }
152
0
            return cleanedPath;
153
0
        }
154
0
    }
155
0
    return path;
156
0
}
157
158
std::string GDALSubdatasetInfo::quote(const std::string &path)
159
0
{
160
0
    std::string quotedPath{'"'};
161
0
    for (size_t i = 0; i < path.length(); ++i)
162
0
    {
163
0
        if (path.at(i) == '"')
164
0
        {
165
0
            quotedPath += R"(\")";
166
0
        }
167
0
        else
168
0
        {
169
0
            quotedPath += path.at(i);
170
0
        }
171
0
    }
172
0
    return quotedPath + '"';
173
0
}
174
175
void GDALSubdatasetInfo::init() const
176
0
{
177
0
    if (!m_initialized)
178
0
    {
179
0
        GDALSubdatasetInfo *this_ = const_cast<GDALSubdatasetInfo *>(this);
180
0
        this_->parseFileName();
181
0
        this_->m_isQuoted =
182
0
            m_pathComponent.length() >= 2 && m_pathComponent.at(0) == '"' &&
183
0
            m_pathComponent.at(m_pathComponent.length() - 1) == '"';
184
0
        this_->m_cleanedPathComponent =
185
0
            m_isQuoted ? unquote(m_pathComponent) : m_pathComponent;
186
0
        m_initialized = true;
187
0
    }
188
0
}
189
190
//! @endcond