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 
getStringAttributeAtIndex(const ResXMLTree & tree,ssize_t attrIndex,String8 * outError)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 
getIntegerAttributeAtIndex(const ResXMLTree & tree,ssize_t attrIndex,int32_t defValue,String8 * outError)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 
indexOfAttribute(const ResXMLTree & tree,uint32_t attrRes)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 
getAttribute(const ResXMLTree & tree,const char * ns,const char * attr,String8 * outError)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 
getAttribute(const ResXMLTree & tree,uint32_t attrRes,String8 * outError)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 
getResolvedAttribute(const ResTable & resTable,const ResXMLTree & tree,uint32_t attrRes,String8 * outError)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     Res_value value;
103     if (tree.getAttributeValue(idx, &value) != NO_ERROR) {
104         if (value.dataType == Res_value::TYPE_STRING) {
105             size_t len;
106             const char16_t* str = tree.getAttributeStringValue(idx, &len);
107             return str ? String8(str, len) : String8();
108         }
109         resTable.resolveReference(&value, 0);
110         if (value.dataType != Res_value::TYPE_STRING) {
111             if (outError != NULL) {
112                 *outError = "attribute is not a string value";
113             }
114             return String8();
115         }
116     }
117     size_t len;
118     const Res_value* value2 = &value;
119     const char16_t* str = resTable.valueToString(value2, 0, NULL, &len);
120     return str ? String8(str, len) : String8();
121 }
122 
getIntegerAttribute(const ResXMLTree & tree,const char * ns,const char * attr,int32_t defValue,String8 * outError)123 int32_t getIntegerAttribute(const ResXMLTree& tree, const char* ns,
124         const char* attr, int32_t defValue, String8* outError) {
125     ssize_t idx = tree.indexOfAttribute(ns, attr);
126     if (idx < 0) {
127         return defValue;
128     }
129     return getIntegerAttributeAtIndex(tree, idx, defValue, outError);
130 }
131 
getIntegerAttribute(const ResXMLTree & tree,uint32_t attrRes,int32_t defValue,String8 * outError)132 int32_t getIntegerAttribute(const ResXMLTree& tree, uint32_t attrRes, int32_t defValue,
133         String8* outError) {
134     ssize_t idx = indexOfAttribute(tree, attrRes);
135     if (idx < 0) {
136         return defValue;
137     }
138     return getIntegerAttributeAtIndex(tree, idx, defValue, outError);
139 }
140 
getResolvedIntegerAttribute(const ResTable & resTable,const ResXMLTree & tree,uint32_t attrRes,int32_t defValue,String8 * outError)141 int32_t getResolvedIntegerAttribute(const ResTable& resTable, const ResXMLTree& tree,
142         uint32_t attrRes, int32_t defValue, String8* outError) {
143     ssize_t idx = indexOfAttribute(tree, attrRes);
144     if (idx < 0) {
145         return defValue;
146     }
147     Res_value value;
148     if (tree.getAttributeValue(idx, &value) != NO_ERROR) {
149         if (value.dataType == Res_value::TYPE_REFERENCE) {
150             resTable.resolveReference(&value, 0);
151         }
152         if (value.dataType < Res_value::TYPE_FIRST_INT
153                 || value.dataType > Res_value::TYPE_LAST_INT) {
154             if (outError != NULL) {
155                 *outError = "attribute is not an integer value";
156             }
157             return defValue;
158         }
159     }
160     return value.data;
161 }
162 
getResolvedResourceAttribute(const ResTable & resTable,const ResXMLTree & tree,uint32_t attrRes,Res_value * outValue,String8 * outError)163 void getResolvedResourceAttribute(const ResTable& resTable, const ResXMLTree& tree,
164         uint32_t attrRes, Res_value* outValue, String8* outError) {
165     ssize_t idx = indexOfAttribute(tree, attrRes);
166     if (idx < 0) {
167         if (outError != NULL) {
168             *outError = "attribute could not be found";
169         }
170         return;
171     }
172     if (tree.getAttributeValue(idx, outValue) != NO_ERROR) {
173         if (outValue->dataType == Res_value::TYPE_REFERENCE) {
174             resTable.resolveReference(outValue, 0);
175         }
176         // The attribute was found and was resolved if need be.
177         return;
178     }
179     if (outError != NULL) {
180         *outError = "error getting resolved resource attribute";
181     }
182 }
183 
184 } // namespace AaptXml
185