• 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 "StringHelper.h"
20 
21 #include <android-base/logging.h>
22 #include <android-base/parseint.h>
23 #include <iostream>
24 #include <regex>
25 #include <sstream>
26 
27 #define RE_COMPONENT    "[a-zA-Z_][a-zA-Z_0-9]*"
28 #define RE_PATH         RE_COMPONENT "(?:[.]" RE_COMPONENT ")*"
29 #define RE_MAJOR        "[0-9]+"
30 #define RE_MINOR        "[0-9]+"
31 
32 namespace android {
33 
FQName()34 FQName::FQName()
35     : mValid(false),
36       mIsIdentifier(false) {
37 }
38 
39 // TODO(b/73774955): delete
FQName(const std::string & s)40 FQName::FQName(const std::string &s)
41     : mValid(false),
42       mIsIdentifier(false) {
43     (void)setTo(s);
44 }
45 
parse(const std::string & s,FQName * into)46 bool FQName::parse(const std::string& s, FQName* into) {
47     return into->setTo(s);
48 }
49 
FQName(const std::string & package,const std::string & version,const std::string & name,const std::string & valueName)50 FQName::FQName(
51         const std::string &package,
52         const std::string &version,
53         const std::string &name,
54         const std::string &valueName)
55     : mValid(true),
56       mIsIdentifier(false),
57       mPackage(package),
58       mName(name),
59       mValueName(valueName) {
60     CHECK(setVersion(version)) << version;
61 
62     // Check if this is actually a valid fqName
63     FQName other;
64     CHECK(parse(this->string(), &other)) << this->string();
65     CHECK((*this) == other) << this->string() << " " << other.string();
66 }
67 
FQName(const FQName & other)68 FQName::FQName(const FQName& other)
69     : mValid(other.mValid),
70       mIsIdentifier(other.mIsIdentifier),
71       mPackage(other.mPackage),
72       mMajor(other.mMajor),
73       mMinor(other.mMinor),
74       mName(other.mName),
75       mValueName(other.mValueName) {
76 }
77 
isValid() const78 bool FQName::isValid() const {
79     return mValid;
80 }
81 
isIdentifier() const82 bool FQName::isIdentifier() const {
83     return mIsIdentifier;
84 }
85 
isFullyQualified() const86 bool FQName::isFullyQualified() const {
87     return !mPackage.empty() && !version().empty() && !mName.empty();
88 }
89 
isValidValueName() const90 bool FQName::isValidValueName() const {
91     return mIsIdentifier
92         || (!mName.empty() && !mValueName.empty());
93 }
94 
isInterfaceName() const95 bool FQName::isInterfaceName() const {
96     return !mName.empty() && mName[0] == 'I' && mName.find('.') == std::string::npos;
97 }
98 
setTo(const std::string & s)99 bool FQName::setTo(const std::string &s) {
100     // android.hardware.foo@1.0::IFoo.Type
101     static const std::regex kRE1("(" RE_PATH ")@(" RE_MAJOR ")[.](" RE_MINOR ")::(" RE_PATH ")");
102     // @1.0::IFoo.Type
103     static const std::regex kRE2("@(" RE_MAJOR ")[.](" RE_MINOR ")::(" RE_PATH ")");
104     // android.hardware.foo@1.0 (for package declaration and whole package import)
105     static const std::regex kRE3("(" RE_PATH ")@(" RE_MAJOR ")[.](" RE_MINOR ")");
106     // IFoo.Type
107     static const std::regex kRE4("(" RE_COMPONENT ")([.]" RE_COMPONENT ")+");
108     // Type (a plain identifier)
109     static const std::regex kRE5("(" RE_COMPONENT ")");
110 
111     // android.hardware.foo@1.0::IFoo.Type:MY_ENUM_VALUE
112     static const std::regex kRE6("(" RE_PATH ")@(" RE_MAJOR ")[.](" RE_MINOR ")::(" RE_PATH
113                                  "):(" RE_COMPONENT ")");
114     // @1.0::IFoo.Type:MY_ENUM_VALUE
115     static const std::regex kRE7("@(" RE_MAJOR ")[.](" RE_MINOR ")::(" RE_PATH "):(" RE_COMPONENT
116                                  ")");
117     // IFoo.Type:MY_ENUM_VALUE
118     static const std::regex kRE8("(" RE_PATH "):(" RE_COMPONENT ")");
119 
120     bool invalid = false;
121     clear();
122 
123     std::smatch match;
124     if (std::regex_match(s, match, kRE1)) {
125         CHECK_EQ(match.size(), 5u);
126 
127         mPackage = match.str(1);
128         invalid |= !parseVersion(match.str(2), match.str(3));
129         mName = match.str(4);
130     } else if (std::regex_match(s, match, kRE2)) {
131         CHECK_EQ(match.size(), 4u);
132 
133         invalid |= !parseVersion(match.str(1), match.str(2));
134         mName = match.str(3);
135     } else if (std::regex_match(s, match, kRE3)) {
136         CHECK_EQ(match.size(), 4u);
137 
138         mPackage = match.str(1);
139         invalid |= !parseVersion(match.str(2), match.str(3));
140     } else if (std::regex_match(s, match, kRE4)) {
141         mName = match.str(0);
142     } else if (std::regex_match(s, match, kRE5)) {
143         mIsIdentifier = true;
144         mName = match.str(0);
145     } else if (std::regex_match(s, match, kRE6)) {
146         CHECK_EQ(match.size(), 6u);
147 
148         mPackage = match.str(1);
149         invalid |= !parseVersion(match.str(2), match.str(3));
150         mName = match.str(4);
151         mValueName = match.str(5);
152     } else if (std::regex_match(s, match, kRE7)) {
153         CHECK_EQ(match.size(), 5u);
154 
155         invalid |= !parseVersion(match.str(1), match.str(2));
156         mName = match.str(3);
157         mValueName = match.str(4);
158     } else if (std::regex_match(s, match, kRE8)) {
159         CHECK_EQ(match.size(), 3u);
160 
161         mName = match.str(1);
162         mValueName = match.str(2);
163     } else {
164         invalid = true;
165     }
166 
167     // mValueName must go with mName.
168     CHECK(mValueName.empty() || !mName.empty());
169 
170     // package without version is not allowed.
171     CHECK(invalid || mPackage.empty() || !version().empty());
172 
173     // TODO(b/73774955): remove isValid and users
174     // of old FQName constructors
175     return mValid = !invalid;
176 }
177 
package() const178 const std::string& FQName::package() const {
179     return mPackage;
180 }
181 
version() const182 std::string FQName::version() const {
183     if (!hasVersion()) {
184         return "";
185     }
186     return std::to_string(mMajor) + "." + std::to_string(mMinor);
187 }
188 
sanitizedVersion() const189 std::string FQName::sanitizedVersion() const {
190     if (!hasVersion()) {
191         return "";
192     }
193     return "V" + std::to_string(mMajor) + "_" + std::to_string(mMinor);
194 }
195 
atVersion() const196 std::string FQName::atVersion() const {
197     std::string v = version();
198     return v.empty() ? "" : ("@" + v);
199 }
200 
clear()201 void FQName::clear() {
202     mValid = true;
203     mIsIdentifier = false;
204     mPackage.clear();
205     clearVersion();
206     mName.clear();
207     mValueName.clear();
208 }
209 
setVersion(const std::string & v)210 bool FQName::setVersion(const std::string& v) {
211     static const std::regex kREVer("(" RE_MAJOR ")[.](" RE_MINOR ")");
212 
213     if (v.empty()) {
214         clearVersion();
215         return true;
216     }
217 
218     std::smatch match;
219     if (!std::regex_match(v, match, kREVer)) {
220         return mValid = false;
221     }
222     CHECK_EQ(match.size(), 3u);
223 
224     return parseVersion(match.str(1), match.str(2));
225 }
226 
clearVersion()227 void FQName::clearVersion() {
228     mMajor = mMinor = 0;
229 }
230 
parseVersion(const std::string & majorStr,const std::string & minorStr)231 bool FQName::parseVersion(const std::string& majorStr, const std::string& minorStr) {
232     bool versionParseSuccess =
233         ::android::base::ParseUint(majorStr, &mMajor) &&
234         ::android::base::ParseUint(minorStr, &mMinor);
235     if (!versionParseSuccess) {
236         LOG(ERROR) << "numbers in " << majorStr << "." << minorStr << " are out of range.";
237         mValid = false;
238     }
239     return versionParseSuccess;
240 }
241 
name() const242 const std::string& FQName::name() const {
243     return mName;
244 }
245 
names() const246 std::vector<std::string> FQName::names() const {
247     std::vector<std::string> res {};
248     std::istringstream ss(name());
249     std::string s;
250     while (std::getline(ss, s, '.')) {
251         res.push_back(s);
252     }
253     return res;
254 }
255 
valueName() const256 const std::string& FQName::valueName() const {
257     return mValueName;
258 }
259 
typeName() const260 FQName FQName::typeName() const {
261     return FQName(mPackage, version(), mName);
262 }
263 
applyDefaults(const std::string & defaultPackage,const std::string & defaultVersion)264 void FQName::applyDefaults(
265         const std::string &defaultPackage,
266         const std::string &defaultVersion) {
267 
268     // package without version is not allowed.
269     CHECK(mPackage.empty() || !version().empty());
270 
271     if (mPackage.empty()) {
272         mPackage = defaultPackage;
273     }
274 
275     if (version().empty()) {
276         CHECK(setVersion(defaultVersion));
277     }
278 }
279 
string() const280 std::string FQName::string() const {
281     CHECK(mValid) << mPackage << atVersion() << mName;
282 
283     std::string out;
284     out.append(mPackage);
285     out.append(atVersion());
286     if (!mName.empty()) {
287         if (!mPackage.empty() || !version().empty()) {
288             out.append("::");
289         }
290         out.append(mName);
291 
292         if (!mValueName.empty()) {
293             out.append(":");
294             out.append(mValueName);
295         }
296     }
297 
298     return out;
299 }
300 
operator <(const FQName & other) const301 bool FQName::operator<(const FQName &other) const {
302     return string() < other.string();
303 }
304 
operator ==(const FQName & other) const305 bool FQName::operator==(const FQName &other) const {
306     return string() == other.string();
307 }
308 
operator !=(const FQName & other) const309 bool FQName::operator!=(const FQName &other) const {
310     return !(*this == other);
311 }
312 
getInterfaceName() const313 const std::string& FQName::getInterfaceName() const {
314     CHECK(isInterfaceName()) << mName;
315 
316     return mName;
317 }
318 
getInterfaceBaseName() const319 std::string FQName::getInterfaceBaseName() const {
320     // cut off the leading 'I'.
321     return getInterfaceName().substr(1);
322 }
323 
getInterfaceAdapterName() const324 std::string FQName::getInterfaceAdapterName() const {
325     return "A" + getInterfaceBaseName();
326 }
327 
getInterfaceHwName() const328 std::string FQName::getInterfaceHwName() const {
329     return "IHw" + getInterfaceBaseName();
330 }
331 
getInterfaceProxyName() const332 std::string FQName::getInterfaceProxyName() const {
333     return "BpHw" + getInterfaceBaseName();
334 }
335 
getInterfaceStubName() const336 std::string FQName::getInterfaceStubName() const {
337     return "BnHw" + getInterfaceBaseName();
338 }
339 
getInterfacePassthroughName() const340 std::string FQName::getInterfacePassthroughName() const {
341     return "Bs" + getInterfaceBaseName();
342 }
343 
getInterfaceProxyFqName() const344 FQName FQName::getInterfaceProxyFqName() const {
345     return FQName(package(), version(), getInterfaceProxyName());
346 }
347 
getInterfaceAdapterFqName() const348 FQName FQName::getInterfaceAdapterFqName() const {
349     return FQName(package(), version(), getInterfaceAdapterName());
350 }
351 
getInterfaceStubFqName() const352 FQName FQName::getInterfaceStubFqName() const {
353     return FQName(package(), version(), getInterfaceStubName());
354 }
355 
getInterfacePassthroughFqName() const356 FQName FQName::getInterfacePassthroughFqName() const {
357     return FQName(package(), version(), getInterfacePassthroughName());
358 }
359 
getTypesForPackage() const360 FQName FQName::getTypesForPackage() const {
361     return FQName(package(), version(), "types");
362 }
363 
getPackageAndVersion() const364 FQName FQName::getPackageAndVersion() const {
365     return FQName(package(), version(), "");
366 }
367 
getTopLevelType() const368 FQName FQName::getTopLevelType() const {
369     auto idx = mName.find('.');
370 
371     if (idx == std::string::npos) {
372         return *this;
373     }
374 
375     return FQName(mPackage, version(), mName.substr(0, idx));
376 }
377 
tokenName() const378 std::string FQName::tokenName() const {
379     std::vector<std::string> components;
380     getPackageAndVersionComponents(&components, true /* cpp_compatible */);
381 
382     if (!mName.empty()) {
383         std::vector<std::string> nameComponents;
384         StringHelper::SplitString(mName, '.', &nameComponents);
385 
386         components.insert(components.end(), nameComponents.begin(), nameComponents.end());
387     }
388 
389     return StringHelper::JoinStrings(components, "_");
390 }
391 
cppNamespace() const392 std::string FQName::cppNamespace() const {
393     std::vector<std::string> components;
394     getPackageAndVersionComponents(&components, true /* cpp_compatible */);
395 
396     std::string out = "::";
397     out += StringHelper::JoinStrings(components, "::");
398 
399     return out;
400 }
401 
cppLocalName() const402 std::string FQName::cppLocalName() const {
403     std::vector<std::string> components;
404     StringHelper::SplitString(mName, '.', &components);
405 
406     return StringHelper::JoinStrings(components, "::")
407             + (mValueName.empty() ? "" : ("::" + mValueName));
408 }
409 
cppName() const410 std::string FQName::cppName() const {
411     std::string out = cppNamespace();
412 
413     std::vector<std::string> components;
414     StringHelper::SplitString(name(), '.', &components);
415     out += "::";
416     out += StringHelper::JoinStrings(components, "::");
417     if (!mValueName.empty()) {
418         out  += "::" + mValueName;
419     }
420 
421     return out;
422 }
423 
javaPackage() const424 std::string FQName::javaPackage() const {
425     std::vector<std::string> components;
426     getPackageAndVersionComponents(&components, true /* cpp_compatible */);
427 
428     return StringHelper::JoinStrings(components, ".");
429 }
430 
javaName() const431 std::string FQName::javaName() const {
432     return javaPackage() + "." + name()
433             + (mValueName.empty() ? "" : ("." + mValueName));
434 }
435 
getPackageComponents(std::vector<std::string> * components) const436 void FQName::getPackageComponents(std::vector<std::string> *components) const {
437     StringHelper::SplitString(package(), '.', components);
438 }
439 
getPackageAndVersionComponents(std::vector<std::string> * components,bool cpp_compatible) const440 void FQName::getPackageAndVersionComponents(
441         std::vector<std::string> *components,
442         bool cpp_compatible) const {
443     getPackageComponents(components);
444 
445     if (!hasVersion()) {
446         LOG(WARNING) << "FQName: getPackageAndVersionComponents expects version.";
447         return;
448     }
449 
450     if (!cpp_compatible) {
451         components->push_back(std::to_string(getPackageMajorVersion()) +
452                 "." + std::to_string(getPackageMinorVersion()));
453         return;
454     }
455 
456     components->push_back(sanitizedVersion());
457 }
458 
hasVersion() const459 bool FQName::hasVersion() const {
460     return mMajor > 0;
461 }
462 
withVersion(size_t major,size_t minor) const463 FQName FQName::withVersion(size_t major, size_t minor) const {
464     FQName ret(*this);
465     ret.mMajor = major;
466     ret.mMinor = minor;
467     return ret;
468 }
469 
getPackageMajorVersion() const470 size_t FQName::getPackageMajorVersion() const {
471     CHECK(hasVersion()) << "FQName: No version exists at getPackageMajorVersion(). "
472                         << "Did you check hasVersion()?";
473     return mMajor;
474 }
475 
getPackageMinorVersion() const476 size_t FQName::getPackageMinorVersion() const {
477     CHECK(hasVersion()) << "FQName: No version exists at getPackageMinorVersion(). "
478                         << "Did you check hasVersion()?";
479     return mMinor;
480 }
481 
endsWith(const FQName & other) const482 bool FQName::endsWith(const FQName &other) const {
483     std::string s1 = string();
484     std::string s2 = other.string();
485 
486     size_t pos = s1.rfind(s2);
487     if (pos == std::string::npos || pos + s2.size() != s1.size()) {
488         return false;
489     }
490 
491     // A match is only a match if it is preceded by a "boundary", i.e.
492     // we perform a component-wise match from the end.
493     // "az" is not a match for "android.hardware.foo@1.0::IFoo.bar.baz",
494     // "baz", "bar.baz", "IFoo.bar.baz", "@1.0::IFoo.bar.baz" are.
495     if (pos == 0) {
496         // matches "android.hardware.foo@1.0::IFoo.bar.baz"
497         return true;
498     }
499 
500     if (s1[pos - 1] == '.') {
501         // matches "baz" and "bar.baz"
502         return true;
503     }
504 
505     if (s1[pos - 1] == ':') {
506         // matches "IFoo.bar.baz"
507         return true;
508     }
509 
510     if (s1[pos] == '@') {
511         // matches "@1.0::IFoo.bar.baz"
512         return true;
513     }
514 
515     return false;
516 }
517 
inPackage(const std::string & package) const518 bool FQName::inPackage(const std::string &package) const {
519     std::vector<std::string> components;
520     getPackageComponents(&components);
521 
522     std::vector<std::string> inComponents;
523     StringHelper::SplitString(package, '.', &inComponents);
524 
525     if (inComponents.size() > components.size()) {
526         return false;
527     }
528 
529     for (size_t i = 0; i < inComponents.size(); i++) {
530         if (inComponents[i] != components[i]) {
531             return false;
532         }
533     }
534 
535     return true;
536 }
537 
downRev() const538 FQName FQName::downRev() const {
539     FQName ret(*this);
540     CHECK(ret.mMinor > 0);
541     ret.mMinor--;
542     return ret;
543 }
544 
545 const FQName gIBaseFqName = FQName("android.hidl.base", "1.0", "IBase");
546 const FQName gIManagerFqName = FQName("android.hidl.manager", "1.0", "IServiceManager");
547 
548 }  // namespace android
549 
550