1ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski/*
2ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski * Copyright (C) 2014 The Android Open Source Project
3ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski *
4ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski * Licensed under the Apache License, Version 2.0 (the "License");
5ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski * you may not use this file except in compliance with the License.
6ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski * You may obtain a copy of the License at
7ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski *
8ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski *      http://www.apache.org/licenses/LICENSE-2.0
9ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski *
10ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski * Unless required by applicable law or agreed to in writing, software
11ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski * distributed under the License is distributed on an "AS IS" BASIS,
12ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski * See the License for the specific language governing permissions and
14ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski * limitations under the License.
15ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski */
16ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski
17ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski#include <androidfw/ResourceTypes.h>
18ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski#include <utils/String8.h>
19ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski
20ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski#include "AaptXml.h"
21ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski
22ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinskiusing namespace android;
23ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski
24ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinskinamespace AaptXml {
25ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski
26ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinskistatic String8 getStringAttributeAtIndex(const ResXMLTree& tree, ssize_t attrIndex,
27ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski        String8* outError) {
28ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski    Res_value value;
29ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski    if (tree.getAttributeValue(attrIndex, &value) < 0) {
30ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski        if (outError != NULL) {
31ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski            *outError = "could not find attribute at index";
32ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski        }
33ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski        return String8();
34ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski    }
35ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski
36ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski    if (value.dataType != Res_value::TYPE_STRING) {
37ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski        if (outError != NULL) {
38ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski            *outError = "attribute is not a string value";
39ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski        }
40ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski        return String8();
41ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski    }
42ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski
43ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski    size_t len;
444bf58108d442b37ab4adf5ce3a4ecd63472ce254Adam Lesinski    const char16_t* str = tree.getAttributeStringValue(attrIndex, &len);
45ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski    return str ? String8(str, len) : String8();
46ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski}
47ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski
48ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinskistatic int32_t getIntegerAttributeAtIndex(const ResXMLTree& tree, ssize_t attrIndex,
49ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski    int32_t defValue, String8* outError) {
50ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski    Res_value value;
51ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski    if (tree.getAttributeValue(attrIndex, &value) < 0) {
52ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski        if (outError != NULL) {
53ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski            *outError = "could not find attribute at index";
54ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski        }
55ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski        return defValue;
56ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski    }
57ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski
58ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski    if (value.dataType < Res_value::TYPE_FIRST_INT
59ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski            || value.dataType > Res_value::TYPE_LAST_INT) {
60ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski        if (outError != NULL) {
61ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski            *outError = "attribute is not an integer value";
62ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski        }
63ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski        return defValue;
64ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski    }
65ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski    return value.data;
66ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski}
67ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski
68ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski
69ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinskissize_t indexOfAttribute(const ResXMLTree& tree, uint32_t attrRes) {
70ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski    size_t attrCount = tree.getAttributeCount();
71ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski    for (size_t i = 0; i < attrCount; i++) {
72ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski        if (tree.getAttributeNameResID(i) == attrRes) {
73ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski            return (ssize_t)i;
74ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski        }
75ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski    }
76ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski    return -1;
77ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski}
78ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski
79ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam LesinskiString8 getAttribute(const ResXMLTree& tree, const char* ns,
80ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski        const char* attr, String8* outError) {
81ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski    ssize_t idx = tree.indexOfAttribute(ns, attr);
82ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski    if (idx < 0) {
83ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski        return String8();
84ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski    }
85ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski    return getStringAttributeAtIndex(tree, idx, outError);
86ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski}
87ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski
88ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam LesinskiString8 getAttribute(const ResXMLTree& tree, uint32_t attrRes, String8* outError) {
89ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski    ssize_t idx = indexOfAttribute(tree, attrRes);
90ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski    if (idx < 0) {
91ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski        return String8();
92ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski    }
93ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski    return getStringAttributeAtIndex(tree, idx, outError);
94ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski}
95ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski
96ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam LesinskiString8 getResolvedAttribute(const ResTable& resTable, const ResXMLTree& tree,
97ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski        uint32_t attrRes, String8* outError) {
98ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski    ssize_t idx = indexOfAttribute(tree, attrRes);
99ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski    if (idx < 0) {
100ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski        return String8();
101ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski    }
102ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski    Res_value value;
103ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski    if (tree.getAttributeValue(idx, &value) != NO_ERROR) {
104ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski        if (value.dataType == Res_value::TYPE_STRING) {
105ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski            size_t len;
1064bf58108d442b37ab4adf5ce3a4ecd63472ce254Adam Lesinski            const char16_t* str = tree.getAttributeStringValue(idx, &len);
107ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski            return str ? String8(str, len) : String8();
108ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski        }
109ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski        resTable.resolveReference(&value, 0);
110ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski        if (value.dataType != Res_value::TYPE_STRING) {
111ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski            if (outError != NULL) {
112ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                *outError = "attribute is not a string value";
113ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski            }
114ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski            return String8();
115ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski        }
116ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski    }
117ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski    size_t len;
118ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski    const Res_value* value2 = &value;
119ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski    const char16_t* str = resTable.valueToString(value2, 0, NULL, &len);
120ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski    return str ? String8(str, len) : String8();
121ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski}
122ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski
123ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinskiint32_t getIntegerAttribute(const ResXMLTree& tree, const char* ns,
124ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski        const char* attr, int32_t defValue, String8* outError) {
125ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski    ssize_t idx = tree.indexOfAttribute(ns, attr);
126ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski    if (idx < 0) {
127ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski        return defValue;
128ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski    }
129ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski    return getIntegerAttributeAtIndex(tree, idx, defValue, outError);
130ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski}
131ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski
132ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinskiint32_t getIntegerAttribute(const ResXMLTree& tree, uint32_t attrRes, int32_t defValue,
133ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski        String8* outError) {
134ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski    ssize_t idx = indexOfAttribute(tree, attrRes);
135ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski    if (idx < 0) {
136ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski        return defValue;
137ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski    }
138ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski    return getIntegerAttributeAtIndex(tree, idx, defValue, outError);
139ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski}
140ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski
141ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinskiint32_t getResolvedIntegerAttribute(const ResTable& resTable, const ResXMLTree& tree,
142ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski        uint32_t attrRes, int32_t defValue, String8* outError) {
143ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski    ssize_t idx = indexOfAttribute(tree, attrRes);
144ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski    if (idx < 0) {
145ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski        return defValue;
146ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski    }
147ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski    Res_value value;
148ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski    if (tree.getAttributeValue(idx, &value) != NO_ERROR) {
149ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski        if (value.dataType == Res_value::TYPE_REFERENCE) {
150ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski            resTable.resolveReference(&value, 0);
151ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski        }
152ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski        if (value.dataType < Res_value::TYPE_FIRST_INT
153ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                || value.dataType > Res_value::TYPE_LAST_INT) {
154ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski            if (outError != NULL) {
155ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski                *outError = "attribute is not an integer value";
156ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski            }
157ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski            return defValue;
158ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski        }
159ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski    }
160ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski    return value.data;
161ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski}
162ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski
163ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinskivoid getResolvedResourceAttribute(const ResTable& resTable, const ResXMLTree& tree,
164ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski        uint32_t attrRes, Res_value* outValue, String8* outError) {
165ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski    ssize_t idx = indexOfAttribute(tree, attrRes);
166ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski    if (idx < 0) {
167ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski        if (outError != NULL) {
168ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski            *outError = "attribute could not be found";
169ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski        }
170ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski        return;
171ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski    }
172ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski    if (tree.getAttributeValue(idx, outValue) != NO_ERROR) {
173ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski        if (outValue->dataType == Res_value::TYPE_REFERENCE) {
174ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski            resTable.resolveReference(outValue, 0);
175ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski        }
176ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski        // The attribute was found and was resolved if need be.
177ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski        return;
178ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski    }
179ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski    if (outError != NULL) {
180ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski        *outError = "error getting resolved resource attribute";
181ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski    }
182ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski}
183ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski
184ad2d07d2d98a46babb2a9472413fe9ce5080ca76Adam Lesinski} // namespace AaptXml
185