• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (C) 2019 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef IORAP_SRC_DB_APP_COMPONENT_NAME_H_
16 #define IORAP_SRC_DB_APP_COMPONENT_NAME_H_
17 
18 namespace iorap::db {
19 
20 struct AppComponentName {
21   std::string package;
22   std::string activity_name;
23 
24   // Turns the activity name to the fully qualified name.
25   // For example, if the activity name is ".MainActivity" and the package is
26   // foo.bar. Then the fully qualified name is foo.bar.MainActivity.
CanonicalizeAppComponentName27   AppComponentName Canonicalize() const {
28     if (!activity_name.empty() && activity_name[0] == '.') {
29       return {package, package + activity_name};
30     }
31     return {package, activity_name};
32   }
33 
HasAppComponentNameAppComponentName34   static bool HasAppComponentName(const std::string& s) {
35     return s.find('/') != std::string::npos;
36   }
37 
38   // "com.foo.bar/.A" -> {"com.foo.bar", ".A"}
FromStringAppComponentName39   static AppComponentName FromString(const std::string& s) {
40     constexpr const char delimiter = '/';
41 
42     if (!HasAppComponentName(s)) {
43       return {std::move(s), ""};
44     }
45 
46     std::string package = s.substr(0, s.find(delimiter));
47 
48     std::string activity_name = s;
49     activity_name.erase(0, s.find(delimiter) + sizeof(delimiter));
50 
51     return {std::move(package), std::move(activity_name)};
52   }
53 
54   // {"com.foo.bar", ".A"} -> "com.foo.bar/.A"
ToStringAppComponentName55   std::string ToString() const {
56     return package + "/" + activity_name;
57   }
58 
59   /*
60    * '/' is encoded into %2F
61    * '%' is encoded into %25
62    *
63    * This allows the component name to be be used as a file name
64    * ('/' is illegal due to being a path separator) with minimal
65    * munging.
66    */
67 
68   // "com.foo.bar%2F.A%25" -> {"com.foo.bar", ".A%"}
FromUrlEncodedStringAppComponentName69   static AppComponentName FromUrlEncodedString(const std::string& s) {
70     std::string cpy = s;
71     Replace(cpy, "%2F", "/");
72     Replace(cpy, "%25", "%");
73 
74     return FromString(cpy);
75   }
76 
77   // {"com.foo.bar", ".A%"} -> "com.foo.bar%2F.A%25"
ToUrlEncodedStringAppComponentName78   std::string ToUrlEncodedString() const {
79     std::string s = ToString();
80     Replace(s, "%", "%25");
81     Replace(s, "/", "%2F");
82     return s;
83   }
84 
85   /*
86    * '/' is encoded into @@
87    * '%' is encoded into ^^
88    *
89    * Two purpose:
90    * 1. This allows the package name to be used as a file name
91    * ('/' is illegal due to being a path separator) with minimal
92    * munging.
93    * 2. This allows the package name to be used in .mk file because
94    * '%' is a special char and cannot be easily escaped in Makefile.
95    *
96    * This is a workround for test purpose.
97    * Only package name is used because activity name varies on
98    * different testing framework.
99    * Hopefully, the double "@@" and "^^" are not used in other cases.
100    */
101   // {"com.foo.bar", ".A%"} -> "com.foo.bar"
ToMakeFileSafeEncodedPkgStringAppComponentName102   std::string ToMakeFileSafeEncodedPkgString() const {
103     std::string s = package;
104     Replace(s, "/", "@@");
105     Replace(s, "%", "^^");
106     return s;
107   }
108 
109  private:
ReplaceAppComponentName110   static bool Replace(std::string& str, const std::string& from, const std::string& to) {
111     // TODO: call in a loop to replace all occurrences, not just the first one.
112     const size_t start_pos = str.find(from);
113     if (start_pos == std::string::npos) {
114       return false;
115     }
116 
117     str.replace(start_pos, from.length(), to);
118 
119     return true;
120 }
121 };
122 
123 inline std::ostream& operator<<(std::ostream& os, const AppComponentName& name) {
124   os << name.ToString();
125   return os;
126 }
127 
128 }  // namespace iorap::db
129 
130 #endif  // IORAP_SRC_DB_APP_COMPONENT_NAME_H_
131