• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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 <vintf/FQName.h>
18 
19 #include <android-base/logging.h>
20 #include <android-base/parseint.h>
21 #include <android-base/strings.h>
22 #include <constants-private.h>
23 #include <iostream>
24 #include <sstream>
25 
26 namespace android::vintf::details {
27 
FQName()28 FQName::FQName() : mIsIdentifier(false) {}
29 
parse(const std::string & s,FQName * into)30 bool FQName::parse(const std::string& s, FQName* into) {
31     return into->setTo(s);
32 }
33 
FQName(const std::string & package,const std::string & version,const std::string & name)34 FQName::FQName(const std::string& package, const std::string& version, const std::string& name) {
35     size_t majorVer, minorVer;
36     CHECK(parseVersion(version, &majorVer, &minorVer));
37     CHECK(setTo(package, majorVer, minorVer, name)) << string();
38 }
39 
setTo(const std::string & package,size_t majorVer,size_t minorVer,const std::string & name)40 bool FQName::setTo(const std::string& package, size_t majorVer, size_t minorVer,
41                    const std::string& name) {
42     mPackage = package;
43     mMajor = majorVer;
44     mMinor = minorVer;
45     mName = name;
46 
47     FQName other;
48     if (!parse(parsedString(), &other)) return false;
49     if ((*this) != other) return false;
50     mIsIdentifier = other.isIdentifier();
51     return true;
52 }
53 
isIdentifier() const54 bool FQName::isIdentifier() const {
55     return mIsIdentifier;
56 }
57 
isInterfaceName() const58 bool FQName::isInterfaceName() const {
59     return !mName.empty() && mName[0] == 'I' && mName.find('.') == std::string::npos;
60 }
61 
isIdentStart(char a)62 static inline bool isIdentStart(char a) {
63     return ('a' <= a && a <= 'z') || ('A' <= a && a <= 'Z') || a == '_';
64 }
isLeadingDigit(char a)65 static inline bool isLeadingDigit(char a) {
66     return '1' <= a && a <= '9';
67 }
isDigit(char a)68 static inline bool isDigit(char a) {
69     return '0' <= a && a <= '9';
70 }
isIdentBody(char a)71 static inline bool isIdentBody(char a) {
72     return isIdentStart(a) || isDigit(a);
73 }
74 
75 // returns pointer to end of [a-zA-Z_][a-zA-Z0-9_]*
eatIdent(const char * l,const char * end)76 static const char* eatIdent(const char* l, const char* end) {
77     if (!(l < end && isIdentStart(*l++))) return nullptr;
78     while (l < end && isIdentBody(*l)) l++;
79     return l;
80 }
81 
82 // returns pointer to end of <ident>(\.<ident>)*
eatPackage(const char * l,const char * end)83 static const char* eatPackage(const char* l, const char* end) {
84     if ((l = eatIdent(l, end)) == nullptr) return nullptr;
85 
86     while (l < end && *l == '.') {
87         l++;
88         if ((l = eatIdent(l, end)) == nullptr) return nullptr;
89     }
90     return l;
91 }
92 
93 // returns pointer to end of [1-9][0-9]*|0
eatNumber(const char * l,const char * end)94 static const char* eatNumber(const char* l, const char* end) {
95     if (!(l < end)) return nullptr;
96     if (*l == '0') return l + 1;
97     if (!isLeadingDigit(*l++)) return nullptr;
98     while (l < end && isDigit(*l)) l++;
99     return l;
100 }
101 
setTo(const std::string & s)102 bool FQName::setTo(const std::string& s) {
103     clear();
104 
105     if (s.empty()) return false;
106 
107     const char* l = s.c_str();
108     const char* end = l + s.size();
109     // android.hardware.foo@10.12::IFoo.Type
110     // S                   ES ES E S        E
111     //
112     // S - start pointer
113     // E - end pointer
114 
115     struct StartEnd {
116         const char* start = nullptr;
117         const char* end = nullptr;
118 
119         std::string string() {
120             if (start == nullptr) return std::string();
121             return std::string(start, end - start);
122         }
123     };
124     StartEnd package, major, minor, name;
125 
126     if (l < end && isIdentStart(*l)) {
127         package.start = l;
128         if ((package.end = l = eatPackage(l, end)) == nullptr) return false;
129     }
130     if (l < end && *l == '@') {
131         l++;
132 
133         major.start = l;
134         if ((major.end = l = eatNumber(l, end)) == nullptr) return false;
135 
136         if (!(l < end && *l++ == '.')) return false;
137 
138         minor.start = l;
139         if ((minor.end = l = eatNumber(l, end)) == nullptr) return false;
140     }
141     if (l < end && *l == ':') {
142         l++;
143         if (l < end && *l == ':') {
144             l++;
145             name.start = l;
146             if ((name.end = l = eatPackage(l, end)) == nullptr) return false;
147         } else {
148             return false;
149         }
150     }
151 
152     if (l < end) return false;
153 
154     CHECK((major.start == nullptr) == (minor.start == nullptr));
155 
156     // if we only parse a package, consider this to be a name
157     if (name.start == nullptr && major.start == nullptr) {
158         name.start = package.start;
159         name.end = package.end;
160         package.start = package.end = nullptr;
161     }
162 
163     // failures after this goto fail to clear
164     mName = name.string();
165     mPackage = package.string();
166 
167     if (major.start != nullptr) {
168         if (!parseVersion(major.string(), minor.string(), &mMajor, &mMinor)) goto fail;
169     } else if (mPackage.empty() && name.end == eatIdent(name.start, name.end)) {
170         // major.start == nullptr
171         mIsIdentifier = true;
172     }
173 
174     if (!mPackage.empty() && version().empty()) goto fail;
175 
176     return true;
177 fail:
178     clear();
179     return false;
180 }
181 
package() const182 const std::string& FQName::package() const {
183     return mPackage;
184 }
185 
version() const186 std::string FQName::version() const {
187     if (!hasVersion()) {
188         return "";
189     }
190     if (mMajor == details::kFakeAidlMajorVersion) {
191         return std::to_string(mMinor);
192     }
193     return std::to_string(mMajor) + "." + std::to_string(mMinor);
194 }
195 
parsedVersion() const196 std::string FQName::parsedVersion() const {
197     if (!hasVersion()) {
198         return "";
199     }
200 
201     return std::to_string(mMajor) + "." + std::to_string(mMinor);
202 }
203 
atVersion() const204 std::string FQName::atVersion() const {
205     std::string v = version();
206     return v.empty() ? "" : ("@" + v);
207 }
208 
parsedAtVersion() const209 std::string FQName::parsedAtVersion() const {
210     std::string v = parsedVersion();
211     return v.empty() ? "" : ("@" + v);
212 }
213 
clear()214 void FQName::clear() {
215     mIsIdentifier = false;
216     mPackage.clear();
217     clearVersion();
218     mName.clear();
219 }
220 
clearVersion(size_t * majorVer,size_t * minorVer)221 void FQName::clearVersion(size_t* majorVer, size_t* minorVer) {
222     *majorVer = *minorVer = 0;
223 }
224 
parseVersion(const std::string & majorStr,const std::string & minorStr,size_t * majorVer,size_t * minorVer)225 bool FQName::parseVersion(const std::string& majorStr, const std::string& minorStr,
226                           size_t* majorVer, size_t* minorVer) {
227     bool versionParseSuccess = ::android::base::ParseUint(majorStr, majorVer) &&
228                                ::android::base::ParseUint(minorStr, minorVer);
229     if (!versionParseSuccess) {
230         LOG(ERROR) << "numbers in " << majorStr << "." << minorStr << " are out of range.";
231     }
232     return versionParseSuccess;
233 }
234 
parseVersion(const std::string & v,size_t * majorVer,size_t * minorVer)235 bool FQName::parseVersion(const std::string& v, size_t* majorVer, size_t* minorVer) {
236     if (v.empty()) {
237         clearVersion(majorVer, minorVer);
238         return true;
239     }
240 
241     std::vector<std::string> vs = base::Split(v, ".");
242     if (vs.size() != 2) return false;
243     return parseVersion(vs[0], vs[1], majorVer, minorVer);
244 }
245 
setVersion(const std::string & v)246 bool FQName::setVersion(const std::string& v) {
247     return parseVersion(v, &mMajor, &mMinor);
248 }
249 
clearVersion()250 void FQName::clearVersion() {
251     clearVersion(&mMajor, &mMinor);
252 }
253 
parseVersion(const std::string & majorStr,const std::string & minorStr)254 bool FQName::parseVersion(const std::string& majorStr, const std::string& minorStr) {
255     return parseVersion(majorStr, minorStr, &mMajor, &mMinor);
256 }
257 
name() const258 const std::string& FQName::name() const {
259     return mName;
260 }
261 
parsedString() const262 std::string FQName::parsedString() const {
263     std::string out;
264     out.append(mPackage);
265     out.append(parsedAtVersion());
266     if (!mName.empty()) {
267         if (!mPackage.empty() || !parsedVersion().empty()) {
268             out.append("::");
269         }
270         out.append(mName);
271     }
272 
273     return out;
274 }
275 
string() const276 std::string FQName::string() const {
277     std::string out;
278     out.append(mPackage);
279     out.append(atVersion());
280     if (!mName.empty()) {
281         if (!mPackage.empty() || !version().empty()) {
282             out.append("::");
283         }
284         out.append(mName);
285     }
286 
287     return out;
288 }
289 
operator <(const FQName & other) const290 bool FQName::operator<(const FQName& other) const {
291     return string() < other.string();
292 }
293 
operator ==(const FQName & other) const294 bool FQName::operator==(const FQName& other) const {
295     return parsedString() == other.parsedString();
296 }
297 
operator !=(const FQName & other) const298 bool FQName::operator!=(const FQName& other) const {
299     return !(*this == other);
300 }
301 
getInterfaceName() const302 const std::string& FQName::getInterfaceName() const {
303     CHECK(isInterfaceName()) << mName;
304 
305     return mName;
306 }
307 
getPackageAndVersion() const308 FQName FQName::getPackageAndVersion() const {
309     return FQName(package(), version(), "");
310 }
311 
getPackageComponents() const312 std::vector<std::string> FQName::getPackageComponents() const {
313     return base::Split(package(), ".");
314 }
315 
hasVersion() const316 bool FQName::hasVersion() const {
317     return mMajor > 0;
318 }
319 
getVersion() const320 std::pair<size_t, size_t> FQName::getVersion() const {
321     return {mMajor, mMinor};
322 }
323 
getPackageMajorVersion() const324 size_t FQName::getPackageMajorVersion() const {
325     CHECK(hasVersion()) << "FQName: No version exists at getPackageMajorVersion(). "
326                         << "Did you check hasVersion()?";
327     return mMajor;
328 }
329 
getPackageMinorVersion() const330 size_t FQName::getPackageMinorVersion() const {
331     CHECK(hasVersion()) << "FQName: No version exists at getPackageMinorVersion(). "
332                         << "Did you check hasVersion()?";
333     return mMinor;
334 }
335 
inPackage(const std::string & package) const336 bool FQName::inPackage(const std::string& package) const {
337     std::vector<std::string> components = getPackageComponents();
338     std::vector<std::string> inComponents = base::Split(package, ".");
339 
340     if (inComponents.size() > components.size()) {
341         return false;
342     }
343 
344     for (size_t i = 0; i < inComponents.size(); i++) {
345         if (inComponents[i] != components[i]) {
346             return false;
347         }
348     }
349 
350     return true;
351 }
352 
353 }  // namespace android::vintf::details
354