• Home
  • History
  • Annotate
  • 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  
27  FQName::FQName() : mIsIdentifier(false) {}
28  
29  bool FQName::parse(const std::string& s, FQName* into) {
30      return into->setTo(s);
31  }
32  
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  
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  
55  bool FQName::isIdentifier() const {
56      return mIsIdentifier;
57  }
58  
59  bool FQName::isFullyQualified() const {
60      return !mPackage.empty() && !version().empty() && !mName.empty();
61  }
62  
63  bool FQName::isValidValueName() const {
64      return mIsIdentifier
65          || (!mName.empty() && !mValueName.empty());
66  }
67  
68  bool FQName::isInterfaceName() const {
69      return !mName.empty() && mName[0] == 'I' && mName.find('.') == std::string::npos;
70  }
71  
72  static inline bool isIdentStart(char a) {
73      return ('a' <= a && a <= 'z') || ('A' <= a && a <= 'Z') || a == '_';
74  }
75  static inline bool isLeadingDigit(char a) {
76      return '1' <= a && a <= '9';
77  }
78  static inline bool isDigit(char a) {
79      return '0' <= a && a <= '9';
80  }
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_]*
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>)*
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
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  
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  
200  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  
225  const std::string& FQName::package() const {
226      return mPackage;
227  }
228  
229  std::string FQName::version() const {
230      if (!hasVersion()) {
231          return "";
232      }
233      return std::to_string(mMajor) + "." + std::to_string(mMinor);
234  }
235  
236  std::string FQName::sanitizedVersion() const {
237      if (!hasVersion()) {
238          return "";
239      }
240      return "V" + std::to_string(mMajor) + "_" + std::to_string(mMinor);
241  }
242  
243  std::string FQName::atVersion() const {
244      std::string v = version();
245      return v.empty() ? "" : ("@" + v);
246  }
247  
248  void FQName::clear() {
249      mIsIdentifier = false;
250      mPackage.clear();
251      clearVersion();
252      mName.clear();
253      mValueName.clear();
254  }
255  
256  void FQName::clearVersion(size_t* majorVer, size_t* minorVer) {
257      *majorVer = *minorVer = 0;
258  }
259  
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  
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  
281  bool FQName::setVersion(const std::string& v) {
282      return parseVersion(v, &mMajor, &mMinor);
283  }
284  
285  void FQName::clearVersion() {
286      clearVersion(&mMajor, &mMinor);
287  }
288  
289  bool FQName::parseVersion(const std::string& majorStr, const std::string& minorStr) {
290      return parseVersion(majorStr, minorStr, &mMajor, &mMinor);
291  }
292  
293  const std::string& FQName::name() const {
294      return mName;
295  }
296  
297  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  
307  const std::string& FQName::valueName() const {
308      return mValueName;
309  }
310  
311  FQName FQName::typeName() const {
312      return FQName(mPackage, version(), mName);
313  }
314  
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  
331  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  
350  bool FQName::operator<(const FQName &other) const {
351      return string() < other.string();
352  }
353  
354  bool FQName::operator==(const FQName &other) const {
355      return string() == other.string();
356  }
357  
358  bool FQName::operator!=(const FQName &other) const {
359      return !(*this == other);
360  }
361  
362  const std::string& FQName::getInterfaceName() const {
363      CHECK(isInterfaceName()) << mName;
364  
365      return mName;
366  }
367  
368  std::string FQName::getInterfaceBaseName() const {
369      // cut off the leading 'I'.
370      return getInterfaceName().substr(1);
371  }
372  
373  std::string FQName::getInterfaceAdapterName() const {
374      return "A" + getInterfaceBaseName();
375  }
376  
377  std::string FQName::getInterfaceHwName() const {
378      return "IHw" + getInterfaceBaseName();
379  }
380  
381  std::string FQName::getInterfaceProxyName() const {
382      return "BpHw" + getInterfaceBaseName();
383  }
384  
385  std::string FQName::getInterfaceStubName() const {
386      return "BnHw" + getInterfaceBaseName();
387  }
388  
389  std::string FQName::getInterfacePassthroughName() const {
390      return "Bs" + getInterfaceBaseName();
391  }
392  
393  FQName FQName::getInterfaceProxyFqName() const {
394      return FQName(package(), version(), getInterfaceProxyName());
395  }
396  
397  FQName FQName::getInterfaceAdapterFqName() const {
398      return FQName(package(), version(), getInterfaceAdapterName());
399  }
400  
401  FQName FQName::getInterfaceStubFqName() const {
402      return FQName(package(), version(), getInterfaceStubName());
403  }
404  
405  FQName FQName::getInterfacePassthroughFqName() const {
406      return FQName(package(), version(), getInterfacePassthroughName());
407  }
408  
409  FQName FQName::getTypesForPackage() const {
410      return FQName(package(), version(), "types");
411  }
412  
413  FQName FQName::getPackageAndVersion() const {
414      return FQName(package(), version(), "");
415  }
416  
417  FQName FQName::getTopLevelType() const {
418      auto idx = mName.find('.');
419  
420      if (idx == std::string::npos) {
421          return *this;
422      }
423  
424      return FQName(mPackage, version(), mName.substr(0, idx));
425  }
426  
427  std::string FQName::tokenName() const {
428      std::vector<std::string> components = getPackageAndVersionComponents(true /* sanitized */);
429  
430      if (!mName.empty()) {
431          std::vector<std::string> nameComponents = base::Split(mName, ".");
432  
433          components.insert(components.end(), nameComponents.begin(), nameComponents.end());
434      }
435  
436      return base::Join(components, "_");
437  }
438  
439  std::string FQName::cppNamespace() const {
440      std::vector<std::string> components = getPackageAndVersionComponents(true /* sanitized */);
441      return "::" + base::Join(components, "::");
442  }
443  
444  std::string FQName::cppLocalName() const {
445      std::vector<std::string> components = base::Split(mName, ".");
446  
447      return base::Join(components, "::")
448              + (mValueName.empty() ? "" : ("::" + mValueName));
449  }
450  
451  std::string FQName::cppName() const {
452      std::string out = cppNamespace();
453  
454      std::vector<std::string> components = base::Split(name(), ".");
455      out += "::";
456      out += base::Join(components, "::");
457      if (!mValueName.empty()) {
458          out  += "::" + mValueName;
459      }
460  
461      return out;
462  }
463  
464  std::string FQName::javaPackage() const {
465      std::vector<std::string> components = getPackageAndVersionComponents(true /* sanitized */);
466      return base::Join(components, ".");
467  }
468  
469  std::string FQName::javaName() const {
470      return javaPackage() + "." + name()
471              + (mValueName.empty() ? "" : ("." + mValueName));
472  }
473  
474  std::vector<std::string> FQName::getPackageComponents() const {
475      return base::Split(package(), ".");
476  }
477  
478  std::vector<std::string> FQName::getPackageAndVersionComponents(bool sanitized) const {
479      CHECK(hasVersion()) << string() << ": getPackageAndVersionComponents expects version.";
480  
481      std::vector<std::string> components = getPackageComponents();
482      if (sanitized) {
483          components.push_back(sanitizedVersion());
484      } else {
485          components.push_back(version());
486      }
487      return components;
488  }
489  
490  bool FQName::hasVersion() const {
491      return mMajor > 0;
492  }
493  
494  std::pair<size_t, size_t> FQName::getVersion() const {
495      return {mMajor, mMinor};
496  }
497  
498  FQName FQName::withVersion(size_t major, size_t minor) const {
499      FQName ret(*this);
500      ret.mMajor = major;
501      ret.mMinor = minor;
502      return ret;
503  }
504  
505  size_t FQName::getPackageMajorVersion() const {
506      CHECK(hasVersion()) << "FQName: No version exists at getPackageMajorVersion(). "
507                          << "Did you check hasVersion()?";
508      return mMajor;
509  }
510  
511  size_t FQName::getPackageMinorVersion() const {
512      CHECK(hasVersion()) << "FQName: No version exists at getPackageMinorVersion(). "
513                          << "Did you check hasVersion()?";
514      return mMinor;
515  }
516  
517  bool FQName::endsWith(const FQName &other) const {
518      std::string s1 = string();
519      std::string s2 = other.string();
520  
521      size_t pos = s1.rfind(s2);
522      if (pos == std::string::npos || pos + s2.size() != s1.size()) {
523          return false;
524      }
525  
526      // A match is only a match if it is preceded by a "boundary", i.e.
527      // we perform a component-wise match from the end.
528      // "az" is not a match for "android.hardware.foo@1.0::IFoo.bar.baz",
529      // "baz", "bar.baz", "IFoo.bar.baz", "@1.0::IFoo.bar.baz" are.
530      if (pos == 0) {
531          // matches "android.hardware.foo@1.0::IFoo.bar.baz"
532          return true;
533      }
534  
535      if (s1[pos - 1] == '.') {
536          // matches "baz" and "bar.baz"
537          return true;
538      }
539  
540      if (s1[pos - 1] == ':') {
541          // matches "IFoo.bar.baz"
542          return true;
543      }
544  
545      if (s1[pos] == '@') {
546          // matches "@1.0::IFoo.bar.baz"
547          return true;
548      }
549  
550      return false;
551  }
552  
553  bool FQName::inPackage(const std::string &package) const {
554      std::vector<std::string> components = getPackageComponents();
555      std::vector<std::string> inComponents = base::Split(package, ".");
556  
557      if (inComponents.size() > components.size()) {
558          return false;
559      }
560  
561      for (size_t i = 0; i < inComponents.size(); i++) {
562          if (inComponents[i] != components[i]) {
563              return false;
564          }
565      }
566  
567      return true;
568  }
569  
570  FQName FQName::downRev() const {
571      FQName ret(*this);
572      CHECK(ret.mMinor > 0);
573      ret.mMinor--;
574      return ret;
575  }
576  
577  FQName FQName::upRev() const {
578      FQName ret(*this);
579      ret.mMinor++;
580      CHECK(ret.mMinor > 0);
581      return ret;
582  }
583  
584  }  // namespace android
585  
586