Home | History | Annotate | Download | only in aapt
      1 /*
      2  * Copyright (C) 2014 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 <androidfw/ResourceTypes.h>
     18 #include <utils/String8.h>
     19 
     20 #include "AaptXml.h"
     21 
     22 using namespace android;
     23 
     24 namespace AaptXml {
     25 
     26 static String8 getStringAttributeAtIndex(const ResXMLTree& tree, ssize_t attrIndex,
     27         String8* outError) {
     28     Res_value value;
     29     if (tree.getAttributeValue(attrIndex, &value) < 0) {
     30         if (outError != NULL) {
     31             *outError = "could not find attribute at index";
     32         }
     33         return String8();
     34     }
     35 
     36     if (value.dataType != Res_value::TYPE_STRING) {
     37         if (outError != NULL) {
     38             *outError = "attribute is not a string value";
     39         }
     40         return String8();
     41     }
     42 
     43     size_t len;
     44     const char16_t* str = tree.getAttributeStringValue(attrIndex, &len);
     45     return str ? String8(str, len) : String8();
     46 }
     47 
     48 static int32_t getIntegerAttributeAtIndex(const ResXMLTree& tree, ssize_t attrIndex,
     49     int32_t defValue, String8* outError) {
     50     Res_value value;
     51     if (tree.getAttributeValue(attrIndex, &value) < 0) {
     52         if (outError != NULL) {
     53             *outError = "could not find attribute at index";
     54         }
     55         return defValue;
     56     }
     57 
     58     if (value.dataType < Res_value::TYPE_FIRST_INT
     59             || value.dataType > Res_value::TYPE_LAST_INT) {
     60         if (outError != NULL) {
     61             *outError = "attribute is not an integer value";
     62         }
     63         return defValue;
     64     }
     65     return value.data;
     66 }
     67 
     68 
     69 ssize_t indexOfAttribute(const ResXMLTree& tree, uint32_t attrRes) {
     70     size_t attrCount = tree.getAttributeCount();
     71     for (size_t i = 0; i < attrCount; i++) {
     72         if (tree.getAttributeNameResID(i) == attrRes) {
     73             return (ssize_t)i;
     74         }
     75     }
     76     return -1;
     77 }
     78 
     79 String8 getAttribute(const ResXMLTree& tree, const char* ns,
     80         const char* attr, String8* outError) {
     81     ssize_t idx = tree.indexOfAttribute(ns, attr);
     82     if (idx < 0) {
     83         return String8();
     84     }
     85     return getStringAttributeAtIndex(tree, idx, outError);
     86 }
     87 
     88 String8 getAttribute(const ResXMLTree& tree, uint32_t attrRes, String8* outError) {
     89     ssize_t idx = indexOfAttribute(tree, attrRes);
     90     if (idx < 0) {
     91         return String8();
     92     }
     93     return getStringAttributeAtIndex(tree, idx, outError);
     94 }
     95 
     96 String8 getResolvedAttribute(const ResTable& resTable, const ResXMLTree& tree,
     97         uint32_t attrRes, String8* outError) {
     98     ssize_t idx = indexOfAttribute(tree, attrRes);
     99     if (idx < 0) {
    100         return String8();
    101     }
    102 
    103     Res_value value;
    104     if (tree.getAttributeValue(idx, &value) == BAD_TYPE) {
    105         if (outError != NULL) {
    106             *outError = "attribute value is corrupt";
    107         }
    108         return String8();
    109     }
    110 
    111     // Check if the string is inline in the XML.
    112     if (value.dataType == Res_value::TYPE_STRING) {
    113         size_t len;
    114         const char16_t* str = tree.getAttributeStringValue(idx, &len);
    115         return str ? String8(str, len) : String8();
    116     }
    117 
    118     // Resolve the reference if there is one.
    119     ssize_t block = resTable.resolveReference(&value, 0);
    120     if (block < 0) {
    121         if (outError != NULL) {
    122             *outError = "attribute value reference does not exist";
    123         }
    124         return String8();
    125     }
    126 
    127     if (value.dataType != Res_value::TYPE_STRING) {
    128         if (outError != NULL) {
    129             *outError = "attribute is not a string value";
    130         }
    131         return String8();
    132     }
    133 
    134     size_t len;
    135     const char16_t* str = resTable.valueToString(&value, static_cast<size_t>(block), NULL, &len);
    136     return str ? String8(str, len) : String8();
    137 }
    138 
    139 int32_t getIntegerAttribute(const ResXMLTree& tree, const char* ns,
    140         const char* attr, int32_t defValue, String8* outError) {
    141     ssize_t idx = tree.indexOfAttribute(ns, attr);
    142     if (idx < 0) {
    143         return defValue;
    144     }
    145     return getIntegerAttributeAtIndex(tree, idx, defValue, outError);
    146 }
    147 
    148 int32_t getIntegerAttribute(const ResXMLTree& tree, uint32_t attrRes, int32_t defValue,
    149         String8* outError) {
    150     ssize_t idx = indexOfAttribute(tree, attrRes);
    151     if (idx < 0) {
    152         return defValue;
    153     }
    154     return getIntegerAttributeAtIndex(tree, idx, defValue, outError);
    155 }
    156 
    157 int32_t getResolvedIntegerAttribute(const ResTable& resTable, const ResXMLTree& tree,
    158         uint32_t attrRes, int32_t defValue, String8* outError) {
    159     ssize_t idx = indexOfAttribute(tree, attrRes);
    160     if (idx < 0) {
    161         return defValue;
    162     }
    163     Res_value value;
    164     if (tree.getAttributeValue(idx, &value) != NO_ERROR) {
    165         if (value.dataType == Res_value::TYPE_REFERENCE) {
    166             resTable.resolveReference(&value, 0);
    167         }
    168         if (value.dataType < Res_value::TYPE_FIRST_INT
    169                 || value.dataType > Res_value::TYPE_LAST_INT) {
    170             if (outError != NULL) {
    171                 *outError = "attribute is not an integer value";
    172             }
    173             return defValue;
    174         }
    175     }
    176     return value.data;
    177 }
    178 
    179 void getResolvedResourceAttribute(const ResTable& resTable, const ResXMLTree& tree,
    180         uint32_t attrRes, Res_value* outValue, String8* outError) {
    181     ssize_t idx = indexOfAttribute(tree, attrRes);
    182     if (idx < 0) {
    183         if (outError != NULL) {
    184             *outError = "attribute could not be found";
    185         }
    186         return;
    187     }
    188     if (tree.getAttributeValue(idx, outValue) != NO_ERROR) {
    189         if (outValue->dataType == Res_value::TYPE_REFERENCE) {
    190             resTable.resolveReference(outValue, 0);
    191         }
    192         // The attribute was found and was resolved if need be.
    193         return;
    194     }
    195     if (outError != NULL) {
    196         *outError = "error getting resolved resource attribute";
    197     }
    198 }
    199 
    200 } // namespace AaptXml
    201