1/*
2 * Copyright (C) 2015 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#ifndef AAPT_NAME_MANGLER_H
18#define AAPT_NAME_MANGLER_H
19
20#include "Resource.h"
21
22#include "util/Maybe.h"
23
24#include <set>
25#include <string>
26
27namespace aapt {
28
29struct NameManglerPolicy {
30    /**
31     * Represents the package we are trying to build. References pointing
32     * to this package are not mangled, and mangled references inherit this package name.
33     */
34    std::u16string targetPackageName;
35
36    /**
37     * We must know which references to mangle, and which to keep (android vs. com.android.support).
38     */
39    std::set<std::u16string> packagesToMangle;
40};
41
42class NameMangler {
43private:
44    NameManglerPolicy mPolicy;
45
46public:
47    NameMangler(NameManglerPolicy policy) : mPolicy(policy) {
48    }
49
50    Maybe<ResourceName> mangleName(const ResourceName& name) {
51        if (mPolicy.targetPackageName == name.package ||
52                mPolicy.packagesToMangle.count(name.package) == 0) {
53            return {};
54        }
55
56        return ResourceName{
57                mPolicy.targetPackageName,
58                name.type,
59                mangleEntry(name.package, name.entry)
60        };
61    }
62
63    bool shouldMangle(const std::u16string& package) const {
64        if (package.empty() || mPolicy.targetPackageName == package) {
65            return false;
66        }
67        return mPolicy.packagesToMangle.count(package) != 0;
68    }
69
70    /**
71     * Returns a mangled name that is a combination of `name` and `package`.
72     * The mangled name should contain symbols that are illegal to define in XML,
73     * so that there will never be name mangling collisions.
74     */
75    static std::u16string mangleEntry(const std::u16string& package, const std::u16string& name) {
76        return package + u"$" + name;
77    }
78
79    /**
80     * Unmangles the name in `outName`, storing the correct name back in `outName`
81     * and the package in `outPackage`. Returns true if the name was unmangled or
82     * false if the name was never mangled to begin with.
83     */
84    static bool unmangle(std::u16string* outName, std::u16string* outPackage) {
85        size_t pivot = outName->find(u'$');
86        if (pivot == std::string::npos) {
87            return false;
88        }
89
90        outPackage->assign(outName->data(), pivot);
91        outName->assign(outName->data() + pivot + 1, outName->size() - (pivot + 1));
92        return true;
93    }
94};
95
96} // namespace aapt
97
98#endif // AAPT_NAME_MANGLER_H
99