Line data Source code
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 2757 : GDALSubdatasetInfoH GDALGetSubdatasetInfo(const char *pszFileName) 23 : { 24 : // Iterate all drivers 25 2757 : GDALDriverManager *poDM_ = GetGDALDriverManager(); 26 2757 : const int nDriverCount = poDM_->GetDriverCount(); 27 596360 : for (int iDriver = 0; iDriver < nDriverCount; ++iDriver) 28 : { 29 593697 : GDALDriver *poDriver = poDM_->GetDriver(iDriver); 30 593697 : if (!poDriver->pfnGetSubdatasetInfoFunc) 31 : { 32 574781 : continue; 33 : } 34 : const char *pszDMDSubdatasets = 35 18916 : GDALGetMetadataItem(poDriver, GDAL_DMD_SUBDATASETS, nullptr); 36 18916 : if (!pszDMDSubdatasets || !CPLTestBool(pszDMDSubdatasets)) 37 : { 38 0 : continue; 39 : } 40 : 41 : GDALSubdatasetInfo *poGetSubdatasetInfo = 42 18916 : poDriver->pfnGetSubdatasetInfoFunc(pszFileName); 43 : 44 18916 : if (!poGetSubdatasetInfo) 45 : { 46 18822 : continue; 47 : } 48 : 49 94 : return static_cast<GDALSubdatasetInfoH>(poGetSubdatasetInfo); 50 : } 51 2663 : return nullptr; 52 : } 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 94 : void GDALDestroySubdatasetInfo(GDALSubdatasetInfoH hInfo) 64 : 65 : { 66 94 : delete hInfo; 67 94 : } 68 : 69 35 : char *GDALSubdatasetInfoGetPathComponent(GDALSubdatasetInfoH hInfo) 70 : { 71 35 : return CPLStrdup(hInfo->GetPathComponent().c_str()); 72 : } 73 : 74 63 : char *GDALSubdatasetInfoGetSubdatasetComponent(GDALSubdatasetInfoH hInfo) 75 : { 76 63 : return CPLStrdup(hInfo->GetSubdatasetComponent().c_str()); 77 : } 78 : 79 21 : char *GDALSubdatasetInfoModifyPathComponent(GDALSubdatasetInfoH hInfo, 80 : const char *pszNewFileName) 81 : { 82 21 : return CPLStrdup(hInfo->ModifyPathComponent(pszNewFileName).c_str()); 83 : } 84 : 85 108 : GDALSubdatasetInfo::GDALSubdatasetInfo(const std::string &fileName) 86 : : m_fileName(fileName), m_pathComponent(), m_cleanedPathComponent(), 87 108 : m_subdatasetComponent(), m_driverPrefixComponent() 88 : { 89 108 : } 90 : 91 : GDALSubdatasetInfo::~GDALSubdatasetInfo() = default; 92 : 93 151 : std::string GDALSubdatasetInfo::GetPathComponent() const 94 : { 95 151 : init(); 96 151 : return m_cleanedPathComponent; 97 : } 98 : 99 : std::string 100 30 : GDALSubdatasetInfo::ModifyPathComponent(const std::string &newPathName) const 101 : { 102 30 : init(); 103 : 104 60 : std::string replaced{m_fileName}; 105 : 106 : try 107 : { 108 60 : auto newPathName_{newPathName}; 109 30 : if (m_isQuoted) 110 : { 111 24 : if (newPathName_.length() >= 2 && newPathName_.at(0) != '"' && 112 9 : newPathName_.at(newPathName_.length() - 1) != '"') 113 : { 114 9 : newPathName_ = quote(newPathName_); 115 : } 116 : } 117 30 : replaced.replace(replaced.find(m_pathComponent), 118 30 : m_pathComponent.length(), newPathName_); 119 : } 120 0 : catch (const std::out_of_range &) 121 : { 122 0 : return ""; 123 : } 124 : 125 30 : return replaced; 126 : } 127 : 128 118 : std::string GDALSubdatasetInfo::GetSubdatasetComponent() const 129 : { 130 118 : init(); 131 118 : return m_subdatasetComponent; 132 : } 133 : 134 : //! @cond Doxygen_Suppress 135 52 : std::string GDALSubdatasetInfo::unquote(const std::string &path) 136 : { 137 52 : if (path.length() >= 2) 138 : { 139 52 : std::string cleanedPath{path}; 140 104 : if (cleanedPath.at(0) == '"' && 141 52 : cleanedPath.at(cleanedPath.length() - 1) == '"') 142 : { 143 52 : cleanedPath = cleanedPath.substr(1, cleanedPath.length() - 2); 144 54 : while (cleanedPath.find(R"(\")") != std::string::npos) 145 : { 146 2 : const auto pos{cleanedPath.find(R"(\")")}; 147 2 : if (pos == 0 || cleanedPath.at(pos - 1) != '\\') 148 : { 149 2 : cleanedPath.erase(pos, 1); 150 : } 151 : } 152 52 : return cleanedPath; 153 : } 154 : } 155 0 : return path; 156 : } 157 : 158 9 : std::string GDALSubdatasetInfo::quote(const std::string &path) 159 : { 160 18 : std::string quotedPath{'"'}; 161 357 : for (size_t i = 0; i < path.length(); ++i) 162 : { 163 348 : if (path.at(i) == '"') 164 : { 165 0 : quotedPath += R"(\")"; 166 : } 167 : else 168 : { 169 348 : quotedPath += path.at(i); 170 : } 171 : } 172 18 : return quotedPath + '"'; 173 : } 174 : 175 299 : void GDALSubdatasetInfo::init() const 176 : { 177 299 : if (!m_initialized) 178 : { 179 108 : GDALSubdatasetInfo *this_ = const_cast<GDALSubdatasetInfo *>(this); 180 108 : this_->parseFileName(); 181 108 : this_->m_isQuoted = 182 160 : m_pathComponent.length() >= 2 && m_pathComponent.at(0) == '"' && 183 52 : m_pathComponent.at(m_pathComponent.length() - 1) == '"'; 184 : this_->m_cleanedPathComponent = 185 108 : m_isQuoted ? unquote(m_pathComponent) : m_pathComponent; 186 108 : m_initialized = true; 187 : } 188 299 : } 189 : 190 : //! @endcond