/* * Copyright 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include using namespace photos_editing_formats::image_io; using namespace std; namespace android::recoverymap { // Extremely simple XML Handler - just searches for interesting elements class XMPXmlHandler : public XmlHandler { public: XMPXmlHandler() : XmlHandler() { rangeScalingFactorState = NotStrarted; } enum ParseState { NotStrarted, Started, Done }; virtual DataMatchResult StartElement(const XmlTokenContext& context) { string val; if (context.BuildTokenValue(&val)) { if (!val.compare(rangeScalingFactorName)) { rangeScalingFactorState = Started; } else { if (rangeScalingFactorState != Done) { rangeScalingFactorState = NotStrarted; } } } return context.GetResult(); } virtual DataMatchResult FinishElement(const XmlTokenContext& context) { if (rangeScalingFactorState == Started) { rangeScalingFactorState = Done; } return context.GetResult(); } virtual DataMatchResult ElementContent(const XmlTokenContext& context) { string val; if (rangeScalingFactorState == Started) { if (context.BuildTokenValue(&val)) { rangeScalingFactorStr.assign(val); } } return context.GetResult(); } bool getRangeScalingFactor(float* scaling_factor) { if (rangeScalingFactorState == Done) { stringstream ss(rangeScalingFactorStr); float val; if (ss >> val) { *scaling_factor = val; return true; } else { return false; } } else { return false; } } bool getTransferFunction(jpegr_transfer_function* transfer_function) { *transfer_function = JPEGR_TF_HLG; return true; } private: static const string rangeScalingFactorName; string rangeScalingFactorStr; ParseState rangeScalingFactorState; }; const string XMPXmlHandler::rangeScalingFactorName = "GContainer:rangeScalingFactor"; bool getMetadataFromXMP(uint8_t* xmp_data, size_t xmp_size, jpegr_metadata* metadata) { string nameSpace = "http://ns.adobe.com/xap/1.0/\0"; if (xmp_size < nameSpace.size()+2) { // Data too short return false; } if (strncmp(reinterpret_cast(xmp_data), nameSpace.c_str(), nameSpace.size())) { // Not correct namespace return false; } // Position the pointers to the start of XMP XML portion xmp_data += nameSpace.size()+1; xmp_size -= nameSpace.size()+1; XMPXmlHandler handler; // We need to remove tail data until the closing tag. Otherwise parser will throw an error. while(xmp_data[xmp_size-1]!='>' && xmp_size > 1) { xmp_size--; } string str(reinterpret_cast(xmp_data), xmp_size); MessageHandler msg_handler; unique_ptr rule(new XmlElementRule); XmlReader reader(&handler, &msg_handler); reader.StartParse(std::move(rule)); reader.Parse(str); reader.FinishParse(); if (reader.HasErrors()) { // Parse error return false; } if (!handler.getRangeScalingFactor(&metadata->rangeScalingFactor)) { return false; } if (!handler.getTransferFunction(&metadata->transferFunction)) { return false; } return true; } } // namespace android::recoverymap