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 <sstream>
24
25 namespace android {
26
FQName()27 FQName::FQName() : mIsIdentifier(false) {}
28
parse(const std::string & s,FQName * into)29 bool FQName::parse(const std::string& s, FQName* into) {
30 return into->setTo(s);
31 }
32
FQName(const std::string & package,const std::string & version,const std::string & name,const std::string & valueName)33 FQName::FQName(const std::string& package, const std::string& version, const std::string& name,
34 const std::string& valueName) {
35 size_t majorVer, minorVer;
36 CHECK(parseVersion(version, &majorVer, &minorVer));
37 CHECK(setTo(package, majorVer, minorVer, name, valueName)) << string();
38 }
39
setTo(const std::string & package,size_t majorVer,size_t minorVer,const std::string & name,const std::string & valueName)40 bool FQName::setTo(const std::string& package, size_t majorVer, size_t minorVer,
41 const std::string& name, const std::string& valueName) {
42 mPackage = package;
43 mMajor = majorVer;
44 mMinor = minorVer;
45 mName = name;
46 mValueName = valueName;
47
48 FQName other;
49 if (!parse(string(), &other)) return false;
50 if ((*this) != other) return false;
51 mIsIdentifier = other.isIdentifier();
52 return true;
53 }
54
isIdentifier() const55 bool FQName::isIdentifier() const {
56 return mIsIdentifier;
57 }
58
isFullyQualified() const59 bool FQName::isFullyQualified() const {
60 return !mPackage.empty() && !version().empty() && !mName.empty();
61 }
62
isValidValueName() const63 bool FQName::isValidValueName() const {
64 return mIsIdentifier
65 || (!mName.empty() && !mValueName.empty());
66 }
67
isInterfaceName() const68 bool FQName::isInterfaceName() const {
69 return !mName.empty() && mName[0] == 'I' && mName.find('.') == std::string::npos;
70 }
71
isIdentStart(char a)72 static inline bool isIdentStart(char a) {
73 return ('a' <= a && a <= 'z') || ('A' <= a && a <= 'Z') || a == '_';
74 }
isLeadingDigit(char a)75 static inline bool isLeadingDigit(char a) {
76 return '1' <= a && a <= '9';
77 }
isDigit(char a)78 static inline bool isDigit(char a) {
79 return '0' <= a && a <= '9';
80 }
isIdentBody(char a)81 static inline bool isIdentBody(char a) {
82 return isIdentStart(a) || isDigit(a);
83 }
84
85 // returns pointer to end of [a-zA-Z_][a-zA-Z0-9_]*
eatIdent(const char * l,const char * end)86 static const char* eatIdent(const char* l, const char* end) {
87 if (!(l < end && isIdentStart(*l++))) return nullptr;
88 while (l < end && isIdentBody(*l)) l++;
89 return l;
90 }
91
92 // returns pointer to end of <ident>(\.<ident>)*
eatPackage(const char * l,const char * end)93 static const char* eatPackage(const char* l, const char* end) {
94 if ((l = eatIdent(l, end)) == nullptr) return nullptr;
95
96 while (l < end && *l == '.') {
97 l++;
98 if ((l = eatIdent(l, end)) == nullptr) return nullptr;
99 }
100 return l;
101 }
102
103 // returns pointer to end of [1-9][0-9]*|0
eatNumber(const char * l,const char * end)104 static const char* eatNumber(const char* l, const char* end) {
105 if (!(l < end)) return nullptr;
106 if (*l == '0') return l + 1;
107 if (!isLeadingDigit(*l++)) return nullptr;
108 while (l < end && isDigit(*l)) l++;
109 return l;
110 }
111
setTo(const std::string & s)112 bool FQName::setTo(const std::string &s) {
113 clear();
114
115 if (s.empty()) return false;
116
117 const char* l = s.c_str();
118 const char* end = l + s.size();
119 // android.hardware.foo@10.12::IFoo.Type:MY_ENUM_VALUE
120 // S ES ES E S ES E
121 //
122 // S - start pointer
123 // E - end pointer
124
125 struct StartEnd {
126 const char* start = nullptr;
127 const char* end = nullptr;
128
129 std::string string() {
130 if (start == nullptr) return std::string();
131 return std::string(start, end - start);
132 }
133 };
134 StartEnd package, major, minor, name, type;
135
136 if (l < end && isIdentStart(*l)) {
137 package.start = l;
138 if ((package.end = l = eatPackage(l, end)) == nullptr) return false;
139 }
140 if (l < end && *l == '@') {
141 l++;
142
143 major.start = l;
144 if ((major.end = l = eatNumber(l, end)) == nullptr) return false;
145
146 if (!(l < end && *l++ == '.')) return false;
147
148 minor.start = l;
149 if ((minor.end = l = eatNumber(l, end)) == nullptr) return false;
150 }
151 if (l < end && *l == ':') {
152 l++;
153 if (l < end && *l == ':') {
154 l++;
155 name.start = l;
156 if ((name.end = l = eatPackage(l, end)) == nullptr) return false;
157 if (l < end && *l++ == ':') {
158 type.start = l;
159 if ((type.end = l = eatIdent(l, end)) == nullptr) return false;
160 }
161 } else {
162 type.start = l;
163 if ((type.end = l = eatIdent(l, end)) == nullptr) return false;
164 }
165 }
166
167 if (l < end) return false;
168
169 CHECK((major.start == nullptr) == (minor.start == nullptr));
170
171 // if we only parse a package, consider this to be a name
172 if (name.start == nullptr && major.start == nullptr) {
173 name.start = package.start;
174 name.end = package.end;
175 package.start = package.end = nullptr;
176 }
177
178 // failures after this goto fail to clear
179 mName = name.string();
180 mPackage = package.string();
181 mValueName = type.string();
182
183 if (major.start != nullptr) {
184 if (!parseVersion(major.string(), minor.string(), &mMajor, &mMinor)) goto fail;
185 } else if (mPackage.empty() && mValueName.empty() &&
186 name.end == eatIdent(name.start, name.end)) {
187 // major.start == nullptr
188 mIsIdentifier = true;
189 }
190
191 if (!mValueName.empty() && mName.empty()) goto fail;
192 if (!mPackage.empty() && version().empty()) goto fail;
193
194 return true;
195 fail:
196 clear();
197 return false;
198 }
199
getRelativeFQName(const FQName & relativeTo) const200 std::string FQName::getRelativeFQName(const FQName& relativeTo) const {
201 if (relativeTo.mPackage != mPackage) {
202 return string();
203 }
204
205 // Package is the same
206 std::string out;
207 if (relativeTo.version() != version()) {
208 out.append(atVersion());
209 if (!mName.empty() && !version().empty()) {
210 out.append("::");
211 }
212 }
213
214 if (!mName.empty()) {
215 out.append(mName);
216 if (!mValueName.empty()) {
217 out.append(":");
218 out.append(mValueName);
219 }
220 }
221
222 return out;
223 }
224
package() const225 const std::string& FQName::package() const {
226 return mPackage;
227 }
228
version() const229 std::string FQName::version() const {
230 if (!hasVersion()) {
231 return "";
232 }
233 return std::to_string(mMajor) + "." + std::to_string(mMinor);
234 }
235
sanitizedVersion() const236 std::string FQName::sanitizedVersion() const {
237 if (!hasVersion()) {
238 return "";
239 }
240 return "V" + std::to_string(mMajor) + "_" + std::to_string(mMinor);
241 }
242
atVersion() const243 std::string FQName::atVersion() const {
244 std::string v = version();
245 return v.empty() ? "" : ("@" + v);
246 }
247
clear()248 void FQName::clear() {
249 mIsIdentifier = false;
250 mPackage.clear();
251 clearVersion();
252 mName.clear();
253 mValueName.clear();
254 }
255
clearVersion(size_t * majorVer,size_t * minorVer)256 void FQName::clearVersion(size_t* majorVer, size_t* minorVer) {
257 *majorVer = *minorVer = 0;
258 }
259
parseVersion(const std::string & majorStr,const std::string & minorStr,size_t * majorVer,size_t * minorVer)260 bool FQName::parseVersion(const std::string& majorStr, const std::string& minorStr,
261 size_t* majorVer, size_t* minorVer) {
262 bool versionParseSuccess = ::android::base::ParseUint(majorStr, majorVer) &&
263 ::android::base::ParseUint(minorStr, minorVer);
264 if (!versionParseSuccess) {
265 LOG(ERROR) << "numbers in " << majorStr << "." << minorStr << " are out of range.";
266 }
267 return versionParseSuccess;
268 }
269
parseVersion(const std::string & v,size_t * majorVer,size_t * minorVer)270 bool FQName::parseVersion(const std::string& v, size_t* majorVer, size_t* minorVer) {
271 if (v.empty()) {
272 clearVersion(majorVer, minorVer);
273 return true;
274 }
275
276 std::vector<std::string> vs = base::Split(v, ".");
277 if (vs.size() != 2) return false;
278 return parseVersion(vs[0], vs[1], majorVer, minorVer);
279 }
280
setVersion(const std::string & v)281 bool FQName::setVersion(const std::string& v) {
282 return parseVersion(v, &mMajor, &mMinor);
283 }
284
clearVersion()285 void FQName::clearVersion() {
286 clearVersion(&mMajor, &mMinor);
287 }
288
parseVersion(const std::string & majorStr,const std::string & minorStr)289 bool FQName::parseVersion(const std::string& majorStr, const std::string& minorStr) {
290 return parseVersion(majorStr, minorStr, &mMajor, &mMinor);
291 }
292
name() const293 const std::string& FQName::name() const {
294 return mName;
295 }
296
names() const297 std::vector<std::string> FQName::names() const {
298 std::vector<std::string> res {};
299 std::istringstream ss(name());
300 std::string s;
301 while (std::getline(ss, s, '.')) {
302 res.push_back(s);
303 }
304 return res;
305 }
306
valueName() const307 const std::string& FQName::valueName() const {
308 return mValueName;
309 }
310
typeName() const311 FQName FQName::typeName() const {
312 return FQName(mPackage, version(), mName);
313 }
314
applyDefaults(const std::string & defaultPackage,const std::string & defaultVersion)315 void FQName::applyDefaults(
316 const std::string &defaultPackage,
317 const std::string &defaultVersion) {
318
319 // package without version is not allowed.
320 CHECK(mPackage.empty() || !version().empty());
321
322 if (mPackage.empty()) {
323 mPackage = defaultPackage;
324 }
325
326 if (version().empty()) {
327 CHECK(setVersion(defaultVersion));
328 }
329 }
330
string() const331 std::string FQName::string() const {
332 std::string out;
333 out.append(mPackage);
334 out.append(atVersion());
335 if (!mName.empty()) {
336 if (!mPackage.empty() || !version().empty()) {
337 out.append("::");
338 }
339 out.append(mName);
340
341 if (!mValueName.empty()) {
342 out.append(":");
343 out.append(mValueName);
344 }
345 }
346
347 return out;
348 }
349
operator <(const FQName & other) const350 bool FQName::operator<(const FQName &other) const {
351 return string() < other.string();
352 }
353
operator ==(const FQName & other) const354 bool FQName::operator==(const FQName &other) const {
355 return string() == other.string();
356 }
357
operator !=(const FQName & other) const358 bool FQName::operator!=(const FQName &other) const {
359 return !(*this == other);
360 }
361
getInterfaceName() const362 const std::string& FQName::getInterfaceName() const {
363 CHECK(isInterfaceName()) << mName;
364
365 return mName;
366 }
367
getInterfaceBaseName() const368 std::string FQName::getInterfaceBaseName() const {
369 // cut off the leading 'I'.
370 return getInterfaceName().substr(1);
371 }
372
getInterfaceAdapterName() const373 std::string FQName::getInterfaceAdapterName() const {
374 return "A" + getInterfaceBaseName();
375 }
376
getInterfaceHwName() const377 std::string FQName::getInterfaceHwName() const {
378 return "IHw" + getInterfaceBaseName();
379 }
380
getInterfaceProxyName() const381 std::string FQName::getInterfaceProxyName() const {
382 return "BpHw" + getInterfaceBaseName();
383 }
384
getInterfaceStubName() const385 std::string FQName::getInterfaceStubName() const {
386 return "BnHw" + getInterfaceBaseName();
387 }
388
getInterfacePassthroughName() const389 std::string FQName::getInterfacePassthroughName() const {
390 return "Bs" + getInterfaceBaseName();
391 }
392
getInterfaceProxyFqName() const393 FQName FQName::getInterfaceProxyFqName() const {
394 return FQName(package(), version(), getInterfaceProxyName());
395 }
396
getInterfaceAdapterFqName() const397 FQName FQName::getInterfaceAdapterFqName() const {
398 return FQName(package(), version(), getInterfaceAdapterName());
399 }
400
getInterfaceStubFqName() const401 FQName FQName::getInterfaceStubFqName() const {
402 return FQName(package(), version(), getInterfaceStubName());
403 }
404
getInterfacePassthroughFqName() const405 FQName FQName::getInterfacePassthroughFqName() const {
406 return FQName(package(), version(), getInterfacePassthroughName());
407 }
408
getTypesForPackage() const409 FQName FQName::getTypesForPackage() const {
410 return FQName(package(), version(), "types");
411 }
412
getPackageAndVersion() const413 FQName FQName::getPackageAndVersion() const {
414 return FQName(package(), version(), "");
415 }
416
getTopLevelType() const417 FQName FQName::getTopLevelType() const {
418 auto idx = mName.find('.');
419
420 if (idx == std::string::npos) {
421 return *this;
422 }
423
424 return FQName(mPackage, version(), mName.substr(0, idx));
425 }
426
tokenName() const427 std::string FQName::tokenName() const {
428 std::vector<std::string> components = getPackageAndVersionComponents(true /* sanitized */);
429
430 if (!mName.empty()) {
431 std::vector<std::string> nameComponents = base::Split(mName, ".");
432
433 components.insert(components.end(), nameComponents.begin(), nameComponents.end());
434 }
435
436 return base::Join(components, "_");
437 }
438
cppNamespace() const439 std::string FQName::cppNamespace() const {
440 std::vector<std::string> components = getPackageAndVersionComponents(true /* sanitized */);
441 return "::" + base::Join(components, "::");
442 }
443
cppLocalName() const444 std::string FQName::cppLocalName() const {
445 std::vector<std::string> components = base::Split(mName, ".");
446
447 return base::Join(components, "::")
448 + (mValueName.empty() ? "" : ("::" + mValueName));
449 }
450
cppName() const451 std::string FQName::cppName() const {
452 std::string out = cppNamespace();
453
454 std::vector<std::string> components = base::Split(name(), ".");
455 out += "::";
456 out += base::Join(components, "::");
457 if (!mValueName.empty()) {
458 out += "::" + mValueName;
459 }
460
461 return out;
462 }
463
javaPackage() const464 std::string FQName::javaPackage() const {
465 std::vector<std::string> components = getPackageAndVersionComponents(true /* sanitized */);
466 return base::Join(components, ".");
467 }
468
javaName() const469 std::string FQName::javaName() const {
470 return javaPackage() + "." + name()
471 + (mValueName.empty() ? "" : ("." + mValueName));
472 }
473
getPackageComponents() const474 std::vector<std::string> FQName::getPackageComponents() const {
475 return base::Split(package(), ".");
476 }
477
getPackageAndVersionComponents(bool sanitized) const478 std::vector<std::string> FQName::getPackageAndVersionComponents(bool sanitized) const {
479 CHECK(hasVersion()) << string() << ": getPackageAndVersionComponents expects version.";
480
481 std::vector<std::string> components = getPackageComponents();
482 if (sanitized) {
483 components.push_back(sanitizedVersion());
484 } else {
485 components.push_back(version());
486 }
487 return components;
488 }
489
hasVersion() const490 bool FQName::hasVersion() const {
491 return mMajor > 0;
492 }
493
getVersion() const494 std::pair<size_t, size_t> FQName::getVersion() const {
495 return {mMajor, mMinor};
496 }
497
withVersion(size_t major,size_t minor) const498 FQName FQName::withVersion(size_t major, size_t minor) const {
499 FQName ret(*this);
500 ret.mMajor = major;
501 ret.mMinor = minor;
502 return ret;
503 }
504
getPackageMajorVersion() const505 size_t FQName::getPackageMajorVersion() const {
506 CHECK(hasVersion()) << "FQName: No version exists at getPackageMajorVersion(). "
507 << "Did you check hasVersion()?";
508 return mMajor;
509 }
510
getPackageMinorVersion() const511 size_t FQName::getPackageMinorVersion() const {
512 CHECK(hasVersion()) << "FQName: No version exists at getPackageMinorVersion(). "
513 << "Did you check hasVersion()?";
514 return mMinor;
515 }
516
endsWith(const FQName & other) const517 bool FQName::endsWith(const FQName &other) const {
518 std::string s1 = string();
519 std::string s2 = other.string();
520
521 size_t pos = s1.rfind(s2);
522 if (pos == std::string::npos || pos + s2.size() != s1.size()) {
523 return false;
524 }
525
526 // A match is only a match if it is preceded by a "boundary", i.e.
527 // we perform a component-wise match from the end.
528 // "az" is not a match for "android.hardware.foo@1.0::IFoo.bar.baz",
529 // "baz", "bar.baz", "IFoo.bar.baz", "@1.0::IFoo.bar.baz" are.
530 if (pos == 0) {
531 // matches "android.hardware.foo@1.0::IFoo.bar.baz"
532 return true;
533 }
534
535 if (s1[pos - 1] == '.') {
536 // matches "baz" and "bar.baz"
537 return true;
538 }
539
540 if (s1[pos - 1] == ':') {
541 // matches "IFoo.bar.baz"
542 return true;
543 }
544
545 if (s1[pos] == '@') {
546 // matches "@1.0::IFoo.bar.baz"
547 return true;
548 }
549
550 return false;
551 }
552
inPackage(const std::string & package) const553 bool FQName::inPackage(const std::string &package) const {
554 std::vector<std::string> components = getPackageComponents();
555 std::vector<std::string> inComponents = base::Split(package, ".");
556
557 if (inComponents.size() > components.size()) {
558 return false;
559 }
560
561 for (size_t i = 0; i < inComponents.size(); i++) {
562 if (inComponents[i] != components[i]) {
563 return false;
564 }
565 }
566
567 return true;
568 }
569
downRev() const570 FQName FQName::downRev() const {
571 FQName ret(*this);
572 CHECK(ret.mMinor > 0);
573 ret.mMinor--;
574 return ret;
575 }
576
upRev() const577 FQName FQName::upRev() const {
578 FQName ret(*this);
579 ret.mMinor++;
580 CHECK(ret.mMinor > 0);
581 return ret;
582 }
583
584 } // namespace android
585
586