blob: 6f6fd09fb954e0c5440f73261b58ef6311e48ee5 [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>
Iliyan Malchev800273d2016-09-02 15:25:07 -070020#include <iostream>
Andreas Huber84f89de2016-07-28 15:39:51 -070021#include <regex>
Iliyan Malchev800273d2016-09-02 15:25:07 -070022#include <sstream>
Andreas Huber84f89de2016-07-28 15:39:51 -070023
24#define RE_COMPONENT "[a-zA-Z_][a-zA-Z_0-9]*"
25#define RE_PATH RE_COMPONENT "([.]" RE_COMPONENT ")*"
26#define RE_VERSION "@[0-9]+[.][0-9]+"
27
28static const std::regex kRE1("(" RE_PATH ")(" RE_VERSION ")?::(" RE_PATH ")");
29static const std::regex kRE2("(" RE_VERSION ")::(" RE_PATH ")");
Andreas Huberda51b8e2016-07-28 16:00:57 -070030static const std::regex kRE3("(" RE_PATH ")(" RE_VERSION ")");
31static const std::regex kRE4(RE_PATH);
Andreas Huber84f89de2016-07-28 15:39:51 -070032
33namespace android {
34
Andreas Huberda51b8e2016-07-28 16:00:57 -070035FQName::FQName()
36 : mValid(false) {
37}
38
Andreas Huber84f89de2016-07-28 15:39:51 -070039FQName::FQName(const std::string &s)
40 : mValid(false) {
41 setTo(s);
42}
43
Andreas Huber68f24592016-07-29 14:53:48 -070044FQName::FQName(
45 const std::string &package,
46 const std::string &version,
47 const std::string &name)
48 : mValid(true),
49 mPackage(package),
50 mVersion(version),
51 mName(name) {
52}
53
Andreas Huber84f89de2016-07-28 15:39:51 -070054bool FQName::isValid() const {
55 return mValid;
56}
57
Andreas Huber68f24592016-07-29 14:53:48 -070058bool FQName::isFullyQualified() const {
59 return !mPackage.empty() && !mVersion.empty() && !mName.empty();
60}
61
Andreas Huber84f89de2016-07-28 15:39:51 -070062bool FQName::setTo(const std::string &s) {
63 mPackage.clear();
64 mVersion.clear();
65 mName.clear();
66
67 mValid = true;
68
69 std::smatch match;
70 if (std::regex_match(s, match, kRE1)) {
71 CHECK_EQ(match.size(), 6u);
72
73 mPackage = match.str(1);
74 mVersion = match.str(3);
75 mName = match.str(4);
76 } else if (std::regex_match(s, match, kRE2)) {
77 CHECK_EQ(match.size(), 4u);
78
79 mVersion = match.str(1);
80 mName = match.str(2);
81 } else if (std::regex_match(s, match, kRE3)) {
Andreas Huberda51b8e2016-07-28 16:00:57 -070082 CHECK_EQ(match.size(), 4u);
83
84 mPackage = match.str(1);
85 mVersion = match.str(3);
86 } else if (std::regex_match(s, match, kRE4)) {
Andreas Huber84f89de2016-07-28 15:39:51 -070087 mName = match.str(0);
88 } else {
89 mValid = false;
90 }
91
92 return isValid();
93}
94
95std::string FQName::package() const {
96 return mPackage;
97}
98
99std::string FQName::version() const {
100 return mVersion;
101}
102
103std::string FQName::name() const {
104 return mName;
105}
106
Iliyan Malchev800273d2016-09-02 15:25:07 -0700107std::vector<std::string> FQName::names() const {
108 std::vector<std::string> res {};
109 std::istringstream ss(name());
110 std::string s;
111 while (std::getline(ss, s, '.')) {
112 res.push_back(s);
113 }
114 return res;
115}
116
Andreas Huber84f89de2016-07-28 15:39:51 -0700117void FQName::applyDefaults(
118 const std::string &defaultPackage,
119 const std::string &defaultVersion) {
120 if (mPackage.empty()) {
121 mPackage = defaultPackage;
122 }
123
124 if (mVersion.empty()) {
125 mVersion = defaultVersion;
126 }
127}
128
Andreas Huber68f24592016-07-29 14:53:48 -0700129std::string FQName::string() const {
Andreas Huber84f89de2016-07-28 15:39:51 -0700130 CHECK(mValid);
131
Andreas Huber5345ec22016-07-29 13:33:27 -0700132 std::string out;
Andreas Huber84f89de2016-07-28 15:39:51 -0700133 out.append(mPackage);
134 out.append(mVersion);
Andreas Huberda51b8e2016-07-28 16:00:57 -0700135 if (!mName.empty()) {
136 if (!mPackage.empty() || !mVersion.empty()) {
137 out.append("::");
138 }
139 out.append(mName);
Andreas Huber84f89de2016-07-28 15:39:51 -0700140 }
Andreas Huber84f89de2016-07-28 15:39:51 -0700141
142 return out;
143}
144
Andreas Huberda51b8e2016-07-28 16:00:57 -0700145void FQName::print() const {
146 if (!mValid) {
147 LOG(INFO) << "INVALID";
148 return;
149 }
150
Andreas Huber68f24592016-07-29 14:53:48 -0700151 LOG(INFO) << string();
152}
153
154bool FQName::operator<(const FQName &other) const {
155 return string() < other.string();
Andreas Huberda51b8e2016-07-28 16:00:57 -0700156}
157
Andreas Huberd2943e12016-08-05 11:59:31 -0700158bool FQName::operator==(const FQName &other) const {
159 return string() == other.string();
160}
161
Andreas Huber0e00de42016-08-03 09:56:02 -0700162static void SplitString(
163 const std::string &s, char c, std::vector<std::string> *components) {
164 components->clear();
165
166 size_t startPos = 0;
167 size_t matchPos;
168 while ((matchPos = s.find(c, startPos)) != std::string::npos) {
169 components->push_back(s.substr(startPos, matchPos - startPos));
170 startPos = matchPos + 1;
171 }
172
173 if (startPos + 1 < s.length()) {
174 components->push_back(s.substr(startPos));
175 }
176}
177
Andreas Huberd2943e12016-08-05 11:59:31 -0700178// static
179std::string FQName::JoinStrings(
Andreas Huber0e00de42016-08-03 09:56:02 -0700180 const std::vector<std::string> &components,
181 const std::string &separator) {
182 std::string out;
183 bool first = true;
184 for (const auto &component : components) {
185 if (!first) {
186 out += separator;
187 }
188 out += component;
189
190 first = false;
191 }
192
193 return out;
194}
195
196std::string FQName::cppNamespace() const {
197 std::vector<std::string> components;
198 getPackageAndVersionComponents(&components, true /* cpp_compatible */);
199
200 std::string out = "::";
201 out += JoinStrings(components, "::");
202
203 return out;
204}
205
206std::string FQName::cppName() const {
207 std::string out = cppNamespace();
208
209 std::vector<std::string> components;
210 SplitString(name(), '.', &components);
211 out += "::";
212 out += JoinStrings(components, "::");
213
214 return out;
215}
216
Andreas Huber2831d512016-08-15 09:33:47 -0700217std::string FQName::javaPackage() const {
218 std::vector<std::string> components;
219 getPackageAndVersionComponents(&components, true /* cpp_compatible */);
220
221 return JoinStrings(components, ".");
222}
223
224std::string FQName::javaName() const {
225 return javaPackage() + "." + name();
226}
227
Andreas Huber0e00de42016-08-03 09:56:02 -0700228void FQName::getPackageComponents(std::vector<std::string> *components) const {
229 SplitString(package(), '.', components);
230}
231
232void FQName::getPackageAndVersionComponents(
233 std::vector<std::string> *components,
234 bool cpp_compatible) const {
235 getPackageComponents(components);
236
237 const std::string packageVersion = version();
238 CHECK(packageVersion[0] == '@');
239
240 if (!cpp_compatible) {
241 components->push_back(packageVersion.substr(1));
242 return;
243 }
244
245 const size_t dotPos = packageVersion.find('.');
246
247 // Form "Vmajor_minor".
248 std::string versionString = "V";
249 versionString.append(packageVersion.substr(1, dotPos - 1));
250 versionString.append("_");
251 versionString.append(packageVersion.substr(dotPos + 1));
252
253 components->push_back(versionString);
254}
255
Andreas Huber39fa7182016-08-19 14:27:33 -0700256bool FQName::endsWith(const FQName &other) const {
257 std::string s1 = string();
258 std::string s2 = other.string();
259
260 size_t pos = s1.rfind(s2);
261 if (pos == std::string::npos || pos + s2.size() != s1.size()) {
262 return false;
263 }
264
265 if (pos > 0) {
266 // A match is only a match if it is preceded by a "boundary", i.e.
267 // we perform a component-wise match from the end.
268 // "az" is not a match for "android.hardware.foo@1.0::IFoo.bar.baz",
269 // "baz", "bar.baz", "IFoo.bar.baz" are.
270
271 char separator = s1[pos - 1];
272 if (separator != '.' && separator != ':') {
273 return false;
274 }
275 }
276
277 return true;
278}
279
Andreas Huber84f89de2016-07-28 15:39:51 -0700280} // namespace android
281