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 "SplitDescription.h"
18
19#include "aapt/AaptConfig.h"
20#include "aapt/AaptUtil.h"
21
22#include <utils/String8.h>
23#include <utils/Vector.h>
24
25using namespace android;
26
27namespace split {
28
29SplitDescription::SplitDescription()
30: abi(abi::Variant_none) {
31}
32
33int SplitDescription::compare(const SplitDescription& rhs) const {
34    int cmp;
35    cmp = (int)abi - (int)rhs.abi;
36    if (cmp != 0) return cmp;
37    return config.compareLogical(rhs.config);
38}
39
40bool SplitDescription::isBetterThan(const SplitDescription& o, const SplitDescription& target) const {
41    if (abi != abi::Variant_none || o.abi != abi::Variant_none) {
42        abi::Family family = abi::getFamily(abi);
43        abi::Family oFamily = abi::getFamily(o.abi);
44        if (family != oFamily) {
45            return family != abi::Family_none;
46        }
47
48        if (int(target.abi) - int(abi) < int(target.abi) - int(o.abi)) {
49            return true;
50        }
51    }
52    return config.isBetterThan(o.config, &target.config);
53}
54
55bool SplitDescription::match(const SplitDescription& o) const {
56    if (abi != abi::Variant_none) {
57        abi::Family family = abi::getFamily(abi);
58        abi::Family oFamily = abi::getFamily(o.abi);
59        if (family != oFamily) {
60            return false;
61        }
62
63        if (int(abi) > int(o.abi)) {
64            return false;
65        }
66    }
67    return config.match(o.config);
68}
69
70String8 SplitDescription::toString() const {
71    String8 extension;
72    if (abi != abi::Variant_none) {
73        if (extension.isEmpty()) {
74            extension.append(":");
75        } else {
76            extension.append("-");
77        }
78        extension.append(abi::toString(abi));
79    }
80    String8 str(config.toString());
81    str.append(extension);
82    return str;
83}
84
85ssize_t parseAbi(const Vector<String8>& parts, const ssize_t index,
86        SplitDescription* outSplit) {
87    const ssize_t N = parts.size();
88    abi::Variant abi = abi::Variant_none;
89    ssize_t endIndex = index;
90    if (parts[endIndex] == "arm64") {
91        endIndex++;
92        if (endIndex < N) {
93            if (parts[endIndex] == "v8a") {
94                endIndex++;
95                abi = abi::Variant_arm64_v8a;
96            }
97        }
98    } else if (parts[endIndex] == "armeabi") {
99        endIndex++;
100        abi = abi::Variant_armeabi;
101        if (endIndex < N) {
102            if (parts[endIndex] == "v7a") {
103                endIndex++;
104                abi = abi::Variant_armeabi_v7a;
105            }
106        }
107    } else if (parts[endIndex] == "x86") {
108        endIndex++;
109        abi = abi::Variant_x86;
110    } else if (parts[endIndex] == "x86_64") {
111        endIndex++;
112        abi = abi::Variant_x86_64;
113    } else if (parts[endIndex] == "mips") {
114        endIndex++;
115        abi = abi::Variant_mips;
116    } else if (parts[endIndex] == "mips64") {
117        endIndex++;
118        abi = abi::Variant_mips64;
119    }
120
121    if (abi == abi::Variant_none && endIndex != index) {
122        return -1;
123    }
124
125    if (outSplit != NULL) {
126        outSplit->abi = abi;
127    }
128    return endIndex;
129}
130
131bool SplitDescription::parse(const String8& str, SplitDescription* outSplit) {
132    ssize_t index = str.find(":");
133
134    String8 configStr;
135    String8 extensionStr;
136    if (index >= 0) {
137        configStr.setTo(str.string(), index);
138        extensionStr.setTo(str.string() + index + 1);
139    } else {
140        configStr.setTo(str);
141    }
142
143    SplitDescription split;
144    if (!AaptConfig::parse(configStr, &split.config)) {
145        return false;
146    }
147
148    Vector<String8> parts = AaptUtil::splitAndLowerCase(extensionStr, '-');
149    const ssize_t N = parts.size();
150    index = 0;
151
152    if (extensionStr.length() == 0) {
153        goto success;
154    }
155
156    index = parseAbi(parts, index, &split);
157    if (index < 0) {
158        return false;
159    } else {
160        if (index == N) {
161            goto success;
162        }
163    }
164
165    // Unrecognized
166    return false;
167
168success:
169    if (outSplit != NULL) {
170        *outSplit = split;
171    }
172    return true;
173}
174
175} // namespace split
176