blob: 9aa5a61a6e976e1448a115defba28d6ed85c79cd [file] [log] [blame]
Andreas Huber1aec3972016-08-26 09:26:32 -07001/*
2 * Copyright (C) 2016 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
Andreas Huber84f89de2016-07-28 15:39:51 -070017#include "FQName.h"
18
19#include <android-base/logging.h>
20#include <regex>
21
22#define RE_COMPONENT "[a-zA-Z_][a-zA-Z_0-9]*"
23#define RE_PATH RE_COMPONENT "([.]" RE_COMPONENT ")*"
24#define RE_VERSION "@[0-9]+[.][0-9]+"
25
26static const std::regex kRE1("(" RE_PATH ")(" RE_VERSION ")?::(" RE_PATH ")");
27static const std::regex kRE2("(" RE_VERSION ")::(" RE_PATH ")");
Andreas Huberda51b8e2016-07-28 16:00:57 -070028static const std::regex kRE3("(" RE_PATH ")(" RE_VERSION ")");
29static const std::regex kRE4(RE_PATH);
Andreas Huber84f89de2016-07-28 15:39:51 -070030
31namespace android {
32
Andreas Huberda51b8e2016-07-28 16:00:57 -070033FQName::FQName()
34 : mValid(false) {
35}
36
Andreas Huber84f89de2016-07-28 15:39:51 -070037FQName::FQName(const std::string &s)
38 : mValid(false) {
39 setTo(s);
40}
41
Andreas Huber68f24592016-07-29 14:53:48 -070042FQName::FQName(
43 const std::string &package,
44 const std::string &version,
45 const std::string &name)
46 : mValid(true),
47 mPackage(package),
48 mVersion(version),
49 mName(name) {
50}
51
Andreas Huber84f89de2016-07-28 15:39:51 -070052bool FQName::isValid() const {
53 return mValid;
54}
55
Andreas Huber68f24592016-07-29 14:53:48 -070056bool FQName::isFullyQualified() const {
57 return !mPackage.empty() && !mVersion.empty() && !mName.empty();
58}
59
Andreas Huber84f89de2016-07-28 15:39:51 -070060bool FQName::setTo(const std::string &s) {
61 mPackage.clear();
62 mVersion.clear();
63 mName.clear();
64
65 mValid = true;
66
67 std::smatch match;
68 if (std::regex_match(s, match, kRE1)) {
69 CHECK_EQ(match.size(), 6u);
70
71 mPackage = match.str(1);
72 mVersion = match.str(3);
73 mName = match.str(4);
74 } else if (std::regex_match(s, match, kRE2)) {
75 CHECK_EQ(match.size(), 4u);
76
77 mVersion = match.str(1);
78 mName = match.str(2);
79 } else if (std::regex_match(s, match, kRE3)) {
Andreas Huberda51b8e2016-07-28 16:00:57 -070080 CHECK_EQ(match.size(), 4u);
81
82 mPackage = match.str(1);
83 mVersion = match.str(3);
84 } else if (std::regex_match(s, match, kRE4)) {
Andreas Huber84f89de2016-07-28 15:39:51 -070085 mName = match.str(0);
86 } else {
87 mValid = false;
88 }
89
90 return isValid();
91}
92
93std::string FQName::package() const {
94 return mPackage;
95}
96
97std::string FQName::version() const {
98 return mVersion;
99}
100
101std::string FQName::name() const {
102 return mName;
103}
104
105void FQName::applyDefaults(
106 const std::string &defaultPackage,
107 const std::string &defaultVersion) {
108 if (mPackage.empty()) {
109 mPackage = defaultPackage;
110 }
111
112 if (mVersion.empty()) {
113 mVersion = defaultVersion;
114 }
115}
116
Andreas Huber68f24592016-07-29 14:53:48 -0700117std::string FQName::string() const {
Andreas Huber84f89de2016-07-28 15:39:51 -0700118 CHECK(mValid);
119
Andreas Huber5345ec22016-07-29 13:33:27 -0700120 std::string out;
Andreas Huber84f89de2016-07-28 15:39:51 -0700121 out.append(mPackage);
122 out.append(mVersion);
Andreas Huberda51b8e2016-07-28 16:00:57 -0700123 if (!mName.empty()) {
124 if (!mPackage.empty() || !mVersion.empty()) {
125 out.append("::");
126 }
127 out.append(mName);
Andreas Huber84f89de2016-07-28 15:39:51 -0700128 }
Andreas Huber84f89de2016-07-28 15:39:51 -0700129
130 return out;
131}
132
Andreas Huberda51b8e2016-07-28 16:00:57 -0700133void FQName::print() const {
134 if (!mValid) {
135 LOG(INFO) << "INVALID";
136 return;
137 }
138
Andreas Huber68f24592016-07-29 14:53:48 -0700139 LOG(INFO) << string();
140}
141
142bool FQName::operator<(const FQName &other) const {
143 return string() < other.string();
Andreas Huberda51b8e2016-07-28 16:00:57 -0700144}
145
Andreas Huberd2943e12016-08-05 11:59:31 -0700146bool FQName::operator==(const FQName &other) const {
147 return string() == other.string();
148}
149
Andreas Huber0e00de42016-08-03 09:56:02 -0700150static void SplitString(
151 const std::string &s, char c, std::vector<std::string> *components) {
152 components->clear();
153
154 size_t startPos = 0;
155 size_t matchPos;
156 while ((matchPos = s.find(c, startPos)) != std::string::npos) {
157 components->push_back(s.substr(startPos, matchPos - startPos));
158 startPos = matchPos + 1;
159 }
160
161 if (startPos + 1 < s.length()) {
162 components->push_back(s.substr(startPos));
163 }
164}
165
Andreas Huberd2943e12016-08-05 11:59:31 -0700166// static
167std::string FQName::JoinStrings(
Andreas Huber0e00de42016-08-03 09:56:02 -0700168 const std::vector<std::string> &components,
169 const std::string &separator) {
170 std::string out;
171 bool first = true;
172 for (const auto &component : components) {
173 if (!first) {
174 out += separator;
175 }
176 out += component;
177
178 first = false;
179 }
180
181 return out;
182}
183
184std::string FQName::cppNamespace() const {
185 std::vector<std::string> components;
186 getPackageAndVersionComponents(&components, true /* cpp_compatible */);
187
188 std::string out = "::";
189 out += JoinStrings(components, "::");
190
191 return out;
192}
193
194std::string FQName::cppName() const {
195 std::string out = cppNamespace();
196
197 std::vector<std::string> components;
198 SplitString(name(), '.', &components);
199 out += "::";
200 out += JoinStrings(components, "::");
201
202 return out;
203}
204
Andreas Huber2831d512016-08-15 09:33:47 -0700205std::string FQName::javaPackage() const {
206 std::vector<std::string> components;
207 getPackageAndVersionComponents(&components, true /* cpp_compatible */);
208
209 return JoinStrings(components, ".");
210}
211
212std::string FQName::javaName() const {
213 return javaPackage() + "." + name();
214}
215
Andreas Huber0e00de42016-08-03 09:56:02 -0700216void FQName::getPackageComponents(std::vector<std::string> *components) const {
217 SplitString(package(), '.', components);
218}
219
220void FQName::getPackageAndVersionComponents(
221 std::vector<std::string> *components,
222 bool cpp_compatible) const {
223 getPackageComponents(components);
224
225 const std::string packageVersion = version();
226 CHECK(packageVersion[0] == '@');
227
228 if (!cpp_compatible) {
229 components->push_back(packageVersion.substr(1));
230 return;
231 }
232
233 const size_t dotPos = packageVersion.find('.');
234
235 // Form "Vmajor_minor".
236 std::string versionString = "V";
237 versionString.append(packageVersion.substr(1, dotPos - 1));
238 versionString.append("_");
239 versionString.append(packageVersion.substr(dotPos + 1));
240
241 components->push_back(versionString);
242}
243
Andreas Huber39fa7182016-08-19 14:27:33 -0700244bool FQName::endsWith(const FQName &other) const {
245 std::string s1 = string();
246 std::string s2 = other.string();
247
248 size_t pos = s1.rfind(s2);
249 if (pos == std::string::npos || pos + s2.size() != s1.size()) {
250 return false;
251 }
252
253 if (pos > 0) {
254 // A match is only a match if it is preceded by a "boundary", i.e.
255 // we perform a component-wise match from the end.
256 // "az" is not a match for "android.hardware.foo@1.0::IFoo.bar.baz",
257 // "baz", "bar.baz", "IFoo.bar.baz" are.
258
259 char separator = s1[pos - 1];
260 if (separator != '.' && separator != ':') {
261 return false;
262 }
263 }
264
265 return true;
266}
267
Andreas Huber84f89de2016-07-28 15:39:51 -0700268} // namespace android
269