blob: fe46cbad91218002f0d520322de07002dba8e7de [file] [log] [blame]
Fyodor Kyslov1dcc4422022-11-16 01:40:53 +00001/*
2 * Copyright 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <jpegrecoverymap/recoverymaputils.h>
18#include <jpegrecoverymap/recoverymap.h>
Fyodor Kyslov6c87e7b2022-11-23 03:12:14 +000019#include <image_io/xml/xml_reader.h>
20#include <image_io/base/message_handler.h>
21#include <image_io/xml/xml_element_rules.h>
22#include <image_io/xml/xml_handler.h>
23#include <image_io/xml/xml_rule.h>
24
25#include <string>
26#include <sstream>
27
28using namespace photos_editing_formats::image_io;
29using namespace std;
Fyodor Kyslov1dcc4422022-11-16 01:40:53 +000030
31namespace android::recoverymap {
32
Fyodor Kyslov6c87e7b2022-11-23 03:12:14 +000033
34// Extremely simple XML Handler - just searches for interesting elements
35class XMPXmlHandler : public XmlHandler {
36public:
37
38 XMPXmlHandler() : XmlHandler() {
39 rangeScalingFactorState = NotStrarted;
40 }
41
42 enum ParseState {
43 NotStrarted,
44 Started,
45 Done
46 };
47
48 virtual DataMatchResult StartElement(const XmlTokenContext& context) {
49 string val;
50 if (context.BuildTokenValue(&val)) {
51 if (!val.compare(rangeScalingFactorName)) {
52 rangeScalingFactorState = Started;
53 } else {
54 if (rangeScalingFactorState != Done) {
55 rangeScalingFactorState = NotStrarted;
56 }
57 }
58 }
59 return context.GetResult();
60 }
61
62 virtual DataMatchResult FinishElement(const XmlTokenContext& context) {
63 if (rangeScalingFactorState == Started) {
64 rangeScalingFactorState = Done;
65 }
66 return context.GetResult();
67 }
68
69 virtual DataMatchResult ElementContent(const XmlTokenContext& context) {
70 string val;
71 if (rangeScalingFactorState == Started) {
72 if (context.BuildTokenValue(&val)) {
73 rangeScalingFactorStr.assign(val);
74 }
75 }
76 return context.GetResult();
77 }
78
79 bool getRangeScalingFactor(float* scaling_factor) {
80 if (rangeScalingFactorState == Done) {
81 stringstream ss(rangeScalingFactorStr);
82 float val;
83 if (ss >> val) {
84 *scaling_factor = val;
85 return true;
86 } else {
87 return false;
88 }
89 } else {
90 return false;
91 }
92 }
93
94 bool getTransferFunction(jpegr_transfer_function* transfer_function) {
95 *transfer_function = JPEGR_TF_HLG;
96 return true;
97 }
98
99private:
100 static const string rangeScalingFactorName;
101 string rangeScalingFactorStr;
102 ParseState rangeScalingFactorState;
103};
104
105const string XMPXmlHandler::rangeScalingFactorName = "GContainer:rangeScalingFactor";
106
107
Fyodor Kyslov1dcc4422022-11-16 01:40:53 +0000108bool getMetadataFromXMP(uint8_t* xmp_data, size_t xmp_size, jpegr_metadata* metadata) {
Fyodor Kyslov6c87e7b2022-11-23 03:12:14 +0000109 string nameSpace = "http://ns.adobe.com/xap/1.0/\0";
110
111 if (xmp_size < nameSpace.size()+2) {
112 // Data too short
113 return false;
114 }
115
116 if (strncmp(reinterpret_cast<char*>(xmp_data), nameSpace.c_str(), nameSpace.size())) {
117 // Not correct namespace
118 return false;
119 }
120
121 // Position the pointers to the start of XMP XML portion
122 xmp_data += nameSpace.size()+1;
123 xmp_size -= nameSpace.size()+1;
124 XMPXmlHandler handler;
125
126 // We need to remove tail data until the closing tag. Otherwise parser will throw an error.
127 while(xmp_data[xmp_size-1]!='>' && xmp_size > 1) {
128 xmp_size--;
129 }
130
131 string str(reinterpret_cast<const char*>(xmp_data), xmp_size);
132 MessageHandler msg_handler;
133 unique_ptr<XmlRule> rule(new XmlElementRule);
134 XmlReader reader(&handler, &msg_handler);
135 reader.StartParse(std::move(rule));
136 reader.Parse(str);
137 reader.FinishParse();
138 if (reader.HasErrors()) {
139 // Parse error
140 return false;
141 }
142
143 if (!handler.getRangeScalingFactor(&metadata->rangeScalingFactor)) {
144 return false;
145 }
146
147 if (!handler.getTransferFunction(&metadata->transferFunction)) {
148 return false;
149 }
Fyodor Kyslov1dcc4422022-11-16 01:40:53 +0000150 return true;
151}
152
Fyodor Kyslov6c87e7b2022-11-23 03:12:14 +0000153} // namespace android::recoverymap