312 lines
8.4 KiB
C++
312 lines
8.4 KiB
C++
#include "aidl_language.h"
|
|
|
|
#include <iostream>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <string>
|
|
|
|
#include <android-base/parseint.h>
|
|
#include <android-base/strings.h>
|
|
|
|
#include "aidl_language_y.h"
|
|
#include "logging.h"
|
|
|
|
#ifdef _WIN32
|
|
int isatty(int fd)
|
|
{
|
|
return (fd == 0);
|
|
}
|
|
#endif
|
|
|
|
using android::aidl::IoDelegate;
|
|
using android::base::Join;
|
|
using android::base::Split;
|
|
using std::cerr;
|
|
using std::endl;
|
|
using std::string;
|
|
using std::unique_ptr;
|
|
|
|
void yylex_init(void **);
|
|
void yylex_destroy(void *);
|
|
void yyset_in(FILE *f, void *);
|
|
int yyparse(Parser*);
|
|
YY_BUFFER_STATE yy_scan_buffer(char *, size_t, void *);
|
|
void yy_delete_buffer(YY_BUFFER_STATE, void *);
|
|
|
|
AidlToken::AidlToken(const std::string& text, const std::string& comments)
|
|
: text_(text),
|
|
comments_(comments) {}
|
|
|
|
AidlType::AidlType(const std::string& name, unsigned line,
|
|
const std::string& comments, bool is_array)
|
|
: name_(name),
|
|
line_(line),
|
|
is_array_(is_array),
|
|
comments_(comments) {}
|
|
|
|
string AidlType::ToString() const {
|
|
return name_ + (is_array_ ? "[]" : "");
|
|
}
|
|
|
|
AidlArgument::AidlArgument(AidlArgument::Direction direction, AidlType* type,
|
|
std::string name, unsigned line)
|
|
: type_(type),
|
|
direction_(direction),
|
|
direction_specified_(true),
|
|
name_(name),
|
|
line_(line) {}
|
|
|
|
AidlArgument::AidlArgument(AidlType* type, std::string name, unsigned line)
|
|
: type_(type),
|
|
direction_(AidlArgument::IN_DIR),
|
|
direction_specified_(false),
|
|
name_(name),
|
|
line_(line) {}
|
|
|
|
string AidlArgument::ToString() const {
|
|
string ret;
|
|
|
|
if (direction_specified_) {
|
|
switch(direction_) {
|
|
case AidlArgument::IN_DIR:
|
|
ret += "in ";
|
|
break;
|
|
case AidlArgument::OUT_DIR:
|
|
ret += "out ";
|
|
break;
|
|
case AidlArgument::INOUT_DIR:
|
|
ret += "inout ";
|
|
break;
|
|
}
|
|
}
|
|
|
|
ret += type_->ToString();
|
|
ret += " ";
|
|
ret += name_;
|
|
|
|
return ret;
|
|
}
|
|
|
|
AidlIntConstant::AidlIntConstant(std::string name, int32_t value)
|
|
: name_(name),
|
|
value_(value),
|
|
is_valid_(true) {}
|
|
|
|
AidlIntConstant::AidlIntConstant(std::string name,
|
|
std::string value,
|
|
unsigned line_number)
|
|
: name_(name) {
|
|
uint32_t unsigned_val;
|
|
if (!android::base::ParseUint(value.c_str(), &unsigned_val)) {
|
|
is_valid_ = false;
|
|
LOG(ERROR) << "Found invalid int value '" << value
|
|
<< "' on line " << line_number;
|
|
} else {
|
|
// Converting from unsigned to signed integer.
|
|
value_ = unsigned_val;
|
|
is_valid_ = true;
|
|
}
|
|
}
|
|
|
|
AidlStringConstant::AidlStringConstant(std::string name,
|
|
std::string value,
|
|
unsigned line_number)
|
|
: name_(name),
|
|
value_(value) {
|
|
is_valid_ = true;
|
|
for (size_t i = 0; i < value_.length(); ++i) {
|
|
const char& c = value_[i];
|
|
if (c <= 0x1f || // control characters are < 0x20
|
|
c >= 0x7f || // DEL is 0x7f
|
|
c == '\\') { // Disallow backslashes for future proofing.
|
|
LOG(ERROR) << "Found invalid character at index " << i
|
|
<< " in string constant '" << value_
|
|
<< "' beginning on line " << line_number;
|
|
is_valid_ = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
AidlMethod::AidlMethod(bool oneway, AidlType* type, std::string name,
|
|
std::vector<std::unique_ptr<AidlArgument>>* args,
|
|
unsigned line, const std::string& comments, int id)
|
|
: oneway_(oneway),
|
|
comments_(comments),
|
|
type_(type),
|
|
name_(name),
|
|
line_(line),
|
|
arguments_(std::move(*args)),
|
|
id_(id) {
|
|
has_id_ = true;
|
|
delete args;
|
|
for (const unique_ptr<AidlArgument>& a : arguments_) {
|
|
if (a->IsIn()) { in_arguments_.push_back(a.get()); }
|
|
if (a->IsOut()) { out_arguments_.push_back(a.get()); }
|
|
}
|
|
}
|
|
|
|
AidlMethod::AidlMethod(bool oneway, AidlType* type, std::string name,
|
|
std::vector<std::unique_ptr<AidlArgument>>* args,
|
|
unsigned line, const std::string& comments)
|
|
: AidlMethod(oneway, type, name, args, line, comments, 0) {
|
|
has_id_ = false;
|
|
}
|
|
|
|
Parser::Parser(const IoDelegate& io_delegate)
|
|
: io_delegate_(io_delegate) {
|
|
yylex_init(&scanner_);
|
|
}
|
|
|
|
AidlParcelable::AidlParcelable(AidlQualifiedName* name, unsigned line,
|
|
const std::vector<std::string>& package,
|
|
const std::string& cpp_header)
|
|
: name_(name),
|
|
line_(line),
|
|
package_(package),
|
|
cpp_header_(cpp_header) {
|
|
// Strip off quotation marks if we actually have a cpp header.
|
|
if (cpp_header_.length() >= 2) {
|
|
cpp_header_ = cpp_header_.substr(1, cpp_header_.length() - 2);
|
|
}
|
|
}
|
|
|
|
std::string AidlParcelable::GetPackage() const {
|
|
return Join(package_, '.');
|
|
}
|
|
|
|
std::string AidlParcelable::GetCanonicalName() const {
|
|
if (package_.empty()) {
|
|
return GetName();
|
|
}
|
|
return GetPackage() + "." + GetName();
|
|
}
|
|
|
|
AidlInterface::AidlInterface(const std::string& name, unsigned line,
|
|
const std::string& comments, bool oneway,
|
|
std::vector<std::unique_ptr<AidlMember>>* members,
|
|
const std::vector<std::string>& package)
|
|
: name_(name),
|
|
comments_(comments),
|
|
line_(line),
|
|
oneway_(oneway),
|
|
package_(package) {
|
|
for (auto& member : *members) {
|
|
AidlMember* local = member.release();
|
|
AidlMethod* method = local->AsMethod();
|
|
AidlIntConstant* int_constant = local->AsIntConstant();
|
|
AidlStringConstant* string_constant = local->AsStringConstant();
|
|
|
|
if (method) {
|
|
methods_.emplace_back(method);
|
|
} else if (int_constant) {
|
|
int_constants_.emplace_back(int_constant);
|
|
} else if (string_constant) {
|
|
string_constants_.emplace_back(string_constant);
|
|
} else {
|
|
LOG(FATAL) << "Member is neither method nor constant!";
|
|
}
|
|
}
|
|
|
|
delete members;
|
|
}
|
|
|
|
std::string AidlInterface::GetPackage() const {
|
|
return Join(package_, '.');
|
|
}
|
|
|
|
std::string AidlInterface::GetCanonicalName() const {
|
|
if (package_.empty()) {
|
|
return GetName();
|
|
}
|
|
return GetPackage() + "." + GetName();
|
|
}
|
|
|
|
AidlDocument::AidlDocument(AidlInterface* interface)
|
|
: interface_(interface) {}
|
|
|
|
AidlQualifiedName::AidlQualifiedName(std::string term,
|
|
std::string comments)
|
|
: terms_({term}),
|
|
comments_(comments) {
|
|
if (term.find('.') != string::npos) {
|
|
terms_ = Split(term, ".");
|
|
for (const auto& term: terms_) {
|
|
if (term.empty()) {
|
|
LOG(FATAL) << "Malformed qualified identifier: '" << term << "'";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void AidlQualifiedName::AddTerm(const std::string& term) {
|
|
terms_.push_back(term);
|
|
}
|
|
|
|
AidlImport::AidlImport(const std::string& from,
|
|
const std::string& needed_class, unsigned line)
|
|
: from_(from),
|
|
needed_class_(needed_class),
|
|
line_(line) {}
|
|
|
|
Parser::~Parser() {
|
|
if (raw_buffer_) {
|
|
yy_delete_buffer(buffer_, scanner_);
|
|
raw_buffer_.reset();
|
|
}
|
|
yylex_destroy(scanner_);
|
|
}
|
|
|
|
bool Parser::ParseFile(const string& filename) {
|
|
// Make sure we can read the file first, before trashing previous state.
|
|
unique_ptr<string> new_buffer = io_delegate_.GetFileContents(filename);
|
|
if (!new_buffer) {
|
|
LOG(ERROR) << "Error while opening file for parsing: '" << filename << "'";
|
|
return false;
|
|
}
|
|
|
|
// Throw away old parsing state if we have any.
|
|
if (raw_buffer_) {
|
|
yy_delete_buffer(buffer_, scanner_);
|
|
raw_buffer_.reset();
|
|
}
|
|
|
|
raw_buffer_ = std::move(new_buffer);
|
|
// We're going to scan this buffer in place, and yacc demands we put two
|
|
// nulls at the end.
|
|
raw_buffer_->append(2u, '\0');
|
|
filename_ = filename;
|
|
package_.reset();
|
|
error_ = 0;
|
|
document_.reset();
|
|
|
|
buffer_ = yy_scan_buffer(&(*raw_buffer_)[0], raw_buffer_->length(), scanner_);
|
|
|
|
if (yy::parser(this).parse() != 0 || error_ != 0) {
|
|
return false;}
|
|
|
|
if (document_.get() != nullptr)
|
|
return true;
|
|
|
|
LOG(ERROR) << "Parser succeeded but yielded no document!";
|
|
return false;
|
|
}
|
|
|
|
void Parser::ReportError(const string& err, unsigned line) {
|
|
cerr << filename_ << ":" << line << ": " << err << endl;
|
|
error_ = 1;
|
|
}
|
|
|
|
std::vector<std::string> Parser::Package() const {
|
|
if (!package_) {
|
|
return {};
|
|
}
|
|
return package_->GetTerms();
|
|
}
|
|
|
|
void Parser::AddImport(AidlQualifiedName* name, unsigned line) {
|
|
imports_.emplace_back(new AidlImport(this->FileName(),
|
|
name->GetDotName(), line));
|
|
delete name;
|
|
}
|