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