xref: /aosp_15_r20/frameworks/base/tools/aapt2/ResourceValues.cpp (revision d57664e9bc4670b3ecf6748a746a57c557b6bc9e)
1*d57664e9SAndroid Build Coastguard Worker /*
2*d57664e9SAndroid Build Coastguard Worker  * Copyright (C) 2015 The Android Open Source Project
3*d57664e9SAndroid Build Coastguard Worker  *
4*d57664e9SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*d57664e9SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*d57664e9SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*d57664e9SAndroid Build Coastguard Worker  *
8*d57664e9SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*d57664e9SAndroid Build Coastguard Worker  *
10*d57664e9SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*d57664e9SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*d57664e9SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*d57664e9SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*d57664e9SAndroid Build Coastguard Worker  * limitations under the License.
15*d57664e9SAndroid Build Coastguard Worker  */
16*d57664e9SAndroid Build Coastguard Worker 
17*d57664e9SAndroid Build Coastguard Worker #include "ResourceValues.h"
18*d57664e9SAndroid Build Coastguard Worker 
19*d57664e9SAndroid Build Coastguard Worker #include <algorithm>
20*d57664e9SAndroid Build Coastguard Worker #include <cinttypes>
21*d57664e9SAndroid Build Coastguard Worker #include <limits>
22*d57664e9SAndroid Build Coastguard Worker #include <set>
23*d57664e9SAndroid Build Coastguard Worker #include <sstream>
24*d57664e9SAndroid Build Coastguard Worker 
25*d57664e9SAndroid Build Coastguard Worker #include "android-base/stringprintf.h"
26*d57664e9SAndroid Build Coastguard Worker #include "androidfw/ResourceTypes.h"
27*d57664e9SAndroid Build Coastguard Worker 
28*d57664e9SAndroid Build Coastguard Worker #include "Resource.h"
29*d57664e9SAndroid Build Coastguard Worker #include "ResourceUtils.h"
30*d57664e9SAndroid Build Coastguard Worker #include "ValueVisitor.h"
31*d57664e9SAndroid Build Coastguard Worker #include "util/Util.h"
32*d57664e9SAndroid Build Coastguard Worker 
33*d57664e9SAndroid Build Coastguard Worker using ::aapt::text::Printer;
34*d57664e9SAndroid Build Coastguard Worker using ::android::StringPiece;
35*d57664e9SAndroid Build Coastguard Worker using ::android::base::StringPrintf;
36*d57664e9SAndroid Build Coastguard Worker 
37*d57664e9SAndroid Build Coastguard Worker namespace aapt {
38*d57664e9SAndroid Build Coastguard Worker 
PrettyPrint(Printer * printer) const39*d57664e9SAndroid Build Coastguard Worker void Value::PrettyPrint(Printer* printer) const {
40*d57664e9SAndroid Build Coastguard Worker   std::ostringstream str_stream;
41*d57664e9SAndroid Build Coastguard Worker   Print(&str_stream);
42*d57664e9SAndroid Build Coastguard Worker   printer->Print(str_stream.str());
43*d57664e9SAndroid Build Coastguard Worker }
44*d57664e9SAndroid Build Coastguard Worker 
operator <<(std::ostream & out,const Value & value)45*d57664e9SAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& out, const Value& value) {
46*d57664e9SAndroid Build Coastguard Worker   value.Print(&out);
47*d57664e9SAndroid Build Coastguard Worker   return out;
48*d57664e9SAndroid Build Coastguard Worker }
49*d57664e9SAndroid Build Coastguard Worker 
Transform(ValueTransformer & transformer) const50*d57664e9SAndroid Build Coastguard Worker std::unique_ptr<Value> Value::Transform(ValueTransformer& transformer) const {
51*d57664e9SAndroid Build Coastguard Worker   return std::unique_ptr<Value>(this->TransformValueImpl(transformer));
52*d57664e9SAndroid Build Coastguard Worker }
53*d57664e9SAndroid Build Coastguard Worker 
Transform(ValueTransformer & transformer) const54*d57664e9SAndroid Build Coastguard Worker std::unique_ptr<Item> Item::Transform(ValueTransformer& transformer) const {
55*d57664e9SAndroid Build Coastguard Worker   return std::unique_ptr<Item>(this->TransformItemImpl(transformer));
56*d57664e9SAndroid Build Coastguard Worker }
57*d57664e9SAndroid Build Coastguard Worker 
58*d57664e9SAndroid Build Coastguard Worker template <typename Derived>
Accept(ValueVisitor * visitor)59*d57664e9SAndroid Build Coastguard Worker void BaseValue<Derived>::Accept(ValueVisitor* visitor) {
60*d57664e9SAndroid Build Coastguard Worker   visitor->Visit(static_cast<Derived*>(this));
61*d57664e9SAndroid Build Coastguard Worker }
62*d57664e9SAndroid Build Coastguard Worker 
63*d57664e9SAndroid Build Coastguard Worker template <typename Derived>
Accept(ConstValueVisitor * visitor) const64*d57664e9SAndroid Build Coastguard Worker void BaseValue<Derived>::Accept(ConstValueVisitor* visitor) const {
65*d57664e9SAndroid Build Coastguard Worker   visitor->Visit(static_cast<const Derived*>(this));
66*d57664e9SAndroid Build Coastguard Worker }
67*d57664e9SAndroid Build Coastguard Worker 
68*d57664e9SAndroid Build Coastguard Worker template <typename Derived>
Accept(ValueVisitor * visitor)69*d57664e9SAndroid Build Coastguard Worker void BaseItem<Derived>::Accept(ValueVisitor* visitor) {
70*d57664e9SAndroid Build Coastguard Worker   visitor->Visit(static_cast<Derived*>(this));
71*d57664e9SAndroid Build Coastguard Worker }
72*d57664e9SAndroid Build Coastguard Worker 
73*d57664e9SAndroid Build Coastguard Worker template <typename Derived>
Accept(ConstValueVisitor * visitor) const74*d57664e9SAndroid Build Coastguard Worker void BaseItem<Derived>::Accept(ConstValueVisitor* visitor) const {
75*d57664e9SAndroid Build Coastguard Worker   visitor->Visit(static_cast<const Derived*>(this));
76*d57664e9SAndroid Build Coastguard Worker }
77*d57664e9SAndroid Build Coastguard Worker 
RawString(const android::StringPool::Ref & ref)78*d57664e9SAndroid Build Coastguard Worker RawString::RawString(const android::StringPool::Ref& ref) : value(ref) {
79*d57664e9SAndroid Build Coastguard Worker }
80*d57664e9SAndroid Build Coastguard Worker 
Equals(const Value * value) const81*d57664e9SAndroid Build Coastguard Worker bool RawString::Equals(const Value* value) const {
82*d57664e9SAndroid Build Coastguard Worker   const RawString* other = ValueCast<RawString>(value);
83*d57664e9SAndroid Build Coastguard Worker   if (!other) {
84*d57664e9SAndroid Build Coastguard Worker     return false;
85*d57664e9SAndroid Build Coastguard Worker   }
86*d57664e9SAndroid Build Coastguard Worker   return *this->value == *other->value;
87*d57664e9SAndroid Build Coastguard Worker }
88*d57664e9SAndroid Build Coastguard Worker 
Flatten(android::Res_value * out_value) const89*d57664e9SAndroid Build Coastguard Worker bool RawString::Flatten(android::Res_value* out_value) const {
90*d57664e9SAndroid Build Coastguard Worker   out_value->dataType = android::Res_value::TYPE_STRING;
91*d57664e9SAndroid Build Coastguard Worker   out_value->data = android::util::HostToDevice32(static_cast<uint32_t>(value.index()));
92*d57664e9SAndroid Build Coastguard Worker   return true;
93*d57664e9SAndroid Build Coastguard Worker }
94*d57664e9SAndroid Build Coastguard Worker 
Print(std::ostream * out) const95*d57664e9SAndroid Build Coastguard Worker void RawString::Print(std::ostream* out) const {
96*d57664e9SAndroid Build Coastguard Worker   *out << "(raw string) " << *value;
97*d57664e9SAndroid Build Coastguard Worker }
98*d57664e9SAndroid Build Coastguard Worker 
Reference()99*d57664e9SAndroid Build Coastguard Worker Reference::Reference() : reference_type(Type::kResource) {}
100*d57664e9SAndroid Build Coastguard Worker 
Reference(const ResourceNameRef & n,Type t)101*d57664e9SAndroid Build Coastguard Worker Reference::Reference(const ResourceNameRef& n, Type t)
102*d57664e9SAndroid Build Coastguard Worker     : name(n.ToResourceName()), reference_type(t) {}
103*d57664e9SAndroid Build Coastguard Worker 
Reference(const ResourceId & i,Type type)104*d57664e9SAndroid Build Coastguard Worker Reference::Reference(const ResourceId& i, Type type)
105*d57664e9SAndroid Build Coastguard Worker     : id(i), reference_type(type) {}
106*d57664e9SAndroid Build Coastguard Worker 
Reference(const ResourceNameRef & n,const ResourceId & i)107*d57664e9SAndroid Build Coastguard Worker Reference::Reference(const ResourceNameRef& n, const ResourceId& i)
108*d57664e9SAndroid Build Coastguard Worker     : name(n.ToResourceName()), id(i), reference_type(Type::kResource) {}
109*d57664e9SAndroid Build Coastguard Worker 
Equals(const Value * value) const110*d57664e9SAndroid Build Coastguard Worker bool Reference::Equals(const Value* value) const {
111*d57664e9SAndroid Build Coastguard Worker   const Reference* other = ValueCast<Reference>(value);
112*d57664e9SAndroid Build Coastguard Worker   if (!other) {
113*d57664e9SAndroid Build Coastguard Worker     return false;
114*d57664e9SAndroid Build Coastguard Worker   }
115*d57664e9SAndroid Build Coastguard Worker   return reference_type == other->reference_type && private_reference == other->private_reference &&
116*d57664e9SAndroid Build Coastguard Worker          id == other->id && name == other->name && type_flags == other->type_flags;
117*d57664e9SAndroid Build Coastguard Worker }
118*d57664e9SAndroid Build Coastguard Worker 
Flatten(android::Res_value * out_value) const119*d57664e9SAndroid Build Coastguard Worker bool Reference::Flatten(android::Res_value* out_value) const {
120*d57664e9SAndroid Build Coastguard Worker   if (name && name.value().type.type == ResourceType::kMacro) {
121*d57664e9SAndroid Build Coastguard Worker     return false;
122*d57664e9SAndroid Build Coastguard Worker   }
123*d57664e9SAndroid Build Coastguard Worker 
124*d57664e9SAndroid Build Coastguard Worker   const ResourceId resid = id.value_or(ResourceId(0));
125*d57664e9SAndroid Build Coastguard Worker   const bool dynamic = resid.is_valid() && is_dynamic;
126*d57664e9SAndroid Build Coastguard Worker 
127*d57664e9SAndroid Build Coastguard Worker   if (reference_type == Reference::Type::kResource) {
128*d57664e9SAndroid Build Coastguard Worker     if (dynamic) {
129*d57664e9SAndroid Build Coastguard Worker       out_value->dataType = android::Res_value::TYPE_DYNAMIC_REFERENCE;
130*d57664e9SAndroid Build Coastguard Worker     } else {
131*d57664e9SAndroid Build Coastguard Worker       out_value->dataType = android::Res_value::TYPE_REFERENCE;
132*d57664e9SAndroid Build Coastguard Worker     }
133*d57664e9SAndroid Build Coastguard Worker   } else {
134*d57664e9SAndroid Build Coastguard Worker     if (dynamic) {
135*d57664e9SAndroid Build Coastguard Worker       out_value->dataType = android::Res_value::TYPE_DYNAMIC_ATTRIBUTE;
136*d57664e9SAndroid Build Coastguard Worker     } else {
137*d57664e9SAndroid Build Coastguard Worker       out_value->dataType = android::Res_value::TYPE_ATTRIBUTE;
138*d57664e9SAndroid Build Coastguard Worker     }
139*d57664e9SAndroid Build Coastguard Worker   }
140*d57664e9SAndroid Build Coastguard Worker   out_value->data = android::util::HostToDevice32(resid.id);
141*d57664e9SAndroid Build Coastguard Worker   return true;
142*d57664e9SAndroid Build Coastguard Worker }
143*d57664e9SAndroid Build Coastguard Worker 
Print(std::ostream * out) const144*d57664e9SAndroid Build Coastguard Worker void Reference::Print(std::ostream* out) const {
145*d57664e9SAndroid Build Coastguard Worker   if (reference_type == Type::kResource) {
146*d57664e9SAndroid Build Coastguard Worker     *out << "(reference) @";
147*d57664e9SAndroid Build Coastguard Worker     if (!name && !id) {
148*d57664e9SAndroid Build Coastguard Worker       *out << "null";
149*d57664e9SAndroid Build Coastguard Worker       return;
150*d57664e9SAndroid Build Coastguard Worker     }
151*d57664e9SAndroid Build Coastguard Worker   } else {
152*d57664e9SAndroid Build Coastguard Worker     *out << "(attr-reference) ?";
153*d57664e9SAndroid Build Coastguard Worker   }
154*d57664e9SAndroid Build Coastguard Worker 
155*d57664e9SAndroid Build Coastguard Worker   if (private_reference) {
156*d57664e9SAndroid Build Coastguard Worker     *out << "*";
157*d57664e9SAndroid Build Coastguard Worker   }
158*d57664e9SAndroid Build Coastguard Worker 
159*d57664e9SAndroid Build Coastguard Worker   if (name) {
160*d57664e9SAndroid Build Coastguard Worker     *out << name.value();
161*d57664e9SAndroid Build Coastguard Worker   }
162*d57664e9SAndroid Build Coastguard Worker 
163*d57664e9SAndroid Build Coastguard Worker   if (id && id.value().is_valid()) {
164*d57664e9SAndroid Build Coastguard Worker     if (name) {
165*d57664e9SAndroid Build Coastguard Worker       *out << " ";
166*d57664e9SAndroid Build Coastguard Worker     }
167*d57664e9SAndroid Build Coastguard Worker     *out << id.value();
168*d57664e9SAndroid Build Coastguard Worker   }
169*d57664e9SAndroid Build Coastguard Worker }
170*d57664e9SAndroid Build Coastguard Worker 
PrettyPrintReferenceImpl(const Reference & ref,bool print_package,Printer * printer)171*d57664e9SAndroid Build Coastguard Worker static void PrettyPrintReferenceImpl(const Reference& ref, bool print_package, Printer* printer) {
172*d57664e9SAndroid Build Coastguard Worker   switch (ref.reference_type) {
173*d57664e9SAndroid Build Coastguard Worker     case Reference::Type::kResource:
174*d57664e9SAndroid Build Coastguard Worker       printer->Print("@");
175*d57664e9SAndroid Build Coastguard Worker       break;
176*d57664e9SAndroid Build Coastguard Worker 
177*d57664e9SAndroid Build Coastguard Worker     case Reference::Type::kAttribute:
178*d57664e9SAndroid Build Coastguard Worker       printer->Print("?");
179*d57664e9SAndroid Build Coastguard Worker       break;
180*d57664e9SAndroid Build Coastguard Worker   }
181*d57664e9SAndroid Build Coastguard Worker 
182*d57664e9SAndroid Build Coastguard Worker   if (!ref.name && !ref.id) {
183*d57664e9SAndroid Build Coastguard Worker     printer->Print("null");
184*d57664e9SAndroid Build Coastguard Worker     return;
185*d57664e9SAndroid Build Coastguard Worker   }
186*d57664e9SAndroid Build Coastguard Worker 
187*d57664e9SAndroid Build Coastguard Worker   if (ref.private_reference) {
188*d57664e9SAndroid Build Coastguard Worker     printer->Print("*");
189*d57664e9SAndroid Build Coastguard Worker   }
190*d57664e9SAndroid Build Coastguard Worker 
191*d57664e9SAndroid Build Coastguard Worker   if (ref.name) {
192*d57664e9SAndroid Build Coastguard Worker     const ResourceName& name = ref.name.value();
193*d57664e9SAndroid Build Coastguard Worker     if (print_package) {
194*d57664e9SAndroid Build Coastguard Worker       printer->Print(name.to_string());
195*d57664e9SAndroid Build Coastguard Worker     } else {
196*d57664e9SAndroid Build Coastguard Worker       printer->Print(name.type.to_string());
197*d57664e9SAndroid Build Coastguard Worker       printer->Print("/");
198*d57664e9SAndroid Build Coastguard Worker       printer->Print(name.entry);
199*d57664e9SAndroid Build Coastguard Worker     }
200*d57664e9SAndroid Build Coastguard Worker   } else if (ref.id && ref.id.value().is_valid()) {
201*d57664e9SAndroid Build Coastguard Worker     printer->Print(ref.id.value().to_string());
202*d57664e9SAndroid Build Coastguard Worker   }
203*d57664e9SAndroid Build Coastguard Worker }
204*d57664e9SAndroid Build Coastguard Worker 
PrettyPrint(Printer * printer) const205*d57664e9SAndroid Build Coastguard Worker void Reference::PrettyPrint(Printer* printer) const {
206*d57664e9SAndroid Build Coastguard Worker   PrettyPrintReferenceImpl(*this, true /*print_package*/, printer);
207*d57664e9SAndroid Build Coastguard Worker }
208*d57664e9SAndroid Build Coastguard Worker 
PrettyPrint(StringPiece package,Printer * printer) const209*d57664e9SAndroid Build Coastguard Worker void Reference::PrettyPrint(StringPiece package, Printer* printer) const {
210*d57664e9SAndroid Build Coastguard Worker   const bool print_package = name ? package != name.value().package : true;
211*d57664e9SAndroid Build Coastguard Worker   PrettyPrintReferenceImpl(*this, print_package, printer);
212*d57664e9SAndroid Build Coastguard Worker }
213*d57664e9SAndroid Build Coastguard Worker 
Equals(const Value * value) const214*d57664e9SAndroid Build Coastguard Worker bool Id::Equals(const Value* value) const {
215*d57664e9SAndroid Build Coastguard Worker   return ValueCast<Id>(value) != nullptr;
216*d57664e9SAndroid Build Coastguard Worker }
217*d57664e9SAndroid Build Coastguard Worker 
Flatten(android::Res_value * out) const218*d57664e9SAndroid Build Coastguard Worker bool Id::Flatten(android::Res_value* out) const {
219*d57664e9SAndroid Build Coastguard Worker   out->dataType = android::Res_value::TYPE_INT_BOOLEAN;
220*d57664e9SAndroid Build Coastguard Worker   out->data = android::util::HostToDevice32(0);
221*d57664e9SAndroid Build Coastguard Worker   return true;
222*d57664e9SAndroid Build Coastguard Worker }
223*d57664e9SAndroid Build Coastguard Worker 
Print(std::ostream * out) const224*d57664e9SAndroid Build Coastguard Worker void Id::Print(std::ostream* out) const {
225*d57664e9SAndroid Build Coastguard Worker   *out << "(id)";
226*d57664e9SAndroid Build Coastguard Worker }
227*d57664e9SAndroid Build Coastguard Worker 
String(const android::StringPool::Ref & ref)228*d57664e9SAndroid Build Coastguard Worker String::String(const android::StringPool::Ref& ref) : value(ref) {
229*d57664e9SAndroid Build Coastguard Worker }
230*d57664e9SAndroid Build Coastguard Worker 
Equals(const Value * value) const231*d57664e9SAndroid Build Coastguard Worker bool String::Equals(const Value* value) const {
232*d57664e9SAndroid Build Coastguard Worker   const String* other = ValueCast<String>(value);
233*d57664e9SAndroid Build Coastguard Worker   if (!other) {
234*d57664e9SAndroid Build Coastguard Worker     return false;
235*d57664e9SAndroid Build Coastguard Worker   }
236*d57664e9SAndroid Build Coastguard Worker 
237*d57664e9SAndroid Build Coastguard Worker   if (this->value != other->value) {
238*d57664e9SAndroid Build Coastguard Worker     return false;
239*d57664e9SAndroid Build Coastguard Worker   }
240*d57664e9SAndroid Build Coastguard Worker 
241*d57664e9SAndroid Build Coastguard Worker   if (untranslatable_sections.size() != other->untranslatable_sections.size()) {
242*d57664e9SAndroid Build Coastguard Worker     return false;
243*d57664e9SAndroid Build Coastguard Worker   }
244*d57664e9SAndroid Build Coastguard Worker 
245*d57664e9SAndroid Build Coastguard Worker   auto other_iter = other->untranslatable_sections.begin();
246*d57664e9SAndroid Build Coastguard Worker   for (const UntranslatableSection& this_section : untranslatable_sections) {
247*d57664e9SAndroid Build Coastguard Worker     if (this_section != *other_iter) {
248*d57664e9SAndroid Build Coastguard Worker       return false;
249*d57664e9SAndroid Build Coastguard Worker     }
250*d57664e9SAndroid Build Coastguard Worker     ++other_iter;
251*d57664e9SAndroid Build Coastguard Worker   }
252*d57664e9SAndroid Build Coastguard Worker   return true;
253*d57664e9SAndroid Build Coastguard Worker }
254*d57664e9SAndroid Build Coastguard Worker 
Flatten(android::Res_value * out_value) const255*d57664e9SAndroid Build Coastguard Worker bool String::Flatten(android::Res_value* out_value) const {
256*d57664e9SAndroid Build Coastguard Worker   // Verify that our StringPool index is within encode-able limits.
257*d57664e9SAndroid Build Coastguard Worker   if (value.index() > std::numeric_limits<uint32_t>::max()) {
258*d57664e9SAndroid Build Coastguard Worker     return false;
259*d57664e9SAndroid Build Coastguard Worker   }
260*d57664e9SAndroid Build Coastguard Worker 
261*d57664e9SAndroid Build Coastguard Worker   out_value->dataType = android::Res_value::TYPE_STRING;
262*d57664e9SAndroid Build Coastguard Worker   out_value->data = android::util::HostToDevice32(static_cast<uint32_t>(value.index()));
263*d57664e9SAndroid Build Coastguard Worker   return true;
264*d57664e9SAndroid Build Coastguard Worker }
265*d57664e9SAndroid Build Coastguard Worker 
Print(std::ostream * out) const266*d57664e9SAndroid Build Coastguard Worker void String::Print(std::ostream* out) const {
267*d57664e9SAndroid Build Coastguard Worker   *out << "(string) \"" << *value << "\"";
268*d57664e9SAndroid Build Coastguard Worker }
269*d57664e9SAndroid Build Coastguard Worker 
PrettyPrint(Printer * printer) const270*d57664e9SAndroid Build Coastguard Worker void String::PrettyPrint(Printer* printer) const {
271*d57664e9SAndroid Build Coastguard Worker   printer->Print("\"");
272*d57664e9SAndroid Build Coastguard Worker   printer->Print(*value);
273*d57664e9SAndroid Build Coastguard Worker   printer->Print("\"");
274*d57664e9SAndroid Build Coastguard Worker }
275*d57664e9SAndroid Build Coastguard Worker 
StyledString(const android::StringPool::StyleRef & ref)276*d57664e9SAndroid Build Coastguard Worker StyledString::StyledString(const android::StringPool::StyleRef& ref) : value(ref) {
277*d57664e9SAndroid Build Coastguard Worker }
278*d57664e9SAndroid Build Coastguard Worker 
Equals(const Value * value) const279*d57664e9SAndroid Build Coastguard Worker bool StyledString::Equals(const Value* value) const {
280*d57664e9SAndroid Build Coastguard Worker   const StyledString* other = ValueCast<StyledString>(value);
281*d57664e9SAndroid Build Coastguard Worker   if (!other) {
282*d57664e9SAndroid Build Coastguard Worker     return false;
283*d57664e9SAndroid Build Coastguard Worker   }
284*d57664e9SAndroid Build Coastguard Worker 
285*d57664e9SAndroid Build Coastguard Worker   if (this->value != other->value) {
286*d57664e9SAndroid Build Coastguard Worker     return false;
287*d57664e9SAndroid Build Coastguard Worker   }
288*d57664e9SAndroid Build Coastguard Worker 
289*d57664e9SAndroid Build Coastguard Worker   if (untranslatable_sections.size() != other->untranslatable_sections.size()) {
290*d57664e9SAndroid Build Coastguard Worker     return false;
291*d57664e9SAndroid Build Coastguard Worker   }
292*d57664e9SAndroid Build Coastguard Worker 
293*d57664e9SAndroid Build Coastguard Worker   auto other_iter = other->untranslatable_sections.begin();
294*d57664e9SAndroid Build Coastguard Worker   for (const UntranslatableSection& this_section : untranslatable_sections) {
295*d57664e9SAndroid Build Coastguard Worker     if (this_section != *other_iter) {
296*d57664e9SAndroid Build Coastguard Worker       return false;
297*d57664e9SAndroid Build Coastguard Worker     }
298*d57664e9SAndroid Build Coastguard Worker     ++other_iter;
299*d57664e9SAndroid Build Coastguard Worker   }
300*d57664e9SAndroid Build Coastguard Worker   return true;
301*d57664e9SAndroid Build Coastguard Worker }
302*d57664e9SAndroid Build Coastguard Worker 
Flatten(android::Res_value * out_value) const303*d57664e9SAndroid Build Coastguard Worker bool StyledString::Flatten(android::Res_value* out_value) const {
304*d57664e9SAndroid Build Coastguard Worker   if (value.index() > std::numeric_limits<uint32_t>::max()) {
305*d57664e9SAndroid Build Coastguard Worker     return false;
306*d57664e9SAndroid Build Coastguard Worker   }
307*d57664e9SAndroid Build Coastguard Worker 
308*d57664e9SAndroid Build Coastguard Worker   out_value->dataType = android::Res_value::TYPE_STRING;
309*d57664e9SAndroid Build Coastguard Worker   out_value->data = android::util::HostToDevice32(static_cast<uint32_t>(value.index()));
310*d57664e9SAndroid Build Coastguard Worker   return true;
311*d57664e9SAndroid Build Coastguard Worker }
312*d57664e9SAndroid Build Coastguard Worker 
Print(std::ostream * out) const313*d57664e9SAndroid Build Coastguard Worker void StyledString::Print(std::ostream* out) const {
314*d57664e9SAndroid Build Coastguard Worker   *out << "(styled string) \"" << value->value << "\"";
315*d57664e9SAndroid Build Coastguard Worker   for (const android::StringPool::Span& span : value->spans) {
316*d57664e9SAndroid Build Coastguard Worker     *out << " " << *span.name << ":" << span.first_char << "," << span.last_char;
317*d57664e9SAndroid Build Coastguard Worker   }
318*d57664e9SAndroid Build Coastguard Worker }
319*d57664e9SAndroid Build Coastguard Worker 
FileReference(const android::StringPool::Ref & _path)320*d57664e9SAndroid Build Coastguard Worker FileReference::FileReference(const android::StringPool::Ref& _path) : path(_path) {
321*d57664e9SAndroid Build Coastguard Worker }
322*d57664e9SAndroid Build Coastguard Worker 
Equals(const Value * value) const323*d57664e9SAndroid Build Coastguard Worker bool FileReference::Equals(const Value* value) const {
324*d57664e9SAndroid Build Coastguard Worker   const FileReference* other = ValueCast<FileReference>(value);
325*d57664e9SAndroid Build Coastguard Worker   if (!other) {
326*d57664e9SAndroid Build Coastguard Worker     return false;
327*d57664e9SAndroid Build Coastguard Worker   }
328*d57664e9SAndroid Build Coastguard Worker   return path == other->path;
329*d57664e9SAndroid Build Coastguard Worker }
330*d57664e9SAndroid Build Coastguard Worker 
Flatten(android::Res_value * out_value) const331*d57664e9SAndroid Build Coastguard Worker bool FileReference::Flatten(android::Res_value* out_value) const {
332*d57664e9SAndroid Build Coastguard Worker   if (path.index() > std::numeric_limits<uint32_t>::max()) {
333*d57664e9SAndroid Build Coastguard Worker     return false;
334*d57664e9SAndroid Build Coastguard Worker   }
335*d57664e9SAndroid Build Coastguard Worker 
336*d57664e9SAndroid Build Coastguard Worker   out_value->dataType = android::Res_value::TYPE_STRING;
337*d57664e9SAndroid Build Coastguard Worker   out_value->data = android::util::HostToDevice32(static_cast<uint32_t>(path.index()));
338*d57664e9SAndroid Build Coastguard Worker   return true;
339*d57664e9SAndroid Build Coastguard Worker }
340*d57664e9SAndroid Build Coastguard Worker 
Print(std::ostream * out) const341*d57664e9SAndroid Build Coastguard Worker void FileReference::Print(std::ostream* out) const {
342*d57664e9SAndroid Build Coastguard Worker   *out << "(file) " << *path;
343*d57664e9SAndroid Build Coastguard Worker   switch (type) {
344*d57664e9SAndroid Build Coastguard Worker     case ResourceFile::Type::kBinaryXml:
345*d57664e9SAndroid Build Coastguard Worker       *out << " type=XML";
346*d57664e9SAndroid Build Coastguard Worker       break;
347*d57664e9SAndroid Build Coastguard Worker     case ResourceFile::Type::kProtoXml:
348*d57664e9SAndroid Build Coastguard Worker       *out << " type=protoXML";
349*d57664e9SAndroid Build Coastguard Worker       break;
350*d57664e9SAndroid Build Coastguard Worker     case ResourceFile::Type::kPng:
351*d57664e9SAndroid Build Coastguard Worker       *out << " type=PNG";
352*d57664e9SAndroid Build Coastguard Worker       break;
353*d57664e9SAndroid Build Coastguard Worker     default:
354*d57664e9SAndroid Build Coastguard Worker       break;
355*d57664e9SAndroid Build Coastguard Worker   }
356*d57664e9SAndroid Build Coastguard Worker }
357*d57664e9SAndroid Build Coastguard Worker 
BinaryPrimitive(const android::Res_value & val)358*d57664e9SAndroid Build Coastguard Worker BinaryPrimitive::BinaryPrimitive(const android::Res_value& val) : value(val) {
359*d57664e9SAndroid Build Coastguard Worker }
360*d57664e9SAndroid Build Coastguard Worker 
BinaryPrimitive(uint8_t dataType,uint32_t data)361*d57664e9SAndroid Build Coastguard Worker BinaryPrimitive::BinaryPrimitive(uint8_t dataType, uint32_t data) {
362*d57664e9SAndroid Build Coastguard Worker   value.dataType = dataType;
363*d57664e9SAndroid Build Coastguard Worker   value.data = data;
364*d57664e9SAndroid Build Coastguard Worker }
365*d57664e9SAndroid Build Coastguard Worker 
Equals(const Value * value) const366*d57664e9SAndroid Build Coastguard Worker bool BinaryPrimitive::Equals(const Value* value) const {
367*d57664e9SAndroid Build Coastguard Worker   const BinaryPrimitive* other = ValueCast<BinaryPrimitive>(value);
368*d57664e9SAndroid Build Coastguard Worker   if (!other) {
369*d57664e9SAndroid Build Coastguard Worker     return false;
370*d57664e9SAndroid Build Coastguard Worker   }
371*d57664e9SAndroid Build Coastguard Worker   return this->value.dataType == other->value.dataType &&
372*d57664e9SAndroid Build Coastguard Worker          this->value.data == other->value.data;
373*d57664e9SAndroid Build Coastguard Worker }
374*d57664e9SAndroid Build Coastguard Worker 
Flatten(::android::Res_value * out_value) const375*d57664e9SAndroid Build Coastguard Worker bool BinaryPrimitive::Flatten(::android::Res_value* out_value) const {
376*d57664e9SAndroid Build Coastguard Worker   out_value->dataType = value.dataType;
377*d57664e9SAndroid Build Coastguard Worker   out_value->data = android::util::HostToDevice32(value.data);
378*d57664e9SAndroid Build Coastguard Worker   return true;
379*d57664e9SAndroid Build Coastguard Worker }
380*d57664e9SAndroid Build Coastguard Worker 
Print(std::ostream * out) const381*d57664e9SAndroid Build Coastguard Worker void BinaryPrimitive::Print(std::ostream* out) const {
382*d57664e9SAndroid Build Coastguard Worker   *out << StringPrintf("(primitive) type=0x%02x data=0x%08x", value.dataType, value.data);
383*d57664e9SAndroid Build Coastguard Worker }
384*d57664e9SAndroid Build Coastguard Worker 
ComplexToString(uint32_t complex_value,bool fraction)385*d57664e9SAndroid Build Coastguard Worker static std::string ComplexToString(uint32_t complex_value, bool fraction) {
386*d57664e9SAndroid Build Coastguard Worker   using ::android::Res_value;
387*d57664e9SAndroid Build Coastguard Worker 
388*d57664e9SAndroid Build Coastguard Worker   constexpr std::array<int, 4> kRadixShifts = {{23, 16, 8, 0}};
389*d57664e9SAndroid Build Coastguard Worker 
390*d57664e9SAndroid Build Coastguard Worker   // Determine the radix that was used.
391*d57664e9SAndroid Build Coastguard Worker   const uint32_t radix =
392*d57664e9SAndroid Build Coastguard Worker       (complex_value >> Res_value::COMPLEX_RADIX_SHIFT) & Res_value::COMPLEX_RADIX_MASK;
393*d57664e9SAndroid Build Coastguard Worker   const uint64_t mantissa = uint64_t{(complex_value >> Res_value::COMPLEX_MANTISSA_SHIFT) &
394*d57664e9SAndroid Build Coastguard Worker                                      Res_value::COMPLEX_MANTISSA_MASK}
395*d57664e9SAndroid Build Coastguard Worker                             << kRadixShifts[radix];
396*d57664e9SAndroid Build Coastguard Worker   const float value = mantissa * (1.0f / (1 << 23));
397*d57664e9SAndroid Build Coastguard Worker 
398*d57664e9SAndroid Build Coastguard Worker   std::string str = StringPrintf("%f", value);
399*d57664e9SAndroid Build Coastguard Worker 
400*d57664e9SAndroid Build Coastguard Worker   const int unit_type =
401*d57664e9SAndroid Build Coastguard Worker       (complex_value >> Res_value::COMPLEX_UNIT_SHIFT) & Res_value::COMPLEX_UNIT_MASK;
402*d57664e9SAndroid Build Coastguard Worker   if (fraction) {
403*d57664e9SAndroid Build Coastguard Worker     switch (unit_type) {
404*d57664e9SAndroid Build Coastguard Worker       case Res_value::COMPLEX_UNIT_FRACTION:
405*d57664e9SAndroid Build Coastguard Worker         str += "%";
406*d57664e9SAndroid Build Coastguard Worker         break;
407*d57664e9SAndroid Build Coastguard Worker       case Res_value::COMPLEX_UNIT_FRACTION_PARENT:
408*d57664e9SAndroid Build Coastguard Worker         str += "%p";
409*d57664e9SAndroid Build Coastguard Worker         break;
410*d57664e9SAndroid Build Coastguard Worker       default:
411*d57664e9SAndroid Build Coastguard Worker         str += "???";
412*d57664e9SAndroid Build Coastguard Worker         break;
413*d57664e9SAndroid Build Coastguard Worker     }
414*d57664e9SAndroid Build Coastguard Worker   } else {
415*d57664e9SAndroid Build Coastguard Worker     switch (unit_type) {
416*d57664e9SAndroid Build Coastguard Worker       case Res_value::COMPLEX_UNIT_PX:
417*d57664e9SAndroid Build Coastguard Worker         str += "px";
418*d57664e9SAndroid Build Coastguard Worker         break;
419*d57664e9SAndroid Build Coastguard Worker       case Res_value::COMPLEX_UNIT_DIP:
420*d57664e9SAndroid Build Coastguard Worker         str += "dp";
421*d57664e9SAndroid Build Coastguard Worker         break;
422*d57664e9SAndroid Build Coastguard Worker       case Res_value::COMPLEX_UNIT_SP:
423*d57664e9SAndroid Build Coastguard Worker         str += "sp";
424*d57664e9SAndroid Build Coastguard Worker         break;
425*d57664e9SAndroid Build Coastguard Worker       case Res_value::COMPLEX_UNIT_PT:
426*d57664e9SAndroid Build Coastguard Worker         str += "pt";
427*d57664e9SAndroid Build Coastguard Worker         break;
428*d57664e9SAndroid Build Coastguard Worker       case Res_value::COMPLEX_UNIT_IN:
429*d57664e9SAndroid Build Coastguard Worker         str += "in";
430*d57664e9SAndroid Build Coastguard Worker         break;
431*d57664e9SAndroid Build Coastguard Worker       case Res_value::COMPLEX_UNIT_MM:
432*d57664e9SAndroid Build Coastguard Worker         str += "mm";
433*d57664e9SAndroid Build Coastguard Worker         break;
434*d57664e9SAndroid Build Coastguard Worker       default:
435*d57664e9SAndroid Build Coastguard Worker         str += "???";
436*d57664e9SAndroid Build Coastguard Worker         break;
437*d57664e9SAndroid Build Coastguard Worker     }
438*d57664e9SAndroid Build Coastguard Worker   }
439*d57664e9SAndroid Build Coastguard Worker   return str;
440*d57664e9SAndroid Build Coastguard Worker }
441*d57664e9SAndroid Build Coastguard Worker 
442*d57664e9SAndroid Build Coastguard Worker // This function is designed to using different specifier to print different floats,
443*d57664e9SAndroid Build Coastguard Worker // which can print more accurate format rather than using %g only.
DecideFormat(float f)444*d57664e9SAndroid Build Coastguard Worker const char* BinaryPrimitive::DecideFormat(float f) {
445*d57664e9SAndroid Build Coastguard Worker   // if the float is either too big or too tiny, print it in scientific notation.
446*d57664e9SAndroid Build Coastguard Worker   // eg: "10995116277760000000000" to 1.099512e+22, "0.00000000001" to 1.000000e-11
447*d57664e9SAndroid Build Coastguard Worker   if (fabs(f) > std::numeric_limits<int64_t>::max() || fabs(f) < 1e-10) {
448*d57664e9SAndroid Build Coastguard Worker     return "%e";
449*d57664e9SAndroid Build Coastguard Worker     // Else if the number is an integer exactly, print it without trailing zeros.
450*d57664e9SAndroid Build Coastguard Worker     // eg: "1099511627776" to 1099511627776
451*d57664e9SAndroid Build Coastguard Worker   } else if (int64_t(f) == f) {
452*d57664e9SAndroid Build Coastguard Worker     return "%.0f";
453*d57664e9SAndroid Build Coastguard Worker   }
454*d57664e9SAndroid Build Coastguard Worker   return "%g";
455*d57664e9SAndroid Build Coastguard Worker }
456*d57664e9SAndroid Build Coastguard Worker 
PrettyPrint(Printer * printer) const457*d57664e9SAndroid Build Coastguard Worker void BinaryPrimitive::PrettyPrint(Printer* printer) const {
458*d57664e9SAndroid Build Coastguard Worker   using ::android::Res_value;
459*d57664e9SAndroid Build Coastguard Worker   switch (value.dataType) {
460*d57664e9SAndroid Build Coastguard Worker     case Res_value::TYPE_NULL:
461*d57664e9SAndroid Build Coastguard Worker       if (value.data == Res_value::DATA_NULL_EMPTY) {
462*d57664e9SAndroid Build Coastguard Worker         printer->Print("@empty");
463*d57664e9SAndroid Build Coastguard Worker       } else {
464*d57664e9SAndroid Build Coastguard Worker         printer->Print("@null");
465*d57664e9SAndroid Build Coastguard Worker       }
466*d57664e9SAndroid Build Coastguard Worker       break;
467*d57664e9SAndroid Build Coastguard Worker 
468*d57664e9SAndroid Build Coastguard Worker     case Res_value::TYPE_INT_DEC:
469*d57664e9SAndroid Build Coastguard Worker       printer->Print(StringPrintf("%" PRIi32, static_cast<int32_t>(value.data)));
470*d57664e9SAndroid Build Coastguard Worker       break;
471*d57664e9SAndroid Build Coastguard Worker 
472*d57664e9SAndroid Build Coastguard Worker     case Res_value::TYPE_INT_HEX:
473*d57664e9SAndroid Build Coastguard Worker       printer->Print(StringPrintf("0x%08x", value.data));
474*d57664e9SAndroid Build Coastguard Worker       break;
475*d57664e9SAndroid Build Coastguard Worker 
476*d57664e9SAndroid Build Coastguard Worker     case Res_value::TYPE_INT_BOOLEAN:
477*d57664e9SAndroid Build Coastguard Worker       printer->Print(value.data != 0 ? "true" : "false");
478*d57664e9SAndroid Build Coastguard Worker       break;
479*d57664e9SAndroid Build Coastguard Worker 
480*d57664e9SAndroid Build Coastguard Worker     case Res_value::TYPE_INT_COLOR_ARGB8:
481*d57664e9SAndroid Build Coastguard Worker     case Res_value::TYPE_INT_COLOR_RGB8:
482*d57664e9SAndroid Build Coastguard Worker     case Res_value::TYPE_INT_COLOR_ARGB4:
483*d57664e9SAndroid Build Coastguard Worker     case Res_value::TYPE_INT_COLOR_RGB4:
484*d57664e9SAndroid Build Coastguard Worker       printer->Print(StringPrintf("#%08x", value.data));
485*d57664e9SAndroid Build Coastguard Worker       break;
486*d57664e9SAndroid Build Coastguard Worker 
487*d57664e9SAndroid Build Coastguard Worker     case Res_value::TYPE_FLOAT:
488*d57664e9SAndroid Build Coastguard Worker       float f;
489*d57664e9SAndroid Build Coastguard Worker       f = *reinterpret_cast<const float*>(&value.data);
490*d57664e9SAndroid Build Coastguard Worker       printer->Print(StringPrintf(DecideFormat(f), f));
491*d57664e9SAndroid Build Coastguard Worker       break;
492*d57664e9SAndroid Build Coastguard Worker 
493*d57664e9SAndroid Build Coastguard Worker     case Res_value::TYPE_DIMENSION:
494*d57664e9SAndroid Build Coastguard Worker       printer->Print(ComplexToString(value.data, false /*fraction*/));
495*d57664e9SAndroid Build Coastguard Worker       break;
496*d57664e9SAndroid Build Coastguard Worker 
497*d57664e9SAndroid Build Coastguard Worker     case Res_value::TYPE_FRACTION:
498*d57664e9SAndroid Build Coastguard Worker       printer->Print(ComplexToString(value.data, true /*fraction*/));
499*d57664e9SAndroid Build Coastguard Worker       break;
500*d57664e9SAndroid Build Coastguard Worker 
501*d57664e9SAndroid Build Coastguard Worker     default:
502*d57664e9SAndroid Build Coastguard Worker       printer->Print(StringPrintf("(unknown 0x%02x) 0x%08x", value.dataType, value.data));
503*d57664e9SAndroid Build Coastguard Worker       break;
504*d57664e9SAndroid Build Coastguard Worker   }
505*d57664e9SAndroid Build Coastguard Worker }
506*d57664e9SAndroid Build Coastguard Worker 
Attribute(uint32_t t)507*d57664e9SAndroid Build Coastguard Worker Attribute::Attribute(uint32_t t)
508*d57664e9SAndroid Build Coastguard Worker     : type_mask(t),
509*d57664e9SAndroid Build Coastguard Worker       min_int(std::numeric_limits<int32_t>::min()),
510*d57664e9SAndroid Build Coastguard Worker       max_int(std::numeric_limits<int32_t>::max()) {
511*d57664e9SAndroid Build Coastguard Worker }
512*d57664e9SAndroid Build Coastguard Worker 
operator <<(std::ostream & out,const Attribute::Symbol & s)513*d57664e9SAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& out, const Attribute::Symbol& s) {
514*d57664e9SAndroid Build Coastguard Worker   if (s.symbol.name) {
515*d57664e9SAndroid Build Coastguard Worker     out << s.symbol.name.value().entry;
516*d57664e9SAndroid Build Coastguard Worker   } else {
517*d57664e9SAndroid Build Coastguard Worker     out << "???";
518*d57664e9SAndroid Build Coastguard Worker   }
519*d57664e9SAndroid Build Coastguard Worker   return out << "=" << s.value;
520*d57664e9SAndroid Build Coastguard Worker }
521*d57664e9SAndroid Build Coastguard Worker 
522*d57664e9SAndroid Build Coastguard Worker template <typename T>
add_pointer(T & val)523*d57664e9SAndroid Build Coastguard Worker constexpr T* add_pointer(T& val) {
524*d57664e9SAndroid Build Coastguard Worker   return &val;
525*d57664e9SAndroid Build Coastguard Worker }
526*d57664e9SAndroid Build Coastguard Worker 
Equals(const Value * value) const527*d57664e9SAndroid Build Coastguard Worker bool Attribute::Equals(const Value* value) const {
528*d57664e9SAndroid Build Coastguard Worker   const Attribute* other = ValueCast<Attribute>(value);
529*d57664e9SAndroid Build Coastguard Worker   if (!other) {
530*d57664e9SAndroid Build Coastguard Worker     return false;
531*d57664e9SAndroid Build Coastguard Worker   }
532*d57664e9SAndroid Build Coastguard Worker 
533*d57664e9SAndroid Build Coastguard Worker   if (symbols.size() != other->symbols.size()) {
534*d57664e9SAndroid Build Coastguard Worker     return false;
535*d57664e9SAndroid Build Coastguard Worker   }
536*d57664e9SAndroid Build Coastguard Worker 
537*d57664e9SAndroid Build Coastguard Worker   if (type_mask != other->type_mask || min_int != other->min_int || max_int != other->max_int) {
538*d57664e9SAndroid Build Coastguard Worker     return false;
539*d57664e9SAndroid Build Coastguard Worker   }
540*d57664e9SAndroid Build Coastguard Worker 
541*d57664e9SAndroid Build Coastguard Worker   std::vector<const Symbol*> sorted_a;
542*d57664e9SAndroid Build Coastguard Worker   std::transform(symbols.begin(), symbols.end(), std::back_inserter(sorted_a),
543*d57664e9SAndroid Build Coastguard Worker                  add_pointer<const Symbol>);
544*d57664e9SAndroid Build Coastguard Worker   std::sort(sorted_a.begin(), sorted_a.end(), [](const Symbol* a, const Symbol* b) -> bool {
545*d57664e9SAndroid Build Coastguard Worker     return a->symbol.name < b->symbol.name;
546*d57664e9SAndroid Build Coastguard Worker   });
547*d57664e9SAndroid Build Coastguard Worker 
548*d57664e9SAndroid Build Coastguard Worker   std::vector<const Symbol*> sorted_b;
549*d57664e9SAndroid Build Coastguard Worker   std::transform(other->symbols.begin(), other->symbols.end(), std::back_inserter(sorted_b),
550*d57664e9SAndroid Build Coastguard Worker                  add_pointer<const Symbol>);
551*d57664e9SAndroid Build Coastguard Worker   std::sort(sorted_b.begin(), sorted_b.end(), [](const Symbol* a, const Symbol* b) -> bool {
552*d57664e9SAndroid Build Coastguard Worker     return a->symbol.name < b->symbol.name;
553*d57664e9SAndroid Build Coastguard Worker   });
554*d57664e9SAndroid Build Coastguard Worker 
555*d57664e9SAndroid Build Coastguard Worker   return std::equal(sorted_a.begin(), sorted_a.end(), sorted_b.begin(),
556*d57664e9SAndroid Build Coastguard Worker                     [](const Symbol* a, const Symbol* b) -> bool {
557*d57664e9SAndroid Build Coastguard Worker                       return a->symbol.Equals(&b->symbol) && a->value == b->value;
558*d57664e9SAndroid Build Coastguard Worker                     });
559*d57664e9SAndroid Build Coastguard Worker }
560*d57664e9SAndroid Build Coastguard Worker 
IsCompatibleWith(const Attribute & attr) const561*d57664e9SAndroid Build Coastguard Worker bool Attribute::IsCompatibleWith(const Attribute& attr) const {
562*d57664e9SAndroid Build Coastguard Worker   // If the high bits are set on any of these attribute type masks, then they are incompatible.
563*d57664e9SAndroid Build Coastguard Worker   // We don't check that flags and enums are identical.
564*d57664e9SAndroid Build Coastguard Worker   if ((type_mask & ~android::ResTable_map::TYPE_ANY) != 0 ||
565*d57664e9SAndroid Build Coastguard Worker       (attr.type_mask & ~android::ResTable_map::TYPE_ANY) != 0) {
566*d57664e9SAndroid Build Coastguard Worker     return false;
567*d57664e9SAndroid Build Coastguard Worker   }
568*d57664e9SAndroid Build Coastguard Worker 
569*d57664e9SAndroid Build Coastguard Worker   // Every attribute accepts a reference.
570*d57664e9SAndroid Build Coastguard Worker   uint32_t this_type_mask = type_mask | android::ResTable_map::TYPE_REFERENCE;
571*d57664e9SAndroid Build Coastguard Worker   uint32_t that_type_mask = attr.type_mask | android::ResTable_map::TYPE_REFERENCE;
572*d57664e9SAndroid Build Coastguard Worker   return this_type_mask == that_type_mask;
573*d57664e9SAndroid Build Coastguard Worker }
574*d57664e9SAndroid Build Coastguard Worker 
MaskString(uint32_t type_mask)575*d57664e9SAndroid Build Coastguard Worker std::string Attribute::MaskString(uint32_t type_mask) {
576*d57664e9SAndroid Build Coastguard Worker   if (type_mask == android::ResTable_map::TYPE_ANY) {
577*d57664e9SAndroid Build Coastguard Worker     return "any";
578*d57664e9SAndroid Build Coastguard Worker   }
579*d57664e9SAndroid Build Coastguard Worker 
580*d57664e9SAndroid Build Coastguard Worker   std::ostringstream out;
581*d57664e9SAndroid Build Coastguard Worker   bool set = false;
582*d57664e9SAndroid Build Coastguard Worker   if ((type_mask & android::ResTable_map::TYPE_REFERENCE) != 0) {
583*d57664e9SAndroid Build Coastguard Worker     if (!set) {
584*d57664e9SAndroid Build Coastguard Worker       set = true;
585*d57664e9SAndroid Build Coastguard Worker     } else {
586*d57664e9SAndroid Build Coastguard Worker       out << "|";
587*d57664e9SAndroid Build Coastguard Worker     }
588*d57664e9SAndroid Build Coastguard Worker     out << "reference";
589*d57664e9SAndroid Build Coastguard Worker   }
590*d57664e9SAndroid Build Coastguard Worker 
591*d57664e9SAndroid Build Coastguard Worker   if ((type_mask & android::ResTable_map::TYPE_STRING) != 0) {
592*d57664e9SAndroid Build Coastguard Worker     if (!set) {
593*d57664e9SAndroid Build Coastguard Worker       set = true;
594*d57664e9SAndroid Build Coastguard Worker     } else {
595*d57664e9SAndroid Build Coastguard Worker       out << "|";
596*d57664e9SAndroid Build Coastguard Worker     }
597*d57664e9SAndroid Build Coastguard Worker     out << "string";
598*d57664e9SAndroid Build Coastguard Worker   }
599*d57664e9SAndroid Build Coastguard Worker 
600*d57664e9SAndroid Build Coastguard Worker   if ((type_mask & android::ResTable_map::TYPE_INTEGER) != 0) {
601*d57664e9SAndroid Build Coastguard Worker     if (!set) {
602*d57664e9SAndroid Build Coastguard Worker       set = true;
603*d57664e9SAndroid Build Coastguard Worker     } else {
604*d57664e9SAndroid Build Coastguard Worker       out << "|";
605*d57664e9SAndroid Build Coastguard Worker     }
606*d57664e9SAndroid Build Coastguard Worker     out << "integer";
607*d57664e9SAndroid Build Coastguard Worker   }
608*d57664e9SAndroid Build Coastguard Worker 
609*d57664e9SAndroid Build Coastguard Worker   if ((type_mask & android::ResTable_map::TYPE_BOOLEAN) != 0) {
610*d57664e9SAndroid Build Coastguard Worker     if (!set) {
611*d57664e9SAndroid Build Coastguard Worker       set = true;
612*d57664e9SAndroid Build Coastguard Worker     } else {
613*d57664e9SAndroid Build Coastguard Worker       out << "|";
614*d57664e9SAndroid Build Coastguard Worker     }
615*d57664e9SAndroid Build Coastguard Worker     out << "boolean";
616*d57664e9SAndroid Build Coastguard Worker   }
617*d57664e9SAndroid Build Coastguard Worker 
618*d57664e9SAndroid Build Coastguard Worker   if ((type_mask & android::ResTable_map::TYPE_COLOR) != 0) {
619*d57664e9SAndroid Build Coastguard Worker     if (!set) {
620*d57664e9SAndroid Build Coastguard Worker       set = true;
621*d57664e9SAndroid Build Coastguard Worker     } else {
622*d57664e9SAndroid Build Coastguard Worker       out << "|";
623*d57664e9SAndroid Build Coastguard Worker     }
624*d57664e9SAndroid Build Coastguard Worker     out << "color";
625*d57664e9SAndroid Build Coastguard Worker   }
626*d57664e9SAndroid Build Coastguard Worker 
627*d57664e9SAndroid Build Coastguard Worker   if ((type_mask & android::ResTable_map::TYPE_FLOAT) != 0) {
628*d57664e9SAndroid Build Coastguard Worker     if (!set) {
629*d57664e9SAndroid Build Coastguard Worker       set = true;
630*d57664e9SAndroid Build Coastguard Worker     } else {
631*d57664e9SAndroid Build Coastguard Worker       out << "|";
632*d57664e9SAndroid Build Coastguard Worker     }
633*d57664e9SAndroid Build Coastguard Worker     out << "float";
634*d57664e9SAndroid Build Coastguard Worker   }
635*d57664e9SAndroid Build Coastguard Worker 
636*d57664e9SAndroid Build Coastguard Worker   if ((type_mask & android::ResTable_map::TYPE_DIMENSION) != 0) {
637*d57664e9SAndroid Build Coastguard Worker     if (!set) {
638*d57664e9SAndroid Build Coastguard Worker       set = true;
639*d57664e9SAndroid Build Coastguard Worker     } else {
640*d57664e9SAndroid Build Coastguard Worker       out << "|";
641*d57664e9SAndroid Build Coastguard Worker     }
642*d57664e9SAndroid Build Coastguard Worker     out << "dimension";
643*d57664e9SAndroid Build Coastguard Worker   }
644*d57664e9SAndroid Build Coastguard Worker 
645*d57664e9SAndroid Build Coastguard Worker   if ((type_mask & android::ResTable_map::TYPE_FRACTION) != 0) {
646*d57664e9SAndroid Build Coastguard Worker     if (!set) {
647*d57664e9SAndroid Build Coastguard Worker       set = true;
648*d57664e9SAndroid Build Coastguard Worker     } else {
649*d57664e9SAndroid Build Coastguard Worker       out << "|";
650*d57664e9SAndroid Build Coastguard Worker     }
651*d57664e9SAndroid Build Coastguard Worker     out << "fraction";
652*d57664e9SAndroid Build Coastguard Worker   }
653*d57664e9SAndroid Build Coastguard Worker 
654*d57664e9SAndroid Build Coastguard Worker   if ((type_mask & android::ResTable_map::TYPE_ENUM) != 0) {
655*d57664e9SAndroid Build Coastguard Worker     if (!set) {
656*d57664e9SAndroid Build Coastguard Worker       set = true;
657*d57664e9SAndroid Build Coastguard Worker     } else {
658*d57664e9SAndroid Build Coastguard Worker       out << "|";
659*d57664e9SAndroid Build Coastguard Worker     }
660*d57664e9SAndroid Build Coastguard Worker     out << "enum";
661*d57664e9SAndroid Build Coastguard Worker   }
662*d57664e9SAndroid Build Coastguard Worker 
663*d57664e9SAndroid Build Coastguard Worker   if ((type_mask & android::ResTable_map::TYPE_FLAGS) != 0) {
664*d57664e9SAndroid Build Coastguard Worker     if (!set) {
665*d57664e9SAndroid Build Coastguard Worker       set = true;
666*d57664e9SAndroid Build Coastguard Worker     } else {
667*d57664e9SAndroid Build Coastguard Worker       out << "|";
668*d57664e9SAndroid Build Coastguard Worker     }
669*d57664e9SAndroid Build Coastguard Worker     out << "flags";
670*d57664e9SAndroid Build Coastguard Worker   }
671*d57664e9SAndroid Build Coastguard Worker   return out.str();
672*d57664e9SAndroid Build Coastguard Worker }
673*d57664e9SAndroid Build Coastguard Worker 
MaskString() const674*d57664e9SAndroid Build Coastguard Worker std::string Attribute::MaskString() const {
675*d57664e9SAndroid Build Coastguard Worker   return MaskString(type_mask);
676*d57664e9SAndroid Build Coastguard Worker }
677*d57664e9SAndroid Build Coastguard Worker 
Print(std::ostream * out) const678*d57664e9SAndroid Build Coastguard Worker void Attribute::Print(std::ostream* out) const {
679*d57664e9SAndroid Build Coastguard Worker   *out << "(attr) " << MaskString();
680*d57664e9SAndroid Build Coastguard Worker 
681*d57664e9SAndroid Build Coastguard Worker   if (!symbols.empty()) {
682*d57664e9SAndroid Build Coastguard Worker     *out << " [" << util::Joiner(symbols, ", ") << "]";
683*d57664e9SAndroid Build Coastguard Worker   }
684*d57664e9SAndroid Build Coastguard Worker 
685*d57664e9SAndroid Build Coastguard Worker   if (min_int != std::numeric_limits<int32_t>::min()) {
686*d57664e9SAndroid Build Coastguard Worker     *out << " min=" << min_int;
687*d57664e9SAndroid Build Coastguard Worker   }
688*d57664e9SAndroid Build Coastguard Worker 
689*d57664e9SAndroid Build Coastguard Worker   if (max_int != std::numeric_limits<int32_t>::max()) {
690*d57664e9SAndroid Build Coastguard Worker     *out << " max=" << max_int;
691*d57664e9SAndroid Build Coastguard Worker   }
692*d57664e9SAndroid Build Coastguard Worker 
693*d57664e9SAndroid Build Coastguard Worker   if (IsWeak()) {
694*d57664e9SAndroid Build Coastguard Worker     *out << " [weak]";
695*d57664e9SAndroid Build Coastguard Worker   }
696*d57664e9SAndroid Build Coastguard Worker }
697*d57664e9SAndroid Build Coastguard Worker 
BuildAttributeMismatchMessage(const Attribute & attr,const Item & value,android::DiagMessage * out_msg)698*d57664e9SAndroid Build Coastguard Worker static void BuildAttributeMismatchMessage(const Attribute& attr, const Item& value,
699*d57664e9SAndroid Build Coastguard Worker                                           android::DiagMessage* out_msg) {
700*d57664e9SAndroid Build Coastguard Worker   *out_msg << "expected";
701*d57664e9SAndroid Build Coastguard Worker   if (attr.type_mask & android::ResTable_map::TYPE_BOOLEAN) {
702*d57664e9SAndroid Build Coastguard Worker     *out_msg << " boolean";
703*d57664e9SAndroid Build Coastguard Worker   }
704*d57664e9SAndroid Build Coastguard Worker 
705*d57664e9SAndroid Build Coastguard Worker   if (attr.type_mask & android::ResTable_map::TYPE_COLOR) {
706*d57664e9SAndroid Build Coastguard Worker     *out_msg << " color";
707*d57664e9SAndroid Build Coastguard Worker   }
708*d57664e9SAndroid Build Coastguard Worker 
709*d57664e9SAndroid Build Coastguard Worker   if (attr.type_mask & android::ResTable_map::TYPE_DIMENSION) {
710*d57664e9SAndroid Build Coastguard Worker     *out_msg << " dimension";
711*d57664e9SAndroid Build Coastguard Worker   }
712*d57664e9SAndroid Build Coastguard Worker 
713*d57664e9SAndroid Build Coastguard Worker   if (attr.type_mask & android::ResTable_map::TYPE_ENUM) {
714*d57664e9SAndroid Build Coastguard Worker     *out_msg << " enum";
715*d57664e9SAndroid Build Coastguard Worker   }
716*d57664e9SAndroid Build Coastguard Worker 
717*d57664e9SAndroid Build Coastguard Worker   if (attr.type_mask & android::ResTable_map::TYPE_FLAGS) {
718*d57664e9SAndroid Build Coastguard Worker     *out_msg << " flags";
719*d57664e9SAndroid Build Coastguard Worker   }
720*d57664e9SAndroid Build Coastguard Worker 
721*d57664e9SAndroid Build Coastguard Worker   if (attr.type_mask & android::ResTable_map::TYPE_FLOAT) {
722*d57664e9SAndroid Build Coastguard Worker     *out_msg << " float";
723*d57664e9SAndroid Build Coastguard Worker   }
724*d57664e9SAndroid Build Coastguard Worker 
725*d57664e9SAndroid Build Coastguard Worker   if (attr.type_mask & android::ResTable_map::TYPE_FRACTION) {
726*d57664e9SAndroid Build Coastguard Worker     *out_msg << " fraction";
727*d57664e9SAndroid Build Coastguard Worker   }
728*d57664e9SAndroid Build Coastguard Worker 
729*d57664e9SAndroid Build Coastguard Worker   if (attr.type_mask & android::ResTable_map::TYPE_INTEGER) {
730*d57664e9SAndroid Build Coastguard Worker     *out_msg << " integer";
731*d57664e9SAndroid Build Coastguard Worker   }
732*d57664e9SAndroid Build Coastguard Worker 
733*d57664e9SAndroid Build Coastguard Worker   if (attr.type_mask & android::ResTable_map::TYPE_REFERENCE) {
734*d57664e9SAndroid Build Coastguard Worker     *out_msg << " reference";
735*d57664e9SAndroid Build Coastguard Worker   }
736*d57664e9SAndroid Build Coastguard Worker 
737*d57664e9SAndroid Build Coastguard Worker   if (attr.type_mask & android::ResTable_map::TYPE_STRING) {
738*d57664e9SAndroid Build Coastguard Worker     *out_msg << " string";
739*d57664e9SAndroid Build Coastguard Worker   }
740*d57664e9SAndroid Build Coastguard Worker 
741*d57664e9SAndroid Build Coastguard Worker   *out_msg << " but got " << value;
742*d57664e9SAndroid Build Coastguard Worker }
743*d57664e9SAndroid Build Coastguard Worker 
Matches(const Item & item,android::DiagMessage * out_msg) const744*d57664e9SAndroid Build Coastguard Worker bool Attribute::Matches(const Item& item, android::DiagMessage* out_msg) const {
745*d57664e9SAndroid Build Coastguard Worker   constexpr const uint32_t TYPE_ENUM = android::ResTable_map::TYPE_ENUM;
746*d57664e9SAndroid Build Coastguard Worker   constexpr const uint32_t TYPE_FLAGS = android::ResTable_map::TYPE_FLAGS;
747*d57664e9SAndroid Build Coastguard Worker   constexpr const uint32_t TYPE_INTEGER = android::ResTable_map::TYPE_INTEGER;
748*d57664e9SAndroid Build Coastguard Worker   constexpr const uint32_t TYPE_REFERENCE = android::ResTable_map::TYPE_REFERENCE;
749*d57664e9SAndroid Build Coastguard Worker 
750*d57664e9SAndroid Build Coastguard Worker   android::Res_value val = {};
751*d57664e9SAndroid Build Coastguard Worker   item.Flatten(&val);
752*d57664e9SAndroid Build Coastguard Worker 
753*d57664e9SAndroid Build Coastguard Worker   const uint32_t flattened_data = android::util::DeviceToHost32(val.data);
754*d57664e9SAndroid Build Coastguard Worker 
755*d57664e9SAndroid Build Coastguard Worker   // Always allow references.
756*d57664e9SAndroid Build Coastguard Worker   const uint32_t actual_type = ResourceUtils::AndroidTypeToAttributeTypeMask(val.dataType);
757*d57664e9SAndroid Build Coastguard Worker 
758*d57664e9SAndroid Build Coastguard Worker   // Only one type must match between the actual and expected.
759*d57664e9SAndroid Build Coastguard Worker   if ((actual_type & (type_mask | TYPE_REFERENCE)) == 0) {
760*d57664e9SAndroid Build Coastguard Worker     if (out_msg) {
761*d57664e9SAndroid Build Coastguard Worker       BuildAttributeMismatchMessage(*this, item, out_msg);
762*d57664e9SAndroid Build Coastguard Worker     }
763*d57664e9SAndroid Build Coastguard Worker     return false;
764*d57664e9SAndroid Build Coastguard Worker   }
765*d57664e9SAndroid Build Coastguard Worker 
766*d57664e9SAndroid Build Coastguard Worker   // Enums and flags are encoded as integers, so check them first before doing any range checks.
767*d57664e9SAndroid Build Coastguard Worker   if ((type_mask & TYPE_ENUM) != 0 && (actual_type & TYPE_ENUM) != 0) {
768*d57664e9SAndroid Build Coastguard Worker     for (const Symbol& s : symbols) {
769*d57664e9SAndroid Build Coastguard Worker       if (flattened_data == s.value) {
770*d57664e9SAndroid Build Coastguard Worker         return true;
771*d57664e9SAndroid Build Coastguard Worker       }
772*d57664e9SAndroid Build Coastguard Worker     }
773*d57664e9SAndroid Build Coastguard Worker 
774*d57664e9SAndroid Build Coastguard Worker     // If the attribute accepts integers, we can't fail here.
775*d57664e9SAndroid Build Coastguard Worker     if ((type_mask & TYPE_INTEGER) == 0) {
776*d57664e9SAndroid Build Coastguard Worker       if (out_msg) {
777*d57664e9SAndroid Build Coastguard Worker         *out_msg << item << " is not a valid enum";
778*d57664e9SAndroid Build Coastguard Worker       }
779*d57664e9SAndroid Build Coastguard Worker       return false;
780*d57664e9SAndroid Build Coastguard Worker     }
781*d57664e9SAndroid Build Coastguard Worker   }
782*d57664e9SAndroid Build Coastguard Worker 
783*d57664e9SAndroid Build Coastguard Worker   if ((type_mask & TYPE_FLAGS) != 0 && (actual_type & TYPE_FLAGS) != 0) {
784*d57664e9SAndroid Build Coastguard Worker     uint32_t mask = 0u;
785*d57664e9SAndroid Build Coastguard Worker     for (const Symbol& s : symbols) {
786*d57664e9SAndroid Build Coastguard Worker       mask |= s.value;
787*d57664e9SAndroid Build Coastguard Worker     }
788*d57664e9SAndroid Build Coastguard Worker 
789*d57664e9SAndroid Build Coastguard Worker     // Check if the flattened data is covered by the flag bit mask.
790*d57664e9SAndroid Build Coastguard Worker     // If the attribute accepts integers, we can't fail here.
791*d57664e9SAndroid Build Coastguard Worker     if ((mask & flattened_data) == flattened_data) {
792*d57664e9SAndroid Build Coastguard Worker       return true;
793*d57664e9SAndroid Build Coastguard Worker     } else if ((type_mask & TYPE_INTEGER) == 0) {
794*d57664e9SAndroid Build Coastguard Worker       if (out_msg) {
795*d57664e9SAndroid Build Coastguard Worker         *out_msg << item << " is not a valid flag";
796*d57664e9SAndroid Build Coastguard Worker       }
797*d57664e9SAndroid Build Coastguard Worker       return false;
798*d57664e9SAndroid Build Coastguard Worker     }
799*d57664e9SAndroid Build Coastguard Worker   }
800*d57664e9SAndroid Build Coastguard Worker 
801*d57664e9SAndroid Build Coastguard Worker   // Finally check the integer range of the value.
802*d57664e9SAndroid Build Coastguard Worker   if ((type_mask & TYPE_INTEGER) != 0 && (actual_type & TYPE_INTEGER) != 0) {
803*d57664e9SAndroid Build Coastguard Worker     if (static_cast<int32_t>(flattened_data) < min_int) {
804*d57664e9SAndroid Build Coastguard Worker       if (out_msg) {
805*d57664e9SAndroid Build Coastguard Worker         *out_msg << item << " is less than minimum integer " << min_int;
806*d57664e9SAndroid Build Coastguard Worker       }
807*d57664e9SAndroid Build Coastguard Worker       return false;
808*d57664e9SAndroid Build Coastguard Worker     } else if (static_cast<int32_t>(flattened_data) > max_int) {
809*d57664e9SAndroid Build Coastguard Worker       if (out_msg) {
810*d57664e9SAndroid Build Coastguard Worker         *out_msg << item << " is greater than maximum integer " << max_int;
811*d57664e9SAndroid Build Coastguard Worker       }
812*d57664e9SAndroid Build Coastguard Worker       return false;
813*d57664e9SAndroid Build Coastguard Worker     }
814*d57664e9SAndroid Build Coastguard Worker   }
815*d57664e9SAndroid Build Coastguard Worker   return true;
816*d57664e9SAndroid Build Coastguard Worker }
817*d57664e9SAndroid Build Coastguard Worker 
operator <<(std::ostream & out,const Style::Entry & entry)818*d57664e9SAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& out, const Style::Entry& entry) {
819*d57664e9SAndroid Build Coastguard Worker   if (entry.key.name) {
820*d57664e9SAndroid Build Coastguard Worker     out << entry.key.name.value();
821*d57664e9SAndroid Build Coastguard Worker   } else if (entry.key.id) {
822*d57664e9SAndroid Build Coastguard Worker     out << entry.key.id.value();
823*d57664e9SAndroid Build Coastguard Worker   } else {
824*d57664e9SAndroid Build Coastguard Worker     out << "???";
825*d57664e9SAndroid Build Coastguard Worker   }
826*d57664e9SAndroid Build Coastguard Worker   out << " = " << entry.value;
827*d57664e9SAndroid Build Coastguard Worker   return out;
828*d57664e9SAndroid Build Coastguard Worker }
829*d57664e9SAndroid Build Coastguard Worker 
830*d57664e9SAndroid Build Coastguard Worker template <typename T>
ToPointerVec(std::vector<T> & src)831*d57664e9SAndroid Build Coastguard Worker std::vector<T*> ToPointerVec(std::vector<T>& src) {
832*d57664e9SAndroid Build Coastguard Worker   std::vector<T*> dst;
833*d57664e9SAndroid Build Coastguard Worker   dst.reserve(src.size());
834*d57664e9SAndroid Build Coastguard Worker   for (T& in : src) {
835*d57664e9SAndroid Build Coastguard Worker     dst.push_back(&in);
836*d57664e9SAndroid Build Coastguard Worker   }
837*d57664e9SAndroid Build Coastguard Worker   return dst;
838*d57664e9SAndroid Build Coastguard Worker }
839*d57664e9SAndroid Build Coastguard Worker 
840*d57664e9SAndroid Build Coastguard Worker template <typename T>
ToPointerVec(const std::vector<T> & src)841*d57664e9SAndroid Build Coastguard Worker std::vector<const T*> ToPointerVec(const std::vector<T>& src) {
842*d57664e9SAndroid Build Coastguard Worker   std::vector<const T*> dst;
843*d57664e9SAndroid Build Coastguard Worker   dst.reserve(src.size());
844*d57664e9SAndroid Build Coastguard Worker   for (const T& in : src) {
845*d57664e9SAndroid Build Coastguard Worker     dst.push_back(&in);
846*d57664e9SAndroid Build Coastguard Worker   }
847*d57664e9SAndroid Build Coastguard Worker   return dst;
848*d57664e9SAndroid Build Coastguard Worker }
849*d57664e9SAndroid Build Coastguard Worker 
KeyNameComparator(const Style::Entry * a,const Style::Entry * b)850*d57664e9SAndroid Build Coastguard Worker static bool KeyNameComparator(const Style::Entry* a, const Style::Entry* b) {
851*d57664e9SAndroid Build Coastguard Worker   return a->key.name < b->key.name;
852*d57664e9SAndroid Build Coastguard Worker }
853*d57664e9SAndroid Build Coastguard Worker 
Equals(const Value * value) const854*d57664e9SAndroid Build Coastguard Worker bool Style::Equals(const Value* value) const {
855*d57664e9SAndroid Build Coastguard Worker   const Style* other = ValueCast<Style>(value);
856*d57664e9SAndroid Build Coastguard Worker   if (!other) {
857*d57664e9SAndroid Build Coastguard Worker     return false;
858*d57664e9SAndroid Build Coastguard Worker   }
859*d57664e9SAndroid Build Coastguard Worker 
860*d57664e9SAndroid Build Coastguard Worker   if (bool(parent) != bool(other->parent) ||
861*d57664e9SAndroid Build Coastguard Worker       (parent && other->parent && !parent.value().Equals(&other->parent.value()))) {
862*d57664e9SAndroid Build Coastguard Worker     return false;
863*d57664e9SAndroid Build Coastguard Worker   }
864*d57664e9SAndroid Build Coastguard Worker 
865*d57664e9SAndroid Build Coastguard Worker   if (entries.size() != other->entries.size()) {
866*d57664e9SAndroid Build Coastguard Worker     return false;
867*d57664e9SAndroid Build Coastguard Worker   }
868*d57664e9SAndroid Build Coastguard Worker 
869*d57664e9SAndroid Build Coastguard Worker   std::vector<const Entry*> sorted_a = ToPointerVec(entries);
870*d57664e9SAndroid Build Coastguard Worker   std::sort(sorted_a.begin(), sorted_a.end(), KeyNameComparator);
871*d57664e9SAndroid Build Coastguard Worker 
872*d57664e9SAndroid Build Coastguard Worker   std::vector<const Entry*> sorted_b = ToPointerVec(other->entries);
873*d57664e9SAndroid Build Coastguard Worker   std::sort(sorted_b.begin(), sorted_b.end(), KeyNameComparator);
874*d57664e9SAndroid Build Coastguard Worker 
875*d57664e9SAndroid Build Coastguard Worker   return std::equal(sorted_a.begin(), sorted_a.end(), sorted_b.begin(),
876*d57664e9SAndroid Build Coastguard Worker                     [](const Entry* a, const Entry* b) -> bool {
877*d57664e9SAndroid Build Coastguard Worker                       return a->key.Equals(&b->key) && a->value->Equals(b->value.get());
878*d57664e9SAndroid Build Coastguard Worker                     });
879*d57664e9SAndroid Build Coastguard Worker }
880*d57664e9SAndroid Build Coastguard Worker 
Print(std::ostream * out) const881*d57664e9SAndroid Build Coastguard Worker void Style::Print(std::ostream* out) const {
882*d57664e9SAndroid Build Coastguard Worker   *out << "(style) ";
883*d57664e9SAndroid Build Coastguard Worker   if (parent && parent.value().name) {
884*d57664e9SAndroid Build Coastguard Worker     const Reference& parent_ref = parent.value();
885*d57664e9SAndroid Build Coastguard Worker     if (parent_ref.private_reference) {
886*d57664e9SAndroid Build Coastguard Worker       *out << "*";
887*d57664e9SAndroid Build Coastguard Worker     }
888*d57664e9SAndroid Build Coastguard Worker     *out << parent_ref.name.value();
889*d57664e9SAndroid Build Coastguard Worker   }
890*d57664e9SAndroid Build Coastguard Worker   *out << " [" << util::Joiner(entries, ", ") << "]";
891*d57664e9SAndroid Build Coastguard Worker }
892*d57664e9SAndroid Build Coastguard Worker 
CloneEntry(const Style::Entry & entry,android::StringPool * pool)893*d57664e9SAndroid Build Coastguard Worker Style::Entry CloneEntry(const Style::Entry& entry, android::StringPool* pool) {
894*d57664e9SAndroid Build Coastguard Worker   Style::Entry cloned_entry{entry.key};
895*d57664e9SAndroid Build Coastguard Worker   if (entry.value != nullptr) {
896*d57664e9SAndroid Build Coastguard Worker     CloningValueTransformer cloner(pool);
897*d57664e9SAndroid Build Coastguard Worker     cloned_entry.value = entry.value->Transform(cloner);
898*d57664e9SAndroid Build Coastguard Worker   }
899*d57664e9SAndroid Build Coastguard Worker   return cloned_entry;
900*d57664e9SAndroid Build Coastguard Worker }
901*d57664e9SAndroid Build Coastguard Worker 
MergeWith(Style * other,android::StringPool * pool)902*d57664e9SAndroid Build Coastguard Worker void Style::MergeWith(Style* other, android::StringPool* pool) {
903*d57664e9SAndroid Build Coastguard Worker   if (other->parent) {
904*d57664e9SAndroid Build Coastguard Worker     parent = other->parent;
905*d57664e9SAndroid Build Coastguard Worker   }
906*d57664e9SAndroid Build Coastguard Worker 
907*d57664e9SAndroid Build Coastguard Worker   // We can't assume that the entries are sorted alphabetically since they're supposed to be
908*d57664e9SAndroid Build Coastguard Worker   // sorted by Resource Id. Not all Resource Ids may be set though, so we can't sort and merge
909*d57664e9SAndroid Build Coastguard Worker   // them keying off that.
910*d57664e9SAndroid Build Coastguard Worker   //
911*d57664e9SAndroid Build Coastguard Worker   // Instead, sort the entries of each Style by their name in a separate structure. Then merge
912*d57664e9SAndroid Build Coastguard Worker   // those.
913*d57664e9SAndroid Build Coastguard Worker 
914*d57664e9SAndroid Build Coastguard Worker   std::vector<Entry*> this_sorted = ToPointerVec(entries);
915*d57664e9SAndroid Build Coastguard Worker   std::sort(this_sorted.begin(), this_sorted.end(), KeyNameComparator);
916*d57664e9SAndroid Build Coastguard Worker 
917*d57664e9SAndroid Build Coastguard Worker   std::vector<Entry*> other_sorted = ToPointerVec(other->entries);
918*d57664e9SAndroid Build Coastguard Worker   std::sort(other_sorted.begin(), other_sorted.end(), KeyNameComparator);
919*d57664e9SAndroid Build Coastguard Worker 
920*d57664e9SAndroid Build Coastguard Worker   auto this_iter = this_sorted.begin();
921*d57664e9SAndroid Build Coastguard Worker   const auto this_end = this_sorted.end();
922*d57664e9SAndroid Build Coastguard Worker 
923*d57664e9SAndroid Build Coastguard Worker   auto other_iter = other_sorted.begin();
924*d57664e9SAndroid Build Coastguard Worker   const auto other_end = other_sorted.end();
925*d57664e9SAndroid Build Coastguard Worker 
926*d57664e9SAndroid Build Coastguard Worker   std::vector<Entry> merged_entries;
927*d57664e9SAndroid Build Coastguard Worker   while (this_iter != this_end) {
928*d57664e9SAndroid Build Coastguard Worker     if (other_iter != other_end) {
929*d57664e9SAndroid Build Coastguard Worker       if ((*this_iter)->key.name < (*other_iter)->key.name) {
930*d57664e9SAndroid Build Coastguard Worker         merged_entries.push_back(std::move(**this_iter));
931*d57664e9SAndroid Build Coastguard Worker         ++this_iter;
932*d57664e9SAndroid Build Coastguard Worker       } else {
933*d57664e9SAndroid Build Coastguard Worker         // The other overrides.
934*d57664e9SAndroid Build Coastguard Worker         merged_entries.push_back(CloneEntry(**other_iter, pool));
935*d57664e9SAndroid Build Coastguard Worker         if ((*this_iter)->key.name == (*other_iter)->key.name) {
936*d57664e9SAndroid Build Coastguard Worker           ++this_iter;
937*d57664e9SAndroid Build Coastguard Worker         }
938*d57664e9SAndroid Build Coastguard Worker         ++other_iter;
939*d57664e9SAndroid Build Coastguard Worker       }
940*d57664e9SAndroid Build Coastguard Worker     } else {
941*d57664e9SAndroid Build Coastguard Worker       merged_entries.push_back(std::move(**this_iter));
942*d57664e9SAndroid Build Coastguard Worker       ++this_iter;
943*d57664e9SAndroid Build Coastguard Worker     }
944*d57664e9SAndroid Build Coastguard Worker   }
945*d57664e9SAndroid Build Coastguard Worker 
946*d57664e9SAndroid Build Coastguard Worker   while (other_iter != other_end) {
947*d57664e9SAndroid Build Coastguard Worker     merged_entries.push_back(CloneEntry(**other_iter, pool));
948*d57664e9SAndroid Build Coastguard Worker     ++other_iter;
949*d57664e9SAndroid Build Coastguard Worker   }
950*d57664e9SAndroid Build Coastguard Worker 
951*d57664e9SAndroid Build Coastguard Worker   entries = std::move(merged_entries);
952*d57664e9SAndroid Build Coastguard Worker }
953*d57664e9SAndroid Build Coastguard Worker 
Equals(const Value * value) const954*d57664e9SAndroid Build Coastguard Worker bool Array::Equals(const Value* value) const {
955*d57664e9SAndroid Build Coastguard Worker   const Array* other = ValueCast<Array>(value);
956*d57664e9SAndroid Build Coastguard Worker   if (!other) {
957*d57664e9SAndroid Build Coastguard Worker     return false;
958*d57664e9SAndroid Build Coastguard Worker   }
959*d57664e9SAndroid Build Coastguard Worker 
960*d57664e9SAndroid Build Coastguard Worker   if (elements.size() != other->elements.size()) {
961*d57664e9SAndroid Build Coastguard Worker     return false;
962*d57664e9SAndroid Build Coastguard Worker   }
963*d57664e9SAndroid Build Coastguard Worker 
964*d57664e9SAndroid Build Coastguard Worker   return std::equal(elements.begin(), elements.end(), other->elements.begin(),
965*d57664e9SAndroid Build Coastguard Worker                     [](const std::unique_ptr<Item>& a, const std::unique_ptr<Item>& b) -> bool {
966*d57664e9SAndroid Build Coastguard Worker                       return a->Equals(b.get());
967*d57664e9SAndroid Build Coastguard Worker                     });
968*d57664e9SAndroid Build Coastguard Worker }
969*d57664e9SAndroid Build Coastguard Worker 
Print(std::ostream * out) const970*d57664e9SAndroid Build Coastguard Worker void Array::Print(std::ostream* out) const {
971*d57664e9SAndroid Build Coastguard Worker   *out << "(array) [" << util::Joiner(elements, ", ") << "]";
972*d57664e9SAndroid Build Coastguard Worker }
973*d57664e9SAndroid Build Coastguard Worker 
RemoveFlagDisabledElements()974*d57664e9SAndroid Build Coastguard Worker void Array::RemoveFlagDisabledElements() {
975*d57664e9SAndroid Build Coastguard Worker   const auto end_iter = elements.end();
976*d57664e9SAndroid Build Coastguard Worker   const auto remove_iter = std::stable_partition(
977*d57664e9SAndroid Build Coastguard Worker       elements.begin(), end_iter, [](const std::unique_ptr<Item>& item) -> bool {
978*d57664e9SAndroid Build Coastguard Worker         return item->GetFlagStatus() != FlagStatus::Disabled;
979*d57664e9SAndroid Build Coastguard Worker       });
980*d57664e9SAndroid Build Coastguard Worker 
981*d57664e9SAndroid Build Coastguard Worker   elements.erase(remove_iter, end_iter);
982*d57664e9SAndroid Build Coastguard Worker }
983*d57664e9SAndroid Build Coastguard Worker 
Equals(const Value * value) const984*d57664e9SAndroid Build Coastguard Worker bool Plural::Equals(const Value* value) const {
985*d57664e9SAndroid Build Coastguard Worker   const Plural* other = ValueCast<Plural>(value);
986*d57664e9SAndroid Build Coastguard Worker   if (!other) {
987*d57664e9SAndroid Build Coastguard Worker     return false;
988*d57664e9SAndroid Build Coastguard Worker   }
989*d57664e9SAndroid Build Coastguard Worker 
990*d57664e9SAndroid Build Coastguard Worker   auto one_iter = values.begin();
991*d57664e9SAndroid Build Coastguard Worker   auto one_end_iter = values.end();
992*d57664e9SAndroid Build Coastguard Worker   auto two_iter = other->values.begin();
993*d57664e9SAndroid Build Coastguard Worker   for (; one_iter != one_end_iter; ++one_iter, ++two_iter) {
994*d57664e9SAndroid Build Coastguard Worker     const std::unique_ptr<Item>& a = *one_iter;
995*d57664e9SAndroid Build Coastguard Worker     const std::unique_ptr<Item>& b = *two_iter;
996*d57664e9SAndroid Build Coastguard Worker     if (a != nullptr && b != nullptr) {
997*d57664e9SAndroid Build Coastguard Worker       if (!a->Equals(b.get())) {
998*d57664e9SAndroid Build Coastguard Worker         return false;
999*d57664e9SAndroid Build Coastguard Worker       }
1000*d57664e9SAndroid Build Coastguard Worker     } else if (a != b) {
1001*d57664e9SAndroid Build Coastguard Worker       return false;
1002*d57664e9SAndroid Build Coastguard Worker     }
1003*d57664e9SAndroid Build Coastguard Worker   }
1004*d57664e9SAndroid Build Coastguard Worker   return true;
1005*d57664e9SAndroid Build Coastguard Worker }
1006*d57664e9SAndroid Build Coastguard Worker 
Print(std::ostream * out) const1007*d57664e9SAndroid Build Coastguard Worker void Plural::Print(std::ostream* out) const {
1008*d57664e9SAndroid Build Coastguard Worker   *out << "(plural)";
1009*d57664e9SAndroid Build Coastguard Worker   if (values[Zero]) {
1010*d57664e9SAndroid Build Coastguard Worker     *out << " zero=" << *values[Zero];
1011*d57664e9SAndroid Build Coastguard Worker   }
1012*d57664e9SAndroid Build Coastguard Worker 
1013*d57664e9SAndroid Build Coastguard Worker   if (values[One]) {
1014*d57664e9SAndroid Build Coastguard Worker     *out << " one=" << *values[One];
1015*d57664e9SAndroid Build Coastguard Worker   }
1016*d57664e9SAndroid Build Coastguard Worker 
1017*d57664e9SAndroid Build Coastguard Worker   if (values[Two]) {
1018*d57664e9SAndroid Build Coastguard Worker     *out << " two=" << *values[Two];
1019*d57664e9SAndroid Build Coastguard Worker   }
1020*d57664e9SAndroid Build Coastguard Worker 
1021*d57664e9SAndroid Build Coastguard Worker   if (values[Few]) {
1022*d57664e9SAndroid Build Coastguard Worker     *out << " few=" << *values[Few];
1023*d57664e9SAndroid Build Coastguard Worker   }
1024*d57664e9SAndroid Build Coastguard Worker 
1025*d57664e9SAndroid Build Coastguard Worker   if (values[Many]) {
1026*d57664e9SAndroid Build Coastguard Worker     *out << " many=" << *values[Many];
1027*d57664e9SAndroid Build Coastguard Worker   }
1028*d57664e9SAndroid Build Coastguard Worker 
1029*d57664e9SAndroid Build Coastguard Worker   if (values[Other]) {
1030*d57664e9SAndroid Build Coastguard Worker     *out << " other=" << *values[Other];
1031*d57664e9SAndroid Build Coastguard Worker   }
1032*d57664e9SAndroid Build Coastguard Worker }
1033*d57664e9SAndroid Build Coastguard Worker 
Equals(const Value * value) const1034*d57664e9SAndroid Build Coastguard Worker bool Styleable::Equals(const Value* value) const {
1035*d57664e9SAndroid Build Coastguard Worker   const Styleable* other = ValueCast<Styleable>(value);
1036*d57664e9SAndroid Build Coastguard Worker   if (!other) {
1037*d57664e9SAndroid Build Coastguard Worker     return false;
1038*d57664e9SAndroid Build Coastguard Worker   }
1039*d57664e9SAndroid Build Coastguard Worker 
1040*d57664e9SAndroid Build Coastguard Worker   if (entries.size() != other->entries.size()) {
1041*d57664e9SAndroid Build Coastguard Worker     return false;
1042*d57664e9SAndroid Build Coastguard Worker   }
1043*d57664e9SAndroid Build Coastguard Worker 
1044*d57664e9SAndroid Build Coastguard Worker   return std::equal(entries.begin(), entries.end(), other->entries.begin(),
1045*d57664e9SAndroid Build Coastguard Worker                     [](const Reference& a, const Reference& b) -> bool {
1046*d57664e9SAndroid Build Coastguard Worker                       return a.Equals(&b);
1047*d57664e9SAndroid Build Coastguard Worker                     });
1048*d57664e9SAndroid Build Coastguard Worker }
1049*d57664e9SAndroid Build Coastguard Worker 
Print(std::ostream * out) const1050*d57664e9SAndroid Build Coastguard Worker void Styleable::Print(std::ostream* out) const {
1051*d57664e9SAndroid Build Coastguard Worker   *out << "(styleable) "
1052*d57664e9SAndroid Build Coastguard Worker        << " [" << util::Joiner(entries, ", ") << "]";
1053*d57664e9SAndroid Build Coastguard Worker }
1054*d57664e9SAndroid Build Coastguard Worker 
Equals(const Value * value) const1055*d57664e9SAndroid Build Coastguard Worker bool Macro::Equals(const Value* value) const {
1056*d57664e9SAndroid Build Coastguard Worker   const Macro* other = ValueCast<Macro>(value);
1057*d57664e9SAndroid Build Coastguard Worker   if (!other) {
1058*d57664e9SAndroid Build Coastguard Worker     return false;
1059*d57664e9SAndroid Build Coastguard Worker   }
1060*d57664e9SAndroid Build Coastguard Worker   return other->raw_value == raw_value && other->style_string.spans == style_string.spans &&
1061*d57664e9SAndroid Build Coastguard Worker          other->style_string.str == style_string.str &&
1062*d57664e9SAndroid Build Coastguard Worker          other->untranslatable_sections == untranslatable_sections &&
1063*d57664e9SAndroid Build Coastguard Worker          other->alias_namespaces == alias_namespaces;
1064*d57664e9SAndroid Build Coastguard Worker }
1065*d57664e9SAndroid Build Coastguard Worker 
Print(std::ostream * out) const1066*d57664e9SAndroid Build Coastguard Worker void Macro::Print(std::ostream* out) const {
1067*d57664e9SAndroid Build Coastguard Worker   *out << "(macro) ";
1068*d57664e9SAndroid Build Coastguard Worker }
1069*d57664e9SAndroid Build Coastguard Worker 
operator <(const Reference & a,const Reference & b)1070*d57664e9SAndroid Build Coastguard Worker bool operator<(const Reference& a, const Reference& b) {
1071*d57664e9SAndroid Build Coastguard Worker   int cmp = a.name.value_or(ResourceName{}).compare(b.name.value_or(ResourceName{}));
1072*d57664e9SAndroid Build Coastguard Worker   if (cmp != 0) return cmp < 0;
1073*d57664e9SAndroid Build Coastguard Worker   return a.id < b.id;
1074*d57664e9SAndroid Build Coastguard Worker }
1075*d57664e9SAndroid Build Coastguard Worker 
operator ==(const Reference & a,const Reference & b)1076*d57664e9SAndroid Build Coastguard Worker bool operator==(const Reference& a, const Reference& b) {
1077*d57664e9SAndroid Build Coastguard Worker   return a.name == b.name && a.id == b.id;
1078*d57664e9SAndroid Build Coastguard Worker }
1079*d57664e9SAndroid Build Coastguard Worker 
operator !=(const Reference & a,const Reference & b)1080*d57664e9SAndroid Build Coastguard Worker bool operator!=(const Reference& a, const Reference& b) {
1081*d57664e9SAndroid Build Coastguard Worker   return a.name != b.name || a.id != b.id;
1082*d57664e9SAndroid Build Coastguard Worker }
1083*d57664e9SAndroid Build Coastguard Worker 
1084*d57664e9SAndroid Build Coastguard Worker struct NameOnlyComparator {
operator ()aapt::NameOnlyComparator1085*d57664e9SAndroid Build Coastguard Worker   bool operator()(const Reference& a, const Reference& b) const {
1086*d57664e9SAndroid Build Coastguard Worker     return a.name < b.name;
1087*d57664e9SAndroid Build Coastguard Worker   }
1088*d57664e9SAndroid Build Coastguard Worker };
1089*d57664e9SAndroid Build Coastguard Worker 
MergeWith(Styleable * other)1090*d57664e9SAndroid Build Coastguard Worker void Styleable::MergeWith(Styleable* other) {
1091*d57664e9SAndroid Build Coastguard Worker   // Compare only names, because some References may already have their IDs
1092*d57664e9SAndroid Build Coastguard Worker   // assigned (framework IDs that don't change).
1093*d57664e9SAndroid Build Coastguard Worker   std::set<Reference, NameOnlyComparator> references;
1094*d57664e9SAndroid Build Coastguard Worker   references.insert(entries.begin(), entries.end());
1095*d57664e9SAndroid Build Coastguard Worker   references.insert(other->entries.begin(), other->entries.end());
1096*d57664e9SAndroid Build Coastguard Worker   entries.clear();
1097*d57664e9SAndroid Build Coastguard Worker   entries.reserve(references.size());
1098*d57664e9SAndroid Build Coastguard Worker   entries.insert(entries.end(), references.begin(), references.end());
1099*d57664e9SAndroid Build Coastguard Worker }
1100*d57664e9SAndroid Build Coastguard Worker 
1101*d57664e9SAndroid Build Coastguard Worker template <typename T>
CopyValueFields(std::unique_ptr<T> new_value,const T * value)1102*d57664e9SAndroid Build Coastguard Worker std::unique_ptr<T> CopyValueFields(std::unique_ptr<T> new_value, const T* value) {
1103*d57664e9SAndroid Build Coastguard Worker   new_value->SetSource(value->GetSource());
1104*d57664e9SAndroid Build Coastguard Worker   new_value->SetComment(value->GetComment());
1105*d57664e9SAndroid Build Coastguard Worker   new_value->SetFlag(value->GetFlag());
1106*d57664e9SAndroid Build Coastguard Worker   new_value->SetFlagStatus(value->GetFlagStatus());
1107*d57664e9SAndroid Build Coastguard Worker   return new_value;
1108*d57664e9SAndroid Build Coastguard Worker }
1109*d57664e9SAndroid Build Coastguard Worker 
CloningValueTransformer(android::StringPool * new_pool)1110*d57664e9SAndroid Build Coastguard Worker CloningValueTransformer::CloningValueTransformer(android::StringPool* new_pool)
1111*d57664e9SAndroid Build Coastguard Worker     : ValueTransformer(new_pool) {
1112*d57664e9SAndroid Build Coastguard Worker }
1113*d57664e9SAndroid Build Coastguard Worker 
TransformDerived(const Reference * value)1114*d57664e9SAndroid Build Coastguard Worker std::unique_ptr<Reference> CloningValueTransformer::TransformDerived(const Reference* value) {
1115*d57664e9SAndroid Build Coastguard Worker   return std::make_unique<Reference>(*value);
1116*d57664e9SAndroid Build Coastguard Worker }
1117*d57664e9SAndroid Build Coastguard Worker 
TransformDerived(const Id * value)1118*d57664e9SAndroid Build Coastguard Worker std::unique_ptr<Id> CloningValueTransformer::TransformDerived(const Id* value) {
1119*d57664e9SAndroid Build Coastguard Worker   return std::make_unique<Id>(*value);
1120*d57664e9SAndroid Build Coastguard Worker }
1121*d57664e9SAndroid Build Coastguard Worker 
TransformDerived(const RawString * value)1122*d57664e9SAndroid Build Coastguard Worker std::unique_ptr<RawString> CloningValueTransformer::TransformDerived(const RawString* value) {
1123*d57664e9SAndroid Build Coastguard Worker   auto new_value = std::make_unique<RawString>(pool_->MakeRef(value->value));
1124*d57664e9SAndroid Build Coastguard Worker   return CopyValueFields(std::move(new_value), value);
1125*d57664e9SAndroid Build Coastguard Worker }
1126*d57664e9SAndroid Build Coastguard Worker 
TransformDerived(const String * value)1127*d57664e9SAndroid Build Coastguard Worker std::unique_ptr<String> CloningValueTransformer::TransformDerived(const String* value) {
1128*d57664e9SAndroid Build Coastguard Worker   auto new_value = std::make_unique<String>(pool_->MakeRef(value->value));
1129*d57664e9SAndroid Build Coastguard Worker   new_value->untranslatable_sections = value->untranslatable_sections;
1130*d57664e9SAndroid Build Coastguard Worker   return CopyValueFields(std::move(new_value), value);
1131*d57664e9SAndroid Build Coastguard Worker }
1132*d57664e9SAndroid Build Coastguard Worker 
TransformDerived(const StyledString * value)1133*d57664e9SAndroid Build Coastguard Worker std::unique_ptr<StyledString> CloningValueTransformer::TransformDerived(const StyledString* value) {
1134*d57664e9SAndroid Build Coastguard Worker   auto new_value = std::make_unique<StyledString>(pool_->MakeRef(value->value));
1135*d57664e9SAndroid Build Coastguard Worker   new_value->untranslatable_sections = value->untranslatable_sections;
1136*d57664e9SAndroid Build Coastguard Worker   return CopyValueFields(std::move(new_value), value);
1137*d57664e9SAndroid Build Coastguard Worker }
1138*d57664e9SAndroid Build Coastguard Worker 
TransformDerived(const FileReference * value)1139*d57664e9SAndroid Build Coastguard Worker std::unique_ptr<FileReference> CloningValueTransformer::TransformDerived(
1140*d57664e9SAndroid Build Coastguard Worker     const FileReference* value) {
1141*d57664e9SAndroid Build Coastguard Worker   auto new_value = std::make_unique<FileReference>(pool_->MakeRef(value->path));
1142*d57664e9SAndroid Build Coastguard Worker   new_value->file = value->file;
1143*d57664e9SAndroid Build Coastguard Worker   new_value->type = value->type;
1144*d57664e9SAndroid Build Coastguard Worker   return CopyValueFields(std::move(new_value), value);
1145*d57664e9SAndroid Build Coastguard Worker }
1146*d57664e9SAndroid Build Coastguard Worker 
TransformDerived(const BinaryPrimitive * value)1147*d57664e9SAndroid Build Coastguard Worker std::unique_ptr<BinaryPrimitive> CloningValueTransformer::TransformDerived(
1148*d57664e9SAndroid Build Coastguard Worker     const BinaryPrimitive* value) {
1149*d57664e9SAndroid Build Coastguard Worker   return std::make_unique<BinaryPrimitive>(*value);
1150*d57664e9SAndroid Build Coastguard Worker }
1151*d57664e9SAndroid Build Coastguard Worker 
TransformDerived(const Attribute * value)1152*d57664e9SAndroid Build Coastguard Worker std::unique_ptr<Attribute> CloningValueTransformer::TransformDerived(const Attribute* value) {
1153*d57664e9SAndroid Build Coastguard Worker   auto new_value = std::make_unique<Attribute>();
1154*d57664e9SAndroid Build Coastguard Worker   new_value->type_mask = value->type_mask;
1155*d57664e9SAndroid Build Coastguard Worker   new_value->min_int = value->min_int;
1156*d57664e9SAndroid Build Coastguard Worker   new_value->max_int = value->max_int;
1157*d57664e9SAndroid Build Coastguard Worker   for (const Attribute::Symbol& s : value->symbols) {
1158*d57664e9SAndroid Build Coastguard Worker     new_value->symbols.emplace_back(Attribute::Symbol{
1159*d57664e9SAndroid Build Coastguard Worker         .symbol = *s.symbol.Transform(*this),
1160*d57664e9SAndroid Build Coastguard Worker         .value = s.value,
1161*d57664e9SAndroid Build Coastguard Worker         .type = s.type,
1162*d57664e9SAndroid Build Coastguard Worker     });
1163*d57664e9SAndroid Build Coastguard Worker   }
1164*d57664e9SAndroid Build Coastguard Worker   return CopyValueFields(std::move(new_value), value);
1165*d57664e9SAndroid Build Coastguard Worker }
1166*d57664e9SAndroid Build Coastguard Worker 
TransformDerived(const Style * value)1167*d57664e9SAndroid Build Coastguard Worker std::unique_ptr<Style> CloningValueTransformer::TransformDerived(const Style* value) {
1168*d57664e9SAndroid Build Coastguard Worker   auto new_value = std::make_unique<Style>();
1169*d57664e9SAndroid Build Coastguard Worker   new_value->parent = value->parent;
1170*d57664e9SAndroid Build Coastguard Worker   new_value->parent_inferred = value->parent_inferred;
1171*d57664e9SAndroid Build Coastguard Worker   for (auto& entry : value->entries) {
1172*d57664e9SAndroid Build Coastguard Worker     new_value->entries.push_back(Style::Entry{entry.key, entry.value->Transform(*this)});
1173*d57664e9SAndroid Build Coastguard Worker   }
1174*d57664e9SAndroid Build Coastguard Worker   return CopyValueFields(std::move(new_value), value);
1175*d57664e9SAndroid Build Coastguard Worker }
1176*d57664e9SAndroid Build Coastguard Worker 
TransformDerived(const Array * value)1177*d57664e9SAndroid Build Coastguard Worker std::unique_ptr<Array> CloningValueTransformer::TransformDerived(const Array* value) {
1178*d57664e9SAndroid Build Coastguard Worker   auto new_value = std::make_unique<Array>();
1179*d57664e9SAndroid Build Coastguard Worker   for (auto& item : value->elements) {
1180*d57664e9SAndroid Build Coastguard Worker     new_value->elements.emplace_back(item->Transform(*this));
1181*d57664e9SAndroid Build Coastguard Worker   }
1182*d57664e9SAndroid Build Coastguard Worker   return CopyValueFields(std::move(new_value), value);
1183*d57664e9SAndroid Build Coastguard Worker }
1184*d57664e9SAndroid Build Coastguard Worker 
TransformDerived(const Plural * value)1185*d57664e9SAndroid Build Coastguard Worker std::unique_ptr<Plural> CloningValueTransformer::TransformDerived(const Plural* value) {
1186*d57664e9SAndroid Build Coastguard Worker   auto new_value = std::make_unique<Plural>();
1187*d57664e9SAndroid Build Coastguard Worker   const size_t count = value->values.size();
1188*d57664e9SAndroid Build Coastguard Worker   for (size_t i = 0; i < count; i++) {
1189*d57664e9SAndroid Build Coastguard Worker     if (value->values[i]) {
1190*d57664e9SAndroid Build Coastguard Worker       new_value->values[i] = value->values[i]->Transform(*this);
1191*d57664e9SAndroid Build Coastguard Worker     }
1192*d57664e9SAndroid Build Coastguard Worker   }
1193*d57664e9SAndroid Build Coastguard Worker   return CopyValueFields(std::move(new_value), value);
1194*d57664e9SAndroid Build Coastguard Worker }
1195*d57664e9SAndroid Build Coastguard Worker 
TransformDerived(const Styleable * value)1196*d57664e9SAndroid Build Coastguard Worker std::unique_ptr<Styleable> CloningValueTransformer::TransformDerived(const Styleable* value) {
1197*d57664e9SAndroid Build Coastguard Worker   auto new_value = std::make_unique<Styleable>();
1198*d57664e9SAndroid Build Coastguard Worker   for (const Reference& s : value->entries) {
1199*d57664e9SAndroid Build Coastguard Worker     new_value->entries.emplace_back(*s.Transform(*this));
1200*d57664e9SAndroid Build Coastguard Worker   }
1201*d57664e9SAndroid Build Coastguard Worker   return CopyValueFields(std::move(new_value), value);
1202*d57664e9SAndroid Build Coastguard Worker }
1203*d57664e9SAndroid Build Coastguard Worker 
TransformDerived(const Macro * value)1204*d57664e9SAndroid Build Coastguard Worker std::unique_ptr<Macro> CloningValueTransformer::TransformDerived(const Macro* value) {
1205*d57664e9SAndroid Build Coastguard Worker   auto new_value = std::make_unique<Macro>(*value);
1206*d57664e9SAndroid Build Coastguard Worker   return CopyValueFields(std::move(new_value), value);
1207*d57664e9SAndroid Build Coastguard Worker }
1208*d57664e9SAndroid Build Coastguard Worker 
1209*d57664e9SAndroid Build Coastguard Worker }  // namespace aapt
1210