1 /*
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
17 #include "FQName.h"
18
19 #include <android-base/logging.h>
20 #include <android-base/parseint.h>
21 #include <android-base/strings.h>
22 #include <iostream>
23 #include <regex>
24 #include <sstream>
25
26 #define RE_COMPONENT "[a-zA-Z_][a-zA-Z_0-9]*"
27 #define RE_PATH RE_COMPONENT "(?:[.]" RE_COMPONENT ")*"
28 #define RE_MAJOR "[0-9]+"
29 #define RE_MINOR "[0-9]+"
30
31 namespace android {
32
FQName()33 FQName::FQName() : mIsIdentifier(false) {}
34
parse(const std::string & s,FQName * into)35 bool FQName::parse(const std::string& s, FQName* into) {
36 return into->setTo(s);
37 }
38
FQName(const std::string & package,const std::string & version,const std::string & name,const std::string & valueName)39 FQName::FQName(const std::string& package, const std::string& version, const std::string& name,
40 const std::string& valueName) {
41 size_t majorVer, minorVer;
42 CHECK(parseVersion(version, &majorVer, &minorVer));
43 CHECK(setTo(package, majorVer, minorVer, name, valueName)) << string();
44 }
45
setTo(const std::string & package,size_t majorVer,size_t minorVer,const std::string & name,const std::string & valueName)46 bool FQName::setTo(const std::string& package, size_t majorVer, size_t minorVer,
47 const std::string& name, const std::string& valueName) {
48 mPackage = package;
49 mMajor = majorVer;
50 mMinor = minorVer;
51 mName = name;
52 mValueName = valueName;
53
54 FQName other;
55 if (!parse(string(), &other)) return false;
56 if ((*this) != other) return false;
57 mIsIdentifier = other.isIdentifier();
58 return true;
59 }
60
FQName(const FQName & other)61 FQName::FQName(const FQName& other)
62 : mIsIdentifier(other.mIsIdentifier),
63 mPackage(other.mPackage),
64 mMajor(other.mMajor),
65 mMinor(other.mMinor),
66 mName(other.mName),
67 mValueName(other.mValueName) {}
68
isIdentifier() const69 bool FQName::isIdentifier() const {
70 return mIsIdentifier;
71 }
72
isFullyQualified() const73 bool FQName::isFullyQualified() const {
74 return !mPackage.empty() && !version().empty() && !mName.empty();
75 }
76
isValidValueName() const77 bool FQName::isValidValueName() const {
78 return mIsIdentifier
79 || (!mName.empty() && !mValueName.empty());
80 }
81
isInterfaceName() const82 bool FQName::isInterfaceName() const {
83 return !mName.empty() && mName[0] == 'I' && mName.find('.') == std::string::npos;
84 }
85
setTo(const std::string & s)86 bool FQName::setTo(const std::string &s) {
87 // android.hardware.foo@1.0::IFoo.Type
88 static const std::regex kRE1("(" RE_PATH ")@(" RE_MAJOR ")[.](" RE_MINOR ")::(" RE_PATH ")");
89 // @1.0::IFoo.Type
90 static const std::regex kRE2("@(" RE_MAJOR ")[.](" RE_MINOR ")::(" RE_PATH ")");
91 // android.hardware.foo@1.0 (for package declaration and whole package import)
92 static const std::regex kRE3("(" RE_PATH ")@(" RE_MAJOR ")[.](" RE_MINOR ")");
93 // IFoo.Type
94 static const std::regex kRE4("(" RE_COMPONENT ")([.]" RE_COMPONENT ")+");
95 // Type (a plain identifier)
96 static const std::regex kRE5("(" RE_COMPONENT ")");
97
98 // android.hardware.foo@1.0::IFoo.Type:MY_ENUM_VALUE
99 static const std::regex kRE6("(" RE_PATH ")@(" RE_MAJOR ")[.](" RE_MINOR ")::(" RE_PATH
100 "):(" RE_COMPONENT ")");
101 // @1.0::IFoo.Type:MY_ENUM_VALUE
102 static const std::regex kRE7("@(" RE_MAJOR ")[.](" RE_MINOR ")::(" RE_PATH "):(" RE_COMPONENT
103 ")");
104 // IFoo.Type:MY_ENUM_VALUE
105 static const std::regex kRE8("(" RE_PATH "):(" RE_COMPONENT ")");
106
107 bool invalid = false;
108 clear();
109
110 std::smatch match;
111 if (std::regex_match(s, match, kRE1)) {
112 CHECK_EQ(match.size(), 5u);
113
114 mPackage = match.str(1);
115 invalid |= !parseVersion(match.str(2), match.str(3));
116 mName = match.str(4);
117 } else if (std::regex_match(s, match, kRE2)) {
118 CHECK_EQ(match.size(), 4u);
119
120 invalid |= !parseVersion(match.str(1), match.str(2));
121 mName = match.str(3);
122 } else if (std::regex_match(s, match, kRE3)) {
123 CHECK_EQ(match.size(), 4u);
124
125 mPackage = match.str(1);
126 invalid |= !parseVersion(match.str(2), match.str(3));
127 } else if (std::regex_match(s, match, kRE4)) {
128 mName = match.str(0);
129 } else if (std::regex_match(s, match, kRE5)) {
130 mIsIdentifier = true;
131 mName = match.str(0);
132 } else if (std::regex_match(s, match, kRE6)) {
133 CHECK_EQ(match.size(), 6u);
134
135 mPackage = match.str(1);
136 invalid |= !parseVersion(match.str(2), match.str(3));
137 mName = match.str(4);
138 mValueName = match.str(5);
139 } else if (std::regex_match(s, match, kRE7)) {
140 CHECK_EQ(match.size(), 5u);
141
142 invalid |= !parseVersion(match.str(1), match.str(2));
143 mName = match.str(3);
144 mValueName = match.str(4);
145 } else if (std::regex_match(s, match, kRE8)) {
146 CHECK_EQ(match.size(), 3u);
147
148 mName = match.str(1);
149 mValueName = match.str(2);
150 } else {
151 invalid = true;
152 }
153
154 // mValueName must go with mName.
155 CHECK(mValueName.empty() || !mName.empty());
156
157 // package without version is not allowed.
158 CHECK(invalid || mPackage.empty() || !version().empty());
159
160 return !invalid;
161 }
162
package() const163 const std::string& FQName::package() const {
164 return mPackage;
165 }
166
version() const167 std::string FQName::version() const {
168 if (!hasVersion()) {
169 return "";
170 }
171 return std::to_string(mMajor) + "." + std::to_string(mMinor);
172 }
173
sanitizedVersion() const174 std::string FQName::sanitizedVersion() const {
175 if (!hasVersion()) {
176 return "";
177 }
178 return "V" + std::to_string(mMajor) + "_" + std::to_string(mMinor);
179 }
180
atVersion() const181 std::string FQName::atVersion() const {
182 std::string v = version();
183 return v.empty() ? "" : ("@" + v);
184 }
185
clear()186 void FQName::clear() {
187 mIsIdentifier = false;
188 mPackage.clear();
189 clearVersion();
190 mName.clear();
191 mValueName.clear();
192 }
193
clearVersion(size_t * majorVer,size_t * minorVer)194 void FQName::clearVersion(size_t* majorVer, size_t* minorVer) {
195 *majorVer = *minorVer = 0;
196 }
197
parseVersion(const std::string & majorStr,const std::string & minorStr,size_t * majorVer,size_t * minorVer)198 bool FQName::parseVersion(const std::string& majorStr, const std::string& minorStr,
199 size_t* majorVer, size_t* minorVer) {
200 bool versionParseSuccess = ::android::base::ParseUint(majorStr, majorVer) &&
201 ::android::base::ParseUint(minorStr, minorVer);
202 if (!versionParseSuccess) {
203 LOG(ERROR) << "numbers in " << majorStr << "." << minorStr << " are out of range.";
204 }
205 return versionParseSuccess;
206 }
207
parseVersion(const std::string & v,size_t * majorVer,size_t * minorVer)208 bool FQName::parseVersion(const std::string& v, size_t* majorVer, size_t* minorVer) {
209 static const std::regex kREVer("(" RE_MAJOR ")[.](" RE_MINOR ")");
210
211 if (v.empty()) {
212 clearVersion(majorVer, minorVer);
213 return true;
214 }
215
216 std::smatch match;
217 if (!std::regex_match(v, match, kREVer)) {
218 return false;
219 }
220 CHECK_EQ(match.size(), 3u);
221
222 return parseVersion(match.str(1), match.str(2), majorVer, minorVer);
223 }
224
setVersion(const std::string & v)225 bool FQName::setVersion(const std::string& v) {
226 return parseVersion(v, &mMajor, &mMinor);
227 }
228
clearVersion()229 void FQName::clearVersion() {
230 clearVersion(&mMajor, &mMinor);
231 }
232
parseVersion(const std::string & majorStr,const std::string & minorStr)233 bool FQName::parseVersion(const std::string& majorStr, const std::string& minorStr) {
234 return parseVersion(majorStr, minorStr, &mMajor, &mMinor);
235 }
236
name() const237 const std::string& FQName::name() const {
238 return mName;
239 }
240
names() const241 std::vector<std::string> FQName::names() const {
242 std::vector<std::string> res {};
243 std::istringstream ss(name());
244 std::string s;
245 while (std::getline(ss, s, '.')) {
246 res.push_back(s);
247 }
248 return res;
249 }
250
valueName() const251 const std::string& FQName::valueName() const {
252 return mValueName;
253 }
254
typeName() const255 FQName FQName::typeName() const {
256 return FQName(mPackage, version(), mName);
257 }
258
applyDefaults(const std::string & defaultPackage,const std::string & defaultVersion)259 void FQName::applyDefaults(
260 const std::string &defaultPackage,
261 const std::string &defaultVersion) {
262
263 // package without version is not allowed.
264 CHECK(mPackage.empty() || !version().empty());
265
266 if (mPackage.empty()) {
267 mPackage = defaultPackage;
268 }
269
270 if (version().empty()) {
271 CHECK(setVersion(defaultVersion));
272 }
273 }
274
string() const275 std::string FQName::string() const {
276 std::string out;
277 out.append(mPackage);
278 out.append(atVersion());
279 if (!mName.empty()) {
280 if (!mPackage.empty() || !version().empty()) {
281 out.append("::");
282 }
283 out.append(mName);
284
285 if (!mValueName.empty()) {
286 out.append(":");
287 out.append(mValueName);
288 }
289 }
290
291 return out;
292 }
293
operator <(const FQName & other) const294 bool FQName::operator<(const FQName &other) const {
295 return string() < other.string();
296 }
297
operator ==(const FQName & other) const298 bool FQName::operator==(const FQName &other) const {
299 return string() == other.string();
300 }
301
operator !=(const FQName & other) const302 bool FQName::operator!=(const FQName &other) const {
303 return !(*this == other);
304 }
305
getInterfaceName() const306 const std::string& FQName::getInterfaceName() const {
307 CHECK(isInterfaceName()) << mName;
308
309 return mName;
310 }
311
getInterfaceBaseName() const312 std::string FQName::getInterfaceBaseName() const {
313 // cut off the leading 'I'.
314 return getInterfaceName().substr(1);
315 }
316
getInterfaceAdapterName() const317 std::string FQName::getInterfaceAdapterName() const {
318 return "A" + getInterfaceBaseName();
319 }
320
getInterfaceHwName() const321 std::string FQName::getInterfaceHwName() const {
322 return "IHw" + getInterfaceBaseName();
323 }
324
getInterfaceProxyName() const325 std::string FQName::getInterfaceProxyName() const {
326 return "BpHw" + getInterfaceBaseName();
327 }
328
getInterfaceStubName() const329 std::string FQName::getInterfaceStubName() const {
330 return "BnHw" + getInterfaceBaseName();
331 }
332
getInterfacePassthroughName() const333 std::string FQName::getInterfacePassthroughName() const {
334 return "Bs" + getInterfaceBaseName();
335 }
336
getInterfaceProxyFqName() const337 FQName FQName::getInterfaceProxyFqName() const {
338 return FQName(package(), version(), getInterfaceProxyName());
339 }
340
getInterfaceAdapterFqName() const341 FQName FQName::getInterfaceAdapterFqName() const {
342 return FQName(package(), version(), getInterfaceAdapterName());
343 }
344
getInterfaceStubFqName() const345 FQName FQName::getInterfaceStubFqName() const {
346 return FQName(package(), version(), getInterfaceStubName());
347 }
348
getInterfacePassthroughFqName() const349 FQName FQName::getInterfacePassthroughFqName() const {
350 return FQName(package(), version(), getInterfacePassthroughName());
351 }
352
getTypesForPackage() const353 FQName FQName::getTypesForPackage() const {
354 return FQName(package(), version(), "types");
355 }
356
getPackageAndVersion() const357 FQName FQName::getPackageAndVersion() const {
358 return FQName(package(), version(), "");
359 }
360
getTopLevelType() const361 FQName FQName::getTopLevelType() const {
362 auto idx = mName.find('.');
363
364 if (idx == std::string::npos) {
365 return *this;
366 }
367
368 return FQName(mPackage, version(), mName.substr(0, idx));
369 }
370
tokenName() const371 std::string FQName::tokenName() const {
372 std::vector<std::string> components;
373 getPackageAndVersionComponents(&components, true /* cpp_compatible */);
374
375 if (!mName.empty()) {
376 std::vector<std::string> nameComponents = base::Split(mName, ".");
377
378 components.insert(components.end(), nameComponents.begin(), nameComponents.end());
379 }
380
381 return base::Join(components, "_");
382 }
383
cppNamespace() const384 std::string FQName::cppNamespace() const {
385 std::vector<std::string> components;
386 getPackageAndVersionComponents(&components, true /* cpp_compatible */);
387
388 std::string out = "::";
389 out += base::Join(components, "::");
390
391 return out;
392 }
393
cppLocalName() const394 std::string FQName::cppLocalName() const {
395 std::vector<std::string> components = base::Split(mName, ".");
396
397 return base::Join(components, "::")
398 + (mValueName.empty() ? "" : ("::" + mValueName));
399 }
400
cppName() const401 std::string FQName::cppName() const {
402 std::string out = cppNamespace();
403
404 std::vector<std::string> components = base::Split(name(), ".");
405 out += "::";
406 out += base::Join(components, "::");
407 if (!mValueName.empty()) {
408 out += "::" + mValueName;
409 }
410
411 return out;
412 }
413
javaPackage() const414 std::string FQName::javaPackage() const {
415 std::vector<std::string> components;
416 getPackageAndVersionComponents(&components, true /* cpp_compatible */);
417
418 return base::Join(components, ".");
419 }
420
javaName() const421 std::string FQName::javaName() const {
422 return javaPackage() + "." + name()
423 + (mValueName.empty() ? "" : ("." + mValueName));
424 }
425
getPackageComponents(std::vector<std::string> * components) const426 void FQName::getPackageComponents(std::vector<std::string> *components) const {
427 *components = base::Split(package(), ".");
428 }
429
getPackageAndVersionComponents(std::vector<std::string> * components,bool cpp_compatible) const430 void FQName::getPackageAndVersionComponents(
431 std::vector<std::string> *components,
432 bool cpp_compatible) const {
433 getPackageComponents(components);
434
435 if (!hasVersion()) {
436 LOG(WARNING) << "FQName: getPackageAndVersionComponents expects version.";
437 return;
438 }
439
440 if (!cpp_compatible) {
441 components->push_back(std::to_string(getPackageMajorVersion()) +
442 "." + std::to_string(getPackageMinorVersion()));
443 return;
444 }
445
446 components->push_back(sanitizedVersion());
447 }
448
hasVersion() const449 bool FQName::hasVersion() const {
450 return mMajor > 0;
451 }
452
getVersion() const453 std::pair<size_t, size_t> FQName::getVersion() const {
454 return {mMajor, mMinor};
455 }
456
withVersion(size_t major,size_t minor) const457 FQName FQName::withVersion(size_t major, size_t minor) const {
458 FQName ret(*this);
459 ret.mMajor = major;
460 ret.mMinor = minor;
461 return ret;
462 }
463
getPackageMajorVersion() const464 size_t FQName::getPackageMajorVersion() const {
465 CHECK(hasVersion()) << "FQName: No version exists at getPackageMajorVersion(). "
466 << "Did you check hasVersion()?";
467 return mMajor;
468 }
469
getPackageMinorVersion() const470 size_t FQName::getPackageMinorVersion() const {
471 CHECK(hasVersion()) << "FQName: No version exists at getPackageMinorVersion(). "
472 << "Did you check hasVersion()?";
473 return mMinor;
474 }
475
endsWith(const FQName & other) const476 bool FQName::endsWith(const FQName &other) const {
477 std::string s1 = string();
478 std::string s2 = other.string();
479
480 size_t pos = s1.rfind(s2);
481 if (pos == std::string::npos || pos + s2.size() != s1.size()) {
482 return false;
483 }
484
485 // A match is only a match if it is preceded by a "boundary", i.e.
486 // we perform a component-wise match from the end.
487 // "az" is not a match for "android.hardware.foo@1.0::IFoo.bar.baz",
488 // "baz", "bar.baz", "IFoo.bar.baz", "@1.0::IFoo.bar.baz" are.
489 if (pos == 0) {
490 // matches "android.hardware.foo@1.0::IFoo.bar.baz"
491 return true;
492 }
493
494 if (s1[pos - 1] == '.') {
495 // matches "baz" and "bar.baz"
496 return true;
497 }
498
499 if (s1[pos - 1] == ':') {
500 // matches "IFoo.bar.baz"
501 return true;
502 }
503
504 if (s1[pos] == '@') {
505 // matches "@1.0::IFoo.bar.baz"
506 return true;
507 }
508
509 return false;
510 }
511
inPackage(const std::string & package) const512 bool FQName::inPackage(const std::string &package) const {
513 std::vector<std::string> components;
514 getPackageComponents(&components);
515
516 std::vector<std::string> inComponents = base::Split(package, ".");
517
518 if (inComponents.size() > components.size()) {
519 return false;
520 }
521
522 for (size_t i = 0; i < inComponents.size(); i++) {
523 if (inComponents[i] != components[i]) {
524 return false;
525 }
526 }
527
528 return true;
529 }
530
downRev() const531 FQName FQName::downRev() const {
532 FQName ret(*this);
533 CHECK(ret.mMinor > 0);
534 ret.mMinor--;
535 return ret;
536 }
537
538 const FQName gIBaseFqName = FQName("android.hidl.base", "1.0", "IBase");
539 const FQName gIManagerFqName = FQName("android.hidl.manager", "1.0", "IServiceManager");
540
541 } // namespace android
542
543