| /* | |
| * Copyright (C) 2014 The Android Open Source Project | |
| * | |
| * Licensed under the Apache License, Version 2.0 (the "License"); | |
| * you may not use this file except in compliance with the License. | |
| * You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, | |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| * See the License for the specific language governing permissions and | |
| * limitations under the License. | |
| */ | |
| #include <androidfw/ResourceTypes.h> | |
| #include <utils/String8.h> | |
| #include "AaptXml.h" | |
| using namespace android; | |
| namespace AaptXml { | |
| static String8 getStringAttributeAtIndex(const ResXMLTree& tree, ssize_t attrIndex, | |
| String8* outError) { | |
| Res_value value; | |
| if (tree.getAttributeValue(attrIndex, &value) < 0) { | |
| if (outError != NULL) { | |
| *outError = "could not find attribute at index"; | |
| } | |
| return String8(); | |
| } | |
| if (value.dataType != Res_value::TYPE_STRING) { | |
| if (outError != NULL) { | |
| *outError = "attribute is not a string value"; | |
| } | |
| return String8(); | |
| } | |
| size_t len; | |
| const char16_t* str = tree.getAttributeStringValue(attrIndex, &len); | |
| return str ? String8(str, len) : String8(); | |
| } | |
| static int32_t getIntegerAttributeAtIndex(const ResXMLTree& tree, ssize_t attrIndex, | |
| int32_t defValue, String8* outError) { | |
| Res_value value; | |
| if (tree.getAttributeValue(attrIndex, &value) < 0) { | |
| if (outError != NULL) { | |
| *outError = "could not find attribute at index"; | |
| } | |
| return defValue; | |
| } | |
| if (value.dataType < Res_value::TYPE_FIRST_INT | |
| || value.dataType > Res_value::TYPE_LAST_INT) { | |
| if (outError != NULL) { | |
| *outError = "attribute is not an integer value"; | |
| } | |
| return defValue; | |
| } | |
| return value.data; | |
| } | |
| ssize_t indexOfAttribute(const ResXMLTree& tree, uint32_t attrRes) { | |
| size_t attrCount = tree.getAttributeCount(); | |
| for (size_t i = 0; i < attrCount; i++) { | |
| if (tree.getAttributeNameResID(i) == attrRes) { | |
| return (ssize_t)i; | |
| } | |
| } | |
| return -1; | |
| } | |
| String8 getAttribute(const ResXMLTree& tree, const char* ns, | |
| const char* attr, String8* outError) { | |
| ssize_t idx = tree.indexOfAttribute(ns, attr); | |
| if (idx < 0) { | |
| return String8(); | |
| } | |
| return getStringAttributeAtIndex(tree, idx, outError); | |
| } | |
| String8 getAttribute(const ResXMLTree& tree, uint32_t attrRes, String8* outError) { | |
| ssize_t idx = indexOfAttribute(tree, attrRes); | |
| if (idx < 0) { | |
| return String8(); | |
| } | |
| return getStringAttributeAtIndex(tree, idx, outError); | |
| } | |
| String8 getResolvedAttribute(const ResTable& resTable, const ResXMLTree& tree, | |
| uint32_t attrRes, String8* outError) { | |
| ssize_t idx = indexOfAttribute(tree, attrRes); | |
| if (idx < 0) { | |
| return String8(); | |
| } | |
| Res_value value; | |
| if (tree.getAttributeValue(idx, &value) == BAD_TYPE) { | |
| if (outError != NULL) { | |
| *outError = "attribute value is corrupt"; | |
| } | |
| return String8(); | |
| } | |
| // Check if the string is inline in the XML. | |
| if (value.dataType == Res_value::TYPE_STRING) { | |
| size_t len; | |
| const char16_t* str = tree.getAttributeStringValue(idx, &len); | |
| return str ? String8(str, len) : String8(); | |
| } | |
| // Resolve the reference if there is one. | |
| ssize_t block = resTable.resolveReference(&value, 0); | |
| if (block < 0) { | |
| if (outError != NULL) { | |
| *outError = "attribute value reference does not exist"; | |
| } | |
| return String8(); | |
| } | |
| if (value.dataType != Res_value::TYPE_STRING) { | |
| if (outError != NULL) { | |
| *outError = "attribute is not a string value"; | |
| } | |
| return String8(); | |
| } | |
| size_t len; | |
| const char16_t* str = resTable.valueToString(&value, static_cast<size_t>(block), NULL, &len); | |
| return str ? String8(str, len) : String8(); | |
| } | |
| int32_t getIntegerAttribute(const ResXMLTree& tree, const char* ns, | |
| const char* attr, int32_t defValue, String8* outError) { | |
| ssize_t idx = tree.indexOfAttribute(ns, attr); | |
| if (idx < 0) { | |
| return defValue; | |
| } | |
| return getIntegerAttributeAtIndex(tree, idx, defValue, outError); | |
| } | |
| int32_t getIntegerAttribute(const ResXMLTree& tree, uint32_t attrRes, int32_t defValue, | |
| String8* outError) { | |
| ssize_t idx = indexOfAttribute(tree, attrRes); | |
| if (idx < 0) { | |
| return defValue; | |
| } | |
| return getIntegerAttributeAtIndex(tree, idx, defValue, outError); | |
| } | |
| int32_t getResolvedIntegerAttribute(const ResTable& resTable, const ResXMLTree& tree, | |
| uint32_t attrRes, int32_t defValue, String8* outError) { | |
| ssize_t idx = indexOfAttribute(tree, attrRes); | |
| if (idx < 0) { | |
| return defValue; | |
| } | |
| Res_value value; | |
| if (tree.getAttributeValue(idx, &value) != NO_ERROR) { | |
| if (value.dataType == Res_value::TYPE_REFERENCE) { | |
| resTable.resolveReference(&value, 0); | |
| } | |
| if (value.dataType < Res_value::TYPE_FIRST_INT | |
| || value.dataType > Res_value::TYPE_LAST_INT) { | |
| if (outError != NULL) { | |
| *outError = "attribute is not an integer value"; | |
| } | |
| return defValue; | |
| } | |
| } | |
| return value.data; | |
| } | |
| void getResolvedResourceAttribute(const ResTable& resTable, const ResXMLTree& tree, | |
| uint32_t attrRes, Res_value* outValue, String8* outError) { | |
| ssize_t idx = indexOfAttribute(tree, attrRes); | |
| if (idx < 0) { | |
| if (outError != NULL) { | |
| *outError = "attribute could not be found"; | |
| } | |
| return; | |
| } | |
| if (tree.getAttributeValue(idx, outValue) != NO_ERROR) { | |
| if (outValue->dataType == Res_value::TYPE_REFERENCE) { | |
| resTable.resolveReference(outValue, 0); | |
| } | |
| // The attribute was found and was resolved if need be. | |
| return; | |
| } | |
| if (outError != NULL) { | |
| *outError = "error getting resolved resource attribute"; | |
| } | |
| } | |
| } // namespace AaptXml |