AAPT2: Move all file output to FileOutputStream
FileOutputStream is safe to use on Windows, as it opens files using our compatibility API. Bug: 68262818 Test: make aapt2_tests Change-Id: Ib0b27e93edd609b49b1327db7d9867a002198ebb
This commit is contained in:
@@ -268,6 +268,11 @@ inline ::std::ostream& operator<<(::std::ostream& out, const ResourceId& res_id)
|
||||
return out << res_id.to_string();
|
||||
}
|
||||
|
||||
// For generic code to call 'using std::to_string; to_string(T);'.
|
||||
inline std::string to_string(const ResourceId& id) {
|
||||
return id.to_string();
|
||||
}
|
||||
|
||||
//
|
||||
// ResourceType implementation.
|
||||
//
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <queue>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
@@ -212,6 +211,8 @@ class LinkContext : public IAaptContext {
|
||||
// This delegate will attempt to masquerade any '@id/' references with ID 0xPPTTEEEE,
|
||||
// where PP > 7f, as 0x7fPPEEEE. Any potential overlapping is verified and an error occurs if such
|
||||
// an overlap exists.
|
||||
//
|
||||
// See b/37498913.
|
||||
class FeatureSplitSymbolTableDelegate : public DefaultSymbolTableDelegate {
|
||||
public:
|
||||
FeatureSplitSymbolTableDelegate(IAaptContext* context) : context_(context) {
|
||||
@@ -652,24 +653,26 @@ bool ResourceFileFlattener::Flatten(ResourceTable* table, IArchiveWriter* archiv
|
||||
static bool WriteStableIdMapToPath(IDiagnostics* diag,
|
||||
const std::unordered_map<ResourceName, ResourceId>& id_map,
|
||||
const std::string& id_map_path) {
|
||||
std::ofstream fout(id_map_path, std::ofstream::binary);
|
||||
if (!fout) {
|
||||
diag->Error(DiagMessage(id_map_path) << strerror(errno));
|
||||
io::FileOutputStream fout(id_map_path);
|
||||
if (fout.HadError()) {
|
||||
diag->Error(DiagMessage(id_map_path) << "failed to open: " << fout.GetError());
|
||||
return false;
|
||||
}
|
||||
|
||||
text::Printer printer(&fout);
|
||||
for (const auto& entry : id_map) {
|
||||
const ResourceName& name = entry.first;
|
||||
const ResourceId& id = entry.second;
|
||||
fout << name << " = " << id << "\n";
|
||||
printer.Print(name.to_string());
|
||||
printer.Print(" = ");
|
||||
printer.Println(id.to_string());
|
||||
}
|
||||
fout.Flush();
|
||||
|
||||
if (!fout) {
|
||||
diag->Error(DiagMessage(id_map_path) << "failed writing to file: "
|
||||
<< android::base::SystemErrorCodeToString(errno));
|
||||
if (fout.HadError()) {
|
||||
diag->Error(DiagMessage(id_map_path) << "failed writing to file: " << fout.GetError());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -985,36 +988,35 @@ class LinkCommand {
|
||||
|
||||
file::AppendPath(&out_path, "R.java");
|
||||
|
||||
std::ofstream fout(out_path, std::ofstream::binary);
|
||||
if (!fout) {
|
||||
context_->GetDiagnostics()->Error(DiagMessage()
|
||||
<< "failed writing to '" << out_path
|
||||
<< "': " << android::base::SystemErrorCodeToString(errno));
|
||||
io::FileOutputStream fout(out_path);
|
||||
if (fout.HadError()) {
|
||||
context_->GetDiagnostics()->Error(DiagMessage() << "failed writing to '" << out_path
|
||||
<< "': " << fout.GetError());
|
||||
return false;
|
||||
}
|
||||
|
||||
std::unique_ptr<std::ofstream> fout_text;
|
||||
std::unique_ptr<io::FileOutputStream> fout_text;
|
||||
if (out_text_symbols_path) {
|
||||
fout_text =
|
||||
util::make_unique<std::ofstream>(out_text_symbols_path.value(), std::ofstream::binary);
|
||||
if (!*fout_text) {
|
||||
context_->GetDiagnostics()->Error(
|
||||
DiagMessage() << "failed writing to '" << out_text_symbols_path.value()
|
||||
<< "': " << android::base::SystemErrorCodeToString(errno));
|
||||
fout_text = util::make_unique<io::FileOutputStream>(out_text_symbols_path.value());
|
||||
if (fout_text->HadError()) {
|
||||
context_->GetDiagnostics()->Error(DiagMessage()
|
||||
<< "failed writing to '" << out_text_symbols_path.value()
|
||||
<< "': " << fout_text->GetError());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
JavaClassGenerator generator(context_, table, java_options);
|
||||
if (!generator.Generate(package_name_to_generate, out_package, &fout, fout_text.get())) {
|
||||
context_->GetDiagnostics()->Error(DiagMessage(out_path) << generator.getError());
|
||||
context_->GetDiagnostics()->Error(DiagMessage(out_path) << generator.GetError());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!fout) {
|
||||
context_->GetDiagnostics()->Error(DiagMessage()
|
||||
<< "failed writing to '" << out_path
|
||||
<< "': " << android::base::SystemErrorCodeToString(errno));
|
||||
fout.Flush();
|
||||
|
||||
if (fout.HadError()) {
|
||||
context_->GetDiagnostics()->Error(DiagMessage() << "failed writing to '" << out_path
|
||||
<< "': " << fout.GetError());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -1142,18 +1144,19 @@ class LinkCommand {
|
||||
|
||||
file::AppendPath(&out_path, "Manifest.java");
|
||||
|
||||
std::ofstream fout(out_path, std::ofstream::binary);
|
||||
if (!fout) {
|
||||
context_->GetDiagnostics()->Error(DiagMessage()
|
||||
<< "failed writing to '" << out_path
|
||||
<< "': " << android::base::SystemErrorCodeToString(errno));
|
||||
io::FileOutputStream fout(out_path);
|
||||
if (fout.HadError()) {
|
||||
context_->GetDiagnostics()->Error(DiagMessage() << "failed to open '" << out_path
|
||||
<< "': " << fout.GetError());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ClassDefinition::WriteJavaFile(manifest_class.get(), package_utf8, true, &fout)) {
|
||||
context_->GetDiagnostics()->Error(DiagMessage()
|
||||
<< "failed writing to '" << out_path
|
||||
<< "': " << android::base::SystemErrorCodeToString(errno));
|
||||
ClassDefinition::WriteJavaFile(manifest_class.get(), package_utf8, true, &fout);
|
||||
fout.Flush();
|
||||
|
||||
if (fout.HadError()) {
|
||||
context_->GetDiagnostics()->Error(DiagMessage() << "failed writing to '" << out_path
|
||||
<< "': " << fout.GetError());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -1165,19 +1168,19 @@ class LinkCommand {
|
||||
}
|
||||
|
||||
const std::string& out_path = out.value();
|
||||
std::ofstream fout(out_path, std::ofstream::binary);
|
||||
if (!fout) {
|
||||
context_->GetDiagnostics()->Error(DiagMessage()
|
||||
<< "failed to open '" << out_path
|
||||
<< "': " << android::base::SystemErrorCodeToString(errno));
|
||||
io::FileOutputStream fout(out_path);
|
||||
if (fout.HadError()) {
|
||||
context_->GetDiagnostics()->Error(DiagMessage() << "failed to open '" << out_path
|
||||
<< "': " << fout.GetError());
|
||||
return false;
|
||||
}
|
||||
|
||||
proguard::WriteKeepSet(&fout, keep_set);
|
||||
if (!fout) {
|
||||
context_->GetDiagnostics()->Error(DiagMessage()
|
||||
<< "failed writing to '" << out_path
|
||||
<< "': " << android::base::SystemErrorCodeToString(errno));
|
||||
proguard::WriteKeepSet(keep_set, &fout);
|
||||
fout.Flush();
|
||||
|
||||
if (fout.HadError()) {
|
||||
context_->GetDiagnostics()->Error(DiagMessage() << "failed writing to '" << out_path
|
||||
<< "': " << fout.GetError());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -25,6 +25,12 @@
|
||||
#include "android-base/macros.h"
|
||||
#include "android-base/utf8.h"
|
||||
|
||||
#if defined(_WIN32)
|
||||
// This is only needed for O_CLOEXEC.
|
||||
#include <windows.h>
|
||||
#define O_CLOEXEC O_NOINHERIT
|
||||
#endif
|
||||
|
||||
using ::android::base::SystemErrorCodeToString;
|
||||
using ::android::base::unique_fd;
|
||||
|
||||
@@ -32,18 +38,20 @@ namespace aapt {
|
||||
namespace io {
|
||||
|
||||
FileInputStream::FileInputStream(const std::string& path, size_t buffer_capacity)
|
||||
: FileInputStream(::android::base::utf8::open(path.c_str(), O_RDONLY | O_BINARY),
|
||||
buffer_capacity) {
|
||||
: buffer_capacity_(buffer_capacity) {
|
||||
int mode = O_RDONLY | O_CLOEXEC | O_BINARY;
|
||||
fd_.reset(TEMP_FAILURE_RETRY(::android::base::utf8::open(path.c_str(), mode)));
|
||||
if (fd_ == -1) {
|
||||
error_ = SystemErrorCodeToString(errno);
|
||||
} else {
|
||||
buffer_.reset(new uint8_t[buffer_capacity_]);
|
||||
}
|
||||
}
|
||||
|
||||
FileInputStream::FileInputStream(int fd, size_t buffer_capacity)
|
||||
: fd_(fd),
|
||||
buffer_capacity_(buffer_capacity),
|
||||
buffer_offset_(0u),
|
||||
buffer_size_(0u),
|
||||
total_byte_count_(0u) {
|
||||
if (fd_ == -1) {
|
||||
error_ = SystemErrorCodeToString(errno);
|
||||
: fd_(fd), buffer_capacity_(buffer_capacity) {
|
||||
if (fd_ < 0) {
|
||||
error_ = "Bad File Descriptor";
|
||||
} else {
|
||||
buffer_.reset(new uint8_t[buffer_capacity_]);
|
||||
}
|
||||
@@ -100,9 +108,16 @@ std::string FileInputStream::GetError() const {
|
||||
return error_;
|
||||
}
|
||||
|
||||
FileOutputStream::FileOutputStream(const std::string& path, int mode, size_t buffer_capacity)
|
||||
: FileOutputStream(unique_fd(::android::base::utf8::open(path.c_str(), mode)),
|
||||
buffer_capacity) {
|
||||
FileOutputStream::FileOutputStream(const std::string& path, size_t buffer_capacity)
|
||||
: buffer_capacity_(buffer_capacity) {
|
||||
int mode = O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_BINARY;
|
||||
owned_fd_.reset(TEMP_FAILURE_RETRY(::android::base::utf8::open(path.c_str(), mode, 0666)));
|
||||
fd_ = owned_fd_.get();
|
||||
if (fd_ < 0) {
|
||||
error_ = SystemErrorCodeToString(errno);
|
||||
} else {
|
||||
buffer_.reset(new uint8_t[buffer_capacity_]);
|
||||
}
|
||||
}
|
||||
|
||||
FileOutputStream::FileOutputStream(unique_fd fd, size_t buffer_capacity)
|
||||
@@ -111,9 +126,9 @@ FileOutputStream::FileOutputStream(unique_fd fd, size_t buffer_capacity)
|
||||
}
|
||||
|
||||
FileOutputStream::FileOutputStream(int fd, size_t buffer_capacity)
|
||||
: fd_(fd), buffer_capacity_(buffer_capacity), buffer_offset_(0u), total_byte_count_(0u) {
|
||||
if (fd_ == -1) {
|
||||
error_ = SystemErrorCodeToString(errno);
|
||||
: fd_(fd), buffer_capacity_(buffer_capacity) {
|
||||
if (fd_ < 0) {
|
||||
error_ = "Bad File Descriptor";
|
||||
} else {
|
||||
buffer_.reset(new uint8_t[buffer_capacity_]);
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "android-base/file.h" // for O_BINARY
|
||||
#include "android-base/macros.h"
|
||||
#include "android-base/unique_fd.h"
|
||||
|
||||
@@ -55,15 +54,15 @@ class FileInputStream : public InputStream {
|
||||
android::base::unique_fd fd_;
|
||||
std::string error_;
|
||||
std::unique_ptr<uint8_t[]> buffer_;
|
||||
size_t buffer_capacity_;
|
||||
size_t buffer_offset_;
|
||||
size_t buffer_size_;
|
||||
size_t total_byte_count_;
|
||||
size_t buffer_capacity_ = 0u;
|
||||
size_t buffer_offset_ = 0u;
|
||||
size_t buffer_size_ = 0u;
|
||||
size_t total_byte_count_ = 0u;
|
||||
};
|
||||
|
||||
class FileOutputStream : public OutputStream {
|
||||
public:
|
||||
explicit FileOutputStream(const std::string& path, int mode = O_RDWR | O_CREAT | O_BINARY,
|
||||
explicit FileOutputStream(const std::string& path,
|
||||
size_t buffer_capacity = kDefaultBufferCapacity);
|
||||
|
||||
// Does not take ownership of `fd`.
|
||||
@@ -97,9 +96,9 @@ class FileOutputStream : public OutputStream {
|
||||
int fd_;
|
||||
std::string error_;
|
||||
std::unique_ptr<uint8_t[]> buffer_;
|
||||
size_t buffer_capacity_;
|
||||
size_t buffer_offset_;
|
||||
size_t total_byte_count_;
|
||||
size_t buffer_capacity_ = 0u;
|
||||
size_t buffer_offset_ = 0u;
|
||||
size_t total_byte_count_ = 0u;
|
||||
};
|
||||
|
||||
} // namespace io
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
#include "io/FileStream.h"
|
||||
|
||||
#include "android-base/file.h"
|
||||
#include "android-base/macros.h"
|
||||
#include "android-base/test_utils.h"
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "text/Utf8Iterator.h"
|
||||
#include "util/Util.h"
|
||||
|
||||
using ::aapt::text::Printer;
|
||||
using ::aapt::text::Utf8Iterator;
|
||||
using ::android::StringPiece;
|
||||
|
||||
@@ -109,23 +110,22 @@ void AnnotationProcessor::AppendNewLine() {
|
||||
}
|
||||
}
|
||||
|
||||
void AnnotationProcessor::WriteToStream(const StringPiece& prefix, std::ostream* out) const {
|
||||
void AnnotationProcessor::Print(Printer* printer) const {
|
||||
if (has_comments_) {
|
||||
std::string result = comment_.str();
|
||||
for (StringPiece line : util::Tokenize(result, '\n')) {
|
||||
*out << prefix << line << "\n";
|
||||
printer->Println(line);
|
||||
}
|
||||
*out << prefix << " */"
|
||||
<< "\n";
|
||||
printer->Println(" */");
|
||||
}
|
||||
|
||||
if (annotation_bit_mask_ & AnnotationRule::kDeprecated) {
|
||||
*out << prefix << "@Deprecated\n";
|
||||
printer->Println("@Deprecated");
|
||||
}
|
||||
|
||||
for (const AnnotationRule& rule : sAnnotationRules) {
|
||||
if (annotation_bit_mask_ & rule.bit_mask) {
|
||||
*out << prefix << rule.annotation << "\n";
|
||||
printer->Println(rule.annotation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
|
||||
#include "androidfw/StringPiece.h"
|
||||
|
||||
#include "text/Printer.h"
|
||||
|
||||
namespace aapt {
|
||||
|
||||
// Builds a JavaDoc comment from a set of XML comments.
|
||||
@@ -61,8 +63,8 @@ class AnnotationProcessor {
|
||||
|
||||
void AppendNewLine();
|
||||
|
||||
// Writes the comments and annotations to the stream, with the given prefix before each line.
|
||||
void WriteToStream(const android::StringPiece& prefix, std::ostream* out) const;
|
||||
// Writes the comments and annotations to the Printer.
|
||||
void Print(text::Printer* printer) const;
|
||||
|
||||
private:
|
||||
std::stringstream comment_;
|
||||
|
||||
@@ -16,8 +16,12 @@
|
||||
|
||||
#include "java/AnnotationProcessor.h"
|
||||
|
||||
#include "io/StringStream.h"
|
||||
#include "test/Test.h"
|
||||
#include "text/Printer.h"
|
||||
|
||||
using ::aapt::io::StringOutputStream;
|
||||
using ::aapt::text::Printer;
|
||||
using ::testing::Eq;
|
||||
using ::testing::HasSubstr;
|
||||
using ::testing::Not;
|
||||
@@ -33,9 +37,11 @@ TEST(AnnotationProcessorTest, EmitsDeprecated) {
|
||||
AnnotationProcessor processor;
|
||||
processor.AppendComment(comment);
|
||||
|
||||
std::stringstream result;
|
||||
processor.WriteToStream("", &result);
|
||||
std::string annotations = result.str();
|
||||
std::string annotations;
|
||||
StringOutputStream out(&annotations);
|
||||
Printer printer(&out);
|
||||
processor.Print(&printer);
|
||||
out.Flush();
|
||||
|
||||
EXPECT_THAT(annotations, HasSubstr("@Deprecated"));
|
||||
}
|
||||
@@ -44,9 +50,11 @@ TEST(AnnotationProcessorTest, EmitsSystemApiAnnotationAndRemovesFromComment) {
|
||||
AnnotationProcessor processor;
|
||||
processor.AppendComment("@SystemApi This is a system API");
|
||||
|
||||
std::stringstream result;
|
||||
processor.WriteToStream("", &result);
|
||||
std::string annotations = result.str();
|
||||
std::string annotations;
|
||||
StringOutputStream out(&annotations);
|
||||
Printer printer(&out);
|
||||
processor.Print(&printer);
|
||||
out.Flush();
|
||||
|
||||
EXPECT_THAT(annotations, HasSubstr("@android.annotation.SystemApi"));
|
||||
EXPECT_THAT(annotations, Not(HasSubstr("@SystemApi")));
|
||||
@@ -57,9 +65,11 @@ TEST(AnnotationProcessorTest, EmitsTestApiAnnotationAndRemovesFromComment) {
|
||||
AnnotationProcessor processor;
|
||||
processor.AppendComment("@TestApi This is a test API");
|
||||
|
||||
std::stringstream result;
|
||||
processor.WriteToStream("", &result);
|
||||
std::string annotations = result.str();
|
||||
std::string annotations;
|
||||
StringOutputStream out(&annotations);
|
||||
Printer printer(&out);
|
||||
processor.Print(&printer);
|
||||
out.Flush();
|
||||
|
||||
EXPECT_THAT(annotations, HasSubstr("@android.annotation.TestApi"));
|
||||
EXPECT_THAT(annotations, Not(HasSubstr("@TestApi")));
|
||||
|
||||
@@ -18,25 +18,27 @@
|
||||
|
||||
#include "androidfw/StringPiece.h"
|
||||
|
||||
using ::aapt::text::Printer;
|
||||
using ::android::StringPiece;
|
||||
|
||||
namespace aapt {
|
||||
|
||||
void ClassMember::WriteToStream(const StringPiece& prefix, bool final, std::ostream* out) const {
|
||||
processor_.WriteToStream(prefix, out);
|
||||
void ClassMember::Print(bool /*final*/, Printer* printer) const {
|
||||
processor_.Print(printer);
|
||||
}
|
||||
|
||||
void MethodDefinition::AppendStatement(const StringPiece& statement) {
|
||||
statements_.push_back(statement.to_string());
|
||||
}
|
||||
|
||||
void MethodDefinition::WriteToStream(const StringPiece& prefix, bool final,
|
||||
std::ostream* out) const {
|
||||
*out << prefix << signature_ << " {\n";
|
||||
void MethodDefinition::Print(bool final, Printer* printer) const {
|
||||
printer->Print(signature_).Println(" {");
|
||||
printer->Indent();
|
||||
for (const auto& statement : statements_) {
|
||||
*out << prefix << " " << statement << "\n";
|
||||
printer->Println(statement);
|
||||
}
|
||||
*out << prefix << "}";
|
||||
printer->Undent();
|
||||
printer->Print("}");
|
||||
}
|
||||
|
||||
ClassDefinition::Result ClassDefinition::AddMember(std::unique_ptr<ClassMember> member) {
|
||||
@@ -62,34 +64,32 @@ bool ClassDefinition::empty() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
void ClassDefinition::WriteToStream(const StringPiece& prefix, bool final,
|
||||
std::ostream* out) const {
|
||||
void ClassDefinition::Print(bool final, Printer* printer) const {
|
||||
if (empty() && !create_if_empty_) {
|
||||
return;
|
||||
}
|
||||
|
||||
ClassMember::WriteToStream(prefix, final, out);
|
||||
ClassMember::Print(final, printer);
|
||||
|
||||
*out << prefix << "public ";
|
||||
printer->Print("public ");
|
||||
if (qualifier_ == ClassQualifier::kStatic) {
|
||||
*out << "static ";
|
||||
printer->Print("static ");
|
||||
}
|
||||
*out << "final class " << name_ << " {\n";
|
||||
|
||||
std::string new_prefix = prefix.to_string();
|
||||
new_prefix.append(kIndent);
|
||||
printer->Print("final class ").Print(name_).Println(" {");
|
||||
printer->Indent();
|
||||
|
||||
for (const std::unique_ptr<ClassMember>& member : ordered_members_) {
|
||||
// There can be nullptr members when a member is added to the ClassDefinition
|
||||
// and takes precedence over a previous member with the same name. The overridden member is
|
||||
// set to nullptr.
|
||||
if (member != nullptr) {
|
||||
member->WriteToStream(new_prefix, final, out);
|
||||
*out << "\n";
|
||||
member->Print(final, printer);
|
||||
printer->Println();
|
||||
}
|
||||
}
|
||||
|
||||
*out << prefix << "}";
|
||||
printer->Undent();
|
||||
printer->Print("}");
|
||||
}
|
||||
|
||||
constexpr static const char* sWarningHeader =
|
||||
@@ -100,11 +100,12 @@ constexpr static const char* sWarningHeader =
|
||||
" * should not be modified by hand.\n"
|
||||
" */\n\n";
|
||||
|
||||
bool ClassDefinition::WriteJavaFile(const ClassDefinition* def, const StringPiece& package,
|
||||
bool final, std::ostream* out) {
|
||||
*out << sWarningHeader << "package " << package << ";\n\n";
|
||||
def->WriteToStream("", final, out);
|
||||
return bool(*out);
|
||||
void ClassDefinition::WriteJavaFile(const ClassDefinition* def, const StringPiece& package,
|
||||
bool final, io::OutputStream* out) {
|
||||
Printer printer(out);
|
||||
printer.Print(sWarningHeader).Print("package ").Print(package).Println(";");
|
||||
printer.Println();
|
||||
def->Print(final, &printer);
|
||||
}
|
||||
|
||||
} // namespace aapt
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
#ifndef AAPT_JAVA_CLASSDEFINITION_H
|
||||
#define AAPT_JAVA_CLASSDEFINITION_H
|
||||
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
@@ -27,6 +26,7 @@
|
||||
|
||||
#include "Resource.h"
|
||||
#include "java/AnnotationProcessor.h"
|
||||
#include "text/Printer.h"
|
||||
#include "util/Util.h"
|
||||
|
||||
namespace aapt {
|
||||
@@ -47,11 +47,10 @@ class ClassMember {
|
||||
|
||||
virtual const std::string& GetName() const = 0;
|
||||
|
||||
// Writes the class member to the out stream. Subclasses should derive this method
|
||||
// Writes the class member to the Printer. Subclasses should derive this method
|
||||
// to write their own data. Call this base method from the subclass to write out
|
||||
// this member's comments/annotations.
|
||||
virtual void WriteToStream(const android::StringPiece& prefix, bool final,
|
||||
std::ostream* out) const;
|
||||
virtual void Print(bool final, text::Printer* printer) const;
|
||||
|
||||
private:
|
||||
AnnotationProcessor processor_;
|
||||
@@ -71,11 +70,16 @@ class PrimitiveMember : public ClassMember {
|
||||
return name_;
|
||||
}
|
||||
|
||||
void WriteToStream(const android::StringPiece& prefix, bool final,
|
||||
std::ostream* out) const override {
|
||||
ClassMember::WriteToStream(prefix, final, out);
|
||||
*out << prefix << "public static " << (final ? "final " : "") << "int " << name_ << "=" << val_
|
||||
<< ";";
|
||||
void Print(bool final, text::Printer* printer) const override {
|
||||
using std::to_string;
|
||||
|
||||
ClassMember::Print(final, printer);
|
||||
|
||||
printer->Print("public static ");
|
||||
if (final) {
|
||||
printer->Print("final ");
|
||||
}
|
||||
printer->Print("int ").Print(name_).Print("=").Print(to_string(val_)).Print(";");
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -100,12 +104,14 @@ class PrimitiveMember<std::string> : public ClassMember {
|
||||
return name_;
|
||||
}
|
||||
|
||||
void WriteToStream(const android::StringPiece& prefix, bool final,
|
||||
std::ostream* out) const override {
|
||||
ClassMember::WriteToStream(prefix, final, out);
|
||||
void Print(bool final, text::Printer* printer) const override {
|
||||
ClassMember::Print(final, printer);
|
||||
|
||||
*out << prefix << "public static " << (final ? "final " : "") << "String "
|
||||
<< name_ << "=\"" << val_ << "\";";
|
||||
printer->Print("public static ");
|
||||
if (final) {
|
||||
printer->Print("final ");
|
||||
}
|
||||
printer->Print("String ").Print(name_).Print("=\"").Print(val_).Print("\";");
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -136,25 +142,27 @@ class PrimitiveArrayMember : public ClassMember {
|
||||
return name_;
|
||||
}
|
||||
|
||||
void WriteToStream(const android::StringPiece& prefix, bool final,
|
||||
std::ostream* out) const override {
|
||||
ClassMember::WriteToStream(prefix, final, out);
|
||||
void Print(bool final, text::Printer* printer) const override {
|
||||
ClassMember::Print(final, printer);
|
||||
|
||||
*out << prefix << "public static final int[] " << name_ << "={";
|
||||
printer->Print("public static final int[] ").Print(name_).Print("={");
|
||||
printer->Indent();
|
||||
|
||||
const auto begin = elements_.begin();
|
||||
const auto end = elements_.end();
|
||||
for (auto current = begin; current != end; ++current) {
|
||||
if (std::distance(begin, current) % kAttribsPerLine == 0) {
|
||||
*out << "\n" << prefix << kIndent << kIndent;
|
||||
printer->Println();
|
||||
}
|
||||
|
||||
*out << *current;
|
||||
printer->Print(to_string(*current));
|
||||
if (std::distance(current, end) > 1) {
|
||||
*out << ", ";
|
||||
printer->Print(", ");
|
||||
}
|
||||
}
|
||||
*out << "\n" << prefix << kIndent << "};";
|
||||
printer->Println();
|
||||
printer->Undent();
|
||||
printer->Print("};");
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -187,8 +195,7 @@ class MethodDefinition : public ClassMember {
|
||||
return false;
|
||||
}
|
||||
|
||||
void WriteToStream(const android::StringPiece& prefix, bool final,
|
||||
std::ostream* out) const override;
|
||||
void Print(bool final, text::Printer* printer) const override;
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(MethodDefinition);
|
||||
@@ -201,8 +208,8 @@ enum class ClassQualifier { kNone, kStatic };
|
||||
|
||||
class ClassDefinition : public ClassMember {
|
||||
public:
|
||||
static bool WriteJavaFile(const ClassDefinition* def, const android::StringPiece& package,
|
||||
bool final, std::ostream* out);
|
||||
static void WriteJavaFile(const ClassDefinition* def, const android::StringPiece& package,
|
||||
bool final, io::OutputStream* out);
|
||||
|
||||
ClassDefinition(const android::StringPiece& name, ClassQualifier qualifier, bool createIfEmpty)
|
||||
: name_(name.to_string()), qualifier_(qualifier), create_if_empty_(createIfEmpty) {}
|
||||
@@ -220,8 +227,7 @@ class ClassDefinition : public ClassMember {
|
||||
return name_;
|
||||
}
|
||||
|
||||
void WriteToStream(const android::StringPiece& prefix, bool final,
|
||||
std::ostream* out) const override;
|
||||
void Print(bool final, text::Printer* printer) const override;
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(ClassDefinition);
|
||||
|
||||
@@ -37,8 +37,10 @@
|
||||
#include "java/ClassDefinition.h"
|
||||
#include "process/SymbolTable.h"
|
||||
|
||||
using android::StringPiece;
|
||||
using android::base::StringPrintf;
|
||||
using ::aapt::io::OutputStream;
|
||||
using ::aapt::text::Printer;
|
||||
using ::android::StringPiece;
|
||||
using ::android::base::StringPrintf;
|
||||
|
||||
namespace aapt {
|
||||
|
||||
@@ -230,7 +232,7 @@ void JavaClassGenerator::ProcessStyleable(const ResourceNameRef& name, const Res
|
||||
const StringPiece& package_name_to_generate,
|
||||
ClassDefinition* out_class_def,
|
||||
MethodDefinition* out_rewrite_method,
|
||||
std::ostream* out_r_txt) {
|
||||
Printer* r_txt_printer) {
|
||||
const std::string array_field_name = TransformToFieldName(name.entry);
|
||||
std::unique_ptr<ResourceArrayMember> array_def =
|
||||
util::make_unique<ResourceArrayMember>(array_field_name);
|
||||
@@ -323,8 +325,8 @@ void JavaClassGenerator::ProcessStyleable(const ResourceNameRef& name, const Res
|
||||
array_def->GetCommentBuilder()->AppendComment(styleable_comment.str());
|
||||
}
|
||||
|
||||
if (out_r_txt != nullptr) {
|
||||
*out_r_txt << "int[] styleable " << array_field_name << " {";
|
||||
if (r_txt_printer != nullptr) {
|
||||
r_txt_printer->Print("int[] styleable ").Print(array_field_name).Print(" {");
|
||||
}
|
||||
|
||||
// Add the ResourceIds to the array member.
|
||||
@@ -332,16 +334,16 @@ void JavaClassGenerator::ProcessStyleable(const ResourceNameRef& name, const Res
|
||||
const ResourceId id = sorted_attributes[i].attr_ref->id.value_or_default(ResourceId(0));
|
||||
array_def->AddElement(id);
|
||||
|
||||
if (out_r_txt != nullptr) {
|
||||
if (r_txt_printer != nullptr) {
|
||||
if (i != 0) {
|
||||
*out_r_txt << ",";
|
||||
r_txt_printer->Print(",");
|
||||
}
|
||||
*out_r_txt << " " << id;
|
||||
r_txt_printer->Print(" ").Print(id.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
if (out_r_txt != nullptr) {
|
||||
*out_r_txt << " }\n";
|
||||
if (r_txt_printer != nullptr) {
|
||||
r_txt_printer->Println(" }");
|
||||
}
|
||||
|
||||
// Add the Styleable array to the Styleable class.
|
||||
@@ -396,9 +398,9 @@ void JavaClassGenerator::ProcessStyleable(const ResourceNameRef& name, const Res
|
||||
attr_processor->AppendComment(
|
||||
StringPrintf("@attr name %s:%s", package_name.data(), attr_name.entry.data()));
|
||||
|
||||
if (out_r_txt != nullptr) {
|
||||
*out_r_txt << StringPrintf("int styleable %s %d\n", sorted_attributes[i].field_name.data(),
|
||||
(int)i);
|
||||
if (r_txt_printer != nullptr) {
|
||||
r_txt_printer->Println(
|
||||
StringPrintf("int styleable %s %zd", sorted_attributes[i].field_name.c_str(), i));
|
||||
}
|
||||
|
||||
out_class_def->AddMember(std::move(index_member));
|
||||
@@ -422,10 +424,12 @@ void JavaClassGenerator::ProcessStyleable(const ResourceNameRef& name, const Res
|
||||
void JavaClassGenerator::ProcessResource(const ResourceNameRef& name, const ResourceId& id,
|
||||
const ResourceEntry& entry, ClassDefinition* out_class_def,
|
||||
MethodDefinition* out_rewrite_method,
|
||||
std::ostream* out_r_txt) {
|
||||
text::Printer* r_txt_printer) {
|
||||
ResourceId real_id = id;
|
||||
if (context_->GetMinSdkVersion() < SDK_O && name.type == ResourceType::kId &&
|
||||
id.package_id() > kAppPackageId) {
|
||||
// Workaround for feature splits using package IDs > 0x7F.
|
||||
// See b/37498913.
|
||||
real_id = ResourceId(kAppPackageId, id.package_id(), id.entry_id());
|
||||
}
|
||||
|
||||
@@ -456,8 +460,13 @@ void JavaClassGenerator::ProcessResource(const ResourceNameRef& name, const Reso
|
||||
|
||||
out_class_def->AddMember(std::move(resource_member));
|
||||
|
||||
if (out_r_txt != nullptr) {
|
||||
*out_r_txt << "int " << name.type << " " << field_name << " " << real_id << "\n";
|
||||
if (r_txt_printer != nullptr) {
|
||||
r_txt_printer->Print("int ")
|
||||
.Print(to_string(name.type))
|
||||
.Print(" ")
|
||||
.Print(field_name)
|
||||
.Print(" ")
|
||||
.Println(real_id.to_string());
|
||||
}
|
||||
|
||||
if (out_rewrite_method != nullptr) {
|
||||
@@ -497,7 +506,7 @@ bool JavaClassGenerator::ProcessType(const StringPiece& package_name_to_generate
|
||||
const ResourceTableType& type,
|
||||
ClassDefinition* out_type_class_def,
|
||||
MethodDefinition* out_rewrite_method_def,
|
||||
std::ostream* out_r_txt) {
|
||||
Printer* r_txt_printer) {
|
||||
for (const auto& entry : type.entries) {
|
||||
const Maybe<std::string> unmangled_name =
|
||||
UnmangleResource(package.name, package_name_to_generate, *entry);
|
||||
@@ -532,18 +541,18 @@ bool JavaClassGenerator::ProcessType(const StringPiece& package_name_to_generate
|
||||
static_cast<const Styleable*>(entry->values.front()->value.get());
|
||||
|
||||
ProcessStyleable(resource_name, id, *styleable, package_name_to_generate, out_type_class_def,
|
||||
out_rewrite_method_def, out_r_txt);
|
||||
out_rewrite_method_def, r_txt_printer);
|
||||
} else {
|
||||
ProcessResource(resource_name, id, *entry, out_type_class_def, out_rewrite_method_def,
|
||||
out_r_txt);
|
||||
r_txt_printer);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JavaClassGenerator::Generate(const StringPiece& package_name_to_generate, std::ostream* out,
|
||||
std::ostream* out_r_txt) {
|
||||
return Generate(package_name_to_generate, package_name_to_generate, out);
|
||||
bool JavaClassGenerator::Generate(const StringPiece& package_name_to_generate, OutputStream* out,
|
||||
OutputStream* out_r_txt) {
|
||||
return Generate(package_name_to_generate, package_name_to_generate, out, out_r_txt);
|
||||
}
|
||||
|
||||
static void AppendJavaDocAnnotations(const std::vector<std::string>& annotations,
|
||||
@@ -556,11 +565,16 @@ static void AppendJavaDocAnnotations(const std::vector<std::string>& annotations
|
||||
}
|
||||
|
||||
bool JavaClassGenerator::Generate(const StringPiece& package_name_to_generate,
|
||||
const StringPiece& out_package_name, std::ostream* out,
|
||||
std::ostream* out_r_txt) {
|
||||
const StringPiece& out_package_name, OutputStream* out,
|
||||
OutputStream* out_r_txt) {
|
||||
ClassDefinition r_class("R", ClassQualifier::kNone, true);
|
||||
std::unique_ptr<MethodDefinition> rewrite_method;
|
||||
|
||||
std::unique_ptr<Printer> r_txt_printer;
|
||||
if (out_r_txt != nullptr) {
|
||||
r_txt_printer = util::make_unique<Printer>(out_r_txt);
|
||||
}
|
||||
|
||||
// Generate an onResourcesLoaded() callback if requested.
|
||||
if (options_.rewrite_callback_options) {
|
||||
rewrite_method =
|
||||
@@ -586,7 +600,7 @@ bool JavaClassGenerator::Generate(const StringPiece& package_name_to_generate,
|
||||
std::unique_ptr<ClassDefinition> class_def = util::make_unique<ClassDefinition>(
|
||||
to_string(type->type), ClassQualifier::kStatic, force_creation_if_empty);
|
||||
if (!ProcessType(package_name_to_generate, *package, *type, class_def.get(),
|
||||
rewrite_method.get(), out_r_txt)) {
|
||||
rewrite_method.get(), r_txt_printer.get())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -595,7 +609,7 @@ bool JavaClassGenerator::Generate(const StringPiece& package_name_to_generate,
|
||||
const ResourceTableType* priv_type = package->FindType(ResourceType::kAttrPrivate);
|
||||
if (priv_type) {
|
||||
if (!ProcessType(package_name_to_generate, *package, *priv_type, class_def.get(),
|
||||
rewrite_method.get(), out_r_txt)) {
|
||||
rewrite_method.get(), r_txt_printer.get())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -619,22 +633,7 @@ bool JavaClassGenerator::Generate(const StringPiece& package_name_to_generate,
|
||||
}
|
||||
|
||||
AppendJavaDocAnnotations(options_.javadoc_annotations, r_class.GetCommentBuilder());
|
||||
|
||||
if (!ClassDefinition::WriteJavaFile(&r_class, out_package_name, options_.use_final, out)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
out->flush();
|
||||
|
||||
if (out_r_txt != nullptr) {
|
||||
out_r_txt->flush();
|
||||
|
||||
if (!*out_r_txt) {
|
||||
error_ = android::base::SystemErrorCodeToString(errno);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ClassDefinition::WriteJavaFile(&r_class, out_package_name, options_.use_final, out);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,16 +17,16 @@
|
||||
#ifndef AAPT_JAVA_CLASS_GENERATOR_H
|
||||
#define AAPT_JAVA_CLASS_GENERATOR_H
|
||||
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
|
||||
#include "androidfw/StringPiece.h"
|
||||
|
||||
#include "ResourceTable.h"
|
||||
#include "ResourceValues.h"
|
||||
#include "androidfw/StringPiece.h"
|
||||
#include "io/Io.h"
|
||||
#include "process/IResourceTableConsumer.h"
|
||||
#include "process/SymbolTable.h"
|
||||
#include "text/Printer.h"
|
||||
|
||||
namespace aapt {
|
||||
|
||||
@@ -70,14 +70,14 @@ class JavaClassGenerator {
|
||||
// All symbols technically belong to a single package, but linked libraries will
|
||||
// have their names mangled, denoting that they came from a different package.
|
||||
// We need to generate these symbols in a separate file. Returns true on success.
|
||||
bool Generate(const android::StringPiece& package_name_to_generate, std::ostream* out,
|
||||
std::ostream* out_r_txt = nullptr);
|
||||
bool Generate(const android::StringPiece& package_name_to_generate, io::OutputStream* out,
|
||||
io::OutputStream* out_r_txt = nullptr);
|
||||
|
||||
bool Generate(const android::StringPiece& package_name_to_generate,
|
||||
const android::StringPiece& output_package_name, std::ostream* out,
|
||||
std::ostream* out_r_txt = nullptr);
|
||||
const android::StringPiece& output_package_name, io::OutputStream* out,
|
||||
io::OutputStream* out_r_txt = nullptr);
|
||||
|
||||
const std::string& getError() const;
|
||||
const std::string& GetError() const;
|
||||
|
||||
static std::string TransformToFieldName(const android::StringPiece& symbol);
|
||||
|
||||
@@ -94,13 +94,13 @@ class JavaClassGenerator {
|
||||
bool ProcessType(const android::StringPiece& package_name_to_generate,
|
||||
const ResourceTablePackage& package, const ResourceTableType& type,
|
||||
ClassDefinition* out_type_class_def, MethodDefinition* out_rewrite_method_def,
|
||||
std::ostream* out_r_txt);
|
||||
text::Printer* r_txt_printer);
|
||||
|
||||
// Writes a resource to the R.java file, optionally writing out a rewrite rule for its package
|
||||
// ID if `out_rewrite_method` is not nullptr.
|
||||
void ProcessResource(const ResourceNameRef& name, const ResourceId& id,
|
||||
const ResourceEntry& entry, ClassDefinition* out_class_def,
|
||||
MethodDefinition* out_rewrite_method, std::ostream* out_r_txt);
|
||||
MethodDefinition* out_rewrite_method, text::Printer* r_txt_printer);
|
||||
|
||||
// Writes a styleable resource to the R.java file, optionally writing out a rewrite rule for
|
||||
// its package ID if `out_rewrite_method` is not nullptr.
|
||||
@@ -109,7 +109,7 @@ class JavaClassGenerator {
|
||||
const Styleable& styleable,
|
||||
const android::StringPiece& package_name_to_generate,
|
||||
ClassDefinition* out_class_def, MethodDefinition* out_rewrite_method,
|
||||
std::ostream* out_r_txt);
|
||||
text::Printer* r_txt_printer);
|
||||
|
||||
IAaptContext* context_;
|
||||
ResourceTable* table_;
|
||||
@@ -117,7 +117,7 @@ class JavaClassGenerator {
|
||||
std::string error_;
|
||||
};
|
||||
|
||||
inline const std::string& JavaClassGenerator::getError() const {
|
||||
inline const std::string& JavaClassGenerator::GetError() const {
|
||||
return error_;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,12 +16,13 @@
|
||||
|
||||
#include "java/JavaClassGenerator.h"
|
||||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include "io/StringStream.h"
|
||||
#include "test/Test.h"
|
||||
#include "util/Util.h"
|
||||
|
||||
using ::aapt::io::StringOutputStream;
|
||||
using ::android::StringPiece;
|
||||
using ::testing::HasSubstr;
|
||||
using ::testing::Lt;
|
||||
@@ -45,7 +46,8 @@ TEST(JavaClassGeneratorTest, FailWhenEntryIsJavaKeyword) {
|
||||
.Build();
|
||||
JavaClassGenerator generator(context.get(), table.get(), {});
|
||||
|
||||
std::stringstream out;
|
||||
std::string result;
|
||||
StringOutputStream out(&result);
|
||||
EXPECT_FALSE(generator.Generate("android", &out));
|
||||
}
|
||||
|
||||
@@ -69,10 +71,10 @@ TEST(JavaClassGeneratorTest, TransformInvalidJavaIdentifierCharacter) {
|
||||
.Build();
|
||||
JavaClassGenerator generator(context.get(), table.get(), {});
|
||||
|
||||
std::stringstream out;
|
||||
std::string output;
|
||||
StringOutputStream out(&output);
|
||||
EXPECT_TRUE(generator.Generate("android", &out));
|
||||
|
||||
std::string output = out.str();
|
||||
out.Flush();
|
||||
|
||||
EXPECT_THAT(output, HasSubstr("public static final int hey_man=0x01020000;"));
|
||||
EXPECT_THAT(output, HasSubstr("public static final int[] hey_dude={"));
|
||||
@@ -93,10 +95,12 @@ TEST(JavaClassGeneratorTest, CorrectPackageNameIsUsed) {
|
||||
.SetNameManglerPolicy(NameManglerPolicy{"android"})
|
||||
.Build();
|
||||
JavaClassGenerator generator(context.get(), table.get(), {});
|
||||
std::stringstream out;
|
||||
ASSERT_TRUE(generator.Generate("android", "com.android.internal", &out));
|
||||
|
||||
std::string output = out.str();
|
||||
std::string output;
|
||||
StringOutputStream out(&output);
|
||||
ASSERT_TRUE(generator.Generate("android", "com.android.internal", &out));
|
||||
out.Flush();
|
||||
|
||||
EXPECT_THAT(output, HasSubstr("package com.android.internal;"));
|
||||
EXPECT_THAT(output, HasSubstr("public static final int one=0x01020000;"));
|
||||
EXPECT_THAT(output, Not(HasSubstr("two")));
|
||||
@@ -117,10 +121,12 @@ TEST(JavaClassGeneratorTest, AttrPrivateIsWrittenAsAttr) {
|
||||
.SetNameManglerPolicy(NameManglerPolicy{"android"})
|
||||
.Build();
|
||||
JavaClassGenerator generator(context.get(), table.get(), {});
|
||||
std::stringstream out;
|
||||
ASSERT_TRUE(generator.Generate("android", &out));
|
||||
|
||||
std::string output = out.str();
|
||||
std::string output;
|
||||
StringOutputStream out(&output);
|
||||
ASSERT_TRUE(generator.Generate("android", &out));
|
||||
out.Flush();
|
||||
|
||||
EXPECT_THAT(output, HasSubstr("public static final class attr"));
|
||||
EXPECT_THAT(output, Not(HasSubstr("public static final class ^attr-private")));
|
||||
}
|
||||
@@ -147,9 +153,11 @@ TEST(JavaClassGeneratorTest, OnlyWritePublicResources) {
|
||||
options.types = JavaClassGeneratorOptions::SymbolTypes::kPublic;
|
||||
{
|
||||
JavaClassGenerator generator(context.get(), table.get(), options);
|
||||
std::stringstream out;
|
||||
std::string output;
|
||||
StringOutputStream out(&output);
|
||||
ASSERT_TRUE(generator.Generate("android", &out));
|
||||
std::string output = out.str();
|
||||
out.Flush();
|
||||
|
||||
EXPECT_THAT(output, HasSubstr("public static final int one=0x01020000;"));
|
||||
EXPECT_THAT(output, Not(HasSubstr("two")));
|
||||
EXPECT_THAT(output, Not(HasSubstr("three")));
|
||||
@@ -158,9 +166,11 @@ TEST(JavaClassGeneratorTest, OnlyWritePublicResources) {
|
||||
options.types = JavaClassGeneratorOptions::SymbolTypes::kPublicPrivate;
|
||||
{
|
||||
JavaClassGenerator generator(context.get(), table.get(), options);
|
||||
std::stringstream out;
|
||||
std::string output;
|
||||
StringOutputStream out(&output);
|
||||
ASSERT_TRUE(generator.Generate("android", &out));
|
||||
std::string output = out.str();
|
||||
out.Flush();
|
||||
|
||||
EXPECT_THAT(output, HasSubstr("public static final int one=0x01020000;"));
|
||||
EXPECT_THAT(output, HasSubstr("public static final int two=0x01020001;"));
|
||||
EXPECT_THAT(output, Not(HasSubstr("three")));
|
||||
@@ -169,9 +179,11 @@ TEST(JavaClassGeneratorTest, OnlyWritePublicResources) {
|
||||
options.types = JavaClassGeneratorOptions::SymbolTypes::kAll;
|
||||
{
|
||||
JavaClassGenerator generator(context.get(), table.get(), options);
|
||||
std::stringstream out;
|
||||
std::string output;
|
||||
StringOutputStream out(&output);
|
||||
ASSERT_TRUE(generator.Generate("android", &out));
|
||||
std::string output = out.str();
|
||||
out.Flush();
|
||||
|
||||
EXPECT_THAT(output, HasSubstr("public static final int one=0x01020000;"));
|
||||
EXPECT_THAT(output, HasSubstr("public static final int two=0x01020001;"));
|
||||
EXPECT_THAT(output, HasSubstr("public static final int three=0x01020002;"));
|
||||
@@ -235,10 +247,11 @@ TEST(JavaClassGeneratorTest, EmitOtherPackagesAttributesInStyleable) {
|
||||
.Build();
|
||||
JavaClassGenerator generator(context.get(), table.get(), {});
|
||||
|
||||
std::stringstream out;
|
||||
std::string output;
|
||||
StringOutputStream out(&output);
|
||||
EXPECT_TRUE(generator.Generate("android", &out));
|
||||
out.Flush();
|
||||
|
||||
std::string output = out.str();
|
||||
EXPECT_THAT(output, HasSubstr("int foo_bar="));
|
||||
EXPECT_THAT(output, HasSubstr("int foo_com_lib_bar="));
|
||||
}
|
||||
@@ -258,9 +271,11 @@ TEST(JavaClassGeneratorTest, CommentsForSimpleResourcesArePresent) {
|
||||
.SetNameManglerPolicy(NameManglerPolicy{"android"})
|
||||
.Build();
|
||||
JavaClassGenerator generator(context.get(), table.get(), {});
|
||||
std::stringstream out;
|
||||
|
||||
std::string output;
|
||||
StringOutputStream out(&output);
|
||||
ASSERT_TRUE(generator.Generate("android", &out));
|
||||
std::string output = out.str();
|
||||
out.Flush();
|
||||
|
||||
const char* expected_text =
|
||||
R"EOF(/**
|
||||
@@ -298,9 +313,11 @@ TEST(JavaClassGeneratorTest, CommentsForStyleablesAndNestedAttributesArePresent)
|
||||
JavaClassGeneratorOptions options;
|
||||
options.use_final = false;
|
||||
JavaClassGenerator generator(context.get(), table.get(), options);
|
||||
std::stringstream out;
|
||||
|
||||
std::string output;
|
||||
StringOutputStream out(&output);
|
||||
ASSERT_TRUE(generator.Generate("android", &out));
|
||||
std::string output = out.str();
|
||||
out.Flush();
|
||||
|
||||
EXPECT_THAT(output, HasSubstr("attr name android:one"));
|
||||
EXPECT_THAT(output, HasSubstr("attr description"));
|
||||
@@ -332,9 +349,11 @@ TEST(JavaClassGeneratorTest, StyleableAndIndicesAreColocated) {
|
||||
|
||||
JavaClassGeneratorOptions options;
|
||||
JavaClassGenerator generator(context.get(), table.get(), {});
|
||||
std::stringstream out;
|
||||
|
||||
std::string output;
|
||||
StringOutputStream out(&output);
|
||||
ASSERT_TRUE(generator.Generate("android", &out));
|
||||
std::string output = out.str();
|
||||
out.Flush();
|
||||
|
||||
std::string::size_type actionbar_pos = output.find("int[] ActionBar");
|
||||
ASSERT_THAT(actionbar_pos, Ne(std::string::npos));
|
||||
@@ -373,9 +392,11 @@ TEST(JavaClassGeneratorTest, CommentsForRemovedAttributesAreNotPresentInClass) {
|
||||
JavaClassGeneratorOptions options;
|
||||
options.use_final = false;
|
||||
JavaClassGenerator generator(context.get(), table.get(), options);
|
||||
std::stringstream out;
|
||||
|
||||
std::string output;
|
||||
StringOutputStream out(&output);
|
||||
ASSERT_TRUE(generator.Generate("android", &out));
|
||||
std::string output = out.str();
|
||||
out.Flush();
|
||||
|
||||
EXPECT_THAT(output, Not(HasSubstr("@attr name android:one")));
|
||||
EXPECT_THAT(output, Not(HasSubstr("@attr description")));
|
||||
@@ -409,10 +430,10 @@ TEST(JavaClassGeneratorTest, GenerateOnResourcesLoadedCallbackForSharedLibrary)
|
||||
options.rewrite_callback_options = OnResourcesLoadedCallbackOptions{{"com.foo", "com.boo"}};
|
||||
JavaClassGenerator generator(context.get(), table.get(), options);
|
||||
|
||||
std::stringstream out;
|
||||
std::string output;
|
||||
StringOutputStream out(&output);
|
||||
ASSERT_TRUE(generator.Generate("android", &out));
|
||||
|
||||
std::string output = out.str();
|
||||
out.Flush();
|
||||
|
||||
EXPECT_THAT(output, HasSubstr("void onResourcesLoaded"));
|
||||
EXPECT_THAT(output, HasSubstr("com.foo.R.onResourcesLoaded"));
|
||||
|
||||
@@ -23,8 +23,7 @@
|
||||
|
||||
namespace aapt {
|
||||
|
||||
std::unique_ptr<ClassDefinition> GenerateManifestClass(IDiagnostics* diag,
|
||||
xml::XmlResource* res);
|
||||
std::unique_ptr<ClassDefinition> GenerateManifestClass(IDiagnostics* diag, xml::XmlResource* res);
|
||||
|
||||
} // namespace aapt
|
||||
|
||||
|
||||
@@ -16,8 +16,10 @@
|
||||
|
||||
#include "java/ManifestClassGenerator.h"
|
||||
|
||||
#include "io/StringStream.h"
|
||||
#include "test/Test.h"
|
||||
|
||||
using ::aapt::io::StringOutputStream;
|
||||
using ::testing::HasSubstr;
|
||||
using ::testing::Not;
|
||||
|
||||
@@ -144,12 +146,9 @@ static ::testing::AssertionResult GetManifestClassText(IAaptContext* context, xm
|
||||
return ::testing::AssertionFailure() << "manifest_class == nullptr";
|
||||
}
|
||||
|
||||
std::stringstream out;
|
||||
if (!manifest_class->WriteJavaFile(manifest_class.get(), "android", true, &out)) {
|
||||
return ::testing::AssertionFailure() << "failed to write java file";
|
||||
}
|
||||
|
||||
*out_str = out.str();
|
||||
StringOutputStream out(out_str);
|
||||
manifest_class->WriteJavaFile(manifest_class.get(), "android", true, &out);
|
||||
out.Flush();
|
||||
return ::testing::AssertionSuccess();
|
||||
}
|
||||
|
||||
|
||||
@@ -20,14 +20,18 @@
|
||||
#include <string>
|
||||
|
||||
#include "android-base/macros.h"
|
||||
#include "androidfw/StringPiece.h"
|
||||
|
||||
#include "JavaClassGenerator.h"
|
||||
#include "ResourceUtils.h"
|
||||
#include "ValueVisitor.h"
|
||||
#include "androidfw/StringPiece.h"
|
||||
#include "text/Printer.h"
|
||||
#include "util/Util.h"
|
||||
#include "xml/XmlDom.h"
|
||||
|
||||
using ::aapt::io::OutputStream;
|
||||
using ::aapt::text::Printer;
|
||||
|
||||
namespace aapt {
|
||||
namespace proguard {
|
||||
|
||||
@@ -326,12 +330,13 @@ bool CollectProguardRules(xml::XmlResource* res, KeepSet* keep_set) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteKeepSet(std::ostream* out, const KeepSet& keep_set) {
|
||||
void WriteKeepSet(const KeepSet& keep_set, OutputStream* out) {
|
||||
Printer printer(out);
|
||||
for (const auto& entry : keep_set.manifest_class_set_) {
|
||||
for (const UsageLocation& location : entry.second) {
|
||||
*out << "# Referenced at " << location.source << "\n";
|
||||
printer.Print("# Referenced at ").Println(location.source.to_string());
|
||||
}
|
||||
*out << "-keep class " << entry.first << " { <init>(...); }\n" << std::endl;
|
||||
printer.Print("-keep class ").Print(entry.first).Println(" { <init>(...); }");
|
||||
}
|
||||
|
||||
for (const auto& entry : keep_set.conditional_class_set_) {
|
||||
@@ -342,26 +347,31 @@ bool WriteKeepSet(std::ostream* out, const KeepSet& keep_set) {
|
||||
}
|
||||
|
||||
for (const UsageLocation& location : entry.second) {
|
||||
*out << "# Referenced at " << location.source << "\n";
|
||||
printer.Print("# Referenced at ").Println(location.source.to_string());
|
||||
}
|
||||
if (keep_set.conditional_keep_rules_ && can_be_conditional) {
|
||||
*out << "-if class **.R$layout {\n";
|
||||
printer.Println("-if class **.R$layout {");
|
||||
printer.Indent();
|
||||
for (const UsageLocation& location : locations) {
|
||||
auto transformed_name = JavaClassGenerator::TransformToFieldName(location.name.entry);
|
||||
*out << " int " << transformed_name << ";\n";
|
||||
printer.Print("int ")
|
||||
.Print(JavaClassGenerator::TransformToFieldName(location.name.entry))
|
||||
.Println(";");
|
||||
}
|
||||
*out << "}\n";
|
||||
printer.Undent();
|
||||
printer.Println("}");
|
||||
printer.Println();
|
||||
}
|
||||
*out << "-keep class " << entry.first << " { <init>(...); }\n" << std::endl;
|
||||
printer.Print("-keep class ").Print(entry.first).Println(" { <init>(...); }");
|
||||
printer.Println();
|
||||
}
|
||||
|
||||
for (const auto& entry : keep_set.method_set_) {
|
||||
for (const UsageLocation& location : entry.second) {
|
||||
*out << "# Referenced at " << location.source << "\n";
|
||||
printer.Print("# Referenced at ").Println(location.source.to_string());
|
||||
}
|
||||
*out << "-keepclassmembers class * { *** " << entry.first << "(...); }\n" << std::endl;
|
||||
printer.Print("-keepclassmembers class * { *** ").Print(entry.first).Println("(...); }");
|
||||
printer.Println();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CollectLocations(const UsageLocation& location, const KeepSet& keep_set,
|
||||
|
||||
@@ -22,11 +22,13 @@
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
#include "androidfw/StringPiece.h"
|
||||
|
||||
#include "Resource.h"
|
||||
#include "ResourceTable.h"
|
||||
#include "Source.h"
|
||||
#include "ValueVisitor.h"
|
||||
#include "androidfw/StringPiece.h"
|
||||
#include "io/Io.h"
|
||||
#include "process/IResourceTableConsumer.h"
|
||||
#include "xml/XmlDom.h"
|
||||
|
||||
@@ -62,7 +64,7 @@ class KeepSet {
|
||||
}
|
||||
|
||||
private:
|
||||
friend bool WriteKeepSet(std::ostream* out, const KeepSet& keep_set);
|
||||
friend void WriteKeepSet(const KeepSet& keep_set, io::OutputStream* out);
|
||||
|
||||
friend bool CollectLocations(const UsageLocation& location, const KeepSet& keep_set,
|
||||
std::set<UsageLocation>* locations);
|
||||
@@ -76,11 +78,12 @@ class KeepSet {
|
||||
|
||||
bool CollectProguardRulesForManifest(xml::XmlResource* res, KeepSet* keep_set,
|
||||
bool main_dex_only = false);
|
||||
bool CollectProguardRules(xml::XmlResource* res, KeepSet* keep_set);
|
||||
bool CollectResourceReferences(aapt::IAaptContext* context, ResourceTable* table,
|
||||
KeepSet* keep_set);
|
||||
|
||||
bool WriteKeepSet(std::ostream* out, const KeepSet& keep_set);
|
||||
bool CollectProguardRules(xml::XmlResource* res, KeepSet* keep_set);
|
||||
|
||||
bool CollectResourceReferences(IAaptContext* context, ResourceTable* table, KeepSet* keep_set);
|
||||
|
||||
void WriteKeepSet(const KeepSet& keep_set, io::OutputStream* out);
|
||||
|
||||
bool CollectLocations(const UsageLocation& location, const KeepSet& keep_set,
|
||||
std::set<UsageLocation>* locations);
|
||||
|
||||
@@ -17,13 +17,23 @@
|
||||
#include "java/ProguardRules.h"
|
||||
#include "link/Linkers.h"
|
||||
|
||||
#include "io/StringStream.h"
|
||||
#include "test/Test.h"
|
||||
|
||||
using ::aapt::io::StringOutputStream;
|
||||
using ::testing::HasSubstr;
|
||||
using ::testing::Not;
|
||||
|
||||
namespace aapt {
|
||||
|
||||
std::string GetKeepSetString(const proguard::KeepSet& set) {
|
||||
std::string out;
|
||||
StringOutputStream sout(&out);
|
||||
proguard::WriteKeepSet(set, &sout);
|
||||
sout.Flush();
|
||||
return out;
|
||||
}
|
||||
|
||||
TEST(ProguardRulesTest, FragmentNameRuleIsEmitted) {
|
||||
std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
|
||||
std::unique_ptr<xml::XmlResource> layout = test::BuildXmlDom(R"(
|
||||
@@ -34,10 +44,8 @@ TEST(ProguardRulesTest, FragmentNameRuleIsEmitted) {
|
||||
proguard::KeepSet set;
|
||||
ASSERT_TRUE(proguard::CollectProguardRules(layout.get(), &set));
|
||||
|
||||
std::stringstream out;
|
||||
ASSERT_TRUE(proguard::WriteKeepSet(&out, set));
|
||||
std::string actual = GetKeepSetString(set);
|
||||
|
||||
std::string actual = out.str();
|
||||
EXPECT_THAT(actual, HasSubstr("com.foo.Bar"));
|
||||
}
|
||||
|
||||
@@ -50,10 +58,8 @@ TEST(ProguardRulesTest, FragmentClassRuleIsEmitted) {
|
||||
proguard::KeepSet set;
|
||||
ASSERT_TRUE(proguard::CollectProguardRules(layout.get(), &set));
|
||||
|
||||
std::stringstream out;
|
||||
ASSERT_TRUE(proguard::WriteKeepSet(&out, set));
|
||||
std::string actual = GetKeepSetString(set);
|
||||
|
||||
std::string actual = out.str();
|
||||
EXPECT_THAT(actual, HasSubstr("com.foo.Bar"));
|
||||
}
|
||||
|
||||
@@ -68,10 +74,8 @@ TEST(ProguardRulesTest, FragmentNameAndClassRulesAreEmitted) {
|
||||
proguard::KeepSet set;
|
||||
ASSERT_TRUE(proguard::CollectProguardRules(layout.get(), &set));
|
||||
|
||||
std::stringstream out;
|
||||
ASSERT_TRUE(proguard::WriteKeepSet(&out, set));
|
||||
std::string actual = GetKeepSetString(set);
|
||||
|
||||
std::string actual = out.str();
|
||||
EXPECT_THAT(actual, HasSubstr("com.foo.Bar"));
|
||||
EXPECT_THAT(actual, HasSubstr("com.foo.Baz"));
|
||||
}
|
||||
@@ -87,10 +91,8 @@ TEST(ProguardRulesTest, CustomViewRulesAreEmitted) {
|
||||
proguard::KeepSet set;
|
||||
ASSERT_TRUE(proguard::CollectProguardRules(layout.get(), &set));
|
||||
|
||||
std::stringstream out;
|
||||
ASSERT_TRUE(proguard::WriteKeepSet(&out, set));
|
||||
std::string actual = GetKeepSetString(set);
|
||||
|
||||
std::string actual = out.str();
|
||||
EXPECT_THAT(actual, HasSubstr("com.foo.Bar"));
|
||||
}
|
||||
|
||||
@@ -126,11 +128,10 @@ TEST(ProguardRulesTest, IncludedLayoutRulesAreConditional) {
|
||||
ASSERT_TRUE(proguard::CollectProguardRules(bar_layout.get(), &set));
|
||||
ASSERT_TRUE(proguard::CollectProguardRules(foo_layout.get(), &set));
|
||||
|
||||
std::stringstream out;
|
||||
ASSERT_TRUE(proguard::WriteKeepSet(&out, set));
|
||||
std::string actual = GetKeepSetString(set);
|
||||
|
||||
std::string actual = out.str();
|
||||
EXPECT_THAT(actual, HasSubstr("-if class **.R$layout"));
|
||||
EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Bar { <init>(...); }"));
|
||||
EXPECT_THAT(actual, HasSubstr("int foo"));
|
||||
EXPECT_THAT(actual, HasSubstr("int bar"));
|
||||
EXPECT_THAT(actual, HasSubstr("com.foo.Bar"));
|
||||
@@ -148,10 +149,9 @@ TEST(ProguardRulesTest, AliasedLayoutRulesAreConditional) {
|
||||
set.AddReference({test::ParseNameOrDie("layout/bar"), {}}, layout->file.name);
|
||||
ASSERT_TRUE(proguard::CollectProguardRules(layout.get(), &set));
|
||||
|
||||
std::stringstream out;
|
||||
ASSERT_TRUE(proguard::WriteKeepSet(&out, set));
|
||||
std::string actual = GetKeepSetString(set);
|
||||
|
||||
std::string actual = out.str();
|
||||
EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Bar { <init>(...); }"));
|
||||
EXPECT_THAT(actual, HasSubstr("-if class **.R$layout"));
|
||||
EXPECT_THAT(actual, HasSubstr("int foo"));
|
||||
EXPECT_THAT(actual, HasSubstr("int bar"));
|
||||
@@ -170,11 +170,10 @@ TEST(ProguardRulesTest, NonLayoutReferencesAreUnconditional) {
|
||||
set.AddReference({test::ParseNameOrDie("style/MyStyle"), {}}, layout->file.name);
|
||||
ASSERT_TRUE(proguard::CollectProguardRules(layout.get(), &set));
|
||||
|
||||
std::stringstream out;
|
||||
ASSERT_TRUE(proguard::WriteKeepSet(&out, set));
|
||||
std::string actual = GetKeepSetString(set);
|
||||
|
||||
std::string actual = out.str();
|
||||
EXPECT_THAT(actual, Not(HasSubstr("-if")));
|
||||
EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Bar { <init>(...); }"));
|
||||
}
|
||||
|
||||
TEST(ProguardRulesTest, ViewOnClickRuleIsEmitted) {
|
||||
@@ -187,10 +186,8 @@ TEST(ProguardRulesTest, ViewOnClickRuleIsEmitted) {
|
||||
proguard::KeepSet set;
|
||||
ASSERT_TRUE(proguard::CollectProguardRules(layout.get(), &set));
|
||||
|
||||
std::stringstream out;
|
||||
ASSERT_TRUE(proguard::WriteKeepSet(&out, set));
|
||||
std::string actual = GetKeepSetString(set);
|
||||
|
||||
std::string actual = out.str();
|
||||
EXPECT_THAT(actual, HasSubstr("bar_method"));
|
||||
}
|
||||
|
||||
@@ -208,10 +205,8 @@ TEST(ProguardRulesTest, MenuRulesAreEmitted) {
|
||||
proguard::KeepSet set;
|
||||
ASSERT_TRUE(proguard::CollectProguardRules(menu.get(), &set));
|
||||
|
||||
std::stringstream out;
|
||||
ASSERT_TRUE(proguard::WriteKeepSet(&out, set));
|
||||
std::string actual = GetKeepSetString(set);
|
||||
|
||||
std::string actual = out.str();
|
||||
EXPECT_THAT(actual, HasSubstr("on_click"));
|
||||
EXPECT_THAT(actual, HasSubstr("com.foo.Bar"));
|
||||
EXPECT_THAT(actual, HasSubstr("com.foo.Baz"));
|
||||
|
||||
@@ -26,18 +26,18 @@ using ::android::StringPiece;
|
||||
namespace aapt {
|
||||
namespace text {
|
||||
|
||||
void Printer::Println(const StringPiece& str) {
|
||||
Printer& Printer::Println(const StringPiece& str) {
|
||||
Print(str);
|
||||
Print("\n");
|
||||
return Print("\n");
|
||||
}
|
||||
|
||||
void Printer::Println() {
|
||||
Print("\n");
|
||||
Printer& Printer::Println() {
|
||||
return Print("\n");
|
||||
}
|
||||
|
||||
void Printer::Print(const StringPiece& str) {
|
||||
Printer& Printer::Print(const StringPiece& str) {
|
||||
if (error_) {
|
||||
return;
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto remaining_str_begin = str.begin();
|
||||
@@ -53,7 +53,7 @@ void Printer::Print(const StringPiece& str) {
|
||||
for (int i = 0; i < indent_level_; i++) {
|
||||
if (!io::Copy(out_, " ")) {
|
||||
error_ = true;
|
||||
return;
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
needs_indent_ = false;
|
||||
@@ -61,7 +61,7 @@ void Printer::Print(const StringPiece& str) {
|
||||
|
||||
if (!io::Copy(out_, str_to_copy)) {
|
||||
error_ = true;
|
||||
return;
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ void Printer::Print(const StringPiece& str) {
|
||||
if (new_line_iter != remaining_str_end) {
|
||||
if (!io::Copy(out_, "\n")) {
|
||||
error_ = true;
|
||||
return;
|
||||
return *this;
|
||||
}
|
||||
needs_indent_ = true;
|
||||
// Ok to increment iterator here because we know that the '\n' character is one byte.
|
||||
@@ -78,6 +78,7 @@ void Printer::Print(const StringPiece& str) {
|
||||
remaining_str_begin = new_line_iter;
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Printer::Indent() {
|
||||
|
||||
@@ -31,9 +31,9 @@ class Printer {
|
||||
explicit Printer(::aapt::io::OutputStream* out) : out_(out) {
|
||||
}
|
||||
|
||||
void Print(const ::android::StringPiece& str);
|
||||
void Println(const ::android::StringPiece& str);
|
||||
void Println();
|
||||
Printer& Print(const ::android::StringPiece& str);
|
||||
Printer& Println(const ::android::StringPiece& str);
|
||||
Printer& Println();
|
||||
|
||||
void Indent();
|
||||
void Undent();
|
||||
|
||||
Reference in New Issue
Block a user