Home | History | Annotate | Download | only in aapt2
      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 "ResourceUtils.h"
     19 #include "ResourceValues.h"
     20 #include "ValueVisitor.h"
     21 #include "io/File.h"
     22 #include "util/Util.h"
     23 
     24 #include <androidfw/ResourceTypes.h>
     25 #include <limits>
     26 
     27 namespace aapt {
     28 
     29 template <typename Derived>
     30 void BaseValue<Derived>::accept(RawValueVisitor* visitor) {
     31     visitor->visit(static_cast<Derived*>(this));
     32 }
     33 
     34 template <typename Derived>
     35 void BaseItem<Derived>::accept(RawValueVisitor* visitor) {
     36     visitor->visit(static_cast<Derived*>(this));
     37 }
     38 
     39 RawString::RawString(const StringPool::Ref& ref) : value(ref) {
     40 }
     41 
     42 RawString* RawString::clone(StringPool* newPool) const {
     43     RawString* rs = new RawString(newPool->makeRef(*value));
     44     rs->mComment = mComment;
     45     rs->mSource = mSource;
     46     return rs;
     47 }
     48 
     49 bool RawString::flatten(android::Res_value* outValue) const {
     50     outValue->dataType = android::Res_value::TYPE_STRING;
     51     outValue->data = util::hostToDevice32(static_cast<uint32_t>(value.getIndex()));
     52     return true;
     53 }
     54 
     55 void RawString::print(std::ostream* out) const {
     56     *out << "(raw string) " << *value;
     57 }
     58 
     59 Reference::Reference() : referenceType(Reference::Type::kResource) {
     60 }
     61 
     62 Reference::Reference(const ResourceNameRef& n, Type t) :
     63         name(n.toResourceName()), referenceType(t) {
     64 }
     65 
     66 Reference::Reference(const ResourceId& i, Type type) : id(i), referenceType(type) {
     67 }
     68 
     69 bool Reference::flatten(android::Res_value* outValue) const {
     70     outValue->dataType = (referenceType == Reference::Type::kResource) ?
     71             android::Res_value::TYPE_REFERENCE : android::Res_value::TYPE_ATTRIBUTE;
     72     outValue->data = util::hostToDevice32(id ? id.value().id : 0);
     73     return true;
     74 }
     75 
     76 Reference* Reference::clone(StringPool* /*newPool*/) const {
     77     return new Reference(*this);
     78 }
     79 
     80 void Reference::print(std::ostream* out) const {
     81     *out << "(reference) ";
     82     if (referenceType == Reference::Type::kResource) {
     83         *out << "@";
     84         if (privateReference) {
     85             *out << "*";
     86         }
     87     } else {
     88         *out << "?";
     89     }
     90 
     91     if (name) {
     92         *out << name.value();
     93     }
     94 
     95     if (id && !Res_INTERNALID(id.value().id)) {
     96         *out << " " << id.value();
     97     }
     98 }
     99 
    100 bool Id::flatten(android::Res_value* out) const {
    101     out->dataType = android::Res_value::TYPE_INT_BOOLEAN;
    102     out->data = util::hostToDevice32(0);
    103     return true;
    104 }
    105 
    106 Id* Id::clone(StringPool* /*newPool*/) const {
    107     return new Id(*this);
    108 }
    109 
    110 void Id::print(std::ostream* out) const {
    111     *out << "(id)";
    112 }
    113 
    114 String::String(const StringPool::Ref& ref) : value(ref), mTranslateable(true) {
    115 }
    116 
    117 void String::setTranslateable(bool val) {
    118     mTranslateable = val;
    119 }
    120 
    121 bool String::isTranslateable() const {
    122     return mTranslateable;
    123 }
    124 
    125 bool String::flatten(android::Res_value* outValue) const {
    126     // Verify that our StringPool index is within encode-able limits.
    127     if (value.getIndex() > std::numeric_limits<uint32_t>::max()) {
    128         return false;
    129     }
    130 
    131     outValue->dataType = android::Res_value::TYPE_STRING;
    132     outValue->data = util::hostToDevice32(static_cast<uint32_t>(value.getIndex()));
    133     return true;
    134 }
    135 
    136 String* String::clone(StringPool* newPool) const {
    137     String* str = new String(newPool->makeRef(*value));
    138     str->mComment = mComment;
    139     str->mSource = mSource;
    140     return str;
    141 }
    142 
    143 void String::print(std::ostream* out) const {
    144     *out << "(string) \"" << *value << "\"";
    145 }
    146 
    147 StyledString::StyledString(const StringPool::StyleRef& ref) : value(ref), mTranslateable(true) {
    148 }
    149 
    150 void StyledString::setTranslateable(bool val) {
    151     mTranslateable = val;
    152 }
    153 
    154 bool StyledString::isTranslateable() const {
    155     return mTranslateable;
    156 }
    157 
    158 bool StyledString::flatten(android::Res_value* outValue) const {
    159     if (value.getIndex() > std::numeric_limits<uint32_t>::max()) {
    160         return false;
    161     }
    162 
    163     outValue->dataType = android::Res_value::TYPE_STRING;
    164     outValue->data = util::hostToDevice32(static_cast<uint32_t>(value.getIndex()));
    165     return true;
    166 }
    167 
    168 StyledString* StyledString::clone(StringPool* newPool) const {
    169     StyledString* str = new StyledString(newPool->makeRef(value));
    170     str->mComment = mComment;
    171     str->mSource = mSource;
    172     return str;
    173 }
    174 
    175 void StyledString::print(std::ostream* out) const {
    176     *out << "(styled string) \"" << *value->str << "\"";
    177 }
    178 
    179 FileReference::FileReference(const StringPool::Ref& _path) : path(_path) {
    180 }
    181 
    182 bool FileReference::flatten(android::Res_value* outValue) const {
    183     if (path.getIndex() > std::numeric_limits<uint32_t>::max()) {
    184         return false;
    185     }
    186 
    187     outValue->dataType = android::Res_value::TYPE_STRING;
    188     outValue->data = util::hostToDevice32(static_cast<uint32_t>(path.getIndex()));
    189     return true;
    190 }
    191 
    192 FileReference* FileReference::clone(StringPool* newPool) const {
    193     FileReference* fr = new FileReference(newPool->makeRef(*path));
    194     fr->file = file;
    195     fr->mComment = mComment;
    196     fr->mSource = mSource;
    197     return fr;
    198 }
    199 
    200 void FileReference::print(std::ostream* out) const {
    201     *out << "(file) " << *path;
    202 }
    203 
    204 BinaryPrimitive::BinaryPrimitive(const android::Res_value& val) : value(val) {
    205 }
    206 
    207 BinaryPrimitive::BinaryPrimitive(uint8_t dataType, uint32_t data) {
    208     value.dataType = dataType;
    209     value.data = data;
    210 }
    211 
    212 bool BinaryPrimitive::flatten(android::Res_value* outValue) const {
    213     outValue->dataType = value.dataType;
    214     outValue->data = util::hostToDevice32(value.data);
    215     return true;
    216 }
    217 
    218 BinaryPrimitive* BinaryPrimitive::clone(StringPool* /*newPool*/) const {
    219     return new BinaryPrimitive(*this);
    220 }
    221 
    222 void BinaryPrimitive::print(std::ostream* out) const {
    223     switch (value.dataType) {
    224         case android::Res_value::TYPE_NULL:
    225             *out << "(null)";
    226             break;
    227         case android::Res_value::TYPE_INT_DEC:
    228             *out << "(integer) " << static_cast<int32_t>(value.data);
    229             break;
    230         case android::Res_value::TYPE_INT_HEX:
    231             *out << "(integer) " << std::hex << value.data << std::dec;
    232             break;
    233         case android::Res_value::TYPE_INT_BOOLEAN:
    234             *out << "(boolean) " << (value.data != 0 ? "true" : "false");
    235             break;
    236         case android::Res_value::TYPE_INT_COLOR_ARGB8:
    237         case android::Res_value::TYPE_INT_COLOR_RGB8:
    238         case android::Res_value::TYPE_INT_COLOR_ARGB4:
    239         case android::Res_value::TYPE_INT_COLOR_RGB4:
    240             *out << "(color) #" << std::hex << value.data << std::dec;
    241             break;
    242         default:
    243             *out << "(unknown 0x" << std::hex << (int) value.dataType << ") 0x"
    244                  << std::hex << value.data << std::dec;
    245             break;
    246     }
    247 }
    248 
    249 Attribute::Attribute(bool w, uint32_t t) :
    250         typeMask(t),
    251         minInt(std::numeric_limits<int32_t>::min()),
    252         maxInt(std::numeric_limits<int32_t>::max()) {
    253     mWeak = w;
    254 }
    255 
    256 Attribute* Attribute::clone(StringPool* /*newPool*/) const {
    257     return new Attribute(*this);
    258 }
    259 
    260 void Attribute::printMask(std::ostream* out) const {
    261     if (typeMask == android::ResTable_map::TYPE_ANY) {
    262         *out << "any";
    263         return;
    264     }
    265 
    266     bool set = false;
    267     if ((typeMask & android::ResTable_map::TYPE_REFERENCE) != 0) {
    268         if (!set) {
    269             set = true;
    270         } else {
    271             *out << "|";
    272         }
    273         *out << "reference";
    274     }
    275 
    276     if ((typeMask & android::ResTable_map::TYPE_STRING) != 0) {
    277         if (!set) {
    278             set = true;
    279         } else {
    280             *out << "|";
    281         }
    282         *out << "string";
    283     }
    284 
    285     if ((typeMask & android::ResTable_map::TYPE_INTEGER) != 0) {
    286         if (!set) {
    287             set = true;
    288         } else {
    289             *out << "|";
    290         }
    291         *out << "integer";
    292     }
    293 
    294     if ((typeMask & android::ResTable_map::TYPE_BOOLEAN) != 0) {
    295         if (!set) {
    296             set = true;
    297         } else {
    298             *out << "|";
    299         }
    300         *out << "boolean";
    301     }
    302 
    303     if ((typeMask & android::ResTable_map::TYPE_COLOR) != 0) {
    304         if (!set) {
    305             set = true;
    306         } else {
    307             *out << "|";
    308         }
    309         *out << "color";
    310     }
    311 
    312     if ((typeMask & android::ResTable_map::TYPE_FLOAT) != 0) {
    313         if (!set) {
    314             set = true;
    315         } else {
    316             *out << "|";
    317         }
    318         *out << "float";
    319     }
    320 
    321     if ((typeMask & android::ResTable_map::TYPE_DIMENSION) != 0) {
    322         if (!set) {
    323             set = true;
    324         } else {
    325             *out << "|";
    326         }
    327         *out << "dimension";
    328     }
    329 
    330     if ((typeMask & android::ResTable_map::TYPE_FRACTION) != 0) {
    331         if (!set) {
    332             set = true;
    333         } else {
    334             *out << "|";
    335         }
    336         *out << "fraction";
    337     }
    338 
    339     if ((typeMask & android::ResTable_map::TYPE_ENUM) != 0) {
    340         if (!set) {
    341             set = true;
    342         } else {
    343             *out << "|";
    344         }
    345         *out << "enum";
    346     }
    347 
    348     if ((typeMask & android::ResTable_map::TYPE_FLAGS) != 0) {
    349         if (!set) {
    350             set = true;
    351         } else {
    352             *out << "|";
    353         }
    354         *out << "flags";
    355     }
    356 }
    357 
    358 void Attribute::print(std::ostream* out) const {
    359     *out << "(attr) ";
    360     printMask(out);
    361 
    362     if (!symbols.empty()) {
    363         *out << " ["
    364             << util::joiner(symbols.begin(), symbols.end(), ", ")
    365             << "]";
    366     }
    367 
    368     if (isWeak()) {
    369         *out << " [weak]";
    370     }
    371 }
    372 
    373 static void buildAttributeMismatchMessage(DiagMessage* msg, const Attribute* attr,
    374                                           const Item* value) {
    375     *msg << "expected";
    376     if (attr->typeMask & android::ResTable_map::TYPE_BOOLEAN) {
    377         *msg << " boolean";
    378     }
    379 
    380     if (attr->typeMask & android::ResTable_map::TYPE_COLOR) {
    381         *msg << " color";
    382     }
    383 
    384     if (attr->typeMask & android::ResTable_map::TYPE_DIMENSION) {
    385         *msg << " dimension";
    386     }
    387 
    388     if (attr->typeMask & android::ResTable_map::TYPE_ENUM) {
    389         *msg << " enum";
    390     }
    391 
    392     if (attr->typeMask & android::ResTable_map::TYPE_FLAGS) {
    393         *msg << " flags";
    394     }
    395 
    396     if (attr->typeMask & android::ResTable_map::TYPE_FLOAT) {
    397         *msg << " float";
    398     }
    399 
    400     if (attr->typeMask & android::ResTable_map::TYPE_FRACTION) {
    401         *msg << " fraction";
    402     }
    403 
    404     if (attr->typeMask & android::ResTable_map::TYPE_INTEGER) {
    405         *msg << " integer";
    406     }
    407 
    408     if (attr->typeMask & android::ResTable_map::TYPE_REFERENCE) {
    409         *msg << " reference";
    410     }
    411 
    412     if (attr->typeMask & android::ResTable_map::TYPE_STRING) {
    413         *msg << " string";
    414     }
    415 
    416     *msg << " but got " << *value;
    417 }
    418 
    419 bool Attribute::matches(const Item* item, DiagMessage* outMsg) const {
    420     android::Res_value val = {};
    421     item->flatten(&val);
    422 
    423     // Always allow references.
    424     const uint32_t mask = typeMask | android::ResTable_map::TYPE_REFERENCE;
    425     if (!(mask & ResourceUtils::androidTypeToAttributeTypeMask(val.dataType))) {
    426         if (outMsg) {
    427             buildAttributeMismatchMessage(outMsg, this, item);
    428         }
    429         return false;
    430 
    431     } else if (ResourceUtils::androidTypeToAttributeTypeMask(val.dataType) &
    432             android::ResTable_map::TYPE_INTEGER) {
    433         if (static_cast<int32_t>(util::deviceToHost32(val.data)) < minInt) {
    434             if (outMsg) {
    435                 *outMsg << *item << " is less than minimum integer " << minInt;
    436             }
    437             return false;
    438         } else if (static_cast<int32_t>(util::deviceToHost32(val.data)) > maxInt) {
    439             if (outMsg) {
    440                 *outMsg << *item << " is greater than maximum integer " << maxInt;
    441             }
    442             return false;
    443         }
    444     }
    445     return true;
    446 }
    447 
    448 Style* Style::clone(StringPool* newPool) const {
    449     Style* style = new Style();
    450     style->parent = parent;
    451     style->parentInferred = parentInferred;
    452     style->mComment = mComment;
    453     style->mSource = mSource;
    454     for (auto& entry : entries) {
    455         style->entries.push_back(Entry{
    456                 entry.key,
    457                 std::unique_ptr<Item>(entry.value->clone(newPool))
    458         });
    459     }
    460     return style;
    461 }
    462 
    463 void Style::print(std::ostream* out) const {
    464     *out << "(style) ";
    465     if (parent && parent.value().name) {
    466         if (parent.value().privateReference) {
    467             *out << "*";
    468         }
    469         *out << parent.value().name.value();
    470     }
    471     *out << " ["
    472         << util::joiner(entries.begin(), entries.end(), ", ")
    473         << "]";
    474 }
    475 
    476 static ::std::ostream& operator<<(::std::ostream& out, const Style::Entry& value) {
    477     if (value.key.name) {
    478         out << value.key.name.value();
    479     } else {
    480         out << "???";
    481     }
    482     out << " = ";
    483     value.value->print(&out);
    484     return out;
    485 }
    486 
    487 Array* Array::clone(StringPool* newPool) const {
    488     Array* array = new Array();
    489     array->mComment = mComment;
    490     array->mSource = mSource;
    491     for (auto& item : items) {
    492         array->items.emplace_back(std::unique_ptr<Item>(item->clone(newPool)));
    493     }
    494     return array;
    495 }
    496 
    497 void Array::print(std::ostream* out) const {
    498     *out << "(array) ["
    499         << util::joiner(items.begin(), items.end(), ", ")
    500         << "]";
    501 }
    502 
    503 Plural* Plural::clone(StringPool* newPool) const {
    504     Plural* p = new Plural();
    505     p->mComment = mComment;
    506     p->mSource = mSource;
    507     const size_t count = values.size();
    508     for (size_t i = 0; i < count; i++) {
    509         if (values[i]) {
    510             p->values[i] = std::unique_ptr<Item>(values[i]->clone(newPool));
    511         }
    512     }
    513     return p;
    514 }
    515 
    516 void Plural::print(std::ostream* out) const {
    517     *out << "(plural)";
    518 }
    519 
    520 static ::std::ostream& operator<<(::std::ostream& out, const std::unique_ptr<Item>& item) {
    521     return out << *item;
    522 }
    523 
    524 Styleable* Styleable::clone(StringPool* /*newPool*/) const {
    525     return new Styleable(*this);
    526 }
    527 
    528 void Styleable::print(std::ostream* out) const {
    529     *out << "(styleable) " << " ["
    530         << util::joiner(entries.begin(), entries.end(), ", ")
    531         << "]";
    532 }
    533 
    534 } // namespace aapt
    535