blob: 5550f192d51af71b96bb853ddb3043f0f51ba3bb [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 Lesinski6f6ceb72014-11-14 14:48:12 -080018#include "ResourceValues.h"
Adam Lesinski1ab598f2015-08-14 14:26:04 -070019#include "ValueVisitor.h"
Adam Lesinski6f6ceb72014-11-14 14:48:12 -080020
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 Lesinski1ab598f2015-08-14 14:26:04 -0700219 *out << "(integer) " << 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 Lesinski6f6ceb72014-11-14 14:48:12 -0800240Attribute::Attribute(bool w, uint32_t t) : weak(w), typeMask(t) {
241}
242
243bool Attribute::isWeak() const {
244 return weak;
245}
246
Adam Lesinski769de982015-04-10 19:43:55 -0700247Attribute* Attribute::clone(StringPool* /*newPool*/) const {
Adam Lesinski467f1712015-11-16 17:35:44 -0800248 return new Attribute(*this);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800249}
250
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700251void Attribute::printMask(std::ostream* out) const {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800252 if (typeMask == android::ResTable_map::TYPE_ANY) {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700253 *out << "any";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800254 return;
255 }
256
257 bool set = false;
258 if ((typeMask & android::ResTable_map::TYPE_REFERENCE) != 0) {
259 if (!set) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800260 set = true;
261 } else {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700262 *out << "|";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800263 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700264 *out << "reference";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800265 }
266
267 if ((typeMask & android::ResTable_map::TYPE_STRING) != 0) {
268 if (!set) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800269 set = true;
270 } else {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700271 *out << "|";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800272 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700273 *out << "string";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800274 }
275
276 if ((typeMask & android::ResTable_map::TYPE_INTEGER) != 0) {
277 if (!set) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800278 set = true;
279 } else {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700280 *out << "|";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800281 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700282 *out << "integer";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800283 }
284
285 if ((typeMask & android::ResTable_map::TYPE_BOOLEAN) != 0) {
286 if (!set) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800287 set = true;
288 } else {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700289 *out << "|";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800290 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700291 *out << "boolean";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800292 }
293
294 if ((typeMask & android::ResTable_map::TYPE_COLOR) != 0) {
295 if (!set) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800296 set = true;
297 } else {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700298 *out << "|";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800299 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700300 *out << "color";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800301 }
302
303 if ((typeMask & android::ResTable_map::TYPE_FLOAT) != 0) {
304 if (!set) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800305 set = true;
306 } else {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700307 *out << "|";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800308 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700309 *out << "float";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800310 }
311
312 if ((typeMask & android::ResTable_map::TYPE_DIMENSION) != 0) {
313 if (!set) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800314 set = true;
315 } else {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700316 *out << "|";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800317 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700318 *out << "dimension";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800319 }
320
321 if ((typeMask & android::ResTable_map::TYPE_FRACTION) != 0) {
322 if (!set) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800323 set = true;
324 } else {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700325 *out << "|";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800326 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700327 *out << "fraction";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800328 }
329
330 if ((typeMask & android::ResTable_map::TYPE_ENUM) != 0) {
331 if (!set) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800332 set = true;
333 } else {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700334 *out << "|";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800335 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700336 *out << "enum";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800337 }
338
339 if ((typeMask & android::ResTable_map::TYPE_FLAGS) != 0) {
340 if (!set) {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800341 set = true;
342 } else {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700343 *out << "|";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800344 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700345 *out << "flags";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800346 }
Adam Lesinski330edcd2015-05-04 17:40:56 -0700347}
348
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700349void Attribute::print(std::ostream* out) const {
350 *out << "(attr) ";
Adam Lesinski330edcd2015-05-04 17:40:56 -0700351 printMask(out);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800352
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700353 if (!symbols.empty()) {
354 *out << " ["
355 << util::joiner(symbols.begin(), symbols.end(), ", ")
356 << "]";
357 }
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800358
359 if (weak) {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700360 *out << " [weak]";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800361 }
362}
363
Adam Lesinski769de982015-04-10 19:43:55 -0700364Style* Style::clone(StringPool* newPool) const {
Adam Lesinskibdaa0922015-05-08 20:16:23 -0700365 Style* style = new Style();
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800366 style->parent = parent;
Adam Lesinskibdaa0922015-05-08 20:16:23 -0700367 style->parentInferred = parentInferred;
Adam Lesinskib274e352015-11-06 15:14:35 -0800368 style->mComment = mComment;
369 style->mSource = mSource;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800370 for (auto& entry : entries) {
371 style->entries.push_back(Entry{
372 entry.key,
Adam Lesinski769de982015-04-10 19:43:55 -0700373 std::unique_ptr<Item>(entry.value->clone(newPool))
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800374 });
375 }
376 return style;
377}
378
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700379void Style::print(std::ostream* out) const {
380 *out << "(style) ";
381 if (parent && parent.value().name) {
382 *out << parent.value().name.value();
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800383 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700384 *out << " ["
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800385 << util::joiner(entries.begin(), entries.end(), ", ")
386 << "]";
387}
388
389static ::std::ostream& operator<<(::std::ostream& out, const Style::Entry& value) {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700390 if (value.key.name) {
391 out << value.key.name.value();
392 } else {
393 out << "???";
394 }
395 out << " = ";
396 value.value->print(&out);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800397 return out;
398}
399
Adam Lesinski769de982015-04-10 19:43:55 -0700400Array* Array::clone(StringPool* newPool) const {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800401 Array* array = new Array();
Adam Lesinskib274e352015-11-06 15:14:35 -0800402 array->mComment = mComment;
403 array->mSource = mSource;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800404 for (auto& item : items) {
Adam Lesinski769de982015-04-10 19:43:55 -0700405 array->items.emplace_back(std::unique_ptr<Item>(item->clone(newPool)));
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800406 }
407 return array;
408}
409
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700410void Array::print(std::ostream* out) const {
411 *out << "(array) ["
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800412 << util::joiner(items.begin(), items.end(), ", ")
413 << "]";
414}
415
Adam Lesinski769de982015-04-10 19:43:55 -0700416Plural* Plural::clone(StringPool* newPool) const {
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800417 Plural* p = new Plural();
Adam Lesinskib274e352015-11-06 15:14:35 -0800418 p->mComment = mComment;
419 p->mSource = mSource;
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800420 const size_t count = values.size();
421 for (size_t i = 0; i < count; i++) {
422 if (values[i]) {
Adam Lesinski769de982015-04-10 19:43:55 -0700423 p->values[i] = std::unique_ptr<Item>(values[i]->clone(newPool));
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800424 }
425 }
426 return p;
427}
428
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700429void Plural::print(std::ostream* out) const {
430 *out << "(plural)";
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800431}
432
433static ::std::ostream& operator<<(::std::ostream& out, const std::unique_ptr<Item>& item) {
434 return out << *item;
435}
436
Adam Lesinski769de982015-04-10 19:43:55 -0700437Styleable* Styleable::clone(StringPool* /*newPool*/) const {
Adam Lesinski467f1712015-11-16 17:35:44 -0800438 return new Styleable(*this);
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800439}
440
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700441void Styleable::print(std::ostream* out) const {
442 *out << "(styleable) " << " ["
Adam Lesinski6f6ceb72014-11-14 14:48:12 -0800443 << util::joiner(entries.begin(), entries.end(), ", ")
444 << "]";
445}
446
447} // namespace aapt