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 
27 namespace aapt {
28 
29 struct 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 
42 class NameMangler {
43 private:
44     NameManglerPolicy mPolicy;
45 
46 public:
NameMangler(NameManglerPolicy policy)47     NameMangler(NameManglerPolicy policy) : mPolicy(policy) {
48     }
49 
mangleName(const ResourceName & name)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 
shouldMangle(const std::u16string & package)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      */
mangleEntry(const std::u16string & package,const std::u16string & name)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      */
unmangle(std::u16string * outName,std::u16string * outPackage)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