blob: 04c375f5f97400d87120115dbccfdd41c3483a6a [file] [log] [blame]
Adam Lesinski6f6ceb72014-11-14 14:48:12 -08001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "Resource.h"
Adam Lesinskia5870652015-11-20 15:32:30 -080018#include "ResourceUtils.h"
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080019#include "ResourceValues.h"
Adam Lesinski1ab598f2015-08-14 14:26:04 -070020#include "ValueVisitor.h"
Adam Lesinskie78fd612015-10-22 12:48:43 -070021#include "util/Util.h"
22#include "flatten/ResourceTypeExtensions.h"
23
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080024#include <androidfw/ResourceTypes.h>
25#include <limits>
26
27namespace aapt {
28
Adam Lesinski1ab598f2015-08-14 14:26:04 -070029template <typename Derived>
30void BaseValue<Derived>::accept(RawValueVisitor* visitor) {
31 visitor->visit(static_cast<Derived*>(this));
32}
33
34template <typename Derived>
35void BaseItem<Derived>::accept(RawValueVisitor* visitor) {
36 visitor->visit(static_cast<Derived*>(this));
37}
38
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080039bool Value::isWeak() const {
40 return false;
41}
42
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080043RawString::RawString(const StringPool::Ref& ref) : value(ref) {
44}
45
Adam Lesinski769de982015-04-10 19:43:55 -070046RawString* RawString::clone(StringPool* newPool) const {
Adam Lesinskib274e352015-11-06 15:14:35 -080047 RawString* rs = new RawString(newPool->makeRef(*value));
48 rs->mComment = mComment;
49 rs->mSource = mSource;
50 return rs;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080051}
52
Adam Lesinski1ab598f2015-08-14 14:26:04 -070053bool RawString::flatten(android::Res_value* outValue) const {
54 outValue->dataType = ExtendedTypes::TYPE_RAW_STRING;
55 outValue->data = util::hostToDevice32(static_cast<uint32_t>(value.getIndex()));
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080056 return true;
57}
58
Adam Lesinski1ab598f2015-08-14 14:26:04 -070059void RawString::print(std::ostream* out) const {
60 *out << "(raw string) " << *value;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080061}
62
63Reference::Reference() : referenceType(Reference::Type::kResource) {
64}
65
66Reference::Reference(const ResourceNameRef& n, Type t) :
67 name(n.toResourceName()), referenceType(t) {
68}
69
70Reference::Reference(const ResourceId& i, Type type) : id(i), referenceType(type) {
71}
72
Adam Lesinski1ab598f2015-08-14 14:26:04 -070073bool Reference::flatten(android::Res_value* outValue) const {
Adam Lesinski467f1712015-11-16 17:35:44 -080074 outValue->dataType = (referenceType == Reference::Type::kResource) ?
75 android::Res_value::TYPE_REFERENCE : android::Res_value::TYPE_ATTRIBUTE;
Adam Lesinski1ab598f2015-08-14 14:26:04 -070076 outValue->data = util::hostToDevice32(id ? id.value().id : 0);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080077 return true;
78}
79
Adam Lesinski769de982015-04-10 19:43:55 -070080Reference* Reference::clone(StringPool* /*newPool*/) const {
Adam Lesinski467f1712015-11-16 17:35:44 -080081 return new Reference(*this);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080082}
83
Adam Lesinski1ab598f2015-08-14 14:26:04 -070084void Reference::print(std::ostream* out) const {
85 *out << "(reference) ";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080086 if (referenceType == Reference::Type::kResource) {
Adam Lesinski1ab598f2015-08-14 14:26:04 -070087 *out << "@";
Adam Lesinski467f1712015-11-16 17:35:44 -080088 if (privateReference) {
89 *out << "*";
90 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080091 } else {
Adam Lesinski1ab598f2015-08-14 14:26:04 -070092 *out << "?";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080093 }
94
Adam Lesinski1ab598f2015-08-14 14:26:04 -070095 if (name) {
96 *out << name.value();
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080097 }
98
Adam Lesinski1ab598f2015-08-14 14:26:04 -070099 if (id && !Res_INTERNALID(id.value().id)) {
100 *out << " " << id.value();
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800101 }
102}
103
104bool Id::isWeak() const {
105 return true;
106}
107
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700108bool Id::flatten(android::Res_value* out) const {
109 out->dataType = android::Res_value::TYPE_INT_BOOLEAN;
110 out->data = util::hostToDevice32(0);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800111 return true;
112}
113
Adam Lesinski769de982015-04-10 19:43:55 -0700114Id* Id::clone(StringPool* /*newPool*/) const {
Adam Lesinski467f1712015-11-16 17:35:44 -0800115 return new Id(*this);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800116}
117
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700118void Id::print(std::ostream* out) const {
119 *out << "(id)";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800120}
121
122String::String(const StringPool::Ref& ref) : value(ref) {
123}
124
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700125bool String::flatten(android::Res_value* outValue) const {
126 // Verify that our StringPool index is within encode-able limits.
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800127 if (value.getIndex() > std::numeric_limits<uint32_t>::max()) {
128 return false;
129 }
130
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700131 outValue->dataType = android::Res_value::TYPE_STRING;
132 outValue->data = util::hostToDevice32(static_cast<uint32_t>(value.getIndex()));
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800133 return true;
134}
135
Adam Lesinski769de982015-04-10 19:43:55 -0700136String* String::clone(StringPool* newPool) const {
Adam Lesinskib274e352015-11-06 15:14:35 -0800137 String* str = new String(newPool->makeRef(*value));
138 str->mComment = mComment;
139 str->mSource = mSource;
140 return str;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800141}
142
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700143void String::print(std::ostream* out) const {
144 *out << "(string) \"" << *value << "\"";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800145}
146
147StyledString::StyledString(const StringPool::StyleRef& ref) : value(ref) {
148}
149
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700150bool StyledString::flatten(android::Res_value* outValue) const {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800151 if (value.getIndex() > std::numeric_limits<uint32_t>::max()) {
152 return false;
153 }
154
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700155 outValue->dataType = android::Res_value::TYPE_STRING;
156 outValue->data = util::hostToDevice32(static_cast<uint32_t>(value.getIndex()));
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800157 return true;
158}
159
Adam Lesinski769de982015-04-10 19:43:55 -0700160StyledString* StyledString::clone(StringPool* newPool) const {
Adam Lesinskib274e352015-11-06 15:14:35 -0800161 StyledString* str = new StyledString(newPool->makeRef(value));
162 str->mComment = mComment;
163 str->mSource = mSource;
164 return str;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800165}
166
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700167void StyledString::print(std::ostream* out) const {
168 *out << "(styled string) \"" << *value->str << "\"";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800169}
170
171FileReference::FileReference(const StringPool::Ref& _path) : path(_path) {
172}
173
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700174bool FileReference::flatten(android::Res_value* outValue) const {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800175 if (path.getIndex() > std::numeric_limits<uint32_t>::max()) {
176 return false;
177 }
178
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700179 outValue->dataType = android::Res_value::TYPE_STRING;
180 outValue->data = util::hostToDevice32(static_cast<uint32_t>(path.getIndex()));
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800181 return true;
182}
183
Adam Lesinski769de982015-04-10 19:43:55 -0700184FileReference* FileReference::clone(StringPool* newPool) const {
Adam Lesinskib274e352015-11-06 15:14:35 -0800185 FileReference* fr = new FileReference(newPool->makeRef(*path));
186 fr->mComment = mComment;
187 fr->mSource = mSource;
188 return fr;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800189}
190
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700191void FileReference::print(std::ostream* out) const {
192 *out << "(file) " << *path;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800193}
194
195BinaryPrimitive::BinaryPrimitive(const android::Res_value& val) : value(val) {
196}
197
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700198BinaryPrimitive::BinaryPrimitive(uint8_t dataType, uint32_t data) {
199 value.dataType = dataType;
200 value.data = data;
201}
202
203bool BinaryPrimitive::flatten(android::Res_value* outValue) const {
204 outValue->dataType = value.dataType;
205 outValue->data = util::hostToDevice32(value.data);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800206 return true;
207}
208
Adam Lesinski769de982015-04-10 19:43:55 -0700209BinaryPrimitive* BinaryPrimitive::clone(StringPool* /*newPool*/) const {
Adam Lesinski467f1712015-11-16 17:35:44 -0800210 return new BinaryPrimitive(*this);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800211}
212
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700213void BinaryPrimitive::print(std::ostream* out) const {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800214 switch (value.dataType) {
215 case android::Res_value::TYPE_NULL:
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700216 *out << "(null)";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800217 break;
218 case android::Res_value::TYPE_INT_DEC:
Adam Lesinskia5870652015-11-20 15:32:30 -0800219 *out << "(integer) " << static_cast<int32_t>(value.data);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800220 break;
221 case android::Res_value::TYPE_INT_HEX:
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700222 *out << "(integer) " << std::hex << value.data << std::dec;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800223 break;
224 case android::Res_value::TYPE_INT_BOOLEAN:
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700225 *out << "(boolean) " << (value.data != 0 ? "true" : "false");
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800226 break;
227 case android::Res_value::TYPE_INT_COLOR_ARGB8:
228 case android::Res_value::TYPE_INT_COLOR_RGB8:
229 case android::Res_value::TYPE_INT_COLOR_ARGB4:
230 case android::Res_value::TYPE_INT_COLOR_RGB4:
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700231 *out << "(color) #" << std::hex << value.data << std::dec;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800232 break;
233 default:
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700234 *out << "(unknown 0x" << std::hex << (int) value.dataType << ") 0x"
235 << std::hex << value.data << std::dec;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800236 break;
237 }
238}
239
Adam Lesinskia5870652015-11-20 15:32:30 -0800240Attribute::Attribute(bool w, uint32_t t) :
241 weak(w), typeMask(t),
242 minInt(std::numeric_limits<int32_t>::min()),
243 maxInt(std::numeric_limits<int32_t>::max()) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800244}
245
246bool Attribute::isWeak() const {
247 return weak;
248}
249
Adam Lesinski769de982015-04-10 19:43:55 -0700250Attribute* Attribute::clone(StringPool* /*newPool*/) const {
Adam Lesinski467f1712015-11-16 17:35:44 -0800251 return new Attribute(*this);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800252}
253
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700254void Attribute::printMask(std::ostream* out) const {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800255 if (typeMask == android::ResTable_map::TYPE_ANY) {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700256 *out << "any";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800257 return;
258 }
259
260 bool set = false;
261 if ((typeMask & android::ResTable_map::TYPE_REFERENCE) != 0) {
262 if (!set) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800263 set = true;
264 } else {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700265 *out << "|";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800266 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700267 *out << "reference";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800268 }
269
270 if ((typeMask & android::ResTable_map::TYPE_STRING) != 0) {
271 if (!set) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800272 set = true;
273 } else {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700274 *out << "|";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800275 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700276 *out << "string";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800277 }
278
279 if ((typeMask & android::ResTable_map::TYPE_INTEGER) != 0) {
280 if (!set) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800281 set = true;
282 } else {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700283 *out << "|";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800284 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700285 *out << "integer";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800286 }
287
288 if ((typeMask & android::ResTable_map::TYPE_BOOLEAN) != 0) {
289 if (!set) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800290 set = true;
291 } else {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700292 *out << "|";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800293 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700294 *out << "boolean";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800295 }
296
297 if ((typeMask & android::ResTable_map::TYPE_COLOR) != 0) {
298 if (!set) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800299 set = true;
300 } else {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700301 *out << "|";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800302 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700303 *out << "color";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800304 }
305
306 if ((typeMask & android::ResTable_map::TYPE_FLOAT) != 0) {
307 if (!set) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800308 set = true;
309 } else {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700310 *out << "|";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800311 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700312 *out << "float";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800313 }
314
315 if ((typeMask & android::ResTable_map::TYPE_DIMENSION) != 0) {
316 if (!set) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800317 set = true;
318 } else {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700319 *out << "|";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800320 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700321 *out << "dimension";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800322 }
323
324 if ((typeMask & android::ResTable_map::TYPE_FRACTION) != 0) {
325 if (!set) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800326 set = true;
327 } else {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700328 *out << "|";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800329 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700330 *out << "fraction";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800331 }
332
333 if ((typeMask & android::ResTable_map::TYPE_ENUM) != 0) {
334 if (!set) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800335 set = true;
336 } else {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700337 *out << "|";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800338 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700339 *out << "enum";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800340 }
341
342 if ((typeMask & android::ResTable_map::TYPE_FLAGS) != 0) {
343 if (!set) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800344 set = true;
345 } else {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700346 *out << "|";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800347 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700348 *out << "flags";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800349 }
Adam Lesinski330edcd2015-05-04 17:40:56 -0700350}
351
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700352void Attribute::print(std::ostream* out) const {
353 *out << "(attr) ";
Adam Lesinski330edcd2015-05-04 17:40:56 -0700354 printMask(out);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800355
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700356 if (!symbols.empty()) {
357 *out << " ["
358 << util::joiner(symbols.begin(), symbols.end(), ", ")
359 << "]";
360 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800361
362 if (weak) {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700363 *out << " [weak]";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800364 }
365}
366
Adam Lesinskia5870652015-11-20 15:32:30 -0800367static void buildAttributeMismatchMessage(DiagMessage* msg, const Attribute* attr,
368 const Item* value) {
369 *msg << "expected";
370 if (attr->typeMask & android::ResTable_map::TYPE_BOOLEAN) {
371 *msg << " boolean";
372 }
373
374 if (attr->typeMask & android::ResTable_map::TYPE_COLOR) {
375 *msg << " color";
376 }
377
378 if (attr->typeMask & android::ResTable_map::TYPE_DIMENSION) {
379 *msg << " dimension";
380 }
381
382 if (attr->typeMask & android::ResTable_map::TYPE_ENUM) {
383 *msg << " enum";
384 }
385
386 if (attr->typeMask & android::ResTable_map::TYPE_FLAGS) {
387 *msg << " flags";
388 }
389
390 if (attr->typeMask & android::ResTable_map::TYPE_FLOAT) {
391 *msg << " float";
392 }
393
394 if (attr->typeMask & android::ResTable_map::TYPE_FRACTION) {
395 *msg << " fraction";
396 }
397
398 if (attr->typeMask & android::ResTable_map::TYPE_INTEGER) {
399 *msg << " integer";
400 }
401
402 if (attr->typeMask & android::ResTable_map::TYPE_REFERENCE) {
403 *msg << " reference";
404 }
405
406 if (attr->typeMask & android::ResTable_map::TYPE_STRING) {
407 *msg << " string";
408 }
409
410 *msg << " but got " << *value;
411}
412
413bool Attribute::matches(const Item* item, DiagMessage* outMsg) const {
414 android::Res_value val = {};
415 item->flatten(&val);
416
417 // Always allow references.
418 const uint32_t mask = typeMask | android::ResTable_map::TYPE_REFERENCE;
419 if (!(mask & ResourceUtils::androidTypeToAttributeTypeMask(val.dataType))) {
420 if (outMsg) {
421 buildAttributeMismatchMessage(outMsg, this, item);
422 }
423 return false;
424
425 } else if (ResourceUtils::androidTypeToAttributeTypeMask(val.dataType) &
426 android::ResTable_map::TYPE_INTEGER) {
427 if (static_cast<int32_t>(util::deviceToHost32(val.data)) < minInt) {
428 if (outMsg) {
429 *outMsg << *item << " is less than minimum integer " << minInt;
430 }
431 return false;
432 } else if (static_cast<int32_t>(util::deviceToHost32(val.data)) > maxInt) {
433 if (outMsg) {
434 *outMsg << *item << " is greater than maximum integer " << maxInt;
435 }
436 return false;
437 }
438 }
439 return true;
440}
441
Adam Lesinski769de982015-04-10 19:43:55 -0700442Style* Style::clone(StringPool* newPool) const {
Adam Lesinskibdaa0922015-05-08 20:16:23 -0700443 Style* style = new Style();
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800444 style->parent = parent;
Adam Lesinskibdaa0922015-05-08 20:16:23 -0700445 style->parentInferred = parentInferred;
Adam Lesinskib274e352015-11-06 15:14:35 -0800446 style->mComment = mComment;
447 style->mSource = mSource;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800448 for (auto& entry : entries) {
449 style->entries.push_back(Entry{
450 entry.key,
Adam Lesinski769de982015-04-10 19:43:55 -0700451 std::unique_ptr<Item>(entry.value->clone(newPool))
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800452 });
453 }
454 return style;
455}
456
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700457void Style::print(std::ostream* out) const {
458 *out << "(style) ";
459 if (parent && parent.value().name) {
460 *out << parent.value().name.value();
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800461 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700462 *out << " ["
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800463 << util::joiner(entries.begin(), entries.end(), ", ")
464 << "]";
465}
466
467static ::std::ostream& operator<<(::std::ostream& out, const Style::Entry& value) {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700468 if (value.key.name) {
469 out << value.key.name.value();
470 } else {
471 out << "???";
472 }
473 out << " = ";
474 value.value->print(&out);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800475 return out;
476}
477
Adam Lesinski769de982015-04-10 19:43:55 -0700478Array* Array::clone(StringPool* newPool) const {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800479 Array* array = new Array();
Adam Lesinskib274e352015-11-06 15:14:35 -0800480 array->mComment = mComment;
481 array->mSource = mSource;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800482 for (auto& item : items) {
Adam Lesinski769de982015-04-10 19:43:55 -0700483 array->items.emplace_back(std::unique_ptr<Item>(item->clone(newPool)));
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800484 }
485 return array;
486}
487
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700488void Array::print(std::ostream* out) const {
489 *out << "(array) ["
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800490 << util::joiner(items.begin(), items.end(), ", ")
491 << "]";
492}
493
Adam Lesinski769de982015-04-10 19:43:55 -0700494Plural* Plural::clone(StringPool* newPool) const {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800495 Plural* p = new Plural();
Adam Lesinskib274e352015-11-06 15:14:35 -0800496 p->mComment = mComment;
497 p->mSource = mSource;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800498 const size_t count = values.size();
499 for (size_t i = 0; i < count; i++) {
500 if (values[i]) {
Adam Lesinski769de982015-04-10 19:43:55 -0700501 p->values[i] = std::unique_ptr<Item>(values[i]->clone(newPool));
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800502 }
503 }
504 return p;
505}
506
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700507void Plural::print(std::ostream* out) const {
508 *out << "(plural)";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800509}
510
511static ::std::ostream& operator<<(::std::ostream& out, const std::unique_ptr<Item>& item) {
512 return out << *item;
513}
514
Adam Lesinski769de982015-04-10 19:43:55 -0700515Styleable* Styleable::clone(StringPool* /*newPool*/) const {
Adam Lesinski467f1712015-11-16 17:35:44 -0800516 return new Styleable(*this);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800517}
518
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700519void Styleable::print(std::ostream* out) const {
520 *out << "(styleable) " << " ["
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800521 << util::joiner(entries.begin(), entries.end(), ", ")
522 << "]";
523}
524
525} // namespace aapt