Home | History | Annotate | Download | only in utils
      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 (at) 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 (at) 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 (at) 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 
     55 FQName::FQName()
     56     : mValid(false),
     57       mIsIdentifier(false) {
     58 }
     59 
     60 FQName::FQName(const std::string &s)
     61     : mValid(false),
     62       mIsIdentifier(false) {
     63     setTo(s);
     64 }
     65 
     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 
     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 
     94 FQName::FQName(const std::vector<std::string> &names)
     95     : mValid(false),
     96       mIsIdentifier(false) {
     97     setTo(StringHelper::JoinStrings(names, "."));
     98 }
     99 
    100 bool FQName::isValid() const {
    101     return mValid;
    102 }
    103 
    104 bool FQName::isIdentifier() const {
    105     return mIsIdentifier;
    106 }
    107 
    108 bool FQName::isFullyQualified() const {
    109     return !mPackage.empty() && !version().empty() && !mName.empty();
    110 }
    111 
    112 bool FQName::isValidValueName() const {
    113     return mIsIdentifier
    114         || (!mName.empty() && !mValueName.empty());
    115 }
    116 
    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 
    177 std::string FQName::package() const {
    178     return mPackage;
    179 }
    180 
    181 std::string FQName::version() const {
    182     if (!hasVersion()) {
    183         return "";
    184     }
    185     return std::to_string(mMajor) + "." + std::to_string(mMinor);
    186 }
    187 
    188 std::string FQName::sanitizedVersion() const {
    189     if (!hasVersion()) {
    190         return "";
    191     }
    192     return "V" + std::to_string(mMajor) + "_" + std::to_string(mMinor);
    193 }
    194 
    195 std::string FQName::atVersion() const {
    196     std::string v = version();
    197     return v.empty() ? "" : ("@" + v);
    198 }
    199 
    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 
    215 void FQName::clearVersion() {
    216     mMajor = mMinor = 0;
    217 }
    218 
    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 
    229 std::string FQName::name() const {
    230     return mName;
    231 }
    232 
    233 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 
    243 std::string FQName::valueName() const {
    244     return mValueName;
    245 }
    246 
    247 FQName FQName::typeName() const {
    248     return FQName(mPackage, version(), mName);
    249 }
    250 
    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 
    267 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 
    288 void FQName::print() const {
    289     if (!mValid) {
    290         LOG(INFO) << "INVALID";
    291         return;
    292     }
    293 
    294     LOG(INFO) << string();
    295 }
    296 
    297 bool FQName::operator<(const FQName &other) const {
    298     return string() < other.string();
    299 }
    300 
    301 bool FQName::operator==(const FQName &other) const {
    302     return string() == other.string();
    303 }
    304 
    305 bool FQName::operator!=(const FQName &other) const {
    306     return !(*this == other);
    307 }
    308 
    309 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 
    316 std::string FQName::getInterfaceBaseName() const {
    317     // cut off the leading 'I'.
    318     return getInterfaceName().substr(1);
    319 }
    320 
    321 std::string FQName::getInterfaceHwName() const {
    322     return "IHw" + getInterfaceBaseName();
    323 }
    324 
    325 std::string FQName::getInterfaceProxyName() const {
    326     return "BpHw" + getInterfaceBaseName();
    327 }
    328 
    329 std::string FQName::getInterfaceStubName() const {
    330     return "BnHw" + getInterfaceBaseName();
    331 }
    332 
    333 std::string FQName::getInterfacePassthroughName() const {
    334     return "Bs" + getInterfaceBaseName();
    335 }
    336 
    337 FQName FQName::getInterfaceProxyFqName() const {
    338     return FQName(package(), version(), getInterfaceProxyName());
    339 }
    340 
    341 FQName FQName::getInterfaceStubFqName() const {
    342     return FQName(package(), version(), getInterfaceStubName());
    343 }
    344 
    345 FQName FQName::getInterfacePassthroughFqName() const {
    346     return FQName(package(), version(), getInterfacePassthroughName());
    347 }
    348 
    349 FQName FQName::getTypesForPackage() const {
    350     return FQName(package(), version(), "types");
    351 }
    352 
    353 FQName FQName::getPackageAndVersion() const {
    354     return FQName(package(), version(), "");
    355 }
    356 
    357 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 
    367 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 
    381 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 
    391 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 
    399 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 
    413 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 
    420 std::string FQName::javaName() const {
    421     return javaPackage() + "." + name()
    422             + (mValueName.empty() ? "" : ("." + mValueName));
    423 }
    424 
    425 void FQName::getPackageComponents(std::vector<std::string> *components) const {
    426     StringHelper::SplitString(package(), '.', components);
    427 }
    428 
    429 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 
    448 bool FQName::hasVersion() const {
    449     return mMajor > 0;
    450 }
    451 
    452 size_t FQName::getPackageMajorVersion() const {
    453     CHECK(hasVersion()) << "FQName: No version exists at getPackageMajorVersion(). "
    454                         << "Did you check hasVersion()?";
    455     return mMajor;
    456 }
    457 
    458 size_t FQName::getPackageMinorVersion() const {
    459     CHECK(hasVersion()) << "FQName: No version exists at getPackageMinorVersion(). "
    460                         << "Did you check hasVersion()?";
    461     return mMinor;
    462 }
    463 
    464 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 (at) 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 (at) 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 
    500 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 
    520 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