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 2686 : GDALSubdatasetInfoH GDALGetSubdatasetInfo(const char *pszFileName) 23 : { 24 : // Iterate all drivers 25 2686 : GDALDriverManager *poDM_ = GetGDALDriverManager(); 26 2686 : const int nDriverCount = poDM_->GetDriverCount(); 27 627491 : for (int iDriver = 0; iDriver < nDriverCount; ++iDriver) 28 : { 29 624900 : GDALDriver *poDriver = poDM_->GetDriver(iDriver); 30 624900 : if (!poDriver->pfnGetSubdatasetInfoFunc) 31 : { 32 606486 : continue; 33 : } 34 : const char *pszDMDSubdatasets = 35 18414 : GDALGetMetadataItem(poDriver, GDAL_DMD_SUBDATASETS, nullptr); 36 18414 : if (!pszDMDSubdatasets || !CPLTestBool(pszDMDSubdatasets)) 37 : { 38 0 : continue; 39 : } 40 : 41 : GDALSubdatasetInfo *poGetSubdatasetInfo = 42 18414 : poDriver->pfnGetSubdatasetInfoFunc(pszFileName); 43 : 44 18414 : if (!poGetSubdatasetInfo) 45 : { 46 18319 : continue; 47 : } 48 : 49 95 : return static_cast<GDALSubdatasetInfoH>(poGetSubdatasetInfo); 50 : } 51 2591 : 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 95 : void GDALDestroySubdatasetInfo(GDALSubdatasetInfoH hInfo) 64 : 65 : { 66 95 : delete hInfo; 67 95 : } 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 109 : GDALSubdatasetInfo::GDALSubdatasetInfo(const std::string &fileName) 86 : : m_fileName(fileName), m_pathComponent(), m_cleanedPathComponent(), 87 109 : m_subdatasetComponent(), m_driverPrefixComponent() 88 : { 89 109 : } 90 : 91 154 : std::string GDALSubdatasetInfo::GetPathComponent() const 92 : { 93 154 : init(); 94 154 : return m_cleanedPathComponent; 95 : } 96 : 97 : std::string 98 31 : GDALSubdatasetInfo::ModifyPathComponent(const std::string &newPathName) const 99 : { 100 31 : init(); 101 : 102 62 : std::string replaced{m_fileName}; 103 : 104 : try 105 : { 106 62 : auto newPathName_{newPathName}; 107 31 : if (m_isQuoted) 108 : { 109 26 : if (newPathName_.length() >= 2 && newPathName_.at(0) != '"' && 110 10 : newPathName_.at(newPathName_.length() - 1) != '"') 111 : { 112 10 : newPathName_ = quote(newPathName_); 113 : } 114 : } 115 31 : replaced.replace(replaced.find(m_pathComponent), 116 31 : m_pathComponent.length(), newPathName_); 117 : } 118 0 : catch (const std::out_of_range &) 119 : { 120 0 : return ""; 121 : } 122 : 123 31 : return replaced; 124 : } 125 : 126 118 : std::string GDALSubdatasetInfo::GetSubdatasetComponent() const 127 : { 128 118 : init(); 129 118 : return m_subdatasetComponent; 130 : } 131 : 132 : //! @cond Doxygen_Suppress 133 53 : std::string GDALSubdatasetInfo::unquote(const std::string &path) 134 : { 135 53 : if (path.length() >= 2) 136 : { 137 53 : std::string cleanedPath{path}; 138 106 : if (cleanedPath.at(0) == '"' && 139 53 : cleanedPath.at(cleanedPath.length() - 1) == '"') 140 : { 141 53 : cleanedPath = cleanedPath.substr(1, cleanedPath.length() - 2); 142 55 : while (cleanedPath.find(R"(\")") != std::string::npos) 143 : { 144 2 : const auto pos{cleanedPath.find(R"(\")")}; 145 2 : if (pos == 0 || cleanedPath.at(pos - 1) != '\\') 146 : { 147 2 : cleanedPath.erase(pos, 1); 148 : } 149 : } 150 53 : return cleanedPath; 151 : } 152 : } 153 0 : return path; 154 : } 155 : 156 10 : std::string GDALSubdatasetInfo::quote(const std::string &path) 157 : { 158 20 : std::string quotedPath{'"'}; 159 336 : for (size_t i = 0; i < path.length(); ++i) 160 : { 161 326 : if (path.at(i) == '"') 162 : { 163 0 : quotedPath += R"(\")"; 164 : } 165 : else 166 : { 167 326 : quotedPath += path.at(i); 168 : } 169 : } 170 20 : return quotedPath + '"'; 171 : } 172 : 173 303 : void GDALSubdatasetInfo::init() const 174 : { 175 303 : if (!m_initialized) 176 : { 177 109 : GDALSubdatasetInfo *this_ = const_cast<GDALSubdatasetInfo *>(this); 178 109 : this_->parseFileName(); 179 109 : this_->m_isQuoted = 180 162 : m_pathComponent.length() >= 2 && m_pathComponent.at(0) == '"' && 181 53 : m_pathComponent.at(m_pathComponent.length() - 1) == '"'; 182 : this_->m_cleanedPathComponent = 183 109 : m_isQuoted ? unquote(m_pathComponent) : m_pathComponent; 184 109 : m_initialized = true; 185 : } 186 303 : } 187 : 188 : //! @endcond