• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
getInterfaceHwName() const373 std::string FQName::getInterfaceHwName() const {
374     return "IHw" + getInterfaceBaseName();
375 }
376 
getInterfaceProxyName() const377 std::string FQName::getInterfaceProxyName() const {
378     return "BpHw" + getInterfaceBaseName();
379 }
380 
getInterfaceStubName() const381 std::string FQName::getInterfaceStubName() const {
382     return "BnHw" + getInterfaceBaseName();
383 }
384 
getInterfacePassthroughName() const385 std::string FQName::getInterfacePassthroughName() const {
386     return "Bs" + getInterfaceBaseName();
387 }
388 
getInterfaceProxyFqName() const389 FQName FQName::getInterfaceProxyFqName() const {
390     return FQName(package(), version(), getInterfaceProxyName());
391 }
392 
getInterfaceStubFqName() const393 FQName FQName::getInterfaceStubFqName() const {
394     return FQName(package(), version(), getInterfaceStubName());
395 }
396 
getInterfacePassthroughFqName() const397 FQName FQName::getInterfacePassthroughFqName() const {
398     return FQName(package(), version(), getInterfacePassthroughName());
399 }
400 
getTypesForPackage() const401 FQName FQName::getTypesForPackage() const {
402     return FQName(package(), version(), "types");
403 }
404 
getPackageAndVersion() const405 FQName FQName::getPackageAndVersion() const {
406     return FQName(package(), version(), "");
407 }
408 
getTopLevelType() const409 FQName FQName::getTopLevelType() const {
410     auto idx = mName.find('.');
411 
412     if (idx == std::string::npos) {
413         return *this;
414     }
415 
416     return FQName(mPackage, version(), mName.substr(0, idx));
417 }
418 
tokenName() const419 std::string FQName::tokenName() const {
420     std::vector<std::string> components = getPackageAndVersionComponents(true /* sanitized */);
421 
422     if (!mName.empty()) {
423         std::vector<std::string> nameComponents = base::Split(mName, ".");
424 
425         components.insert(components.end(), nameComponents.begin(), nameComponents.end());
426     }
427 
428     return base::Join(components, "_");
429 }
430 
cppNamespace() const431 std::string FQName::cppNamespace() const {
432     std::vector<std::string> components = getPackageAndVersionComponents(true /* sanitized */);
433     return "::" + base::Join(components, "::");
434 }
435 
cppLocalName() const436 std::string FQName::cppLocalName() const {
437     std::vector<std::string> components = base::Split(mName, ".");
438 
439     return base::Join(components, "::")
440             + (mValueName.empty() ? "" : ("::" + mValueName));
441 }
442 
cppName() const443 std::string FQName::cppName() const {
444     std::string out = cppNamespace();
445 
446     std::vector<std::string> components = base::Split(name(), ".");
447     out += "::";
448     out += base::Join(components, "::");
449     if (!mValueName.empty()) {
450         out  += "::" + mValueName;
451     }
452 
453     return out;
454 }
455 
javaPackage() const456 std::string FQName::javaPackage() const {
457     std::vector<std::string> components = getPackageAndVersionComponents(true /* sanitized */);
458     return base::Join(components, ".");
459 }
460 
javaName() const461 std::string FQName::javaName() const {
462     return javaPackage() + "." + name()
463             + (mValueName.empty() ? "" : ("." + mValueName));
464 }
465 
getPackageComponents() const466 std::vector<std::string> FQName::getPackageComponents() const {
467     return base::Split(package(), ".");
468 }
469 
getPackageAndVersionComponents(bool sanitized) const470 std::vector<std::string> FQName::getPackageAndVersionComponents(bool sanitized) const {
471     CHECK(hasVersion()) << string() << ": getPackageAndVersionComponents expects version.";
472 
473     std::vector<std::string> components = getPackageComponents();
474     if (sanitized) {
475         components.push_back(sanitizedVersion());
476     } else {
477         components.push_back(version());
478     }
479     return components;
480 }
481 
hasVersion() const482 bool FQName::hasVersion() const {
483     return mMajor > 0;
484 }
485 
getVersion() const486 std::pair<size_t, size_t> FQName::getVersion() const {
487     return {mMajor, mMinor};
488 }
489 
withVersion(size_t major,size_t minor) const490 FQName FQName::withVersion(size_t major, size_t minor) const {
491     FQName ret(*this);
492     ret.mMajor = major;
493     ret.mMinor = minor;
494     return ret;
495 }
496 
getPackageMajorVersion() const497 size_t FQName::getPackageMajorVersion() const {
498     CHECK(hasVersion()) << "FQName: No version exists at getPackageMajorVersion(). "
499                         << "Did you check hasVersion()?";
500     return mMajor;
501 }
502 
getPackageMinorVersion() const503 size_t FQName::getPackageMinorVersion() const {
504     CHECK(hasVersion()) << "FQName: No version exists at getPackageMinorVersion(). "
505                         << "Did you check hasVersion()?";
506     return mMinor;
507 }
508 
endsWith(const FQName & other) const509 bool FQName::endsWith(const FQName &other) const {
510     std::string s1 = string();
511     std::string s2 = other.string();
512 
513     size_t pos = s1.rfind(s2);
514     if (pos == std::string::npos || pos + s2.size() != s1.size()) {
515         return false;
516     }
517 
518     // A match is only a match if it is preceded by a "boundary", i.e.
519     // we perform a component-wise match from the end.
520     // "az" is not a match for "android.hardware.foo@1.0::IFoo.bar.baz",
521     // "baz", "bar.baz", "IFoo.bar.baz", "@1.0::IFoo.bar.baz" are.
522     if (pos == 0) {
523         // matches "android.hardware.foo@1.0::IFoo.bar.baz"
524         return true;
525     }
526 
527     if (s1[pos - 1] == '.') {
528         // matches "baz" and "bar.baz"
529         return true;
530     }
531 
532     if (s1[pos - 1] == ':') {
533         // matches "IFoo.bar.baz"
534         return true;
535     }
536 
537     if (s1[pos] == '@') {
538         // matches "@1.0::IFoo.bar.baz"
539         return true;
540     }
541 
542     return false;
543 }
544 
inPackage(const std::string & package) const545 bool FQName::inPackage(const std::string &package) const {
546     std::vector<std::string> components = getPackageComponents();
547     std::vector<std::string> inComponents = base::Split(package, ".");
548 
549     if (inComponents.size() > components.size()) {
550         return false;
551     }
552 
553     for (size_t i = 0; i < inComponents.size(); i++) {
554         if (inComponents[i] != components[i]) {
555             return false;
556         }
557     }
558 
559     return true;
560 }
561 
downRev() const562 FQName FQName::downRev() const {
563     FQName ret(*this);
564     CHECK(ret.mMinor > 0);
565     ret.mMinor--;
566     return ret;
567 }
568 
upRev() const569 FQName FQName::upRev() const {
570     FQName ret(*this);
571     ret.mMinor++;
572     CHECK(ret.mMinor > 0);
573     return ret;
574 }
575 
576 }  // namespace android
577 
578