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