diff --git a/Modules/Core/Metadata/include/otbMetadataSupplierInterface.h b/Modules/Core/Metadata/include/otbMetadataSupplierInterface.h index f5a289c01c0f366a8fdce09518cbc78cd71d783a..18d2f55f6d84c1a3bd7781a3aa9c6f5c605eec7b 100644 --- a/Modules/Core/Metadata/include/otbMetadataSupplierInterface.h +++ b/Modules/Core/Metadata/include/otbMetadataSupplierInterface.h @@ -74,68 +74,71 @@ public: /** Get the metadata value corresponding to a given path (meaning of this path - * depends on the specific implementation. Returns NULL when path is not found + * depends on the specific implementation. Returns empty string when path is not found, + * and hasValue is set to False. * If band >= 0, the metadata value is looked in the specified band*/ - virtual const char * GetMetadataValue(const char * path, int band=-1) const = 0; + virtual const std::string GetMetadataValue(const std::string path, bool& hasValue, int band=-1) const = 0; - bool HasValue(const char * path, int band=-1); + bool HasValue(std::string path, int band=-1); // utility functions - template <typename T> T GetAs(const char *path, int band=-1) const + template <typename T> T GetAs(std::string path, int band=-1) const + { + bool hasValue; + std::string ret = GetMetadataValue(path, hasValue, band); + if (!hasValue) { - const char * ret = GetMetadataValue(path, band); - if (ret == nullptr) - { otbGenericExceptionMacro(MissingMetadataException,<<"Missing metadata '"<<path<<"'") - } + } try - { + { return boost::lexical_cast<T>(ret); - } + } catch (boost::bad_lexical_cast&) - { + { otbGenericExceptionMacro(MissingMetadataException,<<"Bad metadata value for '"<<path<<"', got: "<<ret) - } } + } /** Parse a metadata value to a std::vector, * If size>=0, then the final std::vector size is checked and an exception * is raised if it doesn't match the given size.*/ - template < typename T> std::vector<T> GetAsVector(const char *path, const char sep=' ', int size=-1, int band=-1) const + template < typename T> std::vector<T> GetAsVector(std::string path, const char sep=' ', int size=-1, int band=-1) const + { + bool hasValue; + std::string ret = GetMetadataValue(path, hasValue, band); + if (!hasValue) { - const char * ret = GetMetadataValue(path, band); - if (ret == nullptr) - { otbGenericExceptionMacro(MissingMetadataException,<<"Missing metadata '"<<path<<"'") - } + } string_view value(ret); string_view filt_value = rstrip(lstrip(value,"[ "), "] "); std::vector<T> output; typedef part_range<splitter_on_delim> range_type; const range_type parts = split_on(filt_value, sep); for (auto const& part : parts) - { + { // TODO: check if we can use lexical_cast on a string_view std::string strPart = to<std::string>(part, "casting string_view to std::string"); if (strPart.empty()) - { + { continue; - } + } try - { + { output.push_back(boost::lexical_cast<T>(strPart)); - } + } catch (boost::bad_lexical_cast&) - { + { otbGenericExceptionMacro(MissingMetadataException,<<"Bad metadata vector element in '"<<path<<"', got :"<<part) - } } + } if ((size >= 0) && (output.size() != (size_t)size)) - { + { otbGenericExceptionMacro(MissingMetadataException,<<"Bad number of elements in vector '"<<path<<"', expected "<<size<< ", got "<<output.size()) - } - return output; } + return output; + } }; diff --git a/Modules/Core/Metadata/include/otbXMLMetadataSupplier.h b/Modules/Core/Metadata/include/otbXMLMetadataSupplier.h index 3783a124f8d4d7c9e44514b40284ba4e33eb86c8..225e14a4c92430581ccd797878a5bc442f7c89de 100644 --- a/Modules/Core/Metadata/include/otbXMLMetadataSupplier.h +++ b/Modules/Core/Metadata/include/otbXMLMetadataSupplier.h @@ -47,7 +47,7 @@ public: /** Get the metadata value corresponding to a given path * Returns NULL when path is not found * If band >= 0, the metadata value is looked in the specified band*/ - const char * GetMetadataValue(const char * path, int band=1) const override; + const std::string GetMetadataValue(const std::string path, bool& hasValue, int band=1) const override; std::string GetResourceFile(std::string="") const override; diff --git a/Modules/Core/Metadata/src/otbMetadataSupplierInterface.cxx b/Modules/Core/Metadata/src/otbMetadataSupplierInterface.cxx index c276bb6096bddb6c3600514efa7b2a648ff74f67..4cbe8a51284e39aedcd530183afb5dfa4b836642 100644 --- a/Modules/Core/Metadata/src/otbMetadataSupplierInterface.cxx +++ b/Modules/Core/Metadata/src/otbMetadataSupplierInterface.cxx @@ -23,10 +23,11 @@ namespace otb { -bool MetadataSupplierInterface::HasValue(const char * path, int band) +bool MetadataSupplierInterface::HasValue(const std::string path, int band) { - const char * ret = GetMetadataValue(path, band); - return ret; + bool hasValue; + const std::string ret = GetMetadataValue(path, hasValue, band); + return hasValue; } diff --git a/Modules/Core/Metadata/src/otbXMLMetadataSupplier.cxx b/Modules/Core/Metadata/src/otbXMLMetadataSupplier.cxx index d4406642c033c96c2c05bea2c17c507abaf4927c..ec1ca62c7947ffb09410e1107fefa69c35b190d3 100644 --- a/Modules/Core/Metadata/src/otbXMLMetadataSupplier.cxx +++ b/Modules/Core/Metadata/src/otbXMLMetadataSupplier.cxx @@ -41,9 +41,17 @@ XMLMetadataSupplier::XMLMetadataSupplier(const std::string & fileName) CPLDestroyXMLNode(psNode); } -const char * XMLMetadataSupplier::GetMetadataValue(const char * path, int band) const +const std::string XMLMetadataSupplier::GetMetadataValue(const std::string path, bool& hasValue, int band) const { - return CSLFetchNameValue(m_MetadataDic, path); + const char * ret = CSLFetchNameValue(m_MetadataDic, path); + if (ret) + hasValue = true; + else + { + hasValue = false; + ret = ""; + } + return std::string(ret); } std::string XMLMetadataSupplier::GetResourceFile(std::string) const diff --git a/Modules/IO/IOGDAL/include/otbGDALImageIO.h b/Modules/IO/IOGDAL/include/otbGDALImageIO.h index 657bea76b239226a02094faaaadfaf0367326b08..22a493a05bac33e8a8d21d342a0b19a7d99b600c 100644 --- a/Modules/IO/IOGDAL/include/otbGDALImageIO.h +++ b/Modules/IO/IOGDAL/include/otbGDALImageIO.h @@ -210,7 +210,7 @@ public: std::vector<std::string> GetResourceFiles() const override; /** Get metadata item in GDALDataset, domain can specified as "domain/key" */ - const char * GetMetadataValue(const char * path, int band = -1) const override; + const std::string GetMetadataValue(const std::string path, bool& hasValue, int band = -1) const override; /** Set metadata item in GDALDataset, domain can specified as prefix of the * path, like "domain/key"*/ diff --git a/Modules/IO/IOGDAL/src/otbGDALImageIO.cxx b/Modules/IO/IOGDAL/src/otbGDALImageIO.cxx index 0bbeae85eb2ce8847c7fe14bf7fe67f63b147687..f50a024c045280fd56a60dc6cb782a5371ac824a 100644 --- a/Modules/IO/IOGDAL/src/otbGDALImageIO.cxx +++ b/Modules/IO/IOGDAL/src/otbGDALImageIO.cxx @@ -1831,24 +1831,31 @@ std::vector<std::string> GDALImageIO::GetResourceFiles() const return result; } -const char * GDALImageIO::GetMetadataValue(const char * path, int band) const +const std::string GDALImageIO::GetMetadataValue(const std::string path, bool& hasValue, int band) const { // detect namespace if any - const char *slash = strchr(path,'/'); std::string domain(""); - const char *domain_c = nullptr; std::string key(path); - if (slash) - { - domain = std::string(path, (slash-path)); - domain_c = domain.c_str(); - key = std::string(slash+1); - } + std::size_t found = path.find_first_of("/"); + if (found != std::string::npos) + { + domain = path.substr(0, found); + key = path.substr(found + 1); + } + + const char* ret; if (band >= 0) - { - return m_Dataset->GetDataSet()->GetRasterBand(band+1)->GetMetadataItem(key.c_str(), domain_c); - } - return m_Dataset->GetDataSet()->GetMetadataItem(key.c_str(), domain_c); + ret = m_Dataset->GetDataSet()->GetRasterBand(band+1)->GetMetadataItem(key.c_str(), domain.c_str()); + else + ret = m_Dataset->GetDataSet()->GetMetadataItem(key.c_str(), domain.c_str()); + if (ret) + hasValue = true; + else + { + hasValue = false; + ret = ""; + } + return std::string(ret); } void GDALImageIO::SetMetadataValue(const char * path, const char * value, int band) @@ -1905,7 +1912,8 @@ void GDALImageIO::ImportMetadata() // Keys Starting with: MDGeomNames[MDGeom::SensorGeometry] + '.' should // be decoded by the (future) SensorModelFactory. // Use ImageMetadataBase::FromKeywordlist to ingest the metadata - if (std::string(GetMetadataValue("METADATATYPE")) != "OTB") + bool hasValue; + if (std::string(GetMetadataValue("METADATATYPE", hasValue)) != "OTB") return; ImageMetadataBase::Keywordlist kwl; GDALMetadataToKeywordlist(m_Dataset->GetDataSet()->GetMetadata(), kwl);