/*
* 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 "SplitDescription.h"
#include "aapt/AaptConfig.h"
#include "aapt/AaptUtil.h"
#include <utils/String8.h>
#include <utils/Vector.h>
using namespace android;
namespace split {
SplitDescription::SplitDescription()
: abi(abi::Variant_none) {
}
int SplitDescription::compare(const SplitDescription& rhs) const {
int cmp;
cmp = (int)abi - (int)rhs.abi;
if (cmp != 0) return cmp;
return config.compareLogical(rhs.config);
}
bool SplitDescription::isBetterThan(const SplitDescription& o, const SplitDescription& target) const {
if (abi != abi::Variant_none || o.abi != abi::Variant_none) {
abi::Family family = abi::getFamily(abi);
abi::Family oFamily = abi::getFamily(o.abi);
if (family != oFamily) {
return family != abi::Family_none;
}
if (int(target.abi) - int(abi) < int(target.abi) - int(o.abi)) {
return true;
}
}
return config.isBetterThan(o.config, &target.config);
}
bool SplitDescription::match(const SplitDescription& o) const {
if (abi != abi::Variant_none) {
abi::Family family = abi::getFamily(abi);
abi::Family oFamily = abi::getFamily(o.abi);
if (family != oFamily) {
return false;
}
if (int(abi) > int(o.abi)) {
return false;
}
}
return config.match(o.config);
}
String8 SplitDescription::toString() const {
String8 extension;
if (abi != abi::Variant_none) {
if (extension.isEmpty()) {
extension.append(":");
} else {
extension.append("-");
}
extension.append(abi::toString(abi));
}
String8 str(config.toString());
str.append(extension);
return str;
}
ssize_t parseAbi(const Vector<String8>& parts, const ssize_t index,
SplitDescription* outSplit) {
const ssize_t N = parts.size();
abi::Variant abi = abi::Variant_none;
ssize_t endIndex = index;
if (parts[endIndex] == "arm64") {
endIndex++;
if (endIndex < N) {
if (parts[endIndex] == "v8a") {
endIndex++;
abi = abi::Variant_arm64_v8a;
}
}
} else if (parts[endIndex] == "armeabi") {
endIndex++;
abi = abi::Variant_armeabi;
if (endIndex < N) {
if (parts[endIndex] == "v7a") {
endIndex++;
abi = abi::Variant_armeabi_v7a;
}
}
} else if (parts[endIndex] == "x86") {
endIndex++;
abi = abi::Variant_x86;
} else if (parts[endIndex] == "x86_64") {
endIndex++;
abi = abi::Variant_x86_64;
} else if (parts[endIndex] == "mips") {
endIndex++;
abi = abi::Variant_mips;
} else if (parts[endIndex] == "mips64") {
endIndex++;
abi = abi::Variant_mips64;
}
if (abi == abi::Variant_none && endIndex != index) {
return -1;
}
if (outSplit != NULL) {
outSplit->abi = abi;
}
return endIndex;
}
bool SplitDescription::parse(const String8& str, SplitDescription* outSplit) {
ssize_t index = str.find(":");
String8 configStr;
String8 extensionStr;
if (index >= 0) {
configStr.setTo(str.string(), index);
extensionStr.setTo(str.string() + index + 1);
} else {
configStr.setTo(str);
}
SplitDescription split;
if (!AaptConfig::parse(configStr, &split.config)) {
return false;
}
Vector<String8> parts = AaptUtil::splitAndLowerCase(extensionStr, '-');
const ssize_t N = parts.size();
index = 0;
if (extensionStr.length() == 0) {
goto success;
}
index = parseAbi(parts, index, &split);
if (index < 0) {
return false;
} else {
if (index == N) {
goto success;
}
}
// Unrecognized
return false;
success:
if (outSplit != NULL) {
*outSplit = split;
}
return true;
}
} // namespace split