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 // android.hardware.foo@1.0::IFoo.Type
33 static const std::regex kRE1("(" RE_PATH ")@(" RE_MAJOR ")[.](" RE_MINOR ")::(" RE_PATH ")");
34 // @1.0::IFoo.Type
35 static const std::regex kRE2("@(" RE_MAJOR ")[.](" RE_MINOR ")::(" RE_PATH ")");
36 // android.hardware.foo@1.0 (for package declaration and whole package import)
37 static const std::regex kRE3("(" RE_PATH ")@(" RE_MAJOR ")[.](" RE_MINOR ")");
38 // IFoo.Type
39 static const std::regex kRE4("(" RE_COMPONENT ")([.]" RE_COMPONENT ")+");
40 // Type (a plain identifier)
41 static const std::regex kRE5("(" RE_COMPONENT ")");
42 
43 // android.hardware.foo@1.0::IFoo.Type:MY_ENUM_VALUE
44 static const std::regex kRE6("(" RE_PATH ")@(" RE_MAJOR ")[.](" RE_MINOR ")::(" RE_PATH "):(" RE_COMPONENT ")");
45 // @1.0::IFoo.Type:MY_ENUM_VALUE
46 static const std::regex kRE7("@(" RE_MAJOR ")[.](" RE_MINOR ")::(" RE_PATH "):(" RE_COMPONENT ")");
47 // IFoo.Type:MY_ENUM_VALUE
48 static const std::regex kRE8("(" RE_PATH "):(" RE_COMPONENT ")");
49 
50 // 1.0
51 static const std::regex kREVer("(" RE_MAJOR ")[.](" RE_MINOR ")");
52 
53 namespace android {
54 
FQName()55 FQName::FQName()
56     : mValid(false),
57       mIsIdentifier(false) {
58 }
59 
FQName(const std::string & s)60 FQName::FQName(const std::string &s)
61     : mValid(false),
62       mIsIdentifier(false) {
63     setTo(s);
64 }
65 
FQName(const std::string & package,const std::string & version,const std::string & name,const std::string & valueName)66 FQName::FQName(
67         const std::string &package,
68         const std::string &version,
69         const std::string &name,
70         const std::string &valueName)
71     : mValid(true),
72       mIsIdentifier(false),
73       mPackage(package),
74       mName(name),
75       mValueName(valueName) {
76     setVersion(version);
77 
78     // Check if this is actually a valid fqName
79     FQName other;
80     other.setTo(this->string());
81     CHECK(other.mValid && (*this) == other);
82 }
83 
FQName(const FQName & other)84 FQName::FQName(const FQName& other)
85     : mValid(other.mValid),
86       mIsIdentifier(other.mIsIdentifier),
87       mPackage(other.mPackage),
88       mMajor(other.mMajor),
89       mMinor(other.mMinor),
90       mName(other.mName),
91       mValueName(other.mValueName) {
92 }
93 
FQName(const std::vector<std::string> & names)94 FQName::FQName(const std::vector<std::string> &names)
95     : mValid(false),
96       mIsIdentifier(false) {
97     setTo(StringHelper::JoinStrings(names, "."));
98 }
99 
isValid() const100 bool FQName::isValid() const {
101     return mValid;
102 }
103 
isIdentifier() const104 bool FQName::isIdentifier() const {
105     return mIsIdentifier;
106 }
107 
isFullyQualified() const108 bool FQName::isFullyQualified() const {
109     return !mPackage.empty() && !version().empty() && !mName.empty();
110 }
111 
isValidValueName() const112 bool FQName::isValidValueName() const {
113     return mIsIdentifier
114         || (!mName.empty() && !mValueName.empty());
115 }
116 
setTo(const std::string & s)117 bool FQName::setTo(const std::string &s) {
118     clearVersion();
119     mPackage.clear();
120     mName.clear();
121 
122     mValid = true;
123 
124     std::smatch match;
125     if (std::regex_match(s, match, kRE1)) {
126         CHECK_EQ(match.size(), 5u);
127 
128         mPackage = match.str(1);
129         parseVersion(match.str(2), match.str(3));
130         mName = match.str(4);
131     } else if (std::regex_match(s, match, kRE2)) {
132         CHECK_EQ(match.size(), 4u);
133 
134         parseVersion(match.str(1), match.str(2));
135         mName = match.str(3);
136     } else if (std::regex_match(s, match, kRE3)) {
137         CHECK_EQ(match.size(), 4u);
138 
139         mPackage = match.str(1);
140         parseVersion(match.str(2), match.str(3));
141     } else if (std::regex_match(s, match, kRE4)) {
142         mName = match.str(0);
143     } else if (std::regex_match(s, match, kRE5)) {
144         mIsIdentifier = true;
145         mName = match.str(0);
146     } else if (std::regex_match(s, match, kRE6)) {
147         CHECK_EQ(match.size(), 6u);
148 
149         mPackage = match.str(1);
150         parseVersion(match.str(2), match.str(3));
151         mName = match.str(4);
152         mValueName = match.str(5);
153     } else if (std::regex_match(s, match, kRE7)) {
154         CHECK_EQ(match.size(), 5u);
155 
156         parseVersion(match.str(1), match.str(2));
157         mName = match.str(3);
158         mValueName = match.str(4);
159     } else if (std::regex_match(s, match, kRE8)) {
160         CHECK_EQ(match.size(), 3u);
161 
162         mName = match.str(1);
163         mValueName = match.str(2);
164     } else {
165         mValid = false;
166     }
167 
168     // mValueName must go with mName.
169     CHECK(mValueName.empty() || !mName.empty());
170 
171     // package without version is not allowed.
172     CHECK(mPackage.empty() || !version().empty());
173 
174     return isValid();
175 }
176 
package() const177 std::string FQName::package() const {
178     return mPackage;
179 }
180 
version() const181 std::string FQName::version() const {
182     if (!hasVersion()) {
183         return "";
184     }
185     return std::to_string(mMajor) + "." + std::to_string(mMinor);
186 }
187 
sanitizedVersion() const188 std::string FQName::sanitizedVersion() const {
189     if (!hasVersion()) {
190         return "";
191     }
192     return "V" + std::to_string(mMajor) + "_" + std::to_string(mMinor);
193 }
194 
atVersion() const195 std::string FQName::atVersion() const {
196     std::string v = version();
197     return v.empty() ? "" : ("@" + v);
198 }
199 
setVersion(const std::string & v)200 void FQName::setVersion(const std::string &v) {
201     if (v.empty()) {
202         clearVersion();
203         return;
204     }
205     std::smatch match;
206     if (std::regex_match(v, match, kREVer)) {
207         CHECK_EQ(match.size(), 3u);
208 
209         parseVersion(match.str(1), match.str(2));
210     } else {
211         mValid = false;
212     }
213 }
214 
clearVersion()215 void FQName::clearVersion() {
216     mMajor = mMinor = 0;
217 }
218 
parseVersion(const std::string & majorStr,const std::string & minorStr)219 void FQName::parseVersion(const std::string &majorStr, const std::string &minorStr) {
220     bool versionParseSuccess =
221         ::android::base::ParseUint(majorStr, &mMajor) &&
222         ::android::base::ParseUint(minorStr, &mMinor);
223     if (!versionParseSuccess) {
224         LOG(ERROR) << "numbers in " << majorStr << "." << minorStr << " are out of range.";
225         mValid = false;
226     }
227 }
228 
name() const229 std::string FQName::name() const {
230     return mName;
231 }
232 
names() const233 std::vector<std::string> FQName::names() const {
234     std::vector<std::string> res {};
235     std::istringstream ss(name());
236     std::string s;
237     while (std::getline(ss, s, '.')) {
238         res.push_back(s);
239     }
240     return res;
241 }
242 
valueName() const243 std::string FQName::valueName() const {
244     return mValueName;
245 }
246 
typeName() const247 FQName FQName::typeName() const {
248     return FQName(mPackage, version(), mName);
249 }
250 
applyDefaults(const std::string & defaultPackage,const std::string & defaultVersion)251 void FQName::applyDefaults(
252         const std::string &defaultPackage,
253         const std::string &defaultVersion) {
254 
255     // package without version is not allowed.
256     CHECK(mPackage.empty() || !version().empty());
257 
258     if (mPackage.empty()) {
259         mPackage = defaultPackage;
260     }
261 
262     if (version().empty()) {
263         setVersion(defaultVersion);
264     }
265 }
266 
string() const267 std::string FQName::string() const {
268     CHECK(mValid);
269 
270     std::string out;
271     out.append(mPackage);
272     out.append(atVersion());
273     if (!mName.empty()) {
274         if (!mPackage.empty() || !version().empty()) {
275             out.append("::");
276         }
277         out.append(mName);
278 
279         if (!mValueName.empty()) {
280             out.append(":");
281             out.append(mValueName);
282         }
283     }
284 
285     return out;
286 }
287 
print() const288 void FQName::print() const {
289     if (!mValid) {
290         LOG(INFO) << "INVALID";
291         return;
292     }
293 
294     LOG(INFO) << string();
295 }
296 
operator <(const FQName & other) const297 bool FQName::operator<(const FQName &other) const {
298     return string() < other.string();
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 !(*this == other);
307 }
308 
getInterfaceName() const309 std::string FQName::getInterfaceName() const {
310     CHECK(names().size() == 1) << "Must be a top level type";
311     CHECK(!mName.empty() && mName[0] == 'I') << mName;
312 
313     return mName;
314 }
315 
getInterfaceBaseName() const316 std::string FQName::getInterfaceBaseName() const {
317     // cut off the leading 'I'.
318     return getInterfaceName().substr(1);
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 
getInterfaceStubFqName() const341 FQName FQName::getInterfaceStubFqName() const {
342     return FQName(package(), version(), getInterfaceStubName());
343 }
344 
getInterfacePassthroughFqName() const345 FQName FQName::getInterfacePassthroughFqName() const {
346     return FQName(package(), version(), getInterfacePassthroughName());
347 }
348 
getTypesForPackage() const349 FQName FQName::getTypesForPackage() const {
350     return FQName(package(), version(), "types");
351 }
352 
getPackageAndVersion() const353 FQName FQName::getPackageAndVersion() const {
354     return FQName(package(), version(), "");
355 }
356 
getTopLevelType() const357 FQName FQName::getTopLevelType() const {
358     auto idx = mName.find('.');
359 
360     if (idx == std::string::npos) {
361         return *this;
362     }
363 
364     return FQName(mPackage, version(), mName.substr(0, idx));
365 }
366 
tokenName() const367 std::string FQName::tokenName() const {
368     std::vector<std::string> components;
369     getPackageAndVersionComponents(&components, true /* cpp_compatible */);
370 
371     if (!mName.empty()) {
372         std::vector<std::string> nameComponents;
373         StringHelper::SplitString(mName, '.', &nameComponents);
374 
375         components.insert(components.end(), nameComponents.begin(), nameComponents.end());
376     }
377 
378     return StringHelper::JoinStrings(components, "_");
379 }
380 
cppNamespace() const381 std::string FQName::cppNamespace() const {
382     std::vector<std::string> components;
383     getPackageAndVersionComponents(&components, true /* cpp_compatible */);
384 
385     std::string out = "::";
386     out += StringHelper::JoinStrings(components, "::");
387 
388     return out;
389 }
390 
cppLocalName() const391 std::string FQName::cppLocalName() const {
392     std::vector<std::string> components;
393     StringHelper::SplitString(mName, '.', &components);
394 
395     return StringHelper::JoinStrings(components, "::")
396             + (mValueName.empty() ? "" : ("::" + mValueName));
397 }
398 
cppName() const399 std::string FQName::cppName() const {
400     std::string out = cppNamespace();
401 
402     std::vector<std::string> components;
403     StringHelper::SplitString(name(), '.', &components);
404     out += "::";
405     out += StringHelper::JoinStrings(components, "::");
406     if (!mValueName.empty()) {
407         out  += "::" + mValueName;
408     }
409 
410     return out;
411 }
412 
javaPackage() const413 std::string FQName::javaPackage() const {
414     std::vector<std::string> components;
415     getPackageAndVersionComponents(&components, true /* cpp_compatible */);
416 
417     return StringHelper::JoinStrings(components, ".");
418 }
419 
javaName() const420 std::string FQName::javaName() const {
421     return javaPackage() + "." + name()
422             + (mValueName.empty() ? "" : ("." + mValueName));
423 }
424 
getPackageComponents(std::vector<std::string> * components) const425 void FQName::getPackageComponents(std::vector<std::string> *components) const {
426     StringHelper::SplitString(package(), '.', components);
427 }
428 
getPackageAndVersionComponents(std::vector<std::string> * components,bool cpp_compatible) const429 void FQName::getPackageAndVersionComponents(
430         std::vector<std::string> *components,
431         bool cpp_compatible) const {
432     getPackageComponents(components);
433 
434     if (!hasVersion()) {
435         LOG(WARNING) << "FQName: getPackageAndVersionComponents expects version.";
436         return;
437     }
438 
439     if (!cpp_compatible) {
440         components->push_back(std::to_string(getPackageMajorVersion()) +
441                 "." + std::to_string(getPackageMinorVersion()));
442         return;
443     }
444 
445     components->push_back(sanitizedVersion());
446 }
447 
hasVersion() const448 bool FQName::hasVersion() const {
449     return mMajor > 0;
450 }
451 
getPackageMajorVersion() const452 size_t FQName::getPackageMajorVersion() const {
453     CHECK(hasVersion()) << "FQName: No version exists at getPackageMajorVersion(). "
454                         << "Did you check hasVersion()?";
455     return mMajor;
456 }
457 
getPackageMinorVersion() const458 size_t FQName::getPackageMinorVersion() const {
459     CHECK(hasVersion()) << "FQName: No version exists at getPackageMinorVersion(). "
460                         << "Did you check hasVersion()?";
461     return mMinor;
462 }
463 
endsWith(const FQName & other) const464 bool FQName::endsWith(const FQName &other) const {
465     std::string s1 = string();
466     std::string s2 = other.string();
467 
468     size_t pos = s1.rfind(s2);
469     if (pos == std::string::npos || pos + s2.size() != s1.size()) {
470         return false;
471     }
472 
473     // A match is only a match if it is preceded by a "boundary", i.e.
474     // we perform a component-wise match from the end.
475     // "az" is not a match for "android.hardware.foo@1.0::IFoo.bar.baz",
476     // "baz", "bar.baz", "IFoo.bar.baz", "@1.0::IFoo.bar.baz" are.
477     if (pos == 0) {
478         // matches "android.hardware.foo@1.0::IFoo.bar.baz"
479         return true;
480     }
481 
482     if (s1[pos - 1] == '.') {
483         // matches "baz" and "bar.baz"
484         return true;
485     }
486 
487     if (s1[pos - 1] == ':') {
488         // matches "IFoo.bar.baz"
489         return true;
490     }
491 
492     if (s1[pos] == '@') {
493         // matches "@1.0::IFoo.bar.baz"
494         return true;
495     }
496 
497     return false;
498 }
499 
inPackage(const std::string & package) const500 bool FQName::inPackage(const std::string &package) const {
501     std::vector<std::string> components;
502     getPackageComponents(&components);
503 
504     std::vector<std::string> inComponents;
505     StringHelper::SplitString(package, '.', &inComponents);
506 
507     if (inComponents.size() > components.size()) {
508         return false;
509     }
510 
511     for (size_t i = 0; i < inComponents.size(); i++) {
512         if (inComponents[i] != components[i]) {
513             return false;
514         }
515     }
516 
517     return true;
518 }
519 
downRev() const520 FQName FQName::downRev() const {
521     FQName ret(*this);
522     CHECK(ret.mMinor > 0);
523     ret.mMinor--;
524     return ret;
525 }
526 
527 }  // namespace android
528 
529