1/* 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" 18#include "ResourceTypeExtensions.h" 19#include "ResourceValues.h" 20#include "Util.h" 21 22#include <androidfw/ResourceTypes.h> 23#include <limits> 24 25namespace aapt { 26 27bool Value::isItem() const { 28 return false; 29} 30 31bool Value::isWeak() const { 32 return false; 33} 34 35bool Item::isItem() const { 36 return true; 37} 38 39RawString::RawString(const StringPool::Ref& ref) : value(ref) { 40} 41 42RawString* RawString::clone(StringPool* newPool) const { 43 return new RawString(newPool->makeRef(*value)); 44} 45 46bool RawString::flatten(android::Res_value& outValue) const { 47 outValue.dataType = ExtendedTypes::TYPE_RAW_STRING; 48 outValue.data = static_cast<uint32_t>(value.getIndex()); 49 return true; 50} 51 52void RawString::print(std::ostream& out) const { 53 out << "(raw string) " << *value; 54} 55 56Reference::Reference() : referenceType(Reference::Type::kResource) { 57} 58 59Reference::Reference(const ResourceNameRef& n, Type t) : 60 name(n.toResourceName()), referenceType(t) { 61} 62 63Reference::Reference(const ResourceId& i, Type type) : id(i), referenceType(type) { 64} 65 66bool Reference::flatten(android::Res_value& outValue) const { 67 outValue.dataType = (referenceType == Reference::Type::kResource) 68 ? android::Res_value::TYPE_REFERENCE 69 : android::Res_value::TYPE_ATTRIBUTE; 70 outValue.data = id.id; 71 return true; 72} 73 74Reference* Reference::clone(StringPool* /*newPool*/) const { 75 Reference* ref = new Reference(); 76 ref->referenceType = referenceType; 77 ref->name = name; 78 ref->id = id; 79 return ref; 80} 81 82void Reference::print(std::ostream& out) const { 83 out << "(reference) "; 84 if (referenceType == Reference::Type::kResource) { 85 out << "@"; 86 } else { 87 out << "?"; 88 } 89 90 if (name.isValid()) { 91 out << name; 92 } 93 94 if (id.isValid() || Res_INTERNALID(id.id)) { 95 out << " " << id; 96 } 97} 98 99bool Id::isWeak() const { 100 return true; 101} 102 103bool Id::flatten(android::Res_value& out) const { 104 out.dataType = android::Res_value::TYPE_INT_BOOLEAN; 105 out.data = 0; 106 return true; 107} 108 109Id* Id::clone(StringPool* /*newPool*/) const { 110 return new Id(); 111} 112 113void Id::print(std::ostream& out) const { 114 out << "(id)"; 115} 116 117String::String(const StringPool::Ref& ref) : value(ref) { 118} 119 120bool String::flatten(android::Res_value& outValue) const { 121 // Verify that our StringPool index is within encodeable limits. 122 if (value.getIndex() > std::numeric_limits<uint32_t>::max()) { 123 return false; 124 } 125 126 outValue.dataType = android::Res_value::TYPE_STRING; 127 outValue.data = static_cast<uint32_t>(value.getIndex()); 128 return true; 129} 130 131String* String::clone(StringPool* newPool) const { 132 return new String(newPool->makeRef(*value)); 133} 134 135void String::print(std::ostream& out) const { 136 out << "(string) \"" << *value << "\""; 137} 138 139StyledString::StyledString(const StringPool::StyleRef& ref) : value(ref) { 140} 141 142bool StyledString::flatten(android::Res_value& outValue) const { 143 if (value.getIndex() > std::numeric_limits<uint32_t>::max()) { 144 return false; 145 } 146 147 outValue.dataType = android::Res_value::TYPE_STRING; 148 outValue.data = static_cast<uint32_t>(value.getIndex()); 149 return true; 150} 151 152StyledString* StyledString::clone(StringPool* newPool) const { 153 return new StyledString(newPool->makeRef(value)); 154} 155 156void StyledString::print(std::ostream& out) const { 157 out << "(styled string) \"" << *value->str << "\""; 158} 159 160FileReference::FileReference(const StringPool::Ref& _path) : path(_path) { 161} 162 163bool FileReference::flatten(android::Res_value& outValue) const { 164 if (path.getIndex() > std::numeric_limits<uint32_t>::max()) { 165 return false; 166 } 167 168 outValue.dataType = android::Res_value::TYPE_STRING; 169 outValue.data = static_cast<uint32_t>(path.getIndex()); 170 return true; 171} 172 173FileReference* FileReference::clone(StringPool* newPool) const { 174 return new FileReference(newPool->makeRef(*path)); 175} 176 177void FileReference::print(std::ostream& out) const { 178 out << "(file) " << *path; 179} 180 181BinaryPrimitive::BinaryPrimitive(const android::Res_value& val) : value(val) { 182} 183 184bool BinaryPrimitive::flatten(android::Res_value& outValue) const { 185 outValue = value; 186 return true; 187} 188 189BinaryPrimitive* BinaryPrimitive::clone(StringPool* /*newPool*/) const { 190 return new BinaryPrimitive(value); 191} 192 193void BinaryPrimitive::print(std::ostream& out) const { 194 switch (value.dataType) { 195 case android::Res_value::TYPE_NULL: 196 out << "(null)"; 197 break; 198 case android::Res_value::TYPE_INT_DEC: 199 out << "(integer) " << value.data; 200 break; 201 case android::Res_value::TYPE_INT_HEX: 202 out << "(integer) " << std::hex << value.data << std::dec; 203 break; 204 case android::Res_value::TYPE_INT_BOOLEAN: 205 out << "(boolean) " << (value.data != 0 ? "true" : "false"); 206 break; 207 case android::Res_value::TYPE_INT_COLOR_ARGB8: 208 case android::Res_value::TYPE_INT_COLOR_RGB8: 209 case android::Res_value::TYPE_INT_COLOR_ARGB4: 210 case android::Res_value::TYPE_INT_COLOR_RGB4: 211 out << "(color) #" << std::hex << value.data << std::dec; 212 break; 213 default: 214 out << "(unknown 0x" << std::hex << (int) value.dataType << ") 0x" 215 << std::hex << value.data << std::dec; 216 break; 217 } 218} 219 220Attribute::Attribute(bool w, uint32_t t) : weak(w), typeMask(t) { 221} 222 223bool Attribute::isWeak() const { 224 return weak; 225} 226 227Attribute* Attribute::clone(StringPool* /*newPool*/) const { 228 Attribute* attr = new Attribute(weak); 229 attr->typeMask = typeMask; 230 std::copy(symbols.begin(), symbols.end(), std::back_inserter(attr->symbols)); 231 return attr; 232} 233 234void Attribute::printMask(std::ostream& out) const { 235 if (typeMask == android::ResTable_map::TYPE_ANY) { 236 out << "any"; 237 return; 238 } 239 240 bool set = false; 241 if ((typeMask & android::ResTable_map::TYPE_REFERENCE) != 0) { 242 if (!set) { 243 set = true; 244 } else { 245 out << "|"; 246 } 247 out << "reference"; 248 } 249 250 if ((typeMask & android::ResTable_map::TYPE_STRING) != 0) { 251 if (!set) { 252 set = true; 253 } else { 254 out << "|"; 255 } 256 out << "string"; 257 } 258 259 if ((typeMask & android::ResTable_map::TYPE_INTEGER) != 0) { 260 if (!set) { 261 set = true; 262 } else { 263 out << "|"; 264 } 265 out << "integer"; 266 } 267 268 if ((typeMask & android::ResTable_map::TYPE_BOOLEAN) != 0) { 269 if (!set) { 270 set = true; 271 } else { 272 out << "|"; 273 } 274 out << "boolean"; 275 } 276 277 if ((typeMask & android::ResTable_map::TYPE_COLOR) != 0) { 278 if (!set) { 279 set = true; 280 } else { 281 out << "|"; 282 } 283 out << "color"; 284 } 285 286 if ((typeMask & android::ResTable_map::TYPE_FLOAT) != 0) { 287 if (!set) { 288 set = true; 289 } else { 290 out << "|"; 291 } 292 out << "float"; 293 } 294 295 if ((typeMask & android::ResTable_map::TYPE_DIMENSION) != 0) { 296 if (!set) { 297 set = true; 298 } else { 299 out << "|"; 300 } 301 out << "dimension"; 302 } 303 304 if ((typeMask & android::ResTable_map::TYPE_FRACTION) != 0) { 305 if (!set) { 306 set = true; 307 } else { 308 out << "|"; 309 } 310 out << "fraction"; 311 } 312 313 if ((typeMask & android::ResTable_map::TYPE_ENUM) != 0) { 314 if (!set) { 315 set = true; 316 } else { 317 out << "|"; 318 } 319 out << "enum"; 320 } 321 322 if ((typeMask & android::ResTable_map::TYPE_FLAGS) != 0) { 323 if (!set) { 324 set = true; 325 } else { 326 out << "|"; 327 } 328 out << "flags"; 329 } 330} 331 332void Attribute::print(std::ostream& out) const { 333 out << "(attr) "; 334 printMask(out); 335 336 out << " [" 337 << util::joiner(symbols.begin(), symbols.end(), ", ") 338 << "]"; 339 340 if (weak) { 341 out << " [weak]"; 342 } 343} 344 345Style* Style::clone(StringPool* newPool) const { 346 Style* style = new Style(); 347 style->parent = parent; 348 style->parentInferred = parentInferred; 349 for (auto& entry : entries) { 350 style->entries.push_back(Entry{ 351 entry.key, 352 std::unique_ptr<Item>(entry.value->clone(newPool)) 353 }); 354 } 355 return style; 356} 357 358void Style::print(std::ostream& out) const { 359 out << "(style) "; 360 if (!parent.name.entry.empty()) { 361 out << parent.name; 362 } 363 out << " [" 364 << util::joiner(entries.begin(), entries.end(), ", ") 365 << "]"; 366} 367 368static ::std::ostream& operator<<(::std::ostream& out, const Style::Entry& value) { 369 out << value.key.name << " = "; 370 value.value->print(out); 371 return out; 372} 373 374Array* Array::clone(StringPool* newPool) const { 375 Array* array = new Array(); 376 for (auto& item : items) { 377 array->items.emplace_back(std::unique_ptr<Item>(item->clone(newPool))); 378 } 379 return array; 380} 381 382void Array::print(std::ostream& out) const { 383 out << "(array) [" 384 << util::joiner(items.begin(), items.end(), ", ") 385 << "]"; 386} 387 388Plural* Plural::clone(StringPool* newPool) const { 389 Plural* p = new Plural(); 390 const size_t count = values.size(); 391 for (size_t i = 0; i < count; i++) { 392 if (values[i]) { 393 p->values[i] = std::unique_ptr<Item>(values[i]->clone(newPool)); 394 } 395 } 396 return p; 397} 398 399void Plural::print(std::ostream& out) const { 400 out << "(plural)"; 401} 402 403static ::std::ostream& operator<<(::std::ostream& out, const std::unique_ptr<Item>& item) { 404 return out << *item; 405} 406 407Styleable* Styleable::clone(StringPool* /*newPool*/) const { 408 Styleable* styleable = new Styleable(); 409 std::copy(entries.begin(), entries.end(), std::back_inserter(styleable->entries)); 410 return styleable; 411} 412 413void Styleable::print(std::ostream& out) const { 414 out << "(styleable) " << " [" 415 << util::joiner(entries.begin(), entries.end(), ", ") 416 << "]"; 417} 418 419} // namespace aapt 420